@crouton-kit/crouter 0.3.16 → 0.3.18

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 (104) hide show
  1. package/dist/builtin-personas/design/{base.md → PERSONA.md} +4 -0
  2. package/dist/builtin-personas/developer/{base.md → PERSONA.md} +4 -0
  3. package/dist/builtin-personas/explore/{base.md → PERSONA.md} +4 -0
  4. package/dist/builtin-personas/general/{base.md → PERSONA.md} +4 -0
  5. package/dist/builtin-personas/orchestration-kernel.md +6 -6
  6. package/dist/builtin-personas/plan/{base.md → PERSONA.md} +5 -1
  7. package/dist/builtin-personas/plan/reviewers/architecture-fit/{base.md → PERSONA.md} +1 -1
  8. package/dist/builtin-personas/plan/reviewers/code-smells/{base.md → PERSONA.md} +1 -1
  9. package/dist/builtin-personas/plan/reviewers/pattern-consistency/{base.md → PERSONA.md} +1 -1
  10. package/dist/builtin-personas/plan/reviewers/requirements-coverage/{base.md → PERSONA.md} +1 -1
  11. package/dist/builtin-personas/plan/reviewers/security/{base.md → PERSONA.md} +1 -1
  12. package/dist/builtin-personas/review/{base.md → PERSONA.md} +4 -0
  13. package/dist/builtin-personas/spec/{base.md → PERSONA.md} +5 -1
  14. package/dist/builtin-skills/skills/crouter-development/personas/SKILL.md +24 -14
  15. package/dist/builtin-skills/skills/crouter-development/personas/base-prompt/SKILL.md +4 -4
  16. package/dist/commands/canvas-browse.d.ts +2 -0
  17. package/dist/commands/canvas-browse.js +45 -0
  18. package/dist/commands/canvas-prune.js +11 -2
  19. package/dist/commands/canvas.js +3 -2
  20. package/dist/commands/daemon.js +1 -1
  21. package/dist/commands/human/prompts.js +3 -9
  22. package/dist/commands/human/shared.d.ts +26 -1
  23. package/dist/commands/human/shared.js +48 -10
  24. package/dist/commands/node.js +66 -4
  25. package/dist/commands/skill/author.js +2 -2
  26. package/dist/core/__tests__/cascade-close.test.js +199 -0
  27. package/dist/core/__tests__/daemon-boot.test.js +7 -0
  28. package/dist/core/__tests__/daemon-liveness.test.js +59 -4
  29. package/dist/core/__tests__/dead-pane-regression.test.js +151 -0
  30. package/dist/core/__tests__/fixtures/fake-pi-host.d.ts +2 -0
  31. package/dist/core/__tests__/fixtures/fake-pi-host.js +301 -0
  32. package/dist/core/__tests__/flagship-lifecycle.test.js +273 -0
  33. package/dist/core/__tests__/grace-clock.test.d.ts +1 -0
  34. package/dist/core/__tests__/grace-clock.test.js +115 -0
  35. package/dist/core/__tests__/helpers/harness.d.ts +78 -0
  36. package/dist/core/__tests__/helpers/harness.js +406 -0
  37. package/dist/core/__tests__/human-surface-target.test.d.ts +1 -0
  38. package/dist/core/__tests__/human-surface-target.test.js +98 -0
  39. package/dist/core/__tests__/lifecycle.test.js +6 -13
  40. package/dist/core/__tests__/live-mutation.test.d.ts +1 -0
  41. package/dist/core/__tests__/live-mutation.test.js +341 -0
  42. package/dist/core/__tests__/persona-subkind.test.js +18 -15
  43. package/dist/core/__tests__/placement-focus.test.js +53 -15
  44. package/dist/core/__tests__/relaunch.test.js +12 -12
  45. package/dist/core/__tests__/reset.test.js +11 -6
  46. package/dist/core/__tests__/spike-harness.test.d.ts +1 -0
  47. package/dist/core/__tests__/spike-harness.test.js +241 -0
  48. package/dist/core/__tests__/subscription-delivery.test.d.ts +1 -0
  49. package/dist/core/__tests__/subscription-delivery.test.js +233 -0
  50. package/dist/core/canvas/browse/__tests__/model.test.d.ts +1 -0
  51. package/dist/core/canvas/browse/__tests__/model.test.js +142 -0
  52. package/dist/core/canvas/browse/__tests__/render.test.d.ts +1 -0
  53. package/dist/core/canvas/browse/__tests__/render.test.js +102 -0
  54. package/dist/core/canvas/browse/app.d.ts +4 -0
  55. package/dist/core/canvas/browse/app.js +349 -0
  56. package/dist/core/canvas/browse/model.d.ts +97 -0
  57. package/dist/core/canvas/browse/model.js +258 -0
  58. package/dist/core/canvas/browse/render.d.ts +41 -0
  59. package/dist/core/canvas/browse/render.js +387 -0
  60. package/dist/core/canvas/browse/terminal.d.ts +23 -0
  61. package/dist/core/canvas/browse/terminal.js +100 -0
  62. package/dist/core/canvas/canvas.d.ts +9 -2
  63. package/dist/core/canvas/canvas.js +41 -3
  64. package/dist/core/canvas/paths.d.ts +4 -1
  65. package/dist/core/canvas/paths.js +10 -4
  66. package/dist/core/canvas/render.d.ts +10 -0
  67. package/dist/core/canvas/render.js +25 -1
  68. package/dist/core/canvas/types.js +2 -2
  69. package/dist/core/feed/inbox.d.ts +0 -3
  70. package/dist/core/feed/inbox.js +1 -5
  71. package/dist/core/help.d.ts +6 -0
  72. package/dist/core/help.js +7 -0
  73. package/dist/core/personas/index.d.ts +4 -3
  74. package/dist/core/personas/index.js +3 -2
  75. package/dist/core/personas/loader.d.ts +34 -16
  76. package/dist/core/personas/loader.js +102 -29
  77. package/dist/core/personas/resolve.d.ts +4 -4
  78. package/dist/core/personas/resolve.js +16 -14
  79. package/dist/core/runtime/busy.d.ts +8 -0
  80. package/dist/core/runtime/busy.js +46 -0
  81. package/dist/core/runtime/lifecycle.d.ts +1 -1
  82. package/dist/core/runtime/lifecycle.js +12 -4
  83. package/dist/core/runtime/naming.d.ts +3 -3
  84. package/dist/core/runtime/naming.js +6 -6
  85. package/dist/core/runtime/placement.d.ts +32 -5
  86. package/dist/core/runtime/placement.js +81 -14
  87. package/dist/core/runtime/reset.d.ts +11 -8
  88. package/dist/core/runtime/reset.js +23 -18
  89. package/dist/core/spawn.d.ts +20 -1
  90. package/dist/core/spawn.js +52 -5
  91. package/dist/daemon/crtrd.js +43 -21
  92. package/dist/pi-extensions/canvas-nav.js +106 -55
  93. package/dist/pi-extensions/canvas-resume.d.ts +0 -1
  94. package/dist/pi-extensions/canvas-resume.js +35 -126
  95. package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
  96. package/dist/pi-extensions/canvas-stophook.js +16 -0
  97. package/dist/prompts/skill.js +6 -1
  98. package/package.json +1 -1
  99. package/dist/commands/__tests__/skill.test.js +0 -290
  100. package/dist/core/__tests__/pkg.test.js +0 -218
  101. package/dist/core/__tests__/sys.test.js +0 -208
  102. /package/dist/{commands/__tests__/skill.test.d.ts → core/__tests__/cascade-close.test.d.ts} +0 -0
  103. /package/dist/core/__tests__/{pkg.test.d.ts → dead-pane-regression.test.d.ts} +0 -0
  104. /package/dist/core/__tests__/{sys.test.d.ts → flagship-lifecycle.test.d.ts} +0 -0
@@ -1,290 +0,0 @@
1
- // Tests for the skill subtree argv-model migration.
2
- // Run with: node --import tsx/esm --test 'src/commands/__tests__/skill.test.ts'
3
- //
4
- // Tests exercise leaf param schemas via parseArgv (framework) — no subprocess
5
- // spawning, no filesystem side-effects from handler logic.
6
- import { test, describe } from 'node:test';
7
- import assert from 'node:assert/strict';
8
- import { parseArgv } from '../../core/command.js';
9
- // ---------------------------------------------------------------------------
10
- // Shared flag param sets (mirrors the leaf definitions exactly)
11
- // ---------------------------------------------------------------------------
12
- const scopeAllFlag = {
13
- kind: 'flag', name: 'scope', type: 'enum',
14
- choices: ['user', 'project', 'all'], required: false, constraint: '',
15
- };
16
- const scopeWriteFlag = {
17
- kind: 'flag', name: 'scope', type: 'enum',
18
- choices: ['user', 'project'], required: false, constraint: '',
19
- };
20
- const pluginFlag = {
21
- kind: 'flag', name: 'plugin', type: 'string', required: false, constraint: '',
22
- };
23
- const includeDisabledFlag = {
24
- kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: '',
25
- };
26
- // ---------------------------------------------------------------------------
27
- // skill find list
28
- // ---------------------------------------------------------------------------
29
- describe('skill find list params', () => {
30
- const params = [
31
- scopeAllFlag,
32
- pluginFlag,
33
- includeDisabledFlag,
34
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: '' },
35
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: '' },
36
- { kind: 'flag', name: 'full', type: 'bool', required: false, constraint: '' },
37
- ];
38
- test('no args: defaults applied', async () => {
39
- const r = await parseArgv(params, []);
40
- assert.equal(r['includeDisabled'], false);
41
- assert.equal(r['limit'], 50);
42
- assert.equal(r['scope'], undefined);
43
- assert.equal(r['plugin'], undefined);
44
- assert.equal(r['cursor'], undefined);
45
- });
46
- test('--scope user', async () => {
47
- const r = await parseArgv(params, ['--scope', 'user']);
48
- assert.equal(r['scope'], 'user');
49
- });
50
- test('--scope invalid rejects', async () => {
51
- await assert.rejects(() => parseArgv(params, ['--scope', 'bogus']), (e) => { assert.match(e.message, /must be one of/); return true; });
52
- });
53
- test('--include-disabled presence = true', async () => {
54
- const r = await parseArgv(params, ['--include-disabled']);
55
- assert.equal(r['includeDisabled'], true);
56
- });
57
- test('--include-disabled=value rejects', async () => {
58
- await assert.rejects(() => parseArgv(params, ['--include-disabled=yes']), (e) => { assert.match(e.message, /takes no value/); return true; });
59
- });
60
- test('--limit 100', async () => {
61
- const r = await parseArgv(params, ['--limit', '100']);
62
- assert.equal(r['limit'], 100);
63
- });
64
- test('--limit non-integer rejects', async () => {
65
- await assert.rejects(() => parseArgv(params, ['--limit', '1.5']), (e) => { assert.match(e.message, /must be an integer/); return true; });
66
- });
67
- test('--cursor TOKEN', async () => {
68
- const r = await parseArgv(params, ['--cursor', 'tok_abc']);
69
- assert.equal(r['cursor'], 'tok_abc');
70
- });
71
- test('--plugin my-plugin', async () => {
72
- const r = await parseArgv(params, ['--plugin', 'my-plugin']);
73
- assert.equal(r['plugin'], 'my-plugin');
74
- });
75
- test('--full presence = true, absence = false', async () => {
76
- const present = await parseArgv(params, ['--full']);
77
- assert.equal(present['full'], true);
78
- const absent = await parseArgv(params, []);
79
- assert.equal(absent['full'], false);
80
- });
81
- });
82
- // ---------------------------------------------------------------------------
83
- // skill find search
84
- // ---------------------------------------------------------------------------
85
- describe('skill find search params', () => {
86
- const params = [
87
- { kind: 'positional', name: 'query', required: true, constraint: '' },
88
- scopeAllFlag,
89
- pluginFlag,
90
- includeDisabledFlag,
91
- { kind: 'flag', name: 'search-body', type: 'bool', required: false, constraint: '' },
92
- ];
93
- test('query positional required', async () => {
94
- await assert.rejects(() => parseArgv(params, []), (e) => { assert.match(e.message, /required parameter is missing/); return true; });
95
- });
96
- test('query parsed as positional', async () => {
97
- const r = await parseArgv(params, ['my topic']);
98
- assert.equal(r['query'], 'my topic');
99
- });
100
- test('query + flags', async () => {
101
- const r = await parseArgv(params, ['debugging', '--scope', 'project', '--include-disabled', '--search-body']);
102
- assert.equal(r['query'], 'debugging');
103
- assert.equal(r['scope'], 'project');
104
- assert.equal(r['includeDisabled'], true);
105
- assert.equal(r['searchBody'], true);
106
- });
107
- test('--search-body presence = true, absence = false', async () => {
108
- const present = await parseArgv(params, ['q', '--search-body']);
109
- assert.equal(present['searchBody'], true);
110
- const absent = await parseArgv(params, ['q']);
111
- assert.equal(absent['searchBody'], false);
112
- });
113
- test('--scope all valid', async () => {
114
- const r = await parseArgv(params, ['q', '--scope', 'all']);
115
- assert.equal(r['scope'], 'all');
116
- });
117
- });
118
- // ---------------------------------------------------------------------------
119
- // skill find grep
120
- // ---------------------------------------------------------------------------
121
- describe('skill find grep params', () => {
122
- const params = [
123
- { kind: 'positional', name: 'pattern', required: true, constraint: '' },
124
- scopeAllFlag,
125
- pluginFlag,
126
- ];
127
- test('pattern positional required', async () => {
128
- await assert.rejects(() => parseArgv(params, []), (e) => { assert.match(e.message, /required parameter is missing/); return true; });
129
- });
130
- test('pattern parsed as positional', async () => {
131
- const r = await parseArgv(params, ['foo.*bar']);
132
- assert.equal(r['pattern'], 'foo.*bar');
133
- });
134
- test('pattern + scope + plugin', async () => {
135
- const r = await parseArgv(params, ['\\btest\\b', '--scope', 'user', '--plugin', 'myplugin']);
136
- assert.equal(r['pattern'], '\\btest\\b');
137
- assert.equal(r['scope'], 'user');
138
- assert.equal(r['plugin'], 'myplugin');
139
- });
140
- });
141
- // ---------------------------------------------------------------------------
142
- // skill read
143
- // ---------------------------------------------------------------------------
144
- describe('skill read params', () => {
145
- const params = [
146
- { kind: 'positional', name: 'name', required: true, constraint: '' },
147
- scopeWriteFlag,
148
- pluginFlag,
149
- { kind: 'flag', name: 'frontmatter', type: 'bool', required: false, constraint: '' },
150
- { kind: 'flag', name: 'no-body', type: 'bool', required: false, constraint: '' },
151
- ];
152
- test('name positional required', async () => {
153
- await assert.rejects(() => parseArgv(params, []), (e) => { assert.match(e.message, /required parameter is missing/); return true; });
154
- });
155
- test('name parsed correctly', async () => {
156
- const r = await parseArgv(params, ['my-skill']);
157
- assert.equal(r['name'], 'my-skill');
158
- });
159
- test('nested name parsed correctly', async () => {
160
- const r = await parseArgv(params, ['some/nested/skill']);
161
- assert.equal(r['name'], 'some/nested/skill');
162
- });
163
- test('--frontmatter presence = true', async () => {
164
- const r = await parseArgv(params, ['my-skill', '--frontmatter']);
165
- assert.equal(r['frontmatter'], true);
166
- });
167
- test('--frontmatter absent = false', async () => {
168
- const r = await parseArgv(params, ['my-skill']);
169
- assert.equal(r['frontmatter'], false);
170
- });
171
- test('--no-body presence = true (kebab to camelCase key)', async () => {
172
- const r = await parseArgv(params, ['my-skill', '--no-body']);
173
- assert.equal(r['noBody'], true);
174
- });
175
- test('--no-body absent = false', async () => {
176
- const r = await parseArgv(params, ['my-skill']);
177
- assert.equal(r['noBody'], false);
178
- });
179
- test('--scope rejects all', async () => {
180
- await assert.rejects(() => parseArgv(params, ['my-skill', '--scope', 'all']), (e) => { assert.match(e.message, /must be one of/); return true; });
181
- });
182
- test('--scope user valid', async () => {
183
- const r = await parseArgv(params, ['my-skill', '--scope', 'user']);
184
- assert.equal(r['scope'], 'user');
185
- });
186
- test('--scope project valid', async () => {
187
- const r = await parseArgv(params, ['skillname', '--scope', 'project']);
188
- assert.equal(r['scope'], 'project');
189
- });
190
- });
191
- // ---------------------------------------------------------------------------
192
- // skill author guide
193
- // ---------------------------------------------------------------------------
194
- describe('skill author guide params', () => {
195
- const VALID_TYPES = ['playbook', 'primer', 'reference', 'runbook', 'freeform'];
196
- const params = [
197
- { kind: 'flag', name: 'type', type: 'enum', choices: VALID_TYPES, required: false, constraint: '' },
198
- { kind: 'flag', name: 'topic', type: 'string', required: false, constraint: '' },
199
- ];
200
- test('no args: both undefined', async () => {
201
- const r = await parseArgv(params, []);
202
- assert.equal(r['type'], undefined);
203
- assert.equal(r['topic'], undefined);
204
- });
205
- test('--type playbook', async () => {
206
- const r = await parseArgv(params, ['--type', 'playbook']);
207
- assert.equal(r['type'], 'playbook');
208
- });
209
- test('--type invalid rejects', async () => {
210
- await assert.rejects(() => parseArgv(params, ['--type', 'bogus']), (e) => { assert.match(e.message, /must be one of/); return true; });
211
- });
212
- test('all valid types accepted', async () => {
213
- for (const t of VALID_TYPES) {
214
- const r = await parseArgv(params, ['--type', t]);
215
- assert.equal(r['type'], t);
216
- }
217
- });
218
- test('--topic string', async () => {
219
- const r = await parseArgv(params, ['--topic', 'debugging methodology']);
220
- assert.equal(r['topic'], 'debugging methodology');
221
- });
222
- });
223
- // ---------------------------------------------------------------------------
224
- // skill author scaffold
225
- // ---------------------------------------------------------------------------
226
- describe('skill author scaffold params', () => {
227
- const VALID_TYPES = ['playbook', 'primer', 'reference', 'runbook', 'freeform'];
228
- const params = [
229
- { kind: 'positional', name: 'qualifier', required: true, constraint: '' },
230
- { kind: 'flag', name: 'type', type: 'enum', choices: VALID_TYPES, required: false, constraint: '' },
231
- { kind: 'flag', name: 'description', type: 'string', required: false, constraint: '' },
232
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
233
- ];
234
- test('qualifier positional required', async () => {
235
- await assert.rejects(() => parseArgv(params, []), (e) => { assert.match(e.message, /required parameter is missing/); return true; });
236
- });
237
- test('qualifier parsed correctly', async () => {
238
- const r = await parseArgv(params, ['myplugin/myskill']);
239
- assert.equal(r['qualifier'], 'myplugin/myskill');
240
- });
241
- test('full invocation', async () => {
242
- const r = await parseArgv(params, [
243
- 'myplugin/myskill',
244
- '--type', 'playbook',
245
- '--scope', 'project',
246
- '--description', 'Use when debugging',
247
- ]);
248
- assert.equal(r['qualifier'], 'myplugin/myskill');
249
- assert.equal(r['type'], 'playbook');
250
- assert.equal(r['scope'], 'project');
251
- assert.equal(r['description'], 'Use when debugging');
252
- });
253
- test('--type invalid rejects', async () => {
254
- await assert.rejects(() => parseArgv(params, ['q/s', '--type', 'invalid']), (e) => { assert.match(e.message, /must be one of/); return true; });
255
- });
256
- test('--scope all rejects', async () => {
257
- await assert.rejects(() => parseArgv(params, ['q/s', '--scope', 'all']), (e) => { assert.match(e.message, /must be one of/); return true; });
258
- });
259
- });
260
- // ---------------------------------------------------------------------------
261
- // skill state enable / disable
262
- // ---------------------------------------------------------------------------
263
- describe('skill state enable/disable params', () => {
264
- const params = [
265
- { kind: 'positional', name: 'name', required: true, constraint: '' },
266
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
267
- ];
268
- test('name positional required', async () => {
269
- await assert.rejects(() => parseArgv(params, []), (e) => { assert.match(e.message, /required parameter is missing/); return true; });
270
- });
271
- test('name parsed correctly', async () => {
272
- const r = await parseArgv(params, ['my-skill']);
273
- assert.equal(r['name'], 'my-skill');
274
- });
275
- test('--scope user', async () => {
276
- const r = await parseArgv(params, ['my-skill', '--scope', 'user']);
277
- assert.equal(r['scope'], 'user');
278
- });
279
- test('--scope project', async () => {
280
- const r = await parseArgv(params, ['my-skill', '--scope', 'project']);
281
- assert.equal(r['scope'], 'project');
282
- });
283
- test('--scope all rejects', async () => {
284
- await assert.rejects(() => parseArgv(params, ['my-skill', '--scope', 'all']), (e) => { assert.match(e.message, /must be one of/); return true; });
285
- });
286
- test('plugin/skill qualifier as name', async () => {
287
- const r = await parseArgv(params, ['myplugin/myskill']);
288
- assert.equal(r['name'], 'myplugin/myskill');
289
- });
290
- });
@@ -1,218 +0,0 @@
1
- // Tests for the pkg subtree argv migration.
2
- // Exercises parseArgv against the param schemas declared in pkg.ts leaves.
3
- // No subprocess spawning; no real FS writes. Tests are schema/parsing level only.
4
- import { test, describe } from 'node:test';
5
- import assert from 'node:assert/strict';
6
- import { parseArgv } from '../command.js';
7
- // ---------------------------------------------------------------------------
8
- // plugin manage install — positional source + optional flags
9
- // ---------------------------------------------------------------------------
10
- describe('pkg plugin manage install', () => {
11
- const params = [
12
- { kind: 'positional', name: 'source', type: 'string', required: true, constraint: 'Git URL.' },
13
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
14
- { kind: 'flag', name: 'ref', type: 'string', required: false, constraint: '' },
15
- ];
16
- test('positional source is required', async () => {
17
- await assert.rejects(() => parseArgv(params, []), (err) => { assert.match(err.message, /required parameter is missing/); return true; });
18
- });
19
- test('parses positional source', async () => {
20
- const result = await parseArgv(params, ['https://github.com/org/my-plugin.git']);
21
- assert.equal(result['source'], 'https://github.com/org/my-plugin.git');
22
- });
23
- test('parses positional source with --scope flag', async () => {
24
- const result = await parseArgv(params, ['https://github.com/org/repo.git', '--scope', 'user']);
25
- assert.equal(result['source'], 'https://github.com/org/repo.git');
26
- assert.equal(result['scope'], 'user');
27
- });
28
- test('parses --ref flag', async () => {
29
- const result = await parseArgv(params, ['https://example.com/repo.git', '--ref', 'v1.2.3']);
30
- assert.equal(result['ref'], 'v1.2.3');
31
- });
32
- test('rejects invalid scope enum', async () => {
33
- await assert.rejects(() => parseArgv(params, ['https://example.com/repo.git', '--scope', 'all']), (err) => { assert.match(err.message, /must be one of/); return true; });
34
- });
35
- });
36
- // ---------------------------------------------------------------------------
37
- // plugin manage remove / enable / disable — positional name + optional scope
38
- // ---------------------------------------------------------------------------
39
- describe('pkg plugin manage remove/enable/disable', () => {
40
- const params = [
41
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Plugin name.' },
42
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
43
- ];
44
- test('parses positional name', async () => {
45
- const result = await parseArgv(params, ['my-plugin']);
46
- assert.equal(result['name'], 'my-plugin');
47
- });
48
- test('parses name with scope', async () => {
49
- const result = await parseArgv(params, ['my-plugin', '--scope', 'project']);
50
- assert.equal(result['name'], 'my-plugin');
51
- assert.equal(result['scope'], 'project');
52
- });
53
- test('missing name throws missing_parameter', async () => {
54
- await assert.rejects(() => parseArgv(params, ['--scope', 'user']), (err) => { assert.match(err.message, /required parameter is missing/); return true; });
55
- });
56
- });
57
- // ---------------------------------------------------------------------------
58
- // plugin manage update — optional --name flag
59
- // ---------------------------------------------------------------------------
60
- describe('pkg plugin manage update', () => {
61
- const params = [
62
- { kind: 'flag', name: 'name', type: 'string', required: false, constraint: '' },
63
- ];
64
- test('no args is valid (update-all path)', async () => {
65
- const result = await parseArgv(params, []);
66
- assert.equal(result['name'], undefined);
67
- });
68
- test('--name sets the name', async () => {
69
- const result = await parseArgv(params, ['--name', 'my-plugin']);
70
- assert.equal(result['name'], 'my-plugin');
71
- });
72
- });
73
- // ---------------------------------------------------------------------------
74
- // plugin inspect list — --include-disabled bool flag + pagination
75
- // ---------------------------------------------------------------------------
76
- describe('pkg plugin inspect list', () => {
77
- const params = [
78
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: '' },
79
- { kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: '' },
80
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: '' },
81
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: '' },
82
- ];
83
- test('no args returns defaults', async () => {
84
- const result = await parseArgv(params, []);
85
- assert.equal(result['includeDisabled'], false);
86
- assert.equal(result['limit'], 50);
87
- assert.equal(result['scope'], undefined);
88
- assert.equal(result['cursor'], undefined);
89
- });
90
- test('--include-disabled presence sets true', async () => {
91
- const result = await parseArgv(params, ['--include-disabled']);
92
- assert.equal(result['includeDisabled'], true);
93
- });
94
- test('--include-disabled camelCase key', async () => {
95
- const result = await parseArgv(params, ['--include-disabled']);
96
- assert.ok('includeDisabled' in result);
97
- assert.ok(!('include-disabled' in result));
98
- });
99
- test('--limit parsed as int', async () => {
100
- const result = await parseArgv(params, ['--limit', '25']);
101
- assert.equal(result['limit'], 25);
102
- });
103
- test('--cursor passed through', async () => {
104
- const result = await parseArgv(params, ['--cursor', 'user:some-plugin']);
105
- assert.equal(result['cursor'], 'user:some-plugin');
106
- });
107
- test('--scope all is valid', async () => {
108
- const result = await parseArgv(params, ['--scope', 'all']);
109
- assert.equal(result['scope'], 'all');
110
- });
111
- });
112
- // ---------------------------------------------------------------------------
113
- // plugin inspect show — positional name
114
- // ---------------------------------------------------------------------------
115
- describe('pkg plugin inspect show', () => {
116
- const params = [
117
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Plugin name.' },
118
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
119
- ];
120
- test('parses positional name', async () => {
121
- const result = await parseArgv(params, ['my-plugin']);
122
- assert.equal(result['name'], 'my-plugin');
123
- });
124
- test('missing name throws', async () => {
125
- await assert.rejects(() => parseArgv(params, []), (err) => { assert.match(err.message, /required parameter is missing/); return true; });
126
- });
127
- });
128
- // ---------------------------------------------------------------------------
129
- // market manage install — --marketplace + --plugin required flags
130
- // ---------------------------------------------------------------------------
131
- describe('pkg market manage install', () => {
132
- const params = [
133
- { kind: 'flag', name: 'marketplace', type: 'string', required: true, constraint: '' },
134
- { kind: 'flag', name: 'plugin', type: 'string', required: true, constraint: '' },
135
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
136
- ];
137
- test('parses --marketplace and --plugin together', async () => {
138
- const result = await parseArgv(params, ['--marketplace', 'official', '--plugin', 'my-plugin']);
139
- assert.equal(result['marketplace'], 'official');
140
- assert.equal(result['plugin'], 'my-plugin');
141
- });
142
- test('missing --marketplace throws', async () => {
143
- await assert.rejects(() => parseArgv(params, ['--plugin', 'my-plugin']), (err) => { assert.match(err.message, /required parameter is missing/); return true; });
144
- });
145
- test('missing --plugin throws', async () => {
146
- await assert.rejects(() => parseArgv(params, ['--marketplace', 'official']), (err) => { assert.match(err.message, /required parameter is missing/); return true; });
147
- });
148
- test('parses all three flags', async () => {
149
- const result = await parseArgv(params, ['--marketplace', 'official', '--plugin', 'my-plugin', '--scope', 'user']);
150
- assert.equal(result['marketplace'], 'official');
151
- assert.equal(result['plugin'], 'my-plugin');
152
- assert.equal(result['scope'], 'user');
153
- });
154
- });
155
- // ---------------------------------------------------------------------------
156
- // market manage update — optional --marketplace flag
157
- // ---------------------------------------------------------------------------
158
- describe('pkg market manage update', () => {
159
- const params = [
160
- { kind: 'flag', name: 'marketplace', type: 'string', required: false, constraint: '' },
161
- ];
162
- test('no args is valid (update-all path)', async () => {
163
- const result = await parseArgv(params, []);
164
- assert.equal(result['marketplace'], undefined);
165
- });
166
- test('--marketplace sets name', async () => {
167
- const result = await parseArgv(params, ['--marketplace', 'official']);
168
- assert.equal(result['marketplace'], 'official');
169
- });
170
- });
171
- // ---------------------------------------------------------------------------
172
- // market manage remove — positional name
173
- // ---------------------------------------------------------------------------
174
- describe('pkg market manage remove', () => {
175
- const params = [
176
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: '' },
177
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: '' },
178
- ];
179
- test('parses positional name', async () => {
180
- const result = await parseArgv(params, ['official']);
181
- assert.equal(result['name'], 'official');
182
- });
183
- });
184
- // ---------------------------------------------------------------------------
185
- // market inspect list / browse — pagination flags
186
- // ---------------------------------------------------------------------------
187
- describe('pkg market inspect list pagination', () => {
188
- const params = [
189
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: '' },
190
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: '' },
191
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: '' },
192
- ];
193
- test('default limit is 50', async () => {
194
- const result = await parseArgv(params, []);
195
- assert.equal(result['limit'], 50);
196
- });
197
- test('--limit and --cursor parsed together', async () => {
198
- const result = await parseArgv(params, ['--limit', '10', '--cursor', 'tok123']);
199
- assert.equal(result['limit'], 10);
200
- assert.equal(result['cursor'], 'tok123');
201
- });
202
- });
203
- describe('pkg market inspect browse', () => {
204
- const params = [
205
- { kind: 'flag', name: 'marketplace', type: 'string', required: false, constraint: '' },
206
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: '' },
207
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: '' },
208
- ];
209
- test('--marketplace optional', async () => {
210
- const result = await parseArgv(params, []);
211
- assert.equal(result['marketplace'], undefined);
212
- });
213
- test('--marketplace with pagination', async () => {
214
- const result = await parseArgv(params, ['--marketplace', 'official', '--limit', '20']);
215
- assert.equal(result['marketplace'], 'official');
216
- assert.equal(result['limit'], 20);
217
- });
218
- });