@notis_ai/cli 0.2.0-beta.16.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.
- package/README.md +335 -0
- package/bin/notis.js +2 -0
- package/package.json +38 -0
- package/src/cli.js +147 -0
- package/src/command-specs/apps.js +496 -0
- package/src/command-specs/auth.js +178 -0
- package/src/command-specs/db.js +163 -0
- package/src/command-specs/helpers.js +193 -0
- package/src/command-specs/index.js +20 -0
- package/src/command-specs/meta.js +154 -0
- package/src/command-specs/tools.js +391 -0
- package/src/runtime/app-platform.js +624 -0
- package/src/runtime/app-preview-server.js +312 -0
- package/src/runtime/errors.js +55 -0
- package/src/runtime/help.js +60 -0
- package/src/runtime/output.js +180 -0
- package/src/runtime/profiles.js +202 -0
- package/src/runtime/transport.js +198 -0
- package/template/app/globals.css +3 -0
- package/template/app/layout.tsx +7 -0
- package/template/app/page.tsx +55 -0
- package/template/components/ui/badge.tsx +28 -0
- package/template/components/ui/button.tsx +53 -0
- package/template/components/ui/card.tsx +56 -0
- package/template/components.json +20 -0
- package/template/lib/utils.ts +6 -0
- package/template/notis.config.ts +18 -0
- package/template/package.json +32 -0
- package/template/packages/notis-sdk/package.json +26 -0
- package/template/packages/notis-sdk/src/config.ts +48 -0
- package/template/packages/notis-sdk/src/helpers.ts +131 -0
- package/template/packages/notis-sdk/src/hooks/useAppState.ts +50 -0
- package/template/packages/notis-sdk/src/hooks/useBackend.ts +41 -0
- package/template/packages/notis-sdk/src/hooks/useCollectionItem.ts +58 -0
- package/template/packages/notis-sdk/src/hooks/useDatabase.ts +87 -0
- package/template/packages/notis-sdk/src/hooks/useDocument.ts +61 -0
- package/template/packages/notis-sdk/src/hooks/useNotis.ts +31 -0
- package/template/packages/notis-sdk/src/hooks/useNotisNavigation.ts +49 -0
- package/template/packages/notis-sdk/src/hooks/useTool.ts +49 -0
- package/template/packages/notis-sdk/src/hooks/useTools.ts +56 -0
- package/template/packages/notis-sdk/src/hooks/useUpsertDocument.ts +57 -0
- package/template/packages/notis-sdk/src/index.ts +47 -0
- package/template/packages/notis-sdk/src/provider.tsx +44 -0
- package/template/packages/notis-sdk/src/runtime.ts +159 -0
- package/template/packages/notis-sdk/src/styles.css +123 -0
- package/template/packages/notis-sdk/src/ui.ts +15 -0
- package/template/packages/notis-sdk/src/vite.ts +54 -0
- package/template/packages/notis-sdk/tsconfig.json +15 -0
- package/template/postcss.config.mjs +8 -0
- package/template/tailwind.config.ts +58 -0
- package/template/tsconfig.json +22 -0
- package/template/vite.config.ts +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# @notis_ai/cli
|
|
2
|
+
|
|
3
|
+
Agent-first Notis CLI for apps, databases, and generic tool execution.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
The Notis CLI is bundled automatically with the Notis desktop app.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
notis --help
|
|
13
|
+
notis auth status
|
|
14
|
+
notis apps list
|
|
15
|
+
notis db list
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If you're using the desktop app, login and logout keep the CLI profile in sync automatically.
|
|
19
|
+
|
|
20
|
+
The CLI defaults to `json` output in agent or non-TTY contexts and `table` output in interactive terminals.
|
|
21
|
+
|
|
22
|
+
## Global Flags
|
|
23
|
+
|
|
24
|
+
- `--json` — Shortcut for `--output json`
|
|
25
|
+
- `--output <table|json|yaml|ndjson>` — Output mode override
|
|
26
|
+
- `--non-interactive` — Disable prompts
|
|
27
|
+
- `--profile <name>` — Select a stored profile
|
|
28
|
+
- `--api-base <url>` — Override the API base for one invocation
|
|
29
|
+
- `--timeout-ms <n>` — HTTP timeout in milliseconds
|
|
30
|
+
- `--idempotency-key <key>` — Override the generated idempotency key for mutating commands
|
|
31
|
+
|
|
32
|
+
## Auth
|
|
33
|
+
|
|
34
|
+
### `notis auth login`
|
|
35
|
+
|
|
36
|
+
Store credentials for a named CLI profile.
|
|
37
|
+
|
|
38
|
+
When to use: Use this before authenticated commands, especially in fresh environments or CI profiles.
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
- `--jwt <token>` — JWT token to store for the profile.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
- `notis auth login --jwt <token>`
|
|
45
|
+
- `notis auth login --profile staging --api-base http://localhost:3001`
|
|
46
|
+
|
|
47
|
+
### `notis auth logout`
|
|
48
|
+
|
|
49
|
+
Remove the stored JWT for the active profile.
|
|
50
|
+
|
|
51
|
+
When to use: Use this to clear local credentials without touching other profiles.
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
- `notis auth logout`
|
|
55
|
+
- `notis auth logout --profile staging`
|
|
56
|
+
|
|
57
|
+
### `notis auth status`
|
|
58
|
+
|
|
59
|
+
Inspect local auth configuration and optionally verify it against the API.
|
|
60
|
+
|
|
61
|
+
When to use: Use this before automating commands to confirm the active profile and token health.
|
|
62
|
+
|
|
63
|
+
Options:
|
|
64
|
+
- `--verify` — Perform a live authenticated roundtrip to the API.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
- `notis auth status`
|
|
68
|
+
- `notis auth status --verify --json`
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## Apps
|
|
72
|
+
|
|
73
|
+
### `notis apps list`
|
|
74
|
+
|
|
75
|
+
List apps the current profile can access.
|
|
76
|
+
|
|
77
|
+
When to use: Discover existing apps before linking or deploying.
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
- `notis apps list`
|
|
81
|
+
- `notis apps list --json`
|
|
82
|
+
|
|
83
|
+
### `notis apps init <name> [dir]`
|
|
84
|
+
|
|
85
|
+
Scaffold a new Notis app project.
|
|
86
|
+
|
|
87
|
+
When to use: Start a new Notis app. Creates a Vite + React project with @notis/sdk pre-configured.
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
- `notis apps init "Mind the Flo"`
|
|
91
|
+
- `notis apps init "My App" ./my-app`
|
|
92
|
+
|
|
93
|
+
### `notis apps create <name> [dir]`
|
|
94
|
+
|
|
95
|
+
Create a new remote Notis app and optionally link a local project to it.
|
|
96
|
+
|
|
97
|
+
When to use: Provision a fresh remote app before the first deploy. Pass a project directory to link it immediately.
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
- `--description <text>` — Optional app description.
|
|
101
|
+
- `--icon <lucide:icon>` — Optional Lucide icon, for example lucide:dices.
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
- `notis apps create "My App"`
|
|
105
|
+
- `notis apps create "My App" . --description "Internal tool" --icon lucide:layout-dashboard`
|
|
106
|
+
|
|
107
|
+
### `notis apps dev [dir]`
|
|
108
|
+
|
|
109
|
+
Run the Vite dev server for local development.
|
|
110
|
+
|
|
111
|
+
When to use: Iterate on app UI with hot reload. SDK hooks return mock data.
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
- `notis apps dev`
|
|
115
|
+
- `notis apps dev ./my-app`
|
|
116
|
+
|
|
117
|
+
### `notis apps build [dir]`
|
|
118
|
+
|
|
119
|
+
Build and package the app into .notis/output/.
|
|
120
|
+
|
|
121
|
+
When to use: Prepare the app for preview or deployment.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
- `notis apps build`
|
|
125
|
+
- `notis apps build ./my-app`
|
|
126
|
+
|
|
127
|
+
### `notis apps preview [dir]`
|
|
128
|
+
|
|
129
|
+
Serve the built bundle locally for testing.
|
|
130
|
+
|
|
131
|
+
When to use: Smoke-test the exact bundle that will be deployed. Databases use seed data.
|
|
132
|
+
|
|
133
|
+
Options:
|
|
134
|
+
- `--port <number>` — Server port (default: 8787).
|
|
135
|
+
|
|
136
|
+
Examples:
|
|
137
|
+
- `notis apps preview`
|
|
138
|
+
- `notis apps preview --port 3000`
|
|
139
|
+
|
|
140
|
+
### `notis apps link <app-id> [dir]`
|
|
141
|
+
|
|
142
|
+
Link a local project to a remote Notis app.
|
|
143
|
+
|
|
144
|
+
When to use: Connect a local project to an existing app for deployment.
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
- `notis apps link abc123`
|
|
148
|
+
- `notis apps link abc123 ./my-app`
|
|
149
|
+
|
|
150
|
+
### `notis apps deploy [dir]`
|
|
151
|
+
|
|
152
|
+
Build and upload the app to the linked Notis app.
|
|
153
|
+
|
|
154
|
+
When to use: Ship the installed app to production for the linked user/team app. Requires a linked app (notis apps link). This command does not publish to the app store.
|
|
155
|
+
|
|
156
|
+
Options:
|
|
157
|
+
- `--app-id <id>` — Override linked app ID.
|
|
158
|
+
- `--skip-build` — Skip the build step (use existing .notis/output/).
|
|
159
|
+
- `--direct` — Upload directly to Supabase storage, bypassing the backend server. Auto-fallback on network errors.
|
|
160
|
+
|
|
161
|
+
Examples:
|
|
162
|
+
- `notis apps deploy`
|
|
163
|
+
- `notis apps deploy --skip-build`
|
|
164
|
+
- `notis apps deploy --app-id abc123`
|
|
165
|
+
- `notis apps deploy --direct`
|
|
166
|
+
|
|
167
|
+
### `notis apps doctor [dir]`
|
|
168
|
+
|
|
169
|
+
Check project health and readiness.
|
|
170
|
+
|
|
171
|
+
When to use: Diagnose issues with a Notis app project.
|
|
172
|
+
|
|
173
|
+
Examples:
|
|
174
|
+
- `notis apps doctor`
|
|
175
|
+
- `notis apps doctor ./my-app`
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
## Databases
|
|
179
|
+
|
|
180
|
+
### `notis db list`
|
|
181
|
+
|
|
182
|
+
List native Notis databases.
|
|
183
|
+
|
|
184
|
+
When to use: Use this to find database ids and slugs before querying or updating schemas.
|
|
185
|
+
|
|
186
|
+
Examples:
|
|
187
|
+
- `notis db list`
|
|
188
|
+
- `notis db list --json`
|
|
189
|
+
|
|
190
|
+
### `notis db upsert`
|
|
191
|
+
|
|
192
|
+
Create or update a native database schema.
|
|
193
|
+
|
|
194
|
+
When to use: Use this when you need to provision a new database or adjust an existing schema.
|
|
195
|
+
|
|
196
|
+
Options:
|
|
197
|
+
- `--operation <create|update>` — Create a new database or update an existing one.
|
|
198
|
+
- `--database-id <id>` — Database id for update operations.
|
|
199
|
+
- `--title <text>` — Database title.
|
|
200
|
+
- `--description <text>` — Database description.
|
|
201
|
+
- `--icon <lucide-icon-name>` — Database icon (Lucide icon name, e.g. database).
|
|
202
|
+
- `--properties <json>` — JSON array of property definitions.
|
|
203
|
+
|
|
204
|
+
Examples:
|
|
205
|
+
- `notis db upsert --operation create --title "Tasks"`
|
|
206
|
+
- `notis db upsert --operation update --database-id db_123 --title "Tasks V2"`
|
|
207
|
+
|
|
208
|
+
### `notis db query <database-slug>`
|
|
209
|
+
|
|
210
|
+
Run a structured query against a native Notis database.
|
|
211
|
+
|
|
212
|
+
When to use: Use this when the database slug is known and you need direct filters, sorts, or pagination.
|
|
213
|
+
|
|
214
|
+
Options:
|
|
215
|
+
- `--filter <json>` — Structured query filter JSON.
|
|
216
|
+
- `--sort <json>` — Sort JSON object or array.
|
|
217
|
+
- `--page-size <n>` — Page size between 1 and 100.
|
|
218
|
+
- `--offset <n>` — Zero-based offset.
|
|
219
|
+
- `--cursor <value>` — Pagination cursor alias for next_offset.
|
|
220
|
+
|
|
221
|
+
Examples:
|
|
222
|
+
- `notis db query tasks --page-size 50`
|
|
223
|
+
- `notis db query tasks --filter '{"property":"Status"}'`
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
## Generic Tools
|
|
227
|
+
|
|
228
|
+
### `notis tools toolkits`
|
|
229
|
+
|
|
230
|
+
List toolkit namespaces available to the active user.
|
|
231
|
+
|
|
232
|
+
When to use: Use this before searching or executing generic tools.
|
|
233
|
+
|
|
234
|
+
Examples:
|
|
235
|
+
- `notis tools toolkits`
|
|
236
|
+
- `notis tools toolkits --json`
|
|
237
|
+
|
|
238
|
+
### `notis tools search <query>`
|
|
239
|
+
|
|
240
|
+
Search across toolkit namespaces using natural language.
|
|
241
|
+
|
|
242
|
+
When to use: Use this when you need a generic capability that does not have a first-class CLI command.
|
|
243
|
+
|
|
244
|
+
Options:
|
|
245
|
+
- `--toolkits <csv-or-json>` — Optional subset of toolkit ids to search.
|
|
246
|
+
|
|
247
|
+
Examples:
|
|
248
|
+
- `notis tools search "send an email"`
|
|
249
|
+
- `notis tools search "update framer page" --toolkits mcp-framer`
|
|
250
|
+
|
|
251
|
+
### `notis tools describe <tool-name>`
|
|
252
|
+
|
|
253
|
+
Describe a generic tool by name.
|
|
254
|
+
|
|
255
|
+
When to use: Use this when you know the tool name and want its parameter schema before execution.
|
|
256
|
+
|
|
257
|
+
Options:
|
|
258
|
+
- `--toolkits <csv-or-json>` — Optional subset of toolkit ids to search.
|
|
259
|
+
|
|
260
|
+
Examples:
|
|
261
|
+
- `notis tools describe composio-gmail-default-send_email`
|
|
262
|
+
- `notis tools describe notis-default-query --toolkits notis-default`
|
|
263
|
+
|
|
264
|
+
### `notis tools exec <tool-name>`
|
|
265
|
+
|
|
266
|
+
Execute a generic tool by canonical tool name.
|
|
267
|
+
|
|
268
|
+
When to use: Use this as the escape hatch for integrations or Notis tools without a first-class CLI wrapper.
|
|
269
|
+
|
|
270
|
+
Options:
|
|
271
|
+
- `--arguments <json>` — JSON object, @file path, or - for stdin.
|
|
272
|
+
- `--get-schema` — Display the tool parameter schema without executing.
|
|
273
|
+
- `--dry-run` — Validate arguments against the tool schema without executing.
|
|
274
|
+
- `--watch <seconds>` — Re-execute on an interval and stream results.
|
|
275
|
+
|
|
276
|
+
Examples:
|
|
277
|
+
- `notis tools exec notis-default-query --arguments '{"database_slug":"tasks","query":{}}'`
|
|
278
|
+
- `notis tools exec notis-default-query --get-schema`
|
|
279
|
+
- `notis tools exec notis-default-query --dry-run --arguments '{"database_slug":"tasks","query":{}}'`
|
|
280
|
+
- `notis tools exec notis-default-query --arguments @query.json`
|
|
281
|
+
- `notis tools exec notis-default-query --arguments - < query.json`
|
|
282
|
+
- `notis tools exec notis-default-query --watch 10 --arguments '{"database_slug":"tasks","query":{}}'`
|
|
283
|
+
|
|
284
|
+
### `notis tools exec-parallel <calls>`
|
|
285
|
+
|
|
286
|
+
Execute multiple tools concurrently.
|
|
287
|
+
|
|
288
|
+
When to use: Use this when you need to run independent tool calls simultaneously for speed.
|
|
289
|
+
|
|
290
|
+
Examples:
|
|
291
|
+
- `notis tools exec-parallel '[{"tool_name":"notis-default-query","arguments":{"database_slug":"tasks","query":{}}},{"tool_name":"notis-default-list_databases","arguments":{}}]'`
|
|
292
|
+
|
|
293
|
+
### `notis tools link <toolkit>`
|
|
294
|
+
|
|
295
|
+
Get the URL to connect an integration toolkit.
|
|
296
|
+
|
|
297
|
+
When to use: Use this when a tool requires authentication with an external service.
|
|
298
|
+
|
|
299
|
+
Examples:
|
|
300
|
+
- `notis tools link github`
|
|
301
|
+
- `notis tools link gmail --json`
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
## Meta Commands
|
|
305
|
+
|
|
306
|
+
### `notis doctor`
|
|
307
|
+
|
|
308
|
+
Run a quick CLI health check for config, auth, and API reachability.
|
|
309
|
+
|
|
310
|
+
When to use: Use this before relying on the CLI in automation or after changing environments.
|
|
311
|
+
|
|
312
|
+
Examples:
|
|
313
|
+
- `notis doctor`
|
|
314
|
+
- `notis doctor --json`
|
|
315
|
+
|
|
316
|
+
### `notis describe <command...>`
|
|
317
|
+
|
|
318
|
+
Describe a first-class CLI command in detail.
|
|
319
|
+
|
|
320
|
+
When to use: Use this when an agent or human needs the exact shape, examples, and semantics of a command.
|
|
321
|
+
|
|
322
|
+
Examples:
|
|
323
|
+
- `notis describe apps push`
|
|
324
|
+
- `notis describe db query`
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
## Local Development
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
cd cli/npm
|
|
331
|
+
npm install
|
|
332
|
+
node ./bin/notis.js --help
|
|
333
|
+
npm run docs:generate
|
|
334
|
+
npm test
|
|
335
|
+
```
|
package/bin/notis.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@notis_ai/cli",
|
|
3
|
+
"version": "0.2.0-beta.16.1",
|
|
4
|
+
"description": "Agent-first Notis CLI for apps, databases, and generic tool execution",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"notis": "bin/notis.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"template/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"docs:generate": "node ./scripts/generate-docs.js",
|
|
17
|
+
"docs:check": "node ./scripts/generate-docs.js --check",
|
|
18
|
+
"release:prepare": "node ./scripts/prepare-publish.js --apply",
|
|
19
|
+
"test": "node --test"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"commander": "^12.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"notis",
|
|
30
|
+
"cli",
|
|
31
|
+
"ai",
|
|
32
|
+
"agent-skills"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT"
|
|
38
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { COMMAND_SPECS, GROUP_SUMMARIES } from './command-specs/index.js';
|
|
3
|
+
import { OutputManager } from './runtime/output.js';
|
|
4
|
+
import { asCliError } from './runtime/errors.js';
|
|
5
|
+
import { resolveRuntimeProfile, workspacePath } from './runtime/profiles.js';
|
|
6
|
+
|
|
7
|
+
const CLI_VERSION = '0.2.0';
|
|
8
|
+
|
|
9
|
+
function buildHelpFooter(spec) {
|
|
10
|
+
const lines = [
|
|
11
|
+
'',
|
|
12
|
+
`When to use: ${spec.when_to_use}`,
|
|
13
|
+
'',
|
|
14
|
+
'Examples:',
|
|
15
|
+
...(spec.examples || []).map((example) => ` ${example}`),
|
|
16
|
+
];
|
|
17
|
+
if (spec.related_commands?.length) {
|
|
18
|
+
lines.push('', 'Related commands:', ...spec.related_commands.map((command) => ` ${command}`));
|
|
19
|
+
}
|
|
20
|
+
return lines.join('\n');
|
|
21
|
+
}
|
|
22
|
+
function mapArgs(spec, rawArgs) {
|
|
23
|
+
const mapped = {};
|
|
24
|
+
const argumentDefs = spec.args_schema?.arguments || [];
|
|
25
|
+
for (const [index, argument] of argumentDefs.entries()) {
|
|
26
|
+
const normalizedToken = (argument.key || argument.token.replace(/[<>\[\]]/g, '').replace('...', ''))
|
|
27
|
+
.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
28
|
+
mapped[normalizedToken] = rawArgs[index];
|
|
29
|
+
}
|
|
30
|
+
return mapped;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ensureParentCommand(program, parentMap, parentPath) {
|
|
34
|
+
const key = parentPath.join(' ');
|
|
35
|
+
if (parentMap.has(key)) {
|
|
36
|
+
return parentMap.get(key);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const parentCommand = ensureParentCommand(program, parentMap, parentPath.slice(0, -1));
|
|
40
|
+
const segment = parentPath[parentPath.length - 1];
|
|
41
|
+
const command = parentCommand.command(segment).description(GROUP_SUMMARIES[segment] || '');
|
|
42
|
+
parentMap.set(key, command);
|
|
43
|
+
return command;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildRuntime(globalOptions, spec) {
|
|
47
|
+
const runtime = resolveRuntimeProfile(globalOptions, { requireAuth: spec.require_auth !== false });
|
|
48
|
+
return {
|
|
49
|
+
...runtime,
|
|
50
|
+
cliVersion: CLI_VERSION,
|
|
51
|
+
color: globalOptions.color !== false,
|
|
52
|
+
workspacePath,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function attachSpec(program, parentMap, spec, specs) {
|
|
57
|
+
const parent = ensureParentCommand(program, parentMap, spec.command_path.slice(0, -1));
|
|
58
|
+
const leaf = spec.command_path[spec.command_path.length - 1];
|
|
59
|
+
const command = parent.command(leaf).description(spec.summary);
|
|
60
|
+
command.addHelpText('after', buildHelpFooter(spec));
|
|
61
|
+
|
|
62
|
+
for (const argument of spec.args_schema?.arguments || []) {
|
|
63
|
+
command.argument(argument.token, argument.description);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const option of spec.args_schema?.options || []) {
|
|
67
|
+
command.option(option.flags, option.description);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
command.action(async (...raw) => {
|
|
71
|
+
const commanderCommand = raw[raw.length - 1];
|
|
72
|
+
const argumentValues = raw.slice(0, -1);
|
|
73
|
+
const globalOptions = commanderCommand.optsWithGlobals();
|
|
74
|
+
try {
|
|
75
|
+
const runtime = buildRuntime(globalOptions, spec);
|
|
76
|
+
const output = new OutputManager(runtime);
|
|
77
|
+
const args = mapArgs(spec, argumentValues);
|
|
78
|
+
|
|
79
|
+
if (spec.deprecated_alias_for && runtime.outputMode === 'table') {
|
|
80
|
+
output.writeWarning(`Warning: Command "${spec.command_path.join(' ')}" is deprecated. Use "${spec.deprecated_alias_for}" instead.`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const exitCode = await spec.handler({
|
|
84
|
+
spec,
|
|
85
|
+
registrySpecs: specs,
|
|
86
|
+
args,
|
|
87
|
+
options: commanderCommand.opts(),
|
|
88
|
+
globalOptions,
|
|
89
|
+
runtime,
|
|
90
|
+
output,
|
|
91
|
+
});
|
|
92
|
+
process.exitCode = typeof exitCode === 'number' ? exitCode : 0;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const runtime = {
|
|
95
|
+
...resolveRuntimeProfile(globalOptions, { requireAuth: false }),
|
|
96
|
+
cliVersion: CLI_VERSION,
|
|
97
|
+
color: globalOptions.color !== false,
|
|
98
|
+
workspacePath,
|
|
99
|
+
};
|
|
100
|
+
const output = new OutputManager(runtime);
|
|
101
|
+
const cliError = asCliError(error);
|
|
102
|
+
process.exitCode = output.emitError({
|
|
103
|
+
command: spec.command_path.join(' '),
|
|
104
|
+
error: cliError,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function createProgram() {
|
|
111
|
+
const program = new Command();
|
|
112
|
+
|
|
113
|
+
program
|
|
114
|
+
.name('notis')
|
|
115
|
+
.description('Agent-first Notis CLI for apps, databases, and generic tool execution')
|
|
116
|
+
.version(CLI_VERSION)
|
|
117
|
+
.showHelpAfterError()
|
|
118
|
+
.option('--json', 'Shortcut for --output json')
|
|
119
|
+
.option('--output <table|json|yaml|ndjson>', 'Output mode override')
|
|
120
|
+
.option('--non-interactive', 'Disable all interactive prompts')
|
|
121
|
+
.option('--quiet', 'Suppress non-essential human output')
|
|
122
|
+
.option('--verbose', 'Show extra human-readable diagnostics')
|
|
123
|
+
.option('--no-color', 'Disable ANSI color output')
|
|
124
|
+
.option('--profile <name>', 'CLI profile name', 'default')
|
|
125
|
+
.option('--api-base <url>', 'Override the API base URL for this invocation')
|
|
126
|
+
.option('--timeout-ms <n>', 'HTTP timeout in milliseconds')
|
|
127
|
+
.option('--idempotency-key <key>', 'Override the generated idempotency key for mutating commands');
|
|
128
|
+
|
|
129
|
+
const parentMap = new Map([['', program]]);
|
|
130
|
+
for (const spec of COMMAND_SPECS) {
|
|
131
|
+
attachSpec(program, parentMap, spec, COMMAND_SPECS);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return program;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function run(argv = process.argv) {
|
|
138
|
+
const program = createProgram();
|
|
139
|
+
await program.parseAsync(argv);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const isDirectInvocation =
|
|
143
|
+
process.argv[1] && import.meta.url === new URL(process.argv[1], 'file://').href;
|
|
144
|
+
|
|
145
|
+
if (isDirectInvocation) {
|
|
146
|
+
run();
|
|
147
|
+
}
|