@notis_ai/cli 0.2.2 → 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.
- package/README.md +19 -18
- package/config/notis_app_boundary_rules.json +50 -0
- package/dist/scaffolds/notis-database/app/globals.css +44 -0
- package/dist/scaffolds/notis-database/app/page.tsx +1091 -0
- package/dist/scaffolds/notis-database/components/ui/table.tsx +120 -0
- package/dist/scaffolds/notis-database/index.html +12 -0
- package/dist/scaffolds/notis-database/lib/types.ts +134 -0
- package/dist/scaffolds/notis-database/metadata/cover.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-database/notis.config.ts +27 -0
- package/dist/scaffolds/notis-database/package.json +31 -0
- package/dist/scaffolds/notis-database/src/dev-main.tsx +23 -0
- package/dist/scaffolds/notis-database/src/mock-runtime.ts +557 -0
- package/dist/scaffolds/notis-database/tailwind.config.ts +59 -0
- package/dist/scaffolds/{notes → notis-database}/tsconfig.json +2 -1
- package/dist/scaffolds/notis-database/vite.config.ts +22 -0
- package/dist/scaffolds/notis-notes/app/layout.tsx +6 -0
- package/dist/scaffolds/{notes → notis-notes}/app/page.tsx +783 -80
- package/dist/scaffolds/notis-notes/components/ui/badge.tsx +28 -0
- package/dist/scaffolds/notis-notes/components/ui/button.tsx +53 -0
- package/dist/scaffolds/notis-notes/components/ui/card.tsx +56 -0
- package/dist/scaffolds/notis-notes/components.json +20 -0
- package/dist/scaffolds/notis-notes/lib/utils.ts +6 -0
- package/dist/scaffolds/notis-notes/metadata/cover.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/{notes → notis-notes}/notis.config.ts +12 -7
- package/dist/scaffolds/{notes → notis-notes}/package.json +2 -2
- package/dist/scaffolds/notis-notes/postcss.config.mjs +8 -0
- package/dist/scaffolds/notis-notes/tsconfig.json +23 -0
- package/dist/scaffolds/notis-random/README.md +33 -0
- package/dist/scaffolds/notis-random/app/globals.css +11 -0
- package/dist/scaffolds/notis-random/app/history/page.tsx +66 -0
- package/dist/scaffolds/notis-random/app/layout.tsx +7 -0
- package/dist/scaffolds/notis-random/app/page.tsx +222 -0
- package/dist/scaffolds/notis-random/index.html +12 -0
- package/dist/scaffolds/notis-random/lib/notis-tools.ts +109 -0
- package/dist/scaffolds/notis-random/lib/rng.ts +42 -0
- package/dist/scaffolds/notis-random/lib/roll-record.ts +102 -0
- package/dist/scaffolds/notis-random/lib/utils.ts +25 -0
- package/dist/scaffolds/notis-random/metadata/cover.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-random/notis.config.ts +43 -0
- package/dist/scaffolds/notis-random/package.json +32 -0
- package/dist/scaffolds/notis-random/postcss.config.mjs +6 -0
- package/dist/scaffolds/notis-random/src/dev-main.tsx +70 -0
- package/dist/scaffolds/notis-random/src/mock-runtime.ts +128 -0
- package/dist/scaffolds/notis-random/tailwind.config.ts +43 -0
- package/dist/scaffolds/notis-random/tsconfig.json +23 -0
- package/dist/scaffolds/notis-random/vite.config.ts +11 -0
- package/dist/scaffolds.json +27 -4
- package/package.json +2 -1
- package/skills/notis-apps/SKILL.md +2 -2
- package/skills/notis-cli/SKILL.md +18 -16
- package/skills/notis-query/cli.md +9 -10
- package/src/cli.js +30 -2
- package/src/command-specs/apps.js +42 -15
- package/src/command-specs/helpers.js +73 -45
- package/src/command-specs/meta.js +7 -7
- package/src/command-specs/tools.js +196 -83
- package/src/runtime/app-boundary-validator.js +65 -14
- package/src/runtime/profiles.js +10 -4
- package/src/runtime/transport.js +122 -37
- package/template/app/page.tsx +1 -1
- package/template/notis.config.ts +1 -1
- package/template/packages/sdk/src/hooks/useTool.ts +1 -1
- /package/dist/scaffolds/{notes → notis-database}/app/layout.tsx +0 -0
- /package/dist/scaffolds/{notes → notis-database}/components/ui/badge.tsx +0 -0
- /package/dist/scaffolds/{notes → notis-database}/components/ui/button.tsx +0 -0
- /package/dist/scaffolds/{notes → notis-database}/components/ui/card.tsx +0 -0
- /package/dist/scaffolds/{notes → notis-database}/components.json +0 -0
- /package/dist/scaffolds/{notes → notis-database}/lib/utils.ts +0 -0
- /package/dist/scaffolds/{notes → notis-database}/postcss.config.mjs +0 -0
- /package/dist/scaffolds/{notes → notis-notes}/app/globals.css +0 -0
- /package/dist/scaffolds/{notes → notis-notes}/tailwind.config.ts +0 -0
- /package/dist/scaffolds/{notes → notis-notes}/vite.config.ts +0 -0
package/src/runtime/transport.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
2
3
|
import { CliError, EXIT_CODES } from './errors.js';
|
|
3
4
|
import {
|
|
4
5
|
DEFAULT_PROFILE,
|
|
@@ -8,31 +9,71 @@ import {
|
|
|
8
9
|
saveConfig,
|
|
9
10
|
} from './profiles.js';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function canonicalizeToolName(toolName) {
|
|
19
|
-
if (typeof toolName !== 'string' || !toolName.length) {
|
|
20
|
-
return toolName;
|
|
21
|
-
}
|
|
12
|
+
function escapeMultipartHeaderValue(value) {
|
|
13
|
+
return String(value ?? '')
|
|
14
|
+
.replace(/"/g, '%22')
|
|
15
|
+
.replace(/\r/g, '%0D')
|
|
16
|
+
.replace(/\n/g, '%0A');
|
|
17
|
+
}
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
function multipartTextPart(boundary, name, value) {
|
|
20
|
+
return [
|
|
21
|
+
`--${boundary}`,
|
|
22
|
+
`Content-Disposition: form-data; name="${escapeMultipartHeaderValue(name)}"`,
|
|
23
|
+
'',
|
|
24
|
+
value,
|
|
25
|
+
'',
|
|
26
|
+
].join('\r\n');
|
|
27
|
+
}
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
function multipartFileHeader(boundary, binding) {
|
|
30
|
+
const filename = escapeMultipartHeaderValue(binding.basename || binding.field_name);
|
|
31
|
+
return [
|
|
32
|
+
`--${boundary}`,
|
|
33
|
+
`Content-Disposition: form-data; name="${escapeMultipartHeaderValue(binding.field_name)}"; filename="${filename}"`,
|
|
34
|
+
`Content-Type: ${binding.contentType || 'application/octet-stream'}`,
|
|
35
|
+
'',
|
|
36
|
+
'',
|
|
37
|
+
].join('\r\n');
|
|
38
|
+
}
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
async function* multipartFileBody(boundary, payload, bindingMetadata, fileBindings) {
|
|
41
|
+
yield Buffer.from(multipartTextPart(boundary, 'payload', JSON.stringify(payload)));
|
|
42
|
+
yield Buffer.from(multipartTextPart(boundary, 'file_bindings', JSON.stringify(bindingMetadata)));
|
|
43
|
+
for (const binding of fileBindings) {
|
|
44
|
+
yield Buffer.from(multipartFileHeader(boundary, binding));
|
|
45
|
+
for await (const chunk of createReadStream(binding.localPath)) {
|
|
46
|
+
yield chunk;
|
|
47
|
+
}
|
|
48
|
+
yield Buffer.from('\r\n');
|
|
33
49
|
}
|
|
50
|
+
yield Buffer.from(`--${boundary}--\r\n`);
|
|
51
|
+
}
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
function createMultipartFileUpload(payload, bindingMetadata, fileBindings) {
|
|
54
|
+
const boundary = `----notis-cli-${randomUUID().replace(/-/g, '')}`;
|
|
55
|
+
const textParts = [
|
|
56
|
+
multipartTextPart(boundary, 'payload', JSON.stringify(payload)),
|
|
57
|
+
multipartTextPart(boundary, 'file_bindings', JSON.stringify(bindingMetadata)),
|
|
58
|
+
];
|
|
59
|
+
const fileHeaderParts = fileBindings.map((binding) => multipartFileHeader(boundary, binding));
|
|
60
|
+
const closingPart = `--${boundary}--\r\n`;
|
|
61
|
+
const contentLength = [
|
|
62
|
+
...textParts,
|
|
63
|
+
...fileHeaderParts,
|
|
64
|
+
...fileBindings.map(() => '\r\n'),
|
|
65
|
+
closingPart,
|
|
66
|
+
].reduce((total, part) => total + Buffer.byteLength(part), 0)
|
|
67
|
+
+ fileBindings.reduce((total, binding) => total + binding.size, 0);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
body: multipartFileBody(boundary, payload, bindingMetadata, fileBindings),
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
73
|
+
'Content-Length': String(contentLength),
|
|
74
|
+
},
|
|
75
|
+
duplex: 'half',
|
|
76
|
+
};
|
|
36
77
|
}
|
|
37
78
|
|
|
38
79
|
function normalizeBackendError(status, payload) {
|
|
@@ -197,6 +238,7 @@ export async function httpRequest({
|
|
|
197
238
|
method = 'POST',
|
|
198
239
|
path,
|
|
199
240
|
body,
|
|
241
|
+
multipart = false,
|
|
200
242
|
requireAuth = true,
|
|
201
243
|
}) {
|
|
202
244
|
await maybeRefreshDevPortalAuth(runtime);
|
|
@@ -211,21 +253,41 @@ export async function httpRequest({
|
|
|
211
253
|
};
|
|
212
254
|
|
|
213
255
|
const headers = {
|
|
214
|
-
'Content-Type': 'application/json',
|
|
215
256
|
'X-Notis-CLI-Version': runtime.cliVersion,
|
|
216
257
|
'X-Notis-Request-Id': requestId,
|
|
217
258
|
};
|
|
259
|
+
if (!multipart) {
|
|
260
|
+
headers['Content-Type'] = 'application/json';
|
|
261
|
+
}
|
|
218
262
|
|
|
219
263
|
if (requireAuth && runtime.jwt) {
|
|
220
264
|
headers.Authorization = `Bearer ${runtime.jwt}`;
|
|
221
265
|
}
|
|
222
266
|
|
|
267
|
+
const resolveBody = () => {
|
|
268
|
+
if (!multipart) {
|
|
269
|
+
return {
|
|
270
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
271
|
+
headers: {},
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (typeof body === 'function') {
|
|
275
|
+
return body();
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
body,
|
|
279
|
+
headers: {},
|
|
280
|
+
};
|
|
281
|
+
};
|
|
282
|
+
|
|
223
283
|
try {
|
|
284
|
+
let requestBody = resolveBody();
|
|
224
285
|
let response = await fetch(`${runtime.apiBase}${path}`, {
|
|
225
286
|
method,
|
|
226
|
-
headers,
|
|
227
|
-
body:
|
|
287
|
+
headers: { ...headers, ...requestBody.headers },
|
|
288
|
+
body: requestBody.body,
|
|
228
289
|
signal: controller.signal,
|
|
290
|
+
...(requestBody.duplex ? { duplex: requestBody.duplex } : {}),
|
|
229
291
|
});
|
|
230
292
|
|
|
231
293
|
let payload = null;
|
|
@@ -243,11 +305,13 @@ export async function httpRequest({
|
|
|
243
305
|
headers.Authorization = `Bearer ${runtime.jwt}`;
|
|
244
306
|
}
|
|
245
307
|
resetTimeout();
|
|
308
|
+
requestBody = resolveBody();
|
|
246
309
|
response = await fetch(`${runtime.apiBase}${path}`, {
|
|
247
310
|
method,
|
|
248
|
-
headers,
|
|
249
|
-
body:
|
|
311
|
+
headers: { ...headers, ...requestBody.headers },
|
|
312
|
+
body: requestBody.body,
|
|
250
313
|
signal: controller.signal,
|
|
314
|
+
...(requestBody.duplex ? { duplex: requestBody.duplex } : {}),
|
|
251
315
|
});
|
|
252
316
|
try {
|
|
253
317
|
payload = await response.json();
|
|
@@ -302,22 +366,43 @@ export async function callTool({
|
|
|
302
366
|
toolName,
|
|
303
367
|
arguments_: argumentsPayload = {},
|
|
304
368
|
idempotencyKey,
|
|
369
|
+
fileBindings = [],
|
|
305
370
|
}) {
|
|
306
371
|
const requestId = idempotencyKey || (runtime.mutating ? randomUUID() : null);
|
|
372
|
+
const payload = {
|
|
373
|
+
tool_name: toolName,
|
|
374
|
+
arguments: argumentsPayload,
|
|
375
|
+
idempotency_key: requestId,
|
|
376
|
+
cli_context: {
|
|
377
|
+
output_mode: runtime.outputMode,
|
|
378
|
+
profile: runtime.profileName,
|
|
379
|
+
cwd: process.cwd(),
|
|
380
|
+
agent_mode: runtime.agentMode,
|
|
381
|
+
cli_version: runtime.cliVersion,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
if (Array.isArray(fileBindings) && fileBindings.length) {
|
|
386
|
+
const bindingMetadata = fileBindings.map((binding) => {
|
|
387
|
+
const {
|
|
388
|
+
contentType,
|
|
389
|
+
localPath,
|
|
390
|
+
...metadata
|
|
391
|
+
} = binding;
|
|
392
|
+
return metadata;
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
return httpRequest({
|
|
396
|
+
runtime,
|
|
397
|
+
path: '/cli_tools',
|
|
398
|
+
body: () => createMultipartFileUpload(payload, bindingMetadata, fileBindings),
|
|
399
|
+
multipart: true,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
307
403
|
return httpRequest({
|
|
308
404
|
runtime,
|
|
309
405
|
path: '/cli_tools',
|
|
310
|
-
body:
|
|
311
|
-
tool_name: canonicalizeToolName(toolName),
|
|
312
|
-
arguments: argumentsPayload,
|
|
313
|
-
idempotency_key: requestId,
|
|
314
|
-
cli_context: {
|
|
315
|
-
output_mode: runtime.outputMode,
|
|
316
|
-
profile: runtime.profileName,
|
|
317
|
-
cwd: process.cwd(),
|
|
318
|
-
agent_mode: runtime.agentMode,
|
|
319
|
-
cli_version: runtime.cliVersion,
|
|
320
|
-
},
|
|
321
|
-
},
|
|
406
|
+
body: payload,
|
|
322
407
|
});
|
|
323
408
|
}
|
package/template/app/page.tsx
CHANGED
|
@@ -25,7 +25,7 @@ type QueryItemsResult = {
|
|
|
25
25
|
|
|
26
26
|
export default function HomePage() {
|
|
27
27
|
const { app, ready } = useNotis();
|
|
28
|
-
const queryItems = useTool<QueryItemsArgs, QueryItemsResult>('
|
|
28
|
+
const queryItems = useTool<QueryItemsArgs, QueryItemsResult>('LOCAL_NOTIS_DATABASE_QUERY');
|
|
29
29
|
const [documents, setDocuments] = useState<ItemDocument[]>([]);
|
|
30
30
|
|
|
31
31
|
useEffect(() => {
|
package/template/notis.config.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface UseToolResult<
|
|
|
25
25
|
* Call a specific Notis tool by name.
|
|
26
26
|
*
|
|
27
27
|
* ```tsx
|
|
28
|
-
* const { call, loading } = useTool('
|
|
28
|
+
* const { call, loading } = useTool('LOCAL_NOTIS_WEB_SEARCH');
|
|
29
29
|
* const result = await call({ query: 'latest news' });
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|