@notis_ai/cli 0.2.17 → 0.2.19

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 +42323 -18258
  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 +271 -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 -1568
  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 -3000
  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
@@ -1,7 +1,11 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { basename } from 'node:path';
2
+ import { basename, isAbsolute } from 'node:path';
3
3
 
4
- import { installAgentSetup, shouldInstallLocalAgentSetup } from '../runtime/agent-setup.js';
4
+ import {
5
+ installAgentSetup,
6
+ installRecallOnlyAgentHooks,
7
+ shouldInstallLocalAgentSetup,
8
+ } from '../runtime/agent-setup.js';
5
9
  import {
6
10
  completePendingTurn,
7
11
  freshRecallItems,
@@ -42,7 +46,54 @@ export function installLocalAgentContext(
42
46
  });
43
47
  }
44
48
 
49
+ /**
50
+ * Recall-only install for a hosted coding agent. The local guard against
51
+ * hosted environments does not apply: this mode is asked for explicitly, binds
52
+ * to the session's injected credential instead of a stored profile, and
53
+ * writes only into the agent's own config folder.
54
+ */
55
+ export function installRecallOnlyAgentContext(ctx, env = process.env) {
56
+ const options = ctx.options || {};
57
+ if (options.memoryHooks === false) {
58
+ throw usageError('--recall-only installs memory hooks; it cannot be combined with --no-memory-hooks');
59
+ }
60
+ if (options.envFile !== undefined && (typeof options.envFile !== 'string' || !isAbsolute(options.envFile))) {
61
+ throw usageError('--env-file must be an absolute path');
62
+ }
63
+ const agents = selectedAgents(options);
64
+ if (ctx.runtime.credentialKind !== 'env' || !ctx.runtime.jwt) {
65
+ return agents.map((agent) => ({ agent, status: 'skipped_requires_session_credential' }));
66
+ }
67
+ return agents.map((agent) => {
68
+ const configDir = agent === 'codex' ? env.CODEX_HOME : env.CLAUDE_CONFIG_DIR;
69
+ if (typeof configDir !== 'string' || !isAbsolute(configDir)) {
70
+ return { agent, status: 'skipped_requires_agent_config_dir' };
71
+ }
72
+ return installRecallOnlyAgentHooks({ agentId: agent, configDir, envFile: options.envFile || null });
73
+ });
74
+ }
75
+
45
76
  async function agentsInstallHandler(ctx) {
77
+ if (ctx.options?.recallOnly) {
78
+ const results = installRecallOnlyAgentContext(ctx);
79
+ const installed = results.filter((result) => result.mode === 'recall_only'
80
+ && result.memory_hook?.status !== 'error');
81
+ const hookErrors = results.filter((result) => result.memory_hook?.status === 'error');
82
+ return ctx.output.emitSuccess({
83
+ command: 'agents install',
84
+ data: { mode: 'recall_only', agents: results },
85
+ humanSummary: installed.length
86
+ ? `Installed recall-only Notis memory hooks for ${installed.length} coding agent${installed.length === 1 ? '' : 's'}.`
87
+ : 'Skipped recall-only coding-agent memory hooks.',
88
+ warnings: hookErrors.map((result) => result.memory_hook.message),
89
+ hints: [],
90
+ renderHuman: () => results.map((result) => (
91
+ result.mode === 'recall_only'
92
+ ? `${result.agent}: recall-only memory hook ${result.memory_hook?.status || 'skipped'}`
93
+ : `${result.agent}: ${result.status}`
94
+ )).join('\n'),
95
+ });
96
+ }
46
97
  const results = installLocalAgentContext(ctx);
47
98
  const hookErrors = results.filter((result) => result.memory_hook?.status === 'error');
48
99
  const configuredCount = results.filter((result) => result.instructions).length;
@@ -132,10 +183,12 @@ export function formatMemoryContext(data, { sessionStart = false } = {}) {
132
183
  return lines.join('\n');
133
184
  }
134
185
 
135
- function withFreshResults(input, data) {
186
+ function withFreshResults(input, data, home) {
136
187
  const results = Array.isArray(data?.results) ? data.results : [];
137
188
  const texts = results.map(memoryText);
138
- const freshTexts = new Set(freshRecallItems(input, texts.filter(Boolean)));
189
+ const freshTexts = new Set(home === undefined
190
+ ? freshRecallItems(input, texts.filter(Boolean))
191
+ : freshRecallItems(input, texts.filter(Boolean), home));
139
192
  const emitted = new Set();
140
193
  return {
141
194
  ...data,
@@ -148,6 +201,45 @@ function withFreshResults(input, data) {
148
201
  };
149
202
  }
150
203
 
204
+ const WORKER_CONTEXT_PREFIX = 'Current worker context for this turn.';
205
+ const INJECTED_BLOCK_PATTERN = /<(system_instruction|notis_[a-z_]+|delegated_provider|interaction_id|relevant_memory|instructions)>[\s\S]*?<\/\1>/g;
206
+
207
+ function withoutInjectedBlocks(text) {
208
+ return text.replace(INJECTED_BLOCK_PATTERN, '\n');
209
+ }
210
+
211
+ /**
212
+ * The user's own request inside a delegated Notis turn. A hosted coding agent
213
+ * receives the Notis contract, earlier history, delivery receipts and a worker
214
+ * context snapshot in the same message; searching all of that would recall
215
+ * memories about the contract instead of the request. Each request follows its
216
+ * `<interaction_id>` tag and ends before the next tag or the worker context.
217
+ */
218
+ export function delegatedRequestText(prompt) {
219
+ const text = typeof prompt === 'string' ? prompt : '';
220
+ const workerAt = text.indexOf(WORKER_CONTEXT_PREFIX);
221
+ const head = workerAt >= 0 ? text.slice(0, workerAt) : text;
222
+ const tagPattern = /<interaction_id>[\s\S]*?<\/interaction_id>/g;
223
+ const tags = [...head.matchAll(tagPattern)];
224
+ let request = '';
225
+ if (tags.length) {
226
+ request = tags.map((tag, index) => {
227
+ const start = tag.index + tag[0].length;
228
+ const end = index + 1 < tags.length ? tags[index + 1].index : head.length;
229
+ return withoutInjectedBlocks(head.slice(start, end)).trim();
230
+ }).filter(Boolean).join('\n');
231
+ } else {
232
+ request = withoutInjectedBlocks(text)
233
+ .replace(/Current worker context for this turn\.[^\n]*(?:\n\{[^\n]*\})?/g, '\n')
234
+ .trim();
235
+ }
236
+ if (!request) {
237
+ const goal = /<goal>([\s\S]*?)<\/goal>/.exec(text);
238
+ request = goal ? goal[1].trim() : '';
239
+ }
240
+ return request.replace(/\n{3,}/g, '\n\n').slice(0, 12000);
241
+ }
242
+
151
243
  function memoryStateInput(input, runtime) {
152
244
  return {
153
245
  ...input,
@@ -166,7 +258,19 @@ export async function agentContextHandler(ctx, {
166
258
  // Hook failures are deliberately silent and fail-open. A temporary Notis
167
259
  // outage must not prevent the user's Codex or Claude prompt from running.
168
260
  try {
169
- const input = await readInput();
261
+ const recallOnly = ctx.options?.recallOnly === true;
262
+ const stateDir = recallOnly && typeof ctx.options?.stateDir === 'string' && isAbsolute(ctx.options.stateDir)
263
+ ? ctx.options.stateDir
264
+ : undefined;
265
+ if (recallOnly) {
266
+ // Recall-only hooks never capture, so no turn is held for a Stop hook.
267
+ rememberPending = () => {};
268
+ clearPending = () => {};
269
+ }
270
+ const rawInput = await readInput();
271
+ const input = recallOnly && rawInput?.hook_event_name === 'UserPromptSubmit'
272
+ ? { ...rawInput, prompt: delegatedRequestText(rawInput.prompt) }
273
+ : rawInput;
170
274
  const stateInput = memoryStateInput(input, ctx.runtime);
171
275
  const event = input?.hook_event_name;
172
276
  if (!['SessionStart', 'UserPromptSubmit'].includes(event)) return 0;
@@ -194,7 +298,7 @@ export async function agentContextHandler(ctx, {
194
298
  include_profile: event === 'SessionStart',
195
299
  },
196
300
  });
197
- const data = withFreshResults(stateInput, unwrapToolPayload(result.payload));
301
+ const data = withFreshResults(stateInput, unwrapToolPayload(result.payload), stateDir);
198
302
  const additionalContext = formatMemoryContext(data, { sessionStart: event === 'SessionStart' });
199
303
  if (!additionalContext) return 0;
200
304
  process.stdout.write(`${JSON.stringify({
@@ -333,13 +437,15 @@ export const agentsCommandSpecs = [
333
437
  command_path: ['agents', 'install'],
334
438
  summary: 'Install Notis instructions and recall/capture hooks for local Codex and Claude Code.',
335
439
  when_to_use:
336
- 'Run after login to give local coding agents durable Notis CLI guidance, session-start profile context, deduplicated relevant recall, and automatic completed-turn capture. Hosted Notis sandboxes already receive prompt context and are skipped.',
440
+ 'Run after login to give local coding agents durable Notis CLI guidance, session-start profile context, deduplicated relevant recall, and automatic completed-turn capture. Hosted Notis sandboxes are skipped unless --recall-only is given: that mode installs only recall hooks into the hosted agent\'s own config folder, signed in with the session\'s injected credential.',
337
441
  args_schema: {
338
442
  arguments: [],
339
443
  options: [
340
444
  { flags: '--codex-only', description: 'Configure only Codex.' },
341
445
  { flags: '--claude-only', description: 'Configure only Claude Code.' },
342
446
  { flags: '--no-memory-hooks', description: 'Install static instructions and remove Notis recall/capture hooks.' },
447
+ { flags: '--recall-only', description: 'Hosted coding agents: install only recall hooks (no capture, no instructions) into CODEX_HOME or CLAUDE_CONFIG_DIR, signed in with the injected NOTIS_JWT.' },
448
+ { flags: '--env-file <path>', description: 'With --recall-only: a shell file each hook sources first to pick up the current injected sign-in.' },
343
449
  ],
344
450
  },
345
451
  examples: [
@@ -347,6 +453,7 @@ export const agentsCommandSpecs = [
347
453
  'notis agents install --codex-only',
348
454
  'notis agents install --claude-only',
349
455
  'notis agents install --no-memory-hooks',
456
+ 'notis agents install --recall-only --codex-only',
350
457
  ],
351
458
  output_schema: 'Returns each configured agent, instruction file path/status, memory-hook file path/status, and profile binding.',
352
459
  mutates: true,
@@ -360,7 +467,13 @@ export const agentsCommandSpecs = [
360
467
  command_path: ['agent-context'],
361
468
  summary: 'Internal hook adapter that injects relevant Notis memory.',
362
469
  when_to_use: 'Called by installed Codex and Claude Code UserPromptSubmit hooks; not intended for direct use.',
363
- args_schema: { arguments: [], options: [] },
470
+ args_schema: {
471
+ arguments: [],
472
+ options: [
473
+ { flags: '--recall-only', description: 'Hosted recall: search only the user request inside a delegated turn and never hold a turn for capture.' },
474
+ { flags: '--state-dir <dir>', description: 'Folder for per-session recall state instead of the home folder.' },
475
+ ],
476
+ },
364
477
  examples: [],
365
478
  output_schema: 'Emits vendor-compatible hook JSON with additionalContext, or no output when context is unavailable.',
366
479
  mutates: false,
@@ -108,7 +108,7 @@ export const authCommandSpecs = [
108
108
  { flags: '--mode <mode>', description: 'auto (default) hands the browser callback to a background listener when this command cannot wait; browser waits in-process; code shows a one-time code to copy.' },
109
109
  { flags: '--paste-code', description: 'Alias for --mode code.' },
110
110
  { flags: '--timeout-seconds <n>', description: 'Authorization lifetime in seconds (default 300 while waiting in a terminal; 1800 for detached or code hand-offs).' },
111
- { flags: '--scope <scope>', description: 'OAuth permission to request (repeatable).', collect: true },
111
+ { flags: '--scope <scope>', description: 'OAuth permission to request (repeatable). Default: every permission Notis offers the CLI.', collect: true },
112
112
  { flags: '--code <code>', description: 'Redeem the code shown in the browser after a non-interactive login.' },
113
113
  ],
114
114
  },
@@ -133,9 +133,9 @@ export const authCommandSpecs = [
133
133
  },
134
134
  {
135
135
  command_path: ['logout'],
136
- summary: 'Revoke and remove the OAuth credential for one CLI profile.',
136
+ summary: 'Sign this computer out of one CLI profile: revoke and remove its OAuth credential.',
137
137
  when_to_use:
138
- 'Use this to disconnect a single account. Other profiles keep their credentials unless you pass --all-profiles.',
138
+ 'Use this to disconnect a single account on this computer. Its sign-ins on other computers stay, and other profiles keep their credentials unless you pass --all-profiles.',
139
139
  args_schema: {
140
140
  arguments: [],
141
141
  options: [
@@ -4,6 +4,8 @@ import { usageError } from '../runtime/errors.js';
4
4
  import {
5
5
  COMPOSIO_MULTI_EXECUTE_TOOL,
6
6
  fetchToolDiscovery,
7
+ fetchToolSchema,
8
+ fetchToolkits,
7
9
  healthCheck,
8
10
  nextIdempotencyKey,
9
11
  runToolCommand,
@@ -37,6 +39,22 @@ function discoveredToolNames(payload) {
37
39
  return [...new Set(names.filter(Boolean))];
38
40
  }
39
41
 
42
+ function isNotisAppSupabase(value) {
43
+ const upper = String(value || '').toUpperCase();
44
+ return upper.includes('SUPABASE') && upper.includes('NOTIS_APP') && !upper.includes('WEBSITE');
45
+ }
46
+
47
+ export function selectSupabaseSqlTool(discoveredNames, toolkits = []) {
48
+ const discovered = discoveredNames.find((name) => (
49
+ isNotisAppSupabase(name) && name.toUpperCase().includes('EXECUTE_SQL')
50
+ ));
51
+ if (discovered) return discovered;
52
+ // Semantic search ranks Composio's generic Supabase tools above a connected
53
+ // custom MCP server, so derive the canonical name from the connected toolkit.
54
+ const toolkit = toolkits.find((entry) => entry.has_active_connection && isNotisAppSupabase(entry.id));
55
+ return toolkit ? `${String(toolkit.id).toUpperCase()}_EXECUTE_SQL` : null;
56
+ }
57
+
40
58
  async function discoverSupabaseSqlTool(runtime) {
41
59
  const payload = await fetchToolDiscovery(
42
60
  runtime,
@@ -44,10 +62,20 @@ async function discoverSupabaseSqlTool(runtime) {
44
62
  'query',
45
63
  );
46
64
  const names = discoveredToolNames(payload);
47
- const match = names.find((name) => (
48
- name.toUpperCase().includes('SUPABASE')
49
- && name.toUpperCase().includes('EXECUTE_SQL')
50
- ));
65
+ let match = selectSupabaseSqlTool(names);
66
+ if (!match) {
67
+ const { toolkits } = await fetchToolkits(runtime);
68
+ const candidate = selectSupabaseSqlTool([], toolkits);
69
+ if (candidate) {
70
+ try {
71
+ await fetchToolSchema(runtime, candidate);
72
+ match = candidate;
73
+ } catch (error) {
74
+ // Only an unknown tool name means the toolkit lacks it; surface outages.
75
+ if (error?.code !== 'usage_error' || !/not found/.test(error.message)) throw error;
76
+ }
77
+ }
78
+ }
51
79
  if (!match) {
52
80
  throw usageError('No connected Supabase execute-SQL capability was discovered. Run `notis tools link mcp_supabase_notis_app`.');
53
81
  }
@@ -56,7 +84,8 @@ async function discoverSupabaseSqlTool(runtime) {
56
84
 
57
85
  export function unwrapToolExecutionPayload(payload) {
58
86
  return (
59
- payload?.data?.results?.[0]?.response?.data
87
+ payload?.data?.data?.results?.[0]?.response?.data
88
+ ?? payload?.data?.results?.[0]?.response?.data
60
89
  ?? payload?.results?.[0]?.response?.data
61
90
  ?? payload?.data?.result
62
91
  ?? payload?.result
@@ -72,30 +101,30 @@ function parseJsonCandidate(value) {
72
101
  return JSON.parse(trimmed);
73
102
  } catch {
74
103
  const boundaryEnd = trimmed.lastIndexOf('</untrusted-data');
75
- const boundaryStart = boundaryEnd >= 0
76
- ? trimmed.lastIndexOf('<untrusted-data', boundaryEnd)
77
- : -1;
78
- const contentStart = boundaryStart >= 0 ? trimmed.indexOf('>', boundaryStart) + 1 : -1;
79
- if (contentStart > 0 && boundaryEnd > contentStart) {
104
+ const boundaryName = boundaryEnd >= 0
105
+ ? trimmed.slice(boundaryEnd + 2, trimmed.indexOf('>', boundaryEnd)) : null;
106
+ const opening = boundaryName ? `<${boundaryName}>` : null;
107
+ for (let boundaryStart = opening ? trimmed.indexOf(opening) : -1;
108
+ boundaryStart >= 0 && boundaryStart < boundaryEnd;
109
+ boundaryStart = trimmed.indexOf(opening, boundaryStart + opening.length)) {
110
+ const contentStart = boundaryStart + opening.length;
80
111
  // Supabase MCP sometimes returns the prose envelope with literal "\\n"
81
112
  // separators. Strip those only at the boundary: globally replacing them
82
113
  // corrupts valid escaped newlines inside JSON string values.
83
114
  const inner = trimmed
84
115
  .slice(contentStart, boundaryEnd)
85
116
  .trim()
86
- .replace(/^(?:\\r?\\n)+/, '')
87
- .replace(/(?:\\r?\\n)+$/, '')
117
+ .replace(/^(?:(?:\\r)?\\n)+/, '')
118
+ .replace(/(?:(?:\\r)?\\n)+$/, '')
88
119
  .trim();
89
120
  try {
90
121
  return JSON.parse(inner);
91
- } catch (error) {
92
- const nested = parseJsonCandidate(inner);
93
- if (nested !== null) return nested;
94
- throw usageError(
95
- `Supabase diagnostic rows were not valid JSON: ${error instanceof Error ? error.message : String(error)}; prefix=${JSON.stringify(inner.slice(0, 100))}`,
96
- );
122
+ } catch {
123
+ // The provider also mentions this marker in its introductory prose.
124
+ // Try its actual opening, never a nested tool result's different marker.
97
125
  }
98
126
  }
127
+ if (boundaryEnd >= 0) throw usageError('Supabase diagnostic rows were not valid JSON.');
99
128
  const arrayMatch = trimmed.match(/(\[[\s\S]*\])/);
100
129
  if (arrayMatch) {
101
130
  try {
@@ -445,7 +474,15 @@ async function debugEntitlementOverrideHandler(ctx) {
445
474
  });
446
475
  }
447
476
 
448
- function buildTraceCostSql(reference) {
477
+ export function langfuseTraceIdCandidates(reference) {
478
+ const value = String(reference);
479
+ const compact = value.replaceAll('-', '').toLowerCase();
480
+ const providerId = /^[0-9a-f]{32}$/.test(compact) && !/^0+$/.test(compact)
481
+ ? compact : createHash('sha256').update(value).digest('hex').slice(0, 32);
482
+ return [...new Set([providerId, value])];
483
+ }
484
+
485
+ export function buildTraceCostSql(reference) {
449
486
  const literal = sqlLiteral(reference);
450
487
  return `
451
488
  SELECT jsonb_build_object(
@@ -464,6 +501,8 @@ SELECT jsonb_build_object(
464
501
  FROM public.interactions AS i
465
502
  WHERE i.id::text = ${literal}
466
503
  OR to_jsonb(i)->>'trace_id' = ${literal}
504
+ OR replace(i.id::text, '-', '') = lower(${literal})
505
+ OR replace(to_jsonb(i)->>'trace_id', '-', '') = lower(${literal})
467
506
  ORDER BY i.created_at ASC;`;
468
507
  }
469
508
 
@@ -579,7 +618,10 @@ async function debugTraceCostHandler(ctx) {
579
618
  refund_basis: refundableEstimate === null
580
619
  ? 'Requires confirmed Notis bug evidence and an explicit bug-attributable cost. Misunderstandings and service limitations are not goodwill bugs.'
581
620
  : 'Capped at the lower of recorded provider cost and the explicitly attributed true-bug amount.',
582
- interactions,
621
+ interactions: interactions.map((item) => ({
622
+ ...item,
623
+ langfuse_trace_id_candidates: langfuseTraceIdCandidates(item.trace_id || item.id),
624
+ })),
583
625
  trace_file: traceDiagnostics,
584
626
  };
585
627
  return ctx.output.emitSuccess({
@@ -606,7 +648,42 @@ async function debugWorkerIdentityHandler(ctx) {
606
648
  });
607
649
  }
608
650
 
651
+ export function buildProcessDiagnosticsSql(reference) {
652
+ if (typeof reference !== 'string' || !reference.trim() || reference.length > 256) {
653
+ throw usageError('An interaction id of 1–256 characters is required.');
654
+ }
655
+ return `BEGIN READ ONLY; SET LOCAL request.jwt.claim.role='service_role'; SELECT public.notis_process_diagnostics_v1(${sqlLiteral(reference)}) AS diagnostic; COMMIT;`;
656
+ }
657
+
658
+ async function debugProcessHandler(ctx) {
659
+ const execution = await executeReadOnlySql(ctx, buildProcessDiagnosticsSql(ctx.args.interactionId), 'process');
660
+ const raw = execution.rows[0]?.diagnostic;
661
+ const diagnostic = typeof raw === 'string' ? JSON.parse(raw) : raw;
662
+ if (!diagnostic || diagnostic.definition_version !== 1 || diagnostic.status) {
663
+ throw usageError(`Process diagnostics unavailable: ${diagnostic?.status || 'invalid response'}.`);
664
+ }
665
+ if (diagnostic.interaction_id !== ctx.args.interactionId) throw usageError('Crossed diagnostic identity.');
666
+ return ctx.output.emitSuccess({
667
+ command: ctx.spec.command_path.join(' '), data: diagnostic, requestId: execution.requestId,
668
+ humanSummary: `${diagnostic.user_outcome}; ${diagnostic.handling}; ${diagnostic.reason_code || 'no incident'}.`,
669
+ meta: { mutating: false, sql_tool: execution.toolName },
670
+ renderHuman: () => JSON.stringify(diagnostic, null, 2),
671
+ });
672
+ }
673
+
609
674
  export const diagnosticCommandSpecs = [
675
+ {
676
+ command_path: ['debug', 'process'],
677
+ summary: 'Read receipt-backed process diagnostics for one interaction.',
678
+ when_to_use: 'Correlate an interaction with Temporal runs, private failure references, delivery and settlement.',
679
+ args_schema: { arguments: [{ token: '<interaction-id>', key: 'interactionId', description: 'Exact interaction id.' }], options: [] },
680
+ examples: ['notis debug process interaction_123 --json'],
681
+ output_schema: 'Versioned, content-free logical outcome, handling, workflow/run and evidence references.',
682
+ mutates: false, idempotent: true,
683
+ related_commands: ['notis debug worker-identity', 'notis debug trace-cost <trace-or-interaction>'],
684
+ backend_call: { type: 'tool-discovery', name: 'Supabase execute SQL capability' },
685
+ handler: debugProcessHandler,
686
+ },
610
687
  {
611
688
  command_path: ['debug', 'user-context'],
612
689
  summary: 'Resolve a user’s effective redacted runtime and billing context.',
@@ -0,0 +1,158 @@
1
+ import { usageError } from '../runtime/errors.js';
2
+ import { httpRequest } from '../runtime/transport.js';
3
+ import { unifiedDiffSummary, versionName } from './version-history.js';
4
+
5
+ const documentArgument = { token: '<document-id>', key: 'documentId', description: 'Exact document ID.' };
6
+ const versionOption = { flags: '--version-id <version-id>', description: 'Saved version ID from versions list.' };
7
+
8
+ async function remote(ctx, operation, { method = 'POST', body, query, humanSummary } = {}) {
9
+ const suffix = query ? `?${new URLSearchParams(Object.entries(query).filter(([, value]) => value != null))}` : '';
10
+ const result = await httpRequest({ runtime: ctx.runtime, method, path: `/portal_documents/${operation}${suffix}`, body, spacesProtocol: true });
11
+ return ctx.output.emitSuccess({ command: ctx.spec.command_path.join(' '), data: result.payload,
12
+ humanSummary: humanSummary ? humanSummary(result.payload) : JSON.stringify(result.payload, null, 2),
13
+ meta: { mutating: method !== 'GET', request_id: result.requestId } });
14
+ }
15
+
16
+ function versionId(options) {
17
+ if (typeof options.versionId !== 'string' || !options.versionId.trim()) throw usageError('Pass --version-id with a saved version ID from versions list.');
18
+ return options.versionId;
19
+ }
20
+
21
+ function limit(value) {
22
+ if (value === undefined) return undefined;
23
+ if (!/^\d+$/.test(value) || Number(value) < 1 || Number(value) > 100) throw usageError('Pass --limit as a whole number from 1 to 100.');
24
+ return Number(value);
25
+ }
26
+
27
+ function confirmed(options, what) {
28
+ if (!options.yes) throw usageError(`${what} cannot be undone. Only do it when the user asked, then pass --yes.`);
29
+ }
30
+
31
+ export const documentsCommandSpecs = [
32
+ {
33
+ command_path: ['documents', 'versions', 'list'],
34
+ summary: 'Read a document’s saved versions, newest first.',
35
+ when_to_use: 'See when and by whom a document changed, before comparing or restoring a version.',
36
+ args_schema: { arguments: [documentArgument], options: [
37
+ { flags: '--before <version-id>', description: 'Read versions older than this version.' },
38
+ { flags: '--limit <count>', description: 'How many versions to read (1 to 100).' },
39
+ ] },
40
+ examples: ['notis documents versions list <document-id>'], mutates: false, idempotent: true, require_auth: true,
41
+ backend_call: { type: 'http', path: '/portal_documents/versions' },
42
+ handler(ctx) {
43
+ return remote(ctx, 'versions', { method: 'GET', query: { document_id: ctx.args.documentId,
44
+ before: ctx.options.before, limit: limit(ctx.options.limit) } });
45
+ },
46
+ },
47
+ {
48
+ command_path: ['documents', 'versions', 'read'],
49
+ summary: 'Read one saved version of a document.',
50
+ when_to_use: 'See exactly what a saved version said, before comparing or restoring it.',
51
+ args_schema: { arguments: [documentArgument], options: [versionOption] },
52
+ examples: ['notis documents versions read <document-id> --version-id <version-id>'],
53
+ mutates: false, idempotent: true, require_auth: true,
54
+ backend_call: { type: 'http', path: '/portal_documents/versions/read' },
55
+ handler(ctx) {
56
+ return remote(ctx, 'versions/read', { method: 'GET', query: { document_id: ctx.args.documentId, version_id: versionId(ctx.options) } });
57
+ },
58
+ },
59
+ {
60
+ command_path: ['documents', 'versions', 'diff'],
61
+ summary: 'Compare two saved versions of a document, or one with the current version.',
62
+ when_to_use: 'See what changed between versions. Prints the unified diff; pass --json for the full comparison.',
63
+ args_schema: { arguments: [documentArgument], options: [
64
+ { flags: '--from <version-id>', description: 'The older saved version.' },
65
+ { flags: '--to <version-id>', description: 'The newer saved version, or current (default).' },
66
+ ] },
67
+ examples: ['notis documents versions diff <document-id> --from <version-id>',
68
+ 'notis documents versions diff <document-id> --from <version-id> --to <version-id> --json'],
69
+ mutates: false, idempotent: true, require_auth: true,
70
+ backend_call: { type: 'http', path: '/portal_documents/versions/diff' },
71
+ handler(ctx) {
72
+ if (typeof ctx.options.from !== 'string' || !ctx.options.from.trim()) throw usageError('Pass --from with a saved version ID from versions list.');
73
+ return remote(ctx, 'versions/diff', { method: 'GET', humanSummary: unifiedDiffSummary,
74
+ query: { document_id: ctx.args.documentId, from: ctx.options.from, to: ctx.options.to || 'current' } });
75
+ },
76
+ },
77
+ {
78
+ command_path: ['documents', 'versions', 'restore'],
79
+ summary: 'Bring a document back to a saved version; what it replaces is kept as a version.',
80
+ when_to_use: 'Undo changes to a document by restoring an earlier version.',
81
+ args_schema: { arguments: [documentArgument], options: [versionOption,
82
+ { flags: '--request-id <id>', description: 'Stable restore request ID; reuse on retry.' }] },
83
+ examples: ['notis documents versions restore <document-id> --version-id <version-id> --request-id undo-edit'],
84
+ mutates: true, idempotent: true, require_auth: true,
85
+ backend_call: { type: 'http', path: '/portal_documents/versions/restore' },
86
+ handler(ctx) {
87
+ const version = versionId(ctx.options);
88
+ if (!ctx.options.requestId) throw usageError('Pass a stable --request-id and reuse it on retry.');
89
+ return remote(ctx, 'versions/restore', { body: { document_id: ctx.args.documentId, version_id: version,
90
+ request_id: ctx.options.requestId } });
91
+ },
92
+ },
93
+ {
94
+ command_path: ['documents', 'versions', 'name'],
95
+ summary: 'Name a saved version of a document, or clear its name.',
96
+ when_to_use: 'Mark a version worth keeping. Named versions are kept past the usual retention.',
97
+ args_schema: { arguments: [documentArgument], options: [versionOption,
98
+ { flags: '--name <name>', description: 'The version name.' },
99
+ { flags: '--clear', description: 'Remove the version name.' }] },
100
+ examples: ['notis documents versions name <document-id> --version-id <version-id> --name "Final draft"'],
101
+ mutates: true, idempotent: true, require_auth: true,
102
+ backend_call: { type: 'http', path: '/portal_documents/versions/name' },
103
+ handler(ctx) {
104
+ return remote(ctx, 'versions/name', { body: { document_id: ctx.args.documentId, version_id: versionId(ctx.options),
105
+ name: versionName(ctx.options) } });
106
+ },
107
+ },
108
+ {
109
+ command_path: ['documents', 'versions', 'delete'],
110
+ summary: 'Delete one saved version of a document for good.',
111
+ when_to_use: 'Only when the user asked to delete this version. It cannot be restored afterwards.',
112
+ args_schema: { arguments: [documentArgument], options: [versionOption,
113
+ { flags: '--yes', description: 'Confirm the user asked to delete this version for good.' }] },
114
+ examples: ['notis documents versions delete <document-id> --version-id <version-id> --yes'],
115
+ mutates: true, idempotent: true, require_auth: true,
116
+ backend_call: { type: 'http', path: '/portal_documents/versions/delete' },
117
+ handler(ctx) {
118
+ const version = versionId(ctx.options);
119
+ confirmed(ctx.options, 'Deleting a saved version');
120
+ return remote(ctx, 'versions/delete', { body: { document_id: ctx.args.documentId, version_id: version } });
121
+ },
122
+ },
123
+ {
124
+ command_path: ['documents', 'bin', 'list'],
125
+ summary: 'List the documents in your Bin.',
126
+ when_to_use: 'Find a deleted document to bring back, or to remove for good.',
127
+ args_schema: { arguments: [], options: [] },
128
+ examples: ['notis documents bin list'], mutates: false, idempotent: true, require_auth: true,
129
+ backend_call: { type: 'http', path: '/portal_documents/bin' },
130
+ handler(ctx) {
131
+ return remote(ctx, 'bin', { method: 'GET' });
132
+ },
133
+ },
134
+ {
135
+ command_path: ['documents', 'bin', 'restore'],
136
+ summary: 'Bring a document back from the Bin.',
137
+ when_to_use: 'Undo deleting a document.',
138
+ args_schema: { arguments: [documentArgument], options: [] },
139
+ examples: ['notis documents bin restore <document-id>'], mutates: true, idempotent: true, require_auth: true,
140
+ backend_call: { type: 'http', path: '/portal_documents/bin/restore' },
141
+ handler(ctx) {
142
+ return remote(ctx, 'bin/restore', { body: { document_id: ctx.args.documentId } });
143
+ },
144
+ },
145
+ {
146
+ command_path: ['documents', 'bin', 'remove'],
147
+ summary: 'Remove a document from the Bin for good.',
148
+ when_to_use: 'Only when the user asked to remove this document for good. It cannot be brought back afterwards.',
149
+ args_schema: { arguments: [documentArgument], options: [
150
+ { flags: '--yes', description: 'Confirm the user asked to remove this document for good.' }] },
151
+ examples: ['notis documents bin remove <document-id> --yes'], mutates: true, idempotent: true, require_auth: true,
152
+ backend_call: { type: 'http', path: '/portal_documents/bin/remove' },
153
+ handler(ctx) {
154
+ confirmed(ctx.options, 'Removing a document from the Bin');
155
+ return remote(ctx, 'bin/remove', { body: { document_id: ctx.args.documentId } });
156
+ },
157
+ },
158
+ ];
@@ -0,0 +1,29 @@
1
+ import { uploadNativeRecordFileWithCliRuntime } from '../runtime/native-record-files.js';
2
+ import { parseJson } from './helpers.js';
3
+ import { usageError } from '../runtime/errors.js';
4
+
5
+ export const filesCommandSpecs = [{
6
+ command_path: ['files', 'upload'],
7
+ summary: 'Upload a local file for one native record you can edit.',
8
+ when_to_use: 'Save file bytes without a cloud computer; attach the returned file reference through a normal revision-checked row update.',
9
+ args_schema: { arguments: [{ token: '<file>', key: 'file', description: 'Local regular file up to 8 MB.' }], options: [
10
+ { flags: '--target <json>', description: 'Exact native target returned by schema discovery.' },
11
+ { flags: '--record-key <id>', description: 'Stable record key to attach this file to.' },
12
+ { flags: '--schema-revision <number>', description: 'Current native schema revision.' },
13
+ { flags: '--request-id <uuid>', description: 'Stable UUID; reuse with identical bytes after an uncertain response.' },
14
+ { flags: '--name <name>', description: 'Attachment name; defaults to the local basename.' },
15
+ { flags: '--content-type <mime>', description: 'File MIME type; inferred from known extensions.' },
16
+ ] },
17
+ examples: ['notis files upload ./report.html --target \'{"database_id":"<database-id>"}\' --record-key <record-key> --schema-revision 1 --request-id <uuid>'],
18
+ mutates: true, idempotent: true, require_auth: true,
19
+ backend_call: { type: 'http', path: '/portal_native_files/upload' },
20
+ async handler(ctx) {
21
+ if (!ctx.options.target || ctx.options.schemaRevision === undefined) throw usageError('Pass the discovered native --target and --schema-revision.');
22
+ const result = await uploadNativeRecordFileWithCliRuntime({ runtime: ctx.runtime, filePath: ctx.args.file,
23
+ target: parseJson(ctx.options.target, '--target'), recordKey: ctx.options.recordKey,
24
+ schemaRevision: Number(ctx.options.schemaRevision), requestId: ctx.options.requestId,
25
+ ...(ctx.options.name ? { name: ctx.options.name } : {}), ...(ctx.options.contentType ? { contentType: ctx.options.contentType } : {}) });
26
+ return ctx.output.emitSuccess({ command: 'files upload', data: result,
27
+ humanSummary: 'Uploaded and verified the file. Attach the returned file reference with a revision-checked record update.', meta: { mutating: true } });
28
+ },
29
+ }];