incur 0.4.0 → 0.4.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.
- package/README.md +83 -22
- package/SKILL.md +6 -6
- package/dist/Cli.d.ts +46 -26
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +728 -441
- package/dist/Cli.js.map +1 -1
- package/dist/Completions.d.ts +4 -3
- package/dist/Completions.d.ts.map +1 -1
- package/dist/Completions.js +17 -10
- package/dist/Completions.js.map +1 -1
- package/dist/Fetch.d.ts.map +1 -1
- package/dist/Fetch.js +10 -9
- package/dist/Fetch.js.map +1 -1
- package/dist/Filter.js +0 -18
- package/dist/Filter.js.map +1 -1
- package/dist/Formatter.d.ts.map +1 -1
- package/dist/Formatter.js +6 -1
- package/dist/Formatter.js.map +1 -1
- package/dist/Help.d.ts +7 -1
- package/dist/Help.d.ts.map +1 -1
- package/dist/Help.js +44 -27
- package/dist/Help.js.map +1 -1
- package/dist/Mcp.d.ts +37 -5
- package/dist/Mcp.d.ts.map +1 -1
- package/dist/Mcp.js +71 -72
- package/dist/Mcp.js.map +1 -1
- package/dist/Openapi.d.ts.map +1 -1
- package/dist/Openapi.js +22 -14
- package/dist/Openapi.js.map +1 -1
- package/dist/Parser.d.ts +4 -0
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +70 -38
- package/dist/Parser.js.map +1 -1
- package/dist/Schema.d.ts +5 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +13 -2
- package/dist/Schema.js.map +1 -1
- package/dist/Skill.d.ts +2 -1
- package/dist/Skill.d.ts.map +1 -1
- package/dist/Skill.js +33 -19
- package/dist/Skill.js.map +1 -1
- package/dist/Skillgen.js +1 -1
- package/dist/Skillgen.js.map +1 -1
- package/dist/SyncSkills.d.ts +48 -0
- package/dist/SyncSkills.d.ts.map +1 -1
- package/dist/SyncSkills.js +108 -10
- package/dist/SyncSkills.js.map +1 -1
- package/dist/Typegen.js +4 -2
- package/dist/Typegen.js.map +1 -1
- package/dist/bin.d.ts +2 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +17 -2
- package/dist/bin.js.map +1 -1
- package/dist/internal/command.d.ts +170 -0
- package/dist/internal/command.d.ts.map +1 -0
- package/dist/internal/command.js +292 -0
- package/dist/internal/command.js.map +1 -0
- package/dist/internal/configSchema.d.ts +8 -0
- package/dist/internal/configSchema.d.ts.map +1 -0
- package/dist/internal/configSchema.js +57 -0
- package/dist/internal/configSchema.js.map +1 -0
- package/dist/internal/dereference.d.ts +12 -0
- package/dist/internal/dereference.d.ts.map +1 -0
- package/dist/internal/dereference.js +71 -0
- package/dist/internal/dereference.js.map +1 -0
- package/dist/internal/helpers.d.ts +9 -0
- package/dist/internal/helpers.d.ts.map +1 -0
- package/dist/internal/helpers.js +54 -0
- package/dist/internal/helpers.js.map +1 -0
- package/dist/middleware.d.ts +6 -8
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +1 -1
- package/dist/middleware.js.map +1 -1
- package/examples/npm/.npmrc.json +21 -0
- package/examples/npm/config.schema.json +134 -0
- package/package.json +6 -29
- package/src/Cli.test-d.ts +44 -33
- package/src/Cli.test.ts +1231 -101
- package/src/Cli.ts +877 -569
- package/src/Completions.test.ts +136 -12
- package/src/Completions.ts +18 -13
- package/src/Fetch.test.ts +21 -0
- package/src/Fetch.ts +8 -10
- package/src/Filter.ts +0 -17
- package/src/Formatter.test.ts +15 -2
- package/src/Formatter.ts +5 -1
- package/src/Help.test.ts +184 -20
- package/src/Help.ts +52 -28
- package/src/Mcp.test.ts +159 -0
- package/src/Mcp.ts +108 -86
- package/src/Openapi.test.ts +17 -5
- package/src/Openapi.ts +21 -15
- package/src/Parser.test-d.ts +22 -0
- package/src/Parser.test.ts +89 -0
- package/src/Parser.ts +87 -36
- package/src/Schema.test.ts +29 -0
- package/src/Schema.ts +12 -2
- package/src/Skill.test.ts +87 -6
- package/src/Skill.ts +38 -21
- package/src/Skillgen.ts +1 -1
- package/src/SyncMcp.test.ts +6 -8
- package/src/SyncSkills.test.ts +146 -3
- package/src/SyncSkills.ts +191 -10
- package/src/Typegen.test.ts +15 -0
- package/src/Typegen.ts +4 -2
- package/src/bin.ts +21 -2
- package/src/e2e.test.ts +188 -98
- package/src/internal/command.ts +449 -0
- package/src/internal/configSchema.test.ts +193 -0
- package/src/internal/configSchema.ts +66 -0
- package/src/internal/dereference.test.ts +695 -0
- package/src/internal/dereference.ts +75 -0
- package/src/internal/helpers.test.ts +75 -0
- package/src/internal/helpers.ts +59 -0
- package/src/middleware.ts +5 -12
package/src/e2e.test.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Cli, Errors, Skill, Typegen, z } from 'incur'
|
|
|
3
3
|
import { app as honoApp } from '../test/fixtures/hono-api.js'
|
|
4
4
|
|
|
5
5
|
let __mockSkillsHash: string | undefined
|
|
6
|
+
let __mockSkillsInstalled = true
|
|
6
7
|
|
|
7
8
|
const originalIsTTY = process.stdout.isTTY
|
|
8
9
|
beforeAll(() => {
|
|
@@ -14,7 +15,11 @@ afterAll(() => {
|
|
|
14
15
|
|
|
15
16
|
vi.mock('./SyncSkills.js', async (importOriginal) => {
|
|
16
17
|
const actual = await importOriginal<typeof import('./SyncSkills.js')>()
|
|
17
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
...actual,
|
|
20
|
+
hasInstalledSkills: () => __mockSkillsInstalled,
|
|
21
|
+
readHash: () => __mockSkillsHash,
|
|
22
|
+
}
|
|
18
23
|
})
|
|
19
24
|
|
|
20
25
|
describe('routing', () => {
|
|
@@ -70,9 +75,9 @@ describe('routing', () => {
|
|
|
70
75
|
"code: COMMAND_NOT_FOUND
|
|
71
76
|
message: 'nonexistent' is not a command for 'app'.
|
|
72
77
|
cta:
|
|
73
|
-
description: "
|
|
74
|
-
commands[1]{command}:
|
|
75
|
-
app --help
|
|
78
|
+
description: "Suggested command:"
|
|
79
|
+
commands[1]{command,description}:
|
|
80
|
+
app --help,see all available commands
|
|
76
81
|
"
|
|
77
82
|
`)
|
|
78
83
|
})
|
|
@@ -85,8 +90,8 @@ describe('routing', () => {
|
|
|
85
90
|
expect(output).toMatchInlineSnapshot(`
|
|
86
91
|
"Error: 'nonexistent' is not a command for 'app'.
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
app --help
|
|
93
|
+
Suggested command:
|
|
94
|
+
app --help # see all available commands
|
|
90
95
|
"
|
|
91
96
|
`)
|
|
92
97
|
})
|
|
@@ -98,9 +103,9 @@ describe('routing', () => {
|
|
|
98
103
|
"code: COMMAND_NOT_FOUND
|
|
99
104
|
message: 'whoami' is not a command for 'app auth'.
|
|
100
105
|
cta:
|
|
101
|
-
description: "
|
|
102
|
-
commands[1]{command}:
|
|
103
|
-
app auth --help
|
|
106
|
+
description: "Suggested command:"
|
|
107
|
+
commands[1]{command,description}:
|
|
108
|
+
app auth --help,see all available commands
|
|
104
109
|
"
|
|
105
110
|
`)
|
|
106
111
|
})
|
|
@@ -112,9 +117,9 @@ describe('routing', () => {
|
|
|
112
117
|
"code: COMMAND_NOT_FOUND
|
|
113
118
|
message: 'nope' is not a command for 'app project deploy'.
|
|
114
119
|
cta:
|
|
115
|
-
description: "
|
|
116
|
-
commands[1]{command}:
|
|
117
|
-
app project deploy --help
|
|
120
|
+
description: "Suggested command:"
|
|
121
|
+
commands[1]{command,description}:
|
|
122
|
+
app project deploy --help,see all available commands
|
|
118
123
|
"
|
|
119
124
|
`)
|
|
120
125
|
})
|
|
@@ -173,7 +178,7 @@ describe('args and options', () => {
|
|
|
173
178
|
'read',
|
|
174
179
|
'--scopes',
|
|
175
180
|
'write',
|
|
176
|
-
'--
|
|
181
|
+
'--full-output',
|
|
177
182
|
'--format',
|
|
178
183
|
'json',
|
|
179
184
|
])
|
|
@@ -192,7 +197,7 @@ describe('args and options', () => {
|
|
|
192
197
|
'list',
|
|
193
198
|
'--limit',
|
|
194
199
|
'5',
|
|
195
|
-
'--
|
|
200
|
+
'--full-output',
|
|
196
201
|
'--format',
|
|
197
202
|
'json',
|
|
198
203
|
])
|
|
@@ -327,8 +332,8 @@ describe('output formats', () => {
|
|
|
327
332
|
`)
|
|
328
333
|
})
|
|
329
334
|
|
|
330
|
-
test('--
|
|
331
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
335
|
+
test('--full-output full envelope', async () => {
|
|
336
|
+
const { output } = await serve(createApp(), ['ping', '--full-output'])
|
|
332
337
|
expect(output).toMatchInlineSnapshot(`
|
|
333
338
|
"ok: true
|
|
334
339
|
data:
|
|
@@ -340,8 +345,8 @@ describe('output formats', () => {
|
|
|
340
345
|
`)
|
|
341
346
|
})
|
|
342
347
|
|
|
343
|
-
test('--
|
|
344
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
348
|
+
test('--full-output --format json full envelope', async () => {
|
|
349
|
+
const { output } = await serve(createApp(), ['ping', '--full-output', '--format', 'json'])
|
|
345
350
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
346
351
|
{
|
|
347
352
|
"data": {
|
|
@@ -356,13 +361,13 @@ describe('output formats', () => {
|
|
|
356
361
|
`)
|
|
357
362
|
})
|
|
358
363
|
|
|
359
|
-
test('nested command path in
|
|
364
|
+
test('nested command path in full-output meta', async () => {
|
|
360
365
|
const { output } = await serve(createApp(), [
|
|
361
366
|
'project',
|
|
362
367
|
'deploy',
|
|
363
368
|
'status',
|
|
364
369
|
'd-1',
|
|
365
|
-
'--
|
|
370
|
+
'--full-output',
|
|
366
371
|
'--format',
|
|
367
372
|
'json',
|
|
368
373
|
])
|
|
@@ -400,8 +405,8 @@ describe('undefined output', () => {
|
|
|
400
405
|
expect(output).toBe('')
|
|
401
406
|
})
|
|
402
407
|
|
|
403
|
-
test('void command shows envelope with --
|
|
404
|
-
const { output } = await serve(createApp(), ['noop', '--
|
|
408
|
+
test('void command shows envelope with --full-output', async () => {
|
|
409
|
+
const { output } = await serve(createApp(), ['noop', '--full-output', '--format', 'json'])
|
|
405
410
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
406
411
|
{
|
|
407
412
|
"meta": {
|
|
@@ -455,10 +460,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
455
460
|
`)
|
|
456
461
|
})
|
|
457
462
|
|
|
458
|
-
test('works with --
|
|
463
|
+
test('works with --full-output', async () => {
|
|
459
464
|
const { output } = await serve(createApp(), [
|
|
460
465
|
'ping',
|
|
461
|
-
'--
|
|
466
|
+
'--full-output',
|
|
462
467
|
'--format',
|
|
463
468
|
'json',
|
|
464
469
|
'--token-limit',
|
|
@@ -479,10 +484,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
479
484
|
`)
|
|
480
485
|
})
|
|
481
486
|
|
|
482
|
-
test('--
|
|
487
|
+
test('--full-output includes meta.nextOffset when truncated', async () => {
|
|
483
488
|
const { output } = await serve(createApp(), [
|
|
484
489
|
'ping',
|
|
485
|
-
'--
|
|
490
|
+
'--full-output',
|
|
486
491
|
'--format',
|
|
487
492
|
'json',
|
|
488
493
|
'--token-limit',
|
|
@@ -492,10 +497,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
492
497
|
expect(output).toContain('[truncated:')
|
|
493
498
|
})
|
|
494
499
|
|
|
495
|
-
test('--
|
|
500
|
+
test('--full-output omits meta.nextOffset when not truncated', async () => {
|
|
496
501
|
const { output } = await serve(createApp(), [
|
|
497
502
|
'ping',
|
|
498
|
-
'--
|
|
503
|
+
'--full-output',
|
|
499
504
|
'--format',
|
|
500
505
|
'json',
|
|
501
506
|
'--token-limit',
|
|
@@ -575,7 +580,7 @@ describe('error handling', () => {
|
|
|
575
580
|
const { output, exitCode } = await serve(createApp(), [
|
|
576
581
|
'auth',
|
|
577
582
|
'status',
|
|
578
|
-
'--
|
|
583
|
+
'--full-output',
|
|
579
584
|
'--format',
|
|
580
585
|
'json',
|
|
581
586
|
])
|
|
@@ -595,7 +600,7 @@ describe('error handling', () => {
|
|
|
595
600
|
"command": "app auth login",
|
|
596
601
|
},
|
|
597
602
|
],
|
|
598
|
-
"description": "Suggested
|
|
603
|
+
"description": "Suggested command:",
|
|
599
604
|
},
|
|
600
605
|
"duration": "<stripped>",
|
|
601
606
|
},
|
|
@@ -633,7 +638,7 @@ describe('error handling', () => {
|
|
|
633
638
|
test('command not found returns error envelope', async () => {
|
|
634
639
|
const { output, exitCode } = await serve(createApp(), [
|
|
635
640
|
'nonexistent',
|
|
636
|
-
'--
|
|
641
|
+
'--full-output',
|
|
637
642
|
'--format',
|
|
638
643
|
'json',
|
|
639
644
|
])
|
|
@@ -650,9 +655,10 @@ describe('error handling', () => {
|
|
|
650
655
|
"commands": [
|
|
651
656
|
{
|
|
652
657
|
"command": "app --help",
|
|
658
|
+
"description": "see all available commands",
|
|
653
659
|
},
|
|
654
660
|
],
|
|
655
|
-
"description": "
|
|
661
|
+
"description": "Suggested command:",
|
|
656
662
|
},
|
|
657
663
|
"duration": "<stripped>",
|
|
658
664
|
},
|
|
@@ -675,7 +681,13 @@ describe('error handling', () => {
|
|
|
675
681
|
|
|
676
682
|
describe('cta', () => {
|
|
677
683
|
test('ok() with string CTAs', async () => {
|
|
678
|
-
const { output } = await serve(createApp(), [
|
|
684
|
+
const { output } = await serve(createApp(), [
|
|
685
|
+
'auth',
|
|
686
|
+
'login',
|
|
687
|
+
'--full-output',
|
|
688
|
+
'--format',
|
|
689
|
+
'json',
|
|
690
|
+
])
|
|
679
691
|
expect(json(output).meta.cta).toMatchInlineSnapshot(`
|
|
680
692
|
{
|
|
681
693
|
"commands": [
|
|
@@ -693,7 +705,7 @@ describe('cta', () => {
|
|
|
693
705
|
'project',
|
|
694
706
|
'create',
|
|
695
707
|
'MyProject',
|
|
696
|
-
'--
|
|
708
|
+
'--full-output',
|
|
697
709
|
'--format',
|
|
698
710
|
'json',
|
|
699
711
|
])
|
|
@@ -714,7 +726,13 @@ describe('cta', () => {
|
|
|
714
726
|
})
|
|
715
727
|
|
|
716
728
|
test('error() with CTA', async () => {
|
|
717
|
-
const { output } = await serve(createApp(), [
|
|
729
|
+
const { output } = await serve(createApp(), [
|
|
730
|
+
'auth',
|
|
731
|
+
'status',
|
|
732
|
+
'--full-output',
|
|
733
|
+
'--format',
|
|
734
|
+
'json',
|
|
735
|
+
])
|
|
718
736
|
expect(json(output).meta.cta).toMatchInlineSnapshot(`
|
|
719
737
|
{
|
|
720
738
|
"commands": [
|
|
@@ -722,13 +740,13 @@ describe('cta', () => {
|
|
|
722
740
|
"command": "app auth login",
|
|
723
741
|
},
|
|
724
742
|
],
|
|
725
|
-
"description": "Suggested
|
|
743
|
+
"description": "Suggested command:",
|
|
726
744
|
}
|
|
727
745
|
`)
|
|
728
746
|
})
|
|
729
747
|
|
|
730
748
|
test('plain return omits CTA', async () => {
|
|
731
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
749
|
+
const { output } = await serve(createApp(), ['ping', '--full-output', '--format', 'json'])
|
|
732
750
|
expect(json(output).meta.cta).toBeUndefined()
|
|
733
751
|
})
|
|
734
752
|
|
|
@@ -737,7 +755,7 @@ describe('cta', () => {
|
|
|
737
755
|
'project',
|
|
738
756
|
'list',
|
|
739
757
|
'--archived',
|
|
740
|
-
'--
|
|
758
|
+
'--full-output',
|
|
741
759
|
'--format',
|
|
742
760
|
'json',
|
|
743
761
|
])
|
|
@@ -779,8 +797,8 @@ describe('streaming', () => {
|
|
|
779
797
|
`)
|
|
780
798
|
})
|
|
781
799
|
|
|
782
|
-
test('default streams toon per chunk (--
|
|
783
|
-
const { output } = await serve(createApp(), ['stream', '--
|
|
800
|
+
test('default streams toon per chunk (--full-output)', async () => {
|
|
801
|
+
const { output } = await serve(createApp(), ['stream', '--full-output'])
|
|
784
802
|
expect(output).toMatchInlineSnapshot(`
|
|
785
803
|
"content: hello
|
|
786
804
|
content: world
|
|
@@ -802,8 +820,8 @@ describe('streaming', () => {
|
|
|
802
820
|
`)
|
|
803
821
|
})
|
|
804
822
|
|
|
805
|
-
test('--format json --
|
|
806
|
-
const { output } = await serve(createApp(), ['stream', '--
|
|
823
|
+
test('--format json --full-output buffers with envelope', async () => {
|
|
824
|
+
const { output } = await serve(createApp(), ['stream', '--full-output', '--format', 'json'])
|
|
807
825
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
808
826
|
{
|
|
809
827
|
"data": [
|
|
@@ -868,7 +886,7 @@ describe('streaming', () => {
|
|
|
868
886
|
"command": "app ping",
|
|
869
887
|
},
|
|
870
888
|
],
|
|
871
|
-
"description": "Suggested
|
|
889
|
+
"description": "Suggested command:",
|
|
872
890
|
}
|
|
873
891
|
`)
|
|
874
892
|
})
|
|
@@ -877,7 +895,7 @@ describe('streaming', () => {
|
|
|
877
895
|
const { output } = await serve(createApp(), ['stream-ok'])
|
|
878
896
|
expect(output).toContain('n: 1')
|
|
879
897
|
expect(output).toContain('n: 2')
|
|
880
|
-
expect(output).toContain('Suggested
|
|
898
|
+
expect(output).toContain('Suggested command:')
|
|
881
899
|
expect(output).toContain('app ping')
|
|
882
900
|
})
|
|
883
901
|
|
|
@@ -963,22 +981,22 @@ describe('help', () => {
|
|
|
963
981
|
stream-throw Stream that throws
|
|
964
982
|
validate-fail Fails validation
|
|
965
983
|
|
|
966
|
-
|
|
984
|
+
Integrations:
|
|
967
985
|
completions Generate shell completion script
|
|
968
|
-
mcp add Register as
|
|
969
|
-
skills
|
|
986
|
+
mcp add Register as MCP server
|
|
987
|
+
skills Sync skill files to agents (add, list)
|
|
970
988
|
|
|
971
989
|
Global Options:
|
|
972
990
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
973
991
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
992
|
+
--full-output Show full output envelope
|
|
974
993
|
--help Show help
|
|
975
994
|
--llms, --llms-full Print LLM-readable manifest
|
|
976
995
|
--mcp Start as MCP stdio server
|
|
977
|
-
--schema Show JSON Schema for
|
|
996
|
+
--schema Show JSON Schema for command
|
|
978
997
|
--token-count Print token count of output (instead of output)
|
|
979
998
|
--token-limit <n> Limit output to n tokens
|
|
980
999
|
--token-offset <n> Skip first n tokens of output
|
|
981
|
-
--verbose Show full output envelope
|
|
982
1000
|
--version Show version
|
|
983
1001
|
"
|
|
984
1002
|
`)
|
|
@@ -1005,13 +1023,13 @@ describe('help', () => {
|
|
|
1005
1023
|
Global Options:
|
|
1006
1024
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1007
1025
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1026
|
+
--full-output Show full output envelope
|
|
1008
1027
|
--help Show help
|
|
1009
1028
|
--llms, --llms-full Print LLM-readable manifest
|
|
1010
|
-
--schema Show JSON Schema for
|
|
1029
|
+
--schema Show JSON Schema for command
|
|
1011
1030
|
--token-count Print token count of output (instead of output)
|
|
1012
1031
|
--token-limit <n> Limit output to n tokens
|
|
1013
1032
|
--token-offset <n> Skip first n tokens of output
|
|
1014
|
-
--verbose Show full output envelope
|
|
1015
1033
|
"
|
|
1016
1034
|
`)
|
|
1017
1035
|
})
|
|
@@ -1032,13 +1050,13 @@ describe('help', () => {
|
|
|
1032
1050
|
Global Options:
|
|
1033
1051
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1034
1052
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1053
|
+
--full-output Show full output envelope
|
|
1035
1054
|
--help Show help
|
|
1036
1055
|
--llms, --llms-full Print LLM-readable manifest
|
|
1037
|
-
--schema Show JSON Schema for
|
|
1056
|
+
--schema Show JSON Schema for command
|
|
1038
1057
|
--token-count Print token count of output (instead of output)
|
|
1039
1058
|
--token-limit <n> Limit output to n tokens
|
|
1040
1059
|
--token-offset <n> Skip first n tokens of output
|
|
1041
|
-
--verbose Show full output envelope
|
|
1042
1060
|
"
|
|
1043
1061
|
`)
|
|
1044
1062
|
})
|
|
@@ -1053,18 +1071,18 @@ describe('help', () => {
|
|
|
1053
1071
|
Options:
|
|
1054
1072
|
--limit, -l <number> Max results (default: 20)
|
|
1055
1073
|
--sort, -s <name|created|updated> Sort field (default: name)
|
|
1056
|
-
--archived
|
|
1074
|
+
--archived Include archived
|
|
1057
1075
|
|
|
1058
1076
|
Global Options:
|
|
1059
1077
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1060
1078
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1079
|
+
--full-output Show full output envelope
|
|
1061
1080
|
--help Show help
|
|
1062
1081
|
--llms, --llms-full Print LLM-readable manifest
|
|
1063
|
-
--schema Show JSON Schema for
|
|
1082
|
+
--schema Show JSON Schema for command
|
|
1064
1083
|
--token-count Print token count of output (instead of output)
|
|
1065
1084
|
--token-limit <n> Limit output to n tokens
|
|
1066
1085
|
--token-offset <n> Skip first n tokens of output
|
|
1067
|
-
--verbose Show full output envelope
|
|
1068
1086
|
"
|
|
1069
1087
|
`)
|
|
1070
1088
|
})
|
|
@@ -1081,7 +1099,7 @@ describe('help', () => {
|
|
|
1081
1099
|
|
|
1082
1100
|
Options:
|
|
1083
1101
|
--branch, -b <string> Branch to deploy (default: main)
|
|
1084
|
-
--dry-run
|
|
1102
|
+
--dry-run Dry run mode
|
|
1085
1103
|
|
|
1086
1104
|
Examples:
|
|
1087
1105
|
app project deploy create staging # Deploy staging from main
|
|
@@ -1090,13 +1108,13 @@ describe('help', () => {
|
|
|
1090
1108
|
Global Options:
|
|
1091
1109
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1092
1110
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1111
|
+
--full-output Show full output envelope
|
|
1093
1112
|
--help Show help
|
|
1094
1113
|
--llms, --llms-full Print LLM-readable manifest
|
|
1095
|
-
--schema Show JSON Schema for
|
|
1114
|
+
--schema Show JSON Schema for command
|
|
1096
1115
|
--token-count Print token count of output (instead of output)
|
|
1097
1116
|
--token-limit <n> Limit output to n tokens
|
|
1098
1117
|
--token-offset <n> Skip first n tokens of output
|
|
1099
|
-
--verbose Show full output envelope
|
|
1100
1118
|
"
|
|
1101
1119
|
`)
|
|
1102
1120
|
})
|
|
@@ -1589,8 +1607,8 @@ describe('typegen', () => {
|
|
|
1589
1607
|
'auth login': { args: {}; options: { hostname: string; web: boolean; scopes: string[] } }
|
|
1590
1608
|
'auth logout': { args: {}; options: {} }
|
|
1591
1609
|
'auth status': { args: {}; options: {} }
|
|
1592
|
-
'config': { args: { key
|
|
1593
|
-
'echo': { args: { message: string; repeat
|
|
1610
|
+
'config': { args: { key?: string }; options: {} }
|
|
1611
|
+
'echo': { args: { message: string; repeat?: number }; options: { upper: boolean; prefix: string } }
|
|
1594
1612
|
'explode': { args: {}; options: {} }
|
|
1595
1613
|
'explode-clac': { args: {}; options: {} }
|
|
1596
1614
|
'noop': { args: {}; options: {} }
|
|
@@ -1738,22 +1756,22 @@ describe('root command with subcommands', () => {
|
|
|
1738
1756
|
info Show info
|
|
1739
1757
|
version Show version
|
|
1740
1758
|
|
|
1741
|
-
|
|
1759
|
+
Integrations:
|
|
1742
1760
|
completions Generate shell completion script
|
|
1743
|
-
mcp add Register as
|
|
1744
|
-
skills
|
|
1761
|
+
mcp add Register as MCP server
|
|
1762
|
+
skills Sync skill files to agents (add, list)
|
|
1745
1763
|
|
|
1746
1764
|
Global Options:
|
|
1747
1765
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1748
1766
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1767
|
+
--full-output Show full output envelope
|
|
1749
1768
|
--help Show help
|
|
1750
1769
|
--llms, --llms-full Print LLM-readable manifest
|
|
1751
1770
|
--mcp Start as MCP stdio server
|
|
1752
|
-
--schema Show JSON Schema for
|
|
1771
|
+
--schema Show JSON Schema for command
|
|
1753
1772
|
--token-count Print token count of output (instead of output)
|
|
1754
1773
|
--token-limit <n> Limit output to n tokens
|
|
1755
1774
|
--token-offset <n> Skip first n tokens of output
|
|
1756
|
-
--verbose Show full output envelope
|
|
1757
1775
|
--version Show version
|
|
1758
1776
|
"
|
|
1759
1777
|
`)
|
|
@@ -1786,7 +1804,7 @@ describe('edge cases', () => {
|
|
|
1786
1804
|
"description": "View "Alpha"",
|
|
1787
1805
|
},
|
|
1788
1806
|
],
|
|
1789
|
-
"description": "Suggested
|
|
1807
|
+
"description": "Suggested command:",
|
|
1790
1808
|
},
|
|
1791
1809
|
"items": [
|
|
1792
1810
|
{
|
|
@@ -1864,7 +1882,7 @@ describe('edge cases', () => {
|
|
|
1864
1882
|
'prod',
|
|
1865
1883
|
'--branch',
|
|
1866
1884
|
'release',
|
|
1867
|
-
'--
|
|
1885
|
+
'--full-output',
|
|
1868
1886
|
])
|
|
1869
1887
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
1870
1888
|
{
|
|
@@ -1893,7 +1911,7 @@ describe('env', () => {
|
|
|
1893
1911
|
test('env vars passed to handler', async () => {
|
|
1894
1912
|
const { output } = await serve(
|
|
1895
1913
|
createApp(),
|
|
1896
|
-
['auth', 'login', '--
|
|
1914
|
+
['auth', 'login', '--full-output', '--format', 'json'],
|
|
1897
1915
|
{ env: { AUTH_HOST: 'custom.example.com' } },
|
|
1898
1916
|
)
|
|
1899
1917
|
expect(json(output).data.hostname).toBe('custom.example.com')
|
|
@@ -1902,7 +1920,7 @@ describe('env', () => {
|
|
|
1902
1920
|
test('env defaults applied when var is unset', async () => {
|
|
1903
1921
|
const { output } = await serve(
|
|
1904
1922
|
createApp(),
|
|
1905
|
-
['auth', 'login', '--
|
|
1923
|
+
['auth', 'login', '--full-output', '--format', 'json'],
|
|
1906
1924
|
{ env: {} },
|
|
1907
1925
|
)
|
|
1908
1926
|
expect(json(output).data.hostname).toBe('api.example.com')
|
|
@@ -1917,19 +1935,19 @@ describe('env', () => {
|
|
|
1917
1935
|
|
|
1918
1936
|
Options:
|
|
1919
1937
|
--hostname, -h <string> API hostname (default: api.example.com)
|
|
1920
|
-
--web, -w
|
|
1938
|
+
--web, -w Open browser
|
|
1921
1939
|
--scopes <array> OAuth scopes
|
|
1922
1940
|
|
|
1923
1941
|
Global Options:
|
|
1924
1942
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1925
1943
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1944
|
+
--full-output Show full output envelope
|
|
1926
1945
|
--help Show help
|
|
1927
1946
|
--llms, --llms-full Print LLM-readable manifest
|
|
1928
|
-
--schema Show JSON Schema for
|
|
1947
|
+
--schema Show JSON Schema for command
|
|
1929
1948
|
--token-count Print token count of output (instead of output)
|
|
1930
1949
|
--token-limit <n> Limit output to n tokens
|
|
1931
1950
|
--token-offset <n> Skip first n tokens of output
|
|
1932
|
-
--verbose Show full output envelope
|
|
1933
1951
|
|
|
1934
1952
|
Environment Variables:
|
|
1935
1953
|
AUTH_TOKEN Pre-existing auth token
|
|
@@ -1970,17 +1988,21 @@ describe('skills staleness', () => {
|
|
|
1970
1988
|
beforeEach(() => {
|
|
1971
1989
|
stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
|
|
1972
1990
|
__mockSkillsHash = undefined
|
|
1991
|
+
__mockSkillsInstalled = true
|
|
1973
1992
|
})
|
|
1974
1993
|
|
|
1975
1994
|
afterEach(() => {
|
|
1976
1995
|
stderrSpy.mockRestore()
|
|
1996
|
+
__mockSkillsHash = undefined
|
|
1997
|
+
__mockSkillsInstalled = true
|
|
1977
1998
|
})
|
|
1978
1999
|
|
|
1979
|
-
test('
|
|
2000
|
+
test('includes skills CTA when stale', async () => {
|
|
1980
2001
|
__mockSkillsHash = '0000000000000000'
|
|
1981
2002
|
const { output } = await serve(createApp(), ['ping'])
|
|
1982
2003
|
expect(output).toContain('pong: true')
|
|
1983
|
-
expect(
|
|
2004
|
+
expect(output).toContain('Skills are out of date:')
|
|
2005
|
+
expect(output).toContain('skills add')
|
|
1984
2006
|
})
|
|
1985
2007
|
|
|
1986
2008
|
test('no warning when skills hash matches', async () => {
|
|
@@ -1991,20 +2013,28 @@ describe('skills staleness', () => {
|
|
|
1991
2013
|
|
|
1992
2014
|
const { output } = await serve(cli, ['ping'])
|
|
1993
2015
|
expect(output).toContain('pong: true')
|
|
1994
|
-
expect(
|
|
2016
|
+
expect(output).not.toContain('Skills are out of date')
|
|
1995
2017
|
})
|
|
1996
2018
|
|
|
1997
2019
|
test('no warning on first use (no hash stored)', async () => {
|
|
1998
2020
|
__mockSkillsHash = undefined
|
|
1999
2021
|
const { output } = await serve(createApp(), ['ping'])
|
|
2000
2022
|
expect(output).toContain('pong: true')
|
|
2001
|
-
expect(
|
|
2023
|
+
expect(output).not.toContain('Skills are out of date')
|
|
2024
|
+
})
|
|
2025
|
+
|
|
2026
|
+
test('no warning when skills are not installed', async () => {
|
|
2027
|
+
__mockSkillsHash = '0000000000000000'
|
|
2028
|
+
__mockSkillsInstalled = false
|
|
2029
|
+
const { output } = await serve(createApp(), ['ping'])
|
|
2030
|
+
expect(output).toContain('pong: true')
|
|
2031
|
+
expect(output).not.toContain('Skills are out of date')
|
|
2002
2032
|
})
|
|
2003
2033
|
|
|
2004
2034
|
test('no warning for --llms', async () => {
|
|
2005
2035
|
__mockSkillsHash = '0000000000000000'
|
|
2006
|
-
await serve(createApp(), ['--llms'])
|
|
2007
|
-
expect(
|
|
2036
|
+
const { output } = await serve(createApp(), ['--llms'])
|
|
2037
|
+
expect(output).not.toContain('Skills are out of date')
|
|
2008
2038
|
})
|
|
2009
2039
|
|
|
2010
2040
|
test('no warning for --mcp', async () => {
|
|
@@ -2034,9 +2064,9 @@ describe('middleware', () => {
|
|
|
2034
2064
|
`)
|
|
2035
2065
|
})
|
|
2036
2066
|
|
|
2037
|
-
test('vars:
|
|
2067
|
+
test('vars: full-output envelope includes var data', async () => {
|
|
2038
2068
|
const { cli } = createMiddlewareApp()
|
|
2039
|
-
const { output } = await serve(cli, ['whoami', '--
|
|
2069
|
+
const { output } = await serve(cli, ['whoami', '--full-output', '--format', 'json'])
|
|
2040
2070
|
const parsed = json(output)
|
|
2041
2071
|
expect(parsed.data.user).toBe('alice')
|
|
2042
2072
|
expect(parsed.data.requestId).toBe('req-default')
|
|
@@ -2204,7 +2234,7 @@ describe('fetch gateway', () => {
|
|
|
2204
2234
|
})
|
|
2205
2235
|
|
|
2206
2236
|
test('query params from --key value', async () => {
|
|
2207
|
-
|
|
2237
|
+
await serve(createApp(), ['api', 'users', '--limit', '5'])
|
|
2208
2238
|
const { output: jsonOut } = await serve(createApp(), [
|
|
2209
2239
|
'api',
|
|
2210
2240
|
'users',
|
|
@@ -2273,8 +2303,14 @@ describe('fetch gateway', () => {
|
|
|
2273
2303
|
expect(json(output)).toEqual({ ok: true })
|
|
2274
2304
|
})
|
|
2275
2305
|
|
|
2276
|
-
test('--
|
|
2277
|
-
const { output } = await serve(createApp(), [
|
|
2306
|
+
test('--full-output wraps in envelope', async () => {
|
|
2307
|
+
const { output } = await serve(createApp(), [
|
|
2308
|
+
'api',
|
|
2309
|
+
'health',
|
|
2310
|
+
'--full-output',
|
|
2311
|
+
'--format',
|
|
2312
|
+
'json',
|
|
2313
|
+
])
|
|
2278
2314
|
const parsed = json(output)
|
|
2279
2315
|
expect(parsed.ok).toBe(true)
|
|
2280
2316
|
expect(parsed.data).toEqual({ ok: true })
|
|
@@ -2441,6 +2477,18 @@ describe('fetch api', () => {
|
|
|
2441
2477
|
},
|
|
2442
2478
|
"meta": {
|
|
2443
2479
|
"command": "project create",
|
|
2480
|
+
"cta": {
|
|
2481
|
+
"commands": [
|
|
2482
|
+
{
|
|
2483
|
+
"command": "app project get p-new",
|
|
2484
|
+
"description": "View "MyProject"",
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
"command": "app project list",
|
|
2488
|
+
},
|
|
2489
|
+
],
|
|
2490
|
+
"description": "Suggested commands:",
|
|
2491
|
+
},
|
|
2444
2492
|
"duration": "<stripped>",
|
|
2445
2493
|
},
|
|
2446
2494
|
"ok": true,
|
|
@@ -2524,21 +2572,22 @@ describe('fetch api', () => {
|
|
|
2524
2572
|
const cli = createApp()
|
|
2525
2573
|
expect(await fetchJson(cli, new Request('http://localhost/explode-clac')))
|
|
2526
2574
|
.toMatchInlineSnapshot(`
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
"
|
|
2535
|
-
|
|
2575
|
+
{
|
|
2576
|
+
"body": {
|
|
2577
|
+
"error": {
|
|
2578
|
+
"code": "QUOTA_EXCEEDED",
|
|
2579
|
+
"message": "Rate limit exceeded",
|
|
2580
|
+
"retryable": true,
|
|
2581
|
+
},
|
|
2582
|
+
"meta": {
|
|
2583
|
+
"command": "explode-clac",
|
|
2584
|
+
"duration": "<stripped>",
|
|
2585
|
+
},
|
|
2586
|
+
"ok": false,
|
|
2536
2587
|
},
|
|
2537
|
-
"
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
}
|
|
2541
|
-
`)
|
|
2588
|
+
"status": 500,
|
|
2589
|
+
}
|
|
2590
|
+
`)
|
|
2542
2591
|
})
|
|
2543
2592
|
|
|
2544
2593
|
test('validation error → 400', async () => {
|
|
@@ -2832,6 +2881,47 @@ describe('fetch api', () => {
|
|
|
2832
2881
|
`)
|
|
2833
2882
|
})
|
|
2834
2883
|
|
|
2884
|
+
test('tools/call with no-args command', async () => {
|
|
2885
|
+
const cli = createApp()
|
|
2886
|
+
const sessionId = await initSession(cli)
|
|
2887
|
+
const res = await mcpRequest(
|
|
2888
|
+
cli,
|
|
2889
|
+
{
|
|
2890
|
+
jsonrpc: '2.0',
|
|
2891
|
+
id: 6,
|
|
2892
|
+
method: 'tools/call',
|
|
2893
|
+
params: { name: 'ping', arguments: {} },
|
|
2894
|
+
},
|
|
2895
|
+
sessionId,
|
|
2896
|
+
)
|
|
2897
|
+
expect(res.status).toBe(200)
|
|
2898
|
+
const body = await res.json()
|
|
2899
|
+
expect(JSON.parse(body.result.content[0].text)).toMatchInlineSnapshot(`
|
|
2900
|
+
{
|
|
2901
|
+
"pong": true,
|
|
2902
|
+
}
|
|
2903
|
+
`)
|
|
2904
|
+
})
|
|
2905
|
+
|
|
2906
|
+
test('tools/call with streaming command', async () => {
|
|
2907
|
+
const cli = createApp()
|
|
2908
|
+
const sessionId = await initSession(cli)
|
|
2909
|
+
const res = await mcpRequest(
|
|
2910
|
+
cli,
|
|
2911
|
+
{
|
|
2912
|
+
jsonrpc: '2.0',
|
|
2913
|
+
id: 7,
|
|
2914
|
+
method: 'tools/call',
|
|
2915
|
+
params: { name: 'stream', arguments: {} },
|
|
2916
|
+
},
|
|
2917
|
+
sessionId,
|
|
2918
|
+
)
|
|
2919
|
+
expect(res.status).toBe(200)
|
|
2920
|
+
const body = await res.json()
|
|
2921
|
+
const chunks = JSON.parse(body.result.content[0].text)
|
|
2922
|
+
expect(chunks).toEqual([{ content: 'hello' }, { content: 'world' }])
|
|
2923
|
+
})
|
|
2924
|
+
|
|
2835
2925
|
test('non-/mcp paths still work alongside MCP', async () => {
|
|
2836
2926
|
const cli = createApp()
|
|
2837
2927
|
// Initialize MCP first
|