@notis_ai/cli 0.2.1 → 0.2.3

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 (117) hide show
  1. package/README.md +106 -170
  2. package/config/notis_app_boundary_rules.json +50 -0
  3. package/dist/scaffolds/notis-database/app/globals.css +44 -0
  4. package/dist/scaffolds/notis-database/app/layout.tsx +6 -0
  5. package/dist/scaffolds/notis-database/app/page.tsx +1091 -0
  6. package/dist/scaffolds/notis-database/components/ui/badge.tsx +28 -0
  7. package/dist/scaffolds/notis-database/components/ui/button.tsx +53 -0
  8. package/dist/scaffolds/notis-database/components/ui/card.tsx +56 -0
  9. package/dist/scaffolds/notis-database/components/ui/table.tsx +120 -0
  10. package/dist/scaffolds/notis-database/components.json +20 -0
  11. package/dist/scaffolds/notis-database/index.html +12 -0
  12. package/dist/scaffolds/notis-database/lib/types.ts +134 -0
  13. package/dist/scaffolds/notis-database/lib/utils.ts +6 -0
  14. package/dist/scaffolds/notis-database/metadata/cover.png +0 -0
  15. package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
  16. package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
  17. package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
  18. package/dist/scaffolds/notis-database/notis.config.ts +27 -0
  19. package/dist/scaffolds/notis-database/package.json +31 -0
  20. package/dist/scaffolds/notis-database/postcss.config.mjs +8 -0
  21. package/dist/scaffolds/notis-database/src/dev-main.tsx +23 -0
  22. package/dist/scaffolds/notis-database/src/mock-runtime.ts +557 -0
  23. package/dist/scaffolds/notis-database/tailwind.config.ts +59 -0
  24. package/dist/scaffolds/notis-database/tsconfig.json +23 -0
  25. package/dist/scaffolds/notis-database/vite.config.ts +22 -0
  26. package/dist/scaffolds/notis-notes/app/globals.css +3 -0
  27. package/dist/scaffolds/notis-notes/app/layout.tsx +6 -0
  28. package/dist/scaffolds/notis-notes/app/page.tsx +2168 -0
  29. package/dist/scaffolds/notis-notes/components/ui/badge.tsx +28 -0
  30. package/dist/scaffolds/notis-notes/components/ui/button.tsx +53 -0
  31. package/dist/scaffolds/notis-notes/components/ui/card.tsx +56 -0
  32. package/dist/scaffolds/notis-notes/components.json +20 -0
  33. package/dist/scaffolds/notis-notes/lib/utils.ts +6 -0
  34. package/dist/scaffolds/notis-notes/metadata/cover.png +0 -0
  35. package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
  36. package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
  37. package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
  38. package/dist/scaffolds/notis-notes/notis.config.ts +36 -0
  39. package/dist/scaffolds/notis-notes/package.json +31 -0
  40. package/dist/scaffolds/notis-notes/postcss.config.mjs +8 -0
  41. package/dist/scaffolds/notis-notes/tailwind.config.ts +58 -0
  42. package/dist/scaffolds/notis-notes/tsconfig.json +23 -0
  43. package/dist/scaffolds/notis-notes/vite.config.ts +10 -0
  44. package/dist/scaffolds/notis-random/README.md +33 -0
  45. package/dist/scaffolds/notis-random/app/globals.css +11 -0
  46. package/dist/scaffolds/notis-random/app/history/page.tsx +66 -0
  47. package/dist/scaffolds/notis-random/app/layout.tsx +7 -0
  48. package/dist/scaffolds/notis-random/app/page.tsx +222 -0
  49. package/dist/scaffolds/notis-random/index.html +12 -0
  50. package/dist/scaffolds/notis-random/lib/notis-tools.ts +109 -0
  51. package/dist/scaffolds/notis-random/lib/rng.ts +42 -0
  52. package/dist/scaffolds/notis-random/lib/roll-record.ts +102 -0
  53. package/dist/scaffolds/notis-random/lib/utils.ts +25 -0
  54. package/dist/scaffolds/notis-random/metadata/cover.png +0 -0
  55. package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
  56. package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
  57. package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
  58. package/dist/scaffolds/notis-random/notis.config.ts +43 -0
  59. package/dist/scaffolds/notis-random/package.json +32 -0
  60. package/dist/scaffolds/notis-random/postcss.config.mjs +6 -0
  61. package/dist/scaffolds/notis-random/src/dev-main.tsx +70 -0
  62. package/dist/scaffolds/notis-random/src/mock-runtime.ts +128 -0
  63. package/dist/scaffolds/notis-random/tailwind.config.ts +43 -0
  64. package/dist/scaffolds/notis-random/tsconfig.json +23 -0
  65. package/dist/scaffolds/notis-random/vite.config.ts +11 -0
  66. package/dist/scaffolds.json +36 -0
  67. package/package.json +8 -3
  68. package/skills/notis-apps/SKILL.md +162 -0
  69. package/skills/notis-apps/cli.md +208 -0
  70. package/skills/notis-cli/SKILL.md +260 -0
  71. package/skills/notis-query/cli.md +39 -0
  72. package/src/cli.js +31 -3
  73. package/src/command-specs/apps.js +248 -56
  74. package/src/command-specs/helpers.js +72 -104
  75. package/src/command-specs/index.js +0 -6
  76. package/src/command-specs/meta.js +14 -13
  77. package/src/command-specs/tools.js +196 -115
  78. package/src/runtime/app-boundary-validator.js +65 -14
  79. package/src/runtime/app-dev-server.js +32 -4
  80. package/src/runtime/app-platform.js +404 -24
  81. package/src/runtime/profiles.js +12 -6
  82. package/src/runtime/transport.js +124 -39
  83. package/template/.harness/index.html.tmpl +1 -50
  84. package/template/app/page.tsx +41 -6
  85. package/template/metadata/cover.png +0 -0
  86. package/template/metadata/screenshot-1.png +0 -0
  87. package/template/metadata/screenshot-2.png +0 -0
  88. package/template/metadata/screenshot-3.png +0 -0
  89. package/template/notis.config.ts +10 -6
  90. package/template/package.json +2 -2
  91. package/template/packages/{notis-sdk → sdk}/package.json +6 -0
  92. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectActionBar.tsx +2 -1
  93. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectCheckbox.tsx +2 -2
  94. package/template/packages/{notis-sdk → sdk}/src/components/MultiSelectDragOverlay.tsx +2 -2
  95. package/template/packages/{notis-sdk → sdk}/src/config.ts +1 -1
  96. package/template/packages/{notis-sdk → sdk}/src/hooks/useDatabase.ts +1 -13
  97. package/template/packages/{notis-sdk → sdk}/src/hooks/useMultiSelect.ts +4 -3
  98. package/template/packages/{notis-sdk → sdk}/src/hooks/useNotis.ts +4 -3
  99. package/template/packages/{notis-sdk → sdk}/src/hooks/useNotisNavigation.ts +3 -3
  100. package/template/packages/{notis-sdk → sdk}/src/hooks/useTool.ts +22 -7
  101. package/template/packages/{notis-sdk → sdk}/src/hooks/useUpsertDocument.ts +0 -8
  102. package/template/packages/{notis-sdk → sdk}/src/index.ts +2 -15
  103. package/template/packages/{notis-sdk → sdk}/src/provider.tsx +1 -1
  104. package/template/packages/{notis-sdk → sdk}/src/runtime.ts +5 -26
  105. package/src/command-specs/auth.js +0 -178
  106. package/src/command-specs/db.js +0 -163
  107. package/template/packages/notis-sdk/src/helpers.ts +0 -131
  108. package/template/packages/notis-sdk/src/hooks/useAppState.ts +0 -50
  109. package/template/packages/notis-sdk/src/hooks/useCollectionItem.ts +0 -58
  110. package/template/packages/notis-sdk/src/hooks/useDocument.ts +0 -61
  111. /package/template/packages/{notis-sdk → sdk}/src/hooks/useBackend.ts +0 -0
  112. /package/template/packages/{notis-sdk → sdk}/src/hooks/useTools.ts +0 -0
  113. /package/template/packages/{notis-sdk → sdk}/src/hooks/useTopBarSearch.ts +0 -0
  114. /package/template/packages/{notis-sdk → sdk}/src/styles.css +0 -0
  115. /package/template/packages/{notis-sdk → sdk}/src/ui.ts +0 -0
  116. /package/template/packages/{notis-sdk → sdk}/src/vite.ts +0 -0
  117. /package/template/packages/{notis-sdk → sdk}/tsconfig.json +0 -0
@@ -1,13 +1,34 @@
1
- import { createInterface } from 'node:readline/promises';
2
1
  import { randomUUID } from 'node:crypto';
3
2
  import { CliError, EXIT_CODES, usageError } from '../runtime/errors.js';
4
3
  import { callTool, httpRequest } from '../runtime/transport.js';
5
- import {
6
- DEFAULT_PROFILE,
7
- ensureProfile,
8
- loadConfig,
9
- saveConfig,
10
- } from '../runtime/profiles.js';
4
+
5
+ export const COMPOSIO_SEARCH_TOOLS = 'COMPOSIO_SEARCH_TOOLS';
6
+ export const COMPOSIO_GET_TOOL_SCHEMAS = 'COMPOSIO_GET_TOOL_SCHEMAS';
7
+ export const COMPOSIO_MULTI_EXECUTE_TOOL = 'COMPOSIO_MULTI_EXECUTE_TOOL';
8
+
9
+ const NOTIS_DATABASE_CORE_NAMES = new Set([
10
+ 'query',
11
+ 'get_database',
12
+ 'get_document',
13
+ 'list_databases',
14
+ 'upsert_database',
15
+ ]);
16
+
17
+ function isNotisDatabaseCoreName(coreName) {
18
+ // Mirrors server is_database_tool_name: canonical database ops plus generated
19
+ // upsert_<db> tools. Database tools live in the NOTIS_DATABASE toolkit so their
20
+ // public slug carries the DATABASE segment.
21
+ return NOTIS_DATABASE_CORE_NAMES.has(coreName) || coreName.startsWith('upsert_');
22
+ }
23
+
24
+ export function localNotisToolSlug(toolName) {
25
+ if (typeof toolName !== 'string' || !toolName.startsWith('notis-')) {
26
+ return toolName;
27
+ }
28
+ const coreName = toolName.slice('notis-'.length);
29
+ const prefix = isNotisDatabaseCoreName(coreName) ? 'LOCAL_NOTIS_DATABASE_' : 'LOCAL_NOTIS_';
30
+ return `${prefix}${coreName.replace(/-/g, '_').toUpperCase()}`;
31
+ }
11
32
 
12
33
  export function parseJson(value, label) {
13
34
  try {
@@ -24,33 +45,6 @@ export function parseMaybeJson(value, label) {
24
45
  return parseJson(value, label);
25
46
  }
26
47
 
27
- export function normalizeToolkits(value) {
28
- if (!value) {
29
- return [];
30
- }
31
- if (value.startsWith('[')) {
32
- const parsed = parseJson(value, 'toolkits');
33
- if (!Array.isArray(parsed)) {
34
- throw usageError('toolkits JSON must be an array of toolkit strings');
35
- }
36
- return parsed;
37
- }
38
- return value
39
- .split(',')
40
- .map((entry) => entry.trim())
41
- .filter(Boolean);
42
- }
43
-
44
- export async function promptForJwt() {
45
- const rl = createInterface({ input: process.stdin, output: process.stdout });
46
- try {
47
- const jwt = await rl.question('Paste your Notis JWT: ');
48
- return jwt.trim();
49
- } finally {
50
- rl.close();
51
- }
52
- }
53
-
54
48
  export function nextIdempotencyKey(globalOptions) {
55
49
  return globalOptions.idempotencyKey || randomUUID();
56
50
  }
@@ -61,39 +55,32 @@ export async function runToolCommand({
61
55
  arguments_ = {},
62
56
  mutating = false,
63
57
  idempotencyKey,
58
+ fileBindings = [],
64
59
  }) {
65
60
  const result = await callTool({
66
61
  runtime: { ...runtime, mutating },
67
62
  toolName,
68
63
  arguments_,
69
64
  idempotencyKey: mutating ? idempotencyKey : null,
65
+ fileBindings,
70
66
  });
71
67
  return result;
72
68
  }
73
69
 
74
70
  export async function fetchToolkits(runtime) {
75
- const result = await runToolCommand({
76
- runtime,
77
- toolName: 'notis_find_toolkits',
78
- });
79
- return result.payload.toolkits || [];
80
- }
81
-
82
- export async function resolveSearchToolkits(runtime, rawToolkits) {
83
- const toolkits = normalizeToolkits(rawToolkits);
84
- if (toolkits.length) {
85
- return toolkits;
86
- }
87
- const availableToolkits = await fetchToolkits(runtime);
88
- return availableToolkits.map((entry) => entry.id);
71
+ const payload = await fetchToolDiscovery(runtime, 'List available toolkit namespaces and connection statuses');
72
+ return (payload.toolkit_connection_statuses || []).map((entry) => ({
73
+ id: entry.toolkit,
74
+ provider: typeof entry.toolkit === 'string' ? entry.toolkit.split('-', 1)[0] : undefined,
75
+ description: entry.description || entry.status_message || entry.toolkit,
76
+ has_active_connection: Boolean(entry.has_active_connection),
77
+ status_message: entry.status_message || '',
78
+ connection_details: entry.connection_details || {},
79
+ }));
89
80
  }
90
81
 
91
82
  export async function probeAuth(runtime) {
92
- const result = await runToolCommand({
93
- runtime,
94
- toolName: 'notis_find_toolkits',
95
- });
96
- return result.payload;
83
+ return fetchToolDiscovery(runtime, 'List available toolkit namespaces and connection statuses');
97
84
  }
98
85
 
99
86
  export async function healthCheck(runtime) {
@@ -105,65 +92,46 @@ export async function healthCheck(runtime) {
105
92
  });
106
93
  }
107
94
 
108
- export function updateStoredProfile({
109
- profileName,
110
- jwt,
111
- apiBase,
112
- authMode,
113
- refreshToken,
114
- accessExpiresAt,
115
- refreshExpiresAt,
116
- setCurrent = true,
117
- }) {
118
- let config = ensureProfile(loadConfig(), profileName || DEFAULT_PROFILE);
119
- const resolvedName = profileName || DEFAULT_PROFILE;
120
- config.profiles[resolvedName] = {
121
- ...config.profiles[resolvedName],
122
- ...(jwt ? { jwt } : {}),
123
- ...(apiBase ? { api_base: apiBase } : {}),
124
- ...(authMode ? { auth_mode: authMode } : {}),
125
- ...(refreshToken ? { refresh_token: refreshToken } : {}),
126
- ...(typeof accessExpiresAt === 'number'
127
- ? { access_expires_at: accessExpiresAt }
128
- : {}),
129
- ...(typeof refreshExpiresAt === 'number'
130
- ? { refresh_expires_at: refreshExpiresAt }
131
- : {}),
132
- };
133
- if (setCurrent) {
134
- config.current_profile = resolvedName;
95
+ export async function fetchToolSchema(runtime, toolName) {
96
+ const result = await runToolCommand({
97
+ runtime,
98
+ toolName: COMPOSIO_GET_TOOL_SCHEMAS,
99
+ arguments_: {
100
+ tool_slugs: [toolName],
101
+ },
102
+ });
103
+ const payload = result.payload || {};
104
+ const schema = (
105
+ payload.tool_schemas?.[toolName] ||
106
+ payload.schemas?.[toolName] ||
107
+ payload.tools?.find?.((tool) => tool?.tool_slug === toolName || tool?.name === toolName)
108
+ );
109
+ if (!schema) {
110
+ throw usageError(`Tool "${toolName}" not found.`);
135
111
  }
136
- saveConfig(config);
137
- return config;
138
- }
139
-
140
- export function clearStoredJwt(profileName) {
141
- const config = ensureProfile(loadConfig(), profileName || DEFAULT_PROFILE);
142
- delete config.profiles[profileName || DEFAULT_PROFILE].jwt;
143
- delete config.profiles[profileName || DEFAULT_PROFILE].auth_mode;
144
- delete config.profiles[profileName || DEFAULT_PROFILE].refresh_token;
145
- delete config.profiles[profileName || DEFAULT_PROFILE].access_expires_at;
146
- delete config.profiles[profileName || DEFAULT_PROFILE].refresh_expires_at;
147
- saveConfig(config);
148
- return config;
112
+ return {
113
+ name: toolName,
114
+ toolkit_id: schema.toolkit,
115
+ description: schema.description || '',
116
+ parameters: schema.input_schema || { type: 'object', properties: {} },
117
+ output_schema: schema.output_schema || {},
118
+ schema_available: Boolean(schema.hasFullSchema),
119
+ };
149
120
  }
150
121
 
151
- export async function fetchToolSchema(runtime, toolName, rawToolkits) {
152
- const toolkits = normalizeToolkits(rawToolkits);
122
+ export async function fetchToolDiscovery(runtime, useCase, knownFields = '') {
123
+ const query = { use_case: useCase };
124
+ if (knownFields) {
125
+ query.known_fields = knownFields;
126
+ }
153
127
  const result = await runToolCommand({
154
128
  runtime,
155
- toolName: 'notis_find_tools',
129
+ toolName: COMPOSIO_SEARCH_TOOLS,
156
130
  arguments_: {
157
- query: toolName,
158
- ...(toolkits.length ? { toolkits } : {}),
131
+ queries: [query],
159
132
  },
160
133
  });
161
- const tools = result.payload.tools || [];
162
- const match = tools.find((t) => t.name === toolName);
163
- if (!match) {
164
- throw usageError(`Tool "${toolName}" not found.`);
165
- }
166
- return match;
134
+ return result.payload || {};
167
135
  }
168
136
 
169
137
  export function validateArguments(schema, args) {
@@ -1,20 +1,14 @@
1
- import { authCommandSpecs } from './auth.js';
2
1
  import { appsCommandSpecs } from './apps.js';
3
- import { dbCommandSpecs } from './db.js';
4
2
  import { toolsCommandSpecs } from './tools.js';
5
3
  import { metaCommandSpecs } from './meta.js';
6
4
 
7
5
  export const GROUP_SUMMARIES = {
8
- auth: 'Authentication and profile management.',
9
6
  apps: 'Develop, build, and deploy Notis Apps.',
10
- db: 'List, query, and update native Notis Databases.',
11
7
  tools: 'Discover and execute generic tools exposed through Notis.',
12
8
  };
13
9
 
14
10
  export const COMMAND_SPECS = [
15
- ...authCommandSpecs,
16
11
  ...appsCommandSpecs,
17
- ...dbCommandSpecs,
18
12
  ...toolsCommandSpecs,
19
13
  ...metaCommandSpecs,
20
14
  ];
@@ -1,4 +1,4 @@
1
- import { healthCheck, probeAuth } from './helpers.js';
1
+ import { COMPOSIO_SEARCH_TOOLS, healthCheck, probeAuth } from './helpers.js';
2
2
  import { findCommandSpec, formatDescribe } from '../runtime/help.js';
3
3
 
4
4
  async function doctorHandler(ctx) {
@@ -21,7 +21,7 @@ async function doctorHandler(ctx) {
21
21
  if (ctx.runtime.jwt) {
22
22
  try {
23
23
  const payload = await probeAuth(ctx.runtime);
24
- checks.tool_roundtrip = Array.isArray(payload.toolkits) ? 'ok' : 'error';
24
+ checks.tool_roundtrip = Array.isArray(payload.toolkit_connection_statuses) ? 'ok' : 'error';
25
25
  } catch {
26
26
  checks.tool_roundtrip = 'error';
27
27
  }
@@ -29,10 +29,10 @@ async function doctorHandler(ctx) {
29
29
 
30
30
  const hints = [];
31
31
  if (checks.auth === 'missing') {
32
- hints.push({ command: 'notis auth login --jwt <token>', reason: 'Configure credentials' });
32
+ hints.push({ command: 'Open the Notis desktop app and sign in', reason: 'Configure CLI credentials' });
33
33
  }
34
34
  if (checks.health === 'error') {
35
- hints.push({ command: 'notis auth status', reason: 'Check API base URL configuration' });
35
+ hints.push({ command: 'Open the Notis desktop app and sign in again', reason: 'Refresh local CLI configuration' });
36
36
  }
37
37
  if (checks.tool_roundtrip === 'error') {
38
38
  hints.push({ command: 'notis whoami', reason: 'Verify your account and permissions' });
@@ -68,7 +68,7 @@ function decodeJwtUserId(jwt) {
68
68
 
69
69
  async function whoamiHandler(ctx) {
70
70
  const payload = await probeAuth(ctx.runtime);
71
- const toolkits = payload.toolkits || [];
71
+ const toolkits = payload.toolkit_connection_statuses || [];
72
72
  const userId = decodeJwtUserId(ctx.runtime.jwt);
73
73
 
74
74
  return ctx.output.emitSuccess({
@@ -78,7 +78,7 @@ async function whoamiHandler(ctx) {
78
78
  api_base: ctx.runtime.apiBase,
79
79
  user_id: userId,
80
80
  toolkit_count: toolkits.length,
81
- toolkits: toolkits.map((t) => t.id),
81
+ toolkits: toolkits.map((t) => t.toolkit),
82
82
  cli_version: ctx.runtime.cliVersion,
83
83
  },
84
84
  humanSummary: `Logged in as ${userId || 'unknown'} via profile "${ctx.runtime.profileName}"`,
@@ -91,7 +91,7 @@ async function whoamiHandler(ctx) {
91
91
  `Version: ${ctx.runtime.cliVersion}`,
92
92
  ].join('\n'),
93
93
  hints: [
94
- { command: 'notis tools toolkits', reason: 'List available toolkit namespaces' },
94
+ { command: 'notis tools toolkits', reason: 'List available toolkit namespaces and connection statuses' },
95
95
  { command: 'notis doctor', reason: 'Run a full health check' },
96
96
  ],
97
97
  });
@@ -110,15 +110,15 @@ async function describeHandler(ctx) {
110
110
  export const metaCommandSpecs = [
111
111
  {
112
112
  command_path: ['whoami'],
113
- summary: 'Display the active profile, user, and available toolkits.',
113
+ summary: 'Display the active profile, user, and available toolkit connection statuses.',
114
114
  when_to_use: 'Use this to quickly confirm which account and environment a command will target.',
115
115
  args_schema: { arguments: [], options: [] },
116
116
  examples: ['notis whoami', 'notis whoami --json'],
117
117
  output_schema: 'Returns profile, api_base, user_id, toolkit count, and CLI version.',
118
118
  mutates: false,
119
119
  idempotent: true,
120
- related_commands: ['notis auth status --verify', 'notis doctor'],
121
- backend_call: { type: 'tool', name: 'notis_find_toolkits' },
120
+ related_commands: ['notis doctor'],
121
+ backend_call: { type: 'tool', name: COMPOSIO_SEARCH_TOOLS },
122
122
  handler: whoamiHandler,
123
123
  },
124
124
  {
@@ -130,7 +130,8 @@ export const metaCommandSpecs = [
130
130
  output_schema: 'Returns config, auth, health, and roundtrip check statuses.',
131
131
  mutates: false,
132
132
  idempotent: true,
133
- related_commands: ['notis auth status --verify', 'notis tools toolkits'],
133
+ require_auth: false,
134
+ related_commands: ['notis tools toolkits'],
134
135
  backend_call: { type: 'health+tool_roundtrip' },
135
136
  handler: doctorHandler,
136
137
  },
@@ -139,10 +140,10 @@ export const metaCommandSpecs = [
139
140
  summary: 'Describe a first-class CLI command in detail.',
140
141
  when_to_use: 'Use this when an agent or human needs the exact shape, examples, and semantics of a command.',
141
142
  args_schema: {
142
- arguments: [{ token: '<command...>', key: 'commandPath', description: 'Command path to describe, such as "apps push".' }],
143
+ arguments: [{ token: '<command...>', key: 'commandPath', description: 'Command path to describe, such as "apps deploy".' }],
143
144
  options: [],
144
145
  },
145
- examples: ['notis describe apps push', 'notis describe db query'],
146
+ examples: ['notis describe apps deploy', 'notis describe tools exec'],
146
147
  output_schema: 'Returns the command spec metadata for the requested command.',
147
148
  mutates: false,
148
149
  idempotent: true,