incur 0.3.1 → 0.3.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 +22 -26
- package/SKILL.md +17 -20
- package/dist/Cli.d.ts +1 -1
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +132 -24
- package/dist/Cli.js.map +1 -1
- package/dist/Fetch.d.ts.map +1 -1
- package/dist/Fetch.js.map +1 -1
- package/dist/Filter.js.map +1 -1
- package/dist/Help.js +21 -7
- package/dist/Help.js.map +1 -1
- package/dist/Openapi.d.ts.map +1 -1
- package/dist/Openapi.js +10 -2
- package/dist/Openapi.js.map +1 -1
- package/dist/Skill.d.ts.map +1 -1
- package/dist/Skill.js.map +1 -1
- package/package.json +1 -1
- package/src/Cli.test.ts +13 -24
- package/src/Cli.ts +211 -63
- package/src/Fetch.test.ts +3 -13
- package/src/Fetch.ts +1 -2
- package/src/Filter.ts +7 -3
- package/src/Help.test.ts +22 -2
- package/src/Help.ts +19 -5
- package/src/Openapi.test.ts +89 -32
- package/src/Openapi.ts +15 -6
- package/src/Skill.test.ts +1 -3
- package/src/Skill.ts +9 -2
- package/src/e2e.test.ts +79 -39
package/src/e2e.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Cli, Errors, Skill, Typegen, z } from 'incur'
|
|
2
|
+
|
|
2
3
|
import { app as honoApp } from '../test/fixtures/hono-api.js'
|
|
3
4
|
|
|
4
5
|
let __mockSkillsHash: string | undefined
|
|
@@ -432,7 +433,13 @@ describe('--token-limit and --token-offset', () => {
|
|
|
432
433
|
})
|
|
433
434
|
|
|
434
435
|
test('--token-limit and --token-offset together for pagination', async () => {
|
|
435
|
-
const { output } = await serve(createApp(), [
|
|
436
|
+
const { output } = await serve(createApp(), [
|
|
437
|
+
'ping',
|
|
438
|
+
'--token-offset',
|
|
439
|
+
'2',
|
|
440
|
+
'--token-limit',
|
|
441
|
+
'4',
|
|
442
|
+
])
|
|
436
443
|
expect(output).toMatchInlineSnapshot(`
|
|
437
444
|
" true
|
|
438
445
|
[truncated: showing tokens 2–3 of 3]
|
|
@@ -449,7 +456,14 @@ describe('--token-limit and --token-offset', () => {
|
|
|
449
456
|
})
|
|
450
457
|
|
|
451
458
|
test('works with --verbose', async () => {
|
|
452
|
-
const { output } = await serve(createApp(), [
|
|
459
|
+
const { output } = await serve(createApp(), [
|
|
460
|
+
'ping',
|
|
461
|
+
'--verbose',
|
|
462
|
+
'--format',
|
|
463
|
+
'json',
|
|
464
|
+
'--token-limit',
|
|
465
|
+
'20',
|
|
466
|
+
])
|
|
453
467
|
expect(output).toMatchInlineSnapshot(`
|
|
454
468
|
"{
|
|
455
469
|
"ok": true,
|
|
@@ -466,13 +480,27 @@ describe('--token-limit and --token-offset', () => {
|
|
|
466
480
|
})
|
|
467
481
|
|
|
468
482
|
test('--verbose includes meta.nextOffset when truncated', async () => {
|
|
469
|
-
const { output } = await serve(createApp(), [
|
|
483
|
+
const { output } = await serve(createApp(), [
|
|
484
|
+
'ping',
|
|
485
|
+
'--verbose',
|
|
486
|
+
'--format',
|
|
487
|
+
'json',
|
|
488
|
+
'--token-limit',
|
|
489
|
+
'2',
|
|
490
|
+
])
|
|
470
491
|
expect(output).toContain('"nextOffset"')
|
|
471
492
|
expect(output).toContain('[truncated:')
|
|
472
493
|
})
|
|
473
494
|
|
|
474
495
|
test('--verbose omits meta.nextOffset when not truncated', async () => {
|
|
475
|
-
const { output } = await serve(createApp(), [
|
|
496
|
+
const { output } = await serve(createApp(), [
|
|
497
|
+
'ping',
|
|
498
|
+
'--verbose',
|
|
499
|
+
'--format',
|
|
500
|
+
'json',
|
|
501
|
+
'--token-limit',
|
|
502
|
+
'10000',
|
|
503
|
+
])
|
|
476
504
|
const parsed = json(output)
|
|
477
505
|
expect(parsed.meta.nextOffset).toBeUndefined()
|
|
478
506
|
})
|
|
@@ -499,7 +527,12 @@ describe('--token-count', () => {
|
|
|
499
527
|
})
|
|
500
528
|
|
|
501
529
|
test('works with --filter-output', async () => {
|
|
502
|
-
const { output } = await serve(createApp(), [
|
|
530
|
+
const { output } = await serve(createApp(), [
|
|
531
|
+
'ping',
|
|
532
|
+
'--filter-output',
|
|
533
|
+
'pong',
|
|
534
|
+
'--token-count',
|
|
535
|
+
])
|
|
503
536
|
expect(output.trim()).toBe('1')
|
|
504
537
|
})
|
|
505
538
|
})
|
|
@@ -1018,9 +1051,9 @@ describe('help', () => {
|
|
|
1018
1051
|
Usage: app project list [options]
|
|
1019
1052
|
|
|
1020
1053
|
Options:
|
|
1021
|
-
--limit, -l <number>
|
|
1022
|
-
--sort, -s <
|
|
1023
|
-
--archived <boolean>
|
|
1054
|
+
--limit, -l <number> Max results (default: 20)
|
|
1055
|
+
--sort, -s <name|created|updated> Sort field (default: name)
|
|
1056
|
+
--archived <boolean> Include archived (default: false)
|
|
1024
1057
|
|
|
1025
1058
|
Global Options:
|
|
1026
1059
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
@@ -1051,8 +1084,8 @@ describe('help', () => {
|
|
|
1051
1084
|
--dry-run <boolean> Dry run mode (default: false)
|
|
1052
1085
|
|
|
1053
1086
|
Examples:
|
|
1054
|
-
|
|
1055
|
-
|
|
1087
|
+
app project deploy create staging # Deploy staging from main
|
|
1088
|
+
app project deploy create production --branch release --dryRun true # Dry run a production deploy
|
|
1056
1089
|
|
|
1057
1090
|
Global Options:
|
|
1058
1091
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
@@ -1222,7 +1255,13 @@ describe('--llms-full', () => {
|
|
|
1222
1255
|
})
|
|
1223
1256
|
|
|
1224
1257
|
test('scoped --llms-full to nested group', async () => {
|
|
1225
|
-
const { output } = await serve(createApp(), [
|
|
1258
|
+
const { output } = await serve(createApp(), [
|
|
1259
|
+
'project',
|
|
1260
|
+
'deploy',
|
|
1261
|
+
'--llms-full',
|
|
1262
|
+
'--format',
|
|
1263
|
+
'json',
|
|
1264
|
+
])
|
|
1226
1265
|
const names = json(output).commands.map((c: any) => c.name)
|
|
1227
1266
|
expect(names).toMatchInlineSnapshot(`
|
|
1228
1267
|
[
|
|
@@ -1253,7 +1292,13 @@ describe('--llms-full', () => {
|
|
|
1253
1292
|
})
|
|
1254
1293
|
|
|
1255
1294
|
test('--llms-full json includes examples on commands', async () => {
|
|
1256
|
-
const { output } = await serve(createApp(), [
|
|
1295
|
+
const { output } = await serve(createApp(), [
|
|
1296
|
+
'project',
|
|
1297
|
+
'deploy',
|
|
1298
|
+
'--llms-full',
|
|
1299
|
+
'--format',
|
|
1300
|
+
'json',
|
|
1301
|
+
])
|
|
1257
1302
|
const deployCreate = json(output).commands.find((c: any) => c.name === 'project deploy create')
|
|
1258
1303
|
expect(deployCreate.examples).toMatchInlineSnapshot(`
|
|
1259
1304
|
[
|
|
@@ -2188,12 +2233,7 @@ describe('fetch gateway', () => {
|
|
|
2188
2233
|
})
|
|
2189
2234
|
|
|
2190
2235
|
test('implicit POST with --body', async () => {
|
|
2191
|
-
const { output } = await serve(createApp(), [
|
|
2192
|
-
'api',
|
|
2193
|
-
'users',
|
|
2194
|
-
'--body',
|
|
2195
|
-
'{"name":"Eve"}',
|
|
2196
|
-
])
|
|
2236
|
+
const { output } = await serve(createApp(), ['api', 'users', '--body', '{"name":"Eve"}'])
|
|
2197
2237
|
expect(output).toMatchInlineSnapshot(`
|
|
2198
2238
|
"created: true
|
|
2199
2239
|
name: Eve
|
|
@@ -2202,13 +2242,7 @@ describe('fetch gateway', () => {
|
|
|
2202
2242
|
})
|
|
2203
2243
|
|
|
2204
2244
|
test('DELETE with --method', async () => {
|
|
2205
|
-
const { output } = await serve(createApp(), [
|
|
2206
|
-
'api',
|
|
2207
|
-
'users',
|
|
2208
|
-
'1',
|
|
2209
|
-
'--method',
|
|
2210
|
-
'DELETE',
|
|
2211
|
-
])
|
|
2245
|
+
const { output } = await serve(createApp(), ['api', 'users', '1', '--method', 'DELETE'])
|
|
2212
2246
|
expect(output).toMatchInlineSnapshot(`
|
|
2213
2247
|
"deleted: true
|
|
2214
2248
|
id: 1
|
|
@@ -2240,13 +2274,7 @@ describe('fetch gateway', () => {
|
|
|
2240
2274
|
})
|
|
2241
2275
|
|
|
2242
2276
|
test('--verbose wraps in envelope', async () => {
|
|
2243
|
-
const { output } = await serve(createApp(), [
|
|
2244
|
-
'api',
|
|
2245
|
-
'health',
|
|
2246
|
-
'--verbose',
|
|
2247
|
-
'--format',
|
|
2248
|
-
'json',
|
|
2249
|
-
])
|
|
2277
|
+
const { output } = await serve(createApp(), ['api', 'health', '--verbose', '--format', 'json'])
|
|
2250
2278
|
const parsed = json(output)
|
|
2251
2279
|
expect(parsed.ok).toBe(true)
|
|
2252
2280
|
expect(parsed.data).toEqual({ ok: true })
|
|
@@ -2298,7 +2326,10 @@ describe('fetch gateway', () => {
|
|
|
2298
2326
|
|
|
2299
2327
|
test('streaming NDJSON --format jsonl', async () => {
|
|
2300
2328
|
const { output } = await serve(createApp(), ['api', 'stream', '--format', 'jsonl'])
|
|
2301
|
-
const lines = output
|
|
2329
|
+
const lines = output
|
|
2330
|
+
.trim()
|
|
2331
|
+
.split('\n')
|
|
2332
|
+
.map((l) => JSON.parse(l))
|
|
2302
2333
|
expect(lines[0]).toEqual({ type: 'chunk', data: { progress: 1 } })
|
|
2303
2334
|
expect(lines[1]).toEqual({ type: 'chunk', data: { progress: 2 } })
|
|
2304
2335
|
expect(lines[2].type).toBe('done')
|
|
@@ -2374,7 +2405,8 @@ describe('fetch api', () => {
|
|
|
2374
2405
|
|
|
2375
2406
|
test('GET with query params → options', async () => {
|
|
2376
2407
|
const cli = createApp()
|
|
2377
|
-
expect(await fetchJson(cli, new Request('http://localhost/echo/hi?prefix=yo')))
|
|
2408
|
+
expect(await fetchJson(cli, new Request('http://localhost/echo/hi?prefix=yo')))
|
|
2409
|
+
.toMatchInlineSnapshot(`
|
|
2378
2410
|
{
|
|
2379
2411
|
"body": {
|
|
2380
2412
|
"data": {
|
|
@@ -2420,7 +2452,8 @@ describe('fetch api', () => {
|
|
|
2420
2452
|
|
|
2421
2453
|
test('trailing path segments → positional args', async () => {
|
|
2422
2454
|
const cli = createApp()
|
|
2423
|
-
expect(await fetchJson(cli, new Request('http://localhost/project/get/p1')))
|
|
2455
|
+
expect(await fetchJson(cli, new Request('http://localhost/project/get/p1')))
|
|
2456
|
+
.toMatchInlineSnapshot(`
|
|
2424
2457
|
{
|
|
2425
2458
|
"body": {
|
|
2426
2459
|
"data": {
|
|
@@ -2447,7 +2480,8 @@ describe('fetch api', () => {
|
|
|
2447
2480
|
|
|
2448
2481
|
test('nested command (3 levels deep)', async () => {
|
|
2449
2482
|
const cli = createApp()
|
|
2450
|
-
expect(await fetchJson(cli, new Request('http://localhost/project/deploy/status/d-456')))
|
|
2483
|
+
expect(await fetchJson(cli, new Request('http://localhost/project/deploy/status/d-456')))
|
|
2484
|
+
.toMatchInlineSnapshot(`
|
|
2451
2485
|
{
|
|
2452
2486
|
"body": {
|
|
2453
2487
|
"data": {
|
|
@@ -2488,7 +2522,8 @@ describe('fetch api', () => {
|
|
|
2488
2522
|
|
|
2489
2523
|
test('IncurError → 500 with code', async () => {
|
|
2490
2524
|
const cli = createApp()
|
|
2491
|
-
expect(await fetchJson(cli, new Request('http://localhost/explode-clac')))
|
|
2525
|
+
expect(await fetchJson(cli, new Request('http://localhost/explode-clac')))
|
|
2526
|
+
.toMatchInlineSnapshot(`
|
|
2492
2527
|
{
|
|
2493
2528
|
"body": {
|
|
2494
2529
|
"error": {
|
|
@@ -2519,7 +2554,10 @@ describe('fetch api', () => {
|
|
|
2519
2554
|
const res = await cli.fetch(new Request('http://localhost/stream'))
|
|
2520
2555
|
expect(res.status).toBe(200)
|
|
2521
2556
|
expect(res.headers.get('content-type')).toBe('application/x-ndjson')
|
|
2522
|
-
const lines = (await res.text())
|
|
2557
|
+
const lines = (await res.text())
|
|
2558
|
+
.trim()
|
|
2559
|
+
.split('\n')
|
|
2560
|
+
.map((l) => JSON.parse(l))
|
|
2523
2561
|
expect(lines).toMatchInlineSnapshot(`
|
|
2524
2562
|
[
|
|
2525
2563
|
{
|
|
@@ -2585,7 +2623,9 @@ describe('fetch api', () => {
|
|
|
2585
2623
|
|
|
2586
2624
|
test('middleware error → error response', async () => {
|
|
2587
2625
|
const cli = Cli.create('test')
|
|
2588
|
-
cli.use((c) => {
|
|
2626
|
+
cli.use((c) => {
|
|
2627
|
+
c.error({ code: 'FORBIDDEN', message: 'nope' })
|
|
2628
|
+
})
|
|
2589
2629
|
cli.command('secret', { run: () => ({ secret: true }) })
|
|
2590
2630
|
expect(await fetchJson(cli, new Request('http://localhost/secret'))).toMatchInlineSnapshot(`
|
|
2591
2631
|
{
|