@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,273 @@
1
+ # SDK reference for Space views
2
+
3
+ For offline verification, read [the fixture contract](fixtures.md) before
4
+ creating a `verificationFixtures` file. That short reference contains the exact
5
+ list-case format and every required initial-read fixture.
6
+
7
+ | Import | Holds |
8
+ | --- | --- |
9
+ | `@notis/sdk` | Data hooks, navigation, host interactions and record components |
10
+ | `@notis/sdk/ui` | The toolkit pieces and their hooks |
11
+ | `@notis/sdk/config` | `defineSpace` and view declarations |
12
+ | `@notis/sdk/words` | Pure action ids, EN and FR words and key specs |
13
+
14
+ `@notis/sdk` and `@notis/sdk/ui` are provided live by the host: never vendor,
15
+ copy or deep-import them (`@notis/sdk/src/...`), and never import the toolkit
16
+ stylesheet; the host adopts it. The host runtime is scoped: source never owns an
17
+ account credential or backend transport.
18
+
19
+ For a toolkit select, import `NativeSelect` from `@notis/sdk/ui` and pass
20
+ `options={[{value: 'all', label: {en: 'All', fr: 'Tous'}}]}`, `value`,
21
+ `onChange={value => ...}` and an accessible `label`. Its callback receives the
22
+ selected string, not a DOM event; its options come from `options`, not child
23
+ `<option>` elements. Keep the visible field label in the surrounding layout.
24
+
25
+ ## Records and declared reads
26
+
27
+ | API | Use |
28
+ | --- | --- |
29
+ | `useViewParams<typeof definition>()` | `{params, invalid, missing, declared, ready, setParams}` for declared typed URL params. Unknown names are dropped; invalid values use their declared default. `setParams(changes, {replace?})` changes this view's own params (`null` removes one) and keeps the same Space and record open. |
30
+ | `useShown<Row>(name, options?)` | Execute the native list in `shows[name]` with current params. Options: `sorts`, `pageSize`, `offset`, `includeContent`, `allPages` (every page, for a whole count or a local search); rows are in `data?.rows` and the schema revision a write needs in `data?.schema_revision`, with `loading`, `hasData`, `isFetching`, `error`, `refetch` (resolves to the read's error, or null when it succeeded; it never rejects). |
31
+ | `useShownAvailable(name)` | Check whether this host exposes the declared native list. A record Site can expose only its exact server-pinned row scope. |
32
+ | `useAction<Inputs, Result>(name)` / `useActionQuery<Result>(name, inputs)` | Call a declared action (`call(inputs, options)`); read the result of a declared read action. Never call account-wide tools from a Space. |
33
+ | `useNativeMutation(binding, operation)` | Insert, update or delete one row of a linked database through the action that declares `LOCAL_NOTIS_DATABASE_INSERT`, `_UPDATE` or `_DELETE` on that binding with `request: { $input: 'request' }`. `mutate(input, {schemaRevision, requestId})` returns the receipt (`record_key`, `revision`); a delete moves the record to the bin, leaves every list at once and comes back if the write fails. One new request ID per effect. An insert action takes no `content_markdown`: insert, then save the body with `useNativeDocumentBody` and the record's revision. |
34
+ | `useNativeDelete(binding)` | Trash many rows of one linked database (a deck and its slides, a multi-select). `deleteMany(inputs, {schemaRevision, requestId})` hides every row from the lists at once, runs the writes a few at a time, each with the request ID `${requestId}:${record_key}` (a retry with the same `requestId` replays instead of trashing twice), refreshes the lists once at the end and brings back the rows whose write failed. It never throws for a failed row: it resolves to `{done, failed}`; say how many failed. Use it rather than a loop of `mutate`. |
35
+ | `useNativeDocumentBody(binding, recordKey, {readAction, writeAction?, enabled?})` | Markdown body adapter. Keep drafts in the view; save with the original content, record/schema revisions and stable request ID. Rich editing normally uses `DocumentEditor`. |
36
+ | `useNotis()` | Host resource, Space labels, route and ready state. Use `resource.id` for the current Space identity. |
37
+
38
+ Keep hooks unconditional. `loading` means no first successful read;
39
+ `isFetching` includes a silent refresh. Do not copy rows into mount-only state
40
+ or clear them on error ([loading rules](design.md#loading-empty-and-error)).
41
+ `Skeleton` and `ViewSkeleton` come from `@notis/sdk`; `ViewSkeleton`'s `label`
42
+ names what loads (`{ en: 'Loading meetings', fr: 'Chargement des réunions' }`),
43
+ said in the Space's language, default Loading content.
44
+
45
+ For another explicitly idempotent read use `useActionQuery`, or
46
+ `useQuery(keyArray, readCallback, { readOnly: true })` with every input in the
47
+ key. Call declared read actions inside a custom read with
48
+ `{ readOnly: true, dedupe: true }`; never mark a whole tool family read-only.
49
+ `useQueryClient().prefetch(...)` with the exact foreground key prepares a small
50
+ known read after render or on hover; never prefetch a write, a polling action or
51
+ a fan-out aggregate. The host keeps one in-memory cache per account, Space,
52
+ version and permission; do not add module-global or `localStorage` caches of
53
+ user data.
54
+
55
+ ## First-party record components
56
+
57
+ | Component | Contract |
58
+ | --- | --- |
59
+ | `<DocumentPage recordKey>` | A record as the view's main content: save state, menu, cover, icon, title, meta, properties that save automatically, collaborative body. Slots `breadcrumb`, `actions`, `menuItems`, `aboveBody`, `belowBody`; toggles `share` (off by default, never for a report record), `header`, `meta`, `properties`, `width` (`standard` 900 px centred column by default, `wide` 1200 px, `full`); `viewer: 'html'` shows a record whose one stored `.html` file is the page; `onSaved`; `layout`. Pair with `DocumentPageSkeleton` and `usePrefetchRecord()`. It is the usual `reader` slot of `ListReader`; there it takes no `breadcrumb`, because the top bar crumb already names the open record. A page with a `breadcrumb` (a record opened from the view) names the top bar crumb leaf with its title itself; `topBarTitle` overrides that, and `onTitle` hears the title. |
60
+ | `<DocumentEditor recordKey>` | Native collaborative body, properties, images and attachments. With separate properties use `showProperties={false}`. |
61
+ | `<RecordProperties recordKey>` | Native revision-checked property editing. |
62
+ | `<HtmlFrame recordKey>` | Attached HTML under viewer CSP and an opaque-origin sandbox. Source cannot relax that boundary. `onReady` is called once per page after it has loaded and painted, or when the record cannot load: keep a slide hidden until then instead of showing a half-drawn page. `presentation={{ onAction }}` turns the pointer into a laser dot inside the page, keeps its buttons and links clickable, and hands the presenter's keys and plain clicks back as `next`, `previous`, `first`, `last` or `stop`; the page can send the same actions, so treat them as navigation only. |
63
+ | `<ReportFrame recordKey>` | A report row's saved independent implementation in its database's current view. |
64
+ | `<ShareControl recordKey>` | Private/shared record Site, copy link and revoke. |
65
+ | `<SpacePageFrame href>` | Another Notis Space page, live in this view: `href` is a Notis link (a path or a full link of this origin, such as a Page property). The Portal shows only that page's view (no sidebar, top bar or chat) with the viewer's own session and permissions. `interactive` (default `false`) lets it take clicks and keys; off, the view around it (a deck's arrows and swipes) keeps them. `title`, `className` (sizes the box it fills). Any other link, and every verify or build preview, shows a card with the title, the path and Open page. |
66
+
67
+ In its own Space's view, a record's Site is a row of the top bar Share panel, not
68
+ a toolbar button. The published Space declares the database binding; the server
69
+ rechecks record scope and binding revision. A Site exposes read-only body and
70
+ property snapshots and HTML for its pinned record, including a declared
71
+ non-collection record param. A report row cannot be shared as a Site; a report
72
+ saved as an HTML file can. A Site has no upload, collaboration credential,
73
+ authoring controls or sharing mutation. No credentials or filesystem URLs belong
74
+ in component props.
75
+
76
+ ## Toolkit pieces
77
+
78
+ From `@notis/sdk/ui`. Their props live in the piece types; read them there
79
+ rather than from a copy.
80
+
81
+ - **Lists**: `ListReader`, `Row`, `TabRow`, `SelectionBar`, `Panels`,
82
+ `OpenAsMenu`, `Keycap`. `ListReader` draws the whole list chrome from props:
83
+ `search` (the host top bar field), `tabs` (pills in one 44px row), `title`
84
+ (a short status with its count at the start of that row, such as "23 to
85
+ triage"), `create` (the "+" at its end), `viewMenu`, `infoLine`,
86
+ `readerLabel` and `readerActions` (the reader bar), `crumbLabel` (the open
87
+ item in the top bar crumb), `onOpenChange(id, reason)` (`reason` is `user`,
88
+ `auto` for a move the list makes itself, or `url`), `renderTile` (tiles), `look` (`two-tone` keeps
89
+ the list tinted) and `autoOpen` (opens the first item). It has no toolbar or
90
+ header slot. `Row` takes `wrap` (title lines) and `now` (a fixed clock for
91
+ relative times). Drag to select is automatic on a list that selects several
92
+ (`selectable` or a bulk action): a drag from empty space selects the rows
93
+ under it, as in the Manager; `dragSelect={false}` turns it off. Reorder is
94
+ off until the view passes `reorder={{ onReorder, canReorder }}`: a row then
95
+ drags with a line where it lands, or moves with Alt and an arrow key (Alt
96
+ with Home or End for the ends), and screen readers hear its new place.
97
+ `onReorder({ item, id, from, to, ids })` gets the moved item, its new index
98
+ and the whole new order; save `ids` in the view's own order (a position
99
+ property, for example). The list shows the new order at once and puts the
100
+ old one back with an error toast if the promise rejects. Pending and
101
+ disabled rows, and rows `canReorder` refuses, do not move; reorder is off
102
+ while `search` filters or `groupBy` groups. For a strip of your own (slide
103
+ thumbnails, a rail), `useReorder({ items, getId, onReorder, orientation })`
104
+ gives the ordered `items`, `getItemProps(id)` for each element and an
105
+ `announcer` to render once.
106
+ - **Boards**: `BoardView` is a Kanban board (a funnel, a pipeline): one
107
+ column per stage (`columns`, each `{ id, label, tone? }`, with `getColumn`
108
+ saying where an item sits) and a tile per item (`renderTile`, the same
109
+ `TileParts` as tiles). It is `ListReader` underneath, so `reader`, the open
110
+ modes, `actions`, selection and `search` work the same; a tile opens on
111
+ Enter or a click and nothing opens on its own. `onMove(ids, toColumnId,
112
+ index?)` moves tiles by drag and drop, Shift+Left/Right and M (Move to):
113
+ update the items in the page (optimistically if you like) and return an
114
+ undo function for Undo in the toast. Leave `onMove` out for a board that
115
+ only reads. Use it rather than columns of your own.
116
+ - **Time and numbers**: `PeriodPicker` with `usePeriod`, `DayPicker`,
117
+ `CalendarView`, `TimelineView`, `Chart`, `StatRow`, `ChartTable`,
118
+ `RenderChartData`. `Chart` stacks bars or areas (`stacked`) and runs bars
119
+ left to right (`horizontal`): each label on up to two lines before its bar
120
+ in a measured axis, and its value after it; `labelFormat` gives that short
121
+ value ("1.2k") while `format` stays the exact tooltip and table text. Draw
122
+ category bars this way rather than with your own recharts. For a chart of
123
+ your own, `ChartContainer` takes `aspect` or `height`; `ChartTooltipContent`
124
+ and `ChartLegend` also work outside it; `<Bar shape={barShape}
125
+ label={{ content: barLabel }} />` keeps zero bars and their value labels. A
126
+ sparkline `null` is a gap. `PeriodPicker` without the `custom` preset offers
127
+ presets only.
128
+ - **Floating**: `Menu`, `Popover`, `Tooltip`.
129
+ - **Files and pictures**: `AttachmentGallery` and `ImageViewer`, the ones
130
+ Notis conversations use. `AttachmentGallery` draws a row of file cards
131
+ (`items`: `url`, `name`, `type` or `kind`, `size`, `thumbnailUrl`); an
132
+ image card opens `ImageViewer` on the gallery's images (zoom, pan, arrows,
133
+ copy, download, Escape), and any other card goes to `onOpen` (a new tab by
134
+ default). `renderOpener` swaps a card's opener, `itemAction` adds a corner
135
+ button, `viewerActions` adds viewer buttons (class `nui-viewer-btn`) and
136
+ `onNotice` hears copy and download results. Use `ImageViewer` alone for a
137
+ picture that opens full screen. Do not build your own lightbox.
138
+ - **Presenting on a second screen**: `useAudienceScreen({ onAction, onClose,
139
+ title })` works like PowerPoint. `secondScreen` says whether another screen
140
+ is connected; call `open(anchor)` from the Present press itself. It answers
141
+ `opened` (the audience window is on the other screen), `one-screen` (present
142
+ full screen in this window, as before), `press-again` (the browser just asked
143
+ for permission and used up the press: show `PRESENT_WORDS.pressAgain`) or
144
+ `blocked` (pop-ups blocked: show `PRESENT_WORDS.blocked`). Render the
145
+ audience view with `portal(<Slide ... />)` from the same component, so both
146
+ windows share one state: the current slide, next and previous, and a
147
+ presented `HtmlFrame`'s laser all stay in sync. Keys, clicks and right clicks
148
+ in the audience window come back through `onAction` (`next`, `previous`,
149
+ `first`, `last`, `stop`); the presenter window keeps the normal view (notes,
150
+ previews, a timer). The browser asks once to place windows on screens; the
151
+ desktop app never asks. Leaving the view closes the audience window.
152
+ - **Blocks**: `Section`, `Badge`, `Button`, `ToggleGroup`, `SegmentedControl`,
153
+ `NativeSelect`, `EmptyState`, `Notice`, `Metric`. A page is a stack of
154
+ `Section`s, full width and without boxes: `kind` is `bar` (period and
155
+ filters), `stats`, `chart`, `data` (a table) or `form`, and its head takes
156
+ `title`, `count`, `meta`, `tabs` and `actions`. There is no page heading and
157
+ no card: the host top bar shows the title. One toggle is a `Button` with
158
+ `pressed`; several with any number on (filters, chart series) are a
159
+ `ToggleGroup`; tabs and filters over a whole list or section are pills
160
+ (`TabRow`); a `SegmentedControl` is only a mode switch inside a section.
161
+ A `Notice` is read politely, danger too; pass `urgent` only for a problem the
162
+ person must act on now (it becomes an alert that interrupts the screen reader).
163
+ - **Fields**: `EditableFields` (a form; Save and Cancel show once something
164
+ changed) or `FieldList` (the same rows without them) around `FieldRow`s holding
165
+ `FieldText`, `FieldLongText`, `FieldSelect`, `FieldMultiSelect` (`searchable`
166
+ for a long list, `onAdd` to add the typed text as an option) or
167
+ `FieldDisclosure` (its summary, such as a `formatLongDay` date, wraps in a
168
+ narrow reader). A row's `hint` describes its control; `invalid` reads the
169
+ hint as the error. Their rules ship in the toolkit styles: draw no `<style>`.
170
+ - **Hooks for your own layout**: `useListKeys` and `useSelection` (list keys and
171
+ selection), `useShortcut` (a key at route scope or below), `usePanels` (split
172
+ or stacked), `useOpenMode`, `useActions` (standard and own actions),
173
+ `useLayerRoot` (container for anything floating), `useEscapeLayer`.
174
+
175
+ A standard action is an id (`archive`, `complete`, `star`, `later`, `move`,
176
+ `assign`, `read`, `delete`...) plus `run`; without `run` it is hidden. The standard
177
+ `delete` hides its records from the lists while `run` works, keeps hidden the
178
+ ones it removed and brings back the ones in `failed` (or all of them when `run`
179
+ throws, and on Undo): return `{ failed }` rather than refetching yourself. An own
180
+ action is `{ id, label: { en, fr }, icon?, key?, tone?, bulk?, appliesTo?, run }`.
181
+ A standard id with a `label` keeps its key, icon and toast: `unarchive` reads
182
+ Move to triage, and a Space whose first stop has a name passes
183
+ `{ id: 'unarchive', label: { en: 'Move to Inbox', fr: 'Remettre dans la boîte' } }`.
184
+
185
+ A status maps to one of ten groups (`backlog`, `todo`, `active`, `review`,
186
+ `waiting`, `done`, `cancelled`, `failed`, and `up`/`down` for a service), each
187
+ with its icon, words and the one status palette: pass the Space's own status to
188
+ `Row` or `StatusIcon` (with `label` for its own name), never a colour.
189
+
190
+ ## Navigation
191
+
192
+ `useNotisNavigation()` exposes `toSpace(spaceId, {recordKey?, params?})` and
193
+ `toNamedSpace(alias, {recordKey?, params?})`. Both return a promise that settles
194
+ once the host has taken the navigation and rejects when the host refuses it:
195
+ `await` it (or `void` it in a click handler). Prefer declared portable navigation
196
+ aliases for sibling destinations; the host resolves them under current access.
197
+ Use declared params for view state, for example `{params: {project: key, period: 'week'}}`.
198
+ The destination drops unknown params and authorizes referenced records. Changing
199
+ a slug cannot change identity. Agents cite current server-returned links.
200
+
201
+ To change the open view's own params (an open item, a tab, a filter), call
202
+ `useViewParams().setParams({open: key})` instead of navigating to the same Space:
203
+ there is no alias to declare and no destination request, and each call adds a
204
+ history entry unless you pass `{replace: true}`. `ListReader` with `openParam` and
205
+ `usePeriod` already write this way.
206
+
207
+ ## Viewer-only exploration
208
+
209
+ `viewerReads: ['databases', 'skills']` permits read-only inspection of what the
210
+ signed-in viewer already reaches. It creates no shared grant. Use
211
+ `useViewerReadAvailable(family)`, `useViewerDatabases`, `useViewerSkills`, or
212
+ `useViewerRead(operation, input)`. Anonymous Sites cannot use these families.
213
+ Explicit synthetic `viewerReads` fixtures stand in for the viewer's reads offline.
214
+
215
+ ## The viewer's cloud computer
216
+
217
+ `cloudComputer: 'shell'` (or `'read'` for facts only) lets a page run one command
218
+ or write one file on the signed-in viewer's own cloud computer, after that viewer
219
+ allows it in the Portal prompt. Use `useCloudComputerShell()`: check `level`, call
220
+ `requestApproval()` when `approved` is false (either level; the facts of
221
+ `useCloudComputer()` are read again once allowed), then, when `available` (`shell`),
222
+ `run(command, options)` or
223
+ `upload({ path, content, content_encoding: 'base64', mode: 0o600 })`. Never put
224
+ secrets in a command; send them as upload content. A run is never repeated for one
225
+ request key: pass `requestId` (run option, or `request_id` in the upload) when the
226
+ page retries a run itself; `cloud_computer_already_ran` means it already ran. The
227
+ approval covers only the exact code the viewer allowed, so every new release asks
228
+ again. Keep a fallback (a Manager draft) for Sites, previews offline and viewers
229
+ who do not allow it. Declare it only when the page's core controls run on the
230
+ cloud computer.
231
+
232
+ ## Visual data and Markdown
233
+
234
+ Give a chart its numbers through `RenderChartData` (the toolkit's `Chart` and
235
+ `ChartTable` already do): it adds a semantic table without a second visible one.
236
+ The renderer never guesses exact numbers from SVG or canvas geometry; a chart
237
+ without it contributes only its accessible name to the Markdown.
238
+
239
+ An optional `markdown` source module exports a pure function of `{params, shown}`.
240
+ It must describe the rendered selection and its actual data. Ordinary rendering
241
+ extracts tables, lists, controls and visible document/HTML content automatically.
242
+
243
+ ## Host interactions and context
244
+
245
+ - `useHandover()` exposes `{handover, available, pending, error}`. Call a declared
246
+ linked Skill with `handover({skill, prompt})`; fall back when no agent UI exists.
247
+ A selected row goes as `record: {binding, recordKey, readAction}`: the host
248
+ reads that row without its body, so pass the database's `query_` action (a
249
+ `read_record_` action fixed to `include_content: true` is refused).
250
+ - The host top bar owns the title, the search and Share. `ListReader` `search`
251
+ fills the host search field; a Space never wires its own search. The open
252
+ item joins the crumb through `ListReader` `crumbLabel`, or
253
+ `useTopBarTitleLeaf(label, onBack)` on your own layout; the view crumb then
254
+ calls `onBack`. When the item is a record of the Space's `collection`, pass
255
+ `useTopBarTitleLeaf(label, onBack, { recordKey })` so Editors rename it from
256
+ the crumb; read its name from your data, which refreshes after the rename. A
257
+ `DocumentPage` breadcrumb moves into the top bar on wide
258
+ screens and stays in the page only on narrow ones, so never draw your own
259
+ title or breadcrumb row. Do not duplicate host chrome.
260
+ - `useActiveResource` publishes the current resource; `useAgentContext`,
261
+ `NotisSelectionBoundary`, `NotisCommentBoundary` and `NotisCommentBox` support
262
+ explicit reference context. [Context sharing](context.md) owns the contract.
263
+ - `Dialog` supplies a themed modal with focus handling; while it is open, only
264
+ its own keys and Escape work. For a confirmation (delete, discard), pass
265
+ `nativeOnTouch` and mark the buttons `data-dialog-confirm` and
266
+ `data-dialog-cancel`: phones and tablets then ask with the system dialog.
267
+ - `MarkdownEditor` is for a view-owned Markdown draft/persistence adapter. Native
268
+ documents use `DocumentEditor` so collaboration and file authority stay with Notis.
269
+
270
+ ## Offline fixtures
271
+
272
+ Read the complete [offline fixture contract](fixtures.md). Keep every fixture
273
+ fictional; verification never falls back to the user's real account.
@@ -0,0 +1,118 @@
1
+ # Store publishing
2
+
3
+ Use this when the user asks to publish a Space, or an update to one, in the
4
+ Store. You prepare everything; the user chooses where it goes and presses
5
+ Publish on the submission page. Store publication stays separate from deploying
6
+ the installed Space ([Delivery](release.md)).
7
+
8
+ ## Never publish for the user
9
+
10
+ There is no agent publish operation, and you never press, simulate or script
11
+ the Publish button. Only the page's Publish button publishes, after the user
12
+ picks Team or Public there. Asking you to publish means: prepare the submission
13
+ and send the page link. A team listing goes live as soon as the user presses
14
+ Publish; a public listing goes to the sandbox reviewer, and Notis messages the
15
+ user with its result.
16
+
17
+ ## The flow
18
+
19
+ All steps use `LOCAL_NOTIS_MANAGE_SPACE`. Each answer is the submission view:
20
+ status, listing text, locales, sample rows and counts, screenshots, findings,
21
+ `can_publish`, `blocked_reason` and `link`.
22
+
23
+ 1. **Prepare.** Call `store_prepare {space_id, request_id}` with the root of the
24
+ tree to publish and a stable request ID. Notis copies the tree into the
25
+ user's hidden Store review Space (the test copy, automations paused), pins
26
+ the source revision, takes screenshots and runs the safety scan. Retry with
27
+ the same request ID; never prepare twice to recover a lost answer.
28
+ 2. **Write the listing** with `store_submission_update {submission_id, metadata,
29
+ locales}`: name, tagline, description, category, icon and accent in
30
+ `metadata` (English), and the French name, tagline and description in
31
+ `locales.fr`. The optional `locales.fr.items` maps `pages`, `databases`,
32
+ `skills` and `automations` by the immutable `key` returned in the submission's
33
+ item inventory. Supply display-only `name` and `description` (`summary` for
34
+ automations), preserving the package's identities and order. A null or blank
35
+ leaf clears that translation, so the viewer falls back to English. Say what the Space does for the person who installs it, from
36
+ its views, databases and Skills. Write French as natural French (tu), not a
37
+ word-for-word translation. No personal names, account details, customer or
38
+ company data from the source.
39
+ 3. **Write sample rows** with `store_submission_update {submission_id,
40
+ sample_rows}` (see below), then read the screenshots. Pass
41
+ `retake_screenshots: true` after sample rows or listing text change what the
42
+ views show.
43
+ 4. **Handle the findings** (see below): ask about privacy, fix the rest in the
44
+ source Space, and list every fix.
45
+ 5. **Send the link.** When `can_publish` is true, give the user the page
46
+ `link`, one short line on what is ready, the fixes you made and their answers.
47
+ If it stays false, say what still blocks it from `blocked_reason` and what
48
+ they can do.
49
+
50
+ ## Sample rows
51
+
52
+ - Up to 8 rows per database, keyed by database key: `{database_key:
53
+ [{key, properties, body}]}`. Use only properties in that database's schema; a
54
+ relation lists the `key` of another row in the same sample set. `body` is
55
+ optional plain text (one paragraph per line); `key` is optional short text.
56
+ - Realistic and wholly synthetic: plausible titles, dates, amounts and states
57
+ that show every main view working (a few statuses, a spread of dates, at
58
+ least one row in each group a view shows).
59
+ - Never a real person's name, email address, phone number, company, address or
60
+ account identifier, and never content copied or paraphrased from the user's
61
+ own rows, notes, contacts or history. Use invented first names only when a
62
+ field needs a person ("Alex", "Camille"), and no contact details at all.
63
+ - Sample rows exist only in the test copy and the published version. They never
64
+ enter the source Space. Installs start with them, and the installer removes
65
+ all of them with one click; updates never bring them back.
66
+
67
+ ## Findings
68
+
69
+ Each finding has `id`, `check`, `severity` (`red` or `amber`), `privacy`,
70
+ `where`, `message`, `fix` and `status`. Publish needs no open red finding and no
71
+ unanswered privacy question.
72
+
73
+ **Privacy.** A finding with `privacy: true` is a candidate, not yet a question.
74
+ Judge whether it carries a real privacy risk for the publisher or for people in
75
+ their data: an outside host that would receive installers' data, an integration
76
+ or MCP call that reads private accounts, a read of Spaces outside the published
77
+ tree, a sharing change, personal data in the listing, screenshots or samples. A
78
+ candidate with no real risk is treated like any other finding. Sample or fake
79
+ data is never a risk: the scan already skips tests, fixtures and placeholder
80
+ hosts, so never ask the user to confirm data you can see is a sample. If one
81
+ still shows up, say it is sample data the scan missed instead of asking about
82
+ it. For each real risk, ask the user one plain question naming what and where, with two choices:
83
+
84
+ - **Remove**: take it out of what is published.
85
+ - **Keep**: publish it as it is; Notis adds your note to the listing so
86
+ installers see it.
87
+
88
+ Record their answer with `store_finding_answer {submission_id, finding_id,
89
+ answer: 'remove'|'keep', note, user_words}`. `user_words` are the user's own
90
+ words; `note` is the short listing sentence for a Keep, written in plain words.
91
+ Never answer a privacy question for the user.
92
+
93
+ **Everything else.** Fix each non-privacy red finding in the source Space
94
+ through the normal release path: pull, change, build, verify, deploy, read back
95
+ ([Delivery](release.md)). Then call `store_prepare` again for the same Space
96
+ with a new request ID, so the open submission pins the new revision and scans
97
+ again. List every fix for the user: what was found, where, and what you changed.
98
+ A finding you cannot fix keeps Publish blocked; say so plainly. Amber findings
99
+ need no fix; mention the ones an installer would notice.
100
+
101
+ Test chats about the submission run on the test copy only; never write sample
102
+ rows, listing text or fixes for the listing into the source Space's data.
103
+
104
+ ## Updates
105
+
106
+ Publishing an update follows the same flow: `store_prepare` on the same root
107
+ creates a new submission on the same listing, and Publish adds a new version to
108
+ it. Never create a second listing, a copy of the Space or a new Space to ship an
109
+ update. Installs that differ only in listing text or screenshots update
110
+ themselves; installs of a version that changes code or databases show an
111
+ Update available card and update when their owner chooses.
112
+
113
+ ## Status
114
+
115
+ Read the submission with `store_submission_read {submission_id}`. `ready` means
116
+ the page can publish; `in_review` means the public review is running and Notis
117
+ will message the user with the result; `published` is live; `rejected` lists what
118
+ to fix, which starts again from step 4 with a new `store_prepare`.
@@ -0,0 +1,28 @@
1
+ # Troubleshooting
2
+
3
+ Start with the actual failing operation and its exact Space, source/record
4
+ revision and current target. [Delivery](release.md) owns the release sequence.
5
+
6
+ | Failure | Check |
7
+ | --- | --- |
8
+ | Build rejects a view | Required `specVersion`, path, descriptions, params, executable shows and memory; use the file/line diagnostic. |
9
+ | Design check rejects a view | Replace the flagged code with the piece or hook the diagnostic names (`useShortcut` for a key listener, `useLayerRoot` for a portal, tokens for a colour, EN and FR copy for a literal). Do not disable the rule. |
10
+ | Main-view conflict | Inspect current database links/main view. Move the existing claim explicitly or retain it; do not remove main just to publish. |
11
+ | Source creation fails | Check its canonical schema and same-view main record param. Verify creates no resource; promotion is atomic. |
12
+ | View-link warning after a successful write | Use `FIND_VIEWS` with the returned record key. The write is already committed; do not insert again. |
13
+ | Empty list or missing properties | Inspect the live schema, filter, authorized binding and returned projection. Distinguish a successful empty result from a denied/failed read. |
14
+ | Verification fails on a read | Add the exact fictional case to the selected fixture file. Never fill missing fixtures with live private data. |
15
+ | A caught write-on-load fails rendering | Remove the side effect from initial rendering. A read-only check cannot authorize writes. |
16
+ | Stale binding/schema/record | Read current state, preserve the original receipt/intent and merge the intended edit. Do not overwrite concurrent changes. |
17
+ | Old code in Workspace | Read the published revision and requested bundle; source edits or restarting Desktop do not deploy it. |
18
+ | `client_update_required` | This Notis app or CLI is too old. Update it, then repeat the same operation. Old apps are not supported. |
19
+ | `protocol_required`, `invalid_protocol` or another 400 naming a `field` | The call is malformed, not out of date. Fix the named field (native Space and database tools take `"protocol": 1`) and call again. |
20
+ | Uncertain deployment | Run `notis doctor`, read the same Space and release/request identity, then reconcile before retrying. |
21
+ | A tool call fails with `network_error`, `network_timeout` or a 502, 503 or 504 | The CLI already retried it where repeating is safe (`attempts` in its answer). Do not add your own retry loop: read back the same target, then run it again only if it did not happen, with the same `request_id`. |
22
+ | Screenshot misses content | Inspect actual inner scrolling, lazy data and frame layout; keep full-height limits and treat a failed capture as unverified. |
23
+ | Site unexpectedly has editor controls | Recheck the anonymous scoped runtime. A Site cannot borrow an ambient signed-in session or another record's authority. |
24
+ | Memory hit looks current but access/freshness is unknown | Render its current link and verify the relevant value. Do not release historical content from an unverified read set. |
25
+
26
+ For visual defects, compare the installed page at 390px and 1440px in EN/FR,
27
+ including loading, empty and error states. A standalone harness cannot certify
28
+ the Portal parent layout, collaboration or public Site behavior.
@@ -0,0 +1,229 @@
1
+ # View authoring
2
+
3
+ A view is the presentation of a Space. A record opens in a view; its database has
4
+ one main view. Words in links describe the destination, while IDs choose it.
5
+ Get links from write results or `LOCAL_NOTIS_FIND_VIEWS`, not by joining labels.
6
+
7
+ ## Start from the collection scaffold
8
+
9
+ ```bash
10
+ notis spaces init "Notes" ./notes --database-key notes --path notes
11
+ notis spaces build ./notes --space collection
12
+ ```
13
+
14
+ `init` is local only. For an existing Space, pull its exact ID instead. Keep its
15
+ lock and local source key; one build/deploy changes that selected Space only.
16
+ A container has children but no page; page-only params/shows/memory belong on views.
17
+
18
+ ## Index the Space in the workspace
19
+
20
+ The root `notis.config.ts` maps each local Space key to an object with its
21
+ definition file. The value is not a path string or the definition itself:
22
+
23
+ ```ts
24
+ import { defineSpaces } from '@notis/sdk/config';
25
+
26
+ export default defineSpaces({
27
+ spaces: { notes: { definition: 'spaces/notes/space.config.ts' } },
28
+ });
29
+ ```
30
+
31
+ That definition file exports `defineSpace`, as below; its `entry` is relative to
32
+ the definition file. `spaces init` creates this index for a new collection.
33
+ When writing a new source workspace through the confined source tools, include
34
+ the index and the definition before requesting a build.
35
+
36
+ ## A complete view declaration
37
+
38
+ The linked `notes` resource below must already resolve to this installation's
39
+ native database. Descriptions explain what a person or agent can do here.
40
+
41
+ ```ts
42
+ import { defineSpace } from '@notis/sdk/config';
43
+
44
+ export default defineSpace({
45
+ specVersion: 2,
46
+ name: 'Notes',
47
+ path: 'notes',
48
+ description: 'Browse notes and open one with its files.',
49
+ readableContext: 'The note parameter opens one note. The list shows all notes available through this Space.',
50
+ entry: './view.tsx',
51
+ resources: { notes: { kind: 'database', key: 'notes' } },
52
+ collection: { database: 'notes', titleProperty: 'title' },
53
+ params: {
54
+ note: { type: 'record', database: 'notes', main: true,
55
+ description: 'The note to open beside the list.' },
56
+ },
57
+ shows: { notes: { database: 'notes', where: {}, open: 'note' } },
58
+ memory: { markdown: true, attachments: true, screenshot: false, snapshots: [] },
59
+ actions: {
60
+ read: {
61
+ tool: 'LOCAL_NOTIS_DATABASE_QUERY',
62
+ inputs: { type: 'object', additionalProperties: false,
63
+ required: ['request'], properties: { request: {
64
+ type: 'object', additionalProperties: false,
65
+ required: ['filter', 'page_size', 'include_content'],
66
+ properties: {
67
+ filter: { type: 'object', additionalProperties: false,
68
+ required: ['field', 'op', 'value'], properties: {
69
+ field: { type: 'object', additionalProperties: false,
70
+ required: ['column'], properties: { column: { const: 'record_key' } } },
71
+ op: { const: 'equals' }, value: { type: 'string', format: 'uuid' },
72
+ } },
73
+ page_size: { const: 1 }, include_content: { const: true },
74
+ },
75
+ } } },
76
+ arguments: { database_id: { $asset: 'notes' }, request: { $input: 'request' } },
77
+ },
78
+ },
79
+ });
80
+ ```
81
+
82
+ The saved `read` action is deliberately constrained to one native record for
83
+ body/Site reads; `shows.notes` owns the Editor's collection list. Keep both tied
84
+ to the same declared resource.
85
+
86
+ ## Write the view
87
+
88
+ Start from the piece that matches the view. A list beside a reader is one
89
+ `ListReader`:
90
+
91
+ ```tsx
92
+ import { DocumentPage, useAction, useNotisRuntime, useShown } from '@notis/sdk';
93
+ import { ListReader, Row } from '@notis/sdk/ui';
94
+
95
+ type Note = { record_key: string; title: string; updated_at: string };
96
+ const keys = (items: Note[]) => ({ record_keys: items.map((n) => n.record_key) });
97
+ const copy = { en: { search: 'Search notes' }, fr: { search: 'Rechercher des notes' } };
98
+
99
+ export default function Notes() {
100
+ const t = copy[useNotisRuntime()?.context.locale === 'fr' ? 'fr' : 'en'];
101
+ const notes = useShown<Note>('notes', { allPages: true });
102
+ const archive = useAction('archive_notes'); // declared write actions
103
+ const pin = useAction('pin_notes');
104
+ return (
105
+ <ListReader
106
+ label={{ en: 'Notes', fr: 'Notes' }}
107
+ items={notes.data?.rows ?? []}
108
+ getId={(n) => n.record_key}
109
+ openParam="note"
110
+ search={{ placeholder: t.search,
111
+ match: (n, query) => n.title.toLocaleLowerCase().includes(query.toLocaleLowerCase()) }}
112
+ row={(n) => <Row title={n.title} time={n.updated_at} />}
113
+ readerLabel={(n) => n.title}
114
+ crumbLabel={(n) => n.title}
115
+ reader={(n) => <DocumentPage recordKey={n.record_key} />}
116
+ actions={[
117
+ { id: 'archive', run: (items) => archive.call(keys(items)) },
118
+ { id: 'pin', key: 'shift+p', label: { en: 'Pin', fr: 'Épingler' },
119
+ run: (items) => pin.call(keys(items)) },
120
+ ]}
121
+ />
122
+ );
123
+ }
124
+ ```
125
+
126
+ That is the whole view. J/K (wrapping), Enter, Escape, selection with X,
127
+ Shift+J/K and Mod+A, E with Notis's Archive words and toast, the selection bar,
128
+ the `?` sheet, open as Side, Center or Full, the one-pane rule next to chat and the
129
+ phone layout come with it. `openParam` names the declared record param, so the
130
+ open note lives in the link. `search` fills the host top bar search field and
131
+ filters the loaded notes; `crumbLabel` adds the open note to the top bar crumb
132
+ ("Notes / Groceries"); `readerLabel` names it in the reader bar. The view draws
133
+ no title, heading or search field of its own. `archive` is a standard action: it
134
+ brings its own words and key. `pin` is the Space's own: it brings its EN and FR
135
+ words and a key the clash check accepts. Add `tabs` for real saved filters and
136
+ `create` for a "+" that makes a record. Other kinds of view start from their own
137
+ piece; see [Design](design.md#pick-the-piece).
138
+
139
+ Keep hooks unconditional; conditional record/list branches can be separate
140
+ components. The [SDK reference](sdk.md) covers data hooks, record components,
141
+ navigation and the toolkit pieces.
142
+
143
+ ## Params and declared lists
144
+
145
+ - Param types: `record`, `enum`, `text`, `number`, `date`, `boolean`. Each needs a
146
+ description. Enum values and defaults are typed; a required param has no default.
147
+ - Record params name a declared database and have no default record. `main: true`
148
+ claims that database's main view. `slugProperty` is a title/number property used
149
+ for readable link text, not record identity.
150
+ - One optional (never `required`) record param per view may declare `page: {where}`:
151
+ a matching saved HTML page or report then opens full screen as its own page, for
152
+ Editors in the Portal (Back, plus Share for HTML) and, for HTML pages only, on its
153
+ record Site. `where` compares
154
+ fixed values over `record_key`/`id`, `content_type`/`file_type`/`title` and select,
155
+ status or checkbox properties; it never reaches the browser. Viewers still get the
156
+ view, so keep its own HTML/report rendering. The full rules live under Record pages
157
+ in the platform reference (`docs/notis-spaces-platform.md`).
158
+ - `path` is descriptive lowercase words, up to four slash-separated segments;
159
+ do not put IDs, credentials or reserved product routes in it.
160
+ - `shows` for native data is `{database, where, open?}`. `where` is the native filter
161
+ grammar and is what `useShown` executes, not commentary beside a different query.
162
+ `open` names a record param over the same database.
163
+ - A condition may add `when: 'late'`, naming a boolean param. It is included
164
+ only when that setting is true; absent/false drops it before pagination.
165
+ This also gates `is_empty` for unplanned tasks. `tasksViewFilter` pairs with
166
+ `tasksViewParams`; bind their property names and Done status to the actual schema.
167
+ Its `today` date param defaults to the declared timezone's today; pin it for
168
+ dated answers. Clear conflicting date/period/late/unplanned settings in controls.
169
+ - A project-scoped task list can use
170
+ `{field: {property: 'Project'}, op: 'contains', value: '{project}'}` with a declared
171
+ project record param. `{project.Status}` reads a property of that authorized record.
172
+ - For connected-service content use `{about, services?}` and declared actions.
173
+ This descriptive form is not a native executable list; use `useAction` for reads.
174
+ - Preserve the application's real semantics and option names. For the existing
175
+ Tasks migration, Inbox is **Project empty OR Status equals Inbox**. Keep imported
176
+ rows, statuses and creation defaults; add the Inbox option only if absent. Its
177
+ native filter is `{or: [{field: {property: 'Project'}, op: 'is_empty'},
178
+ {field: {property: 'Status'}, op: 'equals', value: 'Inbox'}]}`. Other applications
179
+ must use their own inspected schema rather than copying these labels blindly.
180
+
181
+ ## Create a database in the same release
182
+
183
+ Replace an existing database reference with:
184
+
185
+ ```ts
186
+ resources: {
187
+ notes: { kind: 'database', create: {
188
+ name: 'Notes',
189
+ schema: {
190
+ schema_version: 1, value_encoding_version: 1, coercion_version: 1,
191
+ title_property_id: 'title', property_order: ['title'],
192
+ properties: { title: { id: 'title', name: 'Name', kind: 'title',
193
+ storage_family: 'textish', description: '', order: 0, config: {} } },
194
+ },
195
+ } },
196
+ },
197
+ ```
198
+
199
+ The same view declares a record param over `notes` with `main: true`. Promotion
200
+ creates the database, link, main view, optional fictional `starterRows` and source
201
+ atomically; a later failure leaves none of them behind. Verification does not create
202
+ it. `create` is creation-only: later schema edits use native database tools;
203
+ `spaces pull` refreshes the declaration from the live schema.
204
+
205
+ The separate native schema-tool creation route requires `links.add` and
206
+ `main_view: {space_id, param}` in that linked Space. Until the Space next deploys
207
+ that main param, record links open the Space and writes return `view_warning`.
208
+ Inspect current tools for exact argument shapes; do not repeatedly insert rows
209
+ because a pending main view cannot yet open one.
210
+
211
+ ## Rendering and memory
212
+
213
+ Choose [memory](memory.md) deliberately. `chrome: 'hidden'` is for full-screen
214
+ presentations; ordinary collection views keep Portal chrome.
215
+ A Space whose published view hides chrome starts hidden from each person's sidebar;
216
+ it stays reachable by link and search. Each person can turn on **Show hidden Spaces**
217
+ in the sidebar's Spaces menu, then choose **Show in sidebar** in that Space's menu.
218
+ Skill review Spaces stay out of the sidebar, even with **Show hidden Spaces** on:
219
+ people open them from the Skill page's **Changes** list. A review a person already
220
+ chose to show stays in their sidebar until they hide it.
221
+ Optional `markdown: './markdown.ts'` names a module exporting a pure function of
222
+ `{params, shown}`. Its output must represent this view, not make hidden writes.
223
+ Use `<RenderChartData>` with the chart's actual rows so rendered Markdown contains
224
+ precise labels and values as well as its image.
225
+
226
+ Add synthetic action/list/body/record fixtures, then build and verify. Verification
227
+ and live rendering share the read-only renderer; fixture success does not prove
228
+ live permissions or data. After an authorized deploy, render the returned view link
229
+ with `notis views render` and inspect both the Markdown and full-height screenshot.