@agent-native/core 0.72.4 → 0.74.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 (129) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +67 -0
  3. package/corpus/core/docs/content/skills-guide.md +14 -0
  4. package/corpus/core/docs/content/template-clips.md +7 -1
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/agent/durable-background.ts +35 -12
  7. package/corpus/core/src/agent/production-agent.ts +55 -8
  8. package/corpus/core/src/cli/create.ts +1 -1
  9. package/corpus/core/src/cli/skills.ts +450 -19
  10. package/corpus/core/src/client/ConnectBuilderCard.tsx +7 -7
  11. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +1 -1
  12. package/corpus/core/src/client/blocks/library/AnnotatedCodeBlock.tsx +33 -18
  13. package/corpus/core/src/client/blocks/library/annotation-rail.tsx +3 -4
  14. package/corpus/core/src/client/components/CodeRequiredDialog.tsx +5 -8
  15. package/corpus/core/src/server/agent-chat-plugin.ts +7 -7
  16. package/corpus/core/src/server/auth.ts +7 -0
  17. package/corpus/core/src/server/onboarding-html.ts +95 -9
  18. package/corpus/core/src/server/self-dispatch.ts +8 -1
  19. package/corpus/core/src/templates/default/AGENTS.md +4 -0
  20. package/corpus/core/src/templates/default/package.json +2 -1
  21. package/corpus/core/src/templates/headless/AGENTS.md +4 -0
  22. package/corpus/core/src/templates/headless/package.json +1 -0
  23. package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
  24. package/corpus/core/src/templates/workspace-root/README.md +4 -0
  25. package/corpus/core/src/templates/workspace-root/package.json +1 -0
  26. package/corpus/templates/analytics/actions/compose-dashboard.ts +34 -0
  27. package/corpus/templates/analytics/actions/install-dashboard-template.ts +51 -3
  28. package/corpus/templates/analytics/actions/update-dashboard.ts +3 -4
  29. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +175 -48
  30. package/corpus/templates/analytics/app/global.css +15 -13
  31. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +9 -32
  32. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +0 -26
  33. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +0 -23
  34. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/pivot.ts +65 -2
  35. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +3 -4
  36. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-charts-now-fill-sparse-template-time-series-suppor.md +6 -0
  37. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-filters-now-apply-consistently-to-first-party-traf.md +6 -0
  38. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-rows-now-auto-fit-panels-so-one-two-or-three-chart.md +6 -0
  39. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-traffic-tables-now-show-top-urls-and-shared-clips-.md +6 -0
  40. package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +5 -0
  41. package/corpus/templates/analytics/changelog/2026-06-24-first-party-template-dashboards-now-include-repeat-users-ret.md +6 -0
  42. package/corpus/templates/analytics/changelog/2026-06-24-retention-charts-now-break-out-1-day-and-7-day-return-rates-.md +6 -0
  43. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +330 -49
  44. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +7 -2
  45. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +35 -8
  46. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +337 -45
  47. package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +1 -1
  48. package/corpus/templates/calendar/server/plugins/auth.ts +12 -0
  49. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +7 -7
  50. package/corpus/templates/clips/AGENTS.md +6 -2
  51. package/corpus/templates/clips/app/components/capture-install-options.tsx +20 -4
  52. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -0
  53. package/corpus/templates/clips/app/components/player/player-controls.tsx +62 -32
  54. package/corpus/templates/clips/app/lib/capture-install-options.ts +39 -5
  55. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +786 -323
  56. package/corpus/templates/clips/app/routes/download.tsx +2 -2
  57. package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
  58. package/corpus/templates/clips/changelog/2026-06-24-inline-slack-playback-controls-no-longer-shift-when-adjustin.md +6 -0
  59. package/corpus/templates/clips/changelog/2026-06-24-settings-now-puts-what-s-new-in-a-compact-sidebar-prioritize.md +6 -0
  60. package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-console-log-stream-all-le.md +6 -0
  61. package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-fetch-xhr-network-request.md +6 -0
  62. package/corpus/templates/clips/changelog/2026-06-24-the-chrome-extension-option-now-only-appears-on-supported-hosts.md +5 -0
  63. package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +13 -8
  64. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  65. package/corpus/templates/clips/chrome-extension/scripts/package.ts +15 -2
  66. package/corpus/templates/clips/chrome-extension/src/overlay.css +4 -25
  67. package/corpus/templates/clips/chrome-extension/src/overlay.ts +1 -3
  68. package/corpus/templates/clips/server/lib/public-agent-context.ts +67 -24
  69. package/corpus/templates/mail/server/plugins/auth.ts +4 -1
  70. package/corpus/templates/plan/app/pages/PlansPage.tsx +271 -197
  71. package/corpus/templates/plan/changelog/2026-06-24-annotated-code-callouts-now-use-numbered-gutter-markers-that.md +6 -0
  72. package/corpus/templates/plan/server/plan-content.ts +45 -2
  73. package/dist/agent/durable-background.d.ts +9 -4
  74. package/dist/agent/durable-background.d.ts.map +1 -1
  75. package/dist/agent/durable-background.js +34 -11
  76. package/dist/agent/durable-background.js.map +1 -1
  77. package/dist/agent/production-agent.d.ts.map +1 -1
  78. package/dist/agent/production-agent.js +52 -8
  79. package/dist/agent/production-agent.js.map +1 -1
  80. package/dist/cli/create.js +1 -1
  81. package/dist/cli/create.js.map +1 -1
  82. package/dist/cli/skills.d.ts.map +1 -1
  83. package/dist/cli/skills.js +361 -19
  84. package/dist/cli/skills.js.map +1 -1
  85. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  86. package/dist/client/ConnectBuilderCard.js +6 -6
  87. package/dist/client/ConnectBuilderCard.js.map +1 -1
  88. package/dist/client/NewWorkspaceAppFlow.js +1 -1
  89. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  90. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  91. package/dist/client/blocks/library/AnnotatedCodeBlock.js +14 -10
  92. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  93. package/dist/client/blocks/library/annotation-rail.d.ts +3 -4
  94. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  95. package/dist/client/blocks/library/annotation-rail.js +3 -4
  96. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  97. package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
  98. package/dist/client/components/CodeRequiredDialog.js +2 -1
  99. package/dist/client/components/CodeRequiredDialog.js.map +1 -1
  100. package/dist/server/agent-chat-plugin.js +7 -7
  101. package/dist/server/agent-chat-plugin.js.map +1 -1
  102. package/dist/server/auth.d.ts +7 -0
  103. package/dist/server/auth.d.ts.map +1 -1
  104. package/dist/server/auth.js +1 -0
  105. package/dist/server/auth.js.map +1 -1
  106. package/dist/server/onboarding-html.d.ts +15 -0
  107. package/dist/server/onboarding-html.d.ts.map +1 -1
  108. package/dist/server/onboarding-html.js +73 -9
  109. package/dist/server/onboarding-html.js.map +1 -1
  110. package/dist/server/self-dispatch.d.ts.map +1 -1
  111. package/dist/server/self-dispatch.js +5 -1
  112. package/dist/server/self-dispatch.js.map +1 -1
  113. package/dist/templates/default/AGENTS.md +4 -0
  114. package/dist/templates/default/package.json +2 -1
  115. package/dist/templates/headless/AGENTS.md +4 -0
  116. package/dist/templates/headless/package.json +1 -0
  117. package/dist/templates/workspace-root/AGENTS.md +4 -0
  118. package/dist/templates/workspace-root/README.md +4 -0
  119. package/dist/templates/workspace-root/package.json +1 -0
  120. package/docs/content/skills-guide.md +14 -0
  121. package/docs/content/template-clips.md +7 -1
  122. package/package.json +1 -1
  123. package/src/templates/default/AGENTS.md +4 -0
  124. package/src/templates/default/package.json +2 -1
  125. package/src/templates/headless/AGENTS.md +4 -0
  126. package/src/templates/headless/package.json +1 -0
  127. package/src/templates/workspace-root/AGENTS.md +4 -0
  128. package/src/templates/workspace-root/README.md +4 -0
  129. package/src/templates/workspace-root/package.json +1 -0
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 1160
31
- - template files: 4012
31
+ - template files: 4025
@@ -1,5 +1,72 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.74.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4a0d3c4: Durable background agent runs are robust again, and **on by default** for hosted apps.
8
+ - **Graceful inline fallback (the safety fix).** When the foreground turn can't
9
+ hand off to a background worker — the HMAC self-dispatch self-POST fails fast,
10
+ e.g. a connection error or a non-2xx returned within the settle window — the
11
+ agent-chat handler no longer breaks the chat with
12
+ `Failed to dispatch background run`. It now degrades to a normal synchronous
13
+ (inline) run, reusing the already-inserted run row. The run is claimed
14
+ atomically (`claimBackgroundRun`, a conditional `dispatch_mode: background →
15
+ background-processing` UPDATE) before running inline, so the SQL atomic claim
16
+ is the single owner — a delayed background delivery that arrives afterward
17
+ loses the claim and no-ops, and the run can never double-execute. A dispatch
18
+ that _did_ land (so a worker already owns the run) still streams the worker's
19
+ events instead of running a second copy.
20
+ - **Default-on, safely.** `AGENT_CHAT_DURABLE_BACKGROUND` is now opt-out for
21
+ hosted apps: unset/empty/unknown counts as enabled; opt a specific app back
22
+ out with an explicit falsy value (`false`/`0`/`no`/`off`). The gate still
23
+ composes with the existing guards, so a run only goes durable when the runtime
24
+ is hosted/serverless **and** `A2A_SECRET` is configured — local dev and
25
+ unconfigured apps stay on the synchronous inline path unchanged. Default-on is
26
+ safe precisely because a failed dispatch degrades to a working inline run. The
27
+ Netlify 15-min `-background` function emit (`isDurableBackgroundDeployEnabled`)
28
+ remains opt-in until its path is separately verified; with it off, the
29
+ default-on baseline runs the worker through the standard function and
30
+ server-chains continuations.
31
+ - **More diagnosable dispatch errors.** Self-dispatch failures now log the
32
+ resolved base URL so a failure tied to which host the self-POST targets
33
+ (custom domain vs deploy URL) is visible in logs. The URL resolution order is
34
+ unchanged (it matches the working A2A/agent-teams self-dispatch paths).
35
+
36
+ ### Patch Changes
37
+
38
+ - 4a0d3c4: Show numbered annotation markers in the annotated-code gutter, matching the diff
39
+ annotation affordance while preserving the hover popover behavior.
40
+ - 4a0d3c4: Clarify Builder code-change handoff fallbacks when cloud agents are unavailable.
41
+
42
+ ## 0.73.0
43
+
44
+ ### Minor Changes
45
+
46
+ - d684bbf: Durable background agent runs are now **on by default** for hosted apps. Previously the `AGENT_CHAT_DURABLE_BACKGROUND` flag was opt-in (off unless set truthy); it is now opt-out — unset means enabled, and an app disables it with an explicit falsy value (`AGENT_CHAT_DURABLE_BACKGROUND=false`).
47
+
48
+ The gate still composes with the existing guards, so a run only goes durable when the runtime is hosted/serverless **and** `A2A_SECRET` is configured — local dev and unconfigured apps stay on the synchronous inline path unchanged. Default-on uses the server-driven agnostic continuation path (verified in prod: long multi-step runs complete past the 40s soft-timeout with no thrash and no int4 overflow). The Netlify 15-min `-background` function emit (`isDurableBackgroundDeployEnabled`) remains opt-in until its path is separately verified.
49
+
50
+ ### Patch Changes
51
+
52
+ - d684bbf: Clarify the Clips "agent-readable clips" docs so the "see and hear" promise is
53
+ accurate: frame-viewing works in any image-capable agent (ChatGPT, Claude Code,
54
+ Cursor, Codex, MCP-connected agents), while text-only web chats fall back to the
55
+ transcript and can take an uploaded frame. Verified empirically — ChatGPT fetches
56
+ the JPEG frame URLs and describes the screen; claude.ai's web chat reads the
57
+ transcript only. Docs-only copy change; the agent-context/frame APIs are
58
+ unchanged.
59
+ - d684bbf: Add scaffold skill refresh commands for generated Agent Native apps and workspaces, plus public `@agent-native/skills` status/update forwarding.
60
+ - d684bbf: Redesign the Google sign-in preflight notice on the onboarding/sign-in screen
61
+ to match the in-app connect popover: an amber warning-icon chip beside a bold
62
+ heading and muted body copy, with the close affordance moved to the top-right.
63
+ The `googleSignInNotice.body` already accepts a string array, so reassurance
64
+ like "It's safe to continue." now renders on its own line. The Continue /
65
+ Run-locally action buttons no longer wrap their labels (`white-space: nowrap`).
66
+ Purely presentational — the host-gating, Continue, and Run-locally behaviors are
67
+ unchanged.
68
+ - d684bbf: Add a secondary hosted-app signup notice linking to the Agent-Native Terms and Privacy Policy.
69
+
3
70
  ## 0.72.4
4
71
 
5
72
  ### Patch Changes
@@ -264,3 +264,17 @@ npx @agent-native/core@latest skills update visual-plan
264
264
  the copied folder hash to the latest bundled skill, and rewrites stale folders in
265
265
  place. Newly copied Agent Native skills include an `agent-native-skill.json`
266
266
  marker so future status output can identify the source and hash.
267
+
268
+ Generated Agent Native apps and workspaces also include framework-provided
269
+ skills under `.agents/skills` (or `packages/shared/.agents/skills` in a
270
+ workspace). Refresh those scaffolded skills from the current/latest CLI with:
271
+
272
+ ```bash
273
+ npm run skills:update
274
+ # or, without relying on the local package script:
275
+ npx @agent-native/core@latest skills update scaffold --project
276
+ ```
277
+
278
+ `AGENTS.md` and `.agents/skills` stay canonical. The update command also repairs
279
+ Claude compatibility links (`CLAUDE.md` and `.claude/skills`) so Claude Code sees
280
+ the same instructions without maintaining a second copy.
@@ -15,7 +15,7 @@ A capture-everything app: screen recordings, meeting notes from your calendar, a
15
15
  }
16
16
  ```
17
17
 
18
- Think along the lines of Loom + Granola + Wispr Flow rolled into one app — but the agent is a first-class editor across every surface, and the recordings, meetings, and dictations are yours, not a SaaS vendor's. Clips also makes shared recordings agent-readable: paste a normal Clips share link into an agent, and it can "hear" the transcript and "see" timestamped frames even when the underlying model cannot ingest raw video or audio.
18
+ Think along the lines of Loom + Granola + Wispr Flow rolled into one app — but the agent is a first-class editor across every surface, and the recordings, meetings, and dictations are yours, not a SaaS vendor's. Clips also makes shared recordings agent-readable: paste a normal Clips share link into an agent and it can "hear" the transcript as text and "see" timestamped screen frames as images — no raw video needed. Frame-viewing works in any image-capable agent (ChatGPT, Claude Code, Cursor, Codex); text-only web chats still get the full transcript and can take a frame you upload.
19
19
 
20
20
  ```an-diagram title="Capture, transcribe, reuse" summary="Three capture types land in one library; the agent transcribes, titles, and summarizes, then every transcript is searchable and shareable."
21
21
  {
@@ -69,6 +69,12 @@ a compact agent context URL, and that context points to the transcript and frame
69
69
  APIs, so models that only accept text or still images can still understand what
70
70
  happened in the recording.
71
71
 
72
+ Any agent that can fetch an image URL into its vision — ChatGPT, Claude Code,
73
+ Cursor, Codex, and MCP-connected agents — reads the transcript and sees the
74
+ frames. A few text-only web chats read the transcript but won't pull frame images
75
+ in on their own; there, upload a key frame or open the clip in an image-capable
76
+ agent.
77
+
72
78
  | Endpoint | What agents get |
73
79
  | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
74
80
  | `/api/agent-context.json?id=<recordingId>` | Clip metadata, transcript status, chapters, CTAs, recommended frames, and links to the transcript/frame APIs |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.72.4",
3
+ "version": "0.74.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -17,12 +17,22 @@
17
17
  *
18
18
  * GUARDRAIL: when `isAgentChatDurableBackgroundEnabled()` returns false, the
19
19
  * agent-chat handler must behave byte-for-byte like the current synchronous
20
- * path. The flag is only ever true when ALL of these hold:
21
- * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is a truthy value.
20
+ * path. The gate is true only when ALL of these hold:
21
+ * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is not explicitly disabled. It is
22
+ * DEFAULT-ON: unset/empty/unknown counts as enabled; set it to a falsy
23
+ * value (`false`/`0`/`no`/`off`) to opt a specific app back out.
22
24
  * 2. The runtime is hosted/serverless (local dev keeps the inline path so SSE
23
25
  * stays a single live stream and no second function is needed).
24
26
  * 3. `A2A_SECRET` is configured (the HMAC handoff is required to authenticate
25
27
  * the background dispatch; without it the dispatch can't be trusted).
28
+ *
29
+ * Default-on is safe because a *dispatch failure degrades to an inline run*: if
30
+ * the self-dispatch self-POST can't be delivered (fast connection error or
31
+ * fast non-2xx), the foreground handler runs the turn synchronously instead of
32
+ * erroring (see `production-agent.ts` — the inline fallback claims the run row
33
+ * atomically so a delayed delivery can never double-execute). So an app where
34
+ * durable dispatch happens to fail still gets a working chat, just without the
35
+ * 15-min budget.
26
36
  */
27
37
  import {
28
38
  hasConfiguredA2ASecret,
@@ -41,7 +51,10 @@ import {
41
51
  export const AGENT_CHAT_PROCESS_RUN_PATH =
42
52
  "/_agent-native/agent-chat/_process-run";
43
53
 
44
- /** Env flag (off by default) that opts an app into durable background runs. */
54
+ /**
55
+ * Env flag for durable background runs. DEFAULT-ON: unset means enabled; an app
56
+ * opts OUT with an explicit falsy value (`false`/`0`/`no`/`off`).
57
+ */
45
58
  export const AGENT_CHAT_DURABLE_BACKGROUND_ENV =
46
59
  "AGENT_CHAT_DURABLE_BACKGROUND";
47
60
 
@@ -87,21 +100,31 @@ function isFlagEnabled(): boolean {
87
100
  // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials
88
101
  // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this
89
102
  // in sync with AGENT_CHAT_DURABLE_BACKGROUND_ENV.
103
+ //
104
+ // DEFAULT-ON: durable background runs are the desired behavior for every
105
+ // hosted app. So an unset/empty/unknown flag means ON; an app opts OUT only
106
+ // with an explicit falsy value. This still composes with the hosted +
107
+ // A2A_SECRET gates below, so non-hosted / unconfigured apps stay synchronous.
108
+ // Safety net: a failed dispatch degrades to a synchronous inline run (see
109
+ // production-agent.ts), so default-on cannot break chat even if the
110
+ // self-dispatch can't be delivered on a given app.
90
111
  const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;
91
- if (raw == null) return false;
112
+ if (raw == null) return true;
92
113
  const normalized = raw.trim().toLowerCase();
93
- return (
94
- normalized === "1" ||
95
- normalized === "true" ||
96
- normalized === "yes" ||
97
- normalized === "on"
114
+ return !(
115
+ normalized === "0" ||
116
+ normalized === "false" ||
117
+ normalized === "no" ||
118
+ normalized === "off"
98
119
  );
99
120
  }
100
121
 
101
122
  /**
102
- * The single gate. True only when the flag is on AND the runtime is hosted AND
103
- * A2A_SECRET is configured. False otherwise — and false means the current
104
- * synchronous behavior is used, unchanged.
123
+ * The single gate. True when the flag is not explicitly disabled (default-on)
124
+ * AND the runtime is hosted AND A2A_SECRET is configured. False otherwise — and
125
+ * false means the current synchronous behavior is used, unchanged. So a local /
126
+ * non-hosted / unconfigured app stays synchronous even with the flag defaulting
127
+ * on; durable only engages where the runtime actually supports it.
105
128
  */
106
129
  export function isAgentChatDurableBackgroundEnabled(): boolean {
107
130
  return (
@@ -4363,6 +4363,7 @@ export function createProductionAgentHandler(
4363
4363
  // change. With the flag OFF this whole branch is skipped and the inline
4364
4364
  // `startRun` path below runs exactly as before (byte-for-byte).
4365
4365
  if (dispatchToBackground) {
4366
+ let backgroundRowInserted = false;
4366
4367
  try {
4367
4368
  // Insert the run row up front so /runs/active sees it immediately and
4368
4369
  // the slot stays held while the background function cold-starts. Mark
@@ -4370,6 +4371,7 @@ export function createProductionAgentHandler(
4370
4371
  await insertRun(runId, effectiveThreadId, effectiveTurnId, {
4371
4372
  dispatchMode: "background",
4372
4373
  });
4374
+ backgroundRowInserted = true;
4373
4375
  } catch (err) {
4374
4376
  // A duplicate-PK collision means the row already exists (ret­ried POST);
4375
4377
  // any other failure means we can't safely hand off — fall back to the
@@ -4418,14 +4420,59 @@ export function createProductionAgentHandler(
4418
4420
  setResponseStatus(event, 500);
4419
4421
  return { error: "Failed to subscribe to background run" };
4420
4422
  }
4421
- // Dispatch failed before any worker could claim the run. Fail loud: flip
4422
- // the row terminal so the held slot is released (and any reconnect sees a
4423
- // terminal status instead of spinning), then 500 so the client can retry.
4424
- // We do NOT silently fall through to inline here that risks a later,
4425
- // delayed background delivery double-executing the same runId.
4426
- await updateRunStatusIfRunning(runId, "errored").catch(() => {});
4427
- setResponseStatus(event, 500);
4428
- return { error: "Failed to dispatch background run" };
4423
+
4424
+ // ─── Dispatch failed degrade to a normal synchronous (inline) run ────
4425
+ // `fireInternalDispatch` throws ONLY when the self-POST failed *fast*
4426
+ // (rejected the connection, or returned a non-2xx within the ~250ms settle
4427
+ // race). The `_process-run` route verifies the HMAC token and validates
4428
+ // the body BEFORE it ever reaches the SQL atomic claim, so a fast throw
4429
+ // means NO background worker claimed this run — there is nothing to
4430
+ // double-execute. Rather than break the chat with "Failed to dispatch
4431
+ // background run", we run the turn inline (the same synchronous path the
4432
+ // flag-off branch below takes), reusing the already-inserted run row.
4433
+ //
4434
+ // Safety against a (very improbable) delayed background delivery: claim the
4435
+ // run atomically here via `claimBackgroundRun`, which flips the row's
4436
+ // dispatch_mode `background → background-processing` in one conditional
4437
+ // UPDATE. If a delayed dispatch DID land and a worker already won the
4438
+ // claim, our claim returns false and we must NOT run inline (that would
4439
+ // double-execute) — fall back to subscribing to the worker's run instead.
4440
+ // The SQL atomic claim is the single source of truth for ownership, so at
4441
+ // most one of {inline fallback, background worker} ever executes this run.
4442
+ if (backgroundRowInserted) {
4443
+ let claimedInline = false;
4444
+ try {
4445
+ claimedInline = await claimBackgroundRun(runId);
4446
+ } catch (err) {
4447
+ console.error(
4448
+ "[agent-chat] inline-fallback claim failed:",
4449
+ err instanceof Error ? err.message : err,
4450
+ );
4451
+ }
4452
+ if (!claimedInline) {
4453
+ // A background worker already owns this run (a delayed delivery landed
4454
+ // after our fast throw). Stream its events instead of running a second
4455
+ // copy. If we somehow can't subscribe, surface an error rather than
4456
+ // risk a double-run.
4457
+ const stream = subscribeToRun(runId, 0);
4458
+ if (stream) {
4459
+ setResponseHeader(event, "Content-Type", "text/event-stream");
4460
+ setResponseHeader(event, "Cache-Control", "no-cache");
4461
+ setResponseHeader(event, "Connection", "keep-alive");
4462
+ setResponseHeader(event, "X-Run-Id", runId);
4463
+ return stream;
4464
+ }
4465
+ await updateRunStatusIfRunning(runId, "errored").catch(() => {});
4466
+ setResponseStatus(event, 500);
4467
+ return { error: "Failed to dispatch background run" };
4468
+ }
4469
+ // We own the run. `startRun` (below) calls `insertRun` again, but its
4470
+ // duplicate-PK collision is swallowed (`insertRun(...).catch(() => {})`),
4471
+ // so the existing `background-processing` row is reused — no double row.
4472
+ }
4473
+ // Fall through to the inline `startRun` path below (the same one the
4474
+ // flag-off branch uses). If the row was never inserted, `startRun` inserts
4475
+ // it fresh; if it was, the claim above made us the sole owner.
4429
4476
  }
4430
4477
 
4431
4478
  const trackedProgressOwner =
@@ -1893,7 +1893,7 @@ function copyDir(src: string, dest: string, root?: string): void {
1893
1893
 
1894
1894
  function shouldSkipScaffoldEntry(name: string, srcPath?: string): boolean {
1895
1895
  if (
1896
- name === "settings.json" &&
1896
+ /^settings(?:\..*)?\.json$/.test(name) &&
1897
1897
  srcPath?.split(path.sep).includes(".claude")
1898
1898
  ) {
1899
1899
  return true;