agentxchain 2.10.0 → 2.12.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
@@ -25,7 +25,7 @@ npm install -g agentxchain
25
25
  Or run without installing:
26
26
 
27
27
  ```bash
28
- npx agentxchain init --governed -y
28
+ npx agentxchain init --governed --dir my-agentxchain-project -y
29
29
  ```
30
30
 
31
31
  ## Testing
@@ -49,7 +49,7 @@ Duplicate execution remains intentional for the current 36-file slice until a la
49
49
  ### Governed workflow
50
50
 
51
51
  ```bash
52
- npx agentxchain init --governed -y
52
+ npx agentxchain init --governed --dir my-agentxchain-project -y
53
53
  cd my-agentxchain-project
54
54
  git init
55
55
  git add -A
@@ -58,10 +58,16 @@ agentxchain status
58
58
  agentxchain step --role pm
59
59
  ```
60
60
 
61
+ The default governed dev runtime is `claude --print` with stdin prompt delivery. If your local coding agent uses a different launch contract, set it during scaffold creation:
62
+
63
+ ```bash
64
+ npx agentxchain init --governed --dir my-agentxchain-project --dev-command ./scripts/dev-agent.sh --dev-prompt-transport dispatch_bundle_only -y
65
+ ```
66
+
61
67
  If you want template-specific planning artifacts from day one:
62
68
 
63
69
  ```bash
64
- npx agentxchain init --governed --template api-service -y
70
+ npx agentxchain init --governed --template api-service --dir my-agentxchain-project -y
65
71
  ```
66
72
 
67
73
  Built-in governed templates:
@@ -83,7 +89,7 @@ agentxchain step --role qa
83
89
  agentxchain approve-completion
84
90
  ```
85
91
 
86
- Default governed scaffolding configures QA as `api_proxy` with `ANTHROPIC_API_KEY`. For a provider-free walkthrough, switch the QA runtime to `manual` before the QA step.
92
+ Default governed scaffolding configures QA as `api_proxy` with `ANTHROPIC_API_KEY`. For a provider-free walkthrough, switch the QA runtime to `manual` before the QA step. If you override the dev runtime, either include `{prompt}` for argv delivery or set `--dev-prompt-transport` explicitly.
87
93
 
88
94
  ### Migrate a legacy project
89
95
 
@@ -99,7 +105,7 @@ agentxchain step
99
105
 
100
106
  | Command | What it does |
101
107
  |---|---|
102
- | `init --governed [--template <id>]` | Create a governed project, optionally with project-shape-specific planning artifacts |
108
+ | `init --governed [--dir <path>] [--template <id>]` | Create a governed project, optionally in-place or in an explicit target directory, with project-shape-specific planning artifacts |
103
109
  | `migrate` | Convert a legacy v3 project to governed format |
104
110
  | `status` | Show current run, template, phase, turn, and approval state |
105
111
  | `resume` | Initialize or continue a governed run and assign the next turn |
@@ -109,6 +115,7 @@ agentxchain step
109
115
  | `approve-transition` | Approve a pending human-gated phase transition |
110
116
  | `approve-completion` | Approve a pending human-gated run completion |
111
117
  | `validate` | Validate governed kickoff wiring, a staged turn, or both |
118
+ | `template validate` | Prove the template registry, workflow-kit scaffold contract, and planning artifact completeness (`--json` exposes a `workflow_kit` block) |
112
119
  | `verify protocol` | Run the shipped protocol conformance suite against a target implementation |
113
120
  | `dashboard` | Open the local governance dashboard in your browser for repo-local runs or multi-repo coordinator initiatives, including pending gate approvals |
114
121
  | `plugin install|list|remove` | Install, inspect, or remove governed hook plugins backed by `agentxchain-plugin.json` manifests |
@@ -69,6 +69,7 @@ import { escalateCommand } from '../src/commands/escalate.js';
69
69
  import { acceptTurnCommand } from '../src/commands/accept-turn.js';
70
70
  import { rejectTurnCommand } from '../src/commands/reject-turn.js';
71
71
  import { stepCommand } from '../src/commands/step.js';
72
+ import { runCommand } from '../src/commands/run.js';
72
73
  import { approveTransitionCommand } from '../src/commands/approve-transition.js';
73
74
  import { approveCompletionCommand } from '../src/commands/approve-completion.js';
74
75
  import { dashboardCommand } from '../src/commands/dashboard.js';
@@ -114,7 +115,10 @@ program
114
115
  .description('Create a new AgentXchain project folder')
115
116
  .option('-y, --yes', 'Skip prompts, use defaults')
116
117
  .option('--governed', 'Create a governed project (orchestrator-owned state)')
118
+ .option('--dir <path>', 'Scaffold target directory. Use "." for in-place bootstrap.')
117
119
  .option('--template <id>', 'Governed scaffold template: generic, api-service, cli-tool, library, web-app')
120
+ .option('--dev-command <parts...>', 'Governed local-dev command parts. Include {prompt} for argv prompt delivery.')
121
+ .option('--dev-prompt-transport <mode>', 'Governed local-dev prompt transport: argv, stdin, dispatch_bundle_only')
118
122
  .option('--schema-version <version>', 'Schema version (3 for legacy, or use --governed for current)')
119
123
  .action(initCommand);
120
124
 
@@ -245,6 +249,9 @@ verifyCmd
245
249
  .option('--tier <tier>', 'Conformance tier to verify (1, 2, or 3)', '1')
246
250
  .option('--surface <surface>', 'Restrict verification to a single surface')
247
251
  .option('--target <path>', 'Target root containing .agentxchain-conformance/capabilities.json', '.')
252
+ .option('--remote <url>', 'Remote HTTP conformance endpoint base URL')
253
+ .option('--token <token>', 'Bearer token for remote HTTP conformance endpoint')
254
+ .option('--timeout <ms>', 'Per-fixture remote HTTP timeout in milliseconds', '30000')
248
255
  .option('--format <format>', 'Output format: text or json', 'text')
249
256
  .action(verifyProtocolCommand);
250
257
 
@@ -304,6 +311,16 @@ program
304
311
  .option('--auto-reject', 'Auto-reject and retry on validation failure')
305
312
  .action(stepCommand);
306
313
 
314
+ program
315
+ .command('run')
316
+ .description('Drive a governed run to completion: multi-turn execution with gate prompting')
317
+ .option('--role <role>', 'Override the initial role (default: config-driven selection)')
318
+ .option('--max-turns <n>', 'Maximum turns before stopping (default: 50)', parseInt)
319
+ .option('--auto-approve', 'Auto-approve all gates (non-interactive mode)')
320
+ .option('--verbose', 'Stream adapter subprocess output')
321
+ .option('--dry-run', 'Print what would be dispatched without executing')
322
+ .action(runCommand);
323
+
307
324
  program
308
325
  .command('approve-transition')
309
326
  .description('Approve a pending phase transition that requires human sign-off')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxchain",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,6 +20,7 @@
20
20
  "test:node": "node --test test/*.test.js",
21
21
  "preflight:release": "bash scripts/release-preflight.sh",
22
22
  "preflight:release:strict": "bash scripts/release-preflight.sh --strict",
23
+ "postflight:release": "bash scripts/release-postflight.sh",
23
24
  "build:macos": "bun build bin/agentxchain.js --compile --target=bun-darwin-arm64 --outfile=dist/agentxchain-macos-arm64",
24
25
  "build:linux": "bun build bin/agentxchain.js --compile --target=bun-linux-x64 --outfile=dist/agentxchain-linux-x64",
25
26
  "publish:npm": "bash scripts/publish-npm.sh"
@@ -1,11 +1,12 @@
1
1
  import { writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
2
- import { join, resolve, dirname } from 'path';
2
+ import { basename, join, relative, resolve, dirname } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import chalk from 'chalk';
5
5
  import inquirer from 'inquirer';
6
6
  import { CONFIG_FILE, LOCK_FILE, STATE_FILE } from '../lib/config.js';
7
7
  import { generateVSCodeFiles } from '../lib/generate-vscode.js';
8
8
  import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS } from '../lib/governed-templates.js';
9
+ import { VALID_PROMPT_TRANSPORTS } from '../lib/normalized-config.js';
9
10
 
10
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
12
  const TEMPLATES_DIR = join(__dirname, '../templates');
@@ -93,9 +94,16 @@ const GOVERNED_ROLES = {
93
94
  }
94
95
  };
95
96
 
97
+ const DEFAULT_GOVERNED_LOCAL_DEV_RUNTIME = Object.freeze({
98
+ type: 'local_cli',
99
+ command: ['claude', '--print'],
100
+ cwd: '.',
101
+ prompt_transport: 'stdin',
102
+ });
103
+
96
104
  const GOVERNED_RUNTIMES = {
97
105
  'manual-pm': { type: 'manual' },
98
- 'local-dev': { type: 'local_cli', command: ['claude', '--print', '-p', '{prompt}'], cwd: '.', prompt_transport: 'argv' },
106
+ 'local-dev': DEFAULT_GOVERNED_LOCAL_DEV_RUNTIME,
99
107
  'api-qa': { type: 'api_proxy', provider: 'anthropic', model: 'claude-sonnet-4-6', auth_env: 'ANTHROPIC_API_KEY' },
100
108
  'manual-director': { type: 'manual' }
101
109
  };
@@ -353,8 +361,92 @@ ${role.write_authority === 'authoritative'
353
361
  `;
354
362
  }
355
363
 
356
- export function scaffoldGoverned(dir, projectName, projectId, templateId = 'generic') {
364
+ function commandHasPromptPlaceholder(parts = []) {
365
+ return parts.some((part) => typeof part === 'string' && part.includes('{prompt}'));
366
+ }
367
+
368
+ function resolveGovernedLocalDevRuntime(opts = {}) {
369
+ const customCommand = Array.isArray(opts.devCommand)
370
+ ? opts.devCommand.map((part) => String(part).trim()).filter(Boolean)
371
+ : null;
372
+ const explicitTransport = typeof opts.devPromptTransport === 'string' && opts.devPromptTransport.trim()
373
+ ? opts.devPromptTransport.trim()
374
+ : null;
375
+
376
+ if (explicitTransport && !VALID_PROMPT_TRANSPORTS.includes(explicitTransport)) {
377
+ throw new Error(`Unknown --dev-prompt-transport "${explicitTransport}". Valid values: ${VALID_PROMPT_TRANSPORTS.join(', ')}`);
378
+ }
379
+
380
+ if (!customCommand?.length) {
381
+ const command = [...DEFAULT_GOVERNED_LOCAL_DEV_RUNTIME.command];
382
+ if (explicitTransport === 'argv') {
383
+ throw new Error('Default local dev command does not include {prompt}. Use --dev-command ... {prompt} for argv mode.');
384
+ }
385
+ return {
386
+ runtime: {
387
+ ...DEFAULT_GOVERNED_LOCAL_DEV_RUNTIME,
388
+ command,
389
+ prompt_transport: explicitTransport || DEFAULT_GOVERNED_LOCAL_DEV_RUNTIME.prompt_transport,
390
+ },
391
+ };
392
+ }
393
+
394
+ const hasPlaceholder = commandHasPromptPlaceholder(customCommand);
395
+
396
+ if (!explicitTransport && !hasPlaceholder) {
397
+ throw new Error('Custom --dev-command must either include {prompt} or set --dev-prompt-transport explicitly.');
398
+ }
399
+
400
+ if (explicitTransport === 'argv' && !hasPlaceholder) {
401
+ throw new Error('--dev-prompt-transport argv requires {prompt} in --dev-command.');
402
+ }
403
+
404
+ if (explicitTransport && explicitTransport !== 'argv' && hasPlaceholder) {
405
+ throw new Error(`--dev-prompt-transport ${explicitTransport} must not be combined with {prompt} in --dev-command.`);
406
+ }
407
+
408
+ return {
409
+ runtime: {
410
+ type: 'local_cli',
411
+ command: customCommand,
412
+ cwd: '.',
413
+ prompt_transport: explicitTransport || 'argv',
414
+ },
415
+ };
416
+ }
417
+
418
+ function formatGovernedRuntimeCommand(runtime) {
419
+ return Array.isArray(runtime?.command) ? runtime.command.join(' ') : String(runtime?.command || '');
420
+ }
421
+
422
+ function resolveInitDirOption(dirOption) {
423
+ if (dirOption == null) return null;
424
+ const value = String(dirOption).trim();
425
+ if (!value) {
426
+ throw new Error('--dir must not be empty.');
427
+ }
428
+ return value;
429
+ }
430
+
431
+ function inferProjectNameFromTarget(targetPath, fallbackName) {
432
+ const inferred = basename(resolve(process.cwd(), targetPath));
433
+ return inferred && inferred.trim() ? inferred : fallbackName;
434
+ }
435
+
436
+ function formatInitTarget(dir) {
437
+ const rel = relative(process.cwd(), dir);
438
+ if (!rel) return '.';
439
+ if (!rel.startsWith('..')) return rel;
440
+ return dir;
441
+ }
442
+
443
+ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'generic', runtimeOptions = {}) {
357
444
  const template = loadGovernedTemplate(templateId);
445
+ const { runtime: localDevRuntime } = resolveGovernedLocalDevRuntime(runtimeOptions);
446
+ const runtimes = {
447
+ ...GOVERNED_RUNTIMES,
448
+ 'local-dev': localDevRuntime,
449
+ };
358
450
  const config = {
359
451
  schema_version: '1.0',
360
452
  template: template.id,
@@ -364,7 +456,7 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
364
456
  default_branch: 'main'
365
457
  },
366
458
  roles: GOVERNED_ROLES,
367
- runtimes: GOVERNED_RUNTIMES,
459
+ runtimes,
368
460
  routing: GOVERNED_ROUTING,
369
461
  gates: GOVERNED_GATES,
370
462
  budget: {
@@ -475,6 +567,14 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
475
567
  async function initGoverned(opts) {
476
568
  let projectName, folderName;
477
569
  const templateId = opts.template || 'generic';
570
+ let explicitDir;
571
+
572
+ try {
573
+ explicitDir = resolveInitDirOption(opts.dir);
574
+ } catch (err) {
575
+ console.error(chalk.red(` Error: ${err.message}`));
576
+ process.exit(1);
577
+ }
478
578
 
479
579
  if (!VALID_GOVERNED_TEMPLATE_IDS.includes(templateId)) {
480
580
  console.error(chalk.red(` Error: Unknown template "${templateId}".`));
@@ -489,29 +589,44 @@ async function initGoverned(opts) {
489
589
  }
490
590
 
491
591
  if (opts.yes) {
492
- projectName = 'My AgentXchain Project';
493
- folderName = slugify(projectName);
592
+ projectName = explicitDir
593
+ ? inferProjectNameFromTarget(explicitDir, 'My AgentXchain Project')
594
+ : 'My AgentXchain Project';
595
+ folderName = explicitDir || slugify(projectName);
494
596
  } else {
495
597
  const { name } = await inquirer.prompt([{
496
598
  type: 'input',
497
599
  name: 'name',
498
600
  message: 'Project name:',
499
- default: 'My AgentXchain Project'
601
+ default: explicitDir
602
+ ? inferProjectNameFromTarget(explicitDir, 'My AgentXchain Project')
603
+ : 'My AgentXchain Project'
500
604
  }]);
501
605
  projectName = name;
502
- folderName = slugify(projectName);
606
+ folderName = explicitDir || slugify(projectName);
503
607
 
504
- const { folder } = await inquirer.prompt([{
505
- type: 'input',
506
- name: 'folder',
507
- message: 'Folder name:',
508
- default: folderName
509
- }]);
510
- folderName = folder;
608
+ if (!explicitDir) {
609
+ const { folder } = await inquirer.prompt([{
610
+ type: 'input',
611
+ name: 'folder',
612
+ message: 'Folder name:',
613
+ default: folderName
614
+ }]);
615
+ folderName = folder;
616
+ }
511
617
  }
512
618
 
513
619
  const dir = resolve(process.cwd(), folderName);
620
+ const targetLabel = formatInitTarget(dir);
514
621
  const projectId = slugify(projectName);
622
+ let localDevRuntime;
623
+
624
+ try {
625
+ ({ runtime: localDevRuntime } = resolveGovernedLocalDevRuntime(opts));
626
+ } catch (err) {
627
+ console.error(chalk.red(` Error: ${err.message}`));
628
+ process.exit(1);
629
+ }
515
630
 
516
631
  if (existsSync(dir) && existsSync(join(dir, CONFIG_FILE))) {
517
632
  if (!opts.yes) {
@@ -530,10 +645,10 @@ async function initGoverned(opts) {
530
645
 
531
646
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
532
647
 
533
- scaffoldGoverned(dir, projectName, projectId, templateId);
648
+ scaffoldGoverned(dir, projectName, projectId, templateId, opts);
534
649
 
535
650
  console.log('');
536
- console.log(chalk.green(` ✓ Created governed project ${chalk.bold(folderName)}/`));
651
+ console.log(chalk.green(` ✓ Created governed project ${chalk.bold(targetLabel)}/`));
537
652
  console.log('');
538
653
  console.log(` ${chalk.dim('├──')} agentxchain.json ${chalk.dim('(governed)')}`);
539
654
  console.log(` ${chalk.dim('├──')} .agentxchain/`);
@@ -549,10 +664,13 @@ async function initGoverned(opts) {
549
664
  console.log('');
550
665
  console.log(` ${chalk.dim('Roles:')} pm, dev, qa, eng_director`);
551
666
  console.log(` ${chalk.dim('Template:')} ${templateId}`);
667
+ console.log(` ${chalk.dim('Dev runtime:')} ${formatGovernedRuntimeCommand(localDevRuntime)} ${chalk.dim(`(${localDevRuntime.prompt_transport})`)}`);
552
668
  console.log(` ${chalk.dim('Protocol:')} governed convergence`);
553
669
  console.log('');
554
670
  console.log(` ${chalk.cyan('Next:')}`);
555
- console.log(` ${chalk.bold(`cd ${folderName}`)}`);
671
+ if (dir !== process.cwd()) {
672
+ console.log(` ${chalk.bold(`cd ${targetLabel}`)}`);
673
+ }
556
674
  console.log(` ${chalk.bold('agentxchain step')} ${chalk.dim('# run the first governed turn')}`);
557
675
  console.log(` ${chalk.bold('agentxchain status')} ${chalk.dim('# inspect phase, gate, and turn state')}`);
558
676
  console.log('');
@@ -564,11 +682,20 @@ export async function initCommand(opts) {
564
682
  }
565
683
 
566
684
  let project, agents, folderName, rules;
685
+ let explicitDir;
686
+ try {
687
+ explicitDir = resolveInitDirOption(opts.dir);
688
+ } catch (err) {
689
+ console.error(chalk.red(` Error: ${err.message}`));
690
+ process.exit(1);
691
+ }
567
692
 
568
693
  if (opts.yes) {
569
- project = 'My AgentXchain project';
694
+ project = explicitDir
695
+ ? inferProjectNameFromTarget(explicitDir, 'My AgentXchain project')
696
+ : 'My AgentXchain project';
570
697
  agents = DEFAULT_AGENTS;
571
- folderName = slugify(project);
698
+ folderName = explicitDir || slugify(project);
572
699
  rules = {
573
700
  max_consecutive_claims: 2,
574
701
  require_message: true,
@@ -618,7 +745,9 @@ export async function initCommand(opts) {
618
745
  type: 'input',
619
746
  name: 'projectName',
620
747
  message: 'Project name:',
621
- default: 'My AgentXchain project'
748
+ default: explicitDir
749
+ ? inferProjectNameFromTarget(explicitDir, 'My AgentXchain project')
750
+ : 'My AgentXchain project'
622
751
  }]);
623
752
  project = projectName;
624
753
  } else {
@@ -626,7 +755,9 @@ export async function initCommand(opts) {
626
755
  type: 'input',
627
756
  name: 'projectName',
628
757
  message: 'Project name:',
629
- default: 'My AgentXchain project'
758
+ default: explicitDir
759
+ ? inferProjectNameFromTarget(explicitDir, 'My AgentXchain project')
760
+ : 'My AgentXchain project'
630
761
  }]);
631
762
  project = projectName;
632
763
  agents = {};
@@ -681,14 +812,16 @@ export async function initCommand(opts) {
681
812
  }
682
813
  }
683
814
 
684
- folderName = slugify(project);
685
- const { folder } = await inquirer.prompt([{
686
- type: 'input',
687
- name: 'folder',
688
- message: 'Folder name:',
689
- default: folderName
690
- }]);
691
- folderName = folder;
815
+ folderName = explicitDir || slugify(project);
816
+ if (!explicitDir) {
817
+ const { folder } = await inquirer.prompt([{
818
+ type: 'input',
819
+ name: 'folder',
820
+ message: 'Folder name:',
821
+ default: folderName
822
+ }]);
823
+ folderName = folder;
824
+ }
692
825
  }
693
826
 
694
827
  const dir = resolve(process.cwd(), folderName);