@vodmal/vdx-cli 0.15.0 → 0.16.0

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 CHANGED
@@ -49,6 +49,7 @@ vdx doctor [--format=ansi|markdown|json]
49
49
 
50
50
  # Start your agent in a project per your profile (~/.vdx-environment.yaml or $VDX_ENVIRONMENT)
51
51
  vdx ai[@host] [project-path] [--new] [--restart] [--detach] [--dry-run] # default: cwd; @host: over ssh, in tmux there
52
+ vdx ai --help # flags, where launch flags live, exit codes
52
53
 
53
54
  # Print the installed version
54
55
  vdx --version
@@ -87,6 +88,8 @@ name. `vdx ai@<host>` runs the same command on `<host>` over ssh — that machin
87
88
  profile and tmux, the path taken under its home directory; `--detach` only
88
89
  starts it. The machine's own label (`$VDX_HOST`) runs here. Where git knows no
89
90
  commit author, `vdx ai` proposes one (Enter writes it into `.git/config`).
91
+ `vdx ai --help` (`-h`) prints the help; an unknown option or a second path is
92
+ refused with exit 2, and nothing starts.
90
93
 
91
94
  By default the bundled `rubric/vdx-rubric.yaml` is used (a mirror of canonical
92
95
  [vdx-rubric-vodmal](https://github.com/VoDmAl/vdx-rubric-vodmal) at the time of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vodmal/vdx-cli",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "vdx — unified lifecycle interface (up/down/build/test/check/fix) + versioned maturity audit with drift detection. Pairs with the vdx Claude Code plugin.",
5
5
  "keywords": [
6
6
  "vdx",
package/src/index.ts CHANGED
@@ -42,12 +42,46 @@ function usage(): never {
42
42
  vdx publish <patch|minor|major> [--dry-run] [--force]
43
43
  vdx doctor [--format=ansi|markdown|json] [--json]
44
44
  vdx ai[@host] [project_path] [--new] [--restart] [--detach] [--dry-run] (default: cwd; @host: over ssh, in tmux there)
45
+ vdx ai --help (launch flags, profile, exit codes)
45
46
  vdx --version
46
47
  `,
47
48
  );
48
49
  process.exit(1);
49
50
  }
50
51
 
52
+ const AI_USAGE_LINE = 'Usage: vdx ai[@host] [project_path] [--new] [--restart] [--detach] [--dry-run]';
53
+
54
+ const AI_HELP = `${AI_USAGE_LINE}
55
+
56
+ Starts your agent in the project, or attaches to the one already running there.
57
+ Which agent, its flags and whether it runs in tmux come from your profile:
58
+ $VDX_ENVIRONMENT, else ~/.vdx-environment.yaml, else a plain claude/codex.
59
+
60
+ Launch flags live in the profile, not in a command to type: agent.args for
61
+ every project, agent.when[] for a class of projects (a rubric predicate over
62
+ the project's files). Hand a person \`vdx ai\`, not \`<agent> --<flag>\`.
63
+
64
+ project_path the project (default: cwd); its git toplevel is used
65
+ @host the same command on <host> over ssh: its vdx, profile and tmux
66
+ --new a new conversation instead of continuing the last one
67
+ --restart restart the running agent in its pane — applies a changed profile
68
+ --detach start without attaching; print the command that attaches
69
+ --dry-run print the plan and the project's running agents; start nothing
70
+ -h, --help this help
71
+
72
+ Exit codes: 0 the agent runs per the profile; 2 profile or usage error;
73
+ 3 the running agent lacks profile flags (rerun with --restart); 4 the start
74
+ was not confirmed.
75
+ Profile format: https://github.com/VoDmAl/vdx/blob/main/docs/specs/environment-format.md
76
+ `;
77
+
78
+ const AI_FLAGS = ['new', 'restart', 'resume', 'detach', 'dry-run', 'help'];
79
+
80
+ function aiUsageError(message: string): never {
81
+ process.stderr.write(`vdx ai: ${message}\n${AI_USAGE_LINE}\nMore: vdx ai --help\n`);
82
+ process.exit(2);
83
+ }
84
+
51
85
  interface ParsedArgs {
52
86
  cmd: string;
53
87
  positionals: string[];
@@ -264,7 +298,7 @@ function cmdDoctor(opts: ParsedArgs): void {
264
298
 
265
299
  function cmdAi(opts: ParsedArgs): void {
266
300
  // parseArgs hands the token after a bare flag to that flag as its value;
267
- // these flags take none, so such a token is the project path.
301
+ // these flags take none, so such a token is the project path (or `-h`).
268
302
  const positionals = [...opts.positionals];
269
303
  const bool = (name: string): boolean => {
270
304
  const v = opts.flags[name];
@@ -278,6 +312,18 @@ function cmdAi(opts: ParsedArgs): void {
278
312
  bool('resume');
279
313
  const detach = bool('detach');
280
314
  const dryRun = bool('dry-run');
315
+ // `vdx ai` starts an agent, so a misread argument must not run it: an agent
316
+ // that tried `vdx ai --help` got a launch in the current directory.
317
+ if (bool('help') || positionals.includes('-h')) {
318
+ process.stdout.write(AI_HELP);
319
+ process.exit(0);
320
+ }
321
+ const unknown = [
322
+ ...Object.keys(opts.flags).filter((f) => !AI_FLAGS.includes(f)).map((f) => `--${f}`),
323
+ ...positionals.filter((p) => p.startsWith('-')),
324
+ ];
325
+ if (unknown.length > 0) aiUsageError(`unknown option ${unknown.join(', ')}`);
326
+ if (positionals.length > 1) aiUsageError(`unexpected argument ${positionals.slice(1).join(' ')}`);
281
327
  const options = { path: positionals[0] ?? '.', restart, fresh, detach, dryRun };
282
328
  // `ai@m3`: the same command on another machine. Its own label runs here.
283
329
  const host = opts.cmd.startsWith('ai@') ? opts.cmd.slice(3) : null;