@agent-native/core 0.163.4 → 0.164.1

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 (200) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  3. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  4. package/corpus/templates/analytics/netlify.toml +2 -0
  5. package/corpus/templates/assets/netlify.toml +2 -0
  6. package/corpus/templates/brain/netlify.toml +2 -0
  7. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  8. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  9. package/corpus/templates/calendar/netlify.toml +2 -0
  10. package/corpus/templates/chat/netlify.toml +2 -0
  11. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  12. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  13. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  14. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  15. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  16. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  17. package/corpus/templates/clips/app/routes/_index.tsx +10 -2
  18. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  19. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  20. package/corpus/templates/clips/netlify.toml +2 -0
  21. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  22. package/corpus/templates/content/netlify.toml +2 -0
  23. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  24. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  25. package/corpus/templates/design/AGENTS.md +3 -1
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  27. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  28. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  29. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  30. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  31. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  32. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  33. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  34. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  35. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  36. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  37. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  38. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  39. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  40. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  41. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  42. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  43. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  44. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  45. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  46. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  47. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  48. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  49. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  50. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  51. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  52. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  53. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  54. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  55. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  56. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  126. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  127. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  128. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  129. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  130. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  131. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  132. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  133. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  134. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  135. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  136. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  137. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  138. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  139. package/corpus/templates/design/netlify.toml +2 -0
  140. package/corpus/templates/design/shared/board-file.ts +2 -1
  141. package/corpus/templates/dispatch/netlify.toml +2 -0
  142. package/corpus/templates/forms/netlify.toml +2 -0
  143. package/corpus/templates/mail/netlify.toml +2 -0
  144. package/corpus/templates/plan/netlify.toml +2 -0
  145. package/corpus/templates/slides/netlify.toml +2 -0
  146. package/dist/agent/engine/builder-engine.d.ts +6 -4
  147. package/dist/agent/engine/builder-engine.js +91 -26
  148. package/dist/agent/engine/registry.js +16 -0
  149. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  150. package/dist/cli/code-agent-agent-tools.js +188 -0
  151. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  152. package/dist/cli/code-agent-collaboration.js +104 -0
  153. package/dist/cli/code-agent-executor.js +6 -0
  154. package/dist/cli/code-agent-schedules.d.ts +54 -0
  155. package/dist/cli/code-agent-schedules.js +198 -0
  156. package/dist/client/AgentPanel.js +1 -1
  157. package/dist/client/ConnectBuilderCard.js +5 -2
  158. package/dist/client/EnvironmentBadge.js +6 -5
  159. package/dist/client/chat/run-recovery.js +3 -2
  160. package/dist/client/chat/tool-call-display.js +2 -3
  161. package/dist/client/components/CodeRequiredDialog.js +4 -2
  162. package/dist/client/i18n.js +5 -4
  163. package/dist/client/settings/SettingsPanel.js +1 -1
  164. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  165. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  166. package/dist/client/settings/useBuilderStatus.js +22 -33
  167. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  168. package/dist/code-agents/index.d.ts +2 -0
  169. package/dist/code-agents/index.js +2 -0
  170. package/dist/collab/routes.d.ts +1 -1
  171. package/dist/localization/shared.d.ts +2 -0
  172. package/dist/localization/shared.js +5 -0
  173. package/dist/mcp-client/oauth-client.d.ts +1 -0
  174. package/dist/mcp-client/oauth-client.js +50 -1
  175. package/dist/observability/routes.d.ts +1 -1
  176. package/dist/progress/routes.d.ts +1 -1
  177. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  178. package/dist/resources/handlers.d.ts +1 -1
  179. package/dist/server/auth-marketing-locales.d.ts +7 -0
  180. package/dist/server/auth-marketing-locales.js +1322 -0
  181. package/dist/server/auth-marketing.d.ts +1 -0
  182. package/dist/server/auth-marketing.js +35 -6
  183. package/dist/server/auth.js +4 -17
  184. package/dist/server/builder-browser.d.ts +22 -0
  185. package/dist/server/builder-browser.js +77 -1
  186. package/dist/server/builder-oauth.d.ts +50 -0
  187. package/dist/server/builder-oauth.js +263 -0
  188. package/dist/server/core-routes-plugin.d.ts +11 -0
  189. package/dist/server/core-routes-plugin.js +291 -415
  190. package/dist/server/credential-provider.d.ts +1 -1
  191. package/dist/server/credential-provider.js +1 -1
  192. package/dist/server/csrf.js +2 -2
  193. package/dist/server/onboarding-html.js +52 -120
  194. package/dist/settings/store.d.ts +9 -0
  195. package/dist/settings/store.js +19 -0
  196. package/dist/templates/chat/netlify.toml +2 -0
  197. package/docs/content/deployment.mdx +2 -0
  198. package/docs/content/multi-app-workspace.mdx +1 -1
  199. package/package.json +2 -2
  200. package/src/templates/chat/netlify.toml +2 -0
@@ -0,0 +1,198 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { codeAgentStoreRoot } from "./code-agent-runs.js";
5
+ const SCHEDULE_FILE_NAME = "schedules.json";
6
+ const MIN_INTERVAL_MINUTES = 1;
7
+ const MAX_INTERVAL_MINUTES = 31 * 24 * 60;
8
+ export function codeAgentSchedulesPath() {
9
+ return path.join(codeAgentStoreRoot(), SCHEDULE_FILE_NAME);
10
+ }
11
+ export function listCodeAgentSchedules() {
12
+ const records = readScheduleFile();
13
+ return records.sort((a, b) => {
14
+ if (a.enabled !== b.enabled)
15
+ return a.enabled ? -1 : 1;
16
+ return a.nextRunAt.localeCompare(b.nextRunAt);
17
+ });
18
+ }
19
+ export function getCodeAgentSchedule(scheduleId) {
20
+ return (readScheduleFile().find((schedule) => schedule.id === scheduleId) ?? null);
21
+ }
22
+ export function createCodeAgentSchedule(input) {
23
+ const name = normalizeRequiredText(input.name, "Schedule name");
24
+ const prompt = normalizeRequiredText(input.prompt, "Schedule prompt");
25
+ const scope = input.scope ?? "global";
26
+ if (scope !== "global" && scope !== "thread") {
27
+ throw new Error("Schedule scope must be global or thread.");
28
+ }
29
+ const targetRunId = normalizeOptionalText(input.targetRunId);
30
+ if (scope === "thread" && !targetRunId) {
31
+ throw new Error("Thread schedules require a target run.");
32
+ }
33
+ const intervalMinutes = normalizeIntervalMinutes(input.intervalMinutes);
34
+ const now = input.now ?? new Date();
35
+ const nowIso = now.toISOString();
36
+ const record = {
37
+ schemaVersion: 1,
38
+ id: `schedule-${timestampSlug(nowIso)}-${crypto.randomUUID().slice(0, 8)}`,
39
+ name,
40
+ prompt,
41
+ scope,
42
+ ...(targetRunId ? { targetRunId } : {}),
43
+ intervalMinutes,
44
+ enabled: input.enabled ?? true,
45
+ createdAt: nowIso,
46
+ updatedAt: nowIso,
47
+ nextRunAt: new Date(now.getTime() + intervalMinutes * 60_000).toISOString(),
48
+ ...(input.createdByRunId
49
+ ? { createdByRunId: normalizeOptionalText(input.createdByRunId) }
50
+ : {}),
51
+ };
52
+ writeScheduleFile([...readScheduleFile(), record]);
53
+ return record;
54
+ }
55
+ export function updateCodeAgentSchedule(scheduleId, input) {
56
+ const schedules = readScheduleFile();
57
+ const current = schedules.find((schedule) => schedule.id === scheduleId);
58
+ if (!current)
59
+ return null;
60
+ const nextScope = input.scope ?? current.scope;
61
+ if (nextScope !== "global" && nextScope !== "thread") {
62
+ throw new Error("Schedule scope must be global or thread.");
63
+ }
64
+ const nextTargetRunId = input.targetRunId === null
65
+ ? undefined
66
+ : normalizeOptionalText(input.targetRunId ?? current.targetRunId);
67
+ if (nextScope === "thread" && !nextTargetRunId) {
68
+ throw new Error("Thread schedules require a target run.");
69
+ }
70
+ const intervalChanged = input.intervalMinutes !== undefined;
71
+ const intervalMinutes = intervalChanged
72
+ ? normalizeIntervalMinutes(input.intervalMinutes)
73
+ : current.intervalMinutes;
74
+ const now = new Date();
75
+ const next = {
76
+ ...current,
77
+ ...(input.name !== undefined
78
+ ? { name: normalizeRequiredText(input.name, "Schedule name") }
79
+ : {}),
80
+ ...(input.prompt !== undefined
81
+ ? { prompt: normalizeRequiredText(input.prompt, "Schedule prompt") }
82
+ : {}),
83
+ scope: nextScope,
84
+ ...(nextTargetRunId ? { targetRunId: nextTargetRunId } : {}),
85
+ ...(nextTargetRunId ? {} : { targetRunId: undefined }),
86
+ intervalMinutes,
87
+ ...(input.enabled !== undefined ? { enabled: input.enabled } : {}),
88
+ updatedAt: now.toISOString(),
89
+ ...(intervalChanged
90
+ ? {
91
+ nextRunAt: new Date(now.getTime() + intervalMinutes * 60_000).toISOString(),
92
+ }
93
+ : {}),
94
+ };
95
+ writeScheduleFile(schedules.map((schedule) => (schedule.id === scheduleId ? next : schedule)));
96
+ return next;
97
+ }
98
+ export function deleteCodeAgentSchedule(scheduleId) {
99
+ const schedules = readScheduleFile();
100
+ const next = schedules.filter((schedule) => schedule.id !== scheduleId);
101
+ if (next.length === schedules.length)
102
+ return false;
103
+ writeScheduleFile(next);
104
+ return true;
105
+ }
106
+ export function markCodeAgentScheduleRun(scheduleId, patch) {
107
+ const schedules = readScheduleFile();
108
+ const current = schedules.find((schedule) => schedule.id === scheduleId);
109
+ if (!current)
110
+ return null;
111
+ const next = {
112
+ ...current,
113
+ updatedAt: new Date().toISOString(),
114
+ lastRunAt: patch.lastRunAt,
115
+ lastStatus: patch.lastStatus,
116
+ ...(patch.nextRunAt ? { nextRunAt: patch.nextRunAt } : {}),
117
+ ...(patch.lastError
118
+ ? { lastError: patch.lastError }
119
+ : { lastError: undefined }),
120
+ ...(patch.lastTriggeredRunId
121
+ ? { lastTriggeredRunId: patch.lastTriggeredRunId }
122
+ : {}),
123
+ };
124
+ writeScheduleFile(schedules.map((schedule) => (schedule.id === scheduleId ? next : schedule)));
125
+ return next;
126
+ }
127
+ export function isCodeAgentScheduleDue(schedule, now = new Date()) {
128
+ return schedule.enabled && Date.parse(schedule.nextRunAt) <= now.getTime();
129
+ }
130
+ export function nextCodeAgentScheduleRunAt(schedule, now = new Date()) {
131
+ const intervalMs = schedule.intervalMinutes * 60_000;
132
+ let next = Date.parse(schedule.nextRunAt);
133
+ if (!Number.isFinite(next))
134
+ next = now.getTime() + intervalMs;
135
+ while (next <= now.getTime())
136
+ next += intervalMs;
137
+ return new Date(next).toISOString();
138
+ }
139
+ function readScheduleFile() {
140
+ try {
141
+ const raw = JSON.parse(fs.readFileSync(codeAgentSchedulesPath(), "utf8"));
142
+ if (!Array.isArray(raw))
143
+ return [];
144
+ return raw.filter(isScheduleRecord);
145
+ }
146
+ catch {
147
+ return [];
148
+ }
149
+ }
150
+ function writeScheduleFile(records) {
151
+ const filePath = codeAgentSchedulesPath();
152
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
153
+ const tempPath = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
154
+ fs.writeFileSync(tempPath, `${JSON.stringify(records, null, 2)}\n`);
155
+ fs.renameSync(tempPath, filePath);
156
+ }
157
+ function isScheduleRecord(value) {
158
+ if (!value || typeof value !== "object")
159
+ return false;
160
+ const record = value;
161
+ return (record.schemaVersion === 1 &&
162
+ typeof record.id === "string" &&
163
+ typeof record.name === "string" &&
164
+ typeof record.prompt === "string" &&
165
+ (record.scope === "global" || record.scope === "thread") &&
166
+ (record.scope !== "thread" || typeof record.targetRunId === "string") &&
167
+ typeof record.intervalMinutes === "number" &&
168
+ record.intervalMinutes >= MIN_INTERVAL_MINUTES &&
169
+ record.intervalMinutes <= MAX_INTERVAL_MINUTES &&
170
+ typeof record.enabled === "boolean" &&
171
+ typeof record.createdAt === "string" &&
172
+ typeof record.updatedAt === "string" &&
173
+ typeof record.nextRunAt === "string");
174
+ }
175
+ function normalizeRequiredText(value, label) {
176
+ const normalized = typeof value === "string" ? value.trim() : "";
177
+ if (!normalized)
178
+ throw new Error(`${label} is required.`);
179
+ return normalized.slice(0, 8_000);
180
+ }
181
+ function normalizeOptionalText(value) {
182
+ if (typeof value !== "string")
183
+ return undefined;
184
+ const normalized = value.trim();
185
+ return normalized ? normalized.slice(0, 256) : undefined;
186
+ }
187
+ function normalizeIntervalMinutes(value) {
188
+ const interval = Number(value);
189
+ if (!Number.isInteger(interval) ||
190
+ interval < MIN_INTERVAL_MINUTES ||
191
+ interval > MAX_INTERVAL_MINUTES) {
192
+ throw new Error(`Interval must be a whole number between ${MIN_INTERVAL_MINUTES} minute and ${MAX_INTERVAL_MINUTES / (24 * 60)} days.`);
193
+ }
194
+ return interval;
195
+ }
196
+ function timestampSlug(value) {
197
+ return value.replace(/[-:.TZ]/g, "").slice(0, 14);
198
+ }
@@ -310,7 +310,7 @@ function useBuilderConnectUrl() {
310
310
  .then((data) => {
311
311
  if (cancelled || !data)
312
312
  return;
313
- const nextConnectUrl = data.cliAuthUrl || data.connectUrl;
313
+ const nextConnectUrl = data.connectUrl;
314
314
  if (nextConnectUrl)
315
315
  setConnectUrl(nextConnectUrl);
316
316
  const nextConfigured = !!data.configured;
@@ -42,6 +42,9 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
42
42
  // arrives. A transient status failure must not replace a valid Send CTA with
43
43
  // the hook's initial disconnected defaults.
44
44
  const configured = flow.statusResolved ? flow.configured : initialConfigured;
45
+ const codeChangeConfigured = flow.statusResolved
46
+ ? flow.codeChangeConfigured
47
+ : initialConfigured;
45
48
  const builderEnabled = flow.statusResolved
46
49
  ? flow.builderEnabled
47
50
  : initialBuilderEnabled;
@@ -162,7 +165,7 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
162
165
  // Combine connect-flow errors, send errors, waitlist errors, and copy errors.
163
166
  const err = sendErr ?? waitlistErr ?? copyErr ?? flow.error;
164
167
  const hasPrompt = prompt.trim().length > 0;
165
- const canSend = configured && builderEnabled && hasPrompt;
168
+ const canSend = codeChangeConfigured && builderEnabled && hasPrompt;
166
169
  const showDesktopLocalHandoff = electronShell && hasPrompt;
167
170
  const handleDoLocally = useCallback((event) => {
168
171
  if (requestDesktopLocalCodeChange(prompt, event.currentTarget)) {
@@ -191,7 +194,7 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
191
194
  const showWaitlist = !localDevelopment && !builderEnabled && hasPrompt;
192
195
  // Title + subtitle depend on which mode we're in. We compute them up front
193
196
  // so the render tree below stays flat.
194
- const connectedCapabilityText = builderEnabled
197
+ const connectedCapabilityText = builderEnabled && codeChangeConfigured
195
198
  ? "AI credits and cloud code changes are ready to use."
196
199
  : `AI credits are ready to use. ${CODE_CHANGE_FALLBACK_TEXT}`;
197
200
  let title;
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button } from "@agent-native/toolkit/ui/button";
3
3
  import { Popover, PopoverContent, PopoverTrigger, } from "@agent-native/toolkit/ui/popover";
4
- import { IconExternalLink, IconGitBranch } from "@tabler/icons-react";
5
4
  import { useEffect, useMemo, useRef } from "react";
6
5
  import { trackEvent } from "./analytics.js";
7
6
  import { injectedAgentNativeConfig } from "./app-config.js";
@@ -132,7 +131,7 @@ function consumeBetaOptOutQueryParam(sourceHref, now = Date.now()) {
132
131
  return active;
133
132
  }
134
133
  function EnvironmentLink({ label, href }) {
135
- return (_jsx(Button, { asChild: true, className: "w-full justify-start px-2", size: "sm", variant: "ghost", children: _jsxs("a", { href: href, children: [_jsx(IconExternalLink, { "aria-hidden": "true" }), label] }) }));
134
+ return (_jsx(Button, { asChild: true, className: "w-full justify-center", size: "sm", variant: "outline", children: _jsx("a", { href: href, children: label }) }));
136
135
  }
137
136
  /**
138
137
  * Small internal-only lane switcher for first-party hosted Agent-Native apps.
@@ -159,7 +158,6 @@ export function EnvironmentBadge() {
159
158
  didAutoRedirect.current) {
160
159
  return;
161
160
  }
162
- didAutoRedirect.current = true;
163
161
  if (readBetaOptOutUntil() !== null)
164
162
  return;
165
163
  if (consumeBetaOptOutQueryParam(window.location.href))
@@ -167,6 +165,7 @@ export function EnvironmentBadge() {
167
165
  const betaHref = buildEnvironmentUrl(window.location.href, targets.betaHost);
168
166
  if (!betaHref || typeof window.location.replace !== "function")
169
167
  return;
168
+ didAutoRedirect.current = true;
170
169
  trackEvent("environment switched", {
171
170
  from_environment: "production",
172
171
  to_environment: "beta",
@@ -186,6 +185,8 @@ export function EnvironmentBadge() {
186
185
  if (!betaHref || !productionHref)
187
186
  return null;
188
187
  const label = environment === "beta" ? "beta" : "prod";
189
- const title = environment === "beta" ? "Beta environment" : "Production environment";
190
- return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: "fixed bottom-3 right-3 z-[100] h-7 rounded-full border-border/80 bg-background/95 px-2.5 text-[11px] font-semibold uppercase tracking-[0.12em] shadow-sm backdrop-blur-sm", size: "sm", variant: environment === "beta" ? "secondary" : "outline", children: [_jsx("span", { "aria-hidden": "true", className: `size-1.5 rounded-full ${environment === "beta" ? "bg-primary" : "bg-muted-foreground"}` }), label] }) }), _jsxs(PopoverContent, { align: "end", className: "w-64 p-3", side: "top", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2 text-sm font-medium", children: [_jsx(IconGitBranch, { "aria-hidden": "true", className: "size-4 text-muted-foreground" }), title] }), _jsx("div", { className: "grid gap-1", children: environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Go to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })) })] })] }));
188
+ const title = environment === "beta"
189
+ ? "You're on Agent Native Beta"
190
+ : "You're on Agent Native Production";
191
+ return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: "fixed bottom-3 right-3 z-[100] h-6 min-w-0 rounded-xl border-border/80 bg-background/95 px-2 text-[11px] font-semibold uppercase tracking-[0.5px] shadow-sm backdrop-blur-sm", size: "sm", variant: environment === "beta" ? "default" : "outline", children: label }) }), _jsxs(PopoverContent, { align: "center", className: "w-[280px] p-5", side: "top", sideOffset: 8, children: [_jsx("div", { className: "mb-1 text-sm font-semibold leading-5", children: title }), _jsx("div", { className: "mb-4 text-sm text-muted-foreground", children: "Choose where you want to continue." }), _jsx("div", { className: "grid gap-2", children: environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Switch to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })) })] })] }));
191
192
  }
@@ -114,7 +114,7 @@ function isConnectionRecoveryRunError(info) {
114
114
  }
115
115
  // ─── BuilderConnectCta ────────────────────────────────────────────────────────
116
116
  // Renders a single row with left-aligned copy and a right-aligned action.
117
- // Click opens the Builder CLI-auth popup via the shared
117
+ // Click opens the Builder OAuth popup via the shared
118
118
  // `useBuilderConnectFlow` hook (which owns the synchronous window.open,
119
119
  // the 2s status poll, and the focus-refresh). On success the hook broadcasts
120
120
  // a config-change event so the chat clears its local `missingApiKey` gate.
@@ -238,8 +238,9 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
238
238
  }, [onDismiss]);
239
239
  const handleProviderConnected = useCallback(() => {
240
240
  onProviderConnected?.();
241
+ onRetry();
241
242
  onDismiss();
242
- }, [onDismiss, onProviderConnected]);
243
+ }, [onDismiss, onProviderConnected, onRetry]);
243
244
  const handleFork = useCallback(async () => {
244
245
  if (!onFork || forking)
245
246
  return;
@@ -337,9 +337,8 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
337
337
  const parsed = JSON.parse(result);
338
338
  if (parsed?.kind === "connect-builder-card") {
339
339
  return (_jsx(ConnectBuilderCard, { configured: !!parsed.configured, builderEnabled: parsed.builderEnabled !== false,
340
- // Ignore saved cliAuthUrl values from older tool results. They
341
- // contain signed callback state and can expire while a chat sits
342
- // open; the card's hook fetches a fresh signed URL on mount/click.
340
+ // Ignore obsolete direct-auth URLs from older tool results. The
341
+ // card fetches a fresh app-local connect URL on mount and click.
343
342
  connectUrl: parsed.connectUrl || "", orgName: parsed.orgName ?? null, prompt: typeof parsed.prompt === "string" ? parsed.prompt : "" }));
344
343
  }
345
344
  }
@@ -17,8 +17,10 @@ function useBuilderConnected() {
17
17
  .then((data) => {
18
18
  if (data) {
19
19
  setConnected(!!data.configured);
20
- setCloudAgentsAvailable(!!data.builderEnabled);
21
- setConnectUrl(data.cliAuthUrl || data.connectUrl || null);
20
+ setCloudAgentsAvailable(!!data.builderEnabled &&
21
+ !!data.privateKeyConfigured &&
22
+ !!data.publicKeyConfigured);
23
+ setConnectUrl(data.connectUrl || null);
22
24
  }
23
25
  })
24
26
  .catch(() => { });
@@ -7,7 +7,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use
7
7
  import { I18nextProvider, initReactI18next, useTranslation, } from "react-i18next";
8
8
  import { coreMessagesForLocale, englishAgentChatMessages, loadCoreMessagesForLocale, normalizeCoreMessageOverrides, } from "../localization/core-messages.js";
9
9
  import defaultEnglishMessages from "../localization/default-messages.js";
10
- import { DEFAULT_LOCALE, LOCALE_HYDRATION_GLOBAL, LOCALE_METADATA, LOCALE_STORAGE_KEY, SUPPORTED_LOCALES, localeDirection, normalizeLocalizationPreference, resolveLocaleFromCandidates, resolveLocaleFromPreference, } from "../localization/shared.js";
10
+ import { DEFAULT_LOCALE, LOCALE_HYDRATION_GLOBAL, LOCALE_METADATA, LOCALE_STORAGE_KEY, SUPPORTED_LOCALES, localeDisplayName, localeDirection, normalizeLocalizationPreference, resolveLocaleFromCandidates, resolveLocaleFromPreference, } from "../localization/shared.js";
11
11
  import { injectedAgentNativeConfig } from "./app-config.js";
12
12
  import { setClientAppState } from "./application-state.js";
13
13
  import { callAction } from "./use-action.js";
@@ -603,20 +603,21 @@ export function LanguagePicker({ className, includeSystem = true, label, variant
603
603
  const { locale, preference, setPreference, supportedLocales } = useLocale();
604
604
  const [open, setOpen] = useState(false);
605
605
  const copy = LANGUAGE_PICKER_COPY[locale] ?? LANGUAGE_PICKER_COPY[DEFAULT_LOCALE];
606
+ const systemCopy = LANGUAGE_PICKER_COPY[resolveLocaleFromCandidates(browserLanguageCandidates())] ?? LANGUAGE_PICKER_COPY[DEFAULT_LOCALE];
606
607
  const resolvedLabel = label ?? copy.label;
607
608
  const options = [
608
609
  ...(includeSystem
609
610
  ? [
610
611
  {
611
612
  value: "system",
612
- label: copy.system,
613
- description: copy.systemDescription,
613
+ label: systemCopy.system,
614
+ description: systemCopy.systemDescription,
614
615
  },
615
616
  ]
616
617
  : []),
617
618
  ...supportedLocales.map((code) => ({
618
619
  value: code,
619
- label: `${LOCALE_METADATA[code].nativeName} (${code})`,
620
+ label: localeDisplayName(code),
620
621
  description: code,
621
622
  })),
622
623
  ];
@@ -1060,7 +1060,7 @@ function SettingsPanelContent({ isDevMode, initialSection, sectionRequestKey, se
1060
1060
  enabled: !builderConnectionOwnedExternally,
1061
1061
  });
1062
1062
  const connected = builder?.configured ?? false;
1063
- const connectUrl = builder?.cliAuthUrl ?? builder?.connectUrl;
1063
+ const connectUrl = builder?.connectUrl;
1064
1064
  const orgName = builder?.orgName;
1065
1065
  const envManaged = !!builder?.envManaged;
1066
1066
  const credentialSource = builder?.credentialSource;
@@ -247,7 +247,7 @@ export function VoiceTranscriptionSection({ compact = false, } = {}) {
247
247
  };
248
248
  const openBuilderConnect = () => {
249
249
  openBuilderConnectPopup({
250
- url: builderStatus?.cliAuthUrl ?? builderStatus?.connectUrl,
250
+ url: builderStatus?.connectUrl,
251
251
  source: "voice_transcription_settings",
252
252
  features: "noopener,noreferrer,width=600,height=700",
253
253
  });
@@ -9,7 +9,6 @@ export interface BuilderStatus {
9
9
  envManaged?: boolean;
10
10
  credentialSource?: "user" | "org" | "workspace" | "env";
11
11
  connectUrl: string;
12
- cliAuthUrl?: string;
13
12
  appHost: string;
14
13
  apiHost: string;
15
14
  branchProjectIdConfigured?: boolean;
@@ -98,6 +97,12 @@ export interface BuilderConnectFlow {
98
97
  * Builder account.
99
98
  */
100
99
  envManaged: boolean;
100
+ /**
101
+ * True when legacy Builder private/public keys are present. Cloud code-change
102
+ * routes (`/builder/run`, `/builder/agents-run`) still require those keys;
103
+ * OAuth `configured` only covers the chat gateway.
104
+ */
105
+ codeChangeConfigured: boolean;
101
106
  /**
102
107
  * True when the server has a Builder branch project configured for this
103
108
  * request. When false, the card surfaces a waitlist CTA instead of a Send
@@ -88,7 +88,6 @@ const STATUS_FETCH_ABORT_MS = 10_000;
88
88
  const CALLBACK_SUCCESS_STATUS_RETRY_MS = 500;
89
89
  const CALLBACK_SUCCESS_STATUS_RETRIES = 10;
90
90
  const BUILDER_CONNECT_PARAM = "_an_connect";
91
- const BUILDER_STATE_PARAM = "_an_state";
92
91
  const BUILDER_SIGNUP_SOURCE_PARAM = "signupSource";
93
92
  const BUILDER_AGENT_NATIVE_FLOW_PARAM = "agentNativeFlow";
94
93
  const BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = "agentNativeConnectSource";
@@ -214,22 +213,8 @@ function hasSignedConnectToken(url) {
214
213
  return false;
215
214
  }
216
215
  }
217
- function hasSignedCallbackState(url) {
218
- if (!url || typeof window === "undefined")
219
- return false;
220
- try {
221
- const parsed = new URL(url, window.location.origin);
222
- const redirectUrl = parsed.searchParams.get("redirect_url");
223
- if (!redirectUrl)
224
- return false;
225
- return new URL(redirectUrl).searchParams.has(BUILDER_STATE_PARAM);
226
- }
227
- catch {
228
- return false;
229
- }
230
- }
231
216
  function isFreshSignedConnectUrl(url, fetchedAt) {
232
- return ((hasSignedConnectToken(url) || hasSignedCallbackState(url)) &&
217
+ return (hasSignedConnectToken(url) &&
233
218
  typeof fetchedAt === "number" &&
234
219
  Date.now() - fetchedAt < STATUS_CONNECT_URL_TTL_MS);
235
220
  }
@@ -240,6 +225,9 @@ function isCurrentConnectError(error, startedAt) {
240
225
  return true;
241
226
  return typeof error.at !== "number" || error.at >= startedAt - 1000;
242
227
  }
228
+ function isCodeChangeConfigured(status) {
229
+ return !!status?.privateKeyConfigured && !!status?.publicKeyConfigured;
230
+ }
243
231
  function showBuilderConnectPopupPlaceholder(opened) {
244
232
  // Keep opener attached: the Builder callback uses postMessage to notify the
245
233
  // settings tab that the popup completed. We still hold the WindowProxy so the
@@ -379,6 +367,7 @@ export function openBuilderConnectPopup({ url, source = "builder_connect", flow,
379
367
  export function useBuilderConnectFlow(opts = {}) {
380
368
  const { enabled = true, popupUrl, trackingSource = "builder_connect_flow", trackingFlow, onConnected, } = opts;
381
369
  const [configured, setConfigured] = useState(false);
370
+ const [codeChangeConfigured, setCodeChangeConfigured] = useState(false);
382
371
  const [envManaged, setEnvManaged] = useState(false);
383
372
  const [builderEnabled, setBuilderEnabled] = useState(false);
384
373
  const [orgName, setOrgName] = useState(null);
@@ -445,6 +434,7 @@ export function useBuilderConnectFlow(opts = {}) {
445
434
  useEffect(() => {
446
435
  if (!enabled) {
447
436
  setConfigured(false);
437
+ setCodeChangeConfigured(false);
448
438
  setEnvManaged(false);
449
439
  setBuilderEnabled(false);
450
440
  setOrgName(null);
@@ -470,9 +460,10 @@ export function useBuilderConnectFlow(opts = {}) {
470
460
  return;
471
461
  setStatusResolved(true);
472
462
  setConfigured(!!s.configured);
463
+ setCodeChangeConfigured(isCodeChangeConfigured(s));
473
464
  setEnvManaged(!!s.envManaged);
474
465
  setBuilderEnabled(!!s.builderEnabled);
475
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
466
+ const nextConnectUrl = s.connectUrl ?? null;
476
467
  setStatusConnectUrl(nextConnectUrl);
477
468
  statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;
478
469
  const org = s.orgName ?? null;
@@ -548,11 +539,8 @@ export function useBuilderConnectFlow(opts = {}) {
548
539
  // server/package restart cannot leave the user with a stale signed state.
549
540
  // Desktop keeps the direct path because the Electron shell owns the popup.
550
541
  const signedPropUrl = hasSignedConnectToken(popupUrl) ? popupUrl : null;
551
- const signedCliPropUrl = hasSignedCallbackState(popupUrl)
552
- ? popupUrl
553
- : null;
554
542
  const fallbackUrl = new URL(agentNativePath("/_agent-native/builder/connect"), origin).href;
555
- const directUrl = cachedFreshUrl ?? signedCliPropUrl ?? signedPropUrl ?? fallbackUrl;
543
+ const directUrl = cachedFreshUrl ?? signedPropUrl ?? fallbackUrl;
556
544
  if (isAgentNativeDesktop()) {
557
545
  const opened = openBuilderConnectPopup({
558
546
  url: directUrl,
@@ -586,16 +574,17 @@ export function useBuilderConnectFlow(opts = {}) {
586
574
  setHasFetchedStatus(true);
587
575
  setStatusResolved(true);
588
576
  setConfigured(!!s.configured);
577
+ setCodeChangeConfigured(isCodeChangeConfigured(s));
589
578
  setEnvManaged(!!s.envManaged);
590
579
  setBuilderEnabled(!!s.builderEnabled);
591
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
580
+ const nextConnectUrl = s.connectUrl ?? null;
592
581
  setStatusConnectUrl(nextConnectUrl);
593
582
  statusConnectUrlAtRef.current = nextConnectUrl
594
583
  ? Date.now()
595
584
  : null;
596
585
  setOrgName(s.orgName ?? null);
597
586
  }
598
- const hostUrl = s?.cliAuthUrl ?? s?.connectUrl ?? cachedFreshUrl ?? directUrl;
587
+ const hostUrl = s?.connectUrl ?? cachedFreshUrl ?? directUrl;
599
588
  const trackedHostUrl = withBuilderConnectTrackingParams(hostUrl, {
600
589
  source: clickTrackingSource,
601
590
  flow: clickTrackingFlow,
@@ -625,9 +614,10 @@ export function useBuilderConnectFlow(opts = {}) {
625
614
  setHasFetchedStatus(true);
626
615
  setStatusResolved(true);
627
616
  setConfigured(!!s.configured);
617
+ setCodeChangeConfigured(isCodeChangeConfigured(s));
628
618
  setEnvManaged(!!s.envManaged);
629
619
  setBuilderEnabled(!!s.builderEnabled);
630
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
620
+ const nextConnectUrl = s.connectUrl ?? null;
631
621
  setStatusConnectUrl(nextConnectUrl);
632
622
  statusConnectUrlAtRef.current = nextConnectUrl
633
623
  ? Date.now()
@@ -638,12 +628,7 @@ export function useBuilderConnectFlow(opts = {}) {
638
628
  // already rendered into the CTA as a fallback. This avoids closing
639
629
  // the popup when the refresh hits a transient 401/HTML/error
640
630
  // response before the status cache has warmed.
641
- const freshUrl = s?.cliAuthUrl ??
642
- s?.connectUrl ??
643
- cachedFreshUrl ??
644
- signedCliPropUrl ??
645
- signedPropUrl ??
646
- fallbackUrl;
631
+ const freshUrl = s?.connectUrl ?? cachedFreshUrl ?? signedPropUrl ?? fallbackUrl;
647
632
  if (!freshUrl) {
648
633
  try {
649
634
  opened.close();
@@ -691,9 +676,10 @@ export function useBuilderConnectFlow(opts = {}) {
691
676
  setStatusResolved(true);
692
677
  if (s?.configured) {
693
678
  setConfigured(true);
679
+ setCodeChangeConfigured(isCodeChangeConfigured(s));
694
680
  setEnvManaged(!!s.envManaged);
695
681
  setBuilderEnabled(!!s.builderEnabled);
696
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
682
+ const nextConnectUrl = s.connectUrl ?? null;
697
683
  setStatusConnectUrl(nextConnectUrl);
698
684
  statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;
699
685
  const org = s.orgName ?? null;
@@ -775,9 +761,10 @@ export function useBuilderConnectFlow(opts = {}) {
775
761
  if (s) {
776
762
  setStatusResolved(true);
777
763
  setConfigured(false);
764
+ setCodeChangeConfigured(false);
778
765
  setEnvManaged(!!s.envManaged);
779
766
  setBuilderEnabled(!!s.builderEnabled);
780
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
767
+ const nextConnectUrl = s.connectUrl ?? null;
781
768
  setStatusConnectUrl(nextConnectUrl);
782
769
  statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;
783
770
  setOrgName(s.orgName ?? null);
@@ -792,9 +779,10 @@ export function useBuilderConnectFlow(opts = {}) {
792
779
  setHasFetchedStatus(true);
793
780
  setStatusResolved(true);
794
781
  setConfigured(true);
782
+ setCodeChangeConfigured(isCodeChangeConfigured(s));
795
783
  setEnvManaged(!!s.envManaged);
796
784
  setBuilderEnabled(!!s.builderEnabled);
797
- const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;
785
+ const nextConnectUrl = s.connectUrl ?? null;
798
786
  setStatusConnectUrl(nextConnectUrl);
799
787
  statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;
800
788
  const org = s.orgName ?? null;
@@ -850,6 +838,7 @@ export function useBuilderConnectFlow(opts = {}) {
850
838
  }, [fetchStatus]);
851
839
  return {
852
840
  configured,
841
+ codeChangeConfigured,
853
842
  statusResolved,
854
843
  envManaged,
855
844
  builderEnabled,
@@ -31,7 +31,7 @@ export function BuilderTranscriptionCta() {
31
31
  // Env-managed mode counts as configured for the CTA — the deploy
32
32
  // already routes transcription through Builder, no per-user prompt.
33
33
  setConfigured(!!(s?.configured || s?.envManaged));
34
- setConnectUrl(s?.cliAuthUrl || s?.connectUrl || null);
34
+ setConnectUrl(s?.connectUrl || null);
35
35
  })
36
36
  .catch(() => {
37
37
  if (mountedRef.current)
@@ -6,3 +6,5 @@ export { escapePromptAttachmentAttribute, formatPromptWithAttachments, type Agen
6
6
  export { CODE_AGENT_PERMISSION_MODES, appendCodeAgentTranscriptEvent, codeAgentRunArtifactsDir, codeAgentRunTranscriptPath, codeAgentRunsDir, codeAgentStoreRoot, codeAgentTranscriptsDir, createCodeAgentRunRecord, getCodeAgentRunRecord, getLastCodeAgentRunRecord, isActiveCodeAgentRun, listCodeAgentRunRecords, listCodeAgentTranscriptEvents, normalizeCodeAgentPermissionMode, queueCodeAgentFollowUp, updateCodeAgentRunRecord, type AppendCodeAgentTranscriptEventInput, type CodeAgentPermissionMode, type CodeAgentRunDetail, type CodeAgentRunProgress, type CodeAgentRunRecord, type CodeAgentRunStatus, type CodeAgentTranscriptEvent, type CodeAgentTranscriptEventKind, type CreateCodeAgentRunInput, type CodeAgentFollowUpMode, type QueueCodeAgentFollowUpInput, } from "../cli/code-agent-runs.js";
7
7
  export { findProjectSlashCommand, isReservedProjectSlashCommandName, listProjectSkills, listProjectSlashCommands, listVisibleProjectSlashCommands, readProjectCodePack, renderProjectSlashCommandPrompt, type CodeAgentCodePack, type CodeAgentProjectCommand, type CodeAgentProjectSkill, type ReadProjectCodePackOptions, } from "../cli/code-agent-commands.js";
8
8
  export { executeCodeAgentRun, executeExistingCodeAgentRun, executePendingCodeAgentApproval, type ExecuteCodeAgentRunOptions, } from "../cli/code-agent-executor.js";
9
+ export { codeAgentSchedulesPath, createCodeAgentSchedule, deleteCodeAgentSchedule, getCodeAgentSchedule, isCodeAgentScheduleDue, listCodeAgentSchedules, markCodeAgentScheduleRun, nextCodeAgentScheduleRunAt, updateCodeAgentSchedule, type CodeAgentScheduleRecord, type CodeAgentScheduleRunPatch, type CodeAgentScheduleScope, type CodeAgentScheduleStatus, type CreateCodeAgentScheduleInput, type UpdateCodeAgentScheduleInput, } from "../cli/code-agent-schedules.js";
10
+ export { createCodeAgentThread, listCodeAgentThreadSummaries, messageCodeAgentThread, type CodeAgentThreadSummary, type CreateCodeAgentThreadInput, type CreateCodeAgentThreadResult, type MessageCodeAgentThreadInput, type MessageCodeAgentThreadResult, } from "../cli/code-agent-collaboration.js";
@@ -6,3 +6,5 @@ export { escapePromptAttachmentAttribute, formatPromptWithAttachments, } from ".
6
6
  export { CODE_AGENT_PERMISSION_MODES, appendCodeAgentTranscriptEvent, codeAgentRunArtifactsDir, codeAgentRunTranscriptPath, codeAgentRunsDir, codeAgentStoreRoot, codeAgentTranscriptsDir, createCodeAgentRunRecord, getCodeAgentRunRecord, getLastCodeAgentRunRecord, isActiveCodeAgentRun, listCodeAgentRunRecords, listCodeAgentTranscriptEvents, normalizeCodeAgentPermissionMode, queueCodeAgentFollowUp, updateCodeAgentRunRecord, } from "../cli/code-agent-runs.js";
7
7
  export { findProjectSlashCommand, isReservedProjectSlashCommandName, listProjectSkills, listProjectSlashCommands, listVisibleProjectSlashCommands, readProjectCodePack, renderProjectSlashCommandPrompt, } from "../cli/code-agent-commands.js";
8
8
  export { executeCodeAgentRun, executeExistingCodeAgentRun, executePendingCodeAgentApproval, } from "../cli/code-agent-executor.js";
9
+ export { codeAgentSchedulesPath, createCodeAgentSchedule, deleteCodeAgentSchedule, getCodeAgentSchedule, isCodeAgentScheduleDue, listCodeAgentSchedules, markCodeAgentScheduleRun, nextCodeAgentScheduleRunAt, updateCodeAgentSchedule, } from "../cli/code-agent-schedules.js";
10
+ export { createCodeAgentThread, listCodeAgentThreadSummaries, messageCodeAgentThread, } from "../cli/code-agent-collaboration.js";
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- error: string;
30
29
  ok?: undefined;
30
+ error: string;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -29,6 +29,8 @@ export declare const LOCALIZATION_SETTING_KEY = "localization";
29
29
  export declare const LOCALE_STORAGE_KEY = "agent-native:locale-preference";
30
30
  export declare const LOCALE_HYDRATION_GLOBAL = "__AGENT_NATIVE_LOCALE__";
31
31
  export declare const LOCALE_METADATA: Record<LocaleCode, LocaleMetadata>;
32
+ /** Return the short native language name used in compact locale pickers. */
33
+ export declare function localeDisplayName(locale: LocaleCode): string;
32
34
  export declare function isLocaleCode(value: unknown): value is LocaleCode;
33
35
  export declare function normalizeLocaleCode(value: unknown): LocaleCode | null;
34
36
  export declare function normalizeLocalePreference(value: unknown): LocalePreference | null;
@@ -83,6 +83,11 @@ export const LOCALE_METADATA = {
83
83
  dir: "rtl",
84
84
  },
85
85
  };
86
+ /** Return the short native language name used in compact locale pickers. */
87
+ export function localeDisplayName(locale) {
88
+ const nativeName = LOCALE_METADATA[locale]?.nativeName ?? locale;
89
+ return nativeName.split("(", 1)[0]?.trim() || nativeName;
90
+ }
86
91
  const SUPPORTED_LOCALE_SET = new Set(SUPPORTED_LOCALES);
87
92
  const CHINESE_LOCALE_ALIASES = {
88
93
  "zh-cn": "zh-CN",
@@ -70,6 +70,7 @@ export declare class McpOAuthClientProvider implements OAuthClientProvider {
70
70
  get savedCodeVerifierValue(): string | undefined;
71
71
  get savedTokensValue(): OAuthTokens | undefined;
72
72
  get savedClientInformation(): StoredOAuthClientInformation | undefined;
73
+ validateResourceURL(defaultResource: string | URL, advertised?: string): Promise<URL | undefined>;
73
74
  }
74
75
  export declare function startMcpOAuthAuthorization(options: McpOAuthProviderOptions & {
75
76
  scope?: string;