@paradigma-inc/flywheel 0.1.74 → 0.1.78

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.
@@ -0,0 +1,342 @@
1
+ import { CLI_VERSION } from '../version.js';
2
+ import { RUNTIME_ALIASES } from './aliases.js';
3
+ import { collectCommandMetadata, normalizeCommandMetadata, TOPIC_ORDER, } from './help-metadata.js';
4
+ const CLI_NAME = 'Flywheel CLI';
5
+ const CLI_BIN = 'flywheel';
6
+ const CLI_ABOUT = 'Inspect, organize, and operate Flywheel research graphs from the command line.';
7
+ const ROOT_FLAGS = [
8
+ {
9
+ name: 'help',
10
+ type: 'boolean',
11
+ usage: '-h --help',
12
+ description: 'Show this help.',
13
+ },
14
+ {
15
+ name: 'version',
16
+ type: 'boolean',
17
+ usage: '-v --version',
18
+ description: 'Print the Flywheel CLI version.',
19
+ },
20
+ {
21
+ name: 'usage',
22
+ type: 'boolean',
23
+ description: 'Print the public Usage/KDL command specification.',
24
+ },
25
+ {
26
+ name: 'usage-spec',
27
+ type: 'boolean',
28
+ description: 'Print the public Usage/KDL command specification.',
29
+ },
30
+ ];
31
+ const ROOT_COMMANDS = [
32
+ {
33
+ name: 'help',
34
+ summary: 'Show Flywheel CLI help.',
35
+ args: [
36
+ {
37
+ usage: '[command]',
38
+ description: 'Command name to inspect.',
39
+ },
40
+ ],
41
+ flags: [
42
+ {
43
+ name: 'aliases',
44
+ type: 'boolean',
45
+ usage: '-a --aliases',
46
+ description: 'List public command shortcuts.',
47
+ },
48
+ {
49
+ name: 'format',
50
+ type: 'string',
51
+ usage: '--format <FORMAT>',
52
+ description: 'Output help metadata as JSON.',
53
+ choices: ['json'],
54
+ },
55
+ {
56
+ name: 'schema',
57
+ type: 'boolean',
58
+ description: 'Print a minimal JSON payload schema for supported commands.',
59
+ },
60
+ ],
61
+ },
62
+ {
63
+ name: 'version',
64
+ summary: 'Print the Flywheel CLI version.',
65
+ },
66
+ ];
67
+ const RUNTIME_GLOBAL_FLAGS = [
68
+ {
69
+ name: 'format',
70
+ type: 'string',
71
+ usage: '--format <FORMAT>',
72
+ description: 'Output format for command results.',
73
+ choices: ['json', 'tsv', 'csv', 'table'],
74
+ },
75
+ {
76
+ name: 'env',
77
+ type: 'string',
78
+ usage: '--env <PROFILE>',
79
+ description: 'Use a configured CLI profile for this invocation.',
80
+ },
81
+ {
82
+ name: 'out',
83
+ type: 'string',
84
+ usage: '--out <PATH>',
85
+ description: 'Write output to a file path, or use - for stdout.',
86
+ },
87
+ {
88
+ name: 'open',
89
+ type: 'boolean',
90
+ description: 'Open browser-bound URLs when supported.',
91
+ },
92
+ {
93
+ name: 'no-retry',
94
+ type: 'boolean',
95
+ description: 'Disable transient-error retries.',
96
+ },
97
+ {
98
+ name: 'retry-max',
99
+ type: 'integer',
100
+ usage: '--retry-max <N>',
101
+ description: 'Maximum transient-error retry attempts.',
102
+ },
103
+ {
104
+ name: 'wait',
105
+ type: 'boolean',
106
+ description: 'Block on async operations until a terminal state is reached.',
107
+ },
108
+ {
109
+ name: 'wait-timeout',
110
+ type: 'integer',
111
+ usage: '--wait-timeout <SECONDS>',
112
+ description: 'Seconds to wait for --wait before timing out. Defaults to 600.',
113
+ default: '600',
114
+ },
115
+ {
116
+ name: 'allow-self',
117
+ type: 'boolean',
118
+ description: 'Allow mutating the currently active credential.',
119
+ },
120
+ {
121
+ name: 'timeout',
122
+ type: 'integer',
123
+ usage: '--timeout <SECONDS>',
124
+ description: 'Set per-request HTTP timeout in seconds.',
125
+ },
126
+ {
127
+ name: 'idempotency-key',
128
+ type: 'string',
129
+ usage: '--idempotency-key <KEY>',
130
+ description: 'Use a caller-supplied Idempotency-Key for write requests.',
131
+ },
132
+ {
133
+ name: 'force',
134
+ type: 'boolean',
135
+ description: 'Force safety-gated operations where supported.',
136
+ },
137
+ {
138
+ name: 'yes',
139
+ type: 'boolean',
140
+ description: 'Skip confirmation prompts for destructive operations.',
141
+ },
142
+ {
143
+ name: 'debug',
144
+ type: 'boolean',
145
+ description: 'Print structured request debugging with secrets masked.',
146
+ },
147
+ {
148
+ name: 'verbose',
149
+ type: 'boolean',
150
+ description: 'Print verbose progress for long-running operations.',
151
+ },
152
+ {
153
+ name: 'help',
154
+ type: 'boolean',
155
+ usage: '-h --help',
156
+ description: 'Show this help.',
157
+ },
158
+ ];
159
+ const TOPIC_RANK = new Map(TOPIC_ORDER.map((topic, index) => [topic.id, index]));
160
+ const RUNTIME_ALIASES_BY_COMMAND = new Map();
161
+ for (const [alias, command] of Object.entries(RUNTIME_ALIASES)) {
162
+ const aliases = RUNTIME_ALIASES_BY_COMMAND.get(command) ?? [];
163
+ aliases.push(alias);
164
+ RUNTIME_ALIASES_BY_COMMAND.set(command, aliases);
165
+ }
166
+ function kdlString(value) {
167
+ return JSON.stringify(value);
168
+ }
169
+ function flagUsage(param) {
170
+ if (param.usage) {
171
+ return param.usage;
172
+ }
173
+ if (param.type === 'boolean') {
174
+ return `--${param.name}`;
175
+ }
176
+ return `--${param.name} <${param.type}>`;
177
+ }
178
+ function renderFlag(param, required, indent = ' ') {
179
+ const attrs = [`help=${kdlString(param.description)}`];
180
+ if (required) {
181
+ attrs.push('required=#true');
182
+ }
183
+ if (param.default) {
184
+ attrs.push(`default=${kdlString(param.default)}`);
185
+ }
186
+ if (!param.choices) {
187
+ return [`${indent}flag ${kdlString(flagUsage(param))} ${attrs.join(' ')}`];
188
+ }
189
+ return [
190
+ `${indent}flag ${kdlString(flagUsage(param))} ${attrs.join(' ')} {`,
191
+ `${indent} choices ${param.choices.map(kdlString).join(' ')}`,
192
+ `${indent}}`,
193
+ ];
194
+ }
195
+ function renderRootArg(arg, indent = ' ') {
196
+ const attrs = [`help=${kdlString(arg.description)}`];
197
+ if (!arg.choices) {
198
+ return [`${indent}arg ${kdlString(arg.usage)} ${attrs.join(' ')}`];
199
+ }
200
+ return [
201
+ `${indent}arg ${kdlString(arg.usage)} ${attrs.join(' ')} {`,
202
+ `${indent} choices ${arg.choices.map(kdlString).join(' ')}`,
203
+ `${indent}}`,
204
+ ];
205
+ }
206
+ function renderRootCommand(command) {
207
+ const args = command.args ?? [];
208
+ const flags = command.flags ?? [];
209
+ if (args.length === 0 && flags.length === 0) {
210
+ return [`cmd ${kdlString(command.name)} help=${kdlString(command.summary)}`];
211
+ }
212
+ const lines = [`cmd ${kdlString(command.name)} help=${kdlString(command.summary)} {`];
213
+ for (const arg of args) {
214
+ lines.push(...renderRootArg(arg));
215
+ }
216
+ for (const flag of flags) {
217
+ lines.push(...renderFlag(flag, false));
218
+ }
219
+ lines.push('}');
220
+ return lines;
221
+ }
222
+ function helpTargetChoices(commands) {
223
+ const choices = [];
224
+ const seen = new Set();
225
+ const pushChoice = (choice) => {
226
+ if (seen.has(choice))
227
+ return;
228
+ seen.add(choice);
229
+ choices.push(choice);
230
+ };
231
+ for (const command of commands) {
232
+ pushChoice(command.name);
233
+ for (const alias of RUNTIME_ALIASES_BY_COMMAND.get(command.name) ?? []) {
234
+ pushChoice(alias);
235
+ }
236
+ }
237
+ return choices;
238
+ }
239
+ function rootCommandsWithHelpTargetChoices(commands) {
240
+ const choices = helpTargetChoices(commands);
241
+ return ROOT_COMMANDS.map((command) => {
242
+ if (command.name !== 'help')
243
+ return command;
244
+ return {
245
+ ...command,
246
+ args: command.args?.map((arg) => arg.usage === '[command]' ? { ...arg, choices } : arg),
247
+ };
248
+ });
249
+ }
250
+ function renderArg(param, indent = ' ') {
251
+ const attrs = [`help=${kdlString(param.description)}`];
252
+ if (param.default) {
253
+ attrs.push(`default=${kdlString(param.default)}`);
254
+ }
255
+ if (!param.choices) {
256
+ return [`${indent}arg ${kdlString(param.name)} ${attrs.join(' ')}`];
257
+ }
258
+ return [
259
+ `${indent}arg ${kdlString(param.name)} ${attrs.join(' ')} {`,
260
+ `${indent} choices ${param.choices.map(kdlString).join(' ')}`,
261
+ `${indent}}`,
262
+ ];
263
+ }
264
+ function renderCommand(metadata, options) {
265
+ const command = normalizeCommandMetadata(metadata);
266
+ const lines = [`cmd ${kdlString(command.name)} help=${kdlString(command.summary)} {`];
267
+ for (const alias of options.aliases) {
268
+ lines.push(` alias ${kdlString(alias)}`);
269
+ }
270
+ for (const arg of command.args) {
271
+ lines.push(...renderArg(arg));
272
+ }
273
+ for (const param of command.required) {
274
+ lines.push(...renderFlag(param, true));
275
+ }
276
+ for (const param of command.optional) {
277
+ lines.push(...renderFlag(param, false));
278
+ }
279
+ if (options.runtimeGlobals) {
280
+ for (const flag of RUNTIME_GLOBAL_FLAGS) {
281
+ lines.push(...renderFlag(flag, false));
282
+ }
283
+ }
284
+ for (const example of command.examples) {
285
+ lines.push(` example ${kdlString(example.invocation)} help=${kdlString(example.description)}`);
286
+ }
287
+ lines.push('}');
288
+ return lines;
289
+ }
290
+ function sortCommands(commands) {
291
+ return [...commands].sort((a, b) => {
292
+ const topicCmp = (TOPIC_RANK.get(a.group) ?? Number.MAX_SAFE_INTEGER) -
293
+ (TOPIC_RANK.get(b.group) ?? Number.MAX_SAFE_INTEGER);
294
+ if (topicCmp !== 0)
295
+ return topicCmp;
296
+ return a.name.localeCompare(b.name);
297
+ });
298
+ }
299
+ export function renderUsageSpec(extrasOrOptions = []) {
300
+ let extras;
301
+ let version;
302
+ if (Array.isArray(extrasOrOptions)) {
303
+ extras = extrasOrOptions;
304
+ version = CLI_VERSION;
305
+ }
306
+ else {
307
+ const options = extrasOrOptions;
308
+ extras = options.extras ?? [];
309
+ version = options.version ?? CLI_VERSION;
310
+ }
311
+ const runtimeCommandNames = new Set(collectCommandMetadata({
312
+ internal: false,
313
+ adminDiscovery: false,
314
+ extras: [],
315
+ }).map((command) => command.name));
316
+ const commands = sortCommands(collectCommandMetadata({
317
+ internal: false,
318
+ adminDiscovery: false,
319
+ extras,
320
+ }));
321
+ const lines = [
322
+ `name ${kdlString(CLI_NAME)}`,
323
+ `bin ${kdlString(CLI_BIN)}`,
324
+ `about ${kdlString(CLI_ABOUT)}`,
325
+ `version ${kdlString(version)}`,
326
+ ];
327
+ for (const flag of ROOT_FLAGS) {
328
+ lines.push(...renderFlag(flag, false, ''));
329
+ }
330
+ lines.push('');
331
+ for (const command of rootCommandsWithHelpTargetChoices(commands)) {
332
+ lines.push(...renderRootCommand(command), '');
333
+ }
334
+ for (const command of commands) {
335
+ lines.push(...renderCommand(command, {
336
+ runtimeGlobals: runtimeCommandNames.has(command.name),
337
+ aliases: RUNTIME_ALIASES_BY_COMMAND.get(command.name) ?? [],
338
+ }), '');
339
+ }
340
+ return `${lines.join('\n').trimEnd()}\n`;
341
+ }
342
+ //# sourceMappingURL=usage-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-spec.js","sourceRoot":"","sources":["../../src/commands/usage-spec.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { loadProfile } from './auth/profile.js';
11
11
  import { RUNTIME_ALIASES } from './commands/aliases.js';
12
12
  import { BUILTIN_PROFILE_NAMES, isBuiltinProfileName, resolveBuiltinBaseUrl, } from './auth/profiles.js';
13
13
  import { renderCommandHelp, renderCommandHelpAsJson, renderHelp, renderHelpAsJson, } from './commands/help.js';
14
+ import { renderUsageSpec } from './commands/usage-spec.js';
14
15
  import { getCommandByName } from './commands/registry.js';
15
16
  import { MVP_COMMAND_HANDLERS } from './commands/index.js';
16
17
  import { CliApprovalPendingError, CliAuthRequirementError, CliFinalizeFailedError, CliUsageError, CliWaitTimeoutError, } from './errors.js';
@@ -142,8 +143,11 @@ async function resolveRuntimeAuthConfig(config, profile, resolveEnvApiKey) {
142
143
  };
143
144
  }
144
145
  const HELP_TOKENS = new Set(['--help', '-h']);
146
+ const USAGE_TOKENS = new Set(['--usage', '--usage-spec']);
145
147
  const SCHEMA_TOKEN = '--schema';
146
148
  const HELP_EXTRAS_PREFIX = '--_help_extras=';
149
+ const USAGE_EXTRAS_PREFIX = '--_usage_extras=';
150
+ const USAGE_VERSION_PREFIX = '--_usage_version=';
147
151
  const VALID_TOPIC_IDS = new Set([
148
152
  'setup-admin',
149
153
  'auth',
@@ -202,6 +206,80 @@ function parseHelpExtras(argv) {
202
206
  function stripHelpExtras(argv) {
203
207
  return argv.filter((t) => !t.startsWith(HELP_EXTRAS_PREFIX));
204
208
  }
209
+ function isStringArray(value) {
210
+ return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
211
+ }
212
+ function isCommandParamArray(value) {
213
+ return (Array.isArray(value) &&
214
+ value.every((entry) => {
215
+ if (!entry || typeof entry !== 'object')
216
+ return false;
217
+ const candidate = entry;
218
+ return (typeof candidate.name === 'string' &&
219
+ ['string', 'integer', 'json', 'boolean'].includes(String(candidate.type)) &&
220
+ typeof candidate.description === 'string' &&
221
+ (candidate.default === undefined || typeof candidate.default === 'string'));
222
+ }));
223
+ }
224
+ function isCommandExampleArray(value) {
225
+ return (Array.isArray(value) &&
226
+ value.every((entry) => {
227
+ if (!entry || typeof entry !== 'object')
228
+ return false;
229
+ const candidate = entry;
230
+ return (typeof candidate.description === 'string' &&
231
+ typeof candidate.invocation === 'string');
232
+ }));
233
+ }
234
+ function isUsageExtra(value) {
235
+ if (!value || typeof value !== 'object')
236
+ return false;
237
+ const candidate = value;
238
+ return (typeof candidate.name === 'string' &&
239
+ typeof candidate.group === 'string' &&
240
+ VALID_TOPIC_IDS.has(candidate.group) &&
241
+ typeof candidate.summary === 'string' &&
242
+ (candidate.endpoints === undefined || isStringArray(candidate.endpoints)) &&
243
+ (candidate.required === undefined || isCommandParamArray(candidate.required)) &&
244
+ (candidate.optional === undefined || isCommandParamArray(candidate.optional)) &&
245
+ (candidate.examples === undefined || isCommandExampleArray(candidate.examples)) &&
246
+ (candidate.related === undefined || isStringArray(candidate.related)) &&
247
+ (candidate.schema === undefined || typeof candidate.schema === 'string') &&
248
+ (candidate.hidden === undefined || typeof candidate.hidden === 'boolean'));
249
+ }
250
+ function parseUsageExtras(argv) {
251
+ const rawValues = argv
252
+ .filter((token) => token.startsWith(USAGE_EXTRAS_PREFIX))
253
+ .map((token) => token.slice(USAGE_EXTRAS_PREFIX.length));
254
+ const rawVersionValues = argv
255
+ .filter((token) => token.startsWith(USAGE_VERSION_PREFIX))
256
+ .map((token) => token.slice(USAGE_VERSION_PREFIX.length));
257
+ if (rawValues.length === 0 && rawVersionValues.length === 0) {
258
+ return { kind: 'ok', extras: [] };
259
+ }
260
+ if (rawValues.length > 1)
261
+ return { kind: 'invalid' };
262
+ if (rawVersionValues.length > 1)
263
+ return { kind: 'invalid' };
264
+ const version = rawVersionValues[0];
265
+ if (version !== undefined && version.trim() === '')
266
+ return { kind: 'invalid' };
267
+ let extras = [];
268
+ if (rawValues.length === 1) {
269
+ let decoded;
270
+ try {
271
+ decoded = JSON.parse(rawValues[0]);
272
+ }
273
+ catch {
274
+ return { kind: 'invalid' };
275
+ }
276
+ if (!Array.isArray(decoded) || !decoded.every(isUsageExtra)) {
277
+ return { kind: 'invalid' };
278
+ }
279
+ extras = decoded;
280
+ }
281
+ return { kind: 'ok', extras, version };
282
+ }
205
283
  // Commands that do not touch the HTTP runtime and therefore must run even
206
284
  // when ~/.config/flywheel-cli/config.json is absent. These are purely local
207
285
  // state operations (profile bookkeeping, keychain reads/writes) plus the
@@ -300,6 +378,28 @@ function stripFormatTokens(argv) {
300
378
  }
301
379
  return out;
302
380
  }
381
+ function normalizeCommandHelpArgs(argv) {
382
+ let schema = false;
383
+ let aliases = false;
384
+ const commandArgs = [];
385
+ for (const token of argv) {
386
+ if (token === SCHEMA_TOKEN) {
387
+ schema = true;
388
+ continue;
389
+ }
390
+ if (token === '--aliases' || token === '-a') {
391
+ aliases = true;
392
+ continue;
393
+ }
394
+ commandArgs.push(token);
395
+ }
396
+ return { commandArgs, schema, aliases };
397
+ }
398
+ function renderAliasesHelp() {
399
+ return `${Object.entries(RUNTIME_ALIASES)
400
+ .map(([aliasCommand, canonicalCommand]) => ` ${aliasCommand} → ${canonicalCommand}`)
401
+ .join('\n')}\n`;
402
+ }
303
403
  function emitCommandHelp(stdout, stderr, commandName, schema, asJson) {
304
404
  if (asJson) {
305
405
  const payload = renderCommandHelpAsJson(commandName);
@@ -466,6 +566,26 @@ export async function runCli(argv, dependencies = {}) {
466
566
  }
467
567
  argv = rewriteAlias(argv);
468
568
  const [first, ...rest] = argv;
569
+ if (USAGE_TOKENS.has(first)) {
570
+ const extrasParsed = parseUsageExtras(argv);
571
+ if (extrasParsed.kind === 'invalid') {
572
+ writeLine(stderr, 'invalid --_usage_extras payload');
573
+ return EXIT_USAGE;
574
+ }
575
+ stdout(renderUsageSpec({
576
+ extras: extrasParsed.extras,
577
+ version: extrasParsed.version,
578
+ }));
579
+ return 0;
580
+ }
581
+ const usagePrivateFlag = argv.find((token) => token.startsWith(USAGE_EXTRAS_PREFIX) ||
582
+ token.startsWith(USAGE_VERSION_PREFIX));
583
+ if (usagePrivateFlag !== undefined) {
584
+ writeLine(stderr, usagePrivateFlag.startsWith(USAGE_VERSION_PREFIX)
585
+ ? 'unknown flag: --_usage_version'
586
+ : 'unknown flag: --_usage_extras');
587
+ return EXIT_USAGE;
588
+ }
469
589
  // Help-format validation intentionally runs only inside the help branches
470
590
  // below. Non-help commands let `parseCliArgs` validate --format against the
471
591
  // full json|tsv|csv|table set; validating here would reject legitimate
@@ -504,12 +624,20 @@ export async function runCli(argv, dependencies = {}) {
504
624
  return resolved;
505
625
  // Strip --format and --_help_extras tokens so the positional <command>
506
626
  // lookup isn't fooled by them occupying rest[0].
507
- const helpArgs = stripHelpExtras(stripFormatTokens(rest));
627
+ const { commandArgs: helpArgs, schema, aliases } = normalizeCommandHelpArgs(stripHelpExtras(stripFormatTokens(rest)));
508
628
  const extrasParsed = parseHelpExtras(argv);
509
629
  if (extrasParsed.kind === 'invalid') {
510
630
  writeLine(stderr, 'invalid --_help_extras payload');
511
631
  return EXIT_USAGE;
512
632
  }
633
+ if (schema && helpArgs.length === 0) {
634
+ writeLine(stderr, '--schema requires a command name');
635
+ return EXIT_USAGE;
636
+ }
637
+ if (aliases) {
638
+ stdout(renderAliasesHelp());
639
+ return 0;
640
+ }
513
641
  if (helpArgs.length === 0) {
514
642
  const extras = extrasParsed.kind === 'ok' ? extrasParsed.extras : [];
515
643
  stdout(resolved.json ? renderHelpAsJson(extras) : renderHelp(extras));
@@ -527,7 +655,6 @@ export async function runCli(argv, dependencies = {}) {
527
655
  const commandName = Object.prototype.hasOwnProperty.call(RUNTIME_ALIASES, rawCommandName)
528
656
  ? RUNTIME_ALIASES[rawCommandName]
529
657
  : rawCommandName;
530
- const schema = helpArgs.slice(1).includes(SCHEMA_TOKEN);
531
658
  return emitCommandHelp(stdout, stderr, commandName, schema, resolved.json);
532
659
  }
533
660
  // --_help_extras is reserved for top-level help dispatch only. Reject it