@notis_ai/cli 0.2.0 → 0.2.2

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 (81) hide show
  1. package/README.md +122 -158
  2. package/dist/scaffolds/notes/app/globals.css +3 -0
  3. package/dist/scaffolds/notes/app/layout.tsx +6 -0
  4. package/dist/scaffolds/notes/app/page.tsx +1465 -0
  5. package/dist/scaffolds/notes/components/ui/badge.tsx +28 -0
  6. package/dist/scaffolds/notes/components/ui/button.tsx +53 -0
  7. package/dist/scaffolds/notes/components/ui/card.tsx +56 -0
  8. package/dist/scaffolds/notes/components.json +20 -0
  9. package/dist/scaffolds/notes/lib/utils.ts +6 -0
  10. package/dist/scaffolds/notes/notis.config.ts +31 -0
  11. package/dist/scaffolds/notes/package.json +31 -0
  12. package/dist/scaffolds/notes/postcss.config.mjs +8 -0
  13. package/dist/scaffolds/notes/tailwind.config.ts +58 -0
  14. package/dist/scaffolds/notes/tsconfig.json +22 -0
  15. package/dist/scaffolds/notes/vite.config.ts +10 -0
  16. package/dist/scaffolds.json +13 -0
  17. package/package.json +12 -2
  18. package/skills/notis-apps/SKILL.md +162 -0
  19. package/skills/notis-apps/cli.md +208 -0
  20. package/skills/notis-cli/SKILL.md +258 -0
  21. package/skills/notis-query/cli.md +40 -0
  22. package/src/cli.js +1 -1
  23. package/src/command-specs/apps.js +1029 -59
  24. package/src/command-specs/helpers.js +6 -41
  25. package/src/command-specs/index.js +1 -7
  26. package/src/command-specs/meta.js +7 -6
  27. package/src/command-specs/tools.js +29 -34
  28. package/src/runtime/agent-browser.js +192 -0
  29. package/src/runtime/app-boundary-validator.js +132 -0
  30. package/src/runtime/app-dev-server.js +605 -0
  31. package/src/runtime/app-dev-sessions.js +87 -0
  32. package/src/runtime/app-platform.js +1037 -82
  33. package/src/runtime/cli-mode.generated.js +4 -0
  34. package/src/runtime/cli-mode.js +29 -0
  35. package/src/runtime/output.js +2 -2
  36. package/src/runtime/ports.js +15 -0
  37. package/src/runtime/profiles.js +36 -5
  38. package/src/runtime/transport.js +131 -6
  39. package/template/.harness/index.html.tmpl +211 -0
  40. package/template/app/globals.css +3 -0
  41. package/template/app/layout.tsx +6 -0
  42. package/template/app/page.tsx +90 -0
  43. package/template/components/ui/badge.tsx +28 -0
  44. package/template/components/ui/button.tsx +53 -0
  45. package/template/components/ui/card.tsx +56 -0
  46. package/template/components.json +20 -0
  47. package/template/lib/utils.ts +6 -0
  48. package/template/metadata/cover.png +0 -0
  49. package/template/metadata/screenshot-1.png +0 -0
  50. package/template/metadata/screenshot-2.png +0 -0
  51. package/template/metadata/screenshot-3.png +0 -0
  52. package/template/notis.config.ts +37 -0
  53. package/template/package.json +31 -0
  54. package/template/packages/sdk/package.json +32 -0
  55. package/template/packages/sdk/src/components/MultiSelectActionBar.tsx +273 -0
  56. package/template/packages/sdk/src/components/MultiSelectCheckbox.tsx +91 -0
  57. package/template/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
  58. package/template/packages/sdk/src/config.ts +71 -0
  59. package/template/packages/sdk/src/hooks/useBackend.ts +41 -0
  60. package/template/packages/sdk/src/hooks/useDatabase.ts +76 -0
  61. package/template/packages/sdk/src/hooks/useMultiSelect.ts +503 -0
  62. package/template/packages/sdk/src/hooks/useNotis.ts +34 -0
  63. package/template/packages/sdk/src/hooks/useNotisNavigation.ts +49 -0
  64. package/template/packages/sdk/src/hooks/useTool.ts +64 -0
  65. package/template/packages/sdk/src/hooks/useTools.ts +56 -0
  66. package/template/packages/sdk/src/hooks/useTopBarSearch.ts +73 -0
  67. package/template/packages/sdk/src/hooks/useUpsertDocument.ts +50 -0
  68. package/template/packages/sdk/src/index.ts +54 -0
  69. package/template/packages/sdk/src/provider.tsx +43 -0
  70. package/template/packages/sdk/src/runtime.ts +161 -0
  71. package/template/packages/sdk/src/styles.css +38 -0
  72. package/template/packages/sdk/src/ui.ts +15 -0
  73. package/template/packages/sdk/src/vite.ts +56 -0
  74. package/template/packages/sdk/tsconfig.json +15 -0
  75. package/template/postcss.config.mjs +8 -0
  76. package/template/tailwind.config.ts +58 -0
  77. package/template/tsconfig.json +22 -0
  78. package/template/vite.config.ts +10 -0
  79. package/src/command-specs/auth.js +0 -178
  80. package/src/command-specs/db.js +0 -163
  81. package/src/runtime/app-preview-server.js +0 -272
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "declaration": true,
11
+ "outDir": "dist",
12
+ "rootDir": "src"
13
+ },
14
+ "include": ["src"]
15
+ }
@@ -0,0 +1,8 @@
1
+ /** @type {import('postcss-load-config').Config} */
2
+ const config = {
3
+ plugins: {
4
+ tailwindcss: {},
5
+ },
6
+ };
7
+
8
+ export default config;
@@ -0,0 +1,58 @@
1
+ import type { Config } from 'tailwindcss';
2
+ import tailwindAnimate from 'tailwindcss-animate';
3
+
4
+ const config: Config = {
5
+ darkMode: ['class'],
6
+ content: [
7
+ './app/**/*.{ts,tsx}',
8
+ './components/**/*.{ts,tsx}',
9
+ './lib/**/*.{ts,tsx}',
10
+ ],
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ border: 'hsl(var(--border))',
15
+ input: 'hsl(var(--input))',
16
+ ring: 'hsl(var(--ring))',
17
+ background: 'hsl(var(--background))',
18
+ foreground: 'hsl(var(--foreground))',
19
+ primary: {
20
+ DEFAULT: 'hsl(var(--primary))',
21
+ foreground: 'hsl(var(--primary-foreground))',
22
+ },
23
+ secondary: {
24
+ DEFAULT: 'hsl(var(--secondary))',
25
+ foreground: 'hsl(var(--secondary-foreground))',
26
+ },
27
+ destructive: {
28
+ DEFAULT: 'hsl(var(--destructive))',
29
+ foreground: 'hsl(var(--destructive-foreground))',
30
+ },
31
+ muted: {
32
+ DEFAULT: 'hsl(var(--muted))',
33
+ foreground: 'hsl(var(--muted-foreground))',
34
+ },
35
+ accent: {
36
+ DEFAULT: 'hsl(var(--accent))',
37
+ foreground: 'hsl(var(--accent-foreground))',
38
+ },
39
+ popover: {
40
+ DEFAULT: 'hsl(var(--popover))',
41
+ foreground: 'hsl(var(--popover-foreground))',
42
+ },
43
+ card: {
44
+ DEFAULT: 'hsl(var(--card))',
45
+ foreground: 'hsl(var(--card-foreground))',
46
+ },
47
+ },
48
+ borderRadius: {
49
+ lg: 'var(--radius)',
50
+ md: 'calc(var(--radius) - 2px)',
51
+ sm: 'calc(var(--radius) - 4px)',
52
+ },
53
+ },
54
+ },
55
+ plugins: [tailwindAnimate],
56
+ };
57
+
58
+ export default config;
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "paths": {
17
+ "@/*": ["./*"]
18
+ }
19
+ },
20
+ "include": ["**/*.ts", "**/*.tsx"],
21
+ "exclude": ["node_modules"]
22
+ }
@@ -0,0 +1,10 @@
1
+ import { notisViteConfig } from '@notis/sdk/vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import appConfig from './notis.config';
4
+
5
+ const config = notisViteConfig(appConfig);
6
+
7
+ export default {
8
+ ...config,
9
+ plugins: [react(), ...(config.plugins || [])],
10
+ };
@@ -1,178 +0,0 @@
1
- import { CliError, EXIT_CODES } from '../runtime/errors.js';
2
- import {
3
- clearStoredJwt,
4
- probeAuth,
5
- promptForJwt,
6
- updateStoredProfile,
7
- } from './helpers.js';
8
-
9
- async function authLoginHandler(ctx) {
10
- let jwt = ctx.options.jwt || process.env.NOTIS_JWT;
11
- if (!jwt) {
12
- if (ctx.runtime.nonInteractive) {
13
- throw new CliError({
14
- code: 'auth_missing',
15
- message: `No JWT configured for profile ${ctx.runtime.profileName}`,
16
- exitCode: EXIT_CODES.auth,
17
- hints: [
18
- {
19
- command: 'notis auth login --jwt <token>',
20
- reason: 'Provide a token explicitly in non-interactive mode',
21
- },
22
- ],
23
- });
24
- }
25
- jwt = await promptForJwt();
26
- }
27
-
28
- updateStoredProfile({
29
- profileName: ctx.runtime.profileName,
30
- jwt,
31
- apiBase: ctx.globalOptions.apiBase,
32
- setCurrent: true,
33
- });
34
-
35
- return ctx.output.emitSuccess({
36
- command: ctx.spec.command_path.join(' '),
37
- data: {
38
- profile: ctx.runtime.profileName,
39
- api_base: ctx.globalOptions.apiBase || ctx.runtime.apiBase,
40
- },
41
- humanSummary: `Stored credentials for profile ${ctx.runtime.profileName}`,
42
- hints: [
43
- { command: 'notis whoami', reason: 'Verify your identity and available toolkits' },
44
- ],
45
- meta: { mutating: true },
46
- });
47
- }
48
-
49
- async function authLogoutHandler(ctx) {
50
- clearStoredJwt(ctx.runtime.profileName);
51
- return ctx.output.emitSuccess({
52
- command: ctx.spec.command_path.join(' '),
53
- data: { profile: ctx.runtime.profileName },
54
- humanSummary: `Removed stored JWT for profile ${ctx.runtime.profileName}`,
55
- meta: { mutating: true },
56
- });
57
- }
58
-
59
- async function authStatusHandler(ctx) {
60
- const hasJwt = Boolean(ctx.runtime.jwt);
61
- let verified = false;
62
- let toolkits = [];
63
- if (hasJwt && ctx.options.verify) {
64
- const payload = await probeAuth(ctx.runtime);
65
- toolkits = payload.toolkits || [];
66
- verified = true;
67
- }
68
-
69
- return ctx.output.emitSuccess({
70
- command: ctx.spec.command_path.join(' '),
71
- data: {
72
- profile: ctx.runtime.profileName,
73
- api_base: ctx.runtime.apiBase,
74
- has_jwt: hasJwt,
75
- verified,
76
- toolkits,
77
- },
78
- humanSummary: hasJwt
79
- ? `Profile ${ctx.runtime.profileName} is configured`
80
- : `Profile ${ctx.runtime.profileName} is missing a JWT`,
81
- hints: hasJwt
82
- ? []
83
- : [{ command: 'notis auth login --jwt <token>', reason: 'Configure credentials for this profile' }],
84
- meta: { mutating: false },
85
- });
86
- }
87
-
88
- export const authCommandSpecs = [
89
- {
90
- command_path: ['auth', 'login'],
91
- summary: 'Store credentials for a named CLI profile.',
92
- when_to_use: 'Use this before authenticated commands, especially in fresh environments or CI profiles.',
93
- args_schema: {
94
- arguments: [],
95
- options: [
96
- { flags: '--jwt <token>', description: 'JWT token to store for the profile.' },
97
- ],
98
- },
99
- examples: ['notis auth login --jwt <token>', 'notis auth login --profile staging --api-base http://localhost:3001'],
100
- output_schema: 'Returns the active profile name and API base.',
101
- mutates: true,
102
- idempotent: true,
103
- require_auth: false,
104
- related_commands: ['notis auth status --verify', 'notis auth logout'],
105
- backend_call: { type: 'local' },
106
- handler: authLoginHandler,
107
- },
108
- {
109
- command_path: ['auth', 'logout'],
110
- summary: 'Remove the stored JWT for the active profile.',
111
- when_to_use: 'Use this to clear local credentials without touching other profiles.',
112
- args_schema: { arguments: [], options: [] },
113
- examples: ['notis auth logout', 'notis auth logout --profile staging'],
114
- output_schema: 'Returns the profile that was updated.',
115
- mutates: true,
116
- idempotent: true,
117
- require_auth: false,
118
- related_commands: ['notis auth login --jwt <token>', 'notis auth status'],
119
- backend_call: { type: 'local' },
120
- handler: authLogoutHandler,
121
- },
122
- {
123
- command_path: ['auth', 'status'],
124
- summary: 'Inspect local auth configuration and optionally verify it against the API.',
125
- when_to_use: 'Use this before automating commands to confirm the active profile and token health.',
126
- args_schema: {
127
- arguments: [],
128
- options: [
129
- { flags: '--verify', description: 'Perform a live authenticated roundtrip to the API.' },
130
- ],
131
- },
132
- examples: ['notis auth status', 'notis auth status --verify --json'],
133
- output_schema: 'Returns profile, api_base, local auth presence, and optional verification data.',
134
- mutates: false,
135
- idempotent: true,
136
- require_auth: false,
137
- related_commands: ['notis doctor', 'notis auth login --jwt <token>'],
138
- backend_call: { type: 'notis_find_toolkits' },
139
- handler: authStatusHandler,
140
- },
141
- {
142
- command_path: ['login'],
143
- display_name: 'login',
144
- summary: 'Deprecated alias for `notis auth login`.',
145
- when_to_use: 'Use only for backward compatibility with older scripts.',
146
- args_schema: {
147
- arguments: [],
148
- options: [
149
- { flags: '--jwt <token>', description: 'JWT token to store for the profile.' },
150
- ],
151
- },
152
- examples: ['notis login --jwt <token>'],
153
- output_schema: 'Same output as `notis auth login`.',
154
- mutates: true,
155
- idempotent: true,
156
- require_auth: false,
157
- related_commands: ['notis auth login --jwt <token>'],
158
- backend_call: { type: 'local', alias_for: 'auth login' },
159
- deprecated_alias_for: 'notis auth login',
160
- handler: authLoginHandler,
161
- },
162
- {
163
- command_path: ['logout'],
164
- display_name: 'logout',
165
- summary: 'Deprecated alias for `notis auth logout`.',
166
- when_to_use: 'Use only for backward compatibility with older scripts.',
167
- args_schema: { arguments: [], options: [] },
168
- examples: ['notis logout'],
169
- output_schema: 'Same output as `notis auth logout`.',
170
- mutates: true,
171
- idempotent: true,
172
- require_auth: false,
173
- related_commands: ['notis auth logout'],
174
- backend_call: { type: 'local', alias_for: 'auth logout' },
175
- deprecated_alias_for: 'notis auth logout',
176
- handler: authLogoutHandler,
177
- },
178
- ];
@@ -1,163 +0,0 @@
1
- import { formatTable } from '../runtime/output.js';
2
- import { nextIdempotencyKey, parseMaybeJson, runToolCommand } from './helpers.js';
3
-
4
- async function dbListHandler(ctx) {
5
- const result = await runToolCommand({
6
- runtime: ctx.runtime,
7
- toolName: 'notis_list_databases',
8
- });
9
- const databases = result.payload.databases || [];
10
- const firstSlug = databases[0]?.slug;
11
- return ctx.output.emitSuccess({
12
- command: ctx.spec.command_path.join(' '),
13
- data: { databases },
14
- humanSummary: databases.length ? `Found ${databases.length} databases` : 'No databases found.',
15
- hints: firstSlug
16
- ? [{ command: `notis db query ${firstSlug}`, reason: 'Query this database' }]
17
- : [{ command: 'notis db upsert --operation create --title "My DB"', reason: 'Create a new database' }],
18
- renderHuman: () =>
19
- databases.length
20
- ? formatTable(databases, [
21
- { label: 'ID', value: (database) => database.id || '' },
22
- { label: 'Name', value: (database) => database.name || 'Untitled' },
23
- { label: 'Slug', value: (database) => database.slug || '-' },
24
- ])
25
- : 'No databases found.',
26
- });
27
- }
28
-
29
- async function dbUpsertHandler(ctx) {
30
- const idempotencyKey = nextIdempotencyKey(ctx.globalOptions);
31
- const payload = {
32
- operation: ctx.options.operation,
33
- };
34
- if (ctx.options.databaseId) {
35
- payload.database_id = ctx.options.databaseId;
36
- }
37
- if (ctx.options.title) {
38
- payload.title = ctx.options.title;
39
- }
40
- if (ctx.options.description) {
41
- payload.description = ctx.options.description;
42
- }
43
- if (ctx.options.icon) {
44
- const v = ctx.options.icon;
45
- payload.icon = v.startsWith('lucide:') ? v : `lucide:${v}`;
46
- }
47
- if (ctx.options.properties) {
48
- payload.properties = parseMaybeJson(ctx.options.properties, 'properties');
49
- }
50
-
51
- const result = await runToolCommand({
52
- runtime: ctx.runtime,
53
- toolName: 'notis_upsert_database',
54
- arguments_: payload,
55
- mutating: true,
56
- idempotencyKey,
57
- });
58
- return ctx.output.emitSuccess({
59
- command: ctx.spec.command_path.join(' '),
60
- data: result.payload,
61
- humanSummary: `Database ${ctx.options.operation} completed`,
62
- meta: { mutating: true, idempotency_key: idempotencyKey || null },
63
- });
64
- }
65
-
66
- async function dbQueryHandler(ctx) {
67
- const query = {};
68
- if (ctx.options.filter) {
69
- query.filter = parseMaybeJson(ctx.options.filter, 'filter');
70
- }
71
- if (ctx.options.sort) {
72
- const parsedSorts = parseMaybeJson(ctx.options.sort, 'sort');
73
- query.sorts = Array.isArray(parsedSorts) ? parsedSorts : [parsedSorts];
74
- }
75
- if (ctx.options.pageSize) {
76
- query.page_size = Number.parseInt(ctx.options.pageSize, 10);
77
- }
78
-
79
- const payload = {
80
- database_slug: ctx.args.databaseSlug,
81
- query,
82
- };
83
- if (ctx.options.offset) {
84
- payload.offset = Number.parseInt(ctx.options.offset, 10);
85
- }
86
- if (ctx.options.cursor) {
87
- payload.start_cursor = ctx.options.cursor;
88
- }
89
-
90
- const result = await runToolCommand({
91
- runtime: ctx.runtime,
92
- toolName: 'notis_query',
93
- arguments_: payload,
94
- });
95
-
96
- return ctx.output.emitSuccess({
97
- command: ctx.spec.command_path.join(' '),
98
- data: result.payload,
99
- humanSummary: `Queried database ${ctx.args.databaseSlug}`,
100
- renderHuman: () => JSON.stringify(result.payload, null, 2),
101
- });
102
- }
103
-
104
- export const dbCommandSpecs = [
105
- {
106
- command_path: ['db', 'list'],
107
- summary: 'List native Notis databases.',
108
- when_to_use: 'Use this to find database ids and slugs before querying or updating schemas.',
109
- args_schema: { arguments: [], options: [] },
110
- examples: ['notis db list', 'notis db list --json'],
111
- output_schema: 'Returns an array of native database records.',
112
- mutates: false,
113
- idempotent: true,
114
- related_commands: ['notis db query <database-slug>', 'notis db upsert'],
115
- backend_call: { type: 'tool', name: 'notis_list_databases' },
116
- handler: dbListHandler,
117
- },
118
- {
119
- command_path: ['db', 'upsert'],
120
- summary: 'Create or update a native database schema.',
121
- when_to_use: 'Use this when you need to provision a new database or adjust an existing schema.',
122
- args_schema: {
123
- arguments: [],
124
- options: [
125
- { flags: '--operation <create|update>', description: 'Create a new database or update an existing one.' },
126
- { flags: '--database-id <id>', description: 'Database id for update operations.' },
127
- { flags: '--title <text>', description: 'Database title.' },
128
- { flags: '--description <text>', description: 'Database description.' },
129
- { flags: '--icon <lucide-icon-name>', description: 'Database icon (Lucide icon name, e.g. database).' },
130
- { flags: '--properties <json>', description: 'JSON array of property definitions.' },
131
- ],
132
- },
133
- examples: ['notis db upsert --operation create --title "Tasks"', 'notis db upsert --operation update --database-id db_123 --title "Tasks V2"'],
134
- output_schema: 'Returns the backend database upsert payload.',
135
- mutates: true,
136
- idempotent: true,
137
- related_commands: ['notis db list', 'notis db query <database-slug>'],
138
- backend_call: { type: 'tool', name: 'notis_upsert_database' },
139
- handler: dbUpsertHandler,
140
- },
141
- {
142
- command_path: ['db', 'query'],
143
- summary: 'Run a structured query against a native Notis database.',
144
- when_to_use: 'Use this when the database slug is known and you need direct filters, sorts, or pagination.',
145
- args_schema: {
146
- arguments: [{ token: '<database-slug>', description: 'Slug of the native database to query.' }],
147
- options: [
148
- { flags: '--filter <json>', description: 'Structured query filter JSON.' },
149
- { flags: '--sort <json>', description: 'Sort JSON object or array.' },
150
- { flags: '--page-size <n>', description: 'Page size between 1 and 100.' },
151
- { flags: '--offset <n>', description: 'Zero-based offset.' },
152
- { flags: '--cursor <value>', description: 'Pagination cursor alias for next_offset.' },
153
- ],
154
- },
155
- examples: ['notis db query tasks --page-size 50', 'notis db query tasks --filter \'{"property":"Status"}\''],
156
- output_schema: 'Returns the native database query payload from `notis_query`.',
157
- mutates: false,
158
- idempotent: true,
159
- related_commands: ['notis db list', 'notis db upsert'],
160
- backend_call: { type: 'tool', name: 'notis_query' },
161
- handler: dbQueryHandler,
162
- },
163
- ];