incur 0.4.0 → 0.4.1
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 +727 -440
- 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 +44 -0
- package/dist/SyncSkills.d.ts.map +1 -1
- package/dist/SyncSkills.js +82 -7
- 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 +1213 -100
- package/src/Cli.ts +876 -568
- 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 +120 -3
- package/src/SyncSkills.ts +142 -6
- package/src/Typegen.test.ts +15 -0
- package/src/Typegen.ts +4 -2
- package/src/bin.ts +21 -2
- package/src/e2e.test.ts +172 -97
- 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
|
@@ -70,9 +70,9 @@ describe('routing', () => {
|
|
|
70
70
|
"code: COMMAND_NOT_FOUND
|
|
71
71
|
message: 'nonexistent' is not a command for 'app'.
|
|
72
72
|
cta:
|
|
73
|
-
description: "
|
|
74
|
-
commands[1]{command}:
|
|
75
|
-
app --help
|
|
73
|
+
description: "Suggested command:"
|
|
74
|
+
commands[1]{command,description}:
|
|
75
|
+
app --help,see all available commands
|
|
76
76
|
"
|
|
77
77
|
`)
|
|
78
78
|
})
|
|
@@ -85,8 +85,8 @@ describe('routing', () => {
|
|
|
85
85
|
expect(output).toMatchInlineSnapshot(`
|
|
86
86
|
"Error: 'nonexistent' is not a command for 'app'.
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
app --help
|
|
88
|
+
Suggested command:
|
|
89
|
+
app --help # see all available commands
|
|
90
90
|
"
|
|
91
91
|
`)
|
|
92
92
|
})
|
|
@@ -98,9 +98,9 @@ describe('routing', () => {
|
|
|
98
98
|
"code: COMMAND_NOT_FOUND
|
|
99
99
|
message: 'whoami' is not a command for 'app auth'.
|
|
100
100
|
cta:
|
|
101
|
-
description: "
|
|
102
|
-
commands[1]{command}:
|
|
103
|
-
app auth --help
|
|
101
|
+
description: "Suggested command:"
|
|
102
|
+
commands[1]{command,description}:
|
|
103
|
+
app auth --help,see all available commands
|
|
104
104
|
"
|
|
105
105
|
`)
|
|
106
106
|
})
|
|
@@ -112,9 +112,9 @@ describe('routing', () => {
|
|
|
112
112
|
"code: COMMAND_NOT_FOUND
|
|
113
113
|
message: 'nope' is not a command for 'app project deploy'.
|
|
114
114
|
cta:
|
|
115
|
-
description: "
|
|
116
|
-
commands[1]{command}:
|
|
117
|
-
app project deploy --help
|
|
115
|
+
description: "Suggested command:"
|
|
116
|
+
commands[1]{command,description}:
|
|
117
|
+
app project deploy --help,see all available commands
|
|
118
118
|
"
|
|
119
119
|
`)
|
|
120
120
|
})
|
|
@@ -173,7 +173,7 @@ describe('args and options', () => {
|
|
|
173
173
|
'read',
|
|
174
174
|
'--scopes',
|
|
175
175
|
'write',
|
|
176
|
-
'--
|
|
176
|
+
'--full-output',
|
|
177
177
|
'--format',
|
|
178
178
|
'json',
|
|
179
179
|
])
|
|
@@ -192,7 +192,7 @@ describe('args and options', () => {
|
|
|
192
192
|
'list',
|
|
193
193
|
'--limit',
|
|
194
194
|
'5',
|
|
195
|
-
'--
|
|
195
|
+
'--full-output',
|
|
196
196
|
'--format',
|
|
197
197
|
'json',
|
|
198
198
|
])
|
|
@@ -327,8 +327,8 @@ describe('output formats', () => {
|
|
|
327
327
|
`)
|
|
328
328
|
})
|
|
329
329
|
|
|
330
|
-
test('--
|
|
331
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
330
|
+
test('--full-output full envelope', async () => {
|
|
331
|
+
const { output } = await serve(createApp(), ['ping', '--full-output'])
|
|
332
332
|
expect(output).toMatchInlineSnapshot(`
|
|
333
333
|
"ok: true
|
|
334
334
|
data:
|
|
@@ -340,8 +340,8 @@ describe('output formats', () => {
|
|
|
340
340
|
`)
|
|
341
341
|
})
|
|
342
342
|
|
|
343
|
-
test('--
|
|
344
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
343
|
+
test('--full-output --format json full envelope', async () => {
|
|
344
|
+
const { output } = await serve(createApp(), ['ping', '--full-output', '--format', 'json'])
|
|
345
345
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
346
346
|
{
|
|
347
347
|
"data": {
|
|
@@ -356,13 +356,13 @@ describe('output formats', () => {
|
|
|
356
356
|
`)
|
|
357
357
|
})
|
|
358
358
|
|
|
359
|
-
test('nested command path in
|
|
359
|
+
test('nested command path in full-output meta', async () => {
|
|
360
360
|
const { output } = await serve(createApp(), [
|
|
361
361
|
'project',
|
|
362
362
|
'deploy',
|
|
363
363
|
'status',
|
|
364
364
|
'd-1',
|
|
365
|
-
'--
|
|
365
|
+
'--full-output',
|
|
366
366
|
'--format',
|
|
367
367
|
'json',
|
|
368
368
|
])
|
|
@@ -400,8 +400,8 @@ describe('undefined output', () => {
|
|
|
400
400
|
expect(output).toBe('')
|
|
401
401
|
})
|
|
402
402
|
|
|
403
|
-
test('void command shows envelope with --
|
|
404
|
-
const { output } = await serve(createApp(), ['noop', '--
|
|
403
|
+
test('void command shows envelope with --full-output', async () => {
|
|
404
|
+
const { output } = await serve(createApp(), ['noop', '--full-output', '--format', 'json'])
|
|
405
405
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
406
406
|
{
|
|
407
407
|
"meta": {
|
|
@@ -455,10 +455,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
455
455
|
`)
|
|
456
456
|
})
|
|
457
457
|
|
|
458
|
-
test('works with --
|
|
458
|
+
test('works with --full-output', async () => {
|
|
459
459
|
const { output } = await serve(createApp(), [
|
|
460
460
|
'ping',
|
|
461
|
-
'--
|
|
461
|
+
'--full-output',
|
|
462
462
|
'--format',
|
|
463
463
|
'json',
|
|
464
464
|
'--token-limit',
|
|
@@ -479,10 +479,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
479
479
|
`)
|
|
480
480
|
})
|
|
481
481
|
|
|
482
|
-
test('--
|
|
482
|
+
test('--full-output includes meta.nextOffset when truncated', async () => {
|
|
483
483
|
const { output } = await serve(createApp(), [
|
|
484
484
|
'ping',
|
|
485
|
-
'--
|
|
485
|
+
'--full-output',
|
|
486
486
|
'--format',
|
|
487
487
|
'json',
|
|
488
488
|
'--token-limit',
|
|
@@ -492,10 +492,10 @@ describe('--token-limit and --token-offset', () => {
|
|
|
492
492
|
expect(output).toContain('[truncated:')
|
|
493
493
|
})
|
|
494
494
|
|
|
495
|
-
test('--
|
|
495
|
+
test('--full-output omits meta.nextOffset when not truncated', async () => {
|
|
496
496
|
const { output } = await serve(createApp(), [
|
|
497
497
|
'ping',
|
|
498
|
-
'--
|
|
498
|
+
'--full-output',
|
|
499
499
|
'--format',
|
|
500
500
|
'json',
|
|
501
501
|
'--token-limit',
|
|
@@ -575,7 +575,7 @@ describe('error handling', () => {
|
|
|
575
575
|
const { output, exitCode } = await serve(createApp(), [
|
|
576
576
|
'auth',
|
|
577
577
|
'status',
|
|
578
|
-
'--
|
|
578
|
+
'--full-output',
|
|
579
579
|
'--format',
|
|
580
580
|
'json',
|
|
581
581
|
])
|
|
@@ -595,7 +595,7 @@ describe('error handling', () => {
|
|
|
595
595
|
"command": "app auth login",
|
|
596
596
|
},
|
|
597
597
|
],
|
|
598
|
-
"description": "Suggested
|
|
598
|
+
"description": "Suggested command:",
|
|
599
599
|
},
|
|
600
600
|
"duration": "<stripped>",
|
|
601
601
|
},
|
|
@@ -633,7 +633,7 @@ describe('error handling', () => {
|
|
|
633
633
|
test('command not found returns error envelope', async () => {
|
|
634
634
|
const { output, exitCode } = await serve(createApp(), [
|
|
635
635
|
'nonexistent',
|
|
636
|
-
'--
|
|
636
|
+
'--full-output',
|
|
637
637
|
'--format',
|
|
638
638
|
'json',
|
|
639
639
|
])
|
|
@@ -650,9 +650,10 @@ describe('error handling', () => {
|
|
|
650
650
|
"commands": [
|
|
651
651
|
{
|
|
652
652
|
"command": "app --help",
|
|
653
|
+
"description": "see all available commands",
|
|
653
654
|
},
|
|
654
655
|
],
|
|
655
|
-
"description": "
|
|
656
|
+
"description": "Suggested command:",
|
|
656
657
|
},
|
|
657
658
|
"duration": "<stripped>",
|
|
658
659
|
},
|
|
@@ -675,7 +676,13 @@ describe('error handling', () => {
|
|
|
675
676
|
|
|
676
677
|
describe('cta', () => {
|
|
677
678
|
test('ok() with string CTAs', async () => {
|
|
678
|
-
const { output } = await serve(createApp(), [
|
|
679
|
+
const { output } = await serve(createApp(), [
|
|
680
|
+
'auth',
|
|
681
|
+
'login',
|
|
682
|
+
'--full-output',
|
|
683
|
+
'--format',
|
|
684
|
+
'json',
|
|
685
|
+
])
|
|
679
686
|
expect(json(output).meta.cta).toMatchInlineSnapshot(`
|
|
680
687
|
{
|
|
681
688
|
"commands": [
|
|
@@ -693,7 +700,7 @@ describe('cta', () => {
|
|
|
693
700
|
'project',
|
|
694
701
|
'create',
|
|
695
702
|
'MyProject',
|
|
696
|
-
'--
|
|
703
|
+
'--full-output',
|
|
697
704
|
'--format',
|
|
698
705
|
'json',
|
|
699
706
|
])
|
|
@@ -714,7 +721,13 @@ describe('cta', () => {
|
|
|
714
721
|
})
|
|
715
722
|
|
|
716
723
|
test('error() with CTA', async () => {
|
|
717
|
-
const { output } = await serve(createApp(), [
|
|
724
|
+
const { output } = await serve(createApp(), [
|
|
725
|
+
'auth',
|
|
726
|
+
'status',
|
|
727
|
+
'--full-output',
|
|
728
|
+
'--format',
|
|
729
|
+
'json',
|
|
730
|
+
])
|
|
718
731
|
expect(json(output).meta.cta).toMatchInlineSnapshot(`
|
|
719
732
|
{
|
|
720
733
|
"commands": [
|
|
@@ -722,13 +735,13 @@ describe('cta', () => {
|
|
|
722
735
|
"command": "app auth login",
|
|
723
736
|
},
|
|
724
737
|
],
|
|
725
|
-
"description": "Suggested
|
|
738
|
+
"description": "Suggested command:",
|
|
726
739
|
}
|
|
727
740
|
`)
|
|
728
741
|
})
|
|
729
742
|
|
|
730
743
|
test('plain return omits CTA', async () => {
|
|
731
|
-
const { output } = await serve(createApp(), ['ping', '--
|
|
744
|
+
const { output } = await serve(createApp(), ['ping', '--full-output', '--format', 'json'])
|
|
732
745
|
expect(json(output).meta.cta).toBeUndefined()
|
|
733
746
|
})
|
|
734
747
|
|
|
@@ -737,7 +750,7 @@ describe('cta', () => {
|
|
|
737
750
|
'project',
|
|
738
751
|
'list',
|
|
739
752
|
'--archived',
|
|
740
|
-
'--
|
|
753
|
+
'--full-output',
|
|
741
754
|
'--format',
|
|
742
755
|
'json',
|
|
743
756
|
])
|
|
@@ -779,8 +792,8 @@ describe('streaming', () => {
|
|
|
779
792
|
`)
|
|
780
793
|
})
|
|
781
794
|
|
|
782
|
-
test('default streams toon per chunk (--
|
|
783
|
-
const { output } = await serve(createApp(), ['stream', '--
|
|
795
|
+
test('default streams toon per chunk (--full-output)', async () => {
|
|
796
|
+
const { output } = await serve(createApp(), ['stream', '--full-output'])
|
|
784
797
|
expect(output).toMatchInlineSnapshot(`
|
|
785
798
|
"content: hello
|
|
786
799
|
content: world
|
|
@@ -802,8 +815,8 @@ describe('streaming', () => {
|
|
|
802
815
|
`)
|
|
803
816
|
})
|
|
804
817
|
|
|
805
|
-
test('--format json --
|
|
806
|
-
const { output } = await serve(createApp(), ['stream', '--
|
|
818
|
+
test('--format json --full-output buffers with envelope', async () => {
|
|
819
|
+
const { output } = await serve(createApp(), ['stream', '--full-output', '--format', 'json'])
|
|
807
820
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
808
821
|
{
|
|
809
822
|
"data": [
|
|
@@ -868,7 +881,7 @@ describe('streaming', () => {
|
|
|
868
881
|
"command": "app ping",
|
|
869
882
|
},
|
|
870
883
|
],
|
|
871
|
-
"description": "Suggested
|
|
884
|
+
"description": "Suggested command:",
|
|
872
885
|
}
|
|
873
886
|
`)
|
|
874
887
|
})
|
|
@@ -877,7 +890,7 @@ describe('streaming', () => {
|
|
|
877
890
|
const { output } = await serve(createApp(), ['stream-ok'])
|
|
878
891
|
expect(output).toContain('n: 1')
|
|
879
892
|
expect(output).toContain('n: 2')
|
|
880
|
-
expect(output).toContain('Suggested
|
|
893
|
+
expect(output).toContain('Suggested command:')
|
|
881
894
|
expect(output).toContain('app ping')
|
|
882
895
|
})
|
|
883
896
|
|
|
@@ -963,22 +976,22 @@ describe('help', () => {
|
|
|
963
976
|
stream-throw Stream that throws
|
|
964
977
|
validate-fail Fails validation
|
|
965
978
|
|
|
966
|
-
|
|
979
|
+
Integrations:
|
|
967
980
|
completions Generate shell completion script
|
|
968
|
-
mcp add Register as
|
|
969
|
-
skills
|
|
981
|
+
mcp add Register as MCP server
|
|
982
|
+
skills Sync skill files to agents (add, list)
|
|
970
983
|
|
|
971
984
|
Global Options:
|
|
972
985
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
973
986
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
987
|
+
--full-output Show full output envelope
|
|
974
988
|
--help Show help
|
|
975
989
|
--llms, --llms-full Print LLM-readable manifest
|
|
976
990
|
--mcp Start as MCP stdio server
|
|
977
|
-
--schema Show JSON Schema for
|
|
991
|
+
--schema Show JSON Schema for command
|
|
978
992
|
--token-count Print token count of output (instead of output)
|
|
979
993
|
--token-limit <n> Limit output to n tokens
|
|
980
994
|
--token-offset <n> Skip first n tokens of output
|
|
981
|
-
--verbose Show full output envelope
|
|
982
995
|
--version Show version
|
|
983
996
|
"
|
|
984
997
|
`)
|
|
@@ -1005,13 +1018,13 @@ describe('help', () => {
|
|
|
1005
1018
|
Global Options:
|
|
1006
1019
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1007
1020
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1021
|
+
--full-output Show full output envelope
|
|
1008
1022
|
--help Show help
|
|
1009
1023
|
--llms, --llms-full Print LLM-readable manifest
|
|
1010
|
-
--schema Show JSON Schema for
|
|
1024
|
+
--schema Show JSON Schema for command
|
|
1011
1025
|
--token-count Print token count of output (instead of output)
|
|
1012
1026
|
--token-limit <n> Limit output to n tokens
|
|
1013
1027
|
--token-offset <n> Skip first n tokens of output
|
|
1014
|
-
--verbose Show full output envelope
|
|
1015
1028
|
"
|
|
1016
1029
|
`)
|
|
1017
1030
|
})
|
|
@@ -1032,13 +1045,13 @@ describe('help', () => {
|
|
|
1032
1045
|
Global Options:
|
|
1033
1046
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1034
1047
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1048
|
+
--full-output Show full output envelope
|
|
1035
1049
|
--help Show help
|
|
1036
1050
|
--llms, --llms-full Print LLM-readable manifest
|
|
1037
|
-
--schema Show JSON Schema for
|
|
1051
|
+
--schema Show JSON Schema for command
|
|
1038
1052
|
--token-count Print token count of output (instead of output)
|
|
1039
1053
|
--token-limit <n> Limit output to n tokens
|
|
1040
1054
|
--token-offset <n> Skip first n tokens of output
|
|
1041
|
-
--verbose Show full output envelope
|
|
1042
1055
|
"
|
|
1043
1056
|
`)
|
|
1044
1057
|
})
|
|
@@ -1053,18 +1066,18 @@ describe('help', () => {
|
|
|
1053
1066
|
Options:
|
|
1054
1067
|
--limit, -l <number> Max results (default: 20)
|
|
1055
1068
|
--sort, -s <name|created|updated> Sort field (default: name)
|
|
1056
|
-
--archived
|
|
1069
|
+
--archived Include archived
|
|
1057
1070
|
|
|
1058
1071
|
Global Options:
|
|
1059
1072
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1060
1073
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1074
|
+
--full-output Show full output envelope
|
|
1061
1075
|
--help Show help
|
|
1062
1076
|
--llms, --llms-full Print LLM-readable manifest
|
|
1063
|
-
--schema Show JSON Schema for
|
|
1077
|
+
--schema Show JSON Schema for command
|
|
1064
1078
|
--token-count Print token count of output (instead of output)
|
|
1065
1079
|
--token-limit <n> Limit output to n tokens
|
|
1066
1080
|
--token-offset <n> Skip first n tokens of output
|
|
1067
|
-
--verbose Show full output envelope
|
|
1068
1081
|
"
|
|
1069
1082
|
`)
|
|
1070
1083
|
})
|
|
@@ -1081,7 +1094,7 @@ describe('help', () => {
|
|
|
1081
1094
|
|
|
1082
1095
|
Options:
|
|
1083
1096
|
--branch, -b <string> Branch to deploy (default: main)
|
|
1084
|
-
--dry-run
|
|
1097
|
+
--dry-run Dry run mode
|
|
1085
1098
|
|
|
1086
1099
|
Examples:
|
|
1087
1100
|
app project deploy create staging # Deploy staging from main
|
|
@@ -1090,13 +1103,13 @@ describe('help', () => {
|
|
|
1090
1103
|
Global Options:
|
|
1091
1104
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1092
1105
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1106
|
+
--full-output Show full output envelope
|
|
1093
1107
|
--help Show help
|
|
1094
1108
|
--llms, --llms-full Print LLM-readable manifest
|
|
1095
|
-
--schema Show JSON Schema for
|
|
1109
|
+
--schema Show JSON Schema for command
|
|
1096
1110
|
--token-count Print token count of output (instead of output)
|
|
1097
1111
|
--token-limit <n> Limit output to n tokens
|
|
1098
1112
|
--token-offset <n> Skip first n tokens of output
|
|
1099
|
-
--verbose Show full output envelope
|
|
1100
1113
|
"
|
|
1101
1114
|
`)
|
|
1102
1115
|
})
|
|
@@ -1589,8 +1602,8 @@ describe('typegen', () => {
|
|
|
1589
1602
|
'auth login': { args: {}; options: { hostname: string; web: boolean; scopes: string[] } }
|
|
1590
1603
|
'auth logout': { args: {}; options: {} }
|
|
1591
1604
|
'auth status': { args: {}; options: {} }
|
|
1592
|
-
'config': { args: { key
|
|
1593
|
-
'echo': { args: { message: string; repeat
|
|
1605
|
+
'config': { args: { key?: string }; options: {} }
|
|
1606
|
+
'echo': { args: { message: string; repeat?: number }; options: { upper: boolean; prefix: string } }
|
|
1594
1607
|
'explode': { args: {}; options: {} }
|
|
1595
1608
|
'explode-clac': { args: {}; options: {} }
|
|
1596
1609
|
'noop': { args: {}; options: {} }
|
|
@@ -1738,22 +1751,22 @@ describe('root command with subcommands', () => {
|
|
|
1738
1751
|
info Show info
|
|
1739
1752
|
version Show version
|
|
1740
1753
|
|
|
1741
|
-
|
|
1754
|
+
Integrations:
|
|
1742
1755
|
completions Generate shell completion script
|
|
1743
|
-
mcp add Register as
|
|
1744
|
-
skills
|
|
1756
|
+
mcp add Register as MCP server
|
|
1757
|
+
skills Sync skill files to agents (add, list)
|
|
1745
1758
|
|
|
1746
1759
|
Global Options:
|
|
1747
1760
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1748
1761
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1762
|
+
--full-output Show full output envelope
|
|
1749
1763
|
--help Show help
|
|
1750
1764
|
--llms, --llms-full Print LLM-readable manifest
|
|
1751
1765
|
--mcp Start as MCP stdio server
|
|
1752
|
-
--schema Show JSON Schema for
|
|
1766
|
+
--schema Show JSON Schema for command
|
|
1753
1767
|
--token-count Print token count of output (instead of output)
|
|
1754
1768
|
--token-limit <n> Limit output to n tokens
|
|
1755
1769
|
--token-offset <n> Skip first n tokens of output
|
|
1756
|
-
--verbose Show full output envelope
|
|
1757
1770
|
--version Show version
|
|
1758
1771
|
"
|
|
1759
1772
|
`)
|
|
@@ -1786,7 +1799,7 @@ describe('edge cases', () => {
|
|
|
1786
1799
|
"description": "View "Alpha"",
|
|
1787
1800
|
},
|
|
1788
1801
|
],
|
|
1789
|
-
"description": "Suggested
|
|
1802
|
+
"description": "Suggested command:",
|
|
1790
1803
|
},
|
|
1791
1804
|
"items": [
|
|
1792
1805
|
{
|
|
@@ -1864,7 +1877,7 @@ describe('edge cases', () => {
|
|
|
1864
1877
|
'prod',
|
|
1865
1878
|
'--branch',
|
|
1866
1879
|
'release',
|
|
1867
|
-
'--
|
|
1880
|
+
'--full-output',
|
|
1868
1881
|
])
|
|
1869
1882
|
expect(json(output)).toMatchInlineSnapshot(`
|
|
1870
1883
|
{
|
|
@@ -1893,7 +1906,7 @@ describe('env', () => {
|
|
|
1893
1906
|
test('env vars passed to handler', async () => {
|
|
1894
1907
|
const { output } = await serve(
|
|
1895
1908
|
createApp(),
|
|
1896
|
-
['auth', 'login', '--
|
|
1909
|
+
['auth', 'login', '--full-output', '--format', 'json'],
|
|
1897
1910
|
{ env: { AUTH_HOST: 'custom.example.com' } },
|
|
1898
1911
|
)
|
|
1899
1912
|
expect(json(output).data.hostname).toBe('custom.example.com')
|
|
@@ -1902,7 +1915,7 @@ describe('env', () => {
|
|
|
1902
1915
|
test('env defaults applied when var is unset', async () => {
|
|
1903
1916
|
const { output } = await serve(
|
|
1904
1917
|
createApp(),
|
|
1905
|
-
['auth', 'login', '--
|
|
1918
|
+
['auth', 'login', '--full-output', '--format', 'json'],
|
|
1906
1919
|
{ env: {} },
|
|
1907
1920
|
)
|
|
1908
1921
|
expect(json(output).data.hostname).toBe('api.example.com')
|
|
@@ -1917,19 +1930,19 @@ describe('env', () => {
|
|
|
1917
1930
|
|
|
1918
1931
|
Options:
|
|
1919
1932
|
--hostname, -h <string> API hostname (default: api.example.com)
|
|
1920
|
-
--web, -w
|
|
1933
|
+
--web, -w Open browser
|
|
1921
1934
|
--scopes <array> OAuth scopes
|
|
1922
1935
|
|
|
1923
1936
|
Global Options:
|
|
1924
1937
|
--filter-output <keys> Filter output by key paths (e.g. foo,bar.baz,a[0,3])
|
|
1925
1938
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
1939
|
+
--full-output Show full output envelope
|
|
1926
1940
|
--help Show help
|
|
1927
1941
|
--llms, --llms-full Print LLM-readable manifest
|
|
1928
|
-
--schema Show JSON Schema for
|
|
1942
|
+
--schema Show JSON Schema for command
|
|
1929
1943
|
--token-count Print token count of output (instead of output)
|
|
1930
1944
|
--token-limit <n> Limit output to n tokens
|
|
1931
1945
|
--token-offset <n> Skip first n tokens of output
|
|
1932
|
-
--verbose Show full output envelope
|
|
1933
1946
|
|
|
1934
1947
|
Environment Variables:
|
|
1935
1948
|
AUTH_TOKEN Pre-existing auth token
|
|
@@ -1974,13 +1987,15 @@ describe('skills staleness', () => {
|
|
|
1974
1987
|
|
|
1975
1988
|
afterEach(() => {
|
|
1976
1989
|
stderrSpy.mockRestore()
|
|
1990
|
+
__mockSkillsHash = undefined
|
|
1977
1991
|
})
|
|
1978
1992
|
|
|
1979
|
-
test('
|
|
1993
|
+
test('includes skills CTA when stale', async () => {
|
|
1980
1994
|
__mockSkillsHash = '0000000000000000'
|
|
1981
1995
|
const { output } = await serve(createApp(), ['ping'])
|
|
1982
1996
|
expect(output).toContain('pong: true')
|
|
1983
|
-
expect(
|
|
1997
|
+
expect(output).toContain('Skills are out of date:')
|
|
1998
|
+
expect(output).toContain('skills add')
|
|
1984
1999
|
})
|
|
1985
2000
|
|
|
1986
2001
|
test('no warning when skills hash matches', async () => {
|
|
@@ -1991,20 +2006,20 @@ describe('skills staleness', () => {
|
|
|
1991
2006
|
|
|
1992
2007
|
const { output } = await serve(cli, ['ping'])
|
|
1993
2008
|
expect(output).toContain('pong: true')
|
|
1994
|
-
expect(
|
|
2009
|
+
expect(output).not.toContain('Skills are out of date')
|
|
1995
2010
|
})
|
|
1996
2011
|
|
|
1997
2012
|
test('no warning on first use (no hash stored)', async () => {
|
|
1998
2013
|
__mockSkillsHash = undefined
|
|
1999
2014
|
const { output } = await serve(createApp(), ['ping'])
|
|
2000
2015
|
expect(output).toContain('pong: true')
|
|
2001
|
-
expect(
|
|
2016
|
+
expect(output).not.toContain('Skills are out of date')
|
|
2002
2017
|
})
|
|
2003
2018
|
|
|
2004
2019
|
test('no warning for --llms', async () => {
|
|
2005
2020
|
__mockSkillsHash = '0000000000000000'
|
|
2006
|
-
await serve(createApp(), ['--llms'])
|
|
2007
|
-
expect(
|
|
2021
|
+
const { output } = await serve(createApp(), ['--llms'])
|
|
2022
|
+
expect(output).not.toContain('Skills are out of date')
|
|
2008
2023
|
})
|
|
2009
2024
|
|
|
2010
2025
|
test('no warning for --mcp', async () => {
|
|
@@ -2034,9 +2049,9 @@ describe('middleware', () => {
|
|
|
2034
2049
|
`)
|
|
2035
2050
|
})
|
|
2036
2051
|
|
|
2037
|
-
test('vars:
|
|
2052
|
+
test('vars: full-output envelope includes var data', async () => {
|
|
2038
2053
|
const { cli } = createMiddlewareApp()
|
|
2039
|
-
const { output } = await serve(cli, ['whoami', '--
|
|
2054
|
+
const { output } = await serve(cli, ['whoami', '--full-output', '--format', 'json'])
|
|
2040
2055
|
const parsed = json(output)
|
|
2041
2056
|
expect(parsed.data.user).toBe('alice')
|
|
2042
2057
|
expect(parsed.data.requestId).toBe('req-default')
|
|
@@ -2204,7 +2219,7 @@ describe('fetch gateway', () => {
|
|
|
2204
2219
|
})
|
|
2205
2220
|
|
|
2206
2221
|
test('query params from --key value', async () => {
|
|
2207
|
-
|
|
2222
|
+
await serve(createApp(), ['api', 'users', '--limit', '5'])
|
|
2208
2223
|
const { output: jsonOut } = await serve(createApp(), [
|
|
2209
2224
|
'api',
|
|
2210
2225
|
'users',
|
|
@@ -2273,8 +2288,14 @@ describe('fetch gateway', () => {
|
|
|
2273
2288
|
expect(json(output)).toEqual({ ok: true })
|
|
2274
2289
|
})
|
|
2275
2290
|
|
|
2276
|
-
test('--
|
|
2277
|
-
const { output } = await serve(createApp(), [
|
|
2291
|
+
test('--full-output wraps in envelope', async () => {
|
|
2292
|
+
const { output } = await serve(createApp(), [
|
|
2293
|
+
'api',
|
|
2294
|
+
'health',
|
|
2295
|
+
'--full-output',
|
|
2296
|
+
'--format',
|
|
2297
|
+
'json',
|
|
2298
|
+
])
|
|
2278
2299
|
const parsed = json(output)
|
|
2279
2300
|
expect(parsed.ok).toBe(true)
|
|
2280
2301
|
expect(parsed.data).toEqual({ ok: true })
|
|
@@ -2441,6 +2462,18 @@ describe('fetch api', () => {
|
|
|
2441
2462
|
},
|
|
2442
2463
|
"meta": {
|
|
2443
2464
|
"command": "project create",
|
|
2465
|
+
"cta": {
|
|
2466
|
+
"commands": [
|
|
2467
|
+
{
|
|
2468
|
+
"command": "app project get p-new",
|
|
2469
|
+
"description": "View "MyProject"",
|
|
2470
|
+
},
|
|
2471
|
+
{
|
|
2472
|
+
"command": "app project list",
|
|
2473
|
+
},
|
|
2474
|
+
],
|
|
2475
|
+
"description": "Suggested commands:",
|
|
2476
|
+
},
|
|
2444
2477
|
"duration": "<stripped>",
|
|
2445
2478
|
},
|
|
2446
2479
|
"ok": true,
|
|
@@ -2524,21 +2557,22 @@ describe('fetch api', () => {
|
|
|
2524
2557
|
const cli = createApp()
|
|
2525
2558
|
expect(await fetchJson(cli, new Request('http://localhost/explode-clac')))
|
|
2526
2559
|
.toMatchInlineSnapshot(`
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
"
|
|
2535
|
-
|
|
2560
|
+
{
|
|
2561
|
+
"body": {
|
|
2562
|
+
"error": {
|
|
2563
|
+
"code": "QUOTA_EXCEEDED",
|
|
2564
|
+
"message": "Rate limit exceeded",
|
|
2565
|
+
"retryable": true,
|
|
2566
|
+
},
|
|
2567
|
+
"meta": {
|
|
2568
|
+
"command": "explode-clac",
|
|
2569
|
+
"duration": "<stripped>",
|
|
2570
|
+
},
|
|
2571
|
+
"ok": false,
|
|
2536
2572
|
},
|
|
2537
|
-
"
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
}
|
|
2541
|
-
`)
|
|
2573
|
+
"status": 500,
|
|
2574
|
+
}
|
|
2575
|
+
`)
|
|
2542
2576
|
})
|
|
2543
2577
|
|
|
2544
2578
|
test('validation error → 400', async () => {
|
|
@@ -2832,6 +2866,47 @@ describe('fetch api', () => {
|
|
|
2832
2866
|
`)
|
|
2833
2867
|
})
|
|
2834
2868
|
|
|
2869
|
+
test('tools/call with no-args command', async () => {
|
|
2870
|
+
const cli = createApp()
|
|
2871
|
+
const sessionId = await initSession(cli)
|
|
2872
|
+
const res = await mcpRequest(
|
|
2873
|
+
cli,
|
|
2874
|
+
{
|
|
2875
|
+
jsonrpc: '2.0',
|
|
2876
|
+
id: 6,
|
|
2877
|
+
method: 'tools/call',
|
|
2878
|
+
params: { name: 'ping', arguments: {} },
|
|
2879
|
+
},
|
|
2880
|
+
sessionId,
|
|
2881
|
+
)
|
|
2882
|
+
expect(res.status).toBe(200)
|
|
2883
|
+
const body = await res.json()
|
|
2884
|
+
expect(JSON.parse(body.result.content[0].text)).toMatchInlineSnapshot(`
|
|
2885
|
+
{
|
|
2886
|
+
"pong": true,
|
|
2887
|
+
}
|
|
2888
|
+
`)
|
|
2889
|
+
})
|
|
2890
|
+
|
|
2891
|
+
test('tools/call with streaming command', async () => {
|
|
2892
|
+
const cli = createApp()
|
|
2893
|
+
const sessionId = await initSession(cli)
|
|
2894
|
+
const res = await mcpRequest(
|
|
2895
|
+
cli,
|
|
2896
|
+
{
|
|
2897
|
+
jsonrpc: '2.0',
|
|
2898
|
+
id: 7,
|
|
2899
|
+
method: 'tools/call',
|
|
2900
|
+
params: { name: 'stream', arguments: {} },
|
|
2901
|
+
},
|
|
2902
|
+
sessionId,
|
|
2903
|
+
)
|
|
2904
|
+
expect(res.status).toBe(200)
|
|
2905
|
+
const body = await res.json()
|
|
2906
|
+
const chunks = JSON.parse(body.result.content[0].text)
|
|
2907
|
+
expect(chunks).toEqual([{ content: 'hello' }, { content: 'world' }])
|
|
2908
|
+
})
|
|
2909
|
+
|
|
2835
2910
|
test('non-/mcp paths still work alongside MCP', async () => {
|
|
2836
2911
|
const cli = createApp()
|
|
2837
2912
|
// Initialize MCP first
|