@notis_ai/cli 0.2.0-beta.35.1 → 0.2.0-beta.41.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +80 -75
  2. package/dist/scaffolds/notis-database/app/globals.css +44 -0
  3. package/dist/scaffolds/notis-database/app/page.tsx +1091 -0
  4. package/dist/scaffolds/notis-database/components/ui/table.tsx +120 -0
  5. package/dist/scaffolds/notis-database/index.html +12 -0
  6. package/dist/scaffolds/notis-database/lib/types.ts +134 -0
  7. package/dist/scaffolds/notis-database/metadata/cover.png +0 -0
  8. package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
  9. package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
  10. package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
  11. package/dist/scaffolds/notis-database/notis.config.ts +27 -0
  12. package/dist/scaffolds/notis-database/package.json +31 -0
  13. package/dist/scaffolds/notis-database/src/dev-main.tsx +23 -0
  14. package/dist/scaffolds/notis-database/src/mock-runtime.ts +557 -0
  15. package/dist/scaffolds/notis-database/tailwind.config.ts +59 -0
  16. package/dist/scaffolds/{notes → notis-database}/tsconfig.json +2 -1
  17. package/dist/scaffolds/notis-database/vite.config.ts +22 -0
  18. package/dist/scaffolds/notis-notes/app/layout.tsx +6 -0
  19. package/dist/scaffolds/{notes → notis-notes}/app/page.tsx +783 -80
  20. package/dist/scaffolds/notis-notes/components/ui/badge.tsx +28 -0
  21. package/dist/scaffolds/notis-notes/components/ui/button.tsx +53 -0
  22. package/dist/scaffolds/notis-notes/components/ui/card.tsx +56 -0
  23. package/dist/scaffolds/notis-notes/components.json +20 -0
  24. package/dist/scaffolds/notis-notes/lib/utils.ts +6 -0
  25. package/dist/scaffolds/notis-notes/metadata/cover.png +0 -0
  26. package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
  27. package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
  28. package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
  29. package/dist/scaffolds/{notes → notis-notes}/notis.config.ts +12 -7
  30. package/dist/scaffolds/{notes → notis-notes}/package.json +3 -3
  31. package/dist/scaffolds/notis-notes/postcss.config.mjs +8 -0
  32. package/dist/scaffolds/notis-notes/tsconfig.json +23 -0
  33. package/dist/scaffolds/notis-random/README.md +33 -0
  34. package/dist/scaffolds/notis-random/app/globals.css +11 -0
  35. package/dist/scaffolds/notis-random/app/history/page.tsx +66 -0
  36. package/dist/scaffolds/notis-random/app/layout.tsx +7 -0
  37. package/dist/scaffolds/notis-random/app/page.tsx +222 -0
  38. package/dist/scaffolds/notis-random/index.html +12 -0
  39. package/dist/scaffolds/notis-random/lib/notis-tools.ts +109 -0
  40. package/dist/scaffolds/notis-random/lib/rng.ts +42 -0
  41. package/dist/scaffolds/notis-random/lib/roll-record.ts +102 -0
  42. package/dist/scaffolds/notis-random/lib/utils.ts +25 -0
  43. package/dist/scaffolds/notis-random/metadata/cover.png +0 -0
  44. package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
  45. package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
  46. package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
  47. package/dist/scaffolds/notis-random/notis.config.ts +43 -0
  48. package/dist/scaffolds/notis-random/package.json +32 -0
  49. package/dist/scaffolds/notis-random/postcss.config.mjs +6 -0
  50. package/dist/scaffolds/notis-random/src/dev-main.tsx +70 -0
  51. package/dist/scaffolds/notis-random/src/mock-runtime.ts +128 -0
  52. package/dist/scaffolds/notis-random/tailwind.config.ts +43 -0
  53. package/dist/scaffolds/notis-random/tsconfig.json +23 -0
  54. package/dist/scaffolds/notis-random/vite.config.ts +11 -0
  55. package/dist/scaffolds.json +27 -4
  56. package/package.json +1 -1
  57. package/skills/notis-apps/SKILL.md +27 -33
  58. package/skills/notis-apps/cli.md +51 -51
  59. package/skills/notis-cli/SKILL.md +65 -70
  60. package/skills/notis-query/cli.md +11 -11
  61. package/src/cli.js +10 -1
  62. package/src/command-specs/apps.js +2 -2
  63. package/src/command-specs/helpers.js +2 -0
  64. package/src/command-specs/tools.js +100 -2
  65. package/src/runtime/app-dev-server.js +2 -2
  66. package/src/runtime/app-platform.js +28 -0
  67. package/src/runtime/transport.js +129 -17
  68. package/template/packages/sdk/package.json +6 -0
  69. package/template/packages/sdk/src/hooks/useDatabase.ts +76 -0
  70. package/template/packages/sdk/src/hooks/useNotis.ts +10 -6
  71. package/template/packages/sdk/src/hooks/useUpsertDocument.ts +50 -0
  72. package/template/packages/sdk/src/index.ts +9 -1
  73. package/template/packages/sdk/src/runtime.ts +83 -2
  74. /package/dist/scaffolds/{notes → notis-database}/app/layout.tsx +0 -0
  75. /package/dist/scaffolds/{notes → notis-database}/components/ui/badge.tsx +0 -0
  76. /package/dist/scaffolds/{notes → notis-database}/components/ui/button.tsx +0 -0
  77. /package/dist/scaffolds/{notes → notis-database}/components/ui/card.tsx +0 -0
  78. /package/dist/scaffolds/{notes → notis-database}/components.json +0 -0
  79. /package/dist/scaffolds/{notes → notis-database}/lib/utils.ts +0 -0
  80. /package/dist/scaffolds/{notes → notis-database}/postcss.config.mjs +0 -0
  81. /package/dist/scaffolds/{notes → notis-notes}/app/globals.css +0 -0
  82. /package/dist/scaffolds/{notes → notis-notes}/tailwind.config.ts +0 -0
  83. /package/dist/scaffolds/{notes → notis-notes}/vite.config.ts +0 -0
@@ -22,18 +22,13 @@ Activate this skill when:
22
22
  - the user wants to use an integration-backed capability through Notis rather than a first-class local tool
23
23
  - the task mentions the `notis` CLI directly
24
24
 
25
- In a **Vercel Sandbox** or hosted shell environment, use the registry-resolved published npm package:
25
+ Use the registry-resolved published npm package everywhere:
26
26
 
27
- - `npm exec --yes --package @notis_ai/cli@latest -- notis ...`
27
+ - `npx --package @notis_ai/cli@latest -- notis ...`
28
28
 
29
- Do not rely on a globally installed `notis` binary in a sandbox. It may come from an older snapshot. The CLI is pre-authenticated through `NOTIS_JWT`, so this registry-resolved command works without local login state.
29
+ Always use this NPX command form so the agent runs the current published CLI. In hosted shells, the CLI is pre-authenticated through `NOTIS_JWT`; locally, Notis Desktop keeps the CLI auth profile current for NPX invocations.
30
30
 
31
- In a **local repo workspace**, prefer the repo-local CLI entrypoint:
32
-
33
- - from the repo root: `node packages/cli/bin/notis.js ...`
34
- - from app workspaces under `.context/`: `node ../../packages/cli/bin/notis.js ...`
35
-
36
- The Notis desktop app automatically installs and keeps this `notis-cli` skill updated alongside the `notis-apps` skill for local agents. No separate manual skill install is needed on desktop.
31
+ Notis Desktop keeps the CLI auth profile current for NPX runs. This `notis-cli` skill is delivered through normal Notis skill sync for the signed-in user, alongside other curated skills.
37
32
 
38
33
  ## Critical rule for missing tools
39
34
 
@@ -61,47 +56,47 @@ Important: `deploy` means updating the installed app artifact for the current us
61
56
  ### App development workflow
62
57
 
63
58
  1. Scaffold a new app:
64
- - `node packages/cli/bin/notis.js apps init`
59
+ - `npx --package @notis_ai/cli@latest -- notis apps init`
65
60
  2. Or pull an existing app's source to edit it locally (the project is linked automatically):
66
- - `node packages/cli/bin/notis.js apps pull <app-id>`
67
- - then run `npm install`, `node packages/cli/bin/notis.js apps dev`, edit, build, and deploy
61
+ - `npx --package @notis_ai/cli@latest -- notis apps pull <app-id>`
62
+ - then run `npm install`, `npx --package @notis_ai/cli@latest -- notis apps dev`, edit, build, and deploy
68
63
  3. Develop locally with live reload:
69
- - `node packages/cli/bin/notis.js apps dev`
64
+ - `npx --package @notis_ai/cli@latest -- notis apps dev`
70
65
  4. Build the production artifact:
71
- - `node packages/cli/bin/notis.js apps build`
66
+ - `npx --package @notis_ai/cli@latest -- notis apps build`
72
67
  5. Verify the built artifact headlessly:
73
- - `node packages/cli/bin/notis.js apps verify`
68
+ - `npx --package @notis_ai/cli@latest -- notis apps verify`
74
69
  6. For a brand-new app, create the remote app and link the project in one step:
75
- - `node packages/cli/bin/notis.js apps create "My App" .`
70
+ - `npx --package @notis_ai/cli@latest -- notis apps create "My App" .`
76
71
  7. Or link the project to an existing remote app (skip if you used `pull` or `create`):
77
- - `node packages/cli/bin/notis.js apps link`
72
+ - `npx --package @notis_ai/cli@latest -- notis apps link`
78
73
  8. Deploy the artifact to Notis:
79
- - `node packages/cli/bin/notis.js apps deploy`
74
+ - `npx --package @notis_ai/cli@latest -- notis apps deploy`
80
75
  9. Check project health:
81
- - `node packages/cli/bin/notis.js apps doctor`
76
+ - `npx --package @notis_ai/cli@latest -- notis apps doctor`
82
77
 
83
78
  ### App development rules
84
79
 
85
80
  - Always `build` before `deploy`; run `verify` before deploy when validating an app change.
86
- - Prefer `node packages/cli/bin/notis.js apps create "Name" .` for the first deploy of a new app.
81
+ - Prefer `npx --package @notis_ai/cli@latest -- notis apps create "Name" .` for the first deploy of a new app.
87
82
  - Link before `deploy`, or pass `--app-id <id>` when intentionally deploying without writing local link state.
88
- - Use `node packages/cli/bin/notis.js apps doctor` to diagnose configuration or dependency issues.
89
- - Use `node packages/cli/bin/notis.js apps list` to discover existing app IDs before linking.
83
+ - Use `npx --package @notis_ai/cli@latest -- notis apps doctor` to diagnose configuration or dependency issues.
84
+ - Use `npx --package @notis_ai/cli@latest -- notis apps list` to discover existing app IDs before linking.
90
85
  - For App Store publishing, do not use the CLI. The user opens the app details page in the Notis Portal, sets visibility to Team or Public, then uses Publish/Update. The backend opens the registry PR on their behalf using a service token. Do not invent any CLI store-publish command.
91
86
 
92
87
  ### App development command reference
93
88
 
94
- - `node packages/cli/bin/notis.js apps list` -- list accessible apps
95
- - `node packages/cli/bin/notis.js apps init` -- scaffold a new Vite + React + `@notis/sdk` project
96
- - `node packages/cli/bin/notis.js apps pull <app-id> [dir] [--force] [--version <n>]` -- download the persisted source snapshot for an installed app and link the local directory to that app/version; legacy apps must be redeployed once with the current CLI before they can be pulled
97
- - `node packages/cli/bin/notis.js apps dev` -- discover local apps, register desktop-local dev sessions, and load them in the Electron Portal Local development sidebar group
98
- - `node packages/cli/bin/notis.js apps build` -- compile the production artifact
99
- - `node packages/cli/bin/notis.js apps verify` -- headless render-smoke packaged routes before deploy
100
- - `node packages/cli/bin/notis.js apps create` -- create a fresh remote app and optionally link the local project
101
- - `node packages/cli/bin/notis.js apps link` -- associate the project with a remote app
102
- - `node packages/cli/bin/notis.js apps deploy` -- upload the artifact and editable source snapshot to the linked installed app in Notis
103
- - `node packages/cli/bin/notis.js apps deploy --direct` -- deploy directly to Supabase storage, bypassing the backend server (auto-fallback when server is down)
104
- - `node packages/cli/bin/notis.js apps doctor` -- run project diagnostics
89
+ - `npx --package @notis_ai/cli@latest -- notis apps list` -- list accessible apps
90
+ - `npx --package @notis_ai/cli@latest -- notis apps init` -- scaffold a new Vite + React + `@notis/sdk` project
91
+ - `npx --package @notis_ai/cli@latest -- notis apps pull <app-id> [dir] [--force] [--version <n>]` -- download the persisted source snapshot for an installed app and link the local directory to that app/version; legacy apps must be redeployed once with the current CLI before they can be pulled
92
+ - `npx --package @notis_ai/cli@latest -- notis apps dev` -- discover local apps, register desktop-local dev sessions, and load them in the Electron Portal Local development sidebar group
93
+ - `npx --package @notis_ai/cli@latest -- notis apps build` -- compile the production artifact
94
+ - `npx --package @notis_ai/cli@latest -- notis apps verify` -- headless render-smoke packaged routes before deploy
95
+ - `npx --package @notis_ai/cli@latest -- notis apps create` -- create a fresh remote app and optionally link the local project
96
+ - `npx --package @notis_ai/cli@latest -- notis apps link` -- associate the project with a remote app
97
+ - `npx --package @notis_ai/cli@latest -- notis apps deploy` -- upload the artifact and editable source snapshot to the linked installed app in Notis
98
+ - `npx --package @notis_ai/cli@latest -- notis apps deploy --direct` -- deploy directly to Supabase storage, bypassing the backend server (auto-fallback when server is down)
99
+ - `npx --package @notis_ai/cli@latest -- notis apps doctor` -- run project diagnostics
105
100
 
106
101
  App Store publishing is portal-only — there is no CLI publish command.
107
102
 
@@ -109,14 +104,14 @@ If the task is specifically about app structure, runtime behavior, or database/v
109
104
 
110
105
  ## IMPORTANT: When NOT to use tool access for app development
111
106
 
112
- When building or deploying a Notis app, do NOT use `notis tools exec` for any of these operations:
107
+ When building or deploying a Notis app, do NOT use `npx --package @notis_ai/cli@latest -- notis tools exec` for any of these operations:
113
108
 
114
109
  - Creating databases -- declare them in `notis.config.ts` instead
115
- - Loading or saving app files -- use `notis apps build` and `notis apps deploy`
116
- - Linting app files -- use `notis apps build` which validates automatically
110
+ - Loading or saving app files -- use `npx --package @notis_ai/cli@latest -- notis apps build` and `npx --package @notis_ai/cli@latest -- notis apps deploy`
111
+ - Linting app files -- use `npx --package @notis_ai/cli@latest -- notis apps build` which validates automatically
117
112
  - Managing app routes -- write standard Vite + React pages in `app/`, not raw JS files
118
113
 
119
- The only `notis tools exec` calls that are valid during app development are for testing the app's runtime behavior after deployment (e.g., querying a database to verify data was created).
114
+ The only `npx --package @notis_ai/cli@latest -- notis tools exec` calls that are valid during app development are for testing the app's runtime behavior after deployment (e.g., querying a database to verify data was created).
120
115
 
121
116
  ## Section 2: Accessing Tools Through the Notis CLI
122
117
 
@@ -132,29 +127,29 @@ This is the main escape hatch for:
132
127
  ### Tool access workflow
133
128
 
134
129
  1. List available toolkit namespaces:
135
- - `notis tools toolkits`
130
+ - `npx --package @notis_ai/cli@latest -- notis tools toolkits`
136
131
  2. Search for the capability you need using natural language:
137
- - `notis tools search "<query>"`
132
+ - `npx --package @notis_ai/cli@latest -- notis tools search "<query>"`
138
133
  - optionally narrow with `--toolkits <csv-or-json>`
139
134
  3. If needed, inspect the exact tool and parameter schema:
140
- - `notis tools describe <tool-name>`
141
- - `notis tools exec <tool-name> --get-schema`
135
+ - `npx --package @notis_ai/cli@latest -- notis tools describe <tool-name>`
136
+ - `npx --package @notis_ai/cli@latest -- notis tools exec <tool-name> --get-schema`
142
137
  4. Validate arguments before execution when the tool is mutating or the schema is non-trivial:
143
- - `notis tools exec <tool-name> --dry-run --arguments '<json>'`
138
+ - `npx --package @notis_ai/cli@latest -- notis tools exec <tool-name> --dry-run --arguments '<json>'`
144
139
  5. Execute the tool:
145
- - `notis tools exec <tool-name> --arguments '<json>'`
140
+ - `npx --package @notis_ai/cli@latest -- notis tools exec <tool-name> --arguments '<json>'`
146
141
  6. If multiple independent calls are needed, use:
147
- - `notis tools exec-parallel '<json-array>'`
142
+ - `npx --package @notis_ai/cli@latest -- notis tools exec-parallel '<json-array>'`
148
143
  7. If the toolkit is not connected yet, generate the connection URL:
149
- - `notis tools link <toolkit>`
144
+ - `npx --package @notis_ai/cli@latest -- notis tools link <toolkit>`
150
145
 
151
146
  ### Tool access rules
152
147
 
153
- - Never guess tool names. Discover them with `notis tools search` first.
154
- - Prefer first-class CLI commands when they exist, but use `notis tools ...` whenever the capability is not covered by a dedicated command.
155
- - When you know the tool name but not the argument shape, use `notis tools describe` or `--get-schema` before execution.
148
+ - Never guess tool names. Discover them with `npx --package @notis_ai/cli@latest -- notis tools search` first.
149
+ - Prefer first-class CLI commands when they exist, but use `npx --package @notis_ai/cli@latest -- notis tools ...` whenever the capability is not covered by a dedicated command.
150
+ - When you know the tool name but not the argument shape, use `npx --package @notis_ai/cli@latest -- notis tools describe` or `--get-schema` before execution.
156
151
  - Use `--dry-run` before mutating calls when you want schema validation without execution.
157
- - If a toolkit is missing, use `notis tools link <toolkit>` to start the connection flow.
152
+ - If a toolkit is missing, use `npx --package @notis_ai/cli@latest -- notis tools link <toolkit>` to start the connection flow.
158
153
 
159
154
  ### Toolkit mental model
160
155
 
@@ -176,35 +171,35 @@ The pattern is:
176
171
  Find a tool:
177
172
 
178
173
  ```bash
179
- notis tools toolkits
180
- notis tools search "list today's calendar events"
174
+ npx --package @notis_ai/cli@latest -- notis tools toolkits
175
+ npx --package @notis_ai/cli@latest -- notis tools search "list today's calendar events"
181
176
  ```
182
177
 
183
178
  Inspect a tool before execution:
184
179
 
185
180
  ```bash
186
- notis tools describe composio-googlecalendar-default-list_events
187
- notis tools exec composio-googlecalendar-default-list_events --get-schema
181
+ npx --package @notis_ai/cli@latest -- notis tools describe composio-googlecalendar-default-list_events
182
+ npx --package @notis_ai/cli@latest -- notis tools exec composio-googlecalendar-default-list_events --get-schema
188
183
  ```
189
184
 
190
185
  Dry-run a tool call:
191
186
 
192
187
  ```bash
193
- notis tools exec notis-default-query --dry-run --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
194
- notis tools exec notis-default-get_database --dry-run --arguments '{"database_slug":"tasks"}'
188
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-query --dry-run --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
189
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --dry-run --arguments '{"database_slug":"tasks"}'
195
190
  ```
196
191
 
197
192
  Execute a tool call:
198
193
 
199
194
  ```bash
200
- notis tools exec notis-default-query --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
201
- notis tools exec notis-default-get_database --arguments '{"database_slug":"tasks"}'
195
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-query --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
196
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --arguments '{"database_slug":"tasks"}'
202
197
  ```
203
198
 
204
199
  Connect a missing toolkit:
205
200
 
206
201
  ```bash
207
- notis tools link github
202
+ npx --package @notis_ai/cli@latest -- notis tools link github
208
203
  ```
209
204
 
210
205
  ## Native database access
@@ -219,24 +214,24 @@ Native Notis databases are accessed through the generic tool workflow, not a fir
219
214
  Example workflow before building an app:
220
215
 
221
216
  ```bash
222
- notis tools search "list Notis databases"
223
- notis tools exec notis-default-list_databases --arguments '{}'
224
- notis tools exec notis-default-get_database --get-schema
225
- notis tools exec notis-default-get_database --arguments '{"database_slug":"social_media_calendar"}'
226
- notis tools exec notis-default-query --arguments '{"database_slug":"social_media_calendar","query":{"page_size":1}}'
217
+ npx --package @notis_ai/cli@latest -- notis tools search "list Notis databases"
218
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-list_databases --arguments '{}'
219
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --get-schema
220
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --arguments '{"database_slug":"social_media_calendar"}'
221
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-query --arguments '{"database_slug":"social_media_calendar","query":{"page_size":1}}'
227
222
  ```
228
223
 
229
224
  ## Supporting commands
230
225
 
231
- - `notis doctor` — verify CLI config, auth, and API reachability before relying on the CLI
232
- - `notis describe <command...>` — get the exact command contract for first-class CLI commands
226
+ - `npx --package @notis_ai/cli@latest -- notis doctor` — verify CLI config, auth, and API reachability before relying on the CLI
227
+ - `npx --package @notis_ai/cli@latest -- notis describe <command...>` — get the exact command contract for first-class CLI commands
233
228
 
234
229
  ## Summary
235
230
 
236
231
  Use `notis-cli` for two things:
237
232
 
238
- 1. local app development through `notis apps ...`
239
- 2. tool discovery and execution through `notis tools ...`
233
+ 1. local app development through `npx --package @notis_ai/cli@latest -- notis apps ...`
234
+ 2. tool discovery and execution through `npx --package @notis_ai/cli@latest -- notis tools ...`
240
235
 
241
236
  Most importantly: if you do not currently have the tool you need, especially for direct MCP or integration work, use the Notis CLI instead of treating the task as blocked.
242
237
 
@@ -246,11 +241,11 @@ Most importantly: if you do not currently have the tool you need, especially for
246
241
 
247
242
  The backend server at `http://localhost:3001` is not running. Solutions:
248
243
 
249
- 1. Use `--direct` flag: `notis apps deploy --direct` uploads to Supabase storage directly
244
+ 1. Use `--direct` flag: `npx --package @notis_ai/cli@latest -- notis apps deploy --direct` uploads to Supabase storage directly
250
245
  2. Start the backend server: `cd server && python3 main.py`
251
- 3. Check the API base: `notis doctor` shows the configured `api_base`
246
+ 3. Check the API base: `npx --package @notis_ai/cli@latest -- notis doctor` shows the configured `api_base`
252
247
 
253
- ### `notis doctor` shows health/tool_roundtrip errors
248
+ ### `npx --package @notis_ai/cli@latest -- notis doctor` shows health/tool_roundtrip errors
254
249
 
255
250
  The CLI health check pings the backend server. If it's not running, these checks fail. App development commands that are `backend_call: local` (`init`, `build`, `verify`, `link`, `doctor`) work without the server. `dev`, `pull`, `create`, `list`, and normal `deploy` need the backend; `deploy --direct` can bypass it when Supabase credentials are available.
256
251
 
@@ -1,10 +1,10 @@
1
1
  # Notis CLI — Database Tool Workflow
2
2
 
3
- Use the generic `notis tools` workflow for native Notis Database operations from the terminal. The dedicated database command group has been removed.
3
+ Use the generic `notis tools` workflow through NPX for native Notis Database operations from the terminal. The dedicated database command group has been removed.
4
4
 
5
5
  ## Setup
6
6
 
7
- Install and sign into Notis Desktop. The desktop app installs the `notis` command and keeps the CLI profile current.
7
+ Install and sign into Notis Desktop to keep the CLI profile current. Run the CLI through NPX, for example `npx --package @notis_ai/cli@latest -- notis tools search "list Notis databases"`.
8
8
 
9
9
  For CI, hosted agents, or internal scripts, pass a non-persisted token with `NOTIS_JWT=<token>` and use `--api-base <server-url>` when targeting a non-default server.
10
10
 
@@ -18,23 +18,23 @@ For CI, hosted agents, or internal scripts, pass a non-persisted token with `NOT
18
18
  ## Workflow
19
19
 
20
20
  ```bash
21
- notis tools search "list Notis databases"
22
- notis tools exec notis-default-list_databases --arguments '{}'
23
- notis tools exec notis-default-get_database --get-schema
24
- notis tools exec notis-default-get_database --arguments '{"database_slug":"tasks"}'
25
- notis tools exec notis-default-query --dry-run --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
26
- notis tools exec notis-default-query --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
21
+ npx --package @notis_ai/cli@latest -- notis tools search "list Notis databases"
22
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-list_databases --arguments '{}'
23
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --get-schema
24
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-get_database --arguments '{"database_slug":"tasks"}'
25
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-query --dry-run --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
26
+ npx --package @notis_ai/cli@latest -- notis tools exec notis-default-query --arguments '{"database_slug":"tasks","query":{"page_size":10}}'
27
27
  ```
28
28
 
29
29
  ## Supporting command
30
30
 
31
- ### `notis doctor`
31
+ ### `npx --package @notis_ai/cli@latest -- notis doctor`
32
32
 
33
33
  Run a quick CLI health check for config, auth, and API reachability.
34
34
 
35
35
  When to use: Use this before relying on the CLI in automation or after changing environments.
36
36
 
37
37
  Examples:
38
- - `notis doctor`
39
- - `notis doctor --json`
38
+ - `npx --package @notis_ai/cli@latest -- notis doctor`
39
+ - `npx --package @notis_ai/cli@latest -- notis doctor --json`
40
40
 
package/src/cli.js CHANGED
@@ -64,7 +64,16 @@ function attachSpec(program, parentMap, spec, specs) {
64
64
  }
65
65
 
66
66
  for (const option of spec.args_schema?.options || []) {
67
- command.option(option.flags, option.description);
67
+ if (option.collect) {
68
+ command.option(
69
+ option.flags,
70
+ option.description,
71
+ (value, previous) => [...(previous || []), value],
72
+ [],
73
+ );
74
+ } else {
75
+ command.option(option.flags, option.description);
76
+ }
68
77
  }
69
78
 
70
79
  command.action(async (...raw) => {
@@ -381,8 +381,8 @@ export function buildEnsureDevInstallArguments({ appConfig, manifest, linkedStat
381
381
  name: appConfig.name,
382
382
  manifest,
383
383
  };
384
- if (linkedState?.app_id) {
385
- arguments_.app_id = linkedState.app_id;
384
+ if (linkedState?.dev_app_id) {
385
+ arguments_.app_id = linkedState.dev_app_id;
386
386
  }
387
387
  return arguments_;
388
388
  }
@@ -44,12 +44,14 @@ export async function runToolCommand({
44
44
  arguments_ = {},
45
45
  mutating = false,
46
46
  idempotencyKey,
47
+ fileBindings = [],
47
48
  }) {
48
49
  const result = await callTool({
49
50
  runtime: { ...runtime, mutating },
50
51
  toolName,
51
52
  arguments_,
52
53
  idempotencyKey: mutating ? idempotencyKey : null,
54
+ fileBindings,
53
55
  });
54
56
  return result;
55
57
  }
@@ -1,4 +1,6 @@
1
- import { existsSync, readFileSync } from 'node:fs';
1
+ import { accessSync, constants as fsConstants, createReadStream, existsSync, readFileSync, statSync } from 'node:fs';
2
+ import { createHash } from 'node:crypto';
3
+ import { basename } from 'node:path';
2
4
  import { usageError } from '../runtime/errors.js';
3
5
  import {
4
6
  fetchToolkits,
@@ -42,6 +44,89 @@ const LONG_RUNNING_TOOL_NAMES = new Set([
42
44
  'notis-default-edit_image_gemini',
43
45
  ]);
44
46
 
47
+ const EXTENSION_CONTENT_TYPES = new Map([
48
+ ['.pdf', 'application/pdf'],
49
+ ['.png', 'image/png'],
50
+ ['.jpg', 'image/jpeg'],
51
+ ['.jpeg', 'image/jpeg'],
52
+ ['.gif', 'image/gif'],
53
+ ['.webp', 'image/webp'],
54
+ ['.txt', 'text/plain'],
55
+ ['.csv', 'text/csv'],
56
+ ['.json', 'application/json'],
57
+ ['.md', 'text/markdown'],
58
+ ]);
59
+
60
+ function guessContentType(filePath) {
61
+ const lower = filePath.toLowerCase();
62
+ const dotIndex = lower.lastIndexOf('.');
63
+ if (dotIndex === -1) return 'application/octet-stream';
64
+ return EXTENSION_CONTENT_TYPES.get(lower.slice(dotIndex)) || 'application/octet-stream';
65
+ }
66
+
67
+ async function hashFileSha256(localPath) {
68
+ const hash = createHash('sha256');
69
+ for await (const chunk of createReadStream(localPath)) {
70
+ hash.update(chunk);
71
+ }
72
+ return hash.digest('hex');
73
+ }
74
+
75
+ async function parseFileBindingSpec(spec, index) {
76
+ if (typeof spec !== 'string' || !spec.trim()) {
77
+ throw usageError('--file must be formatted as <argument-path>=<local-path>');
78
+ }
79
+
80
+ const equalsIndex = spec.indexOf('=');
81
+ if (equalsIndex <= 0 || equalsIndex === spec.length - 1) {
82
+ throw usageError('--file must be formatted as <argument-path>=<local-path>');
83
+ }
84
+
85
+ const argumentPath = spec.slice(0, equalsIndex).trim();
86
+ const localPath = spec.slice(equalsIndex + 1).trim();
87
+ if (!argumentPath) {
88
+ throw usageError('--file argument path is required');
89
+ }
90
+ if (!localPath) {
91
+ throw usageError('--file local path is required');
92
+ }
93
+ if (!existsSync(localPath)) {
94
+ throw usageError(`File not found: ${localPath}`);
95
+ }
96
+
97
+ let stats;
98
+ try {
99
+ stats = statSync(localPath);
100
+ accessSync(localPath, fsConstants.R_OK);
101
+ } catch {
102
+ throw usageError(`File is not readable: ${localPath}`);
103
+ }
104
+ if (!stats.isFile()) {
105
+ throw usageError(`File is not a regular file: ${localPath}`);
106
+ }
107
+
108
+ const sha256 = await hashFileSha256(localPath);
109
+ const fileBasename = basename(localPath);
110
+ const fieldName = `file_${index}`;
111
+
112
+ return {
113
+ argument_path: argumentPath,
114
+ field_name: fieldName,
115
+ basename: fileBasename,
116
+ size: stats.size,
117
+ sha256,
118
+ contentType: guessContentType(fileBasename),
119
+ localPath,
120
+ };
121
+ }
122
+
123
+ async function parseFileBindings(rawFileOptions) {
124
+ const values = Array.isArray(rawFileOptions)
125
+ ? rawFileOptions
126
+ : (rawFileOptions ? [rawFileOptions] : []);
127
+ return Promise.all(values.map((value, index) => parseFileBindingSpec(value, index)));
128
+ }
129
+
45
130
  function ensureLongRunningToolTimeout(ctx, toolNames) {
46
131
  const names = Array.isArray(toolNames) ? toolNames : [toolNames];
47
132
  if (!names.some((name) => LONG_RUNNING_TOOL_NAMES.has(name))) {
@@ -124,6 +209,7 @@ async function toolsDescribeHandler(ctx) {
124
209
  async function toolsExecHandler(ctx) {
125
210
  ensureLongRunningToolTimeout(ctx, ctx.args.toolName);
126
211
  const toolkits = normalizeToolkits(ctx.options.toolkits);
212
+ const fileBindings = await parseFileBindings(ctx.options.file);
127
213
 
128
214
  if (ctx.options.getSchema) {
129
215
  const tool = await fetchToolSchema(ctx.runtime, ctx.args.toolName, ctx.options.toolkits);
@@ -144,6 +230,9 @@ async function toolsExecHandler(ctx) {
144
230
  : parseMaybeJson(rawArguments, 'arguments') || {};
145
231
 
146
232
  if (ctx.options.dryRun) {
233
+ if (fileBindings.length) {
234
+ throw usageError('--file is only supported when executing a tool, not with --dry-run');
235
+ }
147
236
  const tool = await fetchToolSchema(ctx.runtime, ctx.args.toolName, ctx.options.toolkits);
148
237
  const errors = validateArguments(tool.parameters, args);
149
238
 
@@ -181,6 +270,7 @@ async function toolsExecHandler(ctx) {
181
270
  },
182
271
  mutating: true,
183
272
  idempotencyKey,
273
+ fileBindings,
184
274
  });
185
275
 
186
276
  return ctx.output.emitSuccess({
@@ -193,6 +283,10 @@ async function toolsExecHandler(ctx) {
193
283
  }
194
284
 
195
285
  async function toolsExecParallelHandler(ctx) {
286
+ const parallelFileBindings = await parseFileBindings(ctx.options.file);
287
+ if (parallelFileBindings.length) {
288
+ throw usageError('--file is supported by `notis tools exec` only; exec-parallel accepts JSON calls without file uploads.');
289
+ }
196
290
  const calls = parseMaybeJson(ctx.args.calls, 'calls');
197
291
  if (!Array.isArray(calls) || !calls.length) {
198
292
  throw usageError('calls must be a non-empty JSON array of {tool_name, arguments} objects');
@@ -326,6 +420,7 @@ export const toolsCommandSpecs = [
326
420
  arguments: [{ token: '<tool-name>', description: 'Tool name returned by `notis tools search`.' }],
327
421
  options: [
328
422
  { flags: '--arguments <json>', description: 'JSON object, @file path, or - for stdin.' },
423
+ { flags: '--file <argument-path=local-path>', description: 'Upload a local file into a file-uploadable tool argument. Repeatable.', collect: true },
329
424
  { flags: '--get-schema', description: 'Display the tool parameter schema without executing.' },
330
425
  { flags: '--dry-run', description: 'Validate arguments against the tool schema without executing.' },
331
426
  { flags: '--toolkits <csv-or-json>', description: 'Optional toolkit namespace(s) to use when resolving the tool.' },
@@ -338,6 +433,7 @@ export const toolsCommandSpecs = [
338
433
  'notis tools exec notis-default-query --dry-run --arguments \'{"database_slug":"tasks","query":{}}\'',
339
434
  'notis tools exec notis-default-query --arguments @query.json',
340
435
  'notis tools exec notis-default-query --arguments - < query.json',
436
+ 'notis tools exec composio-dropbox-default-upload_file --arguments \'{"path":"/target/in/dropbox.pdf"}\' --file content=./Invoice.pdf',
341
437
  ],
342
438
  output_schema: 'Returns the raw tool execution payload.',
343
439
  mutates: true,
@@ -354,7 +450,9 @@ export const toolsCommandSpecs = [
354
450
  arguments: [
355
451
  { token: '<calls>', description: 'JSON array of {tool_name, arguments} objects.' },
356
452
  ],
357
- options: [],
453
+ options: [
454
+ { flags: '--file <argument-path=local-path>', description: 'Unsupported for exec-parallel; use tools exec for file uploads.', collect: true },
455
+ ],
358
456
  },
359
457
  examples: [
360
458
  'notis tools exec-parallel \'[{"tool_name":"notis-default-query","arguments":{"database_slug":"tasks","query":{}}},{"tool_name":"notis-default-list_databases","arguments":{}}]\'',
@@ -114,8 +114,8 @@ function reactVersionFromPeer(peerRange) {
114
114
  function resolveHarnessReactVersion(projectDir) {
115
115
  const candidates = [
116
116
  join(projectDir, 'node_modules', '@notis', 'sdk', 'package.json'),
117
- join(REPO_ROOT, 'packages', 'notis-sdk', 'package.json'),
118
- join(CLI_ROOT, 'template', 'packages', 'notis-sdk', 'package.json'),
117
+ join(REPO_ROOT, 'packages', 'sdk', 'package.json'),
118
+ join(CLI_ROOT, 'template', 'packages', 'sdk', 'package.json'),
119
119
  ];
120
120
  for (const candidate of candidates) {
121
121
  const pkg = readJsonFile(candidate);
@@ -27,6 +27,7 @@ const MONOREPO_APPS_DIR = resolve(CLI_ROOT, '../..', 'apps');
27
27
  const DIST_DIR = join(CLI_ROOT, 'dist');
28
28
  const SCAFFOLD_CATALOG_FILE = join(DIST_DIR, 'scaffolds.json');
29
29
  const SCAFFOLD_SOURCE_DIR = join(DIST_DIR, 'scaffolds');
30
+ const TEMPLATE_SDK_DIR = join(CLI_ROOT, 'template', 'packages', 'sdk');
30
31
  export const NOTIS_APP_CATEGORIES = [
31
32
  'Productivity',
32
33
  'Sales & Marketing',
@@ -787,6 +788,7 @@ export function scaffoldProject({ projectDir, appName, fromSlug = null }) {
787
788
  if (existsSync(pkgPath)) {
788
789
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
789
790
  pkg.name = appName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
791
+ ensureScaffoldLocalSdk(projectDir, pkg);
790
792
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
791
793
  }
792
794
 
@@ -821,6 +823,32 @@ export function scaffoldProject({ projectDir, appName, fromSlug = null }) {
821
823
  return { projectDir };
822
824
  }
823
825
 
826
+ function ensureScaffoldLocalSdk(projectDir, pkg) {
827
+ let shouldInstallLocalSdk = false;
828
+ for (const dependencyGroup of ['dependencies', 'devDependencies']) {
829
+ const dependencyValue = pkg[dependencyGroup]?.['@notis/sdk'];
830
+ if (typeof dependencyValue === 'string' && dependencyValue.startsWith('file:')) {
831
+ pkg[dependencyGroup]['@notis/sdk'] = 'file:./packages/sdk';
832
+ shouldInstallLocalSdk = true;
833
+ }
834
+ }
835
+
836
+ if (!shouldInstallLocalSdk) {
837
+ return;
838
+ }
839
+
840
+ const localSdkDir = join(projectDir, 'packages', 'sdk');
841
+ if (existsSync(join(localSdkDir, 'package.json'))) {
842
+ return;
843
+ }
844
+ if (!existsSync(join(TEMPLATE_SDK_DIR, 'package.json'))) {
845
+ throw usageError(`SDK template not found at ${TEMPLATE_SDK_DIR}. Ensure @notis_ai/cli is installed correctly.`);
846
+ }
847
+
848
+ mkdirSync(dirname(localSdkDir), { recursive: true });
849
+ cpSync(TEMPLATE_SDK_DIR, localSdkDir, { recursive: true, dereference: true });
850
+ }
851
+
824
852
  function resolveScaffoldSourceDir(fromSlug) {
825
853
  const bundledDir = join(SCAFFOLD_SOURCE_DIR, fromSlug);
826
854
  if (existsSync(bundledDir)) {