@gadmin2n/cli 0.0.103 → 0.0.104

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.
@@ -388,8 +388,8 @@ function copyTreeOverwrite(srcDir, destDir) {
388
388
  * Resolve which git URL + branch to use for the .claude context sync.
389
389
  *
390
390
  * Priority (highest first):
391
- * 1. CLI --claude-context-repo (full URL override)
392
- * 2. CLI --claude-context-protocol (https | ssh | skip)
391
+ * 1. CLI --coding-context-repo (full URL override)
392
+ * 2. CLI --coding-context-protocol (https | ssh | skip)
393
393
  * 3. Env var GADMIN2_CLAUDE_CONTEXT_REPO (full URL)
394
394
  * 4. Env var GADMIN2_CLAUDE_CONTEXT_PROTOCOL (https | ssh | skip)
395
395
  * 5. --yes (auto mode): default to built-in HTTPS, no prompt
@@ -747,313 +747,329 @@ class UpdateAction extends abstract_action_1.AbstractAction {
747
747
  });
748
748
  }
749
749
  handleUpdate(options) {
750
- var _a, _b, _c, _d, _e, _f, _g;
750
+ var _a, _b, _c, _d, _e, _f, _g, _h;
751
751
  return __awaiter(this, void 0, void 0, function* () {
752
752
  const dryRun = (_a = options.find((o) => o.name === 'dry-run')) === null || _a === void 0 ? void 0 : _a.value;
753
753
  const autoYes = (_b = options.find((o) => o.name === 'yes')) === null || _b === void 0 ? void 0 : _b.value;
754
754
  const smartMergeEnabled = (_d = (_c = options.find((o) => o.name === 'smart-merge')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : true;
755
- let templateDir;
756
- let excludes;
757
- try {
758
- const config = loadTemplateConfig();
759
- templateDir = resolveTemplatePath(config.templateName);
760
- excludes = config.excludes;
761
- }
762
- catch (err) {
763
- console.error(chalk.red(err.message));
755
+ const templateEnabled = ((_e = options.find((o) => o.name === 'template')) === null || _e === void 0 ? void 0 : _e.value) !== false;
756
+ const claudeEnabled = ((_f = options.find((o) => o.name === 'coding-context')) === null || _f === void 0 ? void 0 : _f.value) !==
757
+ false;
758
+ if (!templateEnabled && !claudeEnabled) {
759
+ console.error(chalk.red('\nNothing to do: both --no-template and --no-coding-context were specified.\n'));
764
760
  process.exit(1);
765
761
  }
766
762
  const instanceDir = process.cwd();
767
- console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
768
- console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
769
- // Build smart-merger registry (or null if disabled)
770
- const userTemplateUpdate = smartMergeEnabled
771
- ? (0, template_merge_1.loadTemplateUpdateConfig)(instanceDir)
772
- : null;
773
- const registry = smartMergeEnabled
774
- ? buildMergerRegistry(userTemplateUpdate)
775
- : null;
776
- const userPolicies = userTemplateUpdate === null || userTemplateUpdate === void 0 ? void 0 : userTemplateUpdate.policies;
777
- // Snapshot package.json files BEFORE any writes. We watch:
778
- // - <instanceDir>/package.json (root, if present — workspace / husky / etc.)
779
- // - <instanceDir>/web/package.json
780
- // - <instanceDir>/server/package.json
781
- const pkgSnapshots = [
782
- snapshotPackageJson(instanceDir, '(root)'),
783
- snapshotPackageJson(path.join(instanceDir, 'web'), 'web'),
784
- snapshotPackageJson(path.join(instanceDir, 'server'), 'server'),
785
- ];
786
- const templateFiles = collectFiles(templateDir, excludes);
787
- const instanceFiles = collectFiles(instanceDir, excludes);
788
- const instanceSet = new Set(instanceFiles);
789
- const toUpdate = [];
790
- const toAdd = [];
791
- for (const file of templateFiles) {
792
- if (instanceSet.has(file)) {
793
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
794
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
795
- if (tContent !== iContent) {
796
- toUpdate.push(file);
797
- }
763
+ // Hoisted so stage 3 (auto-install) can see snapshots taken in stage 1.
764
+ // Remains null when --no-template, which is also the signal to skip stage 3.
765
+ let pkgSnapshots = null;
766
+ if (templateEnabled) {
767
+ let templateDir;
768
+ let excludes;
769
+ try {
770
+ const config = loadTemplateConfig();
771
+ templateDir = resolveTemplatePath(config.templateName);
772
+ excludes = config.excludes;
798
773
  }
799
- else {
800
- toAdd.push(file);
774
+ catch (err) {
775
+ console.error(chalk.red(err.message));
776
+ process.exit(1);
801
777
  }
802
- }
803
- if (toUpdate.length === 0 && toAdd.length === 0) {
804
- console.info(chalk.green('✅ Instance is up to date with template.\n'));
805
- }
806
- else {
807
- console.info(chalk.bold('═══════════════════════════════════════════════════'));
808
- console.info(chalk.bold(' Template Update Summary'));
809
- console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
810
- if (toUpdate.length > 0) {
811
- console.info(chalk.yellow(`📝 To update (${toUpdate.length} files)`));
812
- for (const f of toUpdate) {
813
- console.info(` ${f}`);
778
+ console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
779
+ console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
780
+ // Build smart-merger registry (or null if disabled)
781
+ const userTemplateUpdate = smartMergeEnabled
782
+ ? (0, template_merge_1.loadTemplateUpdateConfig)(instanceDir)
783
+ : null;
784
+ const registry = smartMergeEnabled
785
+ ? buildMergerRegistry(userTemplateUpdate)
786
+ : null;
787
+ const userPolicies = userTemplateUpdate === null || userTemplateUpdate === void 0 ? void 0 : userTemplateUpdate.policies;
788
+ // Snapshot package.json files BEFORE any writes. We watch:
789
+ // - <instanceDir>/package.json (root, if present — workspace / husky / etc.)
790
+ // - <instanceDir>/web/package.json
791
+ // - <instanceDir>/server/package.json
792
+ pkgSnapshots = [
793
+ snapshotPackageJson(instanceDir, '(root)'),
794
+ snapshotPackageJson(path.join(instanceDir, 'web'), 'web'),
795
+ snapshotPackageJson(path.join(instanceDir, 'server'), 'server'),
796
+ ];
797
+ const templateFiles = collectFiles(templateDir, excludes);
798
+ const instanceFiles = collectFiles(instanceDir, excludes);
799
+ const instanceSet = new Set(instanceFiles);
800
+ const toUpdate = [];
801
+ const toAdd = [];
802
+ for (const file of templateFiles) {
803
+ if (instanceSet.has(file)) {
804
+ const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
805
+ const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
806
+ if (tContent !== iContent) {
807
+ toUpdate.push(file);
808
+ }
814
809
  }
815
- console.info();
816
- }
817
- if (toAdd.length > 0) {
818
- console.info(chalk.green(`➕ To add (${toAdd.length} files)`));
819
- for (const f of toAdd) {
820
- console.info(` ${f}`);
810
+ else {
811
+ toAdd.push(file);
821
812
  }
822
- console.info();
823
813
  }
824
- console.info(chalk.gray('───────────────────────────────────────────────────'));
825
- console.info(chalk.gray(` Total: ${toUpdate.length} update | ${toAdd.length} add`));
826
- console.info(chalk.gray('───────────────────────────────────────────────────\n'));
827
- if (!dryRun) {
828
- if (!autoYes) {
829
- const { confirm } = yield inquirer.prompt([
830
- {
831
- type: 'confirm',
832
- name: 'confirm',
833
- message: 'Proceed with template update?',
834
- default: false,
835
- },
836
- ]);
837
- if (!confirm) {
838
- console.info('Cancelled.\n');
839
- return;
814
+ if (toUpdate.length === 0 && toAdd.length === 0) {
815
+ console.info(chalk.green('✅ Instance is up to date with template.\n'));
816
+ }
817
+ else {
818
+ console.info(chalk.bold('═══════════════════════════════════════════════════'));
819
+ console.info(chalk.bold(' Template Update Summary'));
820
+ console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
821
+ if (toUpdate.length > 0) {
822
+ console.info(chalk.yellow(`📝 To update (${toUpdate.length} files)`));
823
+ for (const f of toUpdate) {
824
+ console.info(` ${f}`);
840
825
  }
826
+ console.info();
841
827
  }
842
- let skippedCount = 0;
843
- let overwrittenCount = 0;
844
- let mergedCount = 0;
845
- let conflictCount = 0;
846
- let smartCount = 0;
847
- let applyAll = null;
848
- for (let i = 0; i < toUpdate.length; i++) {
849
- const file = toUpdate[i];
850
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
851
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
852
- // 1. Try smart merger if registered for this file
853
- const smartMerger = registry
854
- ? registry.resolve(file)
855
- : null;
856
- let smartResult = null;
857
- if (smartMerger) {
858
- try {
859
- smartResult = yield smartMerger.merge({
860
- filePath: file,
861
- instancePath: path.join(instanceDir, file),
862
- templatePath: path.join(templateDir, file),
863
- instanceContent: iContent,
864
- templateContent: tContent,
865
- policies: userPolicies,
866
- });
867
- }
868
- catch (err) {
869
- smartResult = {
870
- ok: false,
871
- reason: (err === null || err === void 0 ? void 0 : err.message) || String(err),
872
- };
873
- }
828
+ if (toAdd.length > 0) {
829
+ console.info(chalk.green(`➕ To add (${toAdd.length} files)`));
830
+ for (const f of toAdd) {
831
+ console.info(` ${f}`);
874
832
  }
875
- let strategy = applyAll;
876
- if (!strategy) {
877
- if (autoYes) {
878
- // autoYes: prefer smart merge when available, else conflict markers
879
- strategy =
880
- smartResult && smartResult.ok ? 'smart' : 'conflict';
833
+ console.info();
834
+ }
835
+ console.info(chalk.gray('───────────────────────────────────────────────────'));
836
+ console.info(chalk.gray(` Total: ${toUpdate.length} update | ${toAdd.length} add`));
837
+ console.info(chalk.gray('───────────────────────────────────────────────────\n'));
838
+ if (!dryRun) {
839
+ if (!autoYes) {
840
+ const { confirm } = yield inquirer.prompt([
841
+ {
842
+ type: 'confirm',
843
+ name: 'confirm',
844
+ message: 'Proceed with template update?',
845
+ default: false,
846
+ },
847
+ ]);
848
+ if (!confirm) {
849
+ console.info('Cancelled.\n');
850
+ return;
881
851
  }
882
- else {
883
- const diff = createUnifiedDiff(file, iContent, tContent);
884
- console.info(`\n${chalk.bold(`[${i + 1}/${toUpdate.length}]`)} ${chalk.yellow(file)}`);
885
- console.info(diff);
886
- console.info();
887
- const choices = [];
888
- if (smartResult && smartResult.ok) {
889
- const summary = smartResult.notes.slice(0, 3).join('; ');
890
- const more = smartResult.notes.length > 3 ? '...' : '';
891
- choices.push({
892
- name: `Smart merge — ${smartMerger.name} (recommended): ${summary}${more}`,
893
- value: 'smart',
894
- short: 'smart',
895
- });
896
- }
897
- else if (smartMerger) {
898
- const reason = smartResult && !smartResult.ok
899
- ? smartResult.reason
900
- : 'no result';
901
- choices.push({
902
- name: `Smart merge — ${smartMerger.name} (UNAVAILABLE: ${reason})`,
903
- value: 'smart-unavailable',
904
- short: 'smart-unavailable',
905
- disabled: reason,
852
+ }
853
+ let skippedCount = 0;
854
+ let overwrittenCount = 0;
855
+ let mergedCount = 0;
856
+ let conflictCount = 0;
857
+ let smartCount = 0;
858
+ let applyAll = null;
859
+ for (let i = 0; i < toUpdate.length; i++) {
860
+ const file = toUpdate[i];
861
+ const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
862
+ const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
863
+ // 1. Try smart merger if registered for this file
864
+ const smartMerger = registry
865
+ ? registry.resolve(file)
866
+ : null;
867
+ let smartResult = null;
868
+ if (smartMerger) {
869
+ try {
870
+ smartResult = yield smartMerger.merge({
871
+ filePath: file,
872
+ instancePath: path.join(instanceDir, file),
873
+ templatePath: path.join(templateDir, file),
874
+ instanceContent: iContent,
875
+ templateContent: tContent,
876
+ policies: userPolicies,
906
877
  });
907
878
  }
908
- choices.push({
909
- name: 'Skip — keep instance as-is',
910
- value: 'skip',
911
- short: 'skip',
912
- }, {
913
- name: 'Overwrite — use template version',
914
- value: 'overwrite',
915
- short: 'overwrite',
916
- }, {
917
- name: 'Auto merge — attempt git merge',
918
- value: 'merge',
919
- short: 'merge',
920
- }, {
921
- name: 'Conflict markers — write both versions for manual resolve',
922
- value: 'conflict',
923
- short: 'conflict',
924
- }, new inquirer.Separator());
925
- if (smartResult && smartResult.ok) {
926
- choices.push({
927
- name: 'Smart-merge ALL remaining (where supported)',
928
- value: 'smart-all',
929
- short: 'smart all',
930
- });
879
+ catch (err) {
880
+ smartResult = {
881
+ ok: false,
882
+ reason: (err === null || err === void 0 ? void 0 : err.message) || String(err),
883
+ };
931
884
  }
932
- choices.push({
933
- name: 'Skip ALL remaining',
934
- value: 'skip-all',
935
- short: 'skip all',
936
- }, {
937
- name: 'Overwrite ALL remaining',
938
- value: 'overwrite-all',
939
- short: 'overwrite all',
940
- }, {
941
- name: 'Conflict markers ALL remaining',
942
- value: 'conflict-all',
943
- short: 'conflict all',
944
- });
945
- const { action } = yield inquirer.prompt([
946
- {
947
- type: 'list',
948
- name: 'action',
949
- message: `How to handle ${file}?`,
950
- default: smartResult && smartResult.ok ? 'smart' : 'skip',
951
- choices,
952
- },
953
- ]);
954
- if (action.endsWith('-all')) {
955
- applyAll = action.replace('-all', '');
956
- strategy = applyAll;
885
+ }
886
+ let strategy = applyAll;
887
+ if (!strategy) {
888
+ if (autoYes) {
889
+ // autoYes: prefer smart merge when available, else conflict markers
890
+ strategy =
891
+ smartResult && smartResult.ok ? 'smart' : 'conflict';
957
892
  }
958
893
  else {
959
- strategy = action;
894
+ const diff = createUnifiedDiff(file, iContent, tContent);
895
+ console.info(`\n${chalk.bold(`[${i + 1}/${toUpdate.length}]`)} ${chalk.yellow(file)}`);
896
+ console.info(diff);
897
+ console.info();
898
+ const choices = [];
899
+ if (smartResult && smartResult.ok) {
900
+ const summary = smartResult.notes.slice(0, 3).join('; ');
901
+ const more = smartResult.notes.length > 3 ? '...' : '';
902
+ choices.push({
903
+ name: `Smart merge — ${smartMerger.name} (recommended): ${summary}${more}`,
904
+ value: 'smart',
905
+ short: 'smart',
906
+ });
907
+ }
908
+ else if (smartMerger) {
909
+ const reason = smartResult && !smartResult.ok
910
+ ? smartResult.reason
911
+ : 'no result';
912
+ choices.push({
913
+ name: `Smart merge — ${smartMerger.name} (UNAVAILABLE: ${reason})`,
914
+ value: 'smart-unavailable',
915
+ short: 'smart-unavailable',
916
+ disabled: reason,
917
+ });
918
+ }
919
+ choices.push({
920
+ name: 'Skip — keep instance as-is',
921
+ value: 'skip',
922
+ short: 'skip',
923
+ }, {
924
+ name: 'Overwrite — use template version',
925
+ value: 'overwrite',
926
+ short: 'overwrite',
927
+ }, {
928
+ name: 'Auto merge — attempt git merge',
929
+ value: 'merge',
930
+ short: 'merge',
931
+ }, {
932
+ name: 'Conflict markers — write both versions for manual resolve',
933
+ value: 'conflict',
934
+ short: 'conflict',
935
+ }, new inquirer.Separator());
936
+ if (smartResult && smartResult.ok) {
937
+ choices.push({
938
+ name: 'Smart-merge ALL remaining (where supported)',
939
+ value: 'smart-all',
940
+ short: 'smart all',
941
+ });
942
+ }
943
+ choices.push({
944
+ name: 'Skip ALL remaining',
945
+ value: 'skip-all',
946
+ short: 'skip all',
947
+ }, {
948
+ name: 'Overwrite ALL remaining',
949
+ value: 'overwrite-all',
950
+ short: 'overwrite all',
951
+ }, {
952
+ name: 'Conflict markers ALL remaining',
953
+ value: 'conflict-all',
954
+ short: 'conflict all',
955
+ });
956
+ const { action } = yield inquirer.prompt([
957
+ {
958
+ type: 'list',
959
+ name: 'action',
960
+ message: `How to handle ${file}?`,
961
+ default: smartResult && smartResult.ok ? 'smart' : 'skip',
962
+ choices,
963
+ },
964
+ ]);
965
+ if (action.endsWith('-all')) {
966
+ applyAll = action.replace('-all', '');
967
+ strategy = applyAll;
968
+ }
969
+ else {
970
+ strategy = action;
971
+ }
960
972
  }
961
973
  }
962
- }
963
- const destPath = path.join(instanceDir, file);
964
- switch (strategy) {
965
- case 'smart':
966
- if (smartResult && smartResult.ok) {
967
- fs.writeFileSync(destPath, smartResult.merged, 'utf-8');
968
- smartCount++;
969
- console.info(chalk.green(` ✓ ${file} smart merge (${smartMerger.name})`));
970
- for (const note of smartResult.notes) {
971
- console.info(chalk.gray(` • ${note}`));
974
+ const destPath = path.join(instanceDir, file);
975
+ switch (strategy) {
976
+ case 'smart':
977
+ if (smartResult && smartResult.ok) {
978
+ fs.writeFileSync(destPath, smartResult.merged, 'utf-8');
979
+ smartCount++;
980
+ console.info(chalk.green(` ✓ ${file} — smart merge (${smartMerger.name})`));
981
+ for (const note of smartResult.notes) {
982
+ console.info(chalk.gray(` • ${note}`));
983
+ }
972
984
  }
985
+ else {
986
+ // No smart merger usable: fallback to conflict markers
987
+ fs.writeFileSync(destPath, createConflictContent(iContent, tContent), 'utf-8');
988
+ conflictCount++;
989
+ console.info(chalk.yellow(` ⚠️ ${file} — no smart merger available, wrote conflict markers`));
990
+ }
991
+ break;
992
+ case 'skip':
993
+ skippedCount++;
994
+ break;
995
+ case 'overwrite':
996
+ fs.writeFileSync(destPath, tContent, 'utf-8');
997
+ overwrittenCount++;
998
+ break;
999
+ case 'merge': {
1000
+ const result = tryAutoMerge(iContent, tContent);
1001
+ fs.writeFileSync(destPath, result.merged, 'utf-8');
1002
+ if (result.hasConflicts) {
1003
+ conflictCount++;
1004
+ console.info(chalk.yellow(` ⚠️ ${file} — merge has conflicts`));
1005
+ }
1006
+ else {
1007
+ mergedCount++;
1008
+ console.info(chalk.green(` ✓ ${file} — merged cleanly`));
1009
+ }
1010
+ break;
973
1011
  }
974
- else {
975
- // No smart merger usable: fallback to conflict markers
1012
+ case 'conflict':
1013
+ default:
976
1014
  fs.writeFileSync(destPath, createConflictContent(iContent, tContent), 'utf-8');
977
1015
  conflictCount++;
978
- console.info(chalk.yellow(` ⚠️ ${file} — no smart merger available, wrote conflict markers`));
979
- }
980
- break;
981
- case 'skip':
982
- skippedCount++;
983
- break;
984
- case 'overwrite':
985
- fs.writeFileSync(destPath, tContent, 'utf-8');
986
- overwrittenCount++;
987
- break;
988
- case 'merge': {
989
- const result = tryAutoMerge(iContent, tContent);
990
- fs.writeFileSync(destPath, result.merged, 'utf-8');
991
- if (result.hasConflicts) {
992
- conflictCount++;
993
- console.info(chalk.yellow(` ⚠️ ${file} — merge has conflicts`));
994
- }
995
- else {
996
- mergedCount++;
997
- console.info(chalk.green(` ✓ ${file} — merged cleanly`));
998
- }
999
- break;
1016
+ break;
1000
1017
  }
1001
- case 'conflict':
1002
- default:
1003
- fs.writeFileSync(destPath, createConflictContent(iContent, tContent), 'utf-8');
1004
- conflictCount++;
1005
- break;
1018
+ }
1019
+ for (const file of toAdd) {
1020
+ const destPath = path.join(instanceDir, file);
1021
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
1022
+ fs.copyFileSync(path.join(templateDir, file), destPath);
1023
+ }
1024
+ console.info(chalk.bold('\n✅ Template update complete!\n'));
1025
+ const stats = [];
1026
+ if (overwrittenCount > 0)
1027
+ stats.push(`${overwrittenCount} overwritten`);
1028
+ if (smartCount > 0)
1029
+ stats.push(`${smartCount} smart-merged`);
1030
+ if (mergedCount > 0)
1031
+ stats.push(`${mergedCount} merged`);
1032
+ if (conflictCount > 0)
1033
+ stats.push(`${conflictCount} with conflicts`);
1034
+ if (skippedCount > 0)
1035
+ stats.push(`${skippedCount} skipped`);
1036
+ if (toAdd.length > 0)
1037
+ stats.push(`${toAdd.length} added`);
1038
+ console.info(` ${stats.join(' | ')}\n`);
1039
+ if (conflictCount > 0) {
1040
+ console.info(chalk.yellow(`⚠️ ${conflictCount} files have conflict markers. ` +
1041
+ `Search for "<<<<<<< INSTANCE" to resolve them.\n`));
1006
1042
  }
1007
1043
  }
1008
- for (const file of toAdd) {
1009
- const destPath = path.join(instanceDir, file);
1010
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
1011
- fs.copyFileSync(path.join(templateDir, file), destPath);
1012
- }
1013
- console.info(chalk.bold('\n✅ Template update complete!\n'));
1014
- const stats = [];
1015
- if (overwrittenCount > 0)
1016
- stats.push(`${overwrittenCount} overwritten`);
1017
- if (smartCount > 0)
1018
- stats.push(`${smartCount} smart-merged`);
1019
- if (mergedCount > 0)
1020
- stats.push(`${mergedCount} merged`);
1021
- if (conflictCount > 0)
1022
- stats.push(`${conflictCount} with conflicts`);
1023
- if (skippedCount > 0)
1024
- stats.push(`${skippedCount} skipped`);
1025
- if (toAdd.length > 0)
1026
- stats.push(`${toAdd.length} added`);
1027
- console.info(` ${stats.join(' | ')}\n`);
1028
- if (conflictCount > 0) {
1029
- console.info(chalk.yellow(`⚠️ ${conflictCount} files have conflict markers. ` +
1030
- `Search for "<<<<<<< INSTANCE" to resolve them.\n`));
1044
+ else {
1045
+ console.info(chalk.gray('(dry-run mode, no template changes made)\n'));
1031
1046
  }
1032
1047
  }
1033
- else {
1034
- console.info(chalk.gray('(dry-run mode, no template changes made)\n'));
1035
- }
1048
+ }
1049
+ else {
1050
+ console.info(chalk.gray('\nSkipping template update (--no-template).\n'));
1036
1051
  }
1037
1052
  // 2. Sync .claude context (regardless of whether template had changes)
1038
- const claudeEnabled = ((_e = options.find((o) => o.name === 'claude-context')) === null || _e === void 0 ? void 0 : _e.value) !==
1039
- false;
1040
1053
  if (claudeEnabled) {
1041
- const cliRepo = ((_f = options.find((o) => o.name === 'claude-context-repo')) === null || _f === void 0 ? void 0 : _f.value) ||
1054
+ const cliRepo = ((_g = options.find((o) => o.name === 'coding-context-repo')) === null || _g === void 0 ? void 0 : _g.value) ||
1042
1055
  '';
1043
- const cliProtocol = ((_g = options.find((o) => o.name === 'claude-context-protocol')) === null || _g === void 0 ? void 0 : _g.value) || '';
1056
+ const cliProtocol = ((_h = options.find((o) => o.name === 'coding-context-protocol')) === null || _h === void 0 ? void 0 : _h.value) || '';
1044
1057
  const claudeSource = yield resolveClaudeContextSource(cliRepo, cliProtocol, autoYes);
1045
1058
  if (claudeSource) {
1046
1059
  yield syncClaudeContext(instanceDir, dryRun, claudeSource);
1047
1060
  }
1048
1061
  else {
1049
- console.info(chalk.gray('\nSkipping .claude context sync (per user choice / --no-claude-context).\n'));
1062
+ console.info(chalk.gray('\nSkipping .claude context sync (per user choice / --no-coding-context).\n'));
1050
1063
  }
1051
1064
  }
1052
1065
  else {
1053
- console.info(chalk.gray('\nSkipping .claude context sync (--no-claude-context).\n'));
1066
+ console.info(chalk.gray('\nSkipping .claude context sync (--no-coding-context).\n'));
1067
+ }
1068
+ // 3. If web/server package.json changed during template update, install deps.
1069
+ // Skipped entirely under --no-template (no snapshots taken → nothing to compare).
1070
+ if (pkgSnapshots) {
1071
+ yield maybeInstallChangedDeps(pkgSnapshots, dryRun);
1054
1072
  }
1055
- // 3. If web/server package.json changed during template update, install deps
1056
- yield maybeInstallChangedDeps(pkgSnapshots, dryRun);
1057
1073
  });
1058
1074
  }
1059
1075
  }
@@ -21,6 +21,9 @@ class UpdateCommand extends abstract_command_1.AbstractCommand {
21
21
  ' (none) Pull updates from template into instance, sync .claude → .claude-internal/.agent,\n' +
22
22
  ' and run install in web/ or server/ if their package.json changed.\n' +
23
23
  ' diff Show differences between instance and template (read-only).\n\n' +
24
+ ' Stage toggles (combine to run only what you want):\n' +
25
+ ' --no-template Skip stage 1 (template merge) and stage 3 (auto-install).\n' +
26
+ ' --no-coding-context Skip stage 2 (.claude context sync).\n\n' +
24
27
  ' Update strategies (per-file interactive prompt):\n' +
25
28
  ' skip Keep instance file as-is\n' +
26
29
  ' overwrite Replace with template version\n' +
@@ -31,9 +34,10 @@ class UpdateCommand extends abstract_command_1.AbstractCommand {
31
34
  .option('-y, --yes', '[update] Skip per-file prompt, use conflict markers for all.')
32
35
  .option('--no-smart-merge', '[update] Disable smart structural mergers; use line-level prompt for every file.')
33
36
  .option('--no-version-check', '[update | diff] Skip the npm registry version check at startup.')
34
- .option('--claude-context-repo <url>', '[update] Fully override the .claude context repo URL (highest priority).')
35
- .option('--claude-context-protocol <proto>', '[update] Force protocol for the built-in context repo. One of: https | ssh | skip.')
36
- .option('--no-claude-context', '[update] Skip the .claude context sync stage entirely.')
37
+ .option('--coding-context-repo <url>', '[update] Fully override the .claude context repo URL (highest priority).')
38
+ .option('--coding-context-protocol <proto>', '[update] Force protocol for the built-in context repo. One of: https | ssh | skip.')
39
+ .option('--no-coding-context', '[update] Skip the .claude context sync stage entirely.')
40
+ .option('--no-template', '[update] Skip the template merge stage and the auto-install stage; only run .claude context sync.')
37
41
  .action((subcommand, command) => __awaiter(this, void 0, void 0, function* () {
38
42
  const inputs = [];
39
43
  inputs.push({ name: 'subcommand', value: subcommand || '' });
@@ -44,17 +48,21 @@ class UpdateCommand extends abstract_command_1.AbstractCommand {
44
48
  options.push({ name: 'smart-merge', value: command.smartMerge !== false });
45
49
  options.push({ name: 'version-check', value: command.versionCheck !== false });
46
50
  options.push({
47
- name: 'claude-context-repo',
51
+ name: 'coding-context-repo',
48
52
  value: command.claudeContextRepo || '',
49
53
  });
50
54
  options.push({
51
- name: 'claude-context-protocol',
55
+ name: 'coding-context-protocol',
52
56
  value: command.claudeContextProtocol || '',
53
57
  });
54
58
  options.push({
55
- name: 'claude-context',
59
+ name: 'coding-context',
56
60
  value: command.claudeContext !== false,
57
61
  });
62
+ options.push({
63
+ name: 'template',
64
+ value: command.template !== false,
65
+ });
58
66
  yield this.action.handle(inputs, options);
59
67
  }));
60
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadmin2n/cli",
3
- "version": "0.0.103",
3
+ "version": "0.0.104",
4
4
  "description": "Gadmin - modern, fast, powerful node.js web framework (@cli)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -47,7 +47,7 @@
47
47
  "@angular-devkit/core": "13.3.2",
48
48
  "@angular-devkit/schematics": "13.3.2",
49
49
  "@angular-devkit/schematics-cli": "13.3.2",
50
- "@gadmin2n/schematics": "^0.0.85",
50
+ "@gadmin2n/schematics": "^0.0.86",
51
51
  "abc": "^0.6.1",
52
52
  "chalk": "3.0.0",
53
53
  "chokidar": "3.5.3",