@agent-native/core 0.112.0 → 0.114.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 (1902) hide show
  1. package/agent-native.eject.json +164 -0
  2. package/corpus/README.md +4 -2
  3. package/corpus/core/CHANGELOG.md +33 -0
  4. package/corpus/core/README.md +61 -174
  5. package/corpus/core/agent-native.eject.json +164 -0
  6. package/corpus/core/docs/AGENTS.md +7 -0
  7. package/corpus/core/docs/content/agent-native-toolkit.mdx +38 -0
  8. package/corpus/core/docs/content/integrations.mdx +63 -2
  9. package/corpus/core/docs/content/package-lifecycle.mdx +54 -4
  10. package/corpus/core/docs/design/provider-integration-authority.md +117 -0
  11. package/corpus/core/package.json +20 -2
  12. package/corpus/core/scripts/materialize-source-corpus.mjs +9 -2
  13. package/corpus/core/src/cli/atomic-json-file.ts +324 -0
  14. package/corpus/core/src/cli/claude-code-participant.ts +515 -0
  15. package/corpus/core/src/cli/code-agent-executor.ts +18 -10
  16. package/corpus/core/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
  17. package/corpus/core/src/cli/code-agent-runs.ts +55 -62
  18. package/corpus/core/src/cli/codex-cli-participant.ts +496 -0
  19. package/corpus/core/src/cli/eject.ts +1594 -0
  20. package/corpus/core/src/cli/index.ts +16 -0
  21. package/corpus/core/src/cli/multi-frontier-runs.ts +1246 -135
  22. package/corpus/core/src/client/chat/ChatHistoryList.tsx +7 -404
  23. package/corpus/core/src/client/index.ts +4 -0
  24. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +8 -2
  25. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +7 -2
  26. package/corpus/core/src/client/resources/ResourcesPanel.tsx +17 -3
  27. package/corpus/core/src/client/resources/index.ts +19 -0
  28. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +9 -1
  29. package/corpus/core/src/client/resources/runtime.ts +1 -0
  30. package/corpus/core/src/client/setup-connections/catalog.ts +6 -0
  31. package/corpus/core/src/client/setup-connections/index.ts +1 -0
  32. package/corpus/core/src/client/setup-connections/runtime.ts +1 -0
  33. package/corpus/core/src/connections/catalog.ts +41 -24
  34. package/corpus/core/src/connections/index.ts +1 -0
  35. package/corpus/core/src/connections/runtime.ts +1 -0
  36. package/corpus/core/src/eject/provider-api-definitions.ts +193 -0
  37. package/corpus/core/src/eject/remote-mcp-presets.ts +137 -0
  38. package/corpus/core/src/eject/setup-readiness-ui.tsx +29 -0
  39. package/corpus/core/src/eject/workspace-connections.ts +92 -0
  40. package/corpus/core/src/index.ts +1 -0
  41. package/corpus/core/src/integrations/adapter-overrides.ts +12 -0
  42. package/corpus/core/src/integrations/eject/messaging-adapters.ts +85 -0
  43. package/corpus/core/src/integrations/index.ts +15 -1
  44. package/corpus/core/src/integrations/plugin.ts +34 -12
  45. package/corpus/core/src/integrations/runtime.ts +1 -0
  46. package/corpus/core/src/integrations/slack-oauth.ts +1 -0
  47. package/corpus/core/src/integrations/types.ts +3 -1
  48. package/corpus/core/src/integrations/webhook-delivery.ts +55 -0
  49. package/corpus/core/src/notifications/channels.ts +4 -10
  50. package/corpus/core/src/package-lifecycle/eject-manifest.ts +345 -0
  51. package/corpus/core/src/package-lifecycle/index.ts +1 -0
  52. package/corpus/core/src/provider-api/actions/custom-provider-registration.ts +197 -0
  53. package/corpus/core/src/provider-api/actions/delete-staged-dataset.ts +3 -42
  54. package/corpus/core/src/provider-api/actions/list-staged-datasets.ts +3 -45
  55. package/corpus/core/src/provider-api/actions/provider-api-audit.ts +88 -0
  56. package/corpus/core/src/provider-api/actions/provider-api.ts +460 -0
  57. package/corpus/core/src/provider-api/actions/query-staged-dataset.ts +3 -140
  58. package/corpus/core/src/provider-api/actions/staged-datasets.ts +359 -0
  59. package/corpus/core/src/provider-api/gong.ts +108 -0
  60. package/corpus/core/src/provider-api/index.ts +46 -12
  61. package/corpus/core/src/provider-api/runtime.ts +1 -0
  62. package/corpus/core/src/scripts/docs/source-search.ts +2 -1
  63. package/corpus/core/src/server/google-oauth-credentials.ts +80 -3
  64. package/corpus/core/src/server/index.ts +6 -0
  65. package/corpus/core/src/setup-connections/index.ts +1 -0
  66. package/corpus/core/src/shared/merge-by-id.ts +14 -0
  67. package/corpus/core/src/styles/chat-history-list.css +1 -313
  68. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
  69. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +21 -9
  70. package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  71. package/corpus/core/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  72. package/corpus/core/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  73. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  74. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +14 -2
  75. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  76. package/corpus/core/src/templates/default/AGENTS.md +26 -18
  77. package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  78. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +21 -9
  79. package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  80. package/corpus/core/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  81. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  82. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  83. package/corpus/core/src/templates/headless/AGENTS.md +8 -0
  84. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  85. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +21 -9
  86. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +7 -0
  87. package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  88. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +14 -2
  89. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  90. package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -0
  91. package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
  92. package/corpus/core/src/vite/client.ts +25 -2
  93. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -12
  94. package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  95. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +14 -2
  96. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  97. package/corpus/templates/analytics/actions/delete-staged-dataset.ts +3 -23
  98. package/corpus/templates/analytics/actions/list-staged-datasets.ts +3 -27
  99. package/corpus/templates/analytics/actions/provider-api-catalog.ts +16 -19
  100. package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -5
  101. package/corpus/templates/analytics/actions/provider-api-request.ts +162 -185
  102. package/corpus/templates/analytics/actions/query-staged-dataset.ts +3 -47
  103. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +52 -161
  104. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -12
  105. package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  106. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +14 -2
  107. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  108. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +63 -160
  109. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -12
  110. package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  111. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +14 -2
  112. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  113. package/corpus/templates/brain/actions/_schemas.ts +13 -7
  114. package/corpus/templates/brain/actions/delete-staged-dataset.ts +3 -24
  115. package/corpus/templates/brain/actions/list-staged-datasets.ts +3 -28
  116. package/corpus/templates/brain/actions/provider-api-catalog.ts +5 -11
  117. package/corpus/templates/brain/actions/provider-api-docs.ts +3 -5
  118. package/corpus/templates/brain/actions/provider-api-request.ts +3 -37
  119. package/corpus/templates/brain/actions/query-staged-dataset.ts +3 -48
  120. package/corpus/templates/brain/actions/remediate-legacy-capture-audiences.ts +167 -0
  121. package/corpus/templates/brain/actions/update-source.ts +5 -1
  122. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +48 -154
  123. package/corpus/templates/brain/app/lib/brain-chat-readiness.ts +6 -0
  124. package/corpus/templates/brain/app/lib/brain.ts +55 -0
  125. package/corpus/templates/brain/app/lib/ingest-handoff.ts +35 -0
  126. package/corpus/templates/brain/app/routes/_index.tsx +8 -0
  127. package/corpus/templates/brain/app/routes.ts +1 -0
  128. package/corpus/templates/brain/changelog/2026-07-19-ask-starts-immediately-when-builder-s-managed-ai-connection-.md +6 -0
  129. package/corpus/templates/brain/changelog/2026-07-19-slack-and-granola-backfills-now-process-captures-concurrentl.md +6 -0
  130. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-can-now-join-configured-public-channels-befo.md +6 -0
  131. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-continue-across-the-configured-number-of.md +6 -0
  132. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-start-with-a-safe-four-week-window-and-r.md +6 -0
  133. package/corpus/templates/brain/changelog/2026-07-19-source-review-settings-now-control-knowledge-approval.md +6 -0
  134. package/corpus/templates/brain/changelog/2026-07-19-the-manage-agent-page-now-opens-correctly-from-brain-navigat.md +6 -0
  135. package/corpus/templates/brain/server/db/schema.ts +3 -0
  136. package/corpus/templates/brain/server/lib/brain.ts +41 -2
  137. package/corpus/templates/brain/server/lib/connectors.ts +432 -115
  138. package/corpus/templates/brain/server/lib/meeting-audience.ts +38 -0
  139. package/corpus/templates/brain/server/lib/slack-channel-membership.ts +44 -0
  140. package/corpus/templates/brain/server/plugins/db.ts +10 -0
  141. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +6 -4
  142. package/corpus/templates/brain/shared/slack-source-config.ts +60 -0
  143. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -12
  144. package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  145. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +14 -2
  146. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  147. package/corpus/templates/calendar/actions/delete-staged-dataset.ts +3 -24
  148. package/corpus/templates/calendar/actions/list-staged-datasets.ts +3 -28
  149. package/corpus/templates/calendar/actions/provider-api-catalog.ts +5 -11
  150. package/corpus/templates/calendar/actions/provider-api-docs.ts +3 -5
  151. package/corpus/templates/calendar/actions/provider-api-request.ts +3 -37
  152. package/corpus/templates/calendar/actions/query-staged-dataset.ts +3 -48
  153. package/corpus/templates/calendar/server/handlers/gong.ts +6 -61
  154. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -8
  155. package/corpus/templates/calendar/server/lib/google-calendar.ts +7 -45
  156. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  157. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +21 -9
  158. package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  159. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +14 -2
  160. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  161. package/corpus/templates/chat/AGENTS.md +6 -2
  162. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  163. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -12
  164. package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  165. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +14 -2
  166. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  167. package/corpus/templates/clips/AGENTS.md +11 -0
  168. package/corpus/templates/clips/actions/export-to-brain.ts +505 -171
  169. package/corpus/templates/clips/changelog/2026-07-19-ready-clips-transcripts-can-be-backfilled-to-brain-for-a-bou.md +6 -0
  170. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -1
  171. package/corpus/templates/clips/server/lib/google-calendar-client.ts +12 -22
  172. package/corpus/templates/clips/server/lib/google-calendar-oauth.ts +9 -6
  173. package/corpus/templates/clips/server/lib/slack-oauth.ts +12 -47
  174. package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +2 -6
  175. package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -4
  176. package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -12
  177. package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  178. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +14 -2
  179. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  180. package/corpus/templates/content/actions/delete-staged-dataset.ts +3 -24
  181. package/corpus/templates/content/actions/list-staged-datasets.ts +3 -28
  182. package/corpus/templates/content/actions/provider-api-catalog.ts +5 -11
  183. package/corpus/templates/content/actions/provider-api-docs.ts +3 -5
  184. package/corpus/templates/content/actions/provider-api-request.ts +3 -37
  185. package/corpus/templates/content/actions/query-staged-dataset.ts +3 -48
  186. package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -12
  187. package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  188. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +14 -2
  189. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  190. package/corpus/templates/design/actions/delete-staged-dataset.ts +4 -23
  191. package/corpus/templates/design/actions/list-staged-datasets.ts +4 -27
  192. package/corpus/templates/design/actions/provider-api-catalog.ts +15 -18
  193. package/corpus/templates/design/actions/provider-api-docs.ts +57 -48
  194. package/corpus/templates/design/actions/provider-api-request.ts +140 -164
  195. package/corpus/templates/design/actions/query-staged-dataset.ts +4 -47
  196. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -12
  197. package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  198. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +14 -2
  199. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  200. package/corpus/templates/dispatch/actions/delete-staged-dataset.ts +4 -23
  201. package/corpus/templates/dispatch/actions/list-staged-datasets.ts +4 -30
  202. package/corpus/templates/dispatch/actions/provider-api-catalog.ts +15 -18
  203. package/corpus/templates/dispatch/actions/provider-api-docs.ts +57 -48
  204. package/corpus/templates/dispatch/actions/provider-api-request.ts +138 -163
  205. package/corpus/templates/dispatch/actions/query-staged-dataset.ts +4 -47
  206. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -12
  207. package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  208. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +14 -2
  209. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  210. package/corpus/templates/forms/server/lib/integrations.ts +23 -22
  211. package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  212. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  213. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -12
  214. package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  215. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +14 -2
  216. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  217. package/corpus/templates/mail/actions/delete-staged-dataset.ts +4 -23
  218. package/corpus/templates/mail/actions/list-staged-datasets.ts +4 -27
  219. package/corpus/templates/mail/actions/provider-api-catalog.ts +15 -18
  220. package/corpus/templates/mail/actions/provider-api-docs.ts +57 -48
  221. package/corpus/templates/mail/actions/provider-api-request.ts +146 -173
  222. package/corpus/templates/mail/actions/query-staged-dataset.ts +4 -47
  223. package/corpus/templates/mail/server/handlers/gong.ts +6 -61
  224. package/corpus/templates/mail/server/lib/google-auth.ts +10 -13
  225. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -12
  226. package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  227. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +14 -2
  228. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  229. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +47 -156
  230. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -12
  231. package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  232. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +14 -2
  233. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  234. package/corpus/templates/slides/actions/delete-staged-dataset.ts +4 -23
  235. package/corpus/templates/slides/actions/list-staged-datasets.ts +4 -27
  236. package/corpus/templates/slides/actions/provider-api-catalog.ts +15 -18
  237. package/corpus/templates/slides/actions/provider-api-docs.ts +57 -48
  238. package/corpus/templates/slides/actions/provider-api-request.ts +145 -172
  239. package/corpus/templates/slides/actions/query-staged-dataset.ts +4 -47
  240. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +11 -36
  241. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -12
  242. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +21 -9
  243. package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  244. package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +14 -2
  245. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  246. package/corpus/toolkit/CHANGELOG.md +131 -0
  247. package/corpus/toolkit/README.md +60 -0
  248. package/corpus/toolkit/agent-native.eject.json +411 -0
  249. package/corpus/toolkit/export-snapshot.json +35 -0
  250. package/corpus/toolkit/migration-manifest.json +4 -0
  251. package/corpus/toolkit/package.json +284 -0
  252. package/corpus/toolkit/scripts/finalize-build.mjs +55 -0
  253. package/corpus/toolkit/src/app-shell/header-actions.tsx +84 -0
  254. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  255. package/corpus/toolkit/src/chat-history/ChatHistoryList.tsx +469 -0
  256. package/corpus/toolkit/src/chat-history/index.ts +7 -0
  257. package/corpus/toolkit/src/chat-history.css +314 -0
  258. package/corpus/toolkit/src/collab-ui/AgentPresenceChip.tsx +69 -0
  259. package/corpus/toolkit/src/collab-ui/LiveCursorOverlay.tsx +241 -0
  260. package/corpus/toolkit/src/collab-ui/PresenceBar.tsx +346 -0
  261. package/corpus/toolkit/src/collab-ui/RecentEditHighlights.tsx +225 -0
  262. package/corpus/toolkit/src/collab-ui/RemoteSelectionRings.tsx +227 -0
  263. package/corpus/toolkit/src/collab-ui/agent-identity.ts +16 -0
  264. package/corpus/toolkit/src/collab-ui/index.ts +39 -0
  265. package/corpus/toolkit/src/collab-ui/lead-client.ts +32 -0
  266. package/corpus/toolkit/src/collab-ui/types.ts +96 -0
  267. package/corpus/toolkit/src/composer/AgentComposerFrame.tsx +59 -0
  268. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +983 -0
  269. package/corpus/toolkit/src/composer/MentionPopover.tsx +412 -0
  270. package/corpus/toolkit/src/composer/PastedTextChip.tsx +150 -0
  271. package/corpus/toolkit/src/composer/PromptComposer.tsx +718 -0
  272. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +856 -0
  273. package/corpus/toolkit/src/composer/TiptapComposer.tsx +2936 -0
  274. package/corpus/toolkit/src/composer/VoiceButton.tsx +255 -0
  275. package/corpus/toolkit/src/composer/asset-picker-url.ts +80 -0
  276. package/corpus/toolkit/src/composer/attachment-accept.ts +71 -0
  277. package/corpus/toolkit/src/composer/draft-key.ts +7 -0
  278. package/corpus/toolkit/src/composer/extensions/FileReference.tsx +55 -0
  279. package/corpus/toolkit/src/composer/extensions/MentionReference.tsx +93 -0
  280. package/corpus/toolkit/src/composer/extensions/SkillReference.tsx +56 -0
  281. package/corpus/toolkit/src/composer/index.ts +79 -0
  282. package/corpus/toolkit/src/composer/pasted-text.ts +160 -0
  283. package/corpus/toolkit/src/composer/prompt-attachments.ts +93 -0
  284. package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +64 -0
  285. package/corpus/toolkit/src/composer/realtime-voice-transcript.ts +134 -0
  286. package/corpus/toolkit/src/composer/runtime-adapters.tsx +343 -0
  287. package/corpus/toolkit/src/composer/types.ts +66 -0
  288. package/corpus/toolkit/src/composer/use-file-search.ts +64 -0
  289. package/corpus/toolkit/src/composer/use-mention-search.ts +90 -0
  290. package/corpus/toolkit/src/composer/use-skills.ts +45 -0
  291. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +2117 -0
  292. package/corpus/toolkit/src/composer/useVoiceDictation.ts +1191 -0
  293. package/corpus/toolkit/src/context-ui/ContextMeter.tsx +101 -0
  294. package/corpus/toolkit/src/context-ui/ContextSegmentRow.tsx +184 -0
  295. package/corpus/toolkit/src/context-ui/ContextTreemap.tsx +125 -0
  296. package/corpus/toolkit/src/context-ui/ContextXRayPanel.tsx +377 -0
  297. package/corpus/toolkit/src/context-ui/format.ts +42 -0
  298. package/corpus/toolkit/src/context-ui/index.ts +15 -0
  299. package/corpus/toolkit/src/context-ui/types.ts +43 -0
  300. package/corpus/toolkit/src/design-tweaks/index.ts +1 -0
  301. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +1084 -0
  302. package/corpus/toolkit/src/editor/BubbleToolbar.tsx +253 -0
  303. package/corpus/toolkit/src/editor/CodeBlockNode.tsx +254 -0
  304. package/corpus/toolkit/src/editor/DragHandle.ts +1437 -0
  305. package/corpus/toolkit/src/editor/ImageExtension.ts +306 -0
  306. package/corpus/toolkit/src/editor/RegistryBlockContext.tsx +107 -0
  307. package/corpus/toolkit/src/editor/RegistryBlockNode.tsx +652 -0
  308. package/corpus/toolkit/src/editor/RichMarkdownEditor.tsx +81 -0
  309. package/corpus/toolkit/src/editor/RunId.ts +61 -0
  310. package/corpus/toolkit/src/editor/SharedRichEditor.tsx +321 -0
  311. package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +310 -0
  312. package/corpus/toolkit/src/editor/extensions.ts +402 -0
  313. package/corpus/toolkit/src/editor/gfmDoc.ts +92 -0
  314. package/corpus/toolkit/src/editor/index.ts +93 -0
  315. package/corpus/toolkit/src/editor/registrySlashCommands.ts +131 -0
  316. package/corpus/toolkit/src/editor/surgical-apply.ts +192 -0
  317. package/corpus/toolkit/src/editor/useCollabReconcile.ts +589 -0
  318. package/corpus/toolkit/src/editor.css +510 -0
  319. package/corpus/toolkit/src/hooks/index.ts +2 -0
  320. package/corpus/toolkit/src/hooks/use-mobile.tsx +21 -0
  321. package/corpus/toolkit/src/hooks/use-toast.ts +188 -0
  322. package/corpus/toolkit/src/index.ts +8 -0
  323. package/corpus/toolkit/src/onboarding/index.ts +1 -0
  324. package/corpus/toolkit/src/provider.tsx +47 -0
  325. package/corpus/toolkit/src/sharing/VisibilityBadge.tsx +37 -0
  326. package/corpus/toolkit/src/sharing/index.ts +4 -0
  327. package/corpus/toolkit/src/styles.css +21 -0
  328. package/corpus/toolkit/src/ui/accordion.tsx +56 -0
  329. package/corpus/toolkit/src/ui/alert-dialog.tsx +141 -0
  330. package/corpus/toolkit/src/ui/alert.tsx +59 -0
  331. package/corpus/toolkit/src/ui/aspect-ratio.tsx +5 -0
  332. package/corpus/toolkit/src/ui/avatar.tsx +48 -0
  333. package/corpus/toolkit/src/ui/badge.tsx +37 -0
  334. package/corpus/toolkit/src/ui/breadcrumb.tsx +115 -0
  335. package/corpus/toolkit/src/ui/button.tsx +78 -0
  336. package/corpus/toolkit/src/ui/calendar.tsx +214 -0
  337. package/corpus/toolkit/src/ui/card.tsx +86 -0
  338. package/corpus/toolkit/src/ui/carousel.tsx +260 -0
  339. package/corpus/toolkit/src/ui/chart.tsx +375 -0
  340. package/corpus/toolkit/src/ui/checkbox.tsx +28 -0
  341. package/corpus/toolkit/src/ui/collapsible.tsx +9 -0
  342. package/corpus/toolkit/src/ui/command.tsx +174 -0
  343. package/corpus/toolkit/src/ui/context-menu.tsx +202 -0
  344. package/corpus/toolkit/src/ui/date-picker.tsx +64 -0
  345. package/corpus/toolkit/src/ui/dialog.tsx +146 -0
  346. package/corpus/toolkit/src/ui/drawer.tsx +126 -0
  347. package/corpus/toolkit/src/ui/dropdown-menu.tsx +218 -0
  348. package/corpus/toolkit/src/ui/form.tsx +177 -0
  349. package/corpus/toolkit/src/ui/hover-card.tsx +27 -0
  350. package/corpus/toolkit/src/ui/index.ts +52 -0
  351. package/corpus/toolkit/src/ui/input-otp.tsx +69 -0
  352. package/corpus/toolkit/src/ui/input.tsx +22 -0
  353. package/corpus/toolkit/src/ui/label.tsx +24 -0
  354. package/corpus/toolkit/src/ui/logo.tsx +36 -0
  355. package/corpus/toolkit/src/ui/menubar.tsx +235 -0
  356. package/corpus/toolkit/src/ui/navigation-menu.tsx +128 -0
  357. package/corpus/toolkit/src/ui/pagination.tsx +121 -0
  358. package/corpus/toolkit/src/ui/popover.tsx +44 -0
  359. package/corpus/toolkit/src/ui/progress.tsx +26 -0
  360. package/corpus/toolkit/src/ui/radio-group.tsx +42 -0
  361. package/corpus/toolkit/src/ui/resizable.tsx +43 -0
  362. package/corpus/toolkit/src/ui/scroll-area.tsx +46 -0
  363. package/corpus/toolkit/src/ui/select.tsx +158 -0
  364. package/corpus/toolkit/src/ui/separator.tsx +29 -0
  365. package/corpus/toolkit/src/ui/sheet.tsx +160 -0
  366. package/corpus/toolkit/src/ui/sidebar.tsx +777 -0
  367. package/corpus/toolkit/src/ui/skeleton.tsx +18 -0
  368. package/corpus/toolkit/src/ui/slider.tsx +26 -0
  369. package/corpus/toolkit/src/ui/sonner.tsx +58 -0
  370. package/corpus/toolkit/src/ui/spinner.tsx +17 -0
  371. package/corpus/toolkit/src/ui/switch.tsx +27 -0
  372. package/corpus/toolkit/src/ui/table.tsx +117 -0
  373. package/corpus/toolkit/src/ui/tabs.tsx +53 -0
  374. package/corpus/toolkit/src/ui/textarea.tsx +23 -0
  375. package/corpus/toolkit/src/ui/toast.tsx +127 -0
  376. package/corpus/toolkit/src/ui/toaster.tsx +33 -0
  377. package/corpus/toolkit/src/ui/toggle-group.tsx +59 -0
  378. package/corpus/toolkit/src/ui/toggle.tsx +43 -0
  379. package/corpus/toolkit/src/ui/tooltip.tsx +53 -0
  380. package/corpus/toolkit/src/ui/use-toast.ts +3 -0
  381. package/corpus/toolkit/src/utils.ts +8 -0
  382. package/corpus/toolkit/tsconfig.json +23 -0
  383. package/dist/cli/atomic-json-file.d.ts +30 -0
  384. package/dist/cli/atomic-json-file.d.ts.map +1 -0
  385. package/dist/cli/atomic-json-file.js +240 -0
  386. package/dist/cli/atomic-json-file.js.map +1 -0
  387. package/dist/cli/claude-code-participant.d.ts +77 -0
  388. package/dist/cli/claude-code-participant.d.ts.map +1 -0
  389. package/dist/cli/claude-code-participant.js +355 -0
  390. package/dist/cli/claude-code-participant.js.map +1 -0
  391. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  392. package/dist/cli/code-agent-executor.js +18 -10
  393. package/dist/cli/code-agent-executor.js.map +1 -1
  394. package/dist/cli/code-agent-runs.concurrent-worker.d.ts +2 -0
  395. package/dist/cli/code-agent-runs.concurrent-worker.d.ts.map +1 -0
  396. package/dist/cli/code-agent-runs.concurrent-worker.js +32 -0
  397. package/dist/cli/code-agent-runs.concurrent-worker.js.map +1 -0
  398. package/dist/cli/code-agent-runs.d.ts.map +1 -1
  399. package/dist/cli/code-agent-runs.js +43 -56
  400. package/dist/cli/code-agent-runs.js.map +1 -1
  401. package/dist/cli/codex-cli-participant.d.ts +77 -0
  402. package/dist/cli/codex-cli-participant.d.ts.map +1 -0
  403. package/dist/cli/codex-cli-participant.js +354 -0
  404. package/dist/cli/codex-cli-participant.js.map +1 -0
  405. package/dist/cli/eject.d.ts +21 -0
  406. package/dist/cli/eject.d.ts.map +1 -0
  407. package/dist/cli/eject.js +1145 -0
  408. package/dist/cli/eject.js.map +1 -0
  409. package/dist/cli/index.js +15 -0
  410. package/dist/cli/index.js.map +1 -1
  411. package/dist/cli/multi-frontier-runs.d.ts +115 -0
  412. package/dist/cli/multi-frontier-runs.d.ts.map +1 -1
  413. package/dist/cli/multi-frontier-runs.js +831 -113
  414. package/dist/cli/multi-frontier-runs.js.map +1 -1
  415. package/dist/client/chat/ChatHistoryList.d.ts +1 -87
  416. package/dist/client/chat/ChatHistoryList.d.ts.map +1 -1
  417. package/dist/client/chat/ChatHistoryList.js +1 -82
  418. package/dist/client/chat/ChatHistoryList.js.map +1 -1
  419. package/dist/client/index.d.ts +1 -1
  420. package/dist/client/index.d.ts.map +1 -1
  421. package/dist/client/index.js +1 -1
  422. package/dist/client/index.js.map +1 -1
  423. package/dist/client/resources/McpConnectionSuggestion.d.ts +4 -3
  424. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  425. package/dist/client/resources/McpConnectionSuggestion.js +3 -3
  426. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  427. package/dist/client/resources/McpIntegrationDialog.d.ts +4 -3
  428. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  429. package/dist/client/resources/McpIntegrationDialog.js +2 -2
  430. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  431. package/dist/client/resources/ResourcesPanel.d.ts +4 -1
  432. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  433. package/dist/client/resources/ResourcesPanel.js +9 -7
  434. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  435. package/dist/client/resources/index.d.ts +3 -0
  436. package/dist/client/resources/index.d.ts.map +1 -1
  437. package/dist/client/resources/index.js +3 -0
  438. package/dist/client/resources/index.js.map +1 -1
  439. package/dist/client/resources/mcp-integration-catalog.d.ts +2 -1
  440. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  441. package/dist/client/resources/mcp-integration-catalog.js +6 -2
  442. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  443. package/dist/client/resources/runtime.d.ts +2 -0
  444. package/dist/client/resources/runtime.d.ts.map +1 -0
  445. package/dist/client/resources/runtime.js +2 -0
  446. package/dist/client/resources/runtime.js.map +1 -0
  447. package/dist/client/setup-connections/catalog.d.ts +2 -0
  448. package/dist/client/setup-connections/catalog.d.ts.map +1 -0
  449. package/dist/client/setup-connections/catalog.js +7 -0
  450. package/dist/client/setup-connections/catalog.js.map +1 -0
  451. package/dist/client/setup-connections/index.d.ts +1 -0
  452. package/dist/client/setup-connections/index.d.ts.map +1 -1
  453. package/dist/client/setup-connections/index.js +1 -0
  454. package/dist/client/setup-connections/index.js.map +1 -1
  455. package/dist/client/setup-connections/runtime.d.ts +2 -0
  456. package/dist/client/setup-connections/runtime.d.ts.map +1 -0
  457. package/dist/client/setup-connections/runtime.js +2 -0
  458. package/dist/client/setup-connections/runtime.js.map +1 -0
  459. package/dist/collab/awareness.d.ts +2 -2
  460. package/dist/collab/awareness.d.ts.map +1 -1
  461. package/dist/collab/routes.d.ts +1 -1
  462. package/dist/connections/catalog.d.ts +5 -3
  463. package/dist/connections/catalog.d.ts.map +1 -1
  464. package/dist/connections/catalog.js +16 -8
  465. package/dist/connections/catalog.js.map +1 -1
  466. package/dist/connections/index.d.ts +1 -1
  467. package/dist/connections/index.d.ts.map +1 -1
  468. package/dist/connections/index.js +1 -1
  469. package/dist/connections/index.js.map +1 -1
  470. package/dist/connections/runtime.d.ts +2 -0
  471. package/dist/connections/runtime.d.ts.map +1 -0
  472. package/dist/connections/runtime.js +2 -0
  473. package/dist/connections/runtime.js.map +1 -0
  474. package/dist/eject/provider-api-definitions.d.ts +34 -0
  475. package/dist/eject/provider-api-definitions.d.ts.map +1 -0
  476. package/dist/eject/provider-api-definitions.js +88 -0
  477. package/dist/eject/provider-api-definitions.js.map +1 -0
  478. package/dist/eject/remote-mcp-presets.d.ts +17 -0
  479. package/dist/eject/remote-mcp-presets.d.ts.map +1 -0
  480. package/dist/eject/remote-mcp-presets.js +81 -0
  481. package/dist/eject/remote-mcp-presets.js.map +1 -0
  482. package/dist/eject/setup-readiness-ui.d.ts +7 -0
  483. package/dist/eject/setup-readiness-ui.d.ts.map +1 -0
  484. package/dist/eject/setup-readiness-ui.js +13 -0
  485. package/dist/eject/setup-readiness-ui.js.map +1 -0
  486. package/dist/eject/workspace-connections.d.ts +11 -0
  487. package/dist/eject/workspace-connections.d.ts.map +1 -0
  488. package/dist/eject/workspace-connections.js +47 -0
  489. package/dist/eject/workspace-connections.js.map +1 -0
  490. package/dist/index.d.ts +1 -1
  491. package/dist/index.d.ts.map +1 -1
  492. package/dist/index.js +1 -1
  493. package/dist/index.js.map +1 -1
  494. package/dist/integrations/adapter-overrides.d.ts +3 -0
  495. package/dist/integrations/adapter-overrides.d.ts.map +1 -0
  496. package/dist/integrations/adapter-overrides.js +7 -0
  497. package/dist/integrations/adapter-overrides.js.map +1 -0
  498. package/dist/integrations/eject/messaging-adapters.d.ts +12 -0
  499. package/dist/integrations/eject/messaging-adapters.d.ts.map +1 -0
  500. package/dist/integrations/eject/messaging-adapters.js +49 -0
  501. package/dist/integrations/eject/messaging-adapters.js.map +1 -0
  502. package/dist/integrations/index.d.ts +5 -3
  503. package/dist/integrations/index.d.ts.map +1 -1
  504. package/dist/integrations/index.js +4 -2
  505. package/dist/integrations/index.js.map +1 -1
  506. package/dist/integrations/plugin.d.ts +32 -1
  507. package/dist/integrations/plugin.d.ts.map +1 -1
  508. package/dist/integrations/plugin.js +19 -12
  509. package/dist/integrations/plugin.js.map +1 -1
  510. package/dist/integrations/runtime.d.ts +2 -0
  511. package/dist/integrations/runtime.d.ts.map +1 -0
  512. package/dist/integrations/runtime.js +2 -0
  513. package/dist/integrations/runtime.js.map +1 -0
  514. package/dist/integrations/slack-manifest.d.ts +1 -1
  515. package/dist/integrations/slack-oauth.d.ts +1 -1
  516. package/dist/integrations/slack-oauth.d.ts.map +1 -1
  517. package/dist/integrations/slack-oauth.js +1 -0
  518. package/dist/integrations/slack-oauth.js.map +1 -1
  519. package/dist/integrations/types.d.ts +3 -1
  520. package/dist/integrations/types.d.ts.map +1 -1
  521. package/dist/integrations/types.js.map +1 -1
  522. package/dist/integrations/webhook-delivery.d.ts +23 -0
  523. package/dist/integrations/webhook-delivery.d.ts.map +1 -0
  524. package/dist/integrations/webhook-delivery.js +32 -0
  525. package/dist/integrations/webhook-delivery.js.map +1 -0
  526. package/dist/notifications/channels.d.ts.map +1 -1
  527. package/dist/notifications/channels.js +4 -9
  528. package/dist/notifications/channels.js.map +1 -1
  529. package/dist/notifications/routes.d.ts +3 -3
  530. package/dist/package-lifecycle/eject-manifest.d.ts +43 -0
  531. package/dist/package-lifecycle/eject-manifest.d.ts.map +1 -0
  532. package/dist/package-lifecycle/eject-manifest.js +219 -0
  533. package/dist/package-lifecycle/eject-manifest.js.map +1 -0
  534. package/dist/package-lifecycle/index.d.ts +1 -0
  535. package/dist/package-lifecycle/index.d.ts.map +1 -1
  536. package/dist/package-lifecycle/index.js +1 -0
  537. package/dist/package-lifecycle/index.js.map +1 -1
  538. package/dist/progress/routes.d.ts +1 -1
  539. package/dist/provider-api/actions/custom-provider-registration.d.ts +136 -0
  540. package/dist/provider-api/actions/custom-provider-registration.d.ts.map +1 -0
  541. package/dist/provider-api/actions/custom-provider-registration.js +154 -0
  542. package/dist/provider-api/actions/custom-provider-registration.js.map +1 -0
  543. package/dist/provider-api/actions/delete-staged-dataset.d.ts +1 -1
  544. package/dist/provider-api/actions/delete-staged-dataset.d.ts.map +1 -1
  545. package/dist/provider-api/actions/delete-staged-dataset.js +3 -34
  546. package/dist/provider-api/actions/delete-staged-dataset.js.map +1 -1
  547. package/dist/provider-api/actions/list-staged-datasets.d.ts +2 -3
  548. package/dist/provider-api/actions/list-staged-datasets.d.ts.map +1 -1
  549. package/dist/provider-api/actions/list-staged-datasets.js +3 -40
  550. package/dist/provider-api/actions/list-staged-datasets.js.map +1 -1
  551. package/dist/provider-api/actions/provider-api-audit.d.ts +7 -0
  552. package/dist/provider-api/actions/provider-api-audit.d.ts.map +1 -0
  553. package/dist/provider-api/actions/provider-api-audit.js +74 -0
  554. package/dist/provider-api/actions/provider-api-audit.js.map +1 -0
  555. package/dist/provider-api/actions/provider-api.d.ts +370 -0
  556. package/dist/provider-api/actions/provider-api.d.ts.map +1 -0
  557. package/dist/provider-api/actions/provider-api.js +280 -0
  558. package/dist/provider-api/actions/provider-api.js.map +1 -0
  559. package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
  560. package/dist/provider-api/actions/query-staged-dataset.d.ts.map +1 -1
  561. package/dist/provider-api/actions/query-staged-dataset.js +3 -116
  562. package/dist/provider-api/actions/query-staged-dataset.js.map +1 -1
  563. package/dist/provider-api/actions/staged-datasets.d.ts +190 -0
  564. package/dist/provider-api/actions/staged-datasets.d.ts.map +1 -0
  565. package/dist/provider-api/actions/staged-datasets.js +210 -0
  566. package/dist/provider-api/actions/staged-datasets.js.map +1 -0
  567. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  568. package/dist/provider-api/gong.d.ts +44 -0
  569. package/dist/provider-api/gong.d.ts.map +1 -0
  570. package/dist/provider-api/gong.js +56 -0
  571. package/dist/provider-api/gong.js.map +1 -0
  572. package/dist/provider-api/index.d.ts +6 -2
  573. package/dist/provider-api/index.d.ts.map +1 -1
  574. package/dist/provider-api/index.js +25 -12
  575. package/dist/provider-api/index.js.map +1 -1
  576. package/dist/provider-api/runtime.d.ts +2 -0
  577. package/dist/provider-api/runtime.d.ts.map +1 -0
  578. package/dist/provider-api/runtime.js +2 -0
  579. package/dist/provider-api/runtime.js.map +1 -0
  580. package/dist/scripts/docs/source-search.d.ts +2 -1
  581. package/dist/scripts/docs/source-search.d.ts.map +1 -1
  582. package/dist/scripts/docs/source-search.js +2 -1
  583. package/dist/scripts/docs/source-search.js.map +1 -1
  584. package/dist/secrets/routes.d.ts +9 -9
  585. package/dist/server/google-oauth-credentials.d.ts +35 -0
  586. package/dist/server/google-oauth-credentials.d.ts.map +1 -1
  587. package/dist/server/google-oauth-credentials.js +48 -2
  588. package/dist/server/google-oauth-credentials.js.map +1 -1
  589. package/dist/server/index.d.ts +1 -1
  590. package/dist/server/index.d.ts.map +1 -1
  591. package/dist/server/index.js +1 -1
  592. package/dist/server/index.js.map +1 -1
  593. package/dist/server/transcribe-voice.d.ts +1 -1
  594. package/dist/setup-connections/index.d.ts +1 -1
  595. package/dist/setup-connections/index.d.ts.map +1 -1
  596. package/dist/setup-connections/index.js +1 -1
  597. package/dist/setup-connections/index.js.map +1 -1
  598. package/dist/shared/merge-by-id.d.ts +5 -0
  599. package/dist/shared/merge-by-id.d.ts.map +1 -0
  600. package/dist/shared/merge-by-id.js +7 -0
  601. package/dist/shared/merge-by-id.js.map +1 -0
  602. package/dist/styles/chat-history-list.css +1 -313
  603. package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  604. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +21 -9
  605. package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  606. package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +14 -2
  607. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  608. package/dist/templates/chat/AGENTS.md +6 -2
  609. package/dist/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  610. package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -12
  611. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +21 -9
  612. package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  613. package/dist/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  614. package/dist/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  615. package/dist/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  616. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +14 -2
  617. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  618. package/dist/templates/default/AGENTS.md +26 -18
  619. package/dist/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  620. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +21 -9
  621. package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  622. package/dist/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  623. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  624. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  625. package/dist/templates/headless/AGENTS.md +8 -0
  626. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  627. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +21 -9
  628. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +7 -0
  629. package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  630. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +14 -2
  631. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  632. package/dist/templates/workspace-core/AGENTS.md +4 -0
  633. package/dist/templates/workspace-root/AGENTS.md +4 -0
  634. package/dist/vite/client.d.ts.map +1 -1
  635. package/dist/vite/client.js +22 -2
  636. package/dist/vite/client.js.map +1 -1
  637. package/docs/AGENTS.md +7 -0
  638. package/docs/content/agent-native-toolkit.mdx +38 -0
  639. package/docs/content/integrations.mdx +63 -2
  640. package/docs/content/package-lifecycle.mdx +54 -4
  641. package/docs/design/provider-integration-authority.md +117 -0
  642. package/package.json +20 -2
  643. package/src/a2a/agent-card.ts +83 -0
  644. package/src/a2a/artifact-response.ts +1648 -0
  645. package/src/a2a/auth-policy.ts +66 -0
  646. package/src/a2a/caller-auth.ts +102 -0
  647. package/src/a2a/client.ts +876 -0
  648. package/src/a2a/correlation.ts +50 -0
  649. package/src/a2a/handlers.ts +1285 -0
  650. package/src/a2a/index.ts +50 -0
  651. package/src/a2a/invoke.ts +348 -0
  652. package/src/a2a/response-text.ts +53 -0
  653. package/src/a2a/server.ts +586 -0
  654. package/src/a2a/task-store.ts +917 -0
  655. package/src/a2a/types.ts +221 -0
  656. package/src/a2a-claims.ts +52 -0
  657. package/src/action-change-marker.ts +74 -0
  658. package/src/action-ui.ts +38 -0
  659. package/src/action.ts +1406 -0
  660. package/src/adapters/cli/index.ts +6 -0
  661. package/src/adapters/cli/registry.ts +73 -0
  662. package/src/adapters/cli/shell-adapter.ts +92 -0
  663. package/src/adapters/cli/types.ts +27 -0
  664. package/src/agent/action-continuation-guidance.ts +38 -0
  665. package/src/agent/app-model-defaults.ts +201 -0
  666. package/src/agent/context-xray/actions/context-evict.ts +56 -0
  667. package/src/agent/context-xray/actions/context-manifest-get.ts +75 -0
  668. package/src/agent/context-xray/actions/context-pin.ts +56 -0
  669. package/src/agent/context-xray/actions/context-preview-get.ts +134 -0
  670. package/src/agent/context-xray/actions/context-report.ts +75 -0
  671. package/src/agent/context-xray/actions/context-restore.ts +51 -0
  672. package/src/agent/context-xray/actions/errors.ts +40 -0
  673. package/src/agent/context-xray/apply-directives.ts +137 -0
  674. package/src/agent/context-xray/directives-store.ts +178 -0
  675. package/src/agent/context-xray/identity.ts +37 -0
  676. package/src/agent/context-xray/manifest.ts +284 -0
  677. package/src/agent/context-xray/migrations.ts +32 -0
  678. package/src/agent/context-xray/plugin.ts +23 -0
  679. package/src/agent/context-xray/schema.ts +17 -0
  680. package/src/agent/context-xray/segments.ts +194 -0
  681. package/src/agent/context-xray/tokenize.ts +93 -0
  682. package/src/agent/default-model.ts +5 -0
  683. package/src/agent/durable-background.ts +547 -0
  684. package/src/agent/engine/ai-sdk-engine.ts +565 -0
  685. package/src/agent/engine/anthropic-engine.ts +320 -0
  686. package/src/agent/engine/builder-engine.ts +1110 -0
  687. package/src/agent/engine/builder-gateway-headers.ts +44 -0
  688. package/src/agent/engine/builtin.ts +122 -0
  689. package/src/agent/engine/context-directives-transform.ts +73 -0
  690. package/src/agent/engine/continuation-dispatch-retry.ts +168 -0
  691. package/src/agent/engine/credential-errors.ts +69 -0
  692. package/src/agent/engine/index.ts +54 -0
  693. package/src/agent/engine/openai-compatible-endpoint.ts +25 -0
  694. package/src/agent/engine/output-tokens.ts +181 -0
  695. package/src/agent/engine/provider-env-vars.ts +69 -0
  696. package/src/agent/engine/registry.ts +853 -0
  697. package/src/agent/engine/tool-call-journal-seed.ts +85 -0
  698. package/src/agent/engine/translate-ai-sdk.ts +407 -0
  699. package/src/agent/engine/translate-anthropic.ts +611 -0
  700. package/src/agent/engine/types.ts +310 -0
  701. package/src/agent/harness/acp-adapter.ts +893 -0
  702. package/src/agent/harness/acp-builtin.ts +70 -0
  703. package/src/agent/harness/ai-sdk-adapter.ts +509 -0
  704. package/src/agent/harness/background.ts +365 -0
  705. package/src/agent/harness/builtin.ts +50 -0
  706. package/src/agent/harness/index.ts +86 -0
  707. package/src/agent/harness/lifecycle.ts +498 -0
  708. package/src/agent/harness/registry.ts +97 -0
  709. package/src/agent/harness/runner.ts +182 -0
  710. package/src/agent/harness/store.ts +466 -0
  711. package/src/agent/harness/translate.ts +130 -0
  712. package/src/agent/harness/types.ts +129 -0
  713. package/src/agent/index.ts +32 -0
  714. package/src/agent/loop-settings.ts +186 -0
  715. package/src/agent/model-config.ts +363 -0
  716. package/src/agent/observational-memory/compactor.ts +78 -0
  717. package/src/agent/observational-memory/config.ts +78 -0
  718. package/src/agent/observational-memory/index.ts +79 -0
  719. package/src/agent/observational-memory/internal-run.ts +89 -0
  720. package/src/agent/observational-memory/message-text.ts +49 -0
  721. package/src/agent/observational-memory/migrations.ts +44 -0
  722. package/src/agent/observational-memory/observer.ts +128 -0
  723. package/src/agent/observational-memory/plugin.ts +35 -0
  724. package/src/agent/observational-memory/prompts.ts +53 -0
  725. package/src/agent/observational-memory/read.ts +131 -0
  726. package/src/agent/observational-memory/reflector.ts +119 -0
  727. package/src/agent/observational-memory/schema.ts +48 -0
  728. package/src/agent/observational-memory/store.ts +275 -0
  729. package/src/agent/observational-memory/types.ts +65 -0
  730. package/src/agent/processors.ts +209 -0
  731. package/src/agent/production-agent.ts +8254 -0
  732. package/src/agent/run-loop-with-resume.ts +394 -0
  733. package/src/agent/run-manager.ts +1825 -0
  734. package/src/agent/run-ownership.ts +75 -0
  735. package/src/agent/run-store.ts +2601 -0
  736. package/src/agent/runtime-context.ts +169 -0
  737. package/src/agent/thread-data-builder.ts +1584 -0
  738. package/src/agent/tool-call-journal.ts +368 -0
  739. package/src/agent/tool-error-redaction.ts +52 -0
  740. package/src/agent/tool-result-images.ts +178 -0
  741. package/src/agent/tool-search.ts +376 -0
  742. package/src/agent/types.ts +372 -0
  743. package/src/agent-native/index.ts +198 -0
  744. package/src/agent-web/config.ts +253 -0
  745. package/src/agent-web/generator.ts +382 -0
  746. package/src/agent-web/index.ts +36 -0
  747. package/src/appearance/actions/change-appearance.ts +35 -0
  748. package/src/application-state/emitter.ts +81 -0
  749. package/src/application-state/handlers.ts +121 -0
  750. package/src/application-state/index.ts +44 -0
  751. package/src/application-state/script-helpers.ts +155 -0
  752. package/src/application-state/store.ts +274 -0
  753. package/src/assets/branding/agent-native.icon/Assets/background.svg +3 -0
  754. package/src/assets/branding/agent-native.icon/Assets/foreground.svg +12 -0
  755. package/src/assets/branding/agent-native.icon/icon.json +49 -0
  756. package/src/assets/branding/favicon.png +0 -0
  757. package/src/assets/branding/favicon.svg +1 -0
  758. package/src/assets/branding/icon-on-dark.svg +10 -0
  759. package/src/assets/branding/icon-on-light.svg +10 -0
  760. package/src/assets/branding/mac-app-icon.svg +1 -0
  761. package/src/assets/branding/slack-bot/agent-native-1024.png +0 -0
  762. package/src/assets/branding/slack-bot/agent-native-512.png +0 -0
  763. package/src/assets/branding/tray-icon.svg +6 -0
  764. package/src/assets/branding/wordmark-on-dark.svg +21 -0
  765. package/src/assets/branding/wordmark-on-light.svg +21 -0
  766. package/src/assets/fonts/LICENSE_LIBERATION +96 -0
  767. package/src/assets/fonts/LICENSE_NOTO_NASKH_ARABIC +93 -0
  768. package/src/assets/fonts/LiberationSans-Bold.ttf +0 -0
  769. package/src/assets/fonts/LiberationSans-Regular.ttf +0 -0
  770. package/src/assets/fonts/NotoNaskhArabic-Variable.ttf +0 -0
  771. package/src/audit/actions/export-audit-events.ts +162 -0
  772. package/src/audit/actions/get-audit-event.ts +24 -0
  773. package/src/audit/actions/list-audit-events.ts +66 -0
  774. package/src/audit/cleanup-job.ts +100 -0
  775. package/src/audit/config.ts +90 -0
  776. package/src/audit/index.ts +43 -0
  777. package/src/audit/record.ts +180 -0
  778. package/src/audit/redact.ts +109 -0
  779. package/src/audit/store.ts +346 -0
  780. package/src/audit/types.ts +141 -0
  781. package/src/automation/index.ts +802 -0
  782. package/src/brand-kit/brand-signals.ts +124 -0
  783. package/src/brand-kit/fig/index.ts +64 -0
  784. package/src/brand-kit/index.ts +72 -0
  785. package/src/brand-kit/types.ts +113 -0
  786. package/src/browser-sessions/actions.ts +302 -0
  787. package/src/browser-sessions/routes.ts +234 -0
  788. package/src/browser-sessions/store.ts +679 -0
  789. package/src/browser-sessions/types.ts +84 -0
  790. package/src/changelog/parse.ts +328 -0
  791. package/src/chat-threads/emitter.ts +22 -0
  792. package/src/chat-threads/schema.ts +43 -0
  793. package/src/chat-threads/store.ts +1311 -0
  794. package/src/checkpoints/index.ts +15 -0
  795. package/src/checkpoints/service.ts +142 -0
  796. package/src/checkpoints/store.ts +153 -0
  797. package/src/cli/add.ts +425 -0
  798. package/src/cli/agent.ts +424 -0
  799. package/src/cli/agents.ts +122 -0
  800. package/src/cli/app-skill.ts +1455 -0
  801. package/src/cli/atomic-json-file.ts +324 -0
  802. package/src/cli/audit-agent-web.ts +324 -0
  803. package/src/cli/changelog.ts +199 -0
  804. package/src/cli/claude-code-participant.ts +515 -0
  805. package/src/cli/code-agent-commands.ts +270 -0
  806. package/src/cli/code-agent-connector.ts +1109 -0
  807. package/src/cli/code-agent-executor.ts +1970 -0
  808. package/src/cli/code-agent-output-smoother.ts +140 -0
  809. package/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
  810. package/src/cli/code-agent-runs.ts +548 -0
  811. package/src/cli/code.ts +1805 -0
  812. package/src/cli/codex-cli-participant.ts +496 -0
  813. package/src/cli/connect.ts +2714 -0
  814. package/src/cli/content-local.ts +442 -0
  815. package/src/cli/context-xray-local.ts +2193 -0
  816. package/src/cli/create-workspace.ts +30 -0
  817. package/src/cli/create.ts +2247 -0
  818. package/src/cli/deploy-build.ts +50 -0
  819. package/src/cli/design-connect.ts +3187 -0
  820. package/src/cli/doctor.ts +472 -0
  821. package/src/cli/eject.ts +1594 -0
  822. package/src/cli/eval.ts +134 -0
  823. package/src/cli/gateway-helpers.ts +70 -0
  824. package/src/cli/index.ts +1217 -0
  825. package/src/cli/info.ts +105 -0
  826. package/src/cli/invoke.ts +288 -0
  827. package/src/cli/mcp-config-writers.ts +857 -0
  828. package/src/cli/mcp.ts +594 -0
  829. package/src/cli/migrate.ts +1813 -0
  830. package/src/cli/migration-codemod.ts +646 -0
  831. package/src/cli/multi-frontier-runs.ts +1952 -0
  832. package/src/cli/package-lifecycle.ts +823 -0
  833. package/src/cli/plan-blocks.ts +143 -0
  834. package/src/cli/plan-local.ts +3189 -0
  835. package/src/cli/plan-publish-store.ts +138 -0
  836. package/src/cli/pr-visual-recap-workflow.ts +2 -0
  837. package/src/cli/recap.ts +5 -0
  838. package/src/cli/setup-agents.ts +120 -0
  839. package/src/cli/skills-content/assets-skill.ts +83 -0
  840. package/src/cli/skills-content/canvas.ts +153 -0
  841. package/src/cli/skills-content/connection.ts +52 -0
  842. package/src/cli/skills-content/content-skill.ts +120 -0
  843. package/src/cli/skills-content/design-exploration-skill.ts +118 -0
  844. package/src/cli/skills-content/design-visual-edit-skill.ts +228 -0
  845. package/src/cli/skills-content/document-quality.ts +196 -0
  846. package/src/cli/skills-content/exemplar.ts +69 -0
  847. package/src/cli/skills-content/help.ts +77 -0
  848. package/src/cli/skills-content/index.ts +22 -0
  849. package/src/cli/skills-content/local-files.ts +100 -0
  850. package/src/cli/skills-content/plan-setup-auth.ts +80 -0
  851. package/src/cli/skills-content/visual-plan-skill.ts +493 -0
  852. package/src/cli/skills-content/visual-recap-skill.ts +553 -0
  853. package/src/cli/skills-content/visualize-repo-skill.ts +93 -0
  854. package/src/cli/skills-content/wireframe.ts +349 -0
  855. package/src/cli/skills.ts +4340 -0
  856. package/src/cli/sync-builder-starter-manifest.ts +631 -0
  857. package/src/cli/telemetry.ts +136 -0
  858. package/src/cli/templates-meta.ts +269 -0
  859. package/src/cli/upgrade.ts +956 -0
  860. package/src/cli/visualize-repo.ts +715 -0
  861. package/src/cli/workspace-dev.ts +1486 -0
  862. package/src/cli/workspacify.ts +258 -0
  863. package/src/client/AgentAskPopover.tsx +89 -0
  864. package/src/client/AgentChatHome.tsx +66 -0
  865. package/src/client/AgentNative.tsx +161 -0
  866. package/src/client/AgentNativeEmbedded.tsx +288 -0
  867. package/src/client/AgentNativeFrame.tsx +151 -0
  868. package/src/client/AgentPanel.tsx +3437 -0
  869. package/src/client/AgentTaskCard.tsx +273 -0
  870. package/src/client/AppearancePicker.tsx +79 -0
  871. package/src/client/AssistantChat.tsx +5793 -0
  872. package/src/client/ClientOnly.tsx +22 -0
  873. package/src/client/CommandMenu.tsx +726 -0
  874. package/src/client/ConnectBuilderCard.tsx +390 -0
  875. package/src/client/DefaultSpinner.tsx +47 -0
  876. package/src/client/ErrorBoundary.tsx +359 -0
  877. package/src/client/ErrorReportActions.tsx +69 -0
  878. package/src/client/FeedbackButton.tsx +553 -0
  879. package/src/client/HighlightedCodeBlock.tsx +173 -0
  880. package/src/client/IframeEmbed.tsx +151 -0
  881. package/src/client/KeepTabOpenNotice.tsx +181 -0
  882. package/src/client/MultiTabAssistantChat.tsx +2576 -0
  883. package/src/client/NewWorkspaceAppFlow.tsx +525 -0
  884. package/src/client/PoweredByBadge.tsx +284 -0
  885. package/src/client/RunStuckBanner.tsx +431 -0
  886. package/src/client/StarfieldBackground.tsx +466 -0
  887. package/src/client/Turnstile.tsx +125 -0
  888. package/src/client/active-run-state.ts +139 -0
  889. package/src/client/agent-chat/index.ts +279 -0
  890. package/src/client/agent-chat-adapter.ts +3692 -0
  891. package/src/client/agent-chat.ts +1233 -0
  892. package/src/client/agent-engine-key.ts +122 -0
  893. package/src/client/agent-page/AgentContextTab.tsx +487 -0
  894. package/src/client/agent-page/AgentEmptyState.tsx +44 -0
  895. package/src/client/agent-page/AgentJobsTab.tsx +441 -0
  896. package/src/client/agent-page/AgentTabFrame.tsx +39 -0
  897. package/src/client/agent-page/AgentTabsPage.tsx +1096 -0
  898. package/src/client/agent-page/types.ts +18 -0
  899. package/src/client/agent-page/use-jobs.ts +150 -0
  900. package/src/client/agent-sidebar-state.ts +166 -0
  901. package/src/client/analytics/index.ts +40 -0
  902. package/src/client/analytics-session.ts +70 -0
  903. package/src/client/analytics.ts +1757 -0
  904. package/src/client/api-path.ts +124 -0
  905. package/src/client/app-providers.tsx +230 -0
  906. package/src/client/appearance.ts +130 -0
  907. package/src/client/application-state.ts +154 -0
  908. package/src/client/assistant-ui-recovery.tsx +205 -0
  909. package/src/client/automation/index.ts +4 -0
  910. package/src/client/automation.ts +22 -0
  911. package/src/client/blocks/AiEditableField.tsx +30 -0
  912. package/src/client/blocks/BlockView.tsx +145 -0
  913. package/src/client/blocks/RegistryBlockDataProvider.tsx +121 -0
  914. package/src/client/blocks/SchemaBlockEditor.tsx +457 -0
  915. package/src/client/blocks/agent.ts +95 -0
  916. package/src/client/blocks/code-block-direction.ts +21 -0
  917. package/src/client/blocks/index.ts +308 -0
  918. package/src/client/blocks/library/AnnotatedCodeBlock.tsx +710 -0
  919. package/src/client/blocks/library/ApiEndpointBlock.tsx +1120 -0
  920. package/src/client/blocks/library/DataModelBlock.tsx +775 -0
  921. package/src/client/blocks/library/DiffBlock.tsx +1854 -0
  922. package/src/client/blocks/library/FileTreeBlock.tsx +868 -0
  923. package/src/client/blocks/library/HighlightedCode.tsx +260 -0
  924. package/src/client/blocks/library/JsonExplorerBlock.tsx +608 -0
  925. package/src/client/blocks/library/MermaidBlock.tsx +362 -0
  926. package/src/client/blocks/library/OpenApiSpecBlock.tsx +998 -0
  927. package/src/client/blocks/library/annotated-code.config.ts +101 -0
  928. package/src/client/blocks/library/annotation-rail.tsx +1020 -0
  929. package/src/client/blocks/library/api-endpoint.config.ts +207 -0
  930. package/src/client/blocks/library/block-copy.ts +399 -0
  931. package/src/client/blocks/library/callout.config.ts +57 -0
  932. package/src/client/blocks/library/callout.tsx +149 -0
  933. package/src/client/blocks/library/checklist.config.ts +56 -0
  934. package/src/client/blocks/library/checklist.tsx +208 -0
  935. package/src/client/blocks/library/code-filename-label.tsx +59 -0
  936. package/src/client/blocks/library/code-highlight.tsx +178 -0
  937. package/src/client/blocks/library/code-tabs.config.ts +70 -0
  938. package/src/client/blocks/library/code-tabs.tsx +606 -0
  939. package/src/client/blocks/library/code.config.ts +69 -0
  940. package/src/client/blocks/library/code.tsx +440 -0
  941. package/src/client/blocks/library/columns.config.ts +85 -0
  942. package/src/client/blocks/library/columns.tsx +334 -0
  943. package/src/client/blocks/library/data-model.config.ts +152 -0
  944. package/src/client/blocks/library/dev-doc-ui.tsx +191 -0
  945. package/src/client/blocks/library/diagram.config.ts +222 -0
  946. package/src/client/blocks/library/diagram.tsx +958 -0
  947. package/src/client/blocks/library/diff.config.ts +115 -0
  948. package/src/client/blocks/library/file-tree.config.ts +92 -0
  949. package/src/client/blocks/library/html.config.ts +79 -0
  950. package/src/client/blocks/library/html.tsx +258 -0
  951. package/src/client/blocks/library/json-explorer.config.ts +74 -0
  952. package/src/client/blocks/library/mermaid.config.ts +49 -0
  953. package/src/client/blocks/library/narrow-container.tsx +37 -0
  954. package/src/client/blocks/library/openapi-spec.config.ts +66 -0
  955. package/src/client/blocks/library/question-form.config.ts +127 -0
  956. package/src/client/blocks/library/question-form.tsx +944 -0
  957. package/src/client/blocks/library/sanitize-html.ts +343 -0
  958. package/src/client/blocks/library/server-specs.ts +338 -0
  959. package/src/client/blocks/library/specs.tsx +308 -0
  960. package/src/client/blocks/library/table.config.ts +61 -0
  961. package/src/client/blocks/library/table.tsx +449 -0
  962. package/src/client/blocks/library/tabs.config.ts +96 -0
  963. package/src/client/blocks/library/tabs.tsx +665 -0
  964. package/src/client/blocks/library/wireframe-icons.ts +210 -0
  965. package/src/client/blocks/library/wireframe-kit.tsx +1850 -0
  966. package/src/client/blocks/library/wireframe.config.ts +539 -0
  967. package/src/client/blocks/library/wireframe.tsx +535 -0
  968. package/src/client/blocks/mdx.ts +364 -0
  969. package/src/client/blocks/provider.tsx +51 -0
  970. package/src/client/blocks/registry.ts +83 -0
  971. package/src/client/blocks/schema-form/introspect.ts +201 -0
  972. package/src/client/blocks/server.ts +170 -0
  973. package/src/client/blocks/types.ts +415 -0
  974. package/src/client/browser-session-bridge.ts +548 -0
  975. package/src/client/browser-tab-id.ts +36 -0
  976. package/src/client/builder-frame.ts +194 -0
  977. package/src/client/builder-mark.tsx +21 -0
  978. package/src/client/changelog/Changelog.tsx +333 -0
  979. package/src/client/changelog/index.ts +1 -0
  980. package/src/client/chat/ChatHistoryList.tsx +7 -0
  981. package/src/client/chat/attachment-adapters.ts +426 -0
  982. package/src/client/chat/connectors.ts +1579 -0
  983. package/src/client/chat/index.ts +160 -0
  984. package/src/client/chat/markdown-renderer.tsx +693 -0
  985. package/src/client/chat/message-components.tsx +1326 -0
  986. package/src/client/chat/repo-helpers.ts +281 -0
  987. package/src/client/chat/run-recovery.tsx +994 -0
  988. package/src/client/chat/runtime.ts +1810 -0
  989. package/src/client/chat/tool-call-display.tsx +1270 -0
  990. package/src/client/chat/tool-render-registry.tsx +144 -0
  991. package/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  992. package/src/client/chat/use-reconnect-reader-owner.ts +28 -0
  993. package/src/client/chat/widgets/DataChartRenderer.tsx +242 -0
  994. package/src/client/chat/widgets/DataChartWidget.tsx +51 -0
  995. package/src/client/chat/widgets/DataInsightsWidget.tsx +59 -0
  996. package/src/client/chat/widgets/DataTableWidget.tsx +240 -0
  997. package/src/client/chat/widgets/InlineExtensionWidget.tsx +60 -0
  998. package/src/client/chat/widgets/builtin-tool-renderers.tsx +213 -0
  999. package/src/client/chat/widgets/data-widget-types.ts +1 -0
  1000. package/src/client/chat/widgets/inline-extension-result.ts +86 -0
  1001. package/src/client/chat-model-groups.ts +171 -0
  1002. package/src/client/chat-thread-url.ts +11 -0
  1003. package/src/client/chat-view-transition.ts +213 -0
  1004. package/src/client/client-action.ts +21 -0
  1005. package/src/client/client-bootstrap.ts +7 -0
  1006. package/src/client/client-surface.ts +41 -0
  1007. package/src/client/clipboard.ts +89 -0
  1008. package/src/client/code-agent-chat-adapter.ts +537 -0
  1009. package/src/client/collab/index.ts +60 -0
  1010. package/src/client/command-navigation/index.ts +15 -0
  1011. package/src/client/comments-review/index.ts +1 -0
  1012. package/src/client/components/AgentPresenceChip.tsx +4 -0
  1013. package/src/client/components/ApiKeySettings.tsx +309 -0
  1014. package/src/client/components/CodeAgentIndicator.tsx +59 -0
  1015. package/src/client/components/CodeRequiredDialog.tsx +470 -0
  1016. package/src/client/components/LiveCursorOverlay.tsx +5 -0
  1017. package/src/client/components/MissingKeyCard.tsx +61 -0
  1018. package/src/client/components/PresenceBar.tsx +4 -0
  1019. package/src/client/components/RecentEditHighlights.tsx +4 -0
  1020. package/src/client/components/RemoteSelectionRings.tsx +5 -0
  1021. package/src/client/components/icons/AgentNativeIcon.tsx +46 -0
  1022. package/src/client/components/ui/dialog.tsx +1 -0
  1023. package/src/client/components/ui/dropdown-menu.tsx +1 -0
  1024. package/src/client/components/ui/hover-card.tsx +1 -0
  1025. package/src/client/components/ui/message-scroller.tsx +131 -0
  1026. package/src/client/components/ui/popover.tsx +1 -0
  1027. package/src/client/components/ui/sheet.tsx +1 -0
  1028. package/src/client/components/ui/tooltip.tsx +1 -0
  1029. package/src/client/composer/index.ts +11 -0
  1030. package/src/client/composer/runtime-adapters.tsx +123 -0
  1031. package/src/client/composer/use-mention-search.ts +7 -0
  1032. package/src/client/composer/wired-components.tsx +53 -0
  1033. package/src/client/context-xray/ContextMeter.tsx +124 -0
  1034. package/src/client/context-xray/ContextSegmentRow.tsx +27 -0
  1035. package/src/client/context-xray/ContextTreemap.tsx +24 -0
  1036. package/src/client/context-xray/ContextXRayPanel.tsx +59 -0
  1037. package/src/client/context-xray/SegmentProvenancePopover.tsx +18 -0
  1038. package/src/client/context-xray/format.ts +27 -0
  1039. package/src/client/conversation/AgentConversation.tsx +555 -0
  1040. package/src/client/conversation/code-agent-transcript.ts +283 -0
  1041. package/src/client/conversation/index.ts +22 -0
  1042. package/src/client/conversation/types.ts +85 -0
  1043. package/src/client/conversation/use-near-bottom-autoscroll.ts +278 -0
  1044. package/src/client/create-query-client.ts +86 -0
  1045. package/src/client/db-admin/DataGrid.tsx +551 -0
  1046. package/src/client/db-admin/DbAdminPage.tsx +218 -0
  1047. package/src/client/db-admin/DevDatabaseLink.tsx +16 -0
  1048. package/src/client/db-admin/EditableCell.tsx +451 -0
  1049. package/src/client/db-admin/FilterBar.tsx +203 -0
  1050. package/src/client/db-admin/ResultsGrid.tsx +114 -0
  1051. package/src/client/db-admin/RowSidePanel.tsx +337 -0
  1052. package/src/client/db-admin/SqlEditor.tsx +840 -0
  1053. package/src/client/db-admin/TableBrowser.tsx +212 -0
  1054. package/src/client/db-admin/TableEditor.tsx +760 -0
  1055. package/src/client/db-admin/cell-format.ts +246 -0
  1056. package/src/client/db-admin/changeset.ts +296 -0
  1057. package/src/client/db-admin/export-utils.ts +78 -0
  1058. package/src/client/db-admin/index.ts +33 -0
  1059. package/src/client/db-admin/sql-storage.ts +134 -0
  1060. package/src/client/db-admin/storage.ts +68 -0
  1061. package/src/client/db-admin/useAgentSync.ts +226 -0
  1062. package/src/client/db-admin/useDbAdmin.ts +294 -0
  1063. package/src/client/dev-overlay/DevOverlay.tsx +576 -0
  1064. package/src/client/dev-overlay/builtins.ts +40 -0
  1065. package/src/client/dev-overlay/index.ts +23 -0
  1066. package/src/client/dev-overlay/registry.ts +67 -0
  1067. package/src/client/dev-overlay/types.ts +64 -0
  1068. package/src/client/dev-overlay/use-dev-option.ts +78 -0
  1069. package/src/client/dev-overlay/use-dev-overlay-shortcut.ts +31 -0
  1070. package/src/client/dynamic-suggestions.ts +455 -0
  1071. package/src/client/embed-auth.ts +544 -0
  1072. package/src/client/embed.ts +54 -0
  1073. package/src/client/error-capture.ts +690 -0
  1074. package/src/client/error-format.ts +211 -0
  1075. package/src/client/error-reporting.ts +100 -0
  1076. package/src/client/extensions/AgentNativeExtensionFrame.e2e-host.tsx +136 -0
  1077. package/src/client/extensions/AgentNativeExtensionFrame.tsx +708 -0
  1078. package/src/client/extensions/EmbeddedExtension.tsx +604 -0
  1079. package/src/client/extensions/ExtensionEditor.tsx +450 -0
  1080. package/src/client/extensions/ExtensionQueryErrorState.tsx +47 -0
  1081. package/src/client/extensions/ExtensionSlot.tsx +345 -0
  1082. package/src/client/extensions/ExtensionViewer.tsx +1502 -0
  1083. package/src/client/extensions/ExtensionViewerPage.tsx +32 -0
  1084. package/src/client/extensions/ExtensionsListPage.tsx +432 -0
  1085. package/src/client/extensions/ExtensionsSidebarSection.tsx +1259 -0
  1086. package/src/client/extensions/InlineExtensionFrame.tsx +660 -0
  1087. package/src/client/extensions/agent-native-extension-runtime.ts +495 -0
  1088. package/src/client/extensions/delete-extension.ts +76 -0
  1089. package/src/client/extensions/extension-load-error.ts +26 -0
  1090. package/src/client/extensions/extension-order.ts +49 -0
  1091. package/src/client/extensions/extension-popularity.ts +61 -0
  1092. package/src/client/extensions/iframe-bridge.ts +377 -0
  1093. package/src/client/extensions/index.ts +84 -0
  1094. package/src/client/extensions/portable-extension.ts +712 -0
  1095. package/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
  1096. package/src/client/feature-flags/helpers.ts +77 -0
  1097. package/src/client/feature-flags/index.ts +13 -0
  1098. package/src/client/feature-flags/types.ts +29 -0
  1099. package/src/client/feature-flags/use-feature-flag.ts +26 -0
  1100. package/src/client/feedback-context.ts +90 -0
  1101. package/src/client/frame-protocol.ts +168 -0
  1102. package/src/client/frame.ts +329 -0
  1103. package/src/client/guided-questions.tsx +1152 -0
  1104. package/src/client/history/VersionHistoryPanel.tsx +175 -0
  1105. package/src/client/history/index.ts +21 -0
  1106. package/src/client/history/use-history.ts +114 -0
  1107. package/src/client/hooks/index.ts +46 -0
  1108. package/src/client/host/index.ts +170 -0
  1109. package/src/client/host-bridge.ts +1272 -0
  1110. package/src/client/host-tools.ts +190 -0
  1111. package/src/client/i18n.tsx +798 -0
  1112. package/src/client/index.ts +370 -0
  1113. package/src/client/integrations/IntegrationCard.tsx +186 -0
  1114. package/src/client/integrations/IntegrationsPanel.tsx +633 -0
  1115. package/src/client/integrations/api.ts +295 -0
  1116. package/src/client/integrations/index.ts +29 -0
  1117. package/src/client/integrations/useIntegrationStatus.ts +52 -0
  1118. package/src/client/mcp-app-host.ts +720 -0
  1119. package/src/client/mcp-apps/McpAppRenderer.tsx +760 -0
  1120. package/src/client/navigation/index.ts +54 -0
  1121. package/src/client/notifications/NotificationsBell.tsx +383 -0
  1122. package/src/client/notifications/index.ts +1 -0
  1123. package/src/client/observability/ObservabilityDashboard.tsx +890 -0
  1124. package/src/client/observability/ThumbsFeedback.tsx +160 -0
  1125. package/src/client/observability/index.ts +20 -0
  1126. package/src/client/observability/useObservability.ts +266 -0
  1127. package/src/client/onboarding/OnboardingBanner.tsx +73 -0
  1128. package/src/client/onboarding/OnboardingPanel.tsx +1036 -0
  1129. package/src/client/onboarding/SetupButton.tsx +64 -0
  1130. package/src/client/onboarding/index.ts +25 -0
  1131. package/src/client/onboarding/use-onboarding.ts +164 -0
  1132. package/src/client/onboarding/use-preview-mode.ts +40 -0
  1133. package/src/client/org/InvitationBanner.tsx +148 -0
  1134. package/src/client/org/OrgSwitcher.tsx +754 -0
  1135. package/src/client/org/RequireActiveOrg.tsx +337 -0
  1136. package/src/client/org/TeamPage.tsx +1432 -0
  1137. package/src/client/org/hooks.ts +359 -0
  1138. package/src/client/org/index.ts +70 -0
  1139. package/src/client/org/workspace-app-links.ts +367 -0
  1140. package/src/client/org-team/index.ts +1 -0
  1141. package/src/client/progress/RunsTray.tsx +680 -0
  1142. package/src/client/progress/index.ts +1 -0
  1143. package/src/client/require-session.tsx +142 -0
  1144. package/src/client/resources/BuiltinCapabilityDetail.tsx +258 -0
  1145. package/src/client/resources/McpConnectionSuggestion.tsx +276 -0
  1146. package/src/client/resources/McpIntegrationDialog.tsx +808 -0
  1147. package/src/client/resources/McpServerDetail.tsx +230 -0
  1148. package/src/client/resources/ResourceEditor.tsx +872 -0
  1149. package/src/client/resources/ResourceTree.tsx +860 -0
  1150. package/src/client/resources/ResourcesPanel.tsx +1960 -0
  1151. package/src/client/resources/index.ts +25 -0
  1152. package/src/client/resources/mcp-integration-catalog.ts +771 -0
  1153. package/src/client/resources/mcp-integration-logos.ts +108 -0
  1154. package/src/client/resources/runtime.ts +1 -0
  1155. package/src/client/resources/use-builtin-capabilities.ts +113 -0
  1156. package/src/client/resources/use-mcp-servers.ts +217 -0
  1157. package/src/client/resources/use-resources.ts +402 -0
  1158. package/src/client/review/ReviewCommentComposer.tsx +123 -0
  1159. package/src/client/review/ReviewStatusBadge.tsx +39 -0
  1160. package/src/client/review/ReviewThreadPanel.tsx +625 -0
  1161. package/src/client/review/index.ts +38 -0
  1162. package/src/client/review/use-review.ts +186 -0
  1163. package/src/client/route-chunk-recovery/index.ts +1 -0
  1164. package/src/client/route-chunk-recovery.ts +331 -0
  1165. package/src/client/route-state.ts +455 -0
  1166. package/src/client/route-warmup.tsx +543 -0
  1167. package/src/client/session-replay-iframe.e2e-host.tsx +100 -0
  1168. package/src/client/session-replay.ts +3417 -0
  1169. package/src/client/settings/AgentsSection.tsx +441 -0
  1170. package/src/client/settings/AutomationsSection.tsx +516 -0
  1171. package/src/client/settings/BackgroundAgentSection.tsx +189 -0
  1172. package/src/client/settings/BrowserSection.tsx +110 -0
  1173. package/src/client/settings/DemoModeSection.tsx +48 -0
  1174. package/src/client/settings/SecretsSection.tsx +875 -0
  1175. package/src/client/settings/SettingsPanel.tsx +3162 -0
  1176. package/src/client/settings/SettingsSection.tsx +283 -0
  1177. package/src/client/settings/SettingsTabsPage.tsx +592 -0
  1178. package/src/client/settings/UsageSection.tsx +401 -0
  1179. package/src/client/settings/VoiceTranscriptionSection.tsx +960 -0
  1180. package/src/client/settings/agent-settings-search.ts +220 -0
  1181. package/src/client/settings/index.ts +27 -0
  1182. package/src/client/settings/useBuilderStatus.ts +1055 -0
  1183. package/src/client/setup-connections/BuilderConnectCard.tsx +89 -0
  1184. package/src/client/setup-connections/ProviderReadinessBadge.tsx +73 -0
  1185. package/src/client/setup-connections/SetupConnectionsPage.tsx +94 -0
  1186. package/src/client/setup-connections/catalog.ts +6 -0
  1187. package/src/client/setup-connections/index.ts +47 -0
  1188. package/src/client/setup-connections/runtime.ts +1 -0
  1189. package/src/client/sharing/ShareButton.tsx +1748 -0
  1190. package/src/client/sharing/ShareDialog.tsx +846 -0
  1191. package/src/client/sharing/VisibilityBadge.tsx +4 -0
  1192. package/src/client/sharing/index.ts +2 -0
  1193. package/src/client/sse-event-processor.ts +2002 -0
  1194. package/src/client/terminal/AgentTerminal.tsx +488 -0
  1195. package/src/client/terminal/index.ts +7 -0
  1196. package/src/client/theme.ts +27 -0
  1197. package/src/client/tombstone/agent-presence-chip.ts +17 -0
  1198. package/src/client/tombstone/editor.ts +265 -0
  1199. package/src/client/tombstone/live-cursor-overlay.ts +21 -0
  1200. package/src/client/tombstone/presence-bar.ts +17 -0
  1201. package/src/client/tombstone/recent-edit-highlights.ts +17 -0
  1202. package/src/client/tombstone/remote-selection-rings.ts +21 -0
  1203. package/src/client/tombstone/rich-markdown-editor.ts +265 -0
  1204. package/src/client/tombstone/ui-dialog.ts +49 -0
  1205. package/src/client/tombstone/ui-dropdown-menu.ts +69 -0
  1206. package/src/client/tombstone/ui-hover-card.ts +21 -0
  1207. package/src/client/tombstone/ui-popover.ts +25 -0
  1208. package/src/client/tombstone/ui-sheet.ts +49 -0
  1209. package/src/client/tombstone/ui-tooltip.ts +29 -0
  1210. package/src/client/tombstone/visual-style-controls.ts +61 -0
  1211. package/src/client/tool-cells/BashCell.tsx +164 -0
  1212. package/src/client/tool-cells/EditCell.tsx +303 -0
  1213. package/src/client/tool-cells/FilesChangedSummary.tsx +208 -0
  1214. package/src/client/tool-cells/WriteCell.tsx +145 -0
  1215. package/src/client/tool-cells/index.ts +7 -0
  1216. package/src/client/tool-display.ts +41 -0
  1217. package/src/client/track.ts +57 -0
  1218. package/src/client/transcription/BuilderTranscriptionCta.tsx +120 -0
  1219. package/src/client/transcription/use-live-transcription.ts +292 -0
  1220. package/src/client/ui/index.ts +55 -0
  1221. package/src/client/uploads/index.ts +6 -0
  1222. package/src/client/uploads/upload-editor-image.ts +79 -0
  1223. package/src/client/uploads/use-upload-resource.ts +24 -0
  1224. package/src/client/url-scrub.ts +51 -0
  1225. package/src/client/use-action.ts +766 -0
  1226. package/src/client/use-agent-chat-context.ts +63 -0
  1227. package/src/client/use-agent-chat-home-handoff.ts +207 -0
  1228. package/src/client/use-agent-chat.ts +53 -0
  1229. package/src/client/use-agent-engine-configured.ts +211 -0
  1230. package/src/client/use-avatar.ts +127 -0
  1231. package/src/client/use-change-version.ts +150 -0
  1232. package/src/client/use-chat-models.ts +252 -0
  1233. package/src/client/use-chat-threads.ts +1262 -0
  1234. package/src/client/use-db-sync.ts +1112 -0
  1235. package/src/client/use-demo-mode-status.ts +30 -0
  1236. package/src/client/use-dev-mode.ts +177 -0
  1237. package/src/client/use-external-value.ts +40 -0
  1238. package/src/client/use-pausing-interval.ts +65 -0
  1239. package/src/client/use-pinch-zoom.ts +202 -0
  1240. package/src/client/use-run-stuck-detection.ts +427 -0
  1241. package/src/client/use-send-to-agent-chat.ts +85 -0
  1242. package/src/client/use-session.ts +114 -0
  1243. package/src/client/utils.ts +7 -0
  1244. package/src/client/visual-style-controls.tsx +1 -0
  1245. package/src/client/vite-dev-recovery-script.ts +226 -0
  1246. package/src/client/voice-provider-status.ts +44 -0
  1247. package/src/client/widgets/index.ts +41 -0
  1248. package/src/code-agents/background-controller.ts +398 -0
  1249. package/src/code-agents/background-run.ts +156 -0
  1250. package/src/code-agents/index.ts +95 -0
  1251. package/src/code-agents/prompt-attachments.ts +39 -0
  1252. package/src/code-agents/transcript-normalizer.ts +750 -0
  1253. package/src/code-agents/transcript-order.ts +73 -0
  1254. package/src/coding-tools/index.ts +742 -0
  1255. package/src/coding-tools/run-code.ts +1662 -0
  1256. package/src/coding-tools/sandbox/adapter.ts +82 -0
  1257. package/src/coding-tools/sandbox/background.ts +406 -0
  1258. package/src/coding-tools/sandbox/executions-store.ts +517 -0
  1259. package/src/coding-tools/sandbox/index.ts +132 -0
  1260. package/src/coding-tools/sandbox/local-child-process-adapter.ts +217 -0
  1261. package/src/collab/agent-identity.ts +5 -0
  1262. package/src/collab/agent-presence.ts +341 -0
  1263. package/src/collab/awareness-store.ts +196 -0
  1264. package/src/collab/awareness.ts +317 -0
  1265. package/src/collab/client-struct.ts +366 -0
  1266. package/src/collab/client.ts +1205 -0
  1267. package/src/collab/emitter.ts +31 -0
  1268. package/src/collab/follow-mode.ts +107 -0
  1269. package/src/collab/index.ts +151 -0
  1270. package/src/collab/json-to-yjs.ts +504 -0
  1271. package/src/collab/presence.ts +207 -0
  1272. package/src/collab/recent-edits.ts +215 -0
  1273. package/src/collab/routes.ts +191 -0
  1274. package/src/collab/storage.ts +228 -0
  1275. package/src/collab/struct-routes.ts +133 -0
  1276. package/src/collab/text-to-yjs.ts +79 -0
  1277. package/src/collab/undo.ts +432 -0
  1278. package/src/collab/xml-ops.ts +68 -0
  1279. package/src/collab/ydoc-manager.ts +544 -0
  1280. package/src/command-navigation/actions.ts +100 -0
  1281. package/src/command-navigation/index.ts +12 -0
  1282. package/src/comments-review/index.ts +1 -0
  1283. package/src/connections/catalog.ts +451 -0
  1284. package/src/connections/index.ts +48 -0
  1285. package/src/connections/reader.ts +911 -0
  1286. package/src/connections/runtime.ts +1 -0
  1287. package/src/credentials/index.ts +187 -0
  1288. package/src/data-programs/actions.ts +335 -0
  1289. package/src/data-programs/contract.ts +284 -0
  1290. package/src/data-programs/execute.ts +693 -0
  1291. package/src/data-programs/index.ts +72 -0
  1292. package/src/data-programs/schema.ts +148 -0
  1293. package/src/data-programs/store.ts +755 -0
  1294. package/src/data-widgets/index.ts +376 -0
  1295. package/src/db/client.ts +1627 -0
  1296. package/src/db/create-get-db.ts +579 -0
  1297. package/src/db/ddl-guard.ts +302 -0
  1298. package/src/db/drizzle-config.ts +190 -0
  1299. package/src/db/ensure-additive-columns.ts +430 -0
  1300. package/src/db/index.ts +57 -0
  1301. package/src/db/migrations.ts +691 -0
  1302. package/src/db/request-telemetry.ts +154 -0
  1303. package/src/db/runtime-diagnostics.ts +331 -0
  1304. package/src/db/schema.ts +121 -0
  1305. package/src/db/widen-columns.ts +75 -0
  1306. package/src/db-admin/agent-tools.ts +202 -0
  1307. package/src/db-admin/index.ts +26 -0
  1308. package/src/db-admin/operations.ts +803 -0
  1309. package/src/db-admin/routes.ts +174 -0
  1310. package/src/db-admin/types.ts +110 -0
  1311. package/src/demo/browser-state.ts +47 -0
  1312. package/src/demo/fetch-interceptor.ts +175 -0
  1313. package/src/demo/redact.ts +575 -0
  1314. package/src/deploy/build.ts +3935 -0
  1315. package/src/deploy/immutable-assets.ts +65 -0
  1316. package/src/deploy/route-discovery.ts +458 -0
  1317. package/src/deploy/workspace-core.ts +282 -0
  1318. package/src/deploy/workspace-deploy.ts +1488 -0
  1319. package/src/eject/provider-api-definitions.ts +193 -0
  1320. package/src/eject/remote-mcp-presets.ts +137 -0
  1321. package/src/eject/setup-readiness-ui.tsx +29 -0
  1322. package/src/eject/workspace-connections.ts +92 -0
  1323. package/src/embedding/agent.ts +159 -0
  1324. package/src/embedding/bridge.ts +297 -0
  1325. package/src/embedding/index.ts +43 -0
  1326. package/src/embedding/protocol.ts +185 -0
  1327. package/src/embedding/react.tsx +319 -0
  1328. package/src/embeddings/index.ts +233 -0
  1329. package/src/eval/agent-runner.ts +210 -0
  1330. package/src/eval/define-eval.ts +55 -0
  1331. package/src/eval/index.ts +49 -0
  1332. package/src/eval/report.ts +75 -0
  1333. package/src/eval/runner.ts +369 -0
  1334. package/src/eval/scorer.ts +244 -0
  1335. package/src/eval/types.ts +188 -0
  1336. package/src/event-bus/bus.ts +140 -0
  1337. package/src/event-bus/index.ts +3 -0
  1338. package/src/event-bus/registry.ts +79 -0
  1339. package/src/event-bus/types.ts +29 -0
  1340. package/src/extensions/actions.ts +1636 -0
  1341. package/src/extensions/change-marker.ts +54 -0
  1342. package/src/extensions/content-patch.ts +468 -0
  1343. package/src/extensions/fetch-tool.ts +461 -0
  1344. package/src/extensions/html-shell.ts +803 -0
  1345. package/src/extensions/local.ts +462 -0
  1346. package/src/extensions/path.ts +40 -0
  1347. package/src/extensions/proxy-security.ts +171 -0
  1348. package/src/extensions/routes.ts +1080 -0
  1349. package/src/extensions/schema.ts +269 -0
  1350. package/src/extensions/session-replay-iframe.ts +131 -0
  1351. package/src/extensions/slots/routes.ts +126 -0
  1352. package/src/extensions/slots/schema.ts +87 -0
  1353. package/src/extensions/slots/store.ts +450 -0
  1354. package/src/extensions/store.ts +1347 -0
  1355. package/src/extensions/theme.ts +114 -0
  1356. package/src/extensions/url-safety.ts +316 -0
  1357. package/src/extensions/web-content.ts +663 -0
  1358. package/src/extensions/web-search-tool.ts +437 -0
  1359. package/src/feature-flags/a2a-action-route.ts +56 -0
  1360. package/src/feature-flags/actions/get-feature-flags.ts +24 -0
  1361. package/src/feature-flags/actions/list-feature-flags.ts +69 -0
  1362. package/src/feature-flags/actions/set-feature-flag.ts +89 -0
  1363. package/src/feature-flags/index.ts +21 -0
  1364. package/src/feature-flags/permissions.ts +53 -0
  1365. package/src/feature-flags/plugin.ts +44 -0
  1366. package/src/feature-flags/registry.ts +96 -0
  1367. package/src/feature-flags/store.ts +176 -0
  1368. package/src/file-upload/actions/upload-image.ts +213 -0
  1369. package/src/file-upload/builder.ts +431 -0
  1370. package/src/file-upload/index.ts +24 -0
  1371. package/src/file-upload/pre-upload-attachments.ts +305 -0
  1372. package/src/file-upload/registry.ts +125 -0
  1373. package/src/file-upload/types.ts +89 -0
  1374. package/src/guards/db-tool-scoping.ts +129 -0
  1375. package/src/guards/index.ts +23 -0
  1376. package/src/guards/no-drizzle-push.ts +116 -0
  1377. package/src/guards/no-env-credentials.ts +229 -0
  1378. package/src/guards/no-env-mutation.ts +114 -0
  1379. package/src/guards/no-localhost-fallback.ts +124 -0
  1380. package/src/guards/no-unscoped-credentials.ts +227 -0
  1381. package/src/guards/no-unscoped-queries.ts +834 -0
  1382. package/src/guards/scan-utils.ts +105 -0
  1383. package/src/guards/types.ts +30 -0
  1384. package/src/history/actions/create-resource-version.ts +92 -0
  1385. package/src/history/actions/get-resource-version.ts +60 -0
  1386. package/src/history/actions/list-resource-history.ts +53 -0
  1387. package/src/history/actions/list-resource-versions.ts +43 -0
  1388. package/src/history/actions/restore-resource-version.ts +96 -0
  1389. package/src/history/index.ts +26 -0
  1390. package/src/history/registry.ts +111 -0
  1391. package/src/history/store.ts +379 -0
  1392. package/src/history/types.ts +69 -0
  1393. package/src/index.browser.ts +155 -0
  1394. package/src/index.ts +408 -0
  1395. package/src/ingestion/docx.ts +158 -0
  1396. package/src/ingestion/figma-node-to-html.ts +1860 -0
  1397. package/src/ingestion/figma.ts +548 -0
  1398. package/src/ingestion/index.ts +107 -0
  1399. package/src/ingestion/media.ts +264 -0
  1400. package/src/ingestion/notion.ts +121 -0
  1401. package/src/ingestion/office.ts +213 -0
  1402. package/src/ingestion/orchestration.ts +160 -0
  1403. package/src/ingestion/pptx.ts +331 -0
  1404. package/src/ingestion/selection.ts +81 -0
  1405. package/src/ingestion/website.ts +151 -0
  1406. package/src/integrations/a2a-continuation-marker.ts +2 -0
  1407. package/src/integrations/a2a-continuation-processor.ts +888 -0
  1408. package/src/integrations/a2a-continuations-store.ts +643 -0
  1409. package/src/integrations/adapter-overrides.ts +12 -0
  1410. package/src/integrations/adapters/discord.ts +364 -0
  1411. package/src/integrations/adapters/email.ts +1164 -0
  1412. package/src/integrations/adapters/google-docs.ts +371 -0
  1413. package/src/integrations/adapters/index.ts +29 -0
  1414. package/src/integrations/adapters/microsoft-teams.ts +413 -0
  1415. package/src/integrations/adapters/slack.ts +1914 -0
  1416. package/src/integrations/adapters/telegram.ts +386 -0
  1417. package/src/integrations/adapters/whatsapp.ts +358 -0
  1418. package/src/integrations/awaiting-input-store.ts +130 -0
  1419. package/src/integrations/catalog.ts +571 -0
  1420. package/src/integrations/computer-supervision-store.ts +423 -0
  1421. package/src/integrations/computer-supervision.ts +213 -0
  1422. package/src/integrations/config-store.ts +131 -0
  1423. package/src/integrations/controls-store.ts +187 -0
  1424. package/src/integrations/eject/messaging-adapters.ts +85 -0
  1425. package/src/integrations/google-docs-poller.ts +671 -0
  1426. package/src/integrations/identity-links-store.ts +210 -0
  1427. package/src/integrations/identity.ts +196 -0
  1428. package/src/integrations/index.ts +220 -0
  1429. package/src/integrations/installations-store.ts +677 -0
  1430. package/src/integrations/integration-memory.ts +187 -0
  1431. package/src/integrations/internal-token.ts +106 -0
  1432. package/src/integrations/pending-tasks-retry-job.ts +286 -0
  1433. package/src/integrations/pending-tasks-store.ts +468 -0
  1434. package/src/integrations/plugin.ts +3048 -0
  1435. package/src/integrations/remote-commands-store.ts +690 -0
  1436. package/src/integrations/remote-devices-store.ts +492 -0
  1437. package/src/integrations/remote-json-safety.ts +127 -0
  1438. package/src/integrations/remote-push-delivery-job.ts +48 -0
  1439. package/src/integrations/remote-push-delivery.ts +370 -0
  1440. package/src/integrations/remote-push-store.ts +664 -0
  1441. package/src/integrations/remote-retry-job.ts +55 -0
  1442. package/src/integrations/remote-run-events-store.ts +222 -0
  1443. package/src/integrations/remote-types.ts +186 -0
  1444. package/src/integrations/runtime.ts +1 -0
  1445. package/src/integrations/scope-store.ts +498 -0
  1446. package/src/integrations/slack-manifest.ts +78 -0
  1447. package/src/integrations/slack-oauth.ts +344 -0
  1448. package/src/integrations/task-queue-stats.ts +144 -0
  1449. package/src/integrations/thread-mapping-store.ts +134 -0
  1450. package/src/integrations/types.ts +485 -0
  1451. package/src/integrations/usage-budget-store.ts +906 -0
  1452. package/src/integrations/webhook-delivery.ts +55 -0
  1453. package/src/integrations/webhook-handler.ts +1939 -0
  1454. package/src/jobs/actions/list-recurring-jobs.ts +105 -0
  1455. package/src/jobs/actions/manage-recurring-job.ts +85 -0
  1456. package/src/jobs/cron.ts +126 -0
  1457. package/src/jobs/index.ts +9 -0
  1458. package/src/jobs/scheduler.ts +703 -0
  1459. package/src/jobs/tools.ts +367 -0
  1460. package/src/local-artifacts/index.ts +1372 -0
  1461. package/src/localization/actions/get-localization-preference.ts +24 -0
  1462. package/src/localization/actions/set-localization-preference.ts +32 -0
  1463. package/src/localization/default-messages.ts +1009 -0
  1464. package/src/localization/index.ts +2 -0
  1465. package/src/localization/server.ts +131 -0
  1466. package/src/localization/shared.ts +208 -0
  1467. package/src/mcp/actions/call-mcp-tool.ts +19 -0
  1468. package/src/mcp/actions/create-org-service-token.ts +87 -0
  1469. package/src/mcp/actions/list-mcp-tools.ts +18 -0
  1470. package/src/mcp/actions/list-org-service-tokens.ts +44 -0
  1471. package/src/mcp/actions/revoke-org-service-token.ts +30 -0
  1472. package/src/mcp/actions/service-token-access.ts +121 -0
  1473. package/src/mcp/ask-app-inline-tasks.ts +125 -0
  1474. package/src/mcp/build-server.ts +2356 -0
  1475. package/src/mcp/builtin-tools.ts +1506 -0
  1476. package/src/mcp/connect-route.ts +1460 -0
  1477. package/src/mcp/connect-store.ts +680 -0
  1478. package/src/mcp/embed-app.ts +2051 -0
  1479. package/src/mcp/embed-route.ts +84 -0
  1480. package/src/mcp/external-agent-policy.ts +18 -0
  1481. package/src/mcp/index.ts +47 -0
  1482. package/src/mcp/oauth-route.ts +1016 -0
  1483. package/src/mcp/oauth-store.ts +581 -0
  1484. package/src/mcp/oauth-token.ts +227 -0
  1485. package/src/mcp/org-directory.ts +343 -0
  1486. package/src/mcp/route-paths.ts +34 -0
  1487. package/src/mcp/screen-memory-stdio.ts +290 -0
  1488. package/src/mcp/server.ts +507 -0
  1489. package/src/mcp/stdio.ts +328 -0
  1490. package/src/mcp/workspace-resolve.ts +261 -0
  1491. package/src/mcp-client/app-api.ts +136 -0
  1492. package/src/mcp-client/app-result.ts +64 -0
  1493. package/src/mcp-client/builtin-capabilities.ts +146 -0
  1494. package/src/mcp-client/builtin-store.ts +93 -0
  1495. package/src/mcp-client/config.ts +281 -0
  1496. package/src/mcp-client/errors.ts +54 -0
  1497. package/src/mcp-client/hub-client.ts +172 -0
  1498. package/src/mcp-client/hub-routes.ts +198 -0
  1499. package/src/mcp-client/index.ts +504 -0
  1500. package/src/mcp-client/manager.ts +968 -0
  1501. package/src/mcp-client/oauth-client.ts +462 -0
  1502. package/src/mcp-client/oauth-routes.ts +307 -0
  1503. package/src/mcp-client/remote-store.ts +674 -0
  1504. package/src/mcp-client/remote-url.ts +97 -0
  1505. package/src/mcp-client/routes.ts +1093 -0
  1506. package/src/mcp-client/screen-memory-local.ts +461 -0
  1507. package/src/mcp-client/tool-policy.ts +182 -0
  1508. package/src/mcp-client/visibility.ts +56 -0
  1509. package/src/mcp-client/workspace-servers.ts +379 -0
  1510. package/src/navigation/index.ts +170 -0
  1511. package/src/notifications/actions.ts +151 -0
  1512. package/src/notifications/channels.ts +410 -0
  1513. package/src/notifications/index.ts +22 -0
  1514. package/src/notifications/registry.ts +216 -0
  1515. package/src/notifications/routes.ts +106 -0
  1516. package/src/notifications/store.ts +236 -0
  1517. package/src/notifications/types.ts +52 -0
  1518. package/src/oauth-tokens/google-refresh.ts +175 -0
  1519. package/src/oauth-tokens/index.ts +15 -0
  1520. package/src/oauth-tokens/store.ts +384 -0
  1521. package/src/observability/cleanup-job.ts +124 -0
  1522. package/src/observability/evals.ts +507 -0
  1523. package/src/observability/experiments.ts +359 -0
  1524. package/src/observability/feedback.ts +332 -0
  1525. package/src/observability/hosted-model-experiment.ts +118 -0
  1526. package/src/observability/index.ts +62 -0
  1527. package/src/observability/plugin.ts +31 -0
  1528. package/src/observability/routes.ts +431 -0
  1529. package/src/observability/sentiment.ts +261 -0
  1530. package/src/observability/store.ts +1347 -0
  1531. package/src/observability/traces.ts +789 -0
  1532. package/src/observability/tracing.ts +157 -0
  1533. package/src/observability/tracking-identity.ts +55 -0
  1534. package/src/observability/types.ts +211 -0
  1535. package/src/onboarding/default-steps.ts +428 -0
  1536. package/src/onboarding/index.ts +22 -0
  1537. package/src/onboarding/plugin.ts +262 -0
  1538. package/src/onboarding/registry.ts +47 -0
  1539. package/src/onboarding/types.ts +96 -0
  1540. package/src/org/accept-pending.ts +98 -0
  1541. package/src/org/auto-join-domain.ts +113 -0
  1542. package/src/org/context.ts +614 -0
  1543. package/src/org/free-email-providers.ts +124 -0
  1544. package/src/org/handlers.ts +1153 -0
  1545. package/src/org/index.ts +63 -0
  1546. package/src/org/migrations.ts +105 -0
  1547. package/src/org/permissions.ts +30 -0
  1548. package/src/org/plugin.ts +255 -0
  1549. package/src/org/schema.ts +28 -0
  1550. package/src/org/types.ts +57 -0
  1551. package/src/org-team/index.ts +1 -0
  1552. package/src/package-lifecycle/deprecated-imports.ts +179 -0
  1553. package/src/package-lifecycle/eject-manifest.ts +345 -0
  1554. package/src/package-lifecycle/index.ts +7 -0
  1555. package/src/package-lifecycle/manifest.ts +120 -0
  1556. package/src/package-lifecycle/migration-manifest.ts +159 -0
  1557. package/src/package-lifecycle/migration-message.ts +6 -0
  1558. package/src/package-lifecycle/tombstone.ts +58 -0
  1559. package/src/package-lifecycle/upgrade-error.ts +37 -0
  1560. package/src/private-blob/index.ts +18 -0
  1561. package/src/private-blob/registry.ts +242 -0
  1562. package/src/private-blob/types.ts +55 -0
  1563. package/src/progress/actions.ts +179 -0
  1564. package/src/progress/index.ts +16 -0
  1565. package/src/progress/registry.ts +127 -0
  1566. package/src/progress/routes.ts +89 -0
  1567. package/src/progress/store.ts +353 -0
  1568. package/src/progress/types.ts +59 -0
  1569. package/src/provider-api/actions/custom-provider-registration.ts +197 -0
  1570. package/src/provider-api/actions/delete-staged-dataset.ts +5 -0
  1571. package/src/provider-api/actions/github-repo-files.ts +266 -0
  1572. package/src/provider-api/actions/list-staged-datasets.ts +5 -0
  1573. package/src/provider-api/actions/provider-api-audit.ts +88 -0
  1574. package/src/provider-api/actions/provider-api.ts +460 -0
  1575. package/src/provider-api/actions/query-staged-dataset.ts +5 -0
  1576. package/src/provider-api/actions/staged-datasets.ts +359 -0
  1577. package/src/provider-api/corpus-jobs-store.ts +522 -0
  1578. package/src/provider-api/corpus-jobs.ts +1817 -0
  1579. package/src/provider-api/custom-registry.ts +456 -0
  1580. package/src/provider-api/github-repo.ts +675 -0
  1581. package/src/provider-api/gong.ts +108 -0
  1582. package/src/provider-api/index.ts +5444 -0
  1583. package/src/provider-api/quota-governor.ts +562 -0
  1584. package/src/provider-api/runtime.ts +1 -0
  1585. package/src/provider-api/staged-datasets-aggregate.ts +304 -0
  1586. package/src/provider-api/staged-datasets-store.ts +441 -0
  1587. package/src/provider-api/staging.ts +483 -0
  1588. package/src/resources/agents.ts +65 -0
  1589. package/src/resources/emitter.ts +54 -0
  1590. package/src/resources/handlers.ts +728 -0
  1591. package/src/resources/index.ts +4 -0
  1592. package/src/resources/metadata.ts +252 -0
  1593. package/src/resources/script-helpers.ts +160 -0
  1594. package/src/resources/store.ts +1618 -0
  1595. package/src/review/actions/consume-review-feedback.ts +48 -0
  1596. package/src/review/actions/create-review-comment.ts +108 -0
  1597. package/src/review/actions/delete-review-comment.ts +67 -0
  1598. package/src/review/actions/get-review-feedback.ts +49 -0
  1599. package/src/review/actions/list-review-comments.ts +87 -0
  1600. package/src/review/actions/reply-review-comment.ts +118 -0
  1601. package/src/review/actions/resolve-review-thread.ts +94 -0
  1602. package/src/review/actions/send-review-thread-to-agent.ts +62 -0
  1603. package/src/review/actions/set-review-status.ts +58 -0
  1604. package/src/review/identity.ts +101 -0
  1605. package/src/review/index.ts +45 -0
  1606. package/src/review/mentions.ts +44 -0
  1607. package/src/review/registry.ts +111 -0
  1608. package/src/review/store.ts +997 -0
  1609. package/src/review/types.ts +101 -0
  1610. package/src/router/index.ts +24 -0
  1611. package/src/scripts/agent-engines/list-agent-engines.ts +130 -0
  1612. package/src/scripts/agent-engines/manage-agent-engine.ts +197 -0
  1613. package/src/scripts/agent-engines/set-agent-engine.ts +84 -0
  1614. package/src/scripts/agent-engines/test-agent-engine.ts +174 -0
  1615. package/src/scripts/call-agent.ts +792 -0
  1616. package/src/scripts/chat/index.ts +8 -0
  1617. package/src/scripts/chat/open-chat.ts +56 -0
  1618. package/src/scripts/chat/search-chats.ts +121 -0
  1619. package/src/scripts/core-scripts.ts +22 -0
  1620. package/src/scripts/db/check-scoping.ts +212 -0
  1621. package/src/scripts/db/exec.ts +791 -0
  1622. package/src/scripts/db/index.ts +19 -0
  1623. package/src/scripts/db/migrate-encrypt-credentials.ts +223 -0
  1624. package/src/scripts/db/migrate-encrypt-oauth-tokens.ts +213 -0
  1625. package/src/scripts/db/migrate-user-api-keys.ts +257 -0
  1626. package/src/scripts/db/patch.ts +820 -0
  1627. package/src/scripts/db/query.ts +299 -0
  1628. package/src/scripts/db/reset-dev-owner.ts +285 -0
  1629. package/src/scripts/db/safety.ts +286 -0
  1630. package/src/scripts/db/schema.ts +364 -0
  1631. package/src/scripts/db/scoping.ts +341 -0
  1632. package/src/scripts/db/sqlite-client.ts +78 -0
  1633. package/src/scripts/db/tool-mode.ts +23 -0
  1634. package/src/scripts/db/tool-schemas.ts +31 -0
  1635. package/src/scripts/db/wipe-leaked-builder-keys.ts +201 -0
  1636. package/src/scripts/dev/index.ts +296 -0
  1637. package/src/scripts/dev/list-files.ts +119 -0
  1638. package/src/scripts/dev/read-file.ts +77 -0
  1639. package/src/scripts/dev/search-files.ts +151 -0
  1640. package/src/scripts/dev/shell.ts +111 -0
  1641. package/src/scripts/dev/write-file.ts +56 -0
  1642. package/src/scripts/dev-session.ts +96 -0
  1643. package/src/scripts/docs/index.ts +8 -0
  1644. package/src/scripts/docs/search.ts +274 -0
  1645. package/src/scripts/docs/source-search.ts +363 -0
  1646. package/src/scripts/index.ts +15 -0
  1647. package/src/scripts/manage-agent-loop-settings.ts +84 -0
  1648. package/src/scripts/parse-args.ts +46 -0
  1649. package/src/scripts/resources/delete-memory.ts +67 -0
  1650. package/src/scripts/resources/delete.ts +69 -0
  1651. package/src/scripts/resources/effective.ts +71 -0
  1652. package/src/scripts/resources/index.ts +18 -0
  1653. package/src/scripts/resources/list.ts +103 -0
  1654. package/src/scripts/resources/migrate-learnings.ts +40 -0
  1655. package/src/scripts/resources/read.ts +107 -0
  1656. package/src/scripts/resources/save-memory.ts +99 -0
  1657. package/src/scripts/resources/write.ts +158 -0
  1658. package/src/scripts/runner.ts +339 -0
  1659. package/src/scripts/utils.ts +130 -0
  1660. package/src/search/index.ts +413 -0
  1661. package/src/search-utils/index.ts +112 -0
  1662. package/src/secrets/crypto.ts +228 -0
  1663. package/src/secrets/index.ts +65 -0
  1664. package/src/secrets/onboarding.ts +101 -0
  1665. package/src/secrets/register-framework-secrets.ts +228 -0
  1666. package/src/secrets/register.ts +129 -0
  1667. package/src/secrets/routes.ts +697 -0
  1668. package/src/secrets/schema.ts +52 -0
  1669. package/src/secrets/storage.ts +561 -0
  1670. package/src/secrets/substitution.ts +305 -0
  1671. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +150 -0
  1672. package/src/server/action-change.ts +66 -0
  1673. package/src/server/action-discovery.ts +774 -0
  1674. package/src/server/action-routes.ts +608 -0
  1675. package/src/server/agent-access.ts +72 -0
  1676. package/src/server/agent-chat/action-filters-a2a.ts +339 -0
  1677. package/src/server/agent-chat/browser-team-tools.ts +510 -0
  1678. package/src/server/agent-chat/context-tools.ts +599 -0
  1679. package/src/server/agent-chat/framework-prompts.ts +467 -0
  1680. package/src/server/agent-chat/lazy-fs.ts +11 -0
  1681. package/src/server/agent-chat/mcp-glue.ts +91 -0
  1682. package/src/server/agent-chat/plugin-options.ts +379 -0
  1683. package/src/server/agent-chat/process-run-failure.ts +62 -0
  1684. package/src/server/agent-chat/prompt-resources.ts +1004 -0
  1685. package/src/server/agent-chat/recurring-jobs-runtime.ts +80 -0
  1686. package/src/server/agent-chat/request-surface.ts +71 -0
  1687. package/src/server/agent-chat/run-code-tools.ts +67 -0
  1688. package/src/server/agent-chat/script-entries.ts +796 -0
  1689. package/src/server/agent-chat/shared-thread.ts +301 -0
  1690. package/src/server/agent-chat/skill-frontmatter.ts +41 -0
  1691. package/src/server/agent-chat-plugin.ts +5930 -0
  1692. package/src/server/agent-discovery.ts +706 -0
  1693. package/src/server/agent-engine-api-key-route.ts +236 -0
  1694. package/src/server/agent-run-context.ts +204 -0
  1695. package/src/server/agent-teams-run-queue.ts +344 -0
  1696. package/src/server/agent-teams.ts +2257 -0
  1697. package/src/server/agents-bundle.ts +464 -0
  1698. package/src/server/analytics.ts +105 -0
  1699. package/src/server/app-base-path.ts +79 -0
  1700. package/src/server/app-name.ts +53 -0
  1701. package/src/server/app-url.ts +184 -0
  1702. package/src/server/attachment-actions.ts +276 -0
  1703. package/src/server/attribution.ts +214 -0
  1704. package/src/server/auth-marketing.ts +260 -0
  1705. package/src/server/auth-plugin.ts +27 -0
  1706. package/src/server/auth.ts +3803 -0
  1707. package/src/server/better-auth-instance.ts +1197 -0
  1708. package/src/server/builder-browser.ts +1701 -0
  1709. package/src/server/builder-design-systems.ts +668 -0
  1710. package/src/server/builder-space.ts +176 -0
  1711. package/src/server/captcha.ts +63 -0
  1712. package/src/server/capture-error.ts +64 -0
  1713. package/src/server/cli-capture.ts +141 -0
  1714. package/src/server/collab-plugin.ts +391 -0
  1715. package/src/server/complete-text.ts +231 -0
  1716. package/src/server/cookie-namespace.ts +159 -0
  1717. package/src/server/core-routes-plugin.ts +4122 -0
  1718. package/src/server/cors-origins.ts +60 -0
  1719. package/src/server/create-server.ts +268 -0
  1720. package/src/server/credential-provider.ts +1202 -0
  1721. package/src/server/csrf.ts +229 -0
  1722. package/src/server/date-utils.ts +42 -0
  1723. package/src/server/deep-link.ts +119 -0
  1724. package/src/server/derived-secret.ts +32 -0
  1725. package/src/server/design-token-utils.ts +1032 -0
  1726. package/src/server/desktop-sso.ts +83 -0
  1727. package/src/server/edge.ts +69 -0
  1728. package/src/server/email-actions.ts +218 -0
  1729. package/src/server/email-template.ts +192 -0
  1730. package/src/server/email-templates.ts +148 -0
  1731. package/src/server/email.ts +219 -0
  1732. package/src/server/embed-route.ts +283 -0
  1733. package/src/server/embed-session.ts +805 -0
  1734. package/src/server/embedded.ts +252 -0
  1735. package/src/server/entry-server.tsx +154 -0
  1736. package/src/server/framework-request-handler.ts +848 -0
  1737. package/src/server/fusion-app.ts +447 -0
  1738. package/src/server/google-auth-mode.ts +34 -0
  1739. package/src/server/google-auth-plugin.ts +496 -0
  1740. package/src/server/google-oauth-credentials.ts +128 -0
  1741. package/src/server/google-oauth.ts +972 -0
  1742. package/src/server/google-realtime-session.ts +182 -0
  1743. package/src/server/h3-helpers.ts +174 -0
  1744. package/src/server/http-response-telemetry.ts +396 -0
  1745. package/src/server/identity-sso-store.ts +304 -0
  1746. package/src/server/identity-sso.ts +514 -0
  1747. package/src/server/index.ts +593 -0
  1748. package/src/server/missing-key.ts +36 -0
  1749. package/src/server/oauth-helpers.ts +44 -0
  1750. package/src/server/oauth-public-origin.ts +44 -0
  1751. package/src/server/oauth-return-url.ts +120 -0
  1752. package/src/server/og-fonts-data.ts +15 -0
  1753. package/src/server/og-fonts.ts +75 -0
  1754. package/src/server/onboarding-html.ts +4040 -0
  1755. package/src/server/open-route.ts +311 -0
  1756. package/src/server/org-admin.ts +28 -0
  1757. package/src/server/poll-events.ts +88 -0
  1758. package/src/server/poll.ts +1224 -0
  1759. package/src/server/prompts/framework-core-compact.ts +107 -0
  1760. package/src/server/prompts/framework-core.ts +143 -0
  1761. package/src/server/prompts/index.ts +16 -0
  1762. package/src/server/prompts/model-overlays.ts +54 -0
  1763. package/src/server/prompts/shared-rules.ts +104 -0
  1764. package/src/server/realtime-voice.ts +967 -0
  1765. package/src/server/recap-image-route.ts +242 -0
  1766. package/src/server/recap-image-store.ts +185 -0
  1767. package/src/server/request-context.ts +416 -0
  1768. package/src/server/request-origin.ts +67 -0
  1769. package/src/server/resources-plugin.ts +119 -0
  1770. package/src/server/schema-prompt.ts +429 -0
  1771. package/src/server/scoped-key-storage.ts +223 -0
  1772. package/src/server/security-headers.ts +170 -0
  1773. package/src/server/self-dispatch.ts +224 -0
  1774. package/src/server/sentry-config.ts +73 -0
  1775. package/src/server/sentry-plugin.ts +138 -0
  1776. package/src/server/sentry.ts +444 -0
  1777. package/src/server/short-lived-token.ts +170 -0
  1778. package/src/server/social-og-image.ts +454 -0
  1779. package/src/server/sse.ts +102 -0
  1780. package/src/server/ssr-handler.ts +466 -0
  1781. package/src/server/transcribe-voice.ts +1076 -0
  1782. package/src/server/voice-providers-status.ts +118 -0
  1783. package/src/server/workspace-oauth.ts +31 -0
  1784. package/src/server/workspace-provider-oauth.ts +970 -0
  1785. package/src/session-replay-iframe-protocol.ts +58 -0
  1786. package/src/settings/handlers.ts +44 -0
  1787. package/src/settings/index.ts +34 -0
  1788. package/src/settings/org-settings.ts +83 -0
  1789. package/src/settings/script-helpers.ts +24 -0
  1790. package/src/settings/store.ts +247 -0
  1791. package/src/settings/user-settings.ts +47 -0
  1792. package/src/setup-connections/index.ts +90 -0
  1793. package/src/setup-connections/onboarding.ts +47 -0
  1794. package/src/shared/agent-access.ts +112 -0
  1795. package/src/shared/agent-chat.ts +124 -0
  1796. package/src/shared/agent-env.ts +46 -0
  1797. package/src/shared/agent-readable-resource.ts +111 -0
  1798. package/src/shared/agent-sidebar-url.ts +39 -0
  1799. package/src/shared/cache-control.ts +25 -0
  1800. package/src/shared/cloudflare-globals.d.ts +34 -0
  1801. package/src/shared/context-xray.ts +172 -0
  1802. package/src/shared/embed-auth.ts +6 -0
  1803. package/src/shared/index.ts +83 -0
  1804. package/src/shared/llm-connection.ts +42 -0
  1805. package/src/shared/markdown-block-split.ts +129 -0
  1806. package/src/shared/mcp-connect-content.ts +130 -0
  1807. package/src/shared/mcp-embed-headers.ts +175 -0
  1808. package/src/shared/mcp-integration-config.ts +101 -0
  1809. package/src/shared/merge-by-id.ts +14 -0
  1810. package/src/shared/oauth-state.ts +39 -0
  1811. package/src/shared/reasoning-effort.ts +228 -0
  1812. package/src/shared/route-warmup-config.ts +128 -0
  1813. package/src/shared/runtime.ts +31 -0
  1814. package/src/shared/social-meta.ts +82 -0
  1815. package/src/shared/streaming-text-smoothing.ts +184 -0
  1816. package/src/shared/truncate.ts +13 -0
  1817. package/src/shared/workspace-app-audience.ts +177 -0
  1818. package/src/shared/workspace-app-id.ts +54 -0
  1819. package/src/sharing/access.ts +585 -0
  1820. package/src/sharing/actions/create-agent-resource-link.ts +91 -0
  1821. package/src/sharing/actions/extension-change.ts +22 -0
  1822. package/src/sharing/actions/list-resource-shares.ts +93 -0
  1823. package/src/sharing/actions/set-resource-visibility.ts +91 -0
  1824. package/src/sharing/actions/share-resource.ts +322 -0
  1825. package/src/sharing/actions/unshare-resource.ts +72 -0
  1826. package/src/sharing/index.ts +35 -0
  1827. package/src/sharing/registry.ts +201 -0
  1828. package/src/sharing/schema.ts +99 -0
  1829. package/src/styles/agent-conversation.css +766 -0
  1830. package/src/styles/agent-native.css +938 -0
  1831. package/src/styles/blocks.css +1717 -0
  1832. package/src/styles/chat-history-list.css +1 -0
  1833. package/src/styles/rich-markdown-editor.css +1 -0
  1834. package/src/tailwind.preset.ts +140 -0
  1835. package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  1836. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +21 -9
  1837. package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  1838. package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +14 -2
  1839. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  1840. package/src/templates/chat/AGENTS.md +6 -2
  1841. package/src/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  1842. package/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
  1843. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +21 -9
  1844. package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  1845. package/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  1846. package/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  1847. package/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  1848. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +14 -2
  1849. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  1850. package/src/templates/default/AGENTS.md +26 -18
  1851. package/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  1852. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +21 -9
  1853. package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  1854. package/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  1855. package/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  1856. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  1857. package/src/templates/headless/AGENTS.md +8 -0
  1858. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  1859. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +21 -9
  1860. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +7 -0
  1861. package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  1862. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +14 -2
  1863. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  1864. package/src/templates/workspace-core/AGENTS.md +4 -0
  1865. package/src/templates/workspace-root/AGENTS.md +4 -0
  1866. package/src/terminal/cli-registry.ts +57 -0
  1867. package/src/terminal/index.ts +22 -0
  1868. package/src/terminal/pty-server.ts +389 -0
  1869. package/src/terminal/terminal-plugin.ts +265 -0
  1870. package/src/testing.ts +23 -0
  1871. package/src/tracking/index.ts +10 -0
  1872. package/src/tracking/providers.ts +422 -0
  1873. package/src/tracking/registry.ts +102 -0
  1874. package/src/tracking/route.ts +108 -0
  1875. package/src/tracking/types.ts +16 -0
  1876. package/src/transcription/builder-transcription.ts +118 -0
  1877. package/src/triggers/actions/list-automations.ts +99 -0
  1878. package/src/triggers/actions/manage-automation.ts +78 -0
  1879. package/src/triggers/actions.ts +333 -0
  1880. package/src/triggers/condition-evaluator.ts +163 -0
  1881. package/src/triggers/dispatcher.ts +536 -0
  1882. package/src/triggers/index.ts +13 -0
  1883. package/src/triggers/routes.ts +322 -0
  1884. package/src/triggers/types.ts +42 -0
  1885. package/src/types/pglite.d.ts +26 -0
  1886. package/src/usage/store.ts +698 -0
  1887. package/src/vite/action-types-plugin.ts +481 -0
  1888. package/src/vite/agent-web-plugin.ts +78 -0
  1889. package/src/vite/agents-bundle-plugin.ts +185 -0
  1890. package/src/vite/client.ts +3039 -0
  1891. package/src/vite/index.ts +21 -0
  1892. package/src/voice/index.ts +18 -0
  1893. package/src/voice/voice-cleanup-prompt.ts +38 -0
  1894. package/src/voice/voice-context.ts +217 -0
  1895. package/src/voice/voice-replacements.ts +75 -0
  1896. package/src/workspace-connections/credentials.ts +603 -0
  1897. package/src/workspace-connections/index.ts +72 -0
  1898. package/src/workspace-connections/lifecycle.ts +43 -0
  1899. package/src/workspace-connections/store.ts +1943 -0
  1900. package/src/workspace-files/index.ts +18 -0
  1901. package/src/workspace-files/store.ts +339 -0
  1902. package/src/workspace-files/tool.ts +266 -0
@@ -0,0 +1,3189 @@
1
+ /**
2
+ * Plan helper commands.
3
+ *
4
+ * The `plan local` commands are intentionally separate from the Plan app
5
+ * actions. They do not call MCP, hosted write actions, SQLite, or hosted
6
+ * storage; they only read local files or serve them from a localhost bridge so
7
+ * privacy-focused users have an auditable no-DB path. The top-level
8
+ * `plan blocks` command is a schema-only, no-auth helper for fetching the
9
+ * public block catalog before authoring local MDX; it never sends plan content.
10
+ */
11
+
12
+ import { spawnSync } from "node:child_process";
13
+ import crypto from "node:crypto";
14
+ import fs from "node:fs";
15
+ import http, {
16
+ type IncomingMessage,
17
+ type Server,
18
+ type ServerResponse,
19
+ } from "node:http";
20
+ import path from "node:path";
21
+ import { pathToFileURL } from "node:url";
22
+
23
+ import {
24
+ DEFAULT_PLAN_APP_URL,
25
+ defaultPlanBlocksOut,
26
+ fetchPlanBlockCatalog,
27
+ normalizePlanBlockFormat,
28
+ planActionEndpoint,
29
+ } from "./plan-blocks.js";
30
+
31
+ type LocalPlanKind = "plan" | "recap";
32
+
33
+ type LocalPlanFiles = {
34
+ dir: string;
35
+ planMdx: string;
36
+ canvasMdx?: string;
37
+ prototypeMdx?: string;
38
+ stateJson?: string;
39
+ assets?: Record<string, string>;
40
+ };
41
+
42
+ export type LocalPlanValidationIssue = {
43
+ file: string;
44
+ line: number;
45
+ message: string;
46
+ };
47
+
48
+ type LocalPlanPreviewInput = {
49
+ dir: string;
50
+ kind?: LocalPlanKind;
51
+ title?: string;
52
+ brief?: string;
53
+ appUrl?: string;
54
+ };
55
+
56
+ type LocalPlanPreviewResult = {
57
+ ok: true;
58
+ dir: string;
59
+ out?: string;
60
+ url: string;
61
+ title: string;
62
+ kind: LocalPlanKind;
63
+ files: string[];
64
+ opened?: boolean;
65
+ openCommand?: string;
66
+ openError?: string;
67
+ };
68
+
69
+ type LocalPlanBridgeMdxFolder = {
70
+ "plan.mdx": string;
71
+ "canvas.mdx"?: string;
72
+ "prototype.mdx"?: string;
73
+ ".plan-state.json"?: string;
74
+ "assets/"?: Record<string, string>;
75
+ };
76
+
77
+ type LocalPlanBridgeComment = {
78
+ id: string;
79
+ planId: string;
80
+ parentCommentId: string | null;
81
+ sectionId: string | null;
82
+ kind: string;
83
+ status: string;
84
+ anchor: string | null;
85
+ message: string;
86
+ createdBy: string;
87
+ authorEmail: string | null;
88
+ authorName: string | null;
89
+ resolutionTarget: string | null;
90
+ mentions: unknown[];
91
+ mentionsJson: string | null;
92
+ resolvedBy: string | null;
93
+ resolvedAt: string | null;
94
+ consumedAt: string | null;
95
+ deletedAt: string | null;
96
+ deletedBy: string | null;
97
+ createdAt: string;
98
+ updatedAt: string;
99
+ };
100
+
101
+ type LocalPlanBridgeCommentInput = {
102
+ id?: string;
103
+ parentCommentId?: string | null;
104
+ sectionId?: string | null;
105
+ kind?: string;
106
+ status?: string;
107
+ anchor?: string | null;
108
+ message?: string;
109
+ createdBy?: string;
110
+ authorEmail?: string | null;
111
+ authorName?: string | null;
112
+ resolutionTarget?: string | null;
113
+ mentions?: unknown[];
114
+ resolvedBy?: string | null;
115
+ resolvedAt?: string | null;
116
+ };
117
+
118
+ type LocalPlanBridgeCommentUpdate = {
119
+ comments?: LocalPlanBridgeCommentInput[];
120
+ deletedCommentIds?: string[];
121
+ };
122
+
123
+ type VisualAnswerSourcePayload = {
124
+ question?: string;
125
+ title?: string;
126
+ brief?: string;
127
+ repoPath?: string;
128
+ sourceUrl?: string;
129
+ sourceType?: string;
130
+ mdx: {
131
+ "plan.mdx": string;
132
+ "canvas.mdx"?: string;
133
+ "prototype.mdx"?: string;
134
+ "assets/"?: Record<string, string>;
135
+ };
136
+ };
137
+
138
+ export type PublishVisualAnswerInput = {
139
+ appUrl: string;
140
+ token: string;
141
+ question?: string;
142
+ sourcePath?: string;
143
+ out?: string;
144
+ prevPlanId?: string;
145
+ repo?: string;
146
+ sourceUrl?: string;
147
+ sourceType?: string;
148
+ visibility?: "private" | "org" | "public";
149
+ fetchFn?: typeof fetch;
150
+ cwd?: string;
151
+ };
152
+
153
+ export type LocalPlanBridgePayload = {
154
+ ok: true;
155
+ version: 1;
156
+ source: "agent-native-local-bridge";
157
+ localOnly: true;
158
+ slug: string;
159
+ dir: string;
160
+ title: string;
161
+ brief: string;
162
+ kind: LocalPlanKind;
163
+ updatedAt: string;
164
+ files: string[];
165
+ mdx: LocalPlanBridgeMdxFolder;
166
+ comments: LocalPlanBridgeComment[];
167
+ };
168
+
169
+ export type LocalPlanServeResult = {
170
+ ok: true;
171
+ dir: string;
172
+ url: string;
173
+ urlFile?: string;
174
+ bridgeUrl: string;
175
+ appUrl: string;
176
+ title: string;
177
+ kind: LocalPlanKind;
178
+ files: string[];
179
+ host: string;
180
+ port: number;
181
+ opened?: boolean;
182
+ openCommand?: string;
183
+ openError?: string;
184
+ };
185
+
186
+ export type LocalPlanBridgeServer = {
187
+ server: Server;
188
+ result: LocalPlanServeResult;
189
+ };
190
+
191
+ export type RendererValidationIssue = {
192
+ path: string;
193
+ message: string;
194
+ };
195
+
196
+ export type RendererValidation = {
197
+ /** Whether a loopback renderer validate endpoint was reachable and answered. */
198
+ ran: boolean;
199
+ endpoint: string;
200
+ /** Renderer verdict — present only when `ran` is true. */
201
+ valid?: boolean;
202
+ issues?: RendererValidationIssue[];
203
+ /** Transport/endpoint error when `ran` is false (unreachable, 404, old deploy). */
204
+ error?: string;
205
+ };
206
+
207
+ export type LocalPlanVerifyResult = {
208
+ ok: boolean;
209
+ dir: string;
210
+ url: string;
211
+ urlFile?: string;
212
+ bridgeUrl: string;
213
+ appUrl: string;
214
+ title: string;
215
+ kind: LocalPlanKind;
216
+ files: string[];
217
+ preflight: {
218
+ status: number;
219
+ allowOrigin: string | null;
220
+ allowPrivateNetwork: string | null;
221
+ };
222
+ bridge: {
223
+ status: number;
224
+ ok: boolean;
225
+ source?: string;
226
+ localOnly?: boolean;
227
+ files?: string[];
228
+ mdxFiles?: string[];
229
+ error?: string;
230
+ };
231
+ validation: RendererValidation;
232
+ warnings: string[];
233
+ };
234
+
235
+ type OpenLocalUrlResult = {
236
+ ok: boolean;
237
+ command: string;
238
+ error?: string;
239
+ };
240
+
241
+ const LOCAL_PLAN_COMMENTS_FILE = "comments.json";
242
+ const LOCAL_PLAN_OWNER_EMAIL = "local@agent-native.local";
243
+ const LOCAL_PLAN_BRIDGE_COMMENT_BODY_LIMIT = 1024 * 1024;
244
+
245
+ const LOCAL_PLAN_ASSET_MAX_SINGLE_BYTES = 2 * 1024 * 1024;
246
+ const LOCAL_PLAN_ASSET_MAX_TOTAL_BYTES = 10 * 1024 * 1024;
247
+ const AGENT_NATIVE_MANIFEST_FILE = "agent-native.json";
248
+ const VISUAL_ANSWER_SOURCE_FILENAME = "visual-answer-source.json";
249
+ const VISUAL_ANSWER_URL_FILENAME = "visual-answer-url.txt";
250
+ const PLAN_ACTION_HTTP_TIMEOUT_MS = 45_000;
251
+ const LOCAL_PLAN_ASSET_EXTENSIONS = new Set([
252
+ "png",
253
+ "jpg",
254
+ "jpeg",
255
+ "gif",
256
+ "webp",
257
+ "svg",
258
+ ]);
259
+
260
+ function parseArgs(argv: string[]): Record<string, string | boolean> {
261
+ const out: Record<string, string | boolean> = {};
262
+ for (let i = 0; i < argv.length; i += 1) {
263
+ const token = argv[i];
264
+ if (!token.startsWith("--")) continue;
265
+ const key = token.slice(2);
266
+ const next = argv[i + 1];
267
+ if (next === undefined || next.startsWith("--")) out[key] = true;
268
+ else {
269
+ out[key] = next;
270
+ i += 1;
271
+ }
272
+ }
273
+ return out;
274
+ }
275
+
276
+ function stringArg(
277
+ args: Record<string, string | boolean>,
278
+ key: string,
279
+ ): string {
280
+ const value = args[key];
281
+ if (typeof value !== "string" || value.length === 0) {
282
+ throw new Error(`Missing --${key}`);
283
+ }
284
+ return value;
285
+ }
286
+
287
+ function optionalArg(
288
+ args: Record<string, string | boolean>,
289
+ key: string,
290
+ ): string | undefined {
291
+ const value = args[key];
292
+ return typeof value === "string" && value.length > 0 ? value : undefined;
293
+ }
294
+
295
+ function boolArg(args: Record<string, string | boolean>, key: string): boolean {
296
+ return args[key] === true;
297
+ }
298
+
299
+ function sanitizeHttpDetail(value: string, maxLength: number): string {
300
+ const normalized = value.replace(/\s+/g, " ").trim();
301
+ if (normalized.length <= maxLength) return normalized;
302
+ return `${normalized.slice(0, maxLength - 3)}...`;
303
+ }
304
+
305
+ function normalizeVisibility(
306
+ value: string | undefined,
307
+ ): "private" | "org" | "public" | undefined {
308
+ if (!value) return undefined;
309
+ if (value === "private" || value === "org" || value === "public") {
310
+ return value;
311
+ }
312
+ throw new Error(
313
+ `Invalid --visibility "${value}" (expected private, org, or public)`,
314
+ );
315
+ }
316
+
317
+ function normalizeVisualAnswerSourceType(value: string | undefined): string {
318
+ if (!value) return "code";
319
+ if (
320
+ [
321
+ "code",
322
+ "pull-request",
323
+ "commit",
324
+ "branch",
325
+ "diff",
326
+ "issue",
327
+ "page",
328
+ ].includes(value)
329
+ ) {
330
+ return value;
331
+ }
332
+ throw new Error(
333
+ `Invalid --source-type "${value}" (expected code, pull-request, commit, branch, diff, issue, or page)`,
334
+ );
335
+ }
336
+
337
+ function visualAnswerUrlFromPublishResult(
338
+ result: unknown,
339
+ appUrl: string,
340
+ ): string | null {
341
+ const base = appUrl.replace(/\/$/, "");
342
+ if (!result || typeof result !== "object") return null;
343
+ const record = result as Record<string, unknown>;
344
+ const rawUrl =
345
+ typeof record.url === "string"
346
+ ? record.url
347
+ : record.path && typeof record.path === "string"
348
+ ? record.path
349
+ : null;
350
+ if (rawUrl) {
351
+ try {
352
+ return new URL(rawUrl, `${base}/`).toString();
353
+ } catch {
354
+ return null;
355
+ }
356
+ }
357
+ const planId =
358
+ typeof record.planId === "string"
359
+ ? record.planId
360
+ : record.plan &&
361
+ typeof record.plan === "object" &&
362
+ typeof (record.plan as Record<string, unknown>).id === "string"
363
+ ? ((record.plan as Record<string, unknown>).id as string)
364
+ : null;
365
+ return planId ? `${base}/plans/${encodeURIComponent(planId)}` : null;
366
+ }
367
+
368
+ async function fetchActionWithTimeout(
369
+ url: string,
370
+ init: RequestInit,
371
+ fetchFn: typeof fetch,
372
+ ): Promise<Response> {
373
+ return await fetchFn(url, {
374
+ ...init,
375
+ signal: init.signal ?? AbortSignal.timeout(PLAN_ACTION_HTTP_TIMEOUT_MS),
376
+ });
377
+ }
378
+
379
+ export function localPlanFolderName(title: string): string {
380
+ const slug = title
381
+ .normalize("NFKD")
382
+ .replace(/[\u0300-\u036f]/g, "")
383
+ .toLowerCase()
384
+ .replace(/[^a-z0-9]+/g, "-")
385
+ .replace(/^-+|-+$/g, "")
386
+ .slice(0, 64)
387
+ .replace(/-+$/g, "");
388
+ return slug || "untitled-plan";
389
+ }
390
+
391
+ function normalizeKind(value: string | undefined): LocalPlanKind {
392
+ if (!value) return "plan";
393
+ if (value === "plan" || value === "recap") return value;
394
+ throw new Error(`Invalid --kind "${value}" (expected plan or recap)`);
395
+ }
396
+
397
+ function normalizeSlash(filePath: string): string {
398
+ return filePath.replace(/\\/g, "/");
399
+ }
400
+
401
+ function normalizeRelativePath(filePath: string): string | null {
402
+ if (!filePath.trim() || path.isAbsolute(filePath)) return null;
403
+ const normalized = path.posix
404
+ .normalize(normalizeSlash(filePath.trim()))
405
+ .replace(/\/+$/, "");
406
+ if (
407
+ !normalized ||
408
+ normalized === "." ||
409
+ normalized === ".." ||
410
+ normalized.startsWith("../") ||
411
+ normalized.split("/").some((part) => !part || part === "." || part === "..")
412
+ ) {
413
+ return null;
414
+ }
415
+ return normalized;
416
+ }
417
+
418
+ function findUpward(startDir: string, filename: string): string | null {
419
+ let current = path.resolve(startDir);
420
+ for (;;) {
421
+ const candidate = path.join(current, filename);
422
+ if (fs.existsSync(candidate)) return candidate;
423
+ const parent = path.dirname(current);
424
+ if (parent === current) return null;
425
+ current = parent;
426
+ }
427
+ }
428
+
429
+ function isRecord(value: unknown): value is Record<string, unknown> {
430
+ return !!value && typeof value === "object" && !Array.isArray(value);
431
+ }
432
+
433
+ function manifestRootPath(value: unknown): string | null {
434
+ if (typeof value === "string") return normalizeRelativePath(value);
435
+ if (isRecord(value) && typeof value.path === "string") {
436
+ return normalizeRelativePath(value.path);
437
+ }
438
+ return null;
439
+ }
440
+
441
+ function planManifestConfig(): { rootDir: string; plansPath: string } | null {
442
+ const configuredManifest =
443
+ process.env.AGENT_NATIVE_MANIFEST?.trim() ||
444
+ process.env.AGENT_NATIVE_MANIFEST_PATH?.trim();
445
+ const manifestPath = configuredManifest
446
+ ? path.resolve(configuredManifest)
447
+ : findUpward(process.cwd(), AGENT_NATIVE_MANIFEST_FILE);
448
+ if (!manifestPath) return null;
449
+
450
+ try {
451
+ const parsed = JSON.parse(
452
+ fs.readFileSync(manifestPath, "utf-8"),
453
+ ) as unknown;
454
+ const apps = isRecord(parsed) && isRecord(parsed.apps) ? parsed.apps : null;
455
+ const planApp = apps && isRecord(apps.plan) ? apps.plan : null;
456
+ const roots = planApp && Array.isArray(planApp.roots) ? planApp.roots : [];
457
+ const plansPath = roots
458
+ .map(manifestRootPath)
459
+ .find((item): item is string => Boolean(item));
460
+ return plansPath
461
+ ? { rootDir: path.dirname(manifestPath), plansPath }
462
+ : null;
463
+ } catch {
464
+ return null;
465
+ }
466
+ }
467
+
468
+ function localPlanWorkspaceRoot(startDir = process.cwd()): string {
469
+ const manifestPath = findUpward(startDir, AGENT_NATIVE_MANIFEST_FILE);
470
+ if (manifestPath) return path.dirname(manifestPath);
471
+ const gitDir = findUpward(startDir, ".git");
472
+ if (gitDir) return path.dirname(gitDir);
473
+
474
+ const configuredManifest =
475
+ process.env.AGENT_NATIVE_MANIFEST?.trim() ||
476
+ process.env.AGENT_NATIVE_MANIFEST_PATH?.trim();
477
+ if (configuredManifest) return path.dirname(path.resolve(configuredManifest));
478
+ return process.cwd();
479
+ }
480
+
481
+ function defaultPlansDir(): string {
482
+ const configured = process.env.PLAN_LOCAL_DIR;
483
+ if (configured?.trim()) return path.resolve(configured.trim());
484
+ const manifest = planManifestConfig();
485
+ if (manifest) return path.resolve(manifest.rootDir, manifest.plansPath);
486
+ return path.resolve("plans");
487
+ }
488
+
489
+ function defaultLocalPlanAppUrl(): string {
490
+ return (
491
+ process.env.PLAN_LOCAL_APP_URL ||
492
+ process.env.PLAN_BASE_URL ||
493
+ "http://localhost:8096"
494
+ );
495
+ }
496
+
497
+ function defaultLocalPlanBridgeAppUrl(): string {
498
+ return (
499
+ process.env.PLAN_LOCAL_BRIDGE_APP_URL ||
500
+ process.env.PLAN_BASE_URL ||
501
+ DEFAULT_PLAN_APP_URL
502
+ );
503
+ }
504
+
505
+ function normalizeAppUrl(value: string | undefined): string {
506
+ return (value || defaultLocalPlanAppUrl()).replace(/\/+$/, "");
507
+ }
508
+
509
+ function normalizeBridgeAppUrl(value: string | undefined): string {
510
+ return (value || defaultLocalPlanBridgeAppUrl()).replace(/\/+$/, "");
511
+ }
512
+
513
+ function localPlanPreviewUrl(dir: string, appUrl?: string): string {
514
+ const base = `${normalizeAppUrl(appUrl)}/local-plans/${encodeURIComponent(
515
+ path.basename(path.resolve(dir)),
516
+ )}`;
517
+ const repoPath = repoRelativePlanPath(dir);
518
+ if (!repoPath) return base;
519
+ return `${base}?${new URLSearchParams({ path: repoPath }).toString()}`;
520
+ }
521
+
522
+ function realpathIfExists(filePath: string): string {
523
+ try {
524
+ return fs.realpathSync.native(filePath);
525
+ } catch {
526
+ return path.resolve(filePath);
527
+ }
528
+ }
529
+
530
+ function repoRelativePlanPath(dir: string): string | null {
531
+ const resolved = realpathIfExists(dir);
532
+ const root = realpathIfExists(localPlanWorkspaceRoot(resolved));
533
+ const relative = path.relative(root, resolved);
534
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
535
+ return null;
536
+ }
537
+ return normalizeSlash(relative);
538
+ }
539
+
540
+ function localPlanBridgePageUrl(input: {
541
+ dir: string;
542
+ bridgeUrl: string;
543
+ appUrl?: string;
544
+ }): string {
545
+ // Keep the real local folder name out of the hosted request path. The bridge
546
+ // payload supplies the actual slug after the browser connects on loopback.
547
+ // The opaque id keeps simultaneous bridge sessions distinct without
548
+ // disclosing the folder name or access token to the hosted request.
549
+ const bridgeId = crypto
550
+ .createHash("sha256")
551
+ .update(input.bridgeUrl)
552
+ .digest("hex")
553
+ .slice(0, 16);
554
+ return `${normalizeBridgeAppUrl(input.appUrl)}/local-plans/local-${bridgeId}#bridge=${encodeURIComponent(
555
+ input.bridgeUrl,
556
+ )}`;
557
+ }
558
+
559
+ function writeLocalPlanUrlFile(dir: string, url: string, urlFile?: string) {
560
+ const file = path.resolve(urlFile || path.join(dir, ".plan-url"));
561
+ fs.writeFileSync(file, `${url}\n`, { encoding: "utf-8", mode: 0o600 });
562
+ return file;
563
+ }
564
+
565
+ function runOpenCommand(command: string, args: string[]): OpenLocalUrlResult {
566
+ const result = spawnSync(command, args, {
567
+ stdio: "ignore",
568
+ windowsHide: true,
569
+ });
570
+ const commandDisplay = [command, ...args].join(" ");
571
+ if (result.error) {
572
+ return {
573
+ ok: false,
574
+ command: commandDisplay,
575
+ error: result.error.message,
576
+ };
577
+ }
578
+ if (typeof result.status === "number" && result.status !== 0) {
579
+ return {
580
+ ok: false,
581
+ command: commandDisplay,
582
+ error: `exit code ${result.status}`,
583
+ };
584
+ }
585
+ return { ok: true, command: commandDisplay };
586
+ }
587
+
588
+ function openLocalUrl(url: string): OpenLocalUrlResult {
589
+ const platform = process.platform;
590
+ if (platform === "darwin") {
591
+ for (const appName of [
592
+ "Google Chrome",
593
+ "Chromium",
594
+ "Microsoft Edge",
595
+ "Brave Browser",
596
+ ]) {
597
+ const result = runOpenCommand("open", ["-a", appName, url]);
598
+ if (result.ok) return result;
599
+ }
600
+ return runOpenCommand("open", [url]);
601
+ }
602
+ if (platform === "win32") {
603
+ return runOpenCommand("cmd", ["/c", "start", "", url]);
604
+ }
605
+ return runOpenCommand("xdg-open", [url]);
606
+ }
607
+
608
+ function escapeHtml(value: string): string {
609
+ return value
610
+ .replace(/&/g, "&amp;")
611
+ .replace(/</g, "&lt;")
612
+ .replace(/>/g, "&gt;")
613
+ .replace(/"/g, "&quot;")
614
+ .replace(/'/g, "&#39;");
615
+ }
616
+
617
+ function stripFrontmatter(source: string): {
618
+ body: string;
619
+ frontmatter: Record<string, string>;
620
+ } {
621
+ if (!source.startsWith("---\n")) return { body: source, frontmatter: {} };
622
+ const end = source.indexOf("\n---", 4);
623
+ if (end < 0) return { body: source, frontmatter: {} };
624
+ const frontmatterSource = source.slice(4, end).trim();
625
+ const body = source.slice(end + 4).replace(/^\r?\n/, "");
626
+ const frontmatter: Record<string, string> = {};
627
+ for (const line of frontmatterSource.split(/\r?\n/)) {
628
+ const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
629
+ if (!match) continue;
630
+ const value = match[2]
631
+ .trim()
632
+ .replace(/^['"]|['"]$/g, "")
633
+ .trim();
634
+ frontmatter[match[1]] = value;
635
+ }
636
+ return { body, frontmatter };
637
+ }
638
+
639
+ function firstHeading(source: string): string | null {
640
+ for (const line of source.split(/\r?\n/)) {
641
+ const match = line.match(/^#{1,3}\s+(.+)$/);
642
+ if (match) return match[1].trim();
643
+ }
644
+ return null;
645
+ }
646
+
647
+ function splitMdxBlocks(source: string): Array<{
648
+ type: "markdown" | "component";
649
+ name?: string;
650
+ value: string;
651
+ }> {
652
+ const blocks: Array<{
653
+ type: "markdown" | "component";
654
+ name?: string;
655
+ value: string;
656
+ }> = [];
657
+ const lines = source.split(/\r?\n/);
658
+ let markdown: string[] = [];
659
+ let component: string[] | null = null;
660
+ let componentName = "";
661
+
662
+ function flushMarkdown() {
663
+ const value = markdown.join("\n").trim();
664
+ if (value) blocks.push({ type: "markdown", value });
665
+ markdown = [];
666
+ }
667
+
668
+ function flushComponent() {
669
+ if (!component) return;
670
+ blocks.push({
671
+ type: "component",
672
+ name: componentName || "MDX component",
673
+ value: component.join("\n").trim(),
674
+ });
675
+ component = null;
676
+ componentName = "";
677
+ }
678
+
679
+ for (const line of lines) {
680
+ const start = line.match(/^<([A-Z][A-Za-z0-9_]*)\b/);
681
+ if (!component && start) {
682
+ flushMarkdown();
683
+ component = [line];
684
+ componentName = start[1];
685
+ if (/\/>\s*$/.test(line)) flushComponent();
686
+ continue;
687
+ }
688
+
689
+ if (component) {
690
+ component.push(line);
691
+ if (new RegExp(`</${componentName}>\\s*$`).test(line)) {
692
+ flushComponent();
693
+ }
694
+ continue;
695
+ }
696
+
697
+ markdown.push(line);
698
+ }
699
+
700
+ flushComponent();
701
+ flushMarkdown();
702
+ return blocks;
703
+ }
704
+
705
+ function renderMarkdownish(source: string): string {
706
+ const lines = source.split(/\r?\n/);
707
+ const html: string[] = [];
708
+ let inCode = false;
709
+ let codeLines: string[] = [];
710
+ let listLines: string[] = [];
711
+
712
+ function flushList() {
713
+ if (listLines.length === 0) return;
714
+ html.push(
715
+ `<ul>${listLines.map((line) => `<li>${escapeHtml(line)}</li>`).join("")}</ul>`,
716
+ );
717
+ listLines = [];
718
+ }
719
+
720
+ function flushCode() {
721
+ if (!inCode) return;
722
+ html.push(`<pre><code>${escapeHtml(codeLines.join("\n"))}</code></pre>`);
723
+ codeLines = [];
724
+ inCode = false;
725
+ }
726
+
727
+ for (const line of lines) {
728
+ if (line.startsWith("```")) {
729
+ if (inCode) flushCode();
730
+ else {
731
+ flushList();
732
+ inCode = true;
733
+ codeLines = [];
734
+ }
735
+ continue;
736
+ }
737
+ if (inCode) {
738
+ codeLines.push(line);
739
+ continue;
740
+ }
741
+
742
+ const heading = line.match(/^(#{1,4})\s+(.+)$/);
743
+ if (heading) {
744
+ flushList();
745
+ const level = Math.min(heading[1].length, 4);
746
+ html.push(`<h${level}>${escapeHtml(heading[2].trim())}</h${level}>`);
747
+ continue;
748
+ }
749
+
750
+ const bullet = line.match(/^\s*[-*]\s+(.+)$/);
751
+ if (bullet) {
752
+ listLines.push(bullet[1]);
753
+ continue;
754
+ }
755
+
756
+ if (!line.trim()) {
757
+ flushList();
758
+ continue;
759
+ }
760
+
761
+ flushList();
762
+ html.push(`<p>${escapeHtml(line.trim())}</p>`);
763
+ }
764
+
765
+ flushCode();
766
+ flushList();
767
+ return html.join("\n");
768
+ }
769
+
770
+ function readLocalPlanAssets(dir: string): Record<string, string> | undefined {
771
+ const assetsDir = path.join(dir, "assets");
772
+ if (!fs.existsSync(assetsDir)) return undefined;
773
+
774
+ const assets: Record<string, string> = {};
775
+ let totalBytes = 0;
776
+ for (const entry of fs.readdirSync(assetsDir, { withFileTypes: true })) {
777
+ if (!entry.isFile()) continue;
778
+ const filename = path.basename(entry.name);
779
+ if (!filename || filename !== entry.name) continue;
780
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
781
+ if (!LOCAL_PLAN_ASSET_EXTENSIONS.has(ext)) continue;
782
+
783
+ const abs = path.join(assetsDir, filename);
784
+ const bytes = fs.readFileSync(abs);
785
+ if (bytes.byteLength > LOCAL_PLAN_ASSET_MAX_SINGLE_BYTES) continue;
786
+ if (totalBytes + bytes.byteLength > LOCAL_PLAN_ASSET_MAX_TOTAL_BYTES) {
787
+ continue;
788
+ }
789
+ totalBytes += bytes.byteLength;
790
+ assets[filename] = bytes.toString("base64");
791
+ }
792
+
793
+ return Object.keys(assets).length > 0 ? assets : undefined;
794
+ }
795
+
796
+ export function readLocalPlanFiles(dir: string): LocalPlanFiles {
797
+ const resolved = path.resolve(dir);
798
+ const planPath = path.join(resolved, "plan.mdx");
799
+ if (!fs.existsSync(planPath)) {
800
+ throw new Error(`Missing local plan source: ${planPath}`);
801
+ }
802
+ const readOptional = (file: string) => {
803
+ const abs = path.join(resolved, file);
804
+ return fs.existsSync(abs) ? fs.readFileSync(abs, "utf-8") : undefined;
805
+ };
806
+ return {
807
+ dir: resolved,
808
+ planMdx: fs.readFileSync(planPath, "utf-8"),
809
+ canvasMdx: readOptional("canvas.mdx"),
810
+ prototypeMdx: readOptional("prototype.mdx"),
811
+ stateJson: readOptional(".plan-state.json"),
812
+ assets: readLocalPlanAssets(resolved),
813
+ };
814
+ }
815
+
816
+ function localPlanMdxFolder(files: LocalPlanFiles): LocalPlanBridgeMdxFolder {
817
+ return {
818
+ "plan.mdx": files.planMdx,
819
+ ...(files.canvasMdx ? { "canvas.mdx": files.canvasMdx } : {}),
820
+ ...(files.prototypeMdx ? { "prototype.mdx": files.prototypeMdx } : {}),
821
+ ...(files.stateJson ? { ".plan-state.json": files.stateJson } : {}),
822
+ ...(files.assets ? { "assets/": files.assets } : {}),
823
+ };
824
+ }
825
+
826
+ function localPlanFileList(files: LocalPlanFiles): string[] {
827
+ return [
828
+ "plan.mdx",
829
+ ...(files.canvasMdx ? ["canvas.mdx"] : []),
830
+ ...(files.prototypeMdx ? ["prototype.mdx"] : []),
831
+ ...(files.stateJson ? [".plan-state.json"] : []),
832
+ ...Object.keys(files.assets ?? {}).map((filename) => `assets/${filename}`),
833
+ ];
834
+ }
835
+
836
+ function localPlanSourceEntries(files: LocalPlanFiles): Array<{
837
+ file: string;
838
+ source: string;
839
+ }> {
840
+ return [
841
+ { file: "plan.mdx", source: files.planMdx },
842
+ ...(files.canvasMdx
843
+ ? [{ file: "canvas.mdx", source: files.canvasMdx }]
844
+ : []),
845
+ ...(files.prototypeMdx
846
+ ? [{ file: "prototype.mdx", source: files.prototypeMdx }]
847
+ : []),
848
+ ];
849
+ }
850
+
851
+ function lineNumberAt(source: string, index: number): number {
852
+ let line = 1;
853
+ for (let i = 0; i < index; i += 1) {
854
+ if (source.charCodeAt(i) === 10) line += 1;
855
+ }
856
+ return line;
857
+ }
858
+
859
+ function maskFencedCode(source: string): string {
860
+ return source.replace(
861
+ /(^|\n)(```|~~~)[\s\S]*?(\n\2[^\n]*(?=\n|$))/g,
862
+ (match) => match.replace(/[^\n]/g, " "),
863
+ );
864
+ }
865
+
866
+ function findJsxOpeningTagEnd(source: string, start: number): number {
867
+ let quote: string | null = null;
868
+ let braceDepth = 0;
869
+ for (let i = start; i < source.length; i += 1) {
870
+ const char = source[i];
871
+ if (quote) {
872
+ if (char === "\\" && i + 1 < source.length) {
873
+ i += 1;
874
+ continue;
875
+ }
876
+ if (char === quote) quote = null;
877
+ continue;
878
+ }
879
+ if (char === '"' || char === "'" || char === "`") {
880
+ quote = char;
881
+ continue;
882
+ }
883
+ if (char === "{") {
884
+ braceDepth += 1;
885
+ continue;
886
+ }
887
+ if (char === "}") {
888
+ braceDepth = Math.max(0, braceDepth - 1);
889
+ continue;
890
+ }
891
+ if (char === ">" && braceDepth === 0) return i;
892
+ }
893
+ return -1;
894
+ }
895
+
896
+ function addValidationIssue(
897
+ issues: LocalPlanValidationIssue[],
898
+ file: string,
899
+ source: string,
900
+ index: number,
901
+ message: string,
902
+ ) {
903
+ issues.push({ file, line: lineNumberAt(source, index), message });
904
+ }
905
+
906
+ const ENTITY_RE = /&(?:[a-z][a-z0-9]+|#[0-9]+|#x[0-9a-f]+);/gi;
907
+ const HTML_TEXT_ATTR_RE =
908
+ /\b(?:aria-label|alt|placeholder|title|value)=\s*(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/gi;
909
+ const WIREFRAME_TEXT_ATTR_RE =
910
+ /\b(?:text|value|label|placeholder|title|note|due)=\s*(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/gi;
911
+
912
+ function normalizeVisibleText(value: string): string {
913
+ return value
914
+ .replace(/&nbsp;|&#160;|&#x0*a0;/gi, " ")
915
+ .replace(ENTITY_RE, "x")
916
+ .replace(/\s+/g, " ")
917
+ .trim();
918
+ }
919
+
920
+ function meaningfulTextLength(value: string | undefined): number {
921
+ return normalizeVisibleText(value ?? "").length;
922
+ }
923
+
924
+ function htmlMeaningfulTextLength(html: string): number {
925
+ let length = 0;
926
+ for (const match of html.matchAll(HTML_TEXT_ATTR_RE)) {
927
+ length += meaningfulTextLength(match[1] ?? match[2] ?? match[3]);
928
+ }
929
+
930
+ const visibleText = html
931
+ .replace(/<!--[\s\S]*?-->/g, " ")
932
+ .replace(/<script\b[\s\S]*?<\/script>/gi, " ")
933
+ .replace(/<style\b[\s\S]*?<\/style>/gi, " ")
934
+ .replace(/<[^>]+>/g, " ");
935
+ length += meaningfulTextLength(visibleText);
936
+
937
+ return length;
938
+ }
939
+
940
+ function hasSkeletonGeometry(html: string): boolean {
941
+ return (
942
+ /<(?:div|span|section|main|article|ul|li)\b/i.test(html) &&
943
+ /\b(?:height|width|background|border|padding|wf-card|wf-box|wf-pill|wf-chip)\b/i.test(
944
+ html,
945
+ )
946
+ );
947
+ }
948
+
949
+ function stringAttributeValues(source: string, name: string): string[] {
950
+ const values: string[] = [];
951
+ const re = new RegExp(
952
+ `\\b${name}\\s*=\\s*(?:\\{\\s*\`([\\s\\S]*?)\`\\s*\\}|\\{\\s*"([^"]*)"\\s*\\}|\\{\\s*'([^']*)'\\s*\\}|"([^"]*)"|'([^']*)')`,
953
+ "g",
954
+ );
955
+ for (const match of source.matchAll(re)) {
956
+ const value = match[1] ?? match[2] ?? match[3] ?? match[4] ?? match[5];
957
+ if (value !== undefined) values.push(value);
958
+ }
959
+ return values;
960
+ }
961
+
962
+ function hasUnparsedAttributeExpression(source: string, name: string): boolean {
963
+ return new RegExp(`\\b${name}\\s*=\\s*\\{`).test(source);
964
+ }
965
+
966
+ function hasMeaningfulWireframeHtml(screenOpening: string): boolean | null {
967
+ const htmlValues = stringAttributeValues(screenOpening, "html");
968
+ if (htmlValues.length === 0) {
969
+ return hasUnparsedAttributeExpression(screenOpening, "html") ? null : false;
970
+ }
971
+ return htmlValues.some(
972
+ (html) => htmlMeaningfulTextLength(html) >= 2 || hasSkeletonGeometry(html),
973
+ );
974
+ }
975
+
976
+ function hasMeaningfulKitScreen(screenSource: string): boolean {
977
+ for (const match of screenSource.matchAll(WIREFRAME_TEXT_ATTR_RE)) {
978
+ if (meaningfulTextLength(match[1] ?? match[2] ?? match[3]) >= 2) {
979
+ return true;
980
+ }
981
+ }
982
+ if (/\bitems\s*=\s*\{[\s\S]*?\blabel\s*:/i.test(screenSource)) return true;
983
+ if (/\brows\s*=\s*\{[\s\S]*?\b[klv]\s*:/i.test(screenSource)) return true;
984
+ return false;
985
+ }
986
+
987
+ function hasMeaningfulWireframeScreen(blockSource: string): boolean | null {
988
+ const screenMatch = /<Screen\b/.exec(blockSource);
989
+ if (!screenMatch) return false;
990
+ const screenStart = screenMatch.index;
991
+ const screenOpeningEnd = findJsxOpeningTagEnd(blockSource, screenStart);
992
+ if (screenOpeningEnd < 0) return false;
993
+ const screenOpening = blockSource.slice(screenStart, screenOpeningEnd + 1);
994
+ const htmlMeaningful = hasMeaningfulWireframeHtml(screenOpening);
995
+ if (htmlMeaningful === true) return true;
996
+
997
+ const selfClosing = /\/\s*>$/.test(screenOpening);
998
+ const closeIndex = selfClosing
999
+ ? -1
1000
+ : blockSource.indexOf("</Screen>", screenOpeningEnd + 1);
1001
+ const screenSource =
1002
+ closeIndex >= 0
1003
+ ? blockSource.slice(screenStart, closeIndex + "</Screen>".length)
1004
+ : screenOpening;
1005
+ if (hasMeaningfulKitScreen(screenSource)) return true;
1006
+
1007
+ return htmlMeaningful === null ? null : false;
1008
+ }
1009
+
1010
+ function lintWireframeBlocks(
1011
+ file: string,
1012
+ source: string,
1013
+ issues: LocalPlanValidationIssue[],
1014
+ ) {
1015
+ const scanSource = maskFencedCode(source);
1016
+ const re = /<WireframeBlock\b/g;
1017
+ let match: RegExpExecArray | null;
1018
+ while ((match = re.exec(scanSource))) {
1019
+ const start = match.index;
1020
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
1021
+ if (openingEnd < 0) {
1022
+ addValidationIssue(
1023
+ issues,
1024
+ file,
1025
+ source,
1026
+ start,
1027
+ "WireframeBlock opening tag is not closed.",
1028
+ );
1029
+ continue;
1030
+ }
1031
+
1032
+ const opening = scanSource.slice(start, openingEnd + 1);
1033
+ const unsupportedAttr = opening.match(
1034
+ /\b(data|screens|screen|elements)\s*=/,
1035
+ );
1036
+ if (unsupportedAttr) {
1037
+ addValidationIssue(
1038
+ issues,
1039
+ file,
1040
+ source,
1041
+ start,
1042
+ `WireframeBlock uses unsupported "${unsupportedAttr[1]}" prop. Put content inside a <Screen> child instead.`,
1043
+ );
1044
+ }
1045
+
1046
+ const selfClosing = /\/\s*>$/.test(opening);
1047
+ const closeTag = "</WireframeBlock>";
1048
+ const closeIndex = selfClosing
1049
+ ? -1
1050
+ : scanSource.indexOf(closeTag, openingEnd + 1);
1051
+ const blockSource = selfClosing
1052
+ ? opening
1053
+ : closeIndex >= 0
1054
+ ? scanSource.slice(start, closeIndex + closeTag.length)
1055
+ : scanSource.slice(start, openingEnd + 1);
1056
+
1057
+ if (!selfClosing && closeIndex < 0) {
1058
+ addValidationIssue(
1059
+ issues,
1060
+ file,
1061
+ source,
1062
+ start,
1063
+ "WireframeBlock must have a closing </WireframeBlock> tag.",
1064
+ );
1065
+ }
1066
+
1067
+ if (selfClosing || !/<Screen\b/.test(blockSource)) {
1068
+ addValidationIssue(
1069
+ issues,
1070
+ file,
1071
+ source,
1072
+ start,
1073
+ 'WireframeBlock must wrap a <Screen> child; self-closing wireframes render empty. Use <WireframeBlock><Screen surface="browser">...</Screen></WireframeBlock>.',
1074
+ );
1075
+ continue;
1076
+ }
1077
+
1078
+ const meaningfulScreen = hasMeaningfulWireframeScreen(blockSource);
1079
+ if (meaningfulScreen === false) {
1080
+ addValidationIssue(
1081
+ issues,
1082
+ file,
1083
+ source,
1084
+ start,
1085
+ 'WireframeBlock contains an empty <Screen>; local previews render blank wireframes. Add visible html text/controls or kit nodes such as <Title text="Checkout" /> and <Btn label="Pay" />.',
1086
+ );
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ function lintColumnsBlocks(
1092
+ file: string,
1093
+ source: string,
1094
+ issues: LocalPlanValidationIssue[],
1095
+ ) {
1096
+ const scanSource = maskFencedCode(source);
1097
+ const re = /<Columns\b/g;
1098
+ let match: RegExpExecArray | null;
1099
+ while ((match = re.exec(scanSource))) {
1100
+ const start = match.index;
1101
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
1102
+ if (openingEnd < 0) continue;
1103
+ const opening = source.slice(start, openingEnd + 1);
1104
+ const columnsAttr = readJsxAttribute(opening, "columns");
1105
+ if (!columnsAttr) continue;
1106
+ const entries =
1107
+ columnsAttr.kind === "expression"
1108
+ ? extractTopLevelObjectLiterals(columnsAttr.value)
1109
+ : null;
1110
+ if (entries && entries.length > 0) continue;
1111
+ addValidationIssue(
1112
+ issues,
1113
+ file,
1114
+ source,
1115
+ start,
1116
+ 'Columns must use <Column> children or a columns={[{ id, label, blocks }]} array, not a bare columns= prop. Use <Columns><Column label="Before">...</Column><Column label="After">...</Column></Columns>.',
1117
+ );
1118
+ }
1119
+ }
1120
+
1121
+ type JsxAttributeValue = {
1122
+ name: string;
1123
+ kind: "expression" | "string" | "bare" | "boolean";
1124
+ value: string;
1125
+ start: number;
1126
+ };
1127
+
1128
+ function findBalancedEnd(
1129
+ source: string,
1130
+ start: number,
1131
+ open: string,
1132
+ close: string,
1133
+ ): number {
1134
+ let depth = 0;
1135
+ let quote: string | null = null;
1136
+ for (let i = start; i < source.length; i += 1) {
1137
+ const char = source[i];
1138
+ if (quote) {
1139
+ if (char === "\\" && i + 1 < source.length) {
1140
+ i += 1;
1141
+ continue;
1142
+ }
1143
+ if (char === quote) quote = null;
1144
+ continue;
1145
+ }
1146
+ if (char === '"' || char === "'" || char === "`") {
1147
+ quote = char;
1148
+ continue;
1149
+ }
1150
+ if (char === open) {
1151
+ depth += 1;
1152
+ continue;
1153
+ }
1154
+ if (char === close) {
1155
+ depth -= 1;
1156
+ if (depth === 0) return i;
1157
+ }
1158
+ }
1159
+ return -1;
1160
+ }
1161
+
1162
+ function readJsxAttribute(
1163
+ opening: string,
1164
+ name: string,
1165
+ ): JsxAttributeValue | null {
1166
+ let i = 0;
1167
+ while (i < opening.length) {
1168
+ if (!/[A-Za-z_:]/.test(opening[i] ?? "")) {
1169
+ i += 1;
1170
+ continue;
1171
+ }
1172
+ const nameStart = i;
1173
+ i += 1;
1174
+ while (/[\w:.-]/.test(opening[i] ?? "")) i += 1;
1175
+ const attrName = opening.slice(nameStart, i);
1176
+ while (/\s/.test(opening[i] ?? "")) i += 1;
1177
+ if (opening[i] !== "=") {
1178
+ if (attrName === name) {
1179
+ return { name, kind: "boolean", value: "true", start: nameStart };
1180
+ }
1181
+ continue;
1182
+ }
1183
+ i += 1;
1184
+ while (/\s/.test(opening[i] ?? "")) i += 1;
1185
+ const valueStart = i;
1186
+ const quote = opening[i];
1187
+ if (quote === '"' || quote === "'" || quote === "`") {
1188
+ i += 1;
1189
+ while (i < opening.length) {
1190
+ if (opening[i] === "\\" && i + 1 < opening.length) {
1191
+ i += 2;
1192
+ continue;
1193
+ }
1194
+ if (opening[i] === quote) break;
1195
+ i += 1;
1196
+ }
1197
+ const value = opening.slice(valueStart + 1, i);
1198
+ i += 1;
1199
+ if (attrName === name) {
1200
+ return { name, kind: "string", value, start: valueStart + 1 };
1201
+ }
1202
+ continue;
1203
+ }
1204
+ if (quote === "{") {
1205
+ const end = findBalancedEnd(opening, i, "{", "}");
1206
+ if (end < 0) {
1207
+ if (attrName === name) {
1208
+ return {
1209
+ name,
1210
+ kind: "expression",
1211
+ value: opening.slice(valueStart + 1),
1212
+ start: valueStart + 1,
1213
+ };
1214
+ }
1215
+ break;
1216
+ }
1217
+ const value = opening.slice(valueStart + 1, end);
1218
+ i = end + 1;
1219
+ if (attrName === name) {
1220
+ return { name, kind: "expression", value, start: valueStart + 1 };
1221
+ }
1222
+ continue;
1223
+ }
1224
+ while (i < opening.length && !/[\s>]/.test(opening[i] ?? "")) i += 1;
1225
+ if (attrName === name) {
1226
+ return {
1227
+ name,
1228
+ kind: "bare",
1229
+ value: opening.slice(valueStart, i),
1230
+ start: valueStart,
1231
+ };
1232
+ }
1233
+ }
1234
+ return null;
1235
+ }
1236
+
1237
+ function expressionOffset(expression: string): number {
1238
+ return expression.search(/\S/);
1239
+ }
1240
+
1241
+ function extractTopLevelObjectLiterals(expression: string): Array<{
1242
+ source: string;
1243
+ start: number;
1244
+ }> | null {
1245
+ const leading = expressionOffset(expression);
1246
+ if (leading < 0 || expression[leading] !== "[") return null;
1247
+ const arrayEnd = findBalancedEnd(expression, leading, "[", "]");
1248
+ if (arrayEnd < 0) return null;
1249
+ const objects: Array<{ source: string; start: number }> = [];
1250
+ let i = leading + 1;
1251
+ while (i < arrayEnd) {
1252
+ const char = expression[i];
1253
+ if (/\s|,/.test(char ?? "")) {
1254
+ i += 1;
1255
+ continue;
1256
+ }
1257
+ if (char !== "{") {
1258
+ return null;
1259
+ }
1260
+ const objectEnd = findBalancedEnd(expression, i, "{", "}");
1261
+ if (objectEnd < 0 || objectEnd > arrayEnd) return null;
1262
+ objects.push({
1263
+ source: expression.slice(i, objectEnd + 1),
1264
+ start: i,
1265
+ });
1266
+ i = objectEnd + 1;
1267
+ }
1268
+ return objects;
1269
+ }
1270
+
1271
+ function findValueEnd(source: string, start: number): number {
1272
+ let i = start;
1273
+ let quote: string | null = null;
1274
+ let depth = 0;
1275
+ while (i < source.length) {
1276
+ const char = source[i];
1277
+ if (quote) {
1278
+ if (char === "\\" && i + 1 < source.length) {
1279
+ i += 2;
1280
+ continue;
1281
+ }
1282
+ if (char === quote) quote = null;
1283
+ i += 1;
1284
+ continue;
1285
+ }
1286
+ if (char === '"' || char === "'" || char === "`") {
1287
+ quote = char;
1288
+ i += 1;
1289
+ continue;
1290
+ }
1291
+ if (char === "{" || char === "[" || char === "(") {
1292
+ depth += 1;
1293
+ i += 1;
1294
+ continue;
1295
+ }
1296
+ if (char === "}" || char === "]" || char === ")") {
1297
+ if (depth === 0) return i;
1298
+ depth -= 1;
1299
+ i += 1;
1300
+ continue;
1301
+ }
1302
+ if (char === "," && depth === 0) return i;
1303
+ i += 1;
1304
+ }
1305
+ return source.length;
1306
+ }
1307
+
1308
+ function readObjectKey(
1309
+ source: string,
1310
+ start: number,
1311
+ ): {
1312
+ key: string;
1313
+ keyStart: number;
1314
+ colon: number;
1315
+ } | null {
1316
+ let i = start;
1317
+ while (/\s|,/.test(source[i] ?? "")) i += 1;
1318
+ const keyStart = i;
1319
+ const quote = source[i];
1320
+ let key = "";
1321
+ if (quote === '"' || quote === "'") {
1322
+ i += 1;
1323
+ const valueStart = i;
1324
+ while (i < source.length) {
1325
+ if (source[i] === "\\" && i + 1 < source.length) {
1326
+ i += 2;
1327
+ continue;
1328
+ }
1329
+ if (source[i] === quote) break;
1330
+ i += 1;
1331
+ }
1332
+ key = source.slice(valueStart, i);
1333
+ i += 1;
1334
+ } else if (/[A-Za-z_$]/.test(quote ?? "")) {
1335
+ i += 1;
1336
+ while (/[\w$]/.test(source[i] ?? "")) i += 1;
1337
+ key = source.slice(keyStart, i);
1338
+ } else {
1339
+ return null;
1340
+ }
1341
+ while (/\s/.test(source[i] ?? "")) i += 1;
1342
+ if (source[i] !== ":") return null;
1343
+ return { key, keyStart, colon: i };
1344
+ }
1345
+
1346
+ function readTopLevelObjectProperty(
1347
+ objectSource: string,
1348
+ name: string,
1349
+ ): { value: string; valueStart: number } | null {
1350
+ const body = objectSource.trim().startsWith("{")
1351
+ ? objectSource.slice(1, objectSource.lastIndexOf("}"))
1352
+ : objectSource;
1353
+ let i = 0;
1354
+ while (i < body.length) {
1355
+ const key = readObjectKey(body, i);
1356
+ if (!key) {
1357
+ i += 1;
1358
+ continue;
1359
+ }
1360
+ const valueStart = key.colon + 1;
1361
+ const valueEnd = findValueEnd(body, valueStart);
1362
+ if (key.key === name) {
1363
+ return { value: body.slice(valueStart, valueEnd), valueStart };
1364
+ }
1365
+ i = valueEnd + 1;
1366
+ }
1367
+ return null;
1368
+ }
1369
+
1370
+ function isStaticNonEmptyStringLiteral(value: string): boolean {
1371
+ const trimmed = value.trim();
1372
+ const quote = trimmed[0];
1373
+ if (quote !== '"' && quote !== "'" && quote !== "`") return false;
1374
+ if (!trimmed.endsWith(quote)) return false;
1375
+ if (quote === "`" && /\$\{/.test(trimmed)) return false;
1376
+ return trimmed.slice(1, -1).trim().length > 0;
1377
+ }
1378
+
1379
+ function hasRequiredStaticString(objectSource: string, name: string): boolean {
1380
+ const prop = readTopLevelObjectProperty(objectSource, name);
1381
+ return prop ? isStaticNonEmptyStringLiteral(prop.value) : false;
1382
+ }
1383
+
1384
+ function hasRequiredStaticId(objectSource: string): boolean {
1385
+ return hasRequiredStaticString(objectSource, "id");
1386
+ }
1387
+
1388
+ function hasRequiredEnumLiteral(
1389
+ objectSource: string,
1390
+ name: string,
1391
+ allowed: readonly string[],
1392
+ ): boolean {
1393
+ const prop = readTopLevelObjectProperty(objectSource, name);
1394
+ if (!prop) return false;
1395
+ const trimmed = prop.value.trim();
1396
+ const quote = trimmed[0];
1397
+ if (quote !== '"' && quote !== "'" && quote !== "`") return false;
1398
+ if (!trimmed.endsWith(quote)) return false;
1399
+ if (quote === "`" && /\$\{/.test(trimmed)) return false;
1400
+ return allowed.includes(trimmed.slice(1, -1).trim());
1401
+ }
1402
+
1403
+ // Shared per-item checks so the top-level `<Checklist items={[…]} />` tag and
1404
+ // blocks authored as JSON inside a container's `tabs={[…]}` / `columns={[…]}`
1405
+ // array enforce the SAME required fields. `listBase` is the absolute offset of
1406
+ // the items array in the original source so line numbers point near the item.
1407
+ function checkChecklistItemList(
1408
+ items: Array<{ source: string; start: number }>,
1409
+ listBase: number,
1410
+ file: string,
1411
+ source: string,
1412
+ issues: LocalPlanValidationIssue[],
1413
+ ) {
1414
+ items.forEach((item, index) => {
1415
+ const base = listBase + item.start;
1416
+ if (!hasRequiredStaticId(item.source)) {
1417
+ addValidationIssue(
1418
+ issues,
1419
+ file,
1420
+ source,
1421
+ base,
1422
+ `Checklist items[${index}].id is required by the Plan renderer schema; add a stable string id.`,
1423
+ );
1424
+ }
1425
+ if (!hasRequiredStaticString(item.source, "label")) {
1426
+ addValidationIssue(
1427
+ issues,
1428
+ file,
1429
+ source,
1430
+ base,
1431
+ `Checklist items[${index}].label is required by the Plan renderer schema; add a non-empty string label.`,
1432
+ );
1433
+ }
1434
+ });
1435
+ }
1436
+
1437
+ function checkQuestionObjectList(
1438
+ questionObjects: Array<{ source: string; start: number }>,
1439
+ listBase: number,
1440
+ tag: string,
1441
+ file: string,
1442
+ source: string,
1443
+ issues: LocalPlanValidationIssue[],
1444
+ ) {
1445
+ questionObjects.forEach((question, questionIndex) => {
1446
+ const questionBase = listBase + question.start;
1447
+ if (!hasRequiredStaticId(question.source)) {
1448
+ addValidationIssue(
1449
+ issues,
1450
+ file,
1451
+ source,
1452
+ questionBase,
1453
+ `${tag} questions[${questionIndex}].id is required by the Plan renderer schema; add a stable string id.`,
1454
+ );
1455
+ }
1456
+ if (!hasRequiredStaticString(question.source, "title")) {
1457
+ addValidationIssue(
1458
+ issues,
1459
+ file,
1460
+ source,
1461
+ questionBase,
1462
+ `${tag} questions[${questionIndex}].title is required by the Plan renderer schema; add a non-empty string title.`,
1463
+ );
1464
+ }
1465
+ if (
1466
+ !hasRequiredEnumLiteral(question.source, "mode", [
1467
+ "single",
1468
+ "multi",
1469
+ "freeform",
1470
+ ])
1471
+ ) {
1472
+ addValidationIssue(
1473
+ issues,
1474
+ file,
1475
+ source,
1476
+ questionBase,
1477
+ `${tag} questions[${questionIndex}].mode is required by the Plan renderer schema; use "single", "multi", or "freeform".`,
1478
+ );
1479
+ }
1480
+ const options = readTopLevelObjectProperty(question.source, "options");
1481
+ if (!options) return;
1482
+ const optionObjects = extractTopLevelObjectLiterals(options.value);
1483
+ if (!optionObjects) {
1484
+ addValidationIssue(
1485
+ issues,
1486
+ file,
1487
+ source,
1488
+ questionBase + options.valueStart,
1489
+ `${tag} questions[${questionIndex}].options must be an inline array of object literals.`,
1490
+ );
1491
+ return;
1492
+ }
1493
+ optionObjects.forEach((option, optionIndex) => {
1494
+ const optionBase = questionBase + options.valueStart + option.start;
1495
+ if (!hasRequiredStaticId(option.source)) {
1496
+ addValidationIssue(
1497
+ issues,
1498
+ file,
1499
+ source,
1500
+ optionBase,
1501
+ `${tag} questions[${questionIndex}].options[${optionIndex}].id is required by the Plan renderer schema; add a stable string id.`,
1502
+ );
1503
+ }
1504
+ if (!hasRequiredStaticString(option.source, "label")) {
1505
+ addValidationIssue(
1506
+ issues,
1507
+ file,
1508
+ source,
1509
+ optionBase,
1510
+ `${tag} questions[${questionIndex}].options[${optionIndex}].label is required by the Plan renderer schema; add a non-empty string label.`,
1511
+ );
1512
+ }
1513
+ });
1514
+ });
1515
+ }
1516
+
1517
+ function lintChecklistShape(
1518
+ file: string,
1519
+ source: string,
1520
+ issues: LocalPlanValidationIssue[],
1521
+ ) {
1522
+ const scanSource = maskCodeRegions(source);
1523
+ const re = /<Checklist\b/g;
1524
+ let match: RegExpExecArray | null;
1525
+ while ((match = re.exec(scanSource))) {
1526
+ const start = match.index;
1527
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
1528
+ if (openingEnd < 0) continue;
1529
+ const opening = source.slice(start, openingEnd + 1);
1530
+ const items = readJsxAttribute(opening, "items");
1531
+ if (!items) continue;
1532
+ if (items.kind !== "expression") {
1533
+ addValidationIssue(
1534
+ issues,
1535
+ file,
1536
+ source,
1537
+ start + items.start,
1538
+ "Checklist items must be an inline array expression with stable item ids.",
1539
+ );
1540
+ continue;
1541
+ }
1542
+ const objects = extractTopLevelObjectLiterals(items.value);
1543
+ if (!objects) {
1544
+ addValidationIssue(
1545
+ issues,
1546
+ file,
1547
+ source,
1548
+ start + items.start,
1549
+ "Checklist items must be an inline array of object literals so local check can validate the renderer schema.",
1550
+ );
1551
+ continue;
1552
+ }
1553
+ checkChecklistItemList(objects, start + items.start, file, source, issues);
1554
+ }
1555
+ }
1556
+
1557
+ function lintQuestionFormShape(
1558
+ file: string,
1559
+ source: string,
1560
+ issues: LocalPlanValidationIssue[],
1561
+ ) {
1562
+ const scanSource = maskCodeRegions(source);
1563
+ const re = /<(QuestionForm|VisualQuestions)\b/g;
1564
+ let match: RegExpExecArray | null;
1565
+ while ((match = re.exec(scanSource))) {
1566
+ const start = match.index;
1567
+ const tag = match[1] ?? "QuestionForm";
1568
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
1569
+ if (openingEnd < 0) continue;
1570
+ const opening = source.slice(start, openingEnd + 1);
1571
+ const questions = readJsxAttribute(opening, "questions");
1572
+ if (!questions) {
1573
+ addValidationIssue(
1574
+ issues,
1575
+ file,
1576
+ source,
1577
+ start,
1578
+ `${tag} requires a questions array with at least one question object.`,
1579
+ );
1580
+ continue;
1581
+ }
1582
+ if (questions.kind !== "expression") {
1583
+ addValidationIssue(
1584
+ issues,
1585
+ file,
1586
+ source,
1587
+ start + questions.start,
1588
+ `${tag} questions must be an inline array expression with stable question ids.`,
1589
+ );
1590
+ continue;
1591
+ }
1592
+ const questionObjects = extractTopLevelObjectLiterals(questions.value);
1593
+ if (!questionObjects || questionObjects.length === 0) {
1594
+ addValidationIssue(
1595
+ issues,
1596
+ file,
1597
+ source,
1598
+ start + questions.start,
1599
+ `${tag} questions must be a non-empty inline array of object literals.`,
1600
+ );
1601
+ continue;
1602
+ }
1603
+ checkQuestionObjectList(
1604
+ questionObjects,
1605
+ start + questions.start,
1606
+ tag,
1607
+ file,
1608
+ source,
1609
+ issues,
1610
+ );
1611
+ }
1612
+ }
1613
+
1614
+ function staticStringLiteralValue(
1615
+ value: string | undefined,
1616
+ ): string | undefined {
1617
+ if (value === undefined) return undefined;
1618
+ const trimmed = value.trim();
1619
+ const quote = trimmed[0];
1620
+ if (quote !== '"' && quote !== "'" && quote !== "`") return undefined;
1621
+ if (!trimmed.endsWith(quote) || trimmed.length < 2) return undefined;
1622
+ if (quote === "`" && /\$\{/.test(trimmed)) return undefined;
1623
+ return trimmed.slice(1, -1);
1624
+ }
1625
+
1626
+ // Container blocks authored with a JSON attribute array (`<TabsBlock tabs={[…]}
1627
+ // />`) carry their children as nested block objects, not top-level JSX tags, so
1628
+ // the tag-based linters above never inspect them — the exact "false green" the
1629
+ // renderer catches because it validates the whole parsed block tree. Walk those
1630
+ // nested `blocks: [...]` arrays and enforce the same per-block required fields,
1631
+ // recursing through nested containers. This is still a subset of the renderer
1632
+ // schema (which is why `verify` is the authority), but it closes the common
1633
+ // nested checklist / question-form / missing-id case offline.
1634
+ const NESTED_CONTAINER_TAGS: ReadonlyArray<{ tag: string; attr: string }> = [
1635
+ { tag: "TabsBlock", attr: "tabs" },
1636
+ { tag: "Tabs", attr: "tabs" },
1637
+ { tag: "Columns", attr: "columns" },
1638
+ ];
1639
+
1640
+ function lintNestedContainerEntry(
1641
+ entrySource: string,
1642
+ entryBase: number,
1643
+ file: string,
1644
+ source: string,
1645
+ issues: LocalPlanValidationIssue[],
1646
+ ) {
1647
+ const blocksProp = readTopLevelObjectProperty(entrySource, "blocks");
1648
+ if (!blocksProp) return;
1649
+ const blockObjects = extractTopLevelObjectLiterals(blocksProp.value);
1650
+ if (!blockObjects) return;
1651
+ const blocksBase = entryBase + blocksProp.valueStart;
1652
+ for (const block of blockObjects) {
1653
+ lintNestedBlock(
1654
+ block.source,
1655
+ blocksBase + block.start,
1656
+ file,
1657
+ source,
1658
+ issues,
1659
+ );
1660
+ }
1661
+ }
1662
+
1663
+ function lintNestedBlock(
1664
+ blockSource: string,
1665
+ blockBase: number,
1666
+ file: string,
1667
+ source: string,
1668
+ issues: LocalPlanValidationIssue[],
1669
+ ) {
1670
+ const typeProp = readTopLevelObjectProperty(blockSource, "type");
1671
+ const type = staticStringLiteralValue(typeProp?.value);
1672
+ if (!hasRequiredStaticId(blockSource)) {
1673
+ addValidationIssue(
1674
+ issues,
1675
+ file,
1676
+ source,
1677
+ blockBase,
1678
+ `Nested ${type ?? "block"} is missing a required string \`id\`; the Plan renderer schema validates every nested block.`,
1679
+ );
1680
+ }
1681
+ const dataProp = readTopLevelObjectProperty(blockSource, "data");
1682
+ if (!dataProp) return;
1683
+ const dataBase = blockBase + dataProp.valueStart;
1684
+
1685
+ if (type === "checklist") {
1686
+ const itemsProp = readTopLevelObjectProperty(dataProp.value, "items");
1687
+ if (!itemsProp) return;
1688
+ const items = extractTopLevelObjectLiterals(itemsProp.value);
1689
+ if (items) {
1690
+ checkChecklistItemList(
1691
+ items,
1692
+ dataBase + itemsProp.valueStart,
1693
+ file,
1694
+ source,
1695
+ issues,
1696
+ );
1697
+ }
1698
+ return;
1699
+ }
1700
+ // visual-questions shares question-form's schema; lint both.
1701
+ if (type === "question-form" || type === "visual-questions") {
1702
+ const questionsProp = readTopLevelObjectProperty(
1703
+ dataProp.value,
1704
+ "questions",
1705
+ );
1706
+ if (!questionsProp) return;
1707
+ const questionObjects = extractTopLevelObjectLiterals(questionsProp.value);
1708
+ if (questionObjects) {
1709
+ checkQuestionObjectList(
1710
+ questionObjects,
1711
+ dataBase + questionsProp.valueStart,
1712
+ type,
1713
+ file,
1714
+ source,
1715
+ issues,
1716
+ );
1717
+ }
1718
+ return;
1719
+ }
1720
+ if (type === "tabs" || type === "columns") {
1721
+ const innerAttr = type === "tabs" ? "tabs" : "columns";
1722
+ const innerProp = readTopLevelObjectProperty(dataProp.value, innerAttr);
1723
+ if (!innerProp) return;
1724
+ const innerEntries = extractTopLevelObjectLiterals(innerProp.value);
1725
+ if (!innerEntries) return;
1726
+ const innerBase = dataBase + innerProp.valueStart;
1727
+ for (const entry of innerEntries) {
1728
+ lintNestedContainerEntry(
1729
+ entry.source,
1730
+ innerBase + entry.start,
1731
+ file,
1732
+ source,
1733
+ issues,
1734
+ );
1735
+ }
1736
+ }
1737
+ }
1738
+
1739
+ function lintNestedContainerBlocks(
1740
+ file: string,
1741
+ source: string,
1742
+ issues: LocalPlanValidationIssue[],
1743
+ ) {
1744
+ const scanSource = maskCodeRegions(source);
1745
+ for (const { tag, attr } of NESTED_CONTAINER_TAGS) {
1746
+ const re = new RegExp(`<${tag}\\b`, "g");
1747
+ let match: RegExpExecArray | null;
1748
+ while ((match = re.exec(scanSource))) {
1749
+ const start = match.index;
1750
+ const openingEnd = findJsxOpeningTagEnd(scanSource, start);
1751
+ if (openingEnd < 0) continue;
1752
+ const opening = source.slice(start, openingEnd + 1);
1753
+ const attrValue = readJsxAttribute(opening, attr);
1754
+ if (!attrValue || attrValue.kind !== "expression") continue;
1755
+ const entries = extractTopLevelObjectLiterals(attrValue.value);
1756
+ if (!entries) continue;
1757
+ const entriesBase = start + attrValue.start;
1758
+ for (const entry of entries) {
1759
+ lintNestedContainerEntry(
1760
+ entry.source,
1761
+ entriesBase + entry.start,
1762
+ file,
1763
+ source,
1764
+ issues,
1765
+ );
1766
+ }
1767
+ }
1768
+ }
1769
+ }
1770
+
1771
+ // Blank out fenced code blocks and inline code spans (preserving newlines and
1772
+ // length) so block-tag linters don't trip on documentation examples written in
1773
+ // prose — e.g. an inline `<WireframeBlock><Screen>...</Screen></WireframeBlock>`
1774
+ // example is not a real block to validate. Real blocks (outside code) are left
1775
+ // intact, so their offsets/line numbers stay correct. Without this the default
1776
+ // `plan local init` scaffold fails its own `plan local check`/`serve` lint.
1777
+ function maskCodeRegions(source: string): string {
1778
+ const blank = (s: string) => s.replace(/[^\n]/g, " ");
1779
+ return source.replace(/```[\s\S]*?```/g, blank).replace(/`[^`\n]*`/g, blank);
1780
+ }
1781
+
1782
+ export function validateLocalPlanFiles(
1783
+ files: LocalPlanFiles,
1784
+ ): LocalPlanValidationIssue[] {
1785
+ const issues: LocalPlanValidationIssue[] = [];
1786
+ for (const entry of localPlanSourceEntries(files)) {
1787
+ const source = maskCodeRegions(entry.source);
1788
+ lintWireframeBlocks(entry.file, source, issues);
1789
+ lintColumnsBlocks(entry.file, source, issues);
1790
+ lintChecklistShape(entry.file, entry.source, issues);
1791
+ lintQuestionFormShape(entry.file, entry.source, issues);
1792
+ lintNestedContainerBlocks(entry.file, entry.source, issues);
1793
+ }
1794
+ return issues;
1795
+ }
1796
+
1797
+ export function assertLocalPlanFilesValid(files: LocalPlanFiles): void {
1798
+ const issues = validateLocalPlanFiles(files);
1799
+ if (issues.length === 0) return;
1800
+ const details = issues
1801
+ .slice(0, 8)
1802
+ .map((issue) => `${issue.file}:${issue.line} ${issue.message}`)
1803
+ .join("\n");
1804
+ const overflow =
1805
+ issues.length > 8 ? `\n...plus ${issues.length - 8} more issues` : "";
1806
+ throw new Error(
1807
+ `Local plan source validation failed:\n${details}${overflow}\nRun \`npx @agent-native/core@latest plan blocks --out plan-blocks.md\` and update the MDX to the documented block shapes.`,
1808
+ );
1809
+ }
1810
+
1811
+ export function buildLocalPlanPreviewHtml(
1812
+ input: LocalPlanPreviewInput,
1813
+ ): string {
1814
+ const files = readLocalPlanFiles(input.dir);
1815
+ assertLocalPlanFilesValid(files);
1816
+ const parsed = stripFrontmatter(files.planMdx);
1817
+ const title =
1818
+ input.title ||
1819
+ parsed.frontmatter.title ||
1820
+ firstHeading(parsed.body) ||
1821
+ path.basename(files.dir);
1822
+ const brief = input.brief || parsed.frontmatter.brief || "";
1823
+ const kind = input.kind || normalizeKind(parsed.frontmatter.kind);
1824
+ const blocks = splitMdxBlocks(parsed.body);
1825
+ const sourceFiles = [
1826
+ ["plan.mdx", files.planMdx],
1827
+ ["canvas.mdx", files.canvasMdx],
1828
+ ["prototype.mdx", files.prototypeMdx],
1829
+ [".plan-state.json", files.stateJson],
1830
+ ].filter((entry): entry is [string, string] => Boolean(entry[1]));
1831
+
1832
+ return `<!doctype html>
1833
+ <html lang="en">
1834
+ <head>
1835
+ <meta charset="utf-8" />
1836
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1837
+ <title>${escapeHtml(title)}</title>
1838
+ <style>
1839
+ :root {
1840
+ color-scheme: light dark;
1841
+ --bg: #f8fafc;
1842
+ --paper: #ffffff;
1843
+ --ink: #0f172a;
1844
+ --muted: #64748b;
1845
+ --line: #cbd5e1;
1846
+ --accent: #2563eb;
1847
+ --soft: #eff6ff;
1848
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
1849
+ }
1850
+ @media (prefers-color-scheme: dark) {
1851
+ :root {
1852
+ --bg: #020617;
1853
+ --paper: #0f172a;
1854
+ --ink: #e2e8f0;
1855
+ --muted: #94a3b8;
1856
+ --line: #334155;
1857
+ --soft: #172554;
1858
+ }
1859
+ }
1860
+ body { margin: 0; background: var(--bg); color: var(--ink); }
1861
+ main { max-width: 1040px; margin: 0 auto; padding: 40px 20px 56px; }
1862
+ header { margin-bottom: 28px; }
1863
+ h1 { font-size: clamp(2rem, 5vw, 3.5rem); line-height: 1; margin: 0 0 12px; }
1864
+ h2 { font-size: 1.35rem; margin: 28px 0 10px; }
1865
+ h3 { font-size: 1.05rem; margin: 0 0 8px; }
1866
+ p, li { line-height: 1.65; }
1867
+ .meta { display: flex; flex-wrap: wrap; gap: 8px; color: var(--muted); font-size: 0.9rem; }
1868
+ .pill { border: 1px solid var(--line); border-radius: 999px; padding: 4px 10px; background: var(--paper); }
1869
+ .notice { background: var(--soft); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; margin: 18px 0; }
1870
+ .block, details { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 18px; margin: 14px 0; }
1871
+ .component summary { cursor: pointer; color: var(--accent); font-weight: 650; }
1872
+ pre { overflow: auto; border-radius: 8px; border: 1px solid var(--line); padding: 14px; background: rgba(148, 163, 184, 0.12); }
1873
+ code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.9rem; }
1874
+ .source-tabs { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
1875
+ </style>
1876
+ </head>
1877
+ <body>
1878
+ <main>
1879
+ <header>
1880
+ <div class="meta">
1881
+ <span class="pill">${kind === "recap" ? "Visual recap" : "Visual plan"}</span>
1882
+ <span class="pill">Local-files mode</span>
1883
+ <span class="pill">No DB writes</span>
1884
+ </div>
1885
+ <h1>${escapeHtml(title)}</h1>
1886
+ ${brief ? `<p>${escapeHtml(brief)}</p>` : ""}
1887
+ <div class="notice">
1888
+ This preview was generated entirely from local files. It does not call
1889
+ the Plan MCP server, the Plan app action surface, a hosted service, or a
1890
+ database. Edit the MDX files and regenerate this preview to update it.
1891
+ </div>
1892
+ </header>
1893
+ <section>
1894
+ ${blocks
1895
+ .map((block) =>
1896
+ block.type === "component"
1897
+ ? `<details class="component block" open><summary>${escapeHtml(
1898
+ block.name || "MDX component",
1899
+ )}</summary><pre><code>${escapeHtml(block.value)}</code></pre></details>`
1900
+ : `<article class="block">${renderMarkdownish(block.value)}</article>`,
1901
+ )
1902
+ .join("\n")}
1903
+ </section>
1904
+ <section>
1905
+ <h2>Local Source Files</h2>
1906
+ <div class="source-tabs">
1907
+ ${sourceFiles
1908
+ .map(
1909
+ ([name, source]) =>
1910
+ `<details><summary>${escapeHtml(name)}</summary><pre><code>${escapeHtml(
1911
+ source,
1912
+ )}</code></pre></details>`,
1913
+ )
1914
+ .join("\n")}
1915
+ </div>
1916
+ </section>
1917
+ </main>
1918
+ </body>
1919
+ </html>
1920
+ `;
1921
+ }
1922
+
1923
+ export function writeLocalPlanPreview(input: {
1924
+ dir: string;
1925
+ out?: string;
1926
+ kind?: LocalPlanKind;
1927
+ title?: string;
1928
+ brief?: string;
1929
+ appUrl?: string;
1930
+ open?: boolean;
1931
+ openUrl?: (url: string) => OpenLocalUrlResult;
1932
+ }): LocalPlanPreviewResult {
1933
+ const dir = path.resolve(input.dir);
1934
+ const files = readLocalPlanFiles(dir);
1935
+ assertLocalPlanFilesValid(files);
1936
+ const parsed = stripFrontmatter(files.planMdx);
1937
+ const kind = input.kind || normalizeKind(parsed.frontmatter.kind);
1938
+ const title =
1939
+ input.title ||
1940
+ parsed.frontmatter.title ||
1941
+ firstHeading(parsed.body) ||
1942
+ path.basename(dir);
1943
+ const out = input.out ? path.resolve(input.out) : undefined;
1944
+ if (out) {
1945
+ fs.mkdirSync(path.dirname(out), { recursive: true });
1946
+ fs.writeFileSync(out, buildLocalPlanPreviewHtml({ ...input, dir, kind }));
1947
+ }
1948
+ const result: LocalPlanPreviewResult = {
1949
+ ok: true,
1950
+ dir,
1951
+ ...(out ? { out } : {}),
1952
+ url: out ? pathToFileURL(out).href : localPlanPreviewUrl(dir, input.appUrl),
1953
+ title,
1954
+ kind,
1955
+ files: localPlanFileList(files),
1956
+ };
1957
+ if (!input.open) return result;
1958
+
1959
+ const openResult = (input.openUrl || openLocalUrl)(result.url);
1960
+ return {
1961
+ ...result,
1962
+ opened: openResult.ok,
1963
+ openCommand: openResult.command,
1964
+ ...(openResult.error ? { openError: openResult.error } : {}),
1965
+ };
1966
+ }
1967
+
1968
+ function readLocalPlanBridgeComments(dir: string): LocalPlanBridgeComment[] {
1969
+ try {
1970
+ const raw = fs.readFileSync(
1971
+ path.join(dir, LOCAL_PLAN_COMMENTS_FILE),
1972
+ "utf-8",
1973
+ );
1974
+ const parsed = JSON.parse(raw);
1975
+ return Array.isArray(parsed)
1976
+ ? (parsed as LocalPlanBridgeComment[]).filter(
1977
+ (comment) => comment && typeof comment.id === "string",
1978
+ )
1979
+ : [];
1980
+ } catch {
1981
+ return [];
1982
+ }
1983
+ }
1984
+
1985
+ function writeLocalPlanBridgeComments(
1986
+ dir: string,
1987
+ comments: LocalPlanBridgeComment[],
1988
+ ): void {
1989
+ const target = path.join(dir, LOCAL_PLAN_COMMENTS_FILE);
1990
+ if (comments.length === 0) {
1991
+ fs.rmSync(target, { force: true });
1992
+ return;
1993
+ }
1994
+ fs.writeFileSync(target, `${JSON.stringify(comments, null, 2)}\n`, "utf-8");
1995
+ }
1996
+
1997
+ function normalizeBridgeCommentString(value: unknown, fallback = ""): string {
1998
+ return typeof value === "string" ? value : fallback;
1999
+ }
2000
+
2001
+ function normalizeBridgeCommentNullableString(value: unknown): string | null {
2002
+ const text = typeof value === "string" ? value.trim() : "";
2003
+ return text || null;
2004
+ }
2005
+
2006
+ function normalizeBridgeCommentStatus(value: unknown): string {
2007
+ return value === "resolved" ? "resolved" : "open";
2008
+ }
2009
+
2010
+ function newLocalBridgeCommentId(): string {
2011
+ return `cmt_${crypto.randomBytes(8).toString("hex")}`;
2012
+ }
2013
+
2014
+ function applyLocalPlanBridgeCommentUpdate(
2015
+ dir: string,
2016
+ update: LocalPlanBridgeCommentUpdate,
2017
+ ): LocalPlanBridgeComment[] {
2018
+ const existing = readLocalPlanBridgeComments(dir);
2019
+ const byId = new Map(existing.map((comment) => [comment.id, comment]));
2020
+ const now = new Date().toISOString();
2021
+ const planId = `local-${path.basename(dir)}`;
2022
+
2023
+ for (const input of update.comments ?? []) {
2024
+ const id =
2025
+ normalizeBridgeCommentNullableString(input.id) ??
2026
+ newLocalBridgeCommentId();
2027
+ const prev = byId.get(id);
2028
+ const status = normalizeBridgeCommentStatus(input.status ?? prev?.status);
2029
+ const message =
2030
+ typeof input.message === "string" ? input.message : prev?.message;
2031
+ if (!message?.trim()) continue;
2032
+
2033
+ if (prev) {
2034
+ byId.set(id, {
2035
+ ...prev,
2036
+ parentCommentId:
2037
+ normalizeBridgeCommentNullableString(input.parentCommentId) ??
2038
+ prev.parentCommentId,
2039
+ sectionId:
2040
+ normalizeBridgeCommentNullableString(input.sectionId) ??
2041
+ prev.sectionId,
2042
+ kind: normalizeBridgeCommentString(input.kind, prev.kind),
2043
+ status,
2044
+ anchor:
2045
+ typeof input.anchor === "string" || input.anchor === null
2046
+ ? input.anchor
2047
+ : prev.anchor,
2048
+ message,
2049
+ authorEmail:
2050
+ normalizeBridgeCommentNullableString(input.authorEmail) ??
2051
+ prev.authorEmail,
2052
+ authorName:
2053
+ normalizeBridgeCommentNullableString(input.authorName) ??
2054
+ prev.authorName,
2055
+ resolutionTarget: "agent",
2056
+ mentions: [],
2057
+ mentionsJson: null,
2058
+ resolvedAt:
2059
+ status === "resolved"
2060
+ ? (input.resolvedAt ?? prev.resolvedAt ?? now)
2061
+ : null,
2062
+ resolvedBy:
2063
+ status === "resolved"
2064
+ ? (input.resolvedBy ?? prev.resolvedBy ?? LOCAL_PLAN_OWNER_EMAIL)
2065
+ : null,
2066
+ updatedAt: now,
2067
+ });
2068
+ continue;
2069
+ }
2070
+
2071
+ byId.set(id, {
2072
+ id,
2073
+ planId,
2074
+ parentCommentId: normalizeBridgeCommentNullableString(
2075
+ input.parentCommentId,
2076
+ ),
2077
+ sectionId: normalizeBridgeCommentNullableString(input.sectionId),
2078
+ kind: normalizeBridgeCommentString(input.kind, "annotation"),
2079
+ status,
2080
+ anchor: normalizeBridgeCommentNullableString(input.anchor),
2081
+ message,
2082
+ createdBy: "human",
2083
+ authorEmail:
2084
+ normalizeBridgeCommentNullableString(input.authorEmail) ??
2085
+ LOCAL_PLAN_OWNER_EMAIL,
2086
+ authorName: normalizeBridgeCommentNullableString(input.authorName),
2087
+ resolutionTarget: "agent",
2088
+ mentions: [],
2089
+ mentionsJson: null,
2090
+ resolvedBy: status === "resolved" ? LOCAL_PLAN_OWNER_EMAIL : null,
2091
+ resolvedAt: status === "resolved" ? now : null,
2092
+ consumedAt: null,
2093
+ deletedAt: null,
2094
+ deletedBy: null,
2095
+ createdAt: now,
2096
+ updatedAt: now,
2097
+ });
2098
+ }
2099
+
2100
+ for (const id of update.deletedCommentIds ?? []) {
2101
+ byId.delete(id);
2102
+ for (const comment of byId.values()) {
2103
+ if (comment.parentCommentId === id) byId.delete(comment.id);
2104
+ }
2105
+ }
2106
+
2107
+ const comments = [...byId.values()].sort((a, b) =>
2108
+ a.createdAt === b.createdAt
2109
+ ? a.id.localeCompare(b.id)
2110
+ : a.createdAt.localeCompare(b.createdAt),
2111
+ );
2112
+ writeLocalPlanBridgeComments(dir, comments);
2113
+ return comments;
2114
+ }
2115
+
2116
+ function buildLocalPlanBridgePayload(input: {
2117
+ dir: string;
2118
+ kind?: LocalPlanKind;
2119
+ title?: string;
2120
+ brief?: string;
2121
+ // `verify` brings the bridge up only to exercise transport + the authoritative
2122
+ // renderer check, so it must not be short-circuited by the weaker offline lint.
2123
+ skipSourceValidation?: boolean;
2124
+ }): LocalPlanBridgePayload {
2125
+ const dir = path.resolve(input.dir);
2126
+ const files = readLocalPlanFiles(dir);
2127
+ if (!input.skipSourceValidation) assertLocalPlanFilesValid(files);
2128
+ const parsed = stripFrontmatter(files.planMdx);
2129
+ const kind = input.kind || normalizeKind(parsed.frontmatter.kind);
2130
+ const title =
2131
+ input.title ||
2132
+ parsed.frontmatter.title ||
2133
+ firstHeading(parsed.body) ||
2134
+ path.basename(dir);
2135
+ const brief = input.brief || parsed.frontmatter.brief || "";
2136
+ const comments = readLocalPlanBridgeComments(dir);
2137
+
2138
+ return {
2139
+ ok: true,
2140
+ version: 1,
2141
+ source: "agent-native-local-bridge",
2142
+ localOnly: true,
2143
+ slug: path.basename(dir),
2144
+ dir,
2145
+ title,
2146
+ brief,
2147
+ kind,
2148
+ updatedAt: latestLocalPlanMtime(dir, files),
2149
+ files: localPlanFileList(files),
2150
+ mdx: localPlanMdxFolder(files),
2151
+ comments,
2152
+ };
2153
+ }
2154
+
2155
+ function latestLocalPlanMtime(dir: string, files: LocalPlanFiles): string {
2156
+ const candidates = [
2157
+ path.join(dir, "plan.mdx"),
2158
+ ...(files.canvasMdx ? [path.join(dir, "canvas.mdx")] : []),
2159
+ ...(files.prototypeMdx ? [path.join(dir, "prototype.mdx")] : []),
2160
+ ...(files.stateJson ? [path.join(dir, ".plan-state.json")] : []),
2161
+ path.join(dir, LOCAL_PLAN_COMMENTS_FILE),
2162
+ ...Object.keys(files.assets ?? {}).map((filename) =>
2163
+ path.join(dir, "assets", filename),
2164
+ ),
2165
+ ];
2166
+ let latest = 0;
2167
+ for (const file of candidates) {
2168
+ try {
2169
+ latest = Math.max(latest, fs.statSync(file).mtimeMs);
2170
+ } catch {
2171
+ // Ignore files deleted between the read and stat passes.
2172
+ }
2173
+ }
2174
+ return new Date(latest || Date.now()).toISOString();
2175
+ }
2176
+
2177
+ function sendBridgeJson(
2178
+ res: ServerResponse,
2179
+ status: number,
2180
+ payload: unknown,
2181
+ ): void {
2182
+ res.writeHead(status, {
2183
+ "access-control-allow-origin": "*",
2184
+ "access-control-allow-methods": "GET, POST, OPTIONS",
2185
+ "access-control-allow-headers": "content-type",
2186
+ // Required when the hosted HTTPS Plan UI fetches this localhost bridge.
2187
+ "access-control-allow-private-network": "true",
2188
+ "cache-control": "no-store",
2189
+ "content-type": "application/json; charset=utf-8",
2190
+ "x-agent-native-local-bridge": "1",
2191
+ });
2192
+ res.end(`${JSON.stringify(payload)}\n`);
2193
+ }
2194
+
2195
+ function readBridgeJsonBody(req: IncomingMessage): Promise<unknown> {
2196
+ return new Promise((resolve, reject) => {
2197
+ let raw = "";
2198
+ req.setEncoding("utf-8");
2199
+ req.on("data", (chunk) => {
2200
+ raw += chunk;
2201
+ if (raw.length > LOCAL_PLAN_BRIDGE_COMMENT_BODY_LIMIT) {
2202
+ reject(new Error("Local plan comment update is too large."));
2203
+ req.destroy();
2204
+ }
2205
+ });
2206
+ req.on("end", () => {
2207
+ if (!raw.trim()) {
2208
+ resolve({});
2209
+ return;
2210
+ }
2211
+ try {
2212
+ resolve(JSON.parse(raw));
2213
+ } catch {
2214
+ reject(new Error("Local plan comment update must be JSON."));
2215
+ }
2216
+ });
2217
+ req.on("error", reject);
2218
+ });
2219
+ }
2220
+
2221
+ function normalizeBridgeCommentUpdatePayload(
2222
+ payload: unknown,
2223
+ ): LocalPlanBridgeCommentUpdate {
2224
+ if (!payload || typeof payload !== "object") return {};
2225
+ const input = payload as LocalPlanBridgeCommentUpdate;
2226
+ return {
2227
+ comments: Array.isArray(input.comments) ? input.comments : [],
2228
+ deletedCommentIds: Array.isArray(input.deletedCommentIds)
2229
+ ? input.deletedCommentIds.filter((id) => typeof id === "string")
2230
+ : [],
2231
+ };
2232
+ }
2233
+
2234
+ function bridgeRequestUrl(req: IncomingMessage): URL {
2235
+ return new URL(req.url || "/", "http://127.0.0.1");
2236
+ }
2237
+
2238
+ function bridgeHostForUrl(host: string): string {
2239
+ if (host === "0.0.0.0" || host === "::") return "127.0.0.1";
2240
+ return host;
2241
+ }
2242
+
2243
+ export async function startLocalPlanBridge(input: {
2244
+ dir: string;
2245
+ kind?: LocalPlanKind;
2246
+ title?: string;
2247
+ brief?: string;
2248
+ appUrl?: string;
2249
+ host?: string;
2250
+ port?: number;
2251
+ token?: string;
2252
+ open?: boolean;
2253
+ urlFile?: string | false;
2254
+ openUrl?: (url: string) => OpenLocalUrlResult;
2255
+ skipSourceValidation?: boolean;
2256
+ }): Promise<LocalPlanBridgeServer> {
2257
+ const dir = path.resolve(input.dir);
2258
+ const initialPayload = buildLocalPlanBridgePayload({
2259
+ dir,
2260
+ kind: input.kind,
2261
+ title: input.title,
2262
+ brief: input.brief,
2263
+ skipSourceValidation: input.skipSourceValidation,
2264
+ });
2265
+ const token = input.token || crypto.randomBytes(24).toString("base64url");
2266
+ const host = input.host || "127.0.0.1";
2267
+ const appUrl = normalizeBridgeAppUrl(input.appUrl);
2268
+ const server = http.createServer((req, res) => {
2269
+ if (req.method === "OPTIONS") {
2270
+ sendBridgeJson(res, 204, "");
2271
+ return;
2272
+ }
2273
+
2274
+ const url = bridgeRequestUrl(req);
2275
+ if (
2276
+ url.pathname !== "/local-plan.json" &&
2277
+ url.pathname !== "/local-plan-comments.json"
2278
+ ) {
2279
+ sendBridgeJson(res, 404, { ok: false, error: "Not found." });
2280
+ return;
2281
+ }
2282
+ if (url.searchParams.get("token") !== token) {
2283
+ sendBridgeJson(res, 403, { ok: false, error: "Invalid bridge token." });
2284
+ return;
2285
+ }
2286
+ if (url.pathname === "/local-plan.json" && req.method !== "GET") {
2287
+ sendBridgeJson(res, 405, { ok: false, error: "Method not allowed." });
2288
+ return;
2289
+ }
2290
+ if (url.pathname === "/local-plan-comments.json" && req.method !== "POST") {
2291
+ sendBridgeJson(res, 405, { ok: false, error: "Method not allowed." });
2292
+ return;
2293
+ }
2294
+
2295
+ void (async () => {
2296
+ try {
2297
+ if (url.pathname === "/local-plan-comments.json") {
2298
+ const body = await readBridgeJsonBody(req);
2299
+ applyLocalPlanBridgeCommentUpdate(
2300
+ dir,
2301
+ normalizeBridgeCommentUpdatePayload(body),
2302
+ );
2303
+ }
2304
+ sendBridgeJson(
2305
+ res,
2306
+ 200,
2307
+ buildLocalPlanBridgePayload({
2308
+ dir,
2309
+ kind: input.kind,
2310
+ title: input.title,
2311
+ brief: input.brief,
2312
+ skipSourceValidation: input.skipSourceValidation,
2313
+ }),
2314
+ );
2315
+ } catch (error) {
2316
+ sendBridgeJson(res, 500, {
2317
+ ok: false,
2318
+ error: error instanceof Error ? error.message : String(error),
2319
+ });
2320
+ }
2321
+ })();
2322
+ });
2323
+
2324
+ await new Promise<void>((resolve, reject) => {
2325
+ const onError = (error: Error) => {
2326
+ server.off("listening", onListening);
2327
+ reject(error);
2328
+ };
2329
+ const onListening = () => {
2330
+ server.off("error", onError);
2331
+ resolve();
2332
+ };
2333
+ server.once("error", onError);
2334
+ server.once("listening", onListening);
2335
+ server.listen(input.port ?? 0, host);
2336
+ });
2337
+
2338
+ const address = server.address();
2339
+ if (!address || typeof address === "string") {
2340
+ server.close();
2341
+ throw new Error("Local plan bridge did not bind to a TCP port.");
2342
+ }
2343
+
2344
+ const bridgeUrl = `http://${bridgeHostForUrl(host)}:${address.port}/local-plan.json?token=${encodeURIComponent(
2345
+ token,
2346
+ )}`;
2347
+ const url = localPlanBridgePageUrl({ dir, bridgeUrl, appUrl });
2348
+ const urlFile =
2349
+ input.urlFile === false
2350
+ ? undefined
2351
+ : writeLocalPlanUrlFile(dir, url, input.urlFile);
2352
+ const openResult = input.open
2353
+ ? (input.openUrl || openLocalUrl)(url)
2354
+ : undefined;
2355
+
2356
+ return {
2357
+ server,
2358
+ result: {
2359
+ ok: true,
2360
+ dir,
2361
+ url,
2362
+ ...(urlFile ? { urlFile } : {}),
2363
+ bridgeUrl,
2364
+ appUrl,
2365
+ title: initialPayload.title,
2366
+ kind: initialPayload.kind,
2367
+ files: initialPayload.files,
2368
+ host,
2369
+ port: address.port,
2370
+ ...(openResult
2371
+ ? {
2372
+ opened: openResult.ok,
2373
+ openCommand: openResult.command,
2374
+ ...(openResult.error ? { openError: openResult.error } : {}),
2375
+ }
2376
+ : {}),
2377
+ },
2378
+ };
2379
+ }
2380
+
2381
+ function localPlanBridgeWarnings(input: {
2382
+ appUrl: string;
2383
+ bridgeUrl: string;
2384
+ }): string[] {
2385
+ const warnings: string[] = [];
2386
+ try {
2387
+ const appUrl = new URL(input.appUrl);
2388
+ const bridgeUrl = new URL(input.bridgeUrl);
2389
+ if (appUrl.protocol === "https:" && bridgeUrl.protocol === "http:") {
2390
+ warnings.push(
2391
+ `Chrome/Edge will ask for Local Network access so ${appUrl.hostname} can read this loopback bridge. Allow it; if you denied it, re-enable Local Network access in the ${appUrl.hostname} site settings, then retry.`,
2392
+ );
2393
+ warnings.push(
2394
+ "Safari may block the hosted HTTPS Plan UI from reading the HTTP localhost bridge. Use Chrome/Chromium/Edge, or pass --app-url http://localhost:8096 when running a local Plan app.",
2395
+ );
2396
+ }
2397
+ } catch {
2398
+ // The URLs were normalized earlier; ignore defensive parse failures.
2399
+ }
2400
+ return warnings;
2401
+ }
2402
+
2403
+ const VALIDATE_LOCAL_PLAN_ACTION = "validate-local-plan-source";
2404
+
2405
+ function isLoopbackAppUrl(value: string): boolean {
2406
+ try {
2407
+ const hostname = new URL(value).hostname.toLowerCase();
2408
+ return (
2409
+ hostname === "localhost" ||
2410
+ hostname === "[::1]" ||
2411
+ hostname === "::1" ||
2412
+ hostname === "0.0.0.0" ||
2413
+ hostname.startsWith("127.")
2414
+ );
2415
+ } catch {
2416
+ return false;
2417
+ }
2418
+ }
2419
+
2420
+ /**
2421
+ * Ask a loopback Plan app to validate the folder against its real renderer schema
2422
+ * (`parsePlanMdxFolder` + `planContentSchema`) via the public, no-DB
2423
+ * `validate-local-plan-source` action. This is what makes `verify`
2424
+ * authoritative without transmitting local plan source off-device. Remote app
2425
+ * URLs are intentionally skipped: local-files privacy mode must never POST MDX
2426
+ * or assets to a hosted validation action. Degrades gracefully (`ran: false`)
2427
+ * when no local Plan app is running or it predates the action.
2428
+ */
2429
+ export async function fetchRendererValidation(input: {
2430
+ appUrl: string;
2431
+ files: LocalPlanFiles;
2432
+ fetchFn?: typeof fetch;
2433
+ }): Promise<RendererValidation> {
2434
+ const fetchFn = input.fetchFn ?? fetch;
2435
+ const endpoint = planActionEndpoint(input.appUrl, VALIDATE_LOCAL_PLAN_ACTION);
2436
+ if (!isLoopbackAppUrl(input.appUrl)) {
2437
+ return {
2438
+ ran: false,
2439
+ endpoint,
2440
+ error:
2441
+ "Skipped remote renderer validation to keep local plan source on this device.",
2442
+ };
2443
+ }
2444
+ try {
2445
+ const response = await fetchActionWithTimeout(
2446
+ endpoint,
2447
+ {
2448
+ method: "POST",
2449
+ headers: {
2450
+ accept: "application/json",
2451
+ "content-type": "application/json",
2452
+ },
2453
+ body: JSON.stringify({ mdx: localPlanMdxFolder(input.files) }),
2454
+ },
2455
+ fetchFn,
2456
+ );
2457
+ if (!response.ok) {
2458
+ const detail = await response.text().catch(() => "");
2459
+ return {
2460
+ ran: false,
2461
+ endpoint,
2462
+ error: `${VALIDATE_LOCAL_PLAN_ACTION} failed ${response.status} ${
2463
+ response.statusText
2464
+ }: ${sanitizeHttpDetail(detail, 300)}`,
2465
+ };
2466
+ }
2467
+ const json = (await response.json().catch(() => null)) as
2468
+ | (Record<string, unknown> & { result?: Record<string, unknown> })
2469
+ | null;
2470
+ const body =
2471
+ json && isRecord(json.result) ? json.result : (json ?? undefined);
2472
+ if (!body || typeof body.valid !== "boolean") {
2473
+ return {
2474
+ ran: false,
2475
+ endpoint,
2476
+ error: `${VALIDATE_LOCAL_PLAN_ACTION} returned an unexpected payload.`,
2477
+ };
2478
+ }
2479
+ const issues = Array.isArray(body.issues)
2480
+ ? body.issues.filter(isRecord).map((issue) => ({
2481
+ path: typeof issue.path === "string" ? issue.path : "",
2482
+ message:
2483
+ typeof issue.message === "string" ? issue.message : "Invalid value",
2484
+ }))
2485
+ : [];
2486
+ return { ran: true, endpoint, valid: body.valid, issues };
2487
+ } catch (err) {
2488
+ return {
2489
+ ran: false,
2490
+ endpoint,
2491
+ error: err instanceof Error ? err.message : String(err),
2492
+ };
2493
+ }
2494
+ }
2495
+
2496
+ function rendererValidationWarnings(
2497
+ validation: RendererValidation,
2498
+ offlineIssues: LocalPlanValidationIssue[],
2499
+ ): string[] {
2500
+ if (!validation.ran) {
2501
+ const base = `Plan content was NOT validated against a local renderer schema (${
2502
+ validation.error ?? "validate endpoint unavailable"
2503
+ }). Fell back to the offline lint. For authoritative validation without data egress, run a local Plan app that exposes ${VALIDATE_LOCAL_PLAN_ACTION} and pass --app-url http://localhost:8096.`;
2504
+ if (offlineIssues.length === 0) return [base];
2505
+ const preview = offlineIssues
2506
+ .slice(0, 8)
2507
+ .map((issue) => `${issue.file}:${issue.line} ${issue.message}`)
2508
+ .join("; ");
2509
+ const overflow =
2510
+ offlineIssues.length > 8 ? ` (+${offlineIssues.length - 8} more)` : "";
2511
+ return [base, `Offline lint rejected this plan: ${preview}${overflow}`];
2512
+ }
2513
+ if (validation.valid) return [];
2514
+ const issues = validation.issues ?? [];
2515
+ const preview = issues
2516
+ .slice(0, 8)
2517
+ .map((issue) =>
2518
+ issue.path ? `${issue.path}: ${issue.message}` : issue.message,
2519
+ )
2520
+ .join("; ");
2521
+ const overflow = issues.length > 8 ? ` (+${issues.length - 8} more)` : "";
2522
+ return [
2523
+ `Renderer schema rejected this plan — it will not render. ${preview}${overflow}`,
2524
+ ];
2525
+ }
2526
+
2527
+ export async function verifyLocalPlanBridge(input: {
2528
+ dir: string;
2529
+ kind?: LocalPlanKind;
2530
+ title?: string;
2531
+ brief?: string;
2532
+ appUrl?: string;
2533
+ host?: string;
2534
+ port?: number;
2535
+ token?: string;
2536
+ urlFile?: string | false;
2537
+ fetchFn?: typeof fetch;
2538
+ }): Promise<LocalPlanVerifyResult> {
2539
+ const fetchFn = input.fetchFn ?? fetch;
2540
+ const files = readLocalPlanFiles(input.dir);
2541
+ const bridge = await startLocalPlanBridge({
2542
+ dir: input.dir,
2543
+ kind: input.kind,
2544
+ title: input.title,
2545
+ brief: input.brief,
2546
+ appUrl: input.appUrl,
2547
+ host: input.host,
2548
+ port: input.port,
2549
+ token: input.token,
2550
+ urlFile: input.urlFile,
2551
+ // Don't let the weaker offline lint abort the bridge before the authoritative
2552
+ // renderer check runs — verify reports the renderer's verdict, not the lint's.
2553
+ skipSourceValidation: true,
2554
+ });
2555
+
2556
+ try {
2557
+ const preflight = await fetchFn(bridge.result.bridgeUrl, {
2558
+ method: "OPTIONS",
2559
+ headers: {
2560
+ origin: bridge.result.appUrl,
2561
+ "access-control-request-method": "GET",
2562
+ "access-control-request-private-network": "true",
2563
+ },
2564
+ });
2565
+ const response = await fetchFn(bridge.result.bridgeUrl, {
2566
+ method: "GET",
2567
+ headers: { accept: "application/json" },
2568
+ });
2569
+ const payload = (await response.json().catch(() => null)) as
2570
+ | (LocalPlanBridgePayload & { mdx?: LocalPlanBridgeMdxFolder })
2571
+ | null;
2572
+ const mdxFiles = payload?.mdx
2573
+ ? Object.keys(payload.mdx).filter((file) => file !== "assets/")
2574
+ : undefined;
2575
+ const bridgeOk =
2576
+ response.ok &&
2577
+ payload?.ok === true &&
2578
+ payload.source === "agent-native-local-bridge" &&
2579
+ payload.localOnly === true &&
2580
+ Boolean(payload.mdx?.["plan.mdx"]);
2581
+ const preflightOk =
2582
+ preflight.status === 204 &&
2583
+ preflight.headers.get("access-control-allow-origin") === "*" &&
2584
+ preflight.headers.get("access-control-allow-private-network") === "true";
2585
+ const validation = await fetchRendererValidation({
2586
+ appUrl: bridge.result.appUrl,
2587
+ files,
2588
+ fetchFn,
2589
+ });
2590
+ // The renderer's verdict is authoritative and gates `ok`. When it could not
2591
+ // run (old/unreachable Plan app), fall back to the offline lint as the
2592
+ // content signal so verify still catches the common cases offline instead
2593
+ // of silently passing unvalidated content.
2594
+ const offlineIssues = validation.ran ? [] : validateLocalPlanFiles(files);
2595
+ const contentOk = validation.ran
2596
+ ? validation.valid === true
2597
+ : offlineIssues.length === 0;
2598
+ return {
2599
+ ok: bridgeOk && preflightOk && contentOk,
2600
+ dir: bridge.result.dir,
2601
+ url: bridge.result.url,
2602
+ ...(bridge.result.urlFile ? { urlFile: bridge.result.urlFile } : {}),
2603
+ bridgeUrl: bridge.result.bridgeUrl,
2604
+ appUrl: bridge.result.appUrl,
2605
+ title: bridge.result.title,
2606
+ kind: bridge.result.kind,
2607
+ files: bridge.result.files,
2608
+ preflight: {
2609
+ status: preflight.status,
2610
+ allowOrigin: preflight.headers.get("access-control-allow-origin"),
2611
+ allowPrivateNetwork: preflight.headers.get(
2612
+ "access-control-allow-private-network",
2613
+ ),
2614
+ },
2615
+ bridge: {
2616
+ status: response.status,
2617
+ ok: bridgeOk,
2618
+ ...(payload?.source ? { source: payload.source } : {}),
2619
+ ...(typeof payload?.localOnly === "boolean"
2620
+ ? { localOnly: payload.localOnly }
2621
+ : {}),
2622
+ ...(Array.isArray(payload?.files) ? { files: payload.files } : {}),
2623
+ ...(mdxFiles ? { mdxFiles } : {}),
2624
+ ...(payload?.error ? { error: payload.error } : {}),
2625
+ },
2626
+ validation,
2627
+ warnings: [
2628
+ ...localPlanBridgeWarnings({
2629
+ appUrl: bridge.result.appUrl,
2630
+ bridgeUrl: bridge.result.bridgeUrl,
2631
+ }),
2632
+ ...rendererValidationWarnings(validation, offlineIssues),
2633
+ ],
2634
+ };
2635
+ } finally {
2636
+ await new Promise<void>((resolve) => bridge.server.close(() => resolve()));
2637
+ }
2638
+ }
2639
+
2640
+ function writeLocalPlanSkeleton(input: {
2641
+ dir?: string;
2642
+ title: string;
2643
+ brief?: string;
2644
+ kind: LocalPlanKind;
2645
+ force?: boolean;
2646
+ }): { ok: true; dir: string; files: string[] } {
2647
+ const dir = path.resolve(
2648
+ input.dir || path.join(defaultPlansDir(), localPlanFolderName(input.title)),
2649
+ );
2650
+ const planPath = path.join(dir, "plan.mdx");
2651
+ if (fs.existsSync(planPath) && !input.force) {
2652
+ throw new Error(
2653
+ `${planPath} already exists. Pass --force to replace the skeleton.`,
2654
+ );
2655
+ }
2656
+ fs.mkdirSync(dir, { recursive: true });
2657
+ const title = input.title;
2658
+ const brief =
2659
+ input.brief ||
2660
+ (input.kind === "recap"
2661
+ ? "Local visual recap generated without Plan app database writes."
2662
+ : "Local visual plan generated without Plan app database writes.");
2663
+ const mdx = [
2664
+ "---",
2665
+ `title: "${title.replace(/"/g, '\\"')}"`,
2666
+ `brief: "${brief.replace(/"/g, '\\"')}"`,
2667
+ `kind: "${input.kind}"`,
2668
+ "localOnly: true",
2669
+ "---",
2670
+ "",
2671
+ `# ${title}`,
2672
+ "",
2673
+ brief,
2674
+ "",
2675
+ "## Review Surface",
2676
+ "",
2677
+ "Author the structured plan or recap here. You can add Agent-Native Plan MDX",
2678
+ 'blocks such as `<WireframeBlock><Screen surface="browser">...</Screen></WireframeBlock>`,',
2679
+ "`<Diagram />`, `<TabsBlock />`, `<FileTree />`, or `<Diff />`; the local",
2680
+ "preview will show the source without publishing it to the Plan app.",
2681
+ "",
2682
+ ].join("\n");
2683
+ fs.writeFileSync(planPath, mdx, "utf-8");
2684
+ fs.writeFileSync(
2685
+ path.join(dir, ".plan-state.json"),
2686
+ JSON.stringify(
2687
+ {
2688
+ localOnly: true,
2689
+ kind: input.kind,
2690
+ createdAt: new Date().toISOString(),
2691
+ },
2692
+ null,
2693
+ 2,
2694
+ ) + "\n",
2695
+ "utf-8",
2696
+ );
2697
+ return { ok: true, dir, files: ["plan.mdx", ".plan-state.json"] };
2698
+ }
2699
+
2700
+ function runInit(args: Record<string, string | boolean>): void {
2701
+ const title = optionalArg(args, "title") || "Untitled local visual plan";
2702
+ const result = writeLocalPlanSkeleton({
2703
+ dir: optionalArg(args, "dir"),
2704
+ title,
2705
+ brief: optionalArg(args, "brief"),
2706
+ kind: normalizeKind(optionalArg(args, "kind")),
2707
+ force: boolArg(args, "force"),
2708
+ });
2709
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
2710
+ }
2711
+
2712
+ function runCheck(args: Record<string, string | boolean>): void {
2713
+ const dir = stringArg(args, "dir");
2714
+ const files = readLocalPlanFiles(dir);
2715
+ assertLocalPlanFilesValid(files);
2716
+ const parsed = stripFrontmatter(files.planMdx);
2717
+ const result = {
2718
+ ok: true,
2719
+ noDb: true,
2720
+ validation: "lint-passed",
2721
+ validationScope: "offline-lint",
2722
+ note: "Quick offline lint only — NOT the full Plan renderer schema. A green here does not guarantee the plan renders. Run `plan local verify` against a Plan app for authoritative validation before handing off.",
2723
+ dir: files.dir,
2724
+ title: parsed.frontmatter.title || firstHeading(parsed.body),
2725
+ kind: normalizeKind(parsed.frontmatter.kind),
2726
+ files: {
2727
+ "plan.mdx": Buffer.byteLength(files.planMdx),
2728
+ ...(files.canvasMdx
2729
+ ? { "canvas.mdx": Buffer.byteLength(files.canvasMdx) }
2730
+ : {}),
2731
+ ...(files.prototypeMdx
2732
+ ? { "prototype.mdx": Buffer.byteLength(files.prototypeMdx) }
2733
+ : {}),
2734
+ ...(files.stateJson
2735
+ ? { ".plan-state.json": Buffer.byteLength(files.stateJson) }
2736
+ : {}),
2737
+ ...(files.assets
2738
+ ? Object.fromEntries(
2739
+ Object.entries(files.assets).map(([filename, base64]) => [
2740
+ `assets/${filename}`,
2741
+ Buffer.byteLength(base64, "base64"),
2742
+ ]),
2743
+ )
2744
+ : {}),
2745
+ },
2746
+ };
2747
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
2748
+ }
2749
+
2750
+ export function readVisualAnswerSourcePayload(
2751
+ sourcePath: string,
2752
+ ): VisualAnswerSourcePayload {
2753
+ let parsed: unknown;
2754
+ try {
2755
+ parsed = JSON.parse(fs.readFileSync(sourcePath, "utf-8"));
2756
+ } catch (error) {
2757
+ throw new Error(
2758
+ `Could not read ${sourcePath}: ${
2759
+ error instanceof Error ? error.message : String(error)
2760
+ }`,
2761
+ );
2762
+ }
2763
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2764
+ throw new Error(`${sourcePath} must contain a JSON object.`);
2765
+ }
2766
+ const source = parsed as Record<string, unknown>;
2767
+ const mdx = source.mdx;
2768
+ if (!mdx || typeof mdx !== "object" || Array.isArray(mdx)) {
2769
+ throw new Error(`${sourcePath} must contain an mdx object.`);
2770
+ }
2771
+ const planMdx = (mdx as Record<string, unknown>)["plan.mdx"];
2772
+ if (typeof planMdx !== "string" || planMdx.trim().length === 0) {
2773
+ throw new Error(
2774
+ `${sourcePath} mdx["plan.mdx"] must be a non-empty string.`,
2775
+ );
2776
+ }
2777
+ return source as VisualAnswerSourcePayload;
2778
+ }
2779
+
2780
+ export async function publishVisualAnswerSource(
2781
+ input: PublishVisualAnswerInput,
2782
+ ): Promise<{ ok: true; url: string; out: string }> {
2783
+ const cwd = input.cwd ?? process.cwd();
2784
+ const sourcePath =
2785
+ input.sourcePath ?? path.join(cwd, VISUAL_ANSWER_SOURCE_FILENAME);
2786
+ const out = input.out ?? path.join(cwd, VISUAL_ANSWER_URL_FILENAME);
2787
+ const token = input.token.trim();
2788
+ if (!token) throw new Error("Plan publish token is empty.");
2789
+
2790
+ const source = readVisualAnswerSourcePayload(sourcePath);
2791
+ const question = input.question ?? source.question;
2792
+ if (!question?.trim()) {
2793
+ throw new Error(
2794
+ `Missing visual answer question. Pass --question or set question in ${sourcePath}.`,
2795
+ );
2796
+ }
2797
+ const body = {
2798
+ question,
2799
+ ...(input.prevPlanId ? { planId: input.prevPlanId } : {}),
2800
+ ...(source.title ? { title: source.title } : {}),
2801
+ ...(source.brief ? { brief: source.brief } : {}),
2802
+ visibility: input.visibility ?? "org",
2803
+ source: "imported",
2804
+ ...((input.repo ?? source.repoPath)
2805
+ ? { repoPath: input.repo ?? source.repoPath }
2806
+ : {}),
2807
+ ...((input.sourceUrl ?? source.sourceUrl)
2808
+ ? { sourceUrl: input.sourceUrl ?? source.sourceUrl }
2809
+ : {}),
2810
+ sourceType: normalizeVisualAnswerSourceType(
2811
+ input.sourceType ?? source.sourceType,
2812
+ ),
2813
+ currentFocus: `visual answer: ${question.trim().slice(0, 120)}`,
2814
+ status: "review",
2815
+ mdx: source.mdx,
2816
+ };
2817
+
2818
+ const endpoint = planActionEndpoint(input.appUrl, "visual-answer");
2819
+ const fetchFn = input.fetchFn ?? fetch;
2820
+ const response = await fetchActionWithTimeout(
2821
+ endpoint,
2822
+ {
2823
+ method: "POST",
2824
+ headers: {
2825
+ accept: "application/json",
2826
+ "content-type": "application/json",
2827
+ authorization: `Bearer ${token}`,
2828
+ },
2829
+ body: JSON.stringify(body),
2830
+ },
2831
+ fetchFn,
2832
+ );
2833
+ const text = await response.text().catch((error) => String(error));
2834
+ if (!response.ok) {
2835
+ throw new Error(
2836
+ `visual-answer failed ${response.status} ${
2837
+ response.statusText
2838
+ }: ${sanitizeHttpDetail(text, 800)}`,
2839
+ );
2840
+ }
2841
+ let result: unknown = null;
2842
+ try {
2843
+ result = text ? JSON.parse(text) : null;
2844
+ } catch {
2845
+ throw new Error("visual-answer returned non-JSON output.");
2846
+ }
2847
+ const url = visualAnswerUrlFromPublishResult(result, input.appUrl);
2848
+ if (!url) {
2849
+ throw new Error(
2850
+ "visual-answer succeeded but did not return a usable /plans/<id> URL or plan id.",
2851
+ );
2852
+ }
2853
+ fs.writeFileSync(path.resolve(out), `${url}\n`, "utf-8");
2854
+ return { ok: true, url, out };
2855
+ }
2856
+
2857
+ async function runVisualAnswer(
2858
+ subcommand: string | undefined,
2859
+ args: Record<string, string | boolean>,
2860
+ ): Promise<void> {
2861
+ if (
2862
+ subcommand === undefined ||
2863
+ subcommand === "help" ||
2864
+ subcommand === "--help" ||
2865
+ subcommand === "-h" ||
2866
+ args.help === true ||
2867
+ args.h === true
2868
+ ) {
2869
+ process.stdout.write(HELP);
2870
+ return;
2871
+ }
2872
+ if (subcommand !== "publish") {
2873
+ process.stderr.write(
2874
+ `Unknown plan visual-answer subcommand: ${subcommand}\n${HELP}`,
2875
+ );
2876
+ process.exit(1);
2877
+ }
2878
+ const appUrl =
2879
+ optionalArg(args, "app-url") ||
2880
+ process.env.PLAN_VISUAL_ANSWER_APP_URL ||
2881
+ process.env.PLAN_RECAP_APP_URL ||
2882
+ DEFAULT_PLAN_APP_URL;
2883
+ const token =
2884
+ optionalArg(args, "token") ||
2885
+ process.env.PLAN_VISUAL_ANSWER_TOKEN ||
2886
+ process.env.PLAN_RECAP_TOKEN ||
2887
+ "";
2888
+ try {
2889
+ const result = await publishVisualAnswerSource({
2890
+ appUrl,
2891
+ token,
2892
+ question: optionalArg(args, "question"),
2893
+ sourcePath: optionalArg(args, "source") ?? VISUAL_ANSWER_SOURCE_FILENAME,
2894
+ out: optionalArg(args, "out") ?? VISUAL_ANSWER_URL_FILENAME,
2895
+ prevPlanId: optionalArg(args, "prev-plan-id"),
2896
+ repo: optionalArg(args, "repo"),
2897
+ sourceUrl: optionalArg(args, "source-url"),
2898
+ sourceType: optionalArg(args, "source-type"),
2899
+ visibility: normalizeVisibility(optionalArg(args, "visibility")),
2900
+ });
2901
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
2902
+ } catch (error) {
2903
+ process.stdout.write(
2904
+ `${JSON.stringify(
2905
+ {
2906
+ ok: false,
2907
+ reason: error instanceof Error ? error.message : String(error),
2908
+ },
2909
+ null,
2910
+ 2,
2911
+ )}\n`,
2912
+ );
2913
+ process.exit(1);
2914
+ }
2915
+ }
2916
+
2917
+ function runPreview(args: Record<string, string | boolean>): void {
2918
+ const result = writeLocalPlanPreview({
2919
+ dir: stringArg(args, "dir"),
2920
+ out: optionalArg(args, "out"),
2921
+ appUrl: optionalArg(args, "app-url"),
2922
+ title: optionalArg(args, "title"),
2923
+ brief: optionalArg(args, "brief"),
2924
+ open: boolArg(args, "open"),
2925
+ kind: optionalArg(args, "kind")
2926
+ ? normalizeKind(optionalArg(args, "kind"))
2927
+ : undefined,
2928
+ });
2929
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
2930
+ }
2931
+
2932
+ async function runServe(args: Record<string, string | boolean>): Promise<void> {
2933
+ const portValue = optionalArg(args, "port");
2934
+ const port = portValue ? Number(portValue) : undefined;
2935
+ if (portValue && (!Number.isInteger(port) || port! < 0 || port! > 65535)) {
2936
+ throw new Error("--port must be an integer between 0 and 65535.");
2937
+ }
2938
+
2939
+ const bridge = await startLocalPlanBridge({
2940
+ dir: stringArg(args, "dir"),
2941
+ appUrl: optionalArg(args, "app-url"),
2942
+ title: optionalArg(args, "title"),
2943
+ brief: optionalArg(args, "brief"),
2944
+ host: optionalArg(args, "host"),
2945
+ port,
2946
+ open: boolArg(args, "open"),
2947
+ urlFile: optionalArg(args, "url-file") || optionalArg(args, "out"),
2948
+ kind: optionalArg(args, "kind")
2949
+ ? normalizeKind(optionalArg(args, "kind"))
2950
+ : undefined,
2951
+ });
2952
+
2953
+ process.stdout.write(`${JSON.stringify(bridge.result, null, 2)}\n`);
2954
+ process.stderr.write(
2955
+ [
2956
+ `Local Plan bridge running at ${bridge.result.bridgeUrl}`,
2957
+ bridge.result.urlFile
2958
+ ? `Open URL written to ${bridge.result.urlFile}`
2959
+ : "",
2960
+ ...localPlanBridgeWarnings({
2961
+ appUrl: bridge.result.appUrl,
2962
+ bridgeUrl: bridge.result.bridgeUrl,
2963
+ }),
2964
+ "Keep this bridge command running while the Plan page is open; stopping it makes this URL unreachable.",
2965
+ "Press Ctrl+C to stop.",
2966
+ ]
2967
+ .filter(Boolean)
2968
+ .join("\n") + "\n",
2969
+ );
2970
+
2971
+ await new Promise<void>((resolve) => {
2972
+ let stopped = false;
2973
+ const cleanup = () => {
2974
+ process.off("SIGINT", stop);
2975
+ process.off("SIGTERM", stop);
2976
+ };
2977
+ const stop = () => {
2978
+ if (stopped) return;
2979
+ stopped = true;
2980
+ cleanup();
2981
+ bridge.server.close(() => resolve());
2982
+ };
2983
+ process.once("SIGINT", stop);
2984
+ process.once("SIGTERM", stop);
2985
+ });
2986
+ }
2987
+
2988
+ async function runVerify(
2989
+ args: Record<string, string | boolean>,
2990
+ ): Promise<void> {
2991
+ const portValue = optionalArg(args, "port");
2992
+ const port = portValue ? Number(portValue) : undefined;
2993
+ if (portValue && (!Number.isInteger(port) || port! < 0 || port! > 65535)) {
2994
+ throw new Error("--port must be an integer between 0 and 65535.");
2995
+ }
2996
+
2997
+ const result = await verifyLocalPlanBridge({
2998
+ dir: stringArg(args, "dir"),
2999
+ appUrl: optionalArg(args, "app-url"),
3000
+ title: optionalArg(args, "title"),
3001
+ brief: optionalArg(args, "brief"),
3002
+ host: optionalArg(args, "host"),
3003
+ port,
3004
+ urlFile: optionalArg(args, "url-file") || optionalArg(args, "out") || false,
3005
+ kind: optionalArg(args, "kind")
3006
+ ? normalizeKind(optionalArg(args, "kind"))
3007
+ : undefined,
3008
+ });
3009
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
3010
+ if (!result.ok) process.exit(1);
3011
+ }
3012
+
3013
+ async function runBlocks(
3014
+ args: Record<string, string | boolean>,
3015
+ ): Promise<void> {
3016
+ const format = normalizePlanBlockFormat(optionalArg(args, "format"));
3017
+ const appUrl =
3018
+ optionalArg(args, "app-url") ||
3019
+ process.env.PLAN_BLOCKS_APP_URL ||
3020
+ process.env.PLAN_RECAP_APP_URL ||
3021
+ DEFAULT_PLAN_APP_URL;
3022
+ const out = optionalArg(args, "out") || defaultPlanBlocksOut(format);
3023
+ const useClack = Boolean(process.stdout.isTTY) && !boolArg(args, "json");
3024
+ let stopSpinner: ((message?: string) => void) | undefined;
3025
+ let clack: typeof import("@clack/prompts") | undefined;
3026
+
3027
+ if (useClack) {
3028
+ clack = await import("@clack/prompts");
3029
+ const spinner = clack.spinner();
3030
+ spinner.start("Fetching Plan block catalog");
3031
+ stopSpinner = (message?: string) => spinner.stop(message);
3032
+ }
3033
+
3034
+ try {
3035
+ const result = await fetchPlanBlockCatalog({
3036
+ appUrl,
3037
+ format,
3038
+ out,
3039
+ });
3040
+ if (!useClack || !clack) {
3041
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
3042
+ return;
3043
+ }
3044
+ stopSpinner?.("Fetched Plan block catalog");
3045
+ clack.note(
3046
+ [
3047
+ `Output ${path.resolve(result.out)}`,
3048
+ `Format ${result.format}`,
3049
+ typeof result.count === "number" ? `Blocks ${result.count}` : "",
3050
+ "Privacy No plan content sent",
3051
+ ]
3052
+ .filter(Boolean)
3053
+ .join("\n"),
3054
+ "Plan block catalog",
3055
+ );
3056
+ clack.outro(`Wrote ${result.out}`);
3057
+ } catch (error) {
3058
+ if (useClack && clack) {
3059
+ stopSpinner?.("Plan block catalog fetch failed");
3060
+ clack.cancel(error instanceof Error ? error.message : String(error));
3061
+ process.exit(1);
3062
+ }
3063
+ throw error;
3064
+ }
3065
+ }
3066
+
3067
+ const HELP = `agent-native plan — local Agent-Native Plan helpers
3068
+
3069
+ Usage:
3070
+ agent-native plan blocks [--format reference|schema] [--app-url <url>] [--out <file>] [--json]
3071
+ agent-native plan visual-answer publish --question <text> [--source visual-answer-source.json] [--out visual-answer-url.txt] [--repo owner/name] [--source-url <url>] [--app-url <url>] [--token <planToken>]
3072
+ agent-native plan serve --dir <folder> [--app-url <url>] [--kind plan|recap] [--open] [--port <port>] [--url-file <file>]
3073
+ agent-native plan local init --title <title> [--brief <text>] [--kind plan|recap] [--dir <folder>] [--force]
3074
+ agent-native plan local check --dir <folder>
3075
+ agent-native plan local serve --dir <folder> [--app-url <url>] [--kind plan|recap] [--open] [--port <port>] [--url-file <file>]
3076
+ agent-native plan local verify --dir <folder> [--app-url <url>] [--kind plan|recap] [--port <port>]
3077
+ agent-native plan local preview --dir <folder> [--app-url <url>] [--kind plan|recap] [--open] [--out preview.html]
3078
+
3079
+ The blocks command fetches the no-auth, read-only get-plan-blocks catalog from
3080
+ the Plan app and writes plan-blocks.md (or plan-blocks.schema.json). It sends no
3081
+ plan content and is safe for local-files authoring before writing MDX. It uses a
3082
+ clack UI in interactive terminals and prints JSON for non-interactive shells or
3083
+ when --json is passed.
3084
+
3085
+ The visual-answer publish command sends a coding-agent-authored
3086
+ visual-answer-source.json file to the Plan app's visual-answer action and writes
3087
+ visual-answer-url.txt. The source file should contain a question, optional
3088
+ title/brief/repoPath/sourceUrl, and MDX files under mdx. It is the terminal
3089
+ handoff for /visual-answer workflows after a coding agent has inspected code via
3090
+ the local repo, the Plan bridge, or GitHub and authored structured Plan blocks.
3091
+
3092
+ The local subcommands are the privacy-focused no-DB path. They only read and
3093
+ write local files: plan.mdx, optional canvas.mdx, optional prototype.mdx, and
3094
+ optional .plan-state.json. They do not call the Plan MCP server, the Plan app
3095
+ write actions, hosted storage, or SQLite.
3096
+
3097
+ Common flow:
3098
+ agent-native plan blocks --out plan-blocks.md
3099
+ agent-native plan local init --title "Checkout review" --kind plan
3100
+ agent-native plan local serve --dir plans/checkout-review --open
3101
+
3102
+ \`plan local serve\` starts a tiny localhost bridge and opens the hosted Plan UI
3103
+ against that local-only source. The hosted app fetches the MDX from localhost in
3104
+ the browser; it does not write plan content to the hosted database. The served
3105
+ URL is written to \`.plan-url\` by default; pass \`--url-file\` to choose a
3106
+ different local-only file. On macOS, \`--open\` prefers Chromium browsers.
3107
+ Chrome/Edge will ask for Local Network access to read the loopback bridge; if
3108
+ you deny it, re-enable Local Network access in the plan.agent-native.com site
3109
+ settings and retry. Keep the bridge command running while the page is open.
3110
+ Safari may block the hosted HTTPS page from reading the HTTP localhost bridge;
3111
+ use a Chromium browser or a local Plan app via \`--app-url http://localhost:8096\`.
3112
+ Use \`plan local verify\` for headless bridge/CORS diagnostics that exit cleanly.
3113
+ Use \`plan local preview\` for a local Plan dev server route. \`preview --out\` is
3114
+ a legacy/debug escape hatch that writes a standalone static HTML file.
3115
+ \`plan serve\` is kept as a compatibility alias for \`plan local serve\`.
3116
+ `;
3117
+
3118
+ export async function runPlan(argv: string[]): Promise<void> {
3119
+ const [area, sub, ...rest] = argv;
3120
+ if (area === "blocks") {
3121
+ await runBlocks(parseArgs(argv.slice(1)));
3122
+ return;
3123
+ }
3124
+ if (area === "serve") {
3125
+ const args = parseArgs(argv.slice(1));
3126
+ if (args.help === true || args.h === true) {
3127
+ process.stdout.write(HELP);
3128
+ return;
3129
+ }
3130
+ await runServe(args);
3131
+ return;
3132
+ }
3133
+ if (area === "visual-answer") {
3134
+ await runVisualAnswer(sub, parseArgs(rest));
3135
+ return;
3136
+ }
3137
+ if (area !== "local") {
3138
+ // Bare `agent-native plan` / `plan help` / `plan --help` → show help on
3139
+ // stdout and exit 0 (informational, not an error).
3140
+ if (
3141
+ area === undefined ||
3142
+ area === "help" ||
3143
+ area === "--help" ||
3144
+ area === "-h"
3145
+ ) {
3146
+ process.stdout.write(HELP);
3147
+ return;
3148
+ }
3149
+ // A non-empty, unrecognised area (e.g. `agent-native plan lokal`) is an
3150
+ // error: print to stderr so the CI log captures it, and exit 1 so callers
3151
+ // can detect the failure. This mirrors the existing behaviour for unknown
3152
+ // subcommands inside `plan local`.
3153
+ process.stderr.write(`Unknown plan area: ${area}\n${HELP}`);
3154
+ process.exit(1);
3155
+ }
3156
+ const args = parseArgs(rest);
3157
+ // `plan local <sub> --help` / `-h` shows help instead of running the
3158
+ // subcommand (e.g. `plan local init --help` must not scaffold a folder).
3159
+ if (args.help === true || args.h === true) {
3160
+ process.stdout.write(HELP);
3161
+ return;
3162
+ }
3163
+ switch (sub) {
3164
+ case "init":
3165
+ runInit(args);
3166
+ return;
3167
+ case "check":
3168
+ runCheck(args);
3169
+ return;
3170
+ case "preview":
3171
+ runPreview(args);
3172
+ return;
3173
+ case "serve":
3174
+ await runServe(args);
3175
+ return;
3176
+ case "verify":
3177
+ await runVerify(args);
3178
+ return;
3179
+ case "help":
3180
+ case "--help":
3181
+ case "-h":
3182
+ case undefined:
3183
+ process.stdout.write(HELP);
3184
+ return;
3185
+ default:
3186
+ process.stderr.write(`Unknown plan local subcommand: ${sub}\n${HELP}`);
3187
+ process.exit(1);
3188
+ }
3189
+ }