wize-dev-kit 0.26.1 → 0.27.2

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 (69) hide show
  1. package/ARCH.md +2 -1
  2. package/CHANGELOG.md +64 -0
  3. package/README.es.md +28 -6
  4. package/README.md +28 -6
  5. package/README.pt-BR.md +28 -6
  6. package/adapters/continue/render.js +2 -3
  7. package/adapters/copilot/render.js +3 -3
  8. package/adapters/cursor/render.js +2 -3
  9. package/adapters/generic/render.js +2 -3
  10. package/adapters/opencode/render.js +3 -4
  11. package/adapters/windsurf/render.js +2 -3
  12. package/docs/WORKTREES.md +150 -0
  13. package/docs/WORKTREES.pt-BR.md +150 -0
  14. package/docs/harnesses/antigravity.md +2 -0
  15. package/docs/harnesses/antigravity.pt-BR.md +2 -0
  16. package/docs/harnesses/claude-code.md +2 -0
  17. package/docs/harnesses/claude-code.pt-BR.md +2 -0
  18. package/docs/harnesses/codex.md +3 -1
  19. package/docs/harnesses/codex.pt-BR.md +3 -1
  20. package/docs/harnesses/continue.md +2 -0
  21. package/docs/harnesses/continue.pt-BR.md +2 -0
  22. package/docs/harnesses/copilot.md +2 -0
  23. package/docs/harnesses/copilot.pt-BR.md +2 -0
  24. package/docs/harnesses/cursor.md +2 -0
  25. package/docs/harnesses/cursor.pt-BR.md +2 -0
  26. package/docs/harnesses/generic.md +2 -0
  27. package/docs/harnesses/generic.pt-BR.md +2 -0
  28. package/docs/harnesses/hermes.md +2 -0
  29. package/docs/harnesses/hermes.pt-BR.md +2 -0
  30. package/docs/harnesses/kimi-code.md +2 -0
  31. package/docs/harnesses/kimi-code.pt-BR.md +2 -0
  32. package/docs/harnesses/kiro.md +2 -0
  33. package/docs/harnesses/kiro.pt-BR.md +2 -0
  34. package/docs/harnesses/opencode.md +2 -0
  35. package/docs/harnesses/opencode.pt-BR.md +2 -0
  36. package/docs/harnesses/windsurf.md +2 -0
  37. package/docs/harnesses/windsurf.pt-BR.md +2 -0
  38. package/package.json +1 -1
  39. package/src/orchestrator-skills/module.yaml +1 -1
  40. package/src/orchestrator-skills/wize/skill.md +17 -7
  41. package/src/orchestrator-skills/wize-help/skill.md +20 -7
  42. package/src/orchestrator-skills/wize-update/skill.md +33 -27
  43. package/tools/installer/commands/doctor.js +186 -40
  44. package/tools/installer/commands/document-project.js +13 -3
  45. package/tools/installer/commands/hooks.js +215 -0
  46. package/tools/installer/commands/hydrate.js +298 -0
  47. package/tools/installer/commands/sync.js +50 -23
  48. package/tools/installer/commands/update.js +596 -120
  49. package/tools/installer/commands/version-check.js +69 -10
  50. package/tools/installer/document-project/modes/full-rescan.js +1 -1
  51. package/tools/installer/document-project/modes/initial-scan.js +5 -4
  52. package/tools/installer/document-project/modes/quick.js +11 -4
  53. package/tools/installer/git-context.js +219 -0
  54. package/tools/installer/git-ops.js +211 -0
  55. package/tools/installer/install-plan.js +136 -0
  56. package/tools/installer/marker.js +67 -0
  57. package/tools/installer/project-root.js +68 -0
  58. package/tools/installer/project-status.js +171 -0
  59. package/tools/installer/render-shared.js +170 -4
  60. package/tools/installer/render-targets.js +112 -0
  61. package/tools/installer/semver.js +59 -0
  62. package/tools/installer/setup-helpers.js +89 -31
  63. package/tools/installer/templates/hydrate.sh +163 -0
  64. package/tools/installer/templates/wize-kit-update.yml +38 -0
  65. package/tools/installer/toml.js +133 -0
  66. package/tools/installer/util.js +16 -0
  67. package/tools/installer/version-check.js +167 -37
  68. package/tools/installer/wize-cli.js +216 -78
  69. package/tools/installer/sync.js +0 -29
@@ -16,10 +16,21 @@ const path = require('node:path');
16
16
  const readline = require('node:readline');
17
17
  const { execSync } = require('node:child_process');
18
18
  const prompts = require('prompts');
19
- const { applyGitignore, generateUserToml } = require('./setup-helpers.js');
20
- const { cmdUpdate, loadProjectConfig } = require('./commands/update.js');
19
+ const { applyGitignore, generateUserToml, ALIAS_BY_TARGET } = require('./setup-helpers.js');
20
+ const { cmdUpdate } = require('./commands/update.js');
21
+ const { loadProjectConfig } = require('./toml.js');
22
+ const { resolveRoot } = require('./project-root.js');
23
+ const { renderTargets } = require('./render-targets.js');
21
24
  const { printUpdateHintIfAny } = require('./version-check.js');
22
25
  const { cmdVersionCheck } = require('./commands/version-check.js');
26
+ const { cmdHydrate } = require('./commands/hydrate.js');
27
+ const { writeMarker } = require('./marker.js');
28
+ const { cmdHooks } = require('./commands/hooks.js');
29
+ const {
30
+ checkInstallRoot, conflictingFlags, installedPin, resolveProjectName, resolveUserName,
31
+ baselineDecision, resolveUninstallRoot
32
+ } = require('./install-plan.js');
33
+ const { gitContext } = require('./git-context.js');
23
34
  const { cmdSync: cmdSyncReal } = require('./commands/sync.js');
24
35
  const { cmdAgentList, cmdAgentCreate, cmdAgentEdit } = require('./commands/agent.js');
25
36
  const { cmdDoctor, adapterTargetPath } = require('./commands/doctor.js');
@@ -73,17 +84,19 @@ Usage:
73
84
  wize-dev-kit <command> [options]
74
85
 
75
86
  Commands:
76
- install Install the kit into the current repo (interactive).
77
- update Apply upstream diff while preserving customizations.
78
- version-check [--json] Check installed vs. latest version (scriptable; never blocks).
87
+ install Install the kit at the repo root (interactive); on an installed project it only hydrates.
88
+ update Converge to this kit: pin kit_version + managed .gitignore + AGENTS block; prepares chore/wize-kit-<v> in a temp worktree (--pr pushes + opens PR).
89
+ hydrate Render this checkout from project.toml (worktree-safe; never touches tracked files).
90
+ hooks <install|print> Opt-in automation: hooks install [--claude] [--cursor] [--github-action]; hooks print <orca|claude|cursor|codex|github-action>.
91
+ version-check [--json] Check project pin, hydration and registry; names the next action (scriptable).
79
92
  uninstall Remove the kit from the current repo (preserves code).
80
93
  list List installed agents, skills and workflows.
81
94
  sync Regenerate IDE adapters for active targets.
82
95
  agent <create|list> Manage agents (built-in or custom).
83
96
  workflow <create|list> Manage workflows.
84
97
  validate Run schema + lint + dry-run validators.
85
- doctor Diagnose the kit + project state, suggest fixes.
86
- document-project Document the current repo (quick | initial_scan | full_rescan | deep_dive).
98
+ doctor [--json] [--strict] Diagnose the kit + project state (hydration, skew, leaks) and suggest fixes.
99
+ document-project Document the current repo (quick | initial_scan | full_rescan | deep_dive); existing files are kept unless --force.
87
100
  help Show this message.
88
101
 
89
102
  Documentation:
@@ -308,7 +321,7 @@ async function multiSelect(label, items, isSelected = i => i.default) {
308
321
  }
309
322
 
310
323
  function isGitRepo(dir) {
311
- return fs.existsSync(path.join(dir, '.git'));
324
+ return gitContext(dir).isRepo;
312
325
  }
313
326
 
314
327
  function detectBrownfield(dir) {
@@ -404,34 +417,16 @@ gate = { granularity = "per-story" }
404
417
  }
405
418
 
406
419
  function renderAdapters({ kitRoot, projectRoot, targets, profiles }) {
407
- const results = [];
408
- const profileCodes = profiles.map(p => p.code);
409
- for (const target of targets) {
410
- const adapterDir = path.join(kitRoot, 'adapters', target.code);
411
- const renderPath = path.join(adapterDir, 'render.js');
412
- if (!fs.existsSync(renderPath)) {
413
- results.push({ code: target.code, skipped: true, reason: 'adapter missing' });
414
- continue;
415
- }
416
- try {
417
- const mod = require(renderPath);
418
- if (typeof mod.render !== 'function') {
419
- results.push({ code: target.code, skipped: true, reason: 'no render() export' });
420
- continue;
421
- }
422
- const out = mod.render(kitRoot, projectRoot, { profiles: profileCodes });
423
- if (out && typeof out === 'object' && Array.isArray(out.written)) {
424
- results.push({ code: target.code, written: out.written.length });
425
- } else {
426
- results.push({ code: target.code, skipped: true, reason: 'stub (no skills emitted)' });
427
- }
428
- } catch (err) {
429
- results.push({ code: target.code, error: err.message });
430
- }
431
- }
432
- return results;
420
+ return renderTargets({ kitRoot, projectRoot, targets, profiles }).adapters;
433
421
  }
434
422
 
423
+ // Flags that never take a value: the next token stays positional.
424
+ const BOOLEAN_FLAGS = new Set([
425
+ 'yes', 'json', 'quiet', 'strict', 'check', 'dry-run', 'if-needed', 'no-delegate',
426
+ 'no-notice', 'no-render', 'in-place', 'pr', 'allow-downgrade', 'exit-code',
427
+ 'refresh', 'here', 'force', 'baseline', 'claude', 'cursor', 'github-action'
428
+ ]);
429
+
435
430
  // Parse --key value and --flag from an argv slice. Returns { flags, positional }.
436
431
  function parseArgs(args) {
437
432
  const flags = {};
@@ -440,9 +435,11 @@ function parseArgs(args) {
440
435
  const a = args[i];
441
436
  if (a.startsWith('--')) {
442
437
  const key = a.slice(2);
443
- if (key.includes('=')) {
444
- const [k, v] = key.split('=', 2);
445
- flags[k] = v;
438
+ const eq = key.indexOf('=');
439
+ if (eq !== -1) {
440
+ flags[key.slice(0, eq)] = key.slice(eq + 1);
441
+ } else if (BOOLEAN_FLAGS.has(key)) {
442
+ flags[key] = true;
446
443
  } else if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
447
444
  flags[key] = args[++i];
448
445
  } else {
@@ -455,6 +452,22 @@ function parseArgs(args) {
455
452
  return { flags, positional };
456
453
  }
457
454
 
455
+ // Drops `--name value` / `--name=value` pairs, value included, so a
456
+ // sub-command's own option parser never sees them.
457
+ function stripValueFlags(args, names) {
458
+ const out = [];
459
+ for (let i = 0; i < args.length; i++) {
460
+ const a = args[i];
461
+ const key = a.startsWith('--') ? a.slice(2).split('=')[0] : null;
462
+ if (key && names.includes(key)) {
463
+ if (!a.includes('=') && i + 1 < args.length && !args[i + 1].startsWith('--')) i++;
464
+ continue;
465
+ }
466
+ out.push(a);
467
+ }
468
+ return out;
469
+ }
470
+
458
471
  function resolveProfiles(flags) {
459
472
  if (!flags.profiles) return null;
460
473
  const codes = flags.profiles.split(',').map(s => s.trim()).filter(Boolean);
@@ -489,15 +502,6 @@ function resolveLang(flags) {
489
502
  return null;
490
503
  }
491
504
 
492
- function resolveName(flags) {
493
- if (flags.name) return flags.name.trim();
494
- if (flags.yes) {
495
- try { return execSync('git config user.name', { encoding: 'utf-8' }).trim(); } catch (_) {}
496
- return process.env.USER || process.env.USERNAME || 'Developer';
497
- }
498
- return null;
499
- }
500
-
501
505
  // --yes quick install: everything on. All harnesses + all overlays, so
502
506
  // `npx wize-dev-kit install --yes` is a true one-shot full install.
503
507
  function defaultProfiles() {
@@ -514,6 +518,53 @@ async function cmdInstall(args) {
514
518
  const dryRun = !!flags['dry-run'];
515
519
  const nonInteractive = !!flags.yes;
516
520
 
521
+ const guard = checkInstallRoot({ cwd, flags });
522
+ if (guard.status === 'nested') {
523
+ console.error(`✖ ${guard.message}`);
524
+ process.exit(1);
525
+ }
526
+ if (guard.status === 'primary') {
527
+ if (nonInteractive) {
528
+ console.log(`wize: ${guard.message}; skipping install`);
529
+ return;
530
+ }
531
+ console.error(`✖ ${guard.message}`);
532
+ process.exit(1);
533
+ }
534
+ if (guard.status === 'subdir') {
535
+ if (nonInteractive) {
536
+ console.error(`✖ ${guard.message}`);
537
+ process.exit(1);
538
+ }
539
+ console.log(`\n⚠ ${cwd} não é a raiz do repositório git (${guard.toplevel}).`);
540
+ const ok = await confirm('Instalar aqui mesmo assim?', false);
541
+ if (!ok) process.exit(1);
542
+ }
543
+
544
+ // Existing project: never reconfigure. Hydrate this checkout and stop, so
545
+ // `install --yes` stays safe in worktree hooks.
546
+ if (guard.installed) {
547
+ const pin = installedPin(cwd);
548
+ const conflicts = conflictingFlags({ flags, root: cwd });
549
+ if (conflicts.length) {
550
+ console.error(`✖ ${conflicts.join(', ')} differ from .wize/config/project.toml: edit [install] in .wize/config/project.toml, then run hydrate`);
551
+ process.exit(1);
552
+ }
553
+ console.log(`kit already installed (kit_version ${pin}): hydrating; run \`npx wize-dev-kit@latest update\` to refresh the managed .gitignore / AGENTS block`);
554
+ if (dryRun) {
555
+ console.log('[DRY-RUN] Executaria hydrate. Nenhum arquivo foi modificado.');
556
+ return;
557
+ }
558
+ const r = cmdHydrate({
559
+ kitRoot: KIT_ROOT,
560
+ binary: KIT_VERSION,
561
+ projectRoot: cwd,
562
+ flags: { 'no-delegate': !!flags['no-delegate'], quiet: !!flags.quiet, 'no-notice': !!flags['no-notice'] }
563
+ });
564
+ process.exitCode = r.exitCode || 0;
565
+ return;
566
+ }
567
+
517
568
  console.log(logo());
518
569
  if (dryRun) console.log('[DRY-RUN] Nenhum arquivo será modificado.\n');
519
570
  console.log('Instalando Wize Development Kit em:', cwd);
@@ -539,15 +590,16 @@ async function cmdInstall(args) {
539
590
  let project_name, profiles, targets, communication_language, document_output_language, user_name, wantsGitignore;
540
591
 
541
592
  if (nonInteractive) {
542
- project_name = flags.name ? resolveName(flags) : (path.basename(cwd));
593
+ project_name = resolveProjectName({ flags, cwd, ctx: guard.ctx });
543
594
  profiles = resolveProfiles(flags) || defaultProfiles();
544
595
  targets = resolveTargets(flags) || defaultTargets();
545
596
  communication_language = resolveLang(flags) || 'pt-BR';
546
597
  document_output_language = resolveLang(flags) || communication_language;
547
- user_name = resolveName(flags);
598
+ user_name = resolveUserName({ flags, cwd, nonInteractive: true });
548
599
  wantsGitignore = true;
549
600
  } else {
550
- project_name = (await promptText(`Nome do projeto`, path.basename(cwd))) || path.basename(cwd);
601
+ const defaultProject = resolveProjectName({ flags, cwd, ctx: guard.ctx });
602
+ project_name = (await promptText(`Nome do projeto`, defaultProject)) || defaultProject;
551
603
  profiles = await multiSelect('Selecione o(s) perfil(is) para instalar', PROFILES);
552
604
  targets = await multiSelect('Selecione o(s) IDE target(s)', TARGETS);
553
605
 
@@ -560,7 +612,7 @@ async function cmdInstall(args) {
560
612
  communication_language
561
613
  );
562
614
 
563
- const defaultName = (os.userInfo().username || '').trim();
615
+ const defaultName = resolveUserName({ flags, cwd }) || (os.userInfo().username || '').trim();
564
616
  user_name = await promptTextMandatory(
565
617
  'Como os agentes devem te chamar?',
566
618
  defaultName
@@ -631,14 +683,32 @@ async function cmdInstall(args) {
631
683
  });
632
684
  for (const r of renderResults) {
633
685
  if (r.skipped) console.log(` - ${r.code}: pulado (${r.reason})`);
634
- else if (r.written) console.log(` ✓ ${r.code}: ${r.written} skill(s) emitidas`);
635
686
  else if (r.error) console.log(` ✖ ${r.code}: ${r.error}`);
687
+ else console.log(` ✓ ${r.code}: ${r.written + r.unchanged} arquivo(s) emitidos`);
688
+ }
689
+ if (!renderResults.some(r => r.error)) {
690
+ writeMarker(cwd, {
691
+ kit_version: KIT_VERSION,
692
+ pin: KIT_VERSION,
693
+ targets: targets.map(t => t.code),
694
+ profiles: profiles.map(p => p.code),
695
+ counts: {
696
+ written: renderResults.reduce((n, r) => n + (r.written || 0), 0),
697
+ unchanged: renderResults.reduce((n, r) => n + (r.unchanged || 0), 0),
698
+ skipped_tracked: 0
699
+ },
700
+ delegated: false,
701
+ rendered_with: KIT_VERSION
702
+ });
636
703
  }
637
704
 
638
- if (detection.brownfield) {
639
- if (process.env.WIZE_SKIP_BASELINE === '1') {
640
- console.log('\nWIZE_SKIP_BASELINE=1 — baseline não será executado.');
641
- } else if (!INTERACTIVE || nonInteractive) {
705
+ const baseline = baselineDecision({ root: cwd, flags, brownfield: detection.brownfield });
706
+ if (baseline.reason === 'env' && (detection.brownfield || flags.baseline)) {
707
+ console.log('\nWIZE_SKIP_BASELINE=1 — baseline não será executado.');
708
+ } else if (baseline.reason === 'exists') {
709
+ console.log('\nBaseline já existe em .wize/knowledge/document-project/; não será executado (use --baseline ou `wize-dev-kit document-project`).');
710
+ } else if (baseline.run) {
711
+ if (!INTERACTIVE || nonInteractive) {
642
712
  console.log('\nInstalação não-interativa detectada; executando baseline rápido...');
643
713
  cmdDocumentProject({ kitRoot: KIT_ROOT, projectRoot: cwd, args: ['quick'], opts: { log: console.log } });
644
714
  } else {
@@ -667,8 +737,10 @@ async function cmdInstall(args) {
667
737
  console.log(composeOnboarding(detection, profiles));
668
738
  console.log('');
669
739
  console.log('Mantenha o kit sincronizado:');
670
- console.log(' • `npx wize-dev-kit update` atualizar adapters após nova versão do kit');
671
- console.log(' • `npx wize-dev-kit sync` re-renderizar adapters após editar config');
740
+ console.log(' • `npx wize-dev-kit hydrate` renderizar um checkout novo ou worktree (sem tocar em arquivos versionados)');
741
+ console.log(' • `npx wize-dev-kit update --pr` atualizar o kit numa branch isolada e abrir o PR');
742
+ console.log(' • `npx wize-dev-kit hooks install` hydrate automático ao criar worktrees');
743
+ console.log(' • `npx wize-dev-kit sync` re-renderizar adapters após editar config');
672
744
  console.log(' • `npx wize-dev-kit agent list | create | edit <code>` gerenciar agentes');
673
745
  console.log('──────────────────────────────────────────────────────────────');
674
746
  }
@@ -704,13 +776,20 @@ function cleanAdapterTarget(targetDir) {
704
776
  }
705
777
 
706
778
  async function cmdUninstall(args) {
707
- const cwd = process.cwd();
708
779
  const { flags } = parseArgs(args || []);
709
780
  const dryRun = !!flags['dry-run'];
781
+ const target = resolveUninstallRoot({ cwd: process.cwd(), flags, env: process.env });
782
+ const root = target.root;
783
+
784
+ console.log(`uninstalling from ${root}`);
785
+ if (target.refused) {
786
+ console.error(`✖ run from ${root} or pass --root ${root}`);
787
+ process.exit(1);
788
+ }
710
789
 
711
790
  if (dryRun) console.log('[DRY-RUN] Nenhum arquivo será removido.\n');
712
791
 
713
- const wizeDir = path.join(cwd, '.wize');
792
+ const wizeDir = path.join(root, '.wize');
714
793
  if (!fs.existsSync(wizeDir)) {
715
794
  console.log('Nenhuma pasta .wize/ encontrada aqui.');
716
795
  return;
@@ -719,7 +798,7 @@ async function cmdUninstall(args) {
719
798
  // Read project.toml to discover which IDE targets were configured.
720
799
  let ideTargets = [];
721
800
  try {
722
- const cfg = loadProjectConfig(cwd);
801
+ const cfg = loadProjectConfig(root);
723
802
  ideTargets = (cfg.install && cfg.install.ide_targets) || [];
724
803
  } catch { /* project.toml may be missing or corrupt */ }
725
804
 
@@ -729,7 +808,7 @@ async function cmdUninstall(args) {
729
808
  // 1. Adapter target dirs (wize-* entries).
730
809
  const adapterDirs = [];
731
810
  for (const code of ideTargets) {
732
- const dir = adapterTargetPath(code, cwd);
811
+ const dir = adapterTargetPath(code, root);
733
812
  if (!dir) continue;
734
813
  if (!fs.existsSync(dir)) continue;
735
814
  let entries;
@@ -739,12 +818,21 @@ async function cmdUninstall(args) {
739
818
  adapterDirs.push({ target: code, dir, name, full: path.join(dir, name) });
740
819
  }
741
820
  }
821
+ // The `wize` alias entrypoints do not start with "wize-": remove them by
822
+ // exact path, never by prefix.
823
+ for (const code of ideTargets) {
824
+ for (const alias of ALIAS_BY_TARGET[code] || []) {
825
+ const full = path.join(root, alias.replace(/\/$/, ''));
826
+ try { fs.lstatSync(full); } catch { continue; }
827
+ adapterDirs.push({ target: code, dir: path.dirname(full), name: alias, full, alias: true });
828
+ }
829
+ }
742
830
 
743
831
  // 2. .wize/ directory.
744
832
  toRemove.push({ kind: 'diretório', path: wizeDir, label: '.wize/' });
745
833
 
746
834
  // 3. AGENTS.md if kit-generated.
747
- const agentsMd = path.join(cwd, 'AGENTS.md');
835
+ const agentsMd = path.join(root, 'AGENTS.md');
748
836
  if (isKitAgentsMd(agentsMd)) {
749
837
  toRemove.push({ kind: 'arquivo', path: agentsMd, label: 'AGENTS.md' });
750
838
  }
@@ -760,6 +848,10 @@ async function cmdUninstall(args) {
760
848
  for (const [code, names] of Object.entries(byTarget)) {
761
849
  console.log(` ${code}: ${names.length} entrada(s) (${names.slice(0, 5).join(', ')}${names.length > 5 ? '...' : ''})`);
762
850
  }
851
+ const aliases = adapterDirs.filter(a => a.alias);
852
+ if (aliases.length > 0) {
853
+ console.log(` alias wize (caminho exato): ${aliases.map(a => path.relative(root, a.full)).join(', ')}`);
854
+ }
763
855
  } else {
764
856
  console.log('Nenhum arquivo de adapter wize-* encontrado.');
765
857
  }
@@ -846,14 +938,14 @@ function cmdList() {
846
938
  }
847
939
  }
848
940
 
849
- function cmdSync() {
850
- return cmdSyncReal({ kitRoot: KIT_ROOT, projectRoot: process.cwd() });
941
+ function cmdSync(projectRoot) {
942
+ return cmdSyncReal({ kitRoot: KIT_ROOT, projectRoot });
851
943
  }
852
944
 
853
- function cmdAgent(args) {
945
+ function cmdAgent(args, projectRoot) {
854
946
  const sub = args[0] || 'list';
855
947
  const rest = args.slice(1);
856
- const ctx = { kitRoot: KIT_ROOT, projectRoot: process.cwd() };
948
+ const ctx = { kitRoot: KIT_ROOT, projectRoot };
857
949
  if (sub === 'list') return cmdAgentList(ctx);
858
950
  if (sub === 'create') return cmdAgentCreate(ctx);
859
951
  if (sub === 'edit') return cmdAgentEdit({ ...ctx, code: rest[0] });
@@ -877,37 +969,83 @@ function cmdValidate() {
877
969
 
878
970
  // Commands worth nudging the user about when a newer version exists. Skipped
879
971
  // for `update` (already updating), `install` (already setting up), `uninstall`
880
- // (already leaving), `validate` (developer-tool), and `version` (the user is
881
- // already asking about versions).
972
+ // (already leaving), `validate` (developer-tool), `hydrate` (runs unattended
973
+ // in worktree hooks and prints its own notice) and `version` (the user is
974
+ // already asking about versions). The hint never waits on the network.
882
975
  const HINT_COMMANDS = new Set(['list', 'sync', 'agent', 'workflow', 'help', 'doctor', 'document-project']);
883
976
 
884
977
  async function main() {
885
978
  const [cmd, ...rest] = process.argv.slice(2);
979
+ const { flags } = parseArgs(rest);
980
+ const rootFor = () => resolveRoot({ flags, env: process.env, cwd: process.cwd(), forCommand: cmd });
981
+ const hint = () => printUpdateHintIfAny(KIT_VERSION, { projectRoot: rootFor(), argv: process.argv.slice(2) });
886
982
  if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
887
- await printUpdateHintIfAny(KIT_VERSION);
983
+ await hint();
984
+ console.log(HELP);
985
+ return;
986
+ }
987
+ // `<command> --help` never runs the command: update, sync, hydrate, install
988
+ // and uninstall all change files.
989
+ if (rest.includes('--help') || rest.includes('-h')) {
888
990
  console.log(HELP);
889
991
  return;
890
992
  }
891
993
  if (HINT_COMMANDS.has(cmd)) {
892
- await printUpdateHintIfAny(KIT_VERSION);
994
+ await hint();
893
995
  }
894
996
  switch (cmd) {
895
997
  case 'install': return cmdInstall(rest);
896
- case 'update': return cmdUpdate({ kitRoot: KIT_ROOT, projectRoot: process.cwd() });
897
- case 'version-check':
898
- return cmdVersionCheck({ currentVersion: KIT_VERSION, json: rest.includes('--json') });
998
+ case 'update': {
999
+ const r = await cmdUpdate({ kitRoot: KIT_ROOT, projectRoot: rootFor(), opts: flags });
1000
+ process.exitCode = r.exitCode || 0;
1001
+ return;
1002
+ }
1003
+ case 'hydrate': {
1004
+ let exitCode = 0;
1005
+ try {
1006
+ const r = cmdHydrate({ kitRoot: KIT_ROOT, binary: KIT_VERSION, projectRoot: rootFor(), flags });
1007
+ exitCode = r.exitCode;
1008
+ } catch (err) {
1009
+ console.error(`wize: hydrate: ${err && err.message ? err.message : err}; run: npx --yes wize-dev-kit@latest hydrate`);
1010
+ exitCode = flags.strict ? 1 : 0;
1011
+ }
1012
+ process.exitCode = exitCode;
1013
+ return;
1014
+ }
1015
+ case 'hooks': {
1016
+ const r = cmdHooks({ projectRoot: rootFor(), args: parseArgs(rest).positional, flags });
1017
+ process.exitCode = r.exitCode || 0;
1018
+ return;
1019
+ }
1020
+ case 'version-check': {
1021
+ const r = await cmdVersionCheck({
1022
+ currentVersion: KIT_VERSION,
1023
+ kitRoot: KIT_ROOT,
1024
+ projectRoot: rootFor(),
1025
+ json: !!flags.json,
1026
+ refresh: !!flags.refresh,
1027
+ quiet: !!flags.quiet,
1028
+ exitCode: !!flags['exit-code']
1029
+ });
1030
+ process.exitCode = r.exitCode || 0;
1031
+ return;
1032
+ }
899
1033
  case 'uninstall': return cmdUninstall(rest);
900
1034
  case 'list': return cmdList();
901
- case 'sync': return cmdSync();
902
- case 'agent': return cmdAgent(rest);
1035
+ case 'sync': return cmdSync(rootFor());
1036
+ case 'agent': return cmdAgent(stripValueFlags(rest, ['root']), rootFor());
903
1037
  case 'workflow': return cmdWorkflow(rest);
904
1038
  case 'validate': return cmdValidate();
905
- case 'doctor': return cmdDoctor({ kitRoot: KIT_ROOT, projectRoot: process.cwd() });
1039
+ case 'doctor': {
1040
+ const r = await cmdDoctor({ kitRoot: KIT_ROOT, projectRoot: rootFor(), opts: { json: !!flags.json, strict: !!flags.strict } });
1041
+ process.exitCode = r.exitCode || 0;
1042
+ return;
1043
+ }
906
1044
  case 'document-project':
907
1045
  return cmdDocumentProject({
908
1046
  kitRoot: KIT_ROOT,
909
- projectRoot: process.cwd(),
910
- args: rest,
1047
+ projectRoot: rootFor(),
1048
+ args: stripValueFlags(rest, ['root']),
911
1049
  opts: { log: console.log }
912
1050
  });
913
1051
  case 'version':
@@ -1,29 +0,0 @@
1
- /*
2
- * Adapter sync — regenerates IDE adapter files for each active target.
3
- *
4
- * Stub: in v0.1 this iterates the adapters/ folder and prints what would
5
- * be generated. Actual file emission per IDE is a v0.2+ deliverable.
6
- */
7
- 'use strict';
8
-
9
- const fs = require('node:fs');
10
- const path = require('node:path');
11
-
12
- function syncAll(kitRoot, projectConfig) {
13
- const adaptersDir = path.join(kitRoot, 'adapters');
14
- if (!fs.existsSync(adaptersDir)) {
15
- console.log('(skip) adapters/ not found');
16
- return;
17
- }
18
- const active = projectConfig?.install?.ide_targets || ['claude-code', 'generic'];
19
- for (const target of active) {
20
- const dir = path.join(adaptersDir, target);
21
- if (!fs.existsSync(dir)) {
22
- console.log(`(warn) adapter "${target}" not found in adapters/`);
23
- continue;
24
- }
25
- console.log(`→ would sync ${target} adapter (stub)`);
26
- }
27
- }
28
-
29
- module.exports = { syncAll };