@notis_ai/cli 0.2.18 → 0.2.20

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 (395) hide show
  1. package/README.md +542 -146
  2. package/bin/check-runtime.js +15 -0
  3. package/bin/notis.js +2 -0
  4. package/config/notis_app_design_rules.json +320 -0
  5. package/config/portal-route-roots.json +45 -0
  6. package/dist/agent-hooks/notis-agent-hook.mjs +42325 -18273
  7. package/dist/base-skills/notis-cli/.notis-base-skill.json +1 -0
  8. package/dist/base-skills/notis-cli/SKILL.md +51 -280
  9. package/dist/base-skills/notis-cli/references/app-delivery.md +17 -0
  10. package/dist/base-skills/notis-cli/references/intelligence.md +94 -0
  11. package/dist/base-skills/notis-cli/references/native-databases.md +21 -0
  12. package/dist/base-skills/notis-cli/references/tool-examples.md +56 -0
  13. package/dist/base-skills/notis-cli/references/troubleshooting.md +67 -0
  14. package/dist/base-skills/notis-query/.notis-base-skill.json +1 -0
  15. package/dist/base-skills/notis-query/SKILL.md +35 -699
  16. package/dist/base-skills/notis-query/references/database-discovery.md +59 -0
  17. package/dist/base-skills/notis-query/references/documents.md +74 -0
  18. package/dist/base-skills/notis-query/references/query.md +76 -0
  19. package/dist/base-skills/notis-spaces/.notis-base-skill.json +1 -0
  20. package/dist/base-skills/notis-spaces/SKILL.md +218 -0
  21. package/dist/base-skills/notis-spaces/references/architecture.md +116 -0
  22. package/dist/base-skills/notis-spaces/references/context.md +81 -0
  23. package/dist/base-skills/notis-spaces/references/design.md +141 -0
  24. package/dist/base-skills/notis-spaces/references/fixtures.md +29 -0
  25. package/dist/base-skills/notis-spaces/references/memory.md +58 -0
  26. package/dist/base-skills/notis-spaces/references/reading.md +73 -0
  27. package/dist/base-skills/notis-spaces/references/release.md +120 -0
  28. package/dist/base-skills/notis-spaces/references/reports.md +77 -0
  29. package/dist/base-skills/notis-spaces/references/sdk.md +273 -0
  30. package/dist/base-skills/notis-spaces/references/store.md +118 -0
  31. package/dist/base-skills/notis-spaces/references/troubleshooting.md +28 -0
  32. package/dist/base-skills/notis-spaces/references/views.md +229 -0
  33. package/{template/packages → dist}/sdk/package.json +9 -10
  34. package/dist/sdk/src/agentContext.ts +36 -0
  35. package/dist/sdk/src/bundleModule.ts +175 -0
  36. package/dist/sdk/src/components/Dialog.tsx +103 -0
  37. package/dist/sdk/src/components/DocumentEditor.tsx +113 -0
  38. package/dist/sdk/src/components/DocumentPage.tsx +184 -0
  39. package/{template/packages → dist}/sdk/src/components/Markdown.tsx +9 -3
  40. package/{template/packages → dist}/sdk/src/components/MarkdownEditor.tsx +26 -5
  41. package/{template/packages → dist}/sdk/src/components/MultiSelectActionBar.tsx +95 -12
  42. package/{template/packages → dist}/sdk/src/components/MultiSelectCheckbox.tsx +4 -2
  43. package/dist/sdk/src/components/NotisCommentBoundary.tsx +172 -0
  44. package/{template/packages → dist}/sdk/src/components/NotisSelectionBoundary.tsx +9 -5
  45. package/dist/sdk/src/components/RecordComponents.tsx +111 -0
  46. package/dist/sdk/src/components/Skeleton.tsx +38 -0
  47. package/dist/sdk/src/config.ts +31 -0
  48. package/{template/packages → dist}/sdk/src/documents.ts +21 -6
  49. package/dist/sdk/src/hooks/useAction.ts +28 -0
  50. package/dist/sdk/src/hooks/useAgentContext.ts +23 -0
  51. package/{template/packages → dist}/sdk/src/hooks/useBackend.ts +3 -2
  52. package/dist/sdk/src/hooks/useCloudComputer.ts +94 -0
  53. package/dist/sdk/src/hooks/useCloudComputerShell.ts +114 -0
  54. package/{template/packages → dist}/sdk/src/hooks/useCollectionInteractions.ts +157 -147
  55. package/dist/sdk/src/hooks/useDatabaseSchema.ts +50 -0
  56. package/{template/packages → dist}/sdk/src/hooks/useDatabaseSubscription.ts +2 -2
  57. package/dist/sdk/src/hooks/useDocument.ts +51 -0
  58. package/{template/packages → dist}/sdk/src/hooks/useDocuments.ts +25 -59
  59. package/{template/packages → dist}/sdk/src/hooks/useHandover.ts +7 -7
  60. package/dist/sdk/src/hooks/useLongPressSelection.ts +79 -0
  61. package/dist/sdk/src/hooks/useMarqueeSelection.ts +194 -0
  62. package/{template/packages → dist}/sdk/src/hooks/useMultiSelect.ts +2 -8
  63. package/dist/sdk/src/hooks/useNativeDocumentBody.ts +50 -0
  64. package/dist/sdk/src/hooks/useNativeDocuments.ts +143 -0
  65. package/{template/packages → dist}/sdk/src/hooks/useNotis.ts +6 -1
  66. package/dist/sdk/src/hooks/useNotisNavigation.ts +70 -0
  67. package/dist/sdk/src/hooks/useQuery.ts +81 -0
  68. package/dist/sdk/src/hooks/useToolQuery.ts +12 -0
  69. package/dist/sdk/src/hooks/useTopBarSearch.ts +102 -0
  70. package/dist/sdk/src/hooks/useTopBarTitleLeaf.ts +75 -0
  71. package/{template/packages → dist}/sdk/src/hooks/useUpsertDocument.ts +1 -1
  72. package/dist/sdk/src/hooks/useViewParams.ts +195 -0
  73. package/dist/sdk/src/hooks/useViewerReads.ts +129 -0
  74. package/{template/packages → dist}/sdk/src/index.ts +64 -1
  75. package/{template/packages → dist}/sdk/src/interactions/actions.ts +14 -1
  76. package/{template/packages → dist}/sdk/src/interactions/shortcuts.tsx +129 -23
  77. package/dist/sdk/src/interactions/visibility.ts +13 -0
  78. package/{template/packages → dist}/sdk/src/interactions.ts +5 -1
  79. package/dist/sdk/src/nativeData.ts +39 -0
  80. package/{template/packages → dist}/sdk/src/provider.tsx +9 -4
  81. package/dist/sdk/src/queryCache.ts +292 -0
  82. package/dist/sdk/src/queryErrors.ts +51 -0
  83. package/dist/sdk/src/runtime.ts +675 -0
  84. package/dist/sdk/src/runtimeModules.ts +33 -0
  85. package/dist/sdk/src/space.ts +442 -0
  86. package/dist/sdk/src/standardViewParams.ts +36 -0
  87. package/{template/packages → dist}/sdk/src/styles.css +81 -16
  88. package/dist/sdk/src/tailwind.ts +66 -0
  89. package/dist/sdk/src/ui/charts/RenderChartData.tsx +25 -0
  90. package/dist/sdk/src/ui/engine/core.ts +392 -0
  91. package/dist/sdk/src/ui/engine/dom.ts +183 -0
  92. package/dist/sdk/src/ui/engine/hooks.ts +195 -0
  93. package/dist/sdk/src/ui/engine/instance.ts +63 -0
  94. package/dist/sdk/src/ui/engine/keycapContext.ts +2 -0
  95. package/dist/sdk/src/ui/engine/registry.ts +262 -0
  96. package/dist/sdk/src/ui/engine/types.ts +62 -0
  97. package/dist/sdk/src/ui/icons.tsx +91 -0
  98. package/dist/sdk/src/ui/util.ts +83 -0
  99. package/dist/sdk/src/viewPeriod.ts +26 -0
  100. package/dist/sdk/src/vite.ts +92 -0
  101. package/dist/sdk/src/words/actions.ts +295 -0
  102. package/dist/sdk/src/words/clashes.ts +158 -0
  103. package/dist/sdk/src/words/format.ts +136 -0
  104. package/dist/sdk/src/words/index.ts +13 -0
  105. package/dist/sdk/src/words/keymap.ts +72 -0
  106. package/dist/sdk/src/words/keys.ts +297 -0
  107. package/dist/sdk/src/words/shell.ts +46 -0
  108. package/dist/sdk/src/words/types.ts +65 -0
  109. package/dist/skill-sync/index.js +832 -151
  110. package/dist/skill-sync/index.js.map +4 -4
  111. package/dist/skill-sync-worker.mjs +3941 -0
  112. package/dist/space-harness/host.js +1460 -0
  113. package/dist/space-sdk/dist/chunk-ZSN57ATH.js +5 -0
  114. package/dist/space-sdk/dist/index.js +15 -0
  115. package/dist/space-sdk/dist/ui.js +18 -0
  116. package/dist/space-sdk/package.json +33 -0
  117. package/dist/space-sdk/src/agentContext.d.ts +36 -0
  118. package/dist/space-sdk/src/components/Dialog.d.ts +20 -0
  119. package/dist/space-sdk/src/components/DocumentEditor.d.ts +46 -0
  120. package/dist/space-sdk/src/components/DocumentPage.d.ts +53 -0
  121. package/dist/space-sdk/src/components/Markdown.d.ts +18 -0
  122. package/dist/space-sdk/src/components/MarkdownEditor.d.ts +11 -0
  123. package/dist/space-sdk/src/components/MultiSelectActionBar.d.ts +31 -0
  124. package/dist/space-sdk/src/components/MultiSelectCheckbox.d.ts +14 -0
  125. package/dist/space-sdk/src/components/MultiSelectDragOverlay.d.ts +8 -0
  126. package/dist/space-sdk/src/components/NotisCommentBoundary.d.ts +36 -0
  127. package/dist/space-sdk/src/components/NotisSelectionBoundary.d.ts +16 -0
  128. package/dist/space-sdk/src/components/RecordComponents.d.ts +64 -0
  129. package/dist/space-sdk/src/components/ShortcutHints.d.ts +12 -0
  130. package/dist/space-sdk/src/components/Skeleton.d.ts +23 -0
  131. package/dist/space-sdk/src/config.ts +31 -0
  132. package/dist/space-sdk/src/documents.d.ts +59 -0
  133. package/dist/space-sdk/src/hooks/useAction.d.ts +8 -0
  134. package/dist/space-sdk/src/hooks/useActiveResource.d.ts +3 -0
  135. package/dist/space-sdk/src/hooks/useAgentContext.d.ts +7 -0
  136. package/dist/space-sdk/src/hooks/useBackend.d.ts +23 -0
  137. package/dist/space-sdk/src/hooks/useCloudComputer.d.ts +45 -0
  138. package/dist/space-sdk/src/hooks/useCloudComputerShell.d.ts +49 -0
  139. package/dist/space-sdk/src/hooks/useCollectionInteractions.d.ts +118 -0
  140. package/dist/space-sdk/src/hooks/useDatabaseSchema.d.ts +14 -0
  141. package/dist/space-sdk/src/hooks/useDatabaseSubscription.d.ts +26 -0
  142. package/dist/space-sdk/src/hooks/useDocument.d.ts +22 -0
  143. package/dist/space-sdk/src/hooks/useDocuments.d.ts +31 -0
  144. package/dist/space-sdk/src/hooks/useHandover.d.ts +43 -0
  145. package/dist/space-sdk/src/hooks/useLongPressSelection.d.ts +9 -0
  146. package/dist/space-sdk/src/hooks/useMarqueeSelection.d.ts +57 -0
  147. package/dist/space-sdk/src/hooks/useMultiSelect.d.ts +51 -0
  148. package/dist/space-sdk/src/hooks/useNativeDocumentBody.d.ts +24 -0
  149. package/dist/space-sdk/src/hooks/useNativeDocuments.d.ts +55 -0
  150. package/dist/space-sdk/src/hooks/useNotis.d.ts +25 -0
  151. package/dist/space-sdk/src/hooks/useNotisNavigation.d.ts +33 -0
  152. package/dist/space-sdk/src/hooks/useQuery.d.ts +22 -0
  153. package/dist/space-sdk/src/hooks/useTool.d.ts +20 -0
  154. package/dist/space-sdk/src/hooks/useToolQuery.d.ts +3 -0
  155. package/dist/space-sdk/src/hooks/useTools.d.ts +15 -0
  156. package/dist/space-sdk/src/hooks/useTopBarSearch.d.ts +48 -0
  157. package/dist/space-sdk/src/hooks/useTopBarTitleLeaf.d.ts +24 -0
  158. package/dist/space-sdk/src/hooks/useUpsertDocument.d.ts +27 -0
  159. package/dist/space-sdk/src/hooks/useViewParams.d.ts +76 -0
  160. package/dist/space-sdk/src/hooks/useViewerReads.d.ts +38 -0
  161. package/dist/space-sdk/src/index.d.ts +98 -0
  162. package/dist/space-sdk/src/interactions/actions.d.ts +33 -0
  163. package/dist/space-sdk/src/interactions/shortcuts.d.ts +42 -0
  164. package/dist/space-sdk/src/interactions/visibility.d.ts +2 -0
  165. package/dist/space-sdk/src/nativeData.d.ts +66 -0
  166. package/dist/space-sdk/src/provider.d.ts +17 -0
  167. package/dist/space-sdk/src/queryCache.d.ts +45 -0
  168. package/dist/space-sdk/src/queryErrors.ts +51 -0
  169. package/dist/space-sdk/src/runtime.d.ts +615 -0
  170. package/dist/space-sdk/src/runtimeModules.ts +33 -0
  171. package/dist/space-sdk/src/space.ts +442 -0
  172. package/dist/space-sdk/src/standardViewParams.d.ts +15 -0
  173. package/dist/space-sdk/src/tailwind-candidates.d.ts +3418 -0
  174. package/dist/space-sdk/src/tailwind.ts +66 -0
  175. package/dist/space-sdk/src/ui/actions/ActionToast.d.ts +15 -0
  176. package/dist/space-sdk/src/ui/actions/actionWords.d.ts +16 -0
  177. package/dist/space-sdk/src/ui/actions/index.d.ts +7 -0
  178. package/dist/space-sdk/src/ui/actions/useActions.d.ts +69 -0
  179. package/dist/space-sdk/src/ui/actions/useToast.d.ts +41 -0
  180. package/dist/space-sdk/src/ui/blocks/Tabs.d.ts +139 -0
  181. package/dist/space-sdk/src/ui/blocks/blocks.d.ts +217 -0
  182. package/dist/space-sdk/src/ui/blocks/index.d.ts +4 -0
  183. package/dist/space-sdk/src/ui/board/BoardView.d.ts +36 -0
  184. package/dist/space-sdk/src/ui/board/boardModel.d.ts +46 -0
  185. package/dist/space-sdk/src/ui/board/boardWords.d.ts +9 -0
  186. package/dist/space-sdk/src/ui/board/index.d.ts +5 -0
  187. package/dist/space-sdk/src/ui/calendar/CalendarView.d.ts +49 -0
  188. package/dist/space-sdk/src/ui/calendar/DayPicker.d.ts +23 -0
  189. package/dist/space-sdk/src/ui/calendar/calendarMath.d.ts +81 -0
  190. package/dist/space-sdk/src/ui/charts/Chart.d.ts +203 -0
  191. package/dist/space-sdk/src/ui/charts/ChartTable.d.ts +37 -0
  192. package/dist/space-sdk/src/ui/charts/RenderChartData.d.ts +16 -0
  193. package/dist/space-sdk/src/ui/charts/StatRow.d.ts +59 -0
  194. package/dist/space-sdk/src/ui/charts/chartData.d.ts +84 -0
  195. package/dist/space-sdk/src/ui/comments/CommentPane.d.ts +58 -0
  196. package/dist/space-sdk/src/ui/comments/commentModel.d.ts +157 -0
  197. package/dist/space-sdk/src/ui/comments/commentWords.d.ts +60 -0
  198. package/dist/space-sdk/src/ui/comments/index.d.ts +4 -0
  199. package/dist/space-sdk/src/ui/comments/useComments.d.ts +146 -0
  200. package/dist/space-sdk/src/ui/engine/HelpSheet.d.ts +12 -0
  201. package/dist/space-sdk/src/ui/engine/KeyboardEngine.d.ts +27 -0
  202. package/dist/space-sdk/src/ui/engine/core.d.ts +73 -0
  203. package/dist/space-sdk/src/ui/engine/hooks.d.ts +64 -0
  204. package/dist/space-sdk/src/ui/engine/index.d.ts +14 -0
  205. package/dist/space-sdk/src/ui/engine/instance.d.ts +21 -0
  206. package/dist/space-sdk/src/ui/engine/keycapContext.d.ts +2 -0
  207. package/dist/space-sdk/src/ui/engine/registry.d.ts +77 -0
  208. package/dist/space-sdk/src/ui/engine/step.d.ts +11 -0
  209. package/dist/space-sdk/src/ui/engine/types.d.ts +54 -0
  210. package/dist/space-sdk/src/ui/fields/fieldWords.d.ts +56 -0
  211. package/dist/space-sdk/src/ui/fields/fields.d.ts +162 -0
  212. package/dist/space-sdk/src/ui/fields/index.d.ts +5 -0
  213. package/dist/space-sdk/src/ui/fields/useFieldDraft.d.ts +22 -0
  214. package/dist/space-sdk/src/ui/gallery/AttachmentGallery.d.ts +53 -0
  215. package/dist/space-sdk/src/ui/gallery/ImageViewer.d.ts +27 -0
  216. package/dist/space-sdk/src/ui/gallery/galleryWords.d.ts +95 -0
  217. package/dist/space-sdk/src/ui/gallery/index.d.ts +5 -0
  218. package/dist/space-sdk/src/ui/icons.d.ts +13 -0
  219. package/dist/space-sdk/src/ui/index.d.ts +54 -0
  220. package/dist/space-sdk/src/ui/keycap/Keycap.d.ts +22 -0
  221. package/dist/space-sdk/src/ui/keycap/index.d.ts +2 -0
  222. package/dist/space-sdk/src/ui/layout/Panels.d.ts +50 -0
  223. package/dist/space-sdk/src/ui/layout/chatPanelEdge.d.ts +77 -0
  224. package/dist/space-sdk/src/ui/layout/index.d.ts +5 -0
  225. package/dist/space-sdk/src/ui/layout/panelMath.d.ts +91 -0
  226. package/dist/space-sdk/src/ui/list/ListReader.d.ts +380 -0
  227. package/dist/space-sdk/src/ui/list/Row.d.ts +145 -0
  228. package/dist/space-sdk/src/ui/list/SelectionBar.d.ts +65 -0
  229. package/dist/space-sdk/src/ui/list/index.d.ts +14 -0
  230. package/dist/space-sdk/src/ui/list/rowState.d.ts +22 -0
  231. package/dist/space-sdk/src/ui/list/useListKeys.d.ts +89 -0
  232. package/dist/space-sdk/src/ui/list/useReorder.d.ts +86 -0
  233. package/dist/space-sdk/src/ui/list/useSelection.d.ts +90 -0
  234. package/dist/space-sdk/src/ui/open/OpenAsMenu.d.ts +15 -0
  235. package/dist/space-sdk/src/ui/open/index.d.ts +6 -0
  236. package/dist/space-sdk/src/ui/open/openModeStore.d.ts +39 -0
  237. package/dist/space-sdk/src/ui/open/useOpenMode.d.ts +17 -0
  238. package/dist/space-sdk/src/ui/overlay/Menu.d.ts +88 -0
  239. package/dist/space-sdk/src/ui/overlay/Popover.d.ts +28 -0
  240. package/dist/space-sdk/src/ui/overlay/Tooltip.d.ts +19 -0
  241. package/dist/space-sdk/src/ui/overlay/index.d.ts +9 -0
  242. package/dist/space-sdk/src/ui/overlay/layerRoot.d.ts +24 -0
  243. package/dist/space-sdk/src/ui/overlay/position.d.ts +31 -0
  244. package/dist/space-sdk/src/ui/period/PeriodPicker.d.ts +30 -0
  245. package/dist/space-sdk/src/ui/period/dateFormat.d.ts +50 -0
  246. package/dist/space-sdk/src/ui/period/dateWords.d.ts +88 -0
  247. package/dist/space-sdk/src/ui/period/periods.d.ts +70 -0
  248. package/dist/space-sdk/src/ui/period/usePeriod.d.ts +23 -0
  249. package/dist/space-sdk/src/ui/present/index.d.ts +3 -0
  250. package/dist/space-sdk/src/ui/present/presentWords.d.ts +27 -0
  251. package/dist/space-sdk/src/ui/present/screens.d.ts +36 -0
  252. package/dist/space-sdk/src/ui/present/useAudienceScreen.d.ts +38 -0
  253. package/dist/space-sdk/src/ui/styles.d.ts +21 -0
  254. package/dist/space-sdk/src/ui/timeline/TimelineView.d.ts +44 -0
  255. package/dist/space-sdk/src/ui/timeline/timelineMath.d.ts +123 -0
  256. package/dist/space-sdk/src/viewPeriod.d.ts +8 -0
  257. package/dist/space-sdk/src/vite.ts +92 -0
  258. package/dist/space-sdk/src/words/actions.ts +295 -0
  259. package/dist/space-sdk/src/words/clashes.ts +158 -0
  260. package/dist/space-sdk/src/words/format.ts +136 -0
  261. package/dist/space-sdk/src/words/index.ts +13 -0
  262. package/dist/space-sdk/src/words/keymap.ts +72 -0
  263. package/dist/space-sdk/src/words/keys.ts +297 -0
  264. package/dist/space-sdk/src/words/shell.ts +46 -0
  265. package/dist/space-sdk/src/words/types.ts +65 -0
  266. package/dist/view-renderer/dist/host.css +1 -0
  267. package/dist/view-renderer/dist/host.js +2374 -0
  268. package/dist/view-renderer/dist/theme.css +73 -0
  269. package/dist/view-renderer/src/dom.js +212 -0
  270. package/dist/view-renderer/src/errors.js +8 -0
  271. package/dist/view-renderer/src/host.tsx +250 -0
  272. package/dist/view-renderer/src/index.js +4 -0
  273. package/dist/view-renderer/src/png.js +213 -0
  274. package/dist/view-renderer/src/pool.js +110 -0
  275. package/dist/view-renderer/src/remote-broker.js +59 -0
  276. package/dist/view-renderer/src/renderer.js +279 -0
  277. package/package.json +21 -11
  278. package/skills/notis-cli/AGENT_INSTRUCTIONS.md +63 -12
  279. package/skills/notis-onboarding/BRIEF.md +14 -9
  280. package/skills/notis-query/cli.md +1 -1
  281. package/skills/notis-spaces/cli.md +540 -0
  282. package/src/cli.js +8 -8
  283. package/src/command-specs/agents.js +121 -8
  284. package/src/command-specs/auth.js +3 -3
  285. package/src/command-specs/diagnostics.js +97 -20
  286. package/src/command-specs/documents.js +158 -0
  287. package/src/command-specs/files.js +29 -0
  288. package/src/command-specs/handover.js +331 -79
  289. package/src/command-specs/helpers.js +50 -40
  290. package/src/command-specs/index.js +14 -5
  291. package/src/command-specs/meta.js +38 -9
  292. package/src/command-specs/onboarding.js +1 -1
  293. package/src/command-specs/profile.js +42 -1
  294. package/src/command-specs/skills.js +314 -9
  295. package/src/command-specs/smoke.js +16 -4
  296. package/src/command-specs/spaces.js +783 -0
  297. package/src/command-specs/tools.js +118 -21
  298. package/src/command-specs/version-history.js +20 -0
  299. package/src/command-specs/views.js +69 -0
  300. package/src/runtime/agent-browser.js +178 -267
  301. package/src/runtime/agent-setup.js +172 -13
  302. package/src/runtime/app-boundary-validator.js +338 -2
  303. package/src/runtime/app-data-literals.js +82 -0
  304. package/src/runtime/app-platform.js +750 -1570
  305. package/src/runtime/auth-recovery.js +17 -0
  306. package/src/runtime/base-skills.d.ts +11 -0
  307. package/src/runtime/base-skills.js +100 -3
  308. package/src/runtime/computer-identity.d.ts +30 -0
  309. package/src/runtime/computer-identity.js +151 -0
  310. package/src/runtime/config-lock.js +135 -0
  311. package/src/runtime/confined-space-build.js +74 -0
  312. package/src/runtime/confined-space-verify.js +49 -0
  313. package/src/runtime/delegated-context.js +5 -21
  314. package/src/runtime/native-record-files.js +47 -0
  315. package/src/runtime/oauth.js +342 -31
  316. package/src/runtime/profiles.js +19 -112
  317. package/src/runtime/retired-sdk-files.js +24 -0
  318. package/src/runtime/retry.js +150 -0
  319. package/src/runtime/skill-sync/cloud-client.ts +33 -8
  320. package/src/runtime/skill-sync/index.ts +443 -106
  321. package/src/runtime/skill-sync/local-scanner.ts +248 -32
  322. package/src/runtime/skill-sync/native-identity.ts +102 -0
  323. package/src/runtime/skill-sync/native-plan.ts +70 -0
  324. package/src/runtime/skill-sync/symlink-manager.ts +66 -16
  325. package/src/runtime/skill-sync/sync-plan.ts +34 -2
  326. package/src/runtime/skill-sync/types.ts +54 -0
  327. package/src/runtime/skill-sync/write-cloud-skill.ts +4 -4
  328. package/src/runtime/skill-sync-service.js +109 -0
  329. package/src/runtime/source-root.js +32 -0
  330. package/src/runtime/space-collection-scaffold.js +107 -0
  331. package/src/runtime/space-database-structures.js +229 -0
  332. package/src/runtime/space-fixture-broker.js +68 -0
  333. package/src/runtime/space-lock.js +337 -0
  334. package/src/runtime/space-platform.js +133 -0
  335. package/src/runtime/space-source.js +290 -0
  336. package/src/runtime/space-test-server.js +354 -0
  337. package/src/runtime/space-verification.js +94 -0
  338. package/src/runtime/space-verify-browser-worker.js +51 -0
  339. package/src/runtime/space-view-manifest.js +368 -0
  340. package/src/runtime/sync-skills.d.ts +5 -1
  341. package/src/runtime/sync-skills.js +11 -2
  342. package/src/runtime/tool-confirmation.js +138 -0
  343. package/src/runtime/transport.js +118 -24
  344. package/src/runtime/upsell.js +219 -0
  345. package/src/runtime/view-render.js +49 -0
  346. package/src/skill-sync-worker-entry.js +2 -0
  347. package/src/skill-sync-worker.js +114 -0
  348. package/src/space-harness-host.ts +122 -0
  349. package/template/.harness/index.html.tmpl +9 -352
  350. package/template/app/globals.css +29 -3
  351. package/template/app/layout.tsx +2 -6
  352. package/template/components/ui/badge.tsx +7 -4
  353. package/template/components/ui/button.tsx +1 -1
  354. package/template/components/ui/native-select.tsx +24 -0
  355. package/template/notis.config.ts +4 -36
  356. package/template/package-lock.json +1800 -1867
  357. package/template/package.json +16 -14
  358. package/template/postcss.config.mjs +1 -1
  359. package/template/tailwind.config.ts +1 -6
  360. package/template/tsconfig.json +1 -0
  361. package/template/vite.config.ts +2 -2
  362. package/dist/base-skills/notis-apps/SKILL.md +0 -613
  363. package/skills/notis-apps/cli.md +0 -285
  364. package/src/command-specs/apps.js +0 -3011
  365. package/src/runtime/app-changelog.js +0 -79
  366. package/src/runtime/app-dev-consumers.js +0 -154
  367. package/src/runtime/app-dev-host-lock.js +0 -80
  368. package/src/runtime/app-dev-process-identity.js +0 -111
  369. package/src/runtime/app-dev-roots.js +0 -284
  370. package/src/runtime/app-dev-server.js +0 -1140
  371. package/src/runtime/app-dev-sessions.js +0 -185
  372. package/src/runtime/app-registry-scaffolds.js +0 -367
  373. package/src/runtime/assets/store-screenshot-dark.png +0 -0
  374. package/src/runtime/cli-mode.generated.js +0 -5
  375. package/src/runtime/cli-mode.js +0 -34
  376. package/src/runtime/store-screenshot.js +0 -143
  377. package/template/CHANGELOG.md +0 -5
  378. package/template/app/page.tsx +0 -60
  379. package/template/components/ui/card.tsx +0 -56
  380. package/template/packages/sdk/src/components/DocumentEditor.tsx +0 -103
  381. package/template/packages/sdk/src/config.ts +0 -259
  382. package/template/packages/sdk/src/hooks/useCloudComputer.ts +0 -97
  383. package/template/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
  384. package/template/packages/sdk/src/hooks/useDocument.ts +0 -78
  385. package/template/packages/sdk/src/hooks/useNotisNavigation.ts +0 -52
  386. package/template/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
  387. package/template/packages/sdk/src/runtime.ts +0 -439
  388. package/template/packages/sdk/src/vite.ts +0 -56
  389. package/template/packages/sdk/tsconfig.json +0 -15
  390. /package/{template/packages → dist}/sdk/src/components/MultiSelectDragOverlay.tsx +0 -0
  391. /package/{template/packages → dist}/sdk/src/components/ShortcutHints.tsx +0 -0
  392. /package/{template/packages → dist}/sdk/src/hooks/useActiveResource.ts +0 -0
  393. /package/{template/packages → dist}/sdk/src/hooks/useTool.ts +0 -0
  394. /package/{template/packages → dist}/sdk/src/hooks/useTools.ts +0 -0
  395. /package/{template/packages → dist}/sdk/src/ui.ts +0 -0
@@ -0,0 +1,38 @@
1
+ import type { CSSProperties } from 'react';
2
+ import { useNotisRuntime } from '../provider';
3
+ import { pick, type Locale, type Words } from '../words/types';
4
+
5
+ /** What a loading placeholder says to screen readers. */
6
+ export const SKELETON_WORDS = Object.freeze({
7
+ loading: { en: 'Loading content', fr: 'Chargement du contenu' },
8
+ }) satisfies Readonly<Record<string, Words>>;
9
+
10
+ /** Content-shaped placeholder. Never use it to replace a successful cached result. */
11
+ export function Skeleton({ className, style }: { className?: string; style?: CSSProperties }) {
12
+ return <span aria-hidden="true" className={className} style={{ display: 'block', height: 16,
13
+ // Apps may define --muted as HSL channels or a complete CSS color. A
14
+ // neutral default remains visible with either token format and no theme.
15
+ borderRadius: 6, background: 'rgba(128,128,128,.18)', ...style }} />;
16
+ }
17
+
18
+ /** A whole view loading: a title bar and table, cards, graph or detail placeholders, named for screen readers in the Space's language. */
19
+ export function ViewSkeleton({ variant = 'table', rows = 5, label, locale }: {
20
+ variant?: 'table' | 'cards' | 'graph' | 'detail'; rows?: number;
21
+ /** What loads, said to screen readers ("Loading meetings"). Default "Loading content". */
22
+ label?: Words | string;
23
+ /** Default the Space's locale. */
24
+ locale?: Locale;
25
+ }) {
26
+ const runtimeLocale = useNotisRuntime()?.context?.locale;
27
+ const shown = locale ?? (runtimeLocale === 'fr' ? 'fr' : 'en');
28
+ return <div role="status" aria-label={pick(label ?? SKELETON_WORDS.loading, shown)} aria-busy="true" data-notis-content-skeleton
29
+ style={{ width: '100%', display: 'grid', gap: 16, padding: 24 }}>
30
+ <Skeleton style={{ width: '32%', height: 28 }} />
31
+ {variant === 'graph' ? <Skeleton style={{ height: 420 }} /> :
32
+ <div style={{ display: 'grid', gap: 12, gridTemplateColumns: variant === 'cards' ? 'repeat(auto-fit,minmax(180px,1fr))' : '1fr' }}>
33
+ {Array.from({ length: rows }, (_, index) => <Skeleton key={index}
34
+ style={{ height: variant === 'cards' ? 112 : variant === 'detail' ? 20 : 44,
35
+ width: variant === 'detail' && index === rows - 1 ? '65%' : '100%' }} />)}
36
+ </div>}
37
+ </div>;
38
+ }
@@ -0,0 +1,31 @@
1
+ export { defineSpace, defineSpaces } from './space';
2
+ export type { SpaceDefinition, SpacesWorkspace, SpaceActionTemplate, SpaceResourceReference, SpaceDatabaseCreate } from './space';
3
+ export type { SpaceViewParam, SpaceViewParamType, SpaceShows, SpaceMemoryPolicy, SpaceMemorySnapshot, SpaceChrome, SpaceMarkdownInput } from './space';
4
+
5
+ /**
6
+ * Configuration utilities for notis.config.ts and Space definitions.
7
+ *
8
+ * Usage:
9
+ * ```ts
10
+ * // notis.config.ts
11
+ * import { defineSpaces } from '@notis/sdk/config';
12
+ *
13
+ * export default defineSpaces({
14
+ * spaces: { notes: { definition: 'spaces/notes/space.config.ts' } },
15
+ * });
16
+ * ```
17
+ *
18
+ * Each definition file exports `defineSpace({ ... })`. `notis spaces build`
19
+ * reads only these two shapes.
20
+ */
21
+
22
+ /**
23
+ * Identity helper kept so older sources whose configuration files still import
24
+ * it keep loading and bundling. It accepts any object and returns it unchanged;
25
+ * `notis spaces build` never reads that shape.
26
+ *
27
+ * @deprecated Use `defineSpaces` for the workspace index and `defineSpace` for each Space.
28
+ */
29
+ export function defineNotisApp<T extends object>(config: T): T {
30
+ return config;
31
+ }
@@ -14,6 +14,17 @@ import type {
14
14
  DocumentRecord,
15
15
  SecretPropertyValue,
16
16
  } from './runtime';
17
+ import { pick, type Locale, type Words } from './words/types';
18
+
19
+ /** The words the document helpers fall back on. */
20
+ export const DOCUMENT_WORDS = Object.freeze({
21
+ untitled: { en: 'Untitled', fr: 'Sans titre' },
22
+ }) satisfies Readonly<Record<string, Words>>;
23
+
24
+ /** The locale of the fallback words ("Untitled"). Default English; the SDK hooks pass the Space's locale. */
25
+ export interface DocumentWordsOptions {
26
+ locale?: Locale;
27
+ }
17
28
 
18
29
  // ---------------------------------------------------------------------------
19
30
  // Value primitives
@@ -113,9 +124,10 @@ function normalizeContentType(value: unknown): DocumentContentType | null {
113
124
  /**
114
125
  * Normalizes a raw document from a Notis database tool result
115
126
  * (LOCAL_NOTIS_DATABASE_QUERY / GET_DOCUMENT / UPSERT_*) into a
116
- * `DocumentRecord`: camelCases fields and collapses property values.
127
+ * `DocumentRecord`: camelCases fields and collapses property values. A
128
+ * document with no title is titled "Untitled" in `options.locale`.
117
129
  */
118
- export function normalizeDocumentRecord(value: unknown): DocumentRecord {
130
+ export function normalizeDocumentRecord(value: unknown, options: DocumentWordsOptions = {}): DocumentRecord {
119
131
  const record = asRecord(value) ?? {};
120
132
  const rawProperties = asRecord(record.properties) ?? {};
121
133
  const properties: Record<string, unknown> = {};
@@ -125,7 +137,9 @@ export function normalizeDocumentRecord(value: unknown): DocumentRecord {
125
137
 
126
138
  return {
127
139
  id: optionalString(record.id) ?? '',
128
- title: optionalString(record.title) ?? 'Untitled',
140
+ recordKey: optionalString(record.recordKey) ?? optionalString(record.record_key) ?? undefined,
141
+ revision: typeof record.revision === 'number' ? record.revision : undefined,
142
+ title: optionalString(record.title) ?? pick(DOCUMENT_WORDS.untitled, options.locale ?? 'en'),
129
143
  url: optionalString(record.url),
130
144
  properties,
131
145
  icon: optionalString(record.icon),
@@ -241,9 +255,10 @@ export function blockNoteToPlainText(blocks: unknown): string {
241
255
 
242
256
  /**
243
257
  * Best-available plain-text preview for a document:
244
- * plainText -> contentMarkdown -> contentBlocknote -> title.
258
+ * plainText -> contentMarkdown -> contentBlocknote -> title, else "Untitled"
259
+ * in `options.locale`.
245
260
  */
246
- export function getDocumentPreview(document: DocumentRecord): string {
261
+ export function getDocumentPreview(document: DocumentRecord, options: DocumentWordsOptions = {}): string {
247
262
  if (isPresentString(document.plainText)) {
248
263
  return document.plainText.replace(/\s+/g, ' ').trim();
249
264
  }
@@ -252,5 +267,5 @@ export function getDocumentPreview(document: DocumentRecord): string {
252
267
  }
253
268
  const fromBlocks = blockNoteToPlainText(document.contentBlocknote);
254
269
  if (fromBlocks) return fromBlocks;
255
- return isPresentString(document.title) ? document.title : 'Untitled';
270
+ return isPresentString(document.title) ? document.title : pick(DOCUMENT_WORDS.untitled, options.locale ?? 'en');
256
271
  }
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useState } from 'react';
4
+ import { useNotisRuntime } from '../provider';
5
+ import { useQuery, type UseQueryOptions, type UseQueryResult } from './useQuery';
6
+ import type { SpaceActionOptions } from '../space';
7
+
8
+ export function useAction<TInput extends Record<string, unknown> = Record<string, unknown>, TResult = unknown>(actionId: string): {
9
+ call: (inputs: TInput, options?: SpaceActionOptions) => Promise<TResult>; loading: boolean; error: Error | null;
10
+ } {
11
+ const runtime = useNotisRuntime();
12
+ const [pending, setPending] = useState(0);
13
+ const [error, setError] = useState<Error | null>(null);
14
+ const call = useCallback(async (inputs: TInput, options?: SpaceActionOptions) => {
15
+ if (runtime?.resource?.kind !== 'space' || !runtime.callAction) throw new Error('A Space action runtime is required.');
16
+ setPending((value) => value + 1); setError(null);
17
+ try { return await runtime.callAction<TResult>(actionId, inputs, options); }
18
+ catch (cause) { const failure = cause instanceof Error ? cause : new Error(String(cause)); setError(failure); throw failure; }
19
+ finally { setPending((value) => value - 1); }
20
+ }, [runtime, actionId]);
21
+ return { call, loading: pending > 0, error };
22
+ }
23
+
24
+ export function useActionQuery<TResult = unknown>(actionId: string, inputs: Record<string, unknown>,
25
+ options: UseQueryOptions = { readOnly: true }): UseQueryResult<TResult> {
26
+ const { call } = useAction<Record<string, unknown>, TResult>(actionId);
27
+ return useQuery(['action', actionId, inputs], () => call(inputs, { readOnly: true, dedupe: true }), options);
28
+ }
@@ -0,0 +1,23 @@
1
+ 'use client';
2
+ import { useMemo } from 'react';
3
+ import { useNotisRuntime } from '../provider';
4
+ import type { AgentContextItem } from '../agentContext';
5
+
6
+ /** Share context without owning storage, opening a new thread, or sending a message. */
7
+ export function useAgentContext() {
8
+ const runtime = useNotisRuntime();
9
+ return useMemo(() => ({
10
+ add(item: AgentContextItem): Promise<boolean> {
11
+ if (!runtime?.addContext) return Promise.reject(new Error('Chat context is unavailable in this host.'));
12
+ return runtime.addContext(item);
13
+ },
14
+ update(item: AgentContextItem): Promise<boolean> {
15
+ if (!runtime?.updateContext) return Promise.reject(new Error('Chat context is unavailable in this host.'));
16
+ return runtime.updateContext(item);
17
+ },
18
+ remove(id: string): Promise<boolean> {
19
+ if (!runtime?.removeContext) return Promise.reject(new Error('Chat context is unavailable in this host.'));
20
+ return runtime.removeContext(id);
21
+ },
22
+ }), [runtime]);
23
+ }
@@ -6,7 +6,7 @@ import { useNotisRuntime } from '../provider';
6
6
  interface UseBackendResult {
7
7
  /**
8
8
  * Make an authenticated request to the Notis backend.
9
- * The path should be an absolute backend path (e.g. `/portal_composio/actions`).
9
+ * The path should be an absolute backend path (e.g. `/portal_composio/toolkits`).
10
10
  */
11
11
  request: (path: string, options?: {
12
12
  method?: string;
@@ -18,10 +18,11 @@ interface UseBackendResult {
18
18
  /**
19
19
  * Raw backend request proxy. Use this for custom server endpoints or
20
20
  * integration APIs not covered by the typed hooks.
21
+ * Spaces deny raw requests; use useAction or useActionQuery for declared actions.
21
22
  *
22
23
  * ```tsx
23
24
  * const { request } = useBackend();
24
- * const data = await request('/portal_composio/actions', { method: 'POST', body: { ... } });
25
+ * const data = await request('/portal_composio/toolkits', { method: 'GET' });
25
26
  * ```
26
27
  */
27
28
  export function useBackend(): UseBackendResult {
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useRef } from 'react';
4
+ import { useQuery } from './useQuery';
5
+ import { useNotisRuntime } from '../provider';
6
+ import { queryKey } from '../queryCache';
7
+ import { spaceQueryKey } from '../space';
8
+ import type { CloudComputerFacts, NotisRuntime } from '../runtime';
9
+
10
+ /** Cache key of the facts read; re-read once the viewer allows a Space to use the cloud computer. */
11
+ export const CLOUD_COMPUTER_FACTS_KEY = ['cloud-computer-facts'] as const;
12
+
13
+ /** Marks the facts stale in the host cache so every mounted `useCloudComputer()` reads them again. */
14
+ export function invalidateCloudComputerFacts(runtime: NotisRuntime | null): void {
15
+ try {
16
+ runtime?.queryClient?.invalidate(queryKey(spaceQueryKey(runtime, CLOUD_COMPUTER_FACTS_KEY)));
17
+ } catch {
18
+ // A host without a Space access context has no shared facts cache to refresh.
19
+ }
20
+ }
21
+
22
+ export interface UseCloudComputerResult {
23
+ /**
24
+ * The facts, or null while the first read is in flight. `facts.available`
25
+ * is false when this host cannot answer — render the app's own fallback.
26
+ */
27
+ facts: CloudComputerFacts | null;
28
+ loading: boolean;
29
+ isFetching: boolean;
30
+ error: Error | null;
31
+ /** Re-read the facts. The platform caches them for a few minutes. */
32
+ refresh: () => Promise<void>;
33
+ /**
34
+ * Space only (`cloudComputer: 'read'` or `'shell'`): ask the host to show its approval prompt.
35
+ * Resolves true once the viewer allowed it (the facts are then read again), false when they did
36
+ * not, and null on hosts without the prompt (Beta Apps, Sites, previews offline).
37
+ */
38
+ requestApproval: () => Promise<boolean | null>;
39
+ }
40
+
41
+ const UNAVAILABLE: CloudComputerFacts = {
42
+ available: false,
43
+ reason: 'unsupported_host',
44
+ sandbox: null,
45
+ cli_auth: {
46
+ gh: { authenticated: null, account: null, checked_at: null, reason: 'unsupported_host' },
47
+ },
48
+ };
49
+
50
+ /**
51
+ * Read-only facts about the user's cloud computer.
52
+ *
53
+ * ```tsx
54
+ * const { facts } = useCloudComputer();
55
+ * const gh = facts?.available ? facts.cli_auth.gh : null;
56
+ *
57
+ * return gh?.authenticated
58
+ * ? <p>Signed in as {gh.account}</p>
59
+ * : <GithubConnect />;
60
+ * ```
61
+ *
62
+ * Requires `cloudComputer: 'read'` (or `'shell'`) in `defineSpace` and the
63
+ * viewer's approval; until the viewer allows it the facts answer
64
+ * unavailable, so offer `requestApproval()`. It answers with state the platform already
65
+ * holds: reading it never creates, resumes or commands a sandbox, and the GitHub
66
+ * probe only runs when the sandbox is already awake. `authenticated: null`
67
+ * therefore means *unknown*, not *signed out* — keep the app's own fallback for
68
+ * that case and for hosts that answer `{ available: false }` (the dev harness,
69
+ * the vite preview).
70
+ */
71
+ export function useCloudComputer(): UseCloudComputerResult {
72
+ const runtime = useNotisRuntime();
73
+ const explicitRefresh = useRef(false);
74
+ const query = useQuery<CloudComputerFacts>(CLOUD_COMPUTER_FACTS_KEY, async () => {
75
+ const refresh = explicitRefresh.current;
76
+ explicitRefresh.current = false;
77
+ return runtime?.cloudComputerFacts ? runtime.cloudComputerFacts(refresh ? { refresh: true } : undefined) : UNAVAILABLE;
78
+ }, { readOnly: true });
79
+ const refresh = useCallback(async () => {
80
+ explicitRefresh.current = true;
81
+ await query.refetch();
82
+ }, [query.refetch]);
83
+ const transport = runtime?.spaceCloudComputer;
84
+ const requestApproval = useCallback(async () => {
85
+ if (!transport) return null;
86
+ const status = await transport.requestApproval();
87
+ if (status?.approved !== true) return false;
88
+ invalidateCloudComputerFacts(runtime);
89
+ await query.refetch();
90
+ return true;
91
+ }, [query.refetch, runtime, transport]);
92
+ return { facts: query.data ?? (query.error ? UNAVAILABLE : null), loading: query.loading,
93
+ isFetching: query.isFetching, error: query.error, refresh, requestApproval };
94
+ }
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { useNotisRuntime } from '../provider';
5
+ import { invalidateCloudComputerFacts } from './useCloudComputer';
6
+ import type {
7
+ SpaceCloudComputerLevel,
8
+ SpaceCloudComputerRunResult,
9
+ SpaceCloudComputerStatus,
10
+ SpaceCloudComputerUploadInput,
11
+ SpaceCloudComputerUploadResult,
12
+ } from '../space';
13
+
14
+ export interface UseCloudComputerShellResult {
15
+ /**
16
+ * The level this Space declares (`'read'` or `'shell'`) when this host offers the cloud computer,
17
+ * else null (Sites, links, verification harnesses, older hosts): keep the page's own fallback.
18
+ */
19
+ level: SpaceCloudComputerLevel | null;
20
+ /** True when `run` and `upload` are offered: the host offers the cloud computer and the Space declares `'shell'`. */
21
+ available: boolean;
22
+ /** The viewer's approval for this Space's current code (either level), or null while it is read. */
23
+ status: SpaceCloudComputerStatus | null;
24
+ approved: boolean;
25
+ loading: boolean;
26
+ /**
27
+ * Run one non-interactive command on the viewer's own cloud computer. Same result as the shell tool.
28
+ * Pass the same `requestId` when the page retries this run itself: a run is never repeated for one key.
29
+ */
30
+ run(command: string, options?: RunOptions): Promise<SpaceCloudComputerRunResult>;
31
+ /** Write one file (at most 1 MiB) straight to the cloud computer; it never travels by URL or chat. */
32
+ upload(file: SpaceCloudComputerUploadInput): Promise<SpaceCloudComputerUploadResult>;
33
+ /**
34
+ * Ask the host to show its approval prompt, for either declared level. Only the person's click in
35
+ * that prompt approves; once allowed, every `useCloudComputer()` reads the facts again.
36
+ */
37
+ requestApproval(): Promise<SpaceCloudComputerStatus | null>;
38
+ refresh(): Promise<void>;
39
+ }
40
+
41
+ type RunOptions = { cwd?: string; timeoutMs?: number; maxOutputLength?: number; requestId?: string };
42
+
43
+ const unavailable = async (): Promise<never> => {
44
+ throw new Error('The cloud computer is not available in this Space.');
45
+ };
46
+
47
+ /**
48
+ * The viewer's approval and, for `cloudComputer: 'shell'`, commands and file writes on the signed-in
49
+ * viewer's own cloud computer, from a Space page.
50
+ *
51
+ * ```tsx
52
+ * const shell = useCloudComputerShell();
53
+ * if (!shell.level) return <AskNotisFallback />;
54
+ * if (!shell.approved) return <Button onClick={() => shell.requestApproval()}>Allow</Button>;
55
+ * const result = await shell.run(`bash ${SCRIPTS}/workspace.sh sync ${quote(repo)} ${quote(name)}`);
56
+ * ```
57
+ *
58
+ * Requires `cloudComputer` in `defineSpace` and the viewer's approval, which the Portal asks for in
59
+ * its own prompt and which covers only the exact code the viewer allowed: any new release asks again.
60
+ */
61
+ export function useCloudComputerShell(): UseCloudComputerShellResult {
62
+ const runtime = useNotisRuntime();
63
+ const transport = runtime?.spaceCloudComputer;
64
+ const declared = runtime?.space?.cloudComputer;
65
+ const level: SpaceCloudComputerLevel | null = transport && (declared === 'read' || declared === 'shell') ? declared : null;
66
+ const available = level === 'shell';
67
+ const [status, setStatus] = useState<SpaceCloudComputerStatus | null>(null);
68
+ const [loading, setLoading] = useState(Boolean(level));
69
+ const mounted = useRef(true);
70
+ useEffect(() => () => { mounted.current = false; }, []);
71
+
72
+ const refresh = useCallback(async () => {
73
+ if (!level || !transport) return;
74
+ setLoading(true);
75
+ try {
76
+ const next = await transport.status();
77
+ if (mounted.current) setStatus(next);
78
+ } catch {
79
+ if (mounted.current) setStatus(null);
80
+ } finally {
81
+ if (mounted.current) setLoading(false);
82
+ }
83
+ }, [level, transport]);
84
+
85
+ useEffect(() => {
86
+ mounted.current = true;
87
+ void refresh();
88
+ }, [refresh]);
89
+
90
+ const run = useCallback(async (command: string, options: RunOptions = {}) => {
91
+ if (!available || !transport) return unavailable();
92
+ return transport.run({ command, ...(options.cwd ? { cwd: options.cwd } : {}),
93
+ ...(options.timeoutMs ? { timeout_ms: options.timeoutMs } : {}),
94
+ ...(options.maxOutputLength ? { max_output_length: options.maxOutputLength } : {}),
95
+ ...(options.requestId ? { request_id: options.requestId } : {}) });
96
+ }, [available, transport]);
97
+
98
+ const upload = useCallback(async (file: SpaceCloudComputerUploadInput) => {
99
+ if (!available || !transport) return unavailable();
100
+ return transport.upload(file);
101
+ }, [available, transport]);
102
+
103
+ const requestApproval = useCallback(async () => {
104
+ if (!level || !transport) return null;
105
+ const next = await transport.requestApproval();
106
+ if (mounted.current) setStatus(next);
107
+ // A facts read refused before the approval must not keep showing "unavailable".
108
+ if (next?.approved === true) invalidateCloudComputerFacts(runtime);
109
+ return next;
110
+ }, [level, runtime, transport]);
111
+
112
+ return { level, available, status, approved: status?.approved === true, loading: Boolean(level) && loading,
113
+ run, upload, requestApproval, refresh };
114
+ }