@haposoft/cafekit 0.11.3 → 0.11.4

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/bin/install.js CHANGED
@@ -122,7 +122,7 @@ async function main() {
122
122
 
123
123
  try {
124
124
  ctx = buildContext(process.argv, `${Date.now()}`);
125
- ctx.ui.intro(`${ctx.ui.pc.bgCyan(ctx.ui.pc.black(' CafeKit '))}Installer v${packageJson.version} · Multi-platform SDD`);
125
+ ctx.ui.intro(`${ctx.ui.pc.bgCyan(ctx.ui.pc.black(' CafeKit '))}${ctx.ui.pc.gray(' Installer')} v${packageJson.version}\n ${ctx.ui.pc.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}\n ${ctx.ui.pc.blue('📦 ' + (ctx.t ? ctx.t('introDesc') : 'AI-native development workflow'))}`);
126
126
  if (got.reclaimed) ctx.ui.info(ctx.t('reclaimed'));
127
127
 
128
128
  await selectLanguage(ctx);
package/bin/lib/i18n.js CHANGED
@@ -37,6 +37,9 @@ const MESSAGES = {
37
37
  modeDryRun: 'Mode: dry-run • no changes will be written',
38
38
  modeInstall: 'Mode: install / update • your customisations are preserved',
39
39
 
40
+ // Intro
41
+ introDesc: 'AI-native development workflow for Claude Code',
42
+
40
43
  // Platform install spinner
41
44
  installingPlatform: 'Installing {name}',
42
45
  platformInstalled: '{name} — {files} file(s), {skills} skill(s)',
@@ -94,8 +97,15 @@ const MESSAGES = {
94
97
  outroDone: 'Done! docs: https://github.com/haposoft/cafekit',
95
98
 
96
99
  // Version check
97
- versionUpToDate: 'Already up to date ({v}). Use --force-overwrite to reinstall.',
98
- versionDowngrade: 'Downgrading {from} → {to}. Features may be removed. Continue?'
100
+ versionUpToDate: 'Already up to date ({v}). Use --force-overwrite to reinstall.',
101
+ versionDowngrade: 'Downgrading {from} → {to}. Features may be removed. Continue?',
102
+ versionSamePrompt: 'CafeKit {v} is already installed. What would you like to do?',
103
+ versionForceReinstall: 'Reinstalling CafeKit {v} (--force-overwrite)...',
104
+ versionUpgradePrompt: 'CafeKit {from} → {to}: Update available!',
105
+ updateOption: 'Update to {v}',
106
+ reinstallOption: 'Reinstall (overwrite managed files)',
107
+ reinstallCurrentOption: 'Reinstall {v}',
108
+ skipOption: 'Skip (exit)'
99
109
  },
100
110
 
101
111
  // ─── 日本語 ─────────────────────────────────────────────────────────────────
@@ -118,6 +128,9 @@ const MESSAGES = {
118
128
  modeDryRun: 'モード: ドライラン • ファイルへの変更はありません',
119
129
  modeInstall: 'モード: インストール / 更新 • カスタマイズは保持されます',
120
130
 
131
+ // Intro
132
+ introDesc: 'Claude Code 向け AI ネイティブ開発ワークフロー',
133
+
121
134
  installingPlatform: '{name} をインストール中',
122
135
  platformInstalled: '{name} — {files} ファイル、{skills} スキル',
123
136
  platformDryInstalled: '{name} — {files} ファイル、{skills} スキル [ドライラン]',
@@ -169,8 +182,15 @@ const MESSAGES = {
169
182
  dryRunOnly: 'ドライラン完了 — ファイルへの変更はありませんでした。\n 変更を適用するには --dry-run なしで再実行してください。',
170
183
  outroDone: '完了! ドキュメント: https://github.com/haposoft/cafekit',
171
184
 
172
- versionUpToDate: '最新バージョンです({v})。再インストールするには --force-overwrite を使用してください。',
173
- versionDowngrade: '{from} → {to} へのダウングレードです。機能が削除される可能性があります。続けますか?'
185
+ versionUpToDate: '最新バージョンです({v})。再インストールするには --force-overwrite を使用してください。',
186
+ versionDowngrade: '{from} → {to} へのダウングレードです。機能が削除される可能性があります。続けますか?',
187
+ versionSamePrompt: 'CafeKit {v} は既にインストールされています。何をしますか?',
188
+ versionForceReinstall: 'CafeKit {v} を再インストール中 (--force-overwrite)...',
189
+ versionUpgradePrompt: 'CafeKit {from} → {to}: アップデートが利用可能です!',
190
+ updateOption: '{v} にアップデート',
191
+ reinstallOption: '再インストール(管理対象ファイルを上書き)',
192
+ reinstallCurrentOption: '{v} を再インストール',
193
+ skipOption: 'スキップ(終了)'
174
194
  },
175
195
 
176
196
  // ─── Tiếng Việt ─────────────────────────────────────────────────────────────
@@ -193,6 +213,9 @@ const MESSAGES = {
193
213
  modeDryRun: 'Chế độ: dry-run • sẽ không thay đổi bất kỳ tệp nào',
194
214
  modeInstall: 'Chế độ: cài / cập nhật • nội dung bạn tuỳ chỉnh được giữ nguyên',
195
215
 
216
+ // Intro
217
+ introDesc: 'Quy trình phát triển AI-native cho Claude Code',
218
+
196
219
  installingPlatform: 'Đang cài {name}',
197
220
  platformInstalled: '{name} — {files} tệp, {skills} skill',
198
221
  platformDryInstalled: '{name} — {files} tệp, {skills} skill [dry-run]',
@@ -244,8 +267,15 @@ const MESSAGES = {
244
267
  dryRunOnly: 'Dry-run hoàn tất — không có tệp nào thay đổi.\n Chạy lại không có --dry-run để áp dụng.',
245
268
  outroDone: 'Xong! Tài liệu: https://github.com/haposoft/cafekit',
246
269
 
247
- versionUpToDate: 'Đã là phiên bản mới nhất ({v}). Dùng --force-overwrite để cài lại.',
248
- versionDowngrade: 'Đang hạ cấp {from} → {to}. Một số tính năng có thể bị xoá. Tiếp tục?'
270
+ versionUpToDate: 'Đã là phiên bản mới nhất ({v}). Dùng --force-overwrite để cài lại.',
271
+ versionDowngrade: 'Đang hạ cấp {from} → {to}. Một số tính năng có thể bị xoá. Tiếp tục?',
272
+ versionSamePrompt: 'CafeKit {v} đã được cài đặt. Bạn muốn làm gì?',
273
+ versionForceReinstall: 'Đang cài lại CafeKit {v} (--force-overwrite)...',
274
+ versionUpgradePrompt: 'CafeKit {from} → {to}: Có bản cập nhật mới!',
275
+ updateOption: 'Cập nhật lên {v}',
276
+ reinstallOption: 'Cài lại (ghi đè file được quản lý)',
277
+ reinstallCurrentOption: 'Cài lại {v}',
278
+ skipOption: 'Bỏ qua (thoát)'
249
279
  }
250
280
  };
251
281
 
@@ -43,46 +43,129 @@ function getInstalledVersion(platformKey) {
43
43
  /**
44
44
  * Check versions for all selected platforms and decide whether to proceed.
45
45
  * Sets ctx.cancelled on same-version (without --force) or unconfirmed downgrade.
46
+ * Shows interactive prompt when version differs, asking user what to do.
46
47
  */
47
48
  async function checkVersions(ctx) {
48
49
  if (ctx.dryRun) return ctx;
49
50
 
50
51
  const incoming = packageJson.version;
52
+ const platformsWithInstall = [];
51
53
 
52
54
  for (const key of ctx.platforms) {
53
55
  const installed = getInstalledVersion(key);
54
- if (!installed) continue; // fresh install — no check needed
56
+ if (installed) {
57
+ platformsWithInstall.push({ key, installed });
58
+ }
59
+ }
60
+
61
+ // All fresh installs - skip version check, proceed normally
62
+ if (platformsWithInstall.length === 0) {
63
+ return ctx;
64
+ }
65
+
66
+ // Get unique versions across all platforms
67
+ const uniqueVersions = [...new Set(platformsWithInstall.map(p => p.installed))];
68
+ const installedVersion = uniqueVersions.length === 1 ? uniqueVersions[0] : `${uniqueVersions.join(', ')}`;
69
+
70
+ // Determine overall comparison (assuming same version across platforms)
71
+ const firstPlatform = platformsWithInstall[0];
72
+ const cmp = cmpVersion(firstPlatform.installed, incoming);
73
+
74
+ // ── Same version ───────────────────────────────────────────────────────────
75
+ if (cmp === 0) {
76
+ if (ctx.options.forceOverwrite) {
77
+ ctx.ui.info(ctx.t ? ctx.t('versionForceReinstall', { v: installedVersion }) : `Reinstalling CafeKit ${installedVersion} (--force-overwrite)...`);
78
+ return ctx;
79
+ }
80
+
81
+ if (!ctx.interactive) {
82
+ ctx.ui.info(ctx.t ? ctx.t('versionUpToDate', { v: installedVersion }) : `CafeKit ${installedVersion} is already up to date. Use --force-overwrite to reinstall.`);
83
+ ctx.cancelled = true;
84
+ return ctx;
85
+ }
86
+
87
+ // Show current vs new and ask what to do
88
+ const { isCancel } = await import('@clack/prompts');
89
+ const { default: select } = await import('@clack/prompts');
90
+
91
+ const options = [
92
+ { value: 'reinstall', label: ctx.t ? ctx.t('reinstallOption') : 'Reinstall (overwrite managed files)' },
93
+ { value: 'skip', label: ctx.t ? ctx.t('skipOption') : 'Skip (exit)' }
94
+ ];
55
95
 
56
- const cmp = cmpVersion(installed, incoming);
96
+ const answer = await select({
97
+ message: ctx.t
98
+ ? ctx.t('versionSamePrompt', { v: installedVersion })
99
+ : `CafeKit ${installedVersion} is already installed. What do you want to do?`,
100
+ options
101
+ });
57
102
 
58
- // ── Same version ─────────────────────────────────────────────────────────
59
- if (cmp === 0) {
60
- if (ctx.options.forceOverwrite) continue; // --force-overwrite overrides
61
- ctx.ui.info(ctx.t ? ctx.t('versionUpToDate', { v: installed }) : `Already up to date (${installed}). Use --force-overwrite to reinstall.`);
103
+ if (isCancel(answer) || answer === 'skip') {
62
104
  ctx.cancelled = true;
63
105
  return ctx;
64
106
  }
65
107
 
66
- // ── Downgrade ─────────────────────────────────────────────────────────────
67
- if (cmp > 0) {
68
- const msg = ctx.t
69
- ? ctx.t('versionDowngrade', { from: installed, to: incoming })
70
- : `Downgrading ${installed} → ${incoming}. This may remove features. Continue?`;
71
-
72
- if (!ctx.interactive) {
73
- ctx.ui.warn ? ctx.ui.warn(`Downgrade detected (${installed} → ${incoming}). Aborted in non-interactive mode. Use --force-overwrite to proceed.`) : console.warn(msg);
74
- ctx.cancelled = true;
75
- return ctx;
76
- }
77
-
78
- const yes = await ctx.ui.confirm({ message: msg, initialValue: false }, false);
79
- if (!yes || ctx.ui.isCancel(yes)) {
80
- ctx.cancelled = true;
81
- return ctx;
82
- }
108
+ if (answer === 'reinstall') {
109
+ ctx.options.forceOverwrite = true;
110
+ }
111
+
112
+ return ctx;
113
+ }
114
+
115
+ // ── Upgrade available ───────────────────────────────────────────────────────
116
+ if (cmp < 0) {
117
+ if (!ctx.interactive) {
118
+ // Non-interactive: proceed with upgrade automatically
119
+ return ctx;
83
120
  }
84
121
 
85
- // cmp < 0 → upgrade, proceed normally
122
+ // Show current vs new and ask what to do
123
+ const { isCancel } = await import('@clack/prompts');
124
+ const { default: select } = await import('@clack/prompts');
125
+
126
+ const options = [
127
+ { value: 'update', label: ctx.t ? ctx.t('updateOption') : `Update to ${incoming}` },
128
+ { value: 'reinstall', label: ctx.t ? ctx.t('reinstallCurrentOption', { v: firstPlatform.installed }) : `Reinstall ${firstPlatform.installed}` },
129
+ { value: 'skip', label: ctx.t ? ctx.t('skipOption') : 'Skip (exit)' }
130
+ ];
131
+
132
+ const answer = await select({
133
+ message: ctx.t
134
+ ? ctx.t('versionUpgradePrompt', { from: firstPlatform.installed, to: incoming })
135
+ : `CafeKit ${firstPlatform.installed} → ${incoming}: Update available!`,
136
+ options
137
+ });
138
+
139
+ if (isCancel(answer) || answer === 'skip') {
140
+ ctx.cancelled = true;
141
+ return ctx;
142
+ }
143
+
144
+ if (answer === 'reinstall') {
145
+ ctx.options.forceOverwrite = true;
146
+ }
147
+
148
+ // 'update' proceeds normally (no special flag needed)
149
+ return ctx;
150
+ }
151
+
152
+ // ── Downgrade ──────────────────────────────────────────────────────────────
153
+ if (cmp > 0) {
154
+ const msg = ctx.t
155
+ ? ctx.t('versionDowngrade', { from: firstPlatform.installed, to: incoming })
156
+ : `Downgrading ${firstPlatform.installed} → ${incoming}. This may remove features.`;
157
+
158
+ if (!ctx.interactive) {
159
+ ctx.ui.warn ? ctx.ui.warn(msg + ' Downgrade aborted in non-interactive mode. Use --force-overwrite to proceed.') : console.warn(msg);
160
+ ctx.cancelled = true;
161
+ return ctx;
162
+ }
163
+
164
+ const yes = await ctx.ui.confirm({ message: msg + ' Continue?', initialValue: false });
165
+ if (!yes || ctx.ui.isCancel(yes)) {
166
+ ctx.cancelled = true;
167
+ return ctx;
168
+ }
86
169
  }
87
170
 
88
171
  return ctx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haposoft/cafekit",
3
- "version": "0.11.3",
3
+ "version": "0.11.4",
4
4
  "description": "Claude Code-first spec-driven workflow for AI coding assistants. Bundles CafeKit hapo: skills, runtime hooks, agents, and installer scaffolding.",
5
5
  "author": "Haposoft <nghialt@haposoft.com>",
6
6
  "license": "MIT",