@notis_ai/cli 0.2.1 → 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 (66) hide show
  1. package/README.md +98 -163
  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 +7 -3
  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 +211 -46
  24. package/src/command-specs/helpers.js +0 -60
  25. package/src/command-specs/index.js +0 -6
  26. package/src/command-specs/meta.js +7 -6
  27. package/src/command-specs/tools.js +1 -33
  28. package/src/runtime/app-dev-server.js +32 -4
  29. package/src/runtime/app-platform.js +404 -24
  30. package/src/runtime/profiles.js +2 -2
  31. package/src/runtime/transport.js +2 -2
  32. package/template/.harness/index.html.tmpl +1 -50
  33. package/template/app/page.tsx +41 -6
  34. package/template/metadata/cover.png +0 -0
  35. package/template/metadata/screenshot-1.png +0 -0
  36. package/template/metadata/screenshot-2.png +0 -0
  37. package/template/metadata/screenshot-3.png +0 -0
  38. package/template/notis.config.ts +10 -6
  39. package/template/package.json +2 -2
  40. package/template/packages/{notis-sdk → sdk}/package.json +6 -0
  41. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectActionBar.tsx +2 -1
  42. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectCheckbox.tsx +2 -2
  43. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectDragOverlay.tsx +2 -2
  44. package/template/packages/{notis-sdk → sdk}/src/config.ts +1 -1
  45. package/template/packages/{notis-sdk → sdk}/src/hooks/useDatabase.ts +1 -13
  46. package/template/packages/{notis-sdk → sdk}/src/hooks/useMultiSelect.ts +4 -3
  47. package/template/packages/{notis-sdk → sdk}/src/hooks/useNotis.ts +4 -3
  48. package/template/packages/{notis-sdk → sdk}/src/hooks/useNotisNavigation.ts +3 -3
  49. package/template/packages/{notis-sdk → sdk}/src/hooks/useTool.ts +22 -7
  50. package/template/packages/{notis-sdk → sdk}/src/hooks/useUpsertDocument.ts +0 -8
  51. package/template/packages/{notis-sdk → sdk}/src/index.ts +2 -15
  52. package/template/packages/{notis-sdk → sdk}/src/provider.tsx +1 -1
  53. package/template/packages/{notis-sdk → sdk}/src/runtime.ts +5 -26
  54. package/src/command-specs/auth.js +0 -178
  55. package/src/command-specs/db.js +0 -163
  56. package/template/packages/notis-sdk/src/helpers.ts +0 -131
  57. package/template/packages/notis-sdk/src/hooks/useAppState.ts +0 -50
  58. package/template/packages/notis-sdk/src/hooks/useCollectionItem.ts +0 -58
  59. package/template/packages/notis-sdk/src/hooks/useDocument.ts +0 -61
  60. /package/template/packages/{notis-sdk → sdk}/src/hooks/useBackend.ts +0 -0
  61. /package/template/packages/{notis-sdk → sdk}/src/hooks/useTools.ts +0 -0
  62. /package/template/packages/{notis-sdk → sdk}/src/hooks/useTopBarSearch.ts +0 -0
  63. /package/template/packages/{notis-sdk → sdk}/src/styles.css +0 -0
  64. /package/template/packages/{notis-sdk → sdk}/src/ui.ts +0 -0
  65. /package/template/packages/{notis-sdk → sdk}/src/vite.ts +0 -0
  66. /package/template/packages/{notis-sdk → sdk}/tsconfig.json +0 -0
@@ -171,37 +171,6 @@ async function toolsExecHandler(ctx) {
171
171
 
172
172
  const idempotencyKey = nextIdempotencyKey(ctx.globalOptions);
173
173
 
174
- if (ctx.options.watch) {
175
- const intervalSec = Math.max(1, parseInt(ctx.options.watch, 10));
176
- const intervalMs = intervalSec * 1000;
177
- process.on('SIGINT', () => process.exit(0));
178
-
179
- while (true) {
180
- try {
181
- const result = await runToolCommand({
182
- runtime: ctx.runtime,
183
- toolName: 'notis_execute_tool',
184
- arguments_: {
185
- tool_name: ctx.args.toolName,
186
- arguments: args,
187
- ...(toolkits.length ? { toolkits } : {}),
188
- },
189
- mutating: true,
190
- idempotencyKey: nextIdempotencyKey(ctx.globalOptions),
191
- });
192
- ctx.output.emitSuccess({
193
- command: ctx.spec.command_path.join(' '),
194
- data: result.payload,
195
- humanSummary: `[${new Date().toISOString()}] ${ctx.args.toolName}`,
196
- renderHuman: () => JSON.stringify(result.payload, null, 2),
197
- });
198
- } catch (error) {
199
- process.stderr.write(`[${new Date().toISOString()}] Error: ${error.message}\n`);
200
- }
201
- await new Promise((r) => setTimeout(r, intervalMs));
202
- }
203
- }
204
-
205
174
  const result = await runToolCommand({
206
175
  runtime: ctx.runtime,
207
176
  toolName: 'notis_execute_tool',
@@ -359,17 +328,16 @@ export const toolsCommandSpecs = [
359
328
  { flags: '--arguments <json>', description: 'JSON object, @file path, or - for stdin.' },
360
329
  { flags: '--get-schema', description: 'Display the tool parameter schema without executing.' },
361
330
  { flags: '--dry-run', description: 'Validate arguments against the tool schema without executing.' },
362
- { flags: '--watch <seconds>', description: 'Re-execute on an interval and stream results.' },
363
331
  { flags: '--toolkits <csv-or-json>', description: 'Optional toolkit namespace(s) to use when resolving the tool.' },
364
332
  ],
365
333
  },
366
334
  examples: [
367
335
  'notis tools exec notis-default-query --arguments \'{"database_slug":"tasks","query":{}}\'',
336
+ 'notis tools exec notis-default-get_database --arguments \'{"database_slug":"tasks"}\'',
368
337
  'notis tools exec notis-default-query --get-schema',
369
338
  'notis tools exec notis-default-query --dry-run --arguments \'{"database_slug":"tasks","query":{}}\'',
370
339
  'notis tools exec notis-default-query --arguments @query.json',
371
340
  'notis tools exec notis-default-query --arguments - < query.json',
372
- 'notis tools exec notis-default-query --watch 10 --arguments \'{"database_slug":"tasks","query":{}}\'',
373
341
  ],
374
342
  output_schema: 'Returns the raw tool execution payload.',
375
343
  mutates: true,
@@ -23,6 +23,7 @@ import {
23
23
  exportNameFromPath,
24
24
  getBundleDir,
25
25
  loadAppConfig,
26
+ prepareArtifactBuild,
26
27
  readManifest,
27
28
  } from './app-platform.js';
28
29
 
@@ -77,6 +78,14 @@ function scriptJson(value) {
77
78
  .replace(/\u2029/g, '\\u2029');
78
79
  }
79
80
 
81
+ function timingMs(startedAt) {
82
+ return Number(process.hrtime.bigint() - startedAt) / 1_000_000;
83
+ }
84
+
85
+ function formatTimingMs(value) {
86
+ return value.toFixed(value < 10 ? 2 : 1);
87
+ }
88
+
80
89
  function readJsonFile(path) {
81
90
  if (!existsSync(path)) {
82
91
  return null;
@@ -105,8 +114,8 @@ function reactVersionFromPeer(peerRange) {
105
114
  function resolveHarnessReactVersion(projectDir) {
106
115
  const candidates = [
107
116
  join(projectDir, 'node_modules', '@notis', 'sdk', 'package.json'),
108
- join(REPO_ROOT, 'packages', 'notis-sdk', 'package.json'),
109
- 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'),
110
119
  ];
111
120
  for (const candidate of candidates) {
112
121
  const pkg = readJsonFile(candidate);
@@ -234,7 +243,7 @@ function renderHarnessHtml({ state, manifest, appConfig, route, harnessOptions }
234
243
  /**
235
244
  * Start the dev server for one or more apps.
236
245
  *
237
- * @param {{apps: Array<{slug: string, projectDir: string, appId?: string}>, port: number, watch?: boolean, harness?: { mode?: string, apiBase?: string, jwt?: string }, log?: (m: string) => void, logError?: (m: string) => void}} options
246
+ * @param {{apps: Array<{slug: string, projectDir: string, appId?: string, userId?: string}>, port: number, watch?: boolean, harness?: { mode?: string, apiBase?: string, jwt?: string }, log?: (m: string) => void, logError?: (m: string) => void}} options
238
247
  */
239
248
  export async function startAppDevServer({
240
249
  apps,
@@ -254,6 +263,7 @@ export async function startAppDevServer({
254
263
  slug: app.slug,
255
264
  projectDir: app.projectDir,
256
265
  appId: app.appId || null,
266
+ userId: app.userId || null,
257
267
  canonicalBundleDir: getBundleDir(app.projectDir),
258
268
  bundleDir: null,
259
269
  jsPath: null,
@@ -381,11 +391,21 @@ export async function startAppDevServer({
381
391
  }
382
392
 
383
393
  if (url.pathname === '/healthz') {
394
+ const now = new Date().toISOString();
395
+ const sessions = Array.from(appState.values()).map((state) => ({
396
+ appId: state.appId,
397
+ userId: state.userId,
398
+ devSlug: state.slug,
399
+ bundleBaseUrl: `http://127.0.0.1:${port}/a/${state.slug}`,
400
+ projectDir: state.projectDir,
401
+ lastHeartbeatAt: now,
402
+ status: 'connected',
403
+ }));
384
404
  res.writeHead(200, {
385
405
  ...headers,
386
406
  'Content-Type': 'application/json; charset=utf-8',
387
407
  });
388
- res.end(JSON.stringify({ ok: true, apps: Array.from(appState.keys()) }));
408
+ res.end(JSON.stringify({ ok: true, apps: Array.from(appState.keys()), sessions }));
389
409
  return;
390
410
  }
391
411
 
@@ -454,17 +474,20 @@ export async function startAppDevServer({
454
474
  }
455
475
 
456
476
  if (routed.rest.startsWith('bundle/')) {
477
+ const startedAt = process.hrtime.bigint();
457
478
  updateBundleDir(state, resolveBundleDir(state));
458
479
  const rel = routed.rest.slice('bundle/'.length);
459
480
  if (!state.bundleDir) {
460
481
  res.writeHead(404, headers);
461
482
  res.end('not found');
483
+ log(`[notis apps timing] ${state.slug}: GET bundle/${rel} -> 404 in ${formatTimingMs(timingMs(startedAt))}ms`);
462
484
  return;
463
485
  }
464
486
  const full = safeJoin(state.bundleDir, rel);
465
487
  if (!full || !existsSync(full)) {
466
488
  res.writeHead(404, headers);
467
489
  res.end('not found');
490
+ log(`[notis apps timing] ${state.slug}: GET bundle/${rel} -> 404 in ${formatTimingMs(timingMs(startedAt))}ms`);
468
491
  return;
469
492
  }
470
493
  const ext = extFor(rel);
@@ -480,6 +503,10 @@ export async function startAppDevServer({
480
503
  } else {
481
504
  res.end(content);
482
505
  }
506
+ log(
507
+ `[notis apps timing] ${state.slug}: GET bundle/${rel} -> 200 ` +
508
+ `${content.byteLength}B in ${formatTimingMs(timingMs(startedAt))}ms`,
509
+ );
483
510
  return;
484
511
  }
485
512
 
@@ -527,6 +554,7 @@ export async function startAppDevServer({
527
554
 
528
555
  for (const state of appState.values()) {
529
556
  if (watch) {
557
+ await prepareArtifactBuild(state.projectDir);
530
558
  pollForBundleAndWatch(state);
531
559
 
532
560
  state.buildProcess = spawn('npm', ['run', 'build', '--', '--watch'], {