claude-cli-advanced-starter-pack 1.8.4 → 1.8.6

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.
@@ -20,6 +20,7 @@ import {
20
20
  ensureQueueDir,
21
21
  } from '../panel/queue.js';
22
22
  import { getVersion } from '../utils.js';
23
+ import { isHappyMode } from '../utils/happy-detect.js';
23
24
 
24
25
  // Panel ASCII Banner
25
26
  const PANEL_BANNER = `
@@ -249,8 +250,15 @@ export async function runPanel(options = {}) {
249
250
 
250
251
  /**
251
252
  * Launch panel in a new terminal window
253
+ * Automatically detects Happy CLI and falls back to inline mode
252
254
  */
253
255
  export async function launchPanel() {
256
+ // If Happy mode detected, use inline panel instead of new window
257
+ if (isHappyMode()) {
258
+ console.log(chalk.cyan('\n Happy CLI detected - using inline panel\n'));
259
+ return launchPanelInline();
260
+ }
261
+
254
262
  console.log(chalk.cyan('\n Launching CCASP Panel in new window...\n'));
255
263
 
256
264
  const ccaspPath = join(process.cwd(), 'node_modules', '.bin', 'ccasp');
@@ -295,3 +303,79 @@ export async function launchPanel() {
295
303
  console.log(chalk.dim(` Run manually: ${chalk.white('ccasp panel')}\n`));
296
304
  }
297
305
  }
306
+
307
+ /**
308
+ * Launch panel inline (mobile-friendly, no new window)
309
+ * Used when Happy CLI is detected or explicitly requested
310
+ */
311
+ export async function launchPanelInline() {
312
+ const MOBILE_PANEL_BANNER = `
313
+ ${chalk.cyan('╔══════════════════════════════════╗')}
314
+ ${chalk.cyan('║')} ${chalk.bold('Panel')} ${chalk.dim('(inline)')}${' '.repeat(17)}${chalk.cyan('║')}
315
+ ${chalk.cyan('╚══════════════════════════════════╝')}`;
316
+
317
+ console.clear();
318
+ console.log(MOBILE_PANEL_BANNER);
319
+ console.log('');
320
+
321
+ // Simplified single-column panel for mobile
322
+ const sections = [
323
+ { header: 'Agents', items: [
324
+ { key: 'A', label: 'Create Agent', cmd: '/create-agent' },
325
+ { key: 'H', label: 'Create Hook', cmd: '/create-hook' },
326
+ { key: 'S', label: 'Create Skill', cmd: '/create-skill' },
327
+ { key: 'M', label: 'Explore MCP', cmd: '/explore-mcp' },
328
+ ]},
329
+ { header: 'Actions', items: [
330
+ { key: 'P', label: 'Phase Dev', cmd: '/phase-dev-plan' },
331
+ { key: 'G', label: 'GitHub Task', cmd: '/github-task' },
332
+ { key: 'T', label: 'E2E Tests', cmd: '/e2e-test' },
333
+ ]},
334
+ ];
335
+
336
+ // Build choices
337
+ const choices = [];
338
+ for (const section of sections) {
339
+ choices.push(new inquirer.Separator(chalk.cyan(` ${section.header}`)));
340
+ for (const item of section.items) {
341
+ choices.push({
342
+ name: `${chalk.yellow(item.key + ')')} ${item.label}`,
343
+ value: item.cmd,
344
+ });
345
+ }
346
+ }
347
+ choices.push(new inquirer.Separator(chalk.dim('─'.repeat(34))));
348
+ choices.push({ name: `${chalk.yellow('B)')} Back`, value: 'back' });
349
+
350
+ const { action } = await inquirer.prompt([{
351
+ type: 'list',
352
+ name: 'action',
353
+ message: 'Select:',
354
+ choices,
355
+ pageSize: 12,
356
+ }]);
357
+
358
+ if (action === 'back') {
359
+ return;
360
+ }
361
+
362
+ // Show command and copy to clipboard
363
+ console.log('');
364
+ console.log(chalk.cyan(`Command: ${action}`));
365
+
366
+ const copied = copyToClipboard(action);
367
+ if (copied) {
368
+ console.log(chalk.green('✓ Copied to clipboard'));
369
+ }
370
+ console.log(chalk.dim('Paste in Claude Code'));
371
+ console.log('');
372
+
373
+ await inquirer.prompt([{
374
+ type: 'input',
375
+ name: 'continue',
376
+ message: 'Enter to continue...',
377
+ }]);
378
+
379
+ // Loop back to panel
380
+ return launchPanelInline();
381
+ }
@@ -578,43 +578,60 @@ function showSetupHeader() {
578
578
  }
579
579
 
580
580
  /**
581
- * Quick setup options - numbered for easy mobile input
581
+ * Streamlined setup options - 3 core paths for easy mobile input
582
+ * Issue #8: Simplified from 7 options to reduce scrolling
582
583
  */
583
584
  const SETUP_OPTIONS = [
584
585
  {
585
- name: `${chalk.yellow('1.')} Quick Start ${chalk.dim('- Detect stack + init .claude')}`,
586
- value: 'quick',
587
- short: 'Quick Start',
586
+ name: `${chalk.green('1.')} Auto Install ${chalk.dim('- Full features + backup (recommended)')}`,
587
+ value: 'auto',
588
+ short: 'Auto Install',
588
589
  },
589
590
  {
590
- name: `${chalk.yellow('2.')} Full Setup ${chalk.dim('- All features + customization')}`,
591
- value: 'full',
592
- short: 'Full Setup',
593
- },
594
- {
595
- name: `${chalk.yellow('3.')} GitHub Setup ${chalk.dim('- Connect project board')}`,
591
+ name: `${chalk.yellow('2.')} GitHub Setup ${chalk.dim('- Connect project board')}`,
596
592
  value: 'github',
597
593
  short: 'GitHub',
598
594
  },
599
595
  {
600
- name: `${chalk.yellow('4.')} View Templates ${chalk.dim('- Browse available items')}`,
596
+ name: `${chalk.dim('3.')} More Options ${chalk.dim('- Templates, releases, remove')}`,
597
+ value: 'more',
598
+ short: 'More',
599
+ },
600
+ {
601
+ name: `${chalk.dim('0.')} Exit`,
602
+ value: 'exit',
603
+ short: 'Exit',
604
+ },
605
+ ];
606
+
607
+ /**
608
+ * Advanced options submenu - accessed via "More Options"
609
+ */
610
+ const ADVANCED_OPTIONS = [
611
+ {
612
+ name: `${chalk.yellow('1.')} Custom Setup ${chalk.dim('- Choose specific features')}`,
613
+ value: 'custom',
614
+ short: 'Custom',
615
+ },
616
+ {
617
+ name: `${chalk.yellow('2.')} View Templates ${chalk.dim('- Browse available items')}`,
601
618
  value: 'templates',
602
619
  short: 'Templates',
603
620
  },
604
621
  {
605
- name: `${chalk.yellow('5.')} Prior Releases ${chalk.dim('- Review & add features from past versions')}`,
622
+ name: `${chalk.yellow('3.')} Prior Releases ${chalk.dim('- Add features from past versions')}`,
606
623
  value: 'releases',
607
624
  short: 'Releases',
608
625
  },
609
626
  {
610
- name: `${chalk.yellow('6.')} Remove CCASP ${chalk.dim('- Uninstall from this project')}`,
627
+ name: `${chalk.yellow('4.')} Remove CCASP ${chalk.dim('- Uninstall from this project')}`,
611
628
  value: 'remove',
612
629
  short: 'Remove',
613
630
  },
614
631
  {
615
- name: `${chalk.yellow('0.')} Exit`,
616
- value: 'exit',
617
- short: 'Exit',
632
+ name: `${chalk.dim('0.')} Back`,
633
+ value: 'back',
634
+ short: 'Back',
618
635
  },
619
636
  ];
620
637
 
@@ -1292,7 +1309,7 @@ export async function runSetupWizard(options = {}) {
1292
1309
  console.log(chalk.green('✓ CLAUDE.md exists\n'));
1293
1310
  }
1294
1311
 
1295
- // Main menu loop
1312
+ // Main menu loop - streamlined 3-path flow (Issue #8)
1296
1313
  let running = true;
1297
1314
  while (running) {
1298
1315
  const { action } = await inquirer.prompt([
@@ -1301,28 +1318,67 @@ export async function runSetupWizard(options = {}) {
1301
1318
  name: 'action',
1302
1319
  message: 'What would you like to do?',
1303
1320
  choices: SETUP_OPTIONS,
1304
- pageSize: 12,
1321
+ pageSize: 6, // All options visible without scrolling
1305
1322
  },
1306
1323
  ]);
1307
1324
 
1308
1325
  switch (action) {
1309
- case 'quick':
1310
- const quickSuccess = await runQuickSetup();
1311
- if (quickSuccess) running = false;
1312
- break;
1313
-
1314
- case 'full':
1315
- await runInit({ interactive: true });
1326
+ case 'auto':
1327
+ // Auto Install: Full features with mandatory backup (Issue #8 requirement)
1328
+ console.log(chalk.cyan('\n📦 Auto Install Mode - Full features with backup\n'));
1329
+ await runInit({
1330
+ interactive: false,
1331
+ backup: true, // Mandatory backup
1332
+ force: true, // Overwrite enabled for testing phase
1333
+ skipPrompts: true,
1334
+ preset: 'full' // All features
1335
+ });
1316
1336
  showRestartReminder();
1317
1337
  running = false;
1318
1338
  break;
1319
1339
 
1320
1340
  case 'github':
1321
1341
  await runGitHubSetup({});
1322
- // GitHub setup modifies .claude/ config
1323
1342
  showRestartReminder();
1324
1343
  break;
1325
1344
 
1345
+ case 'more':
1346
+ // Advanced options submenu
1347
+ await showAdvancedOptions();
1348
+ break;
1349
+
1350
+ case 'exit':
1351
+ running = false;
1352
+ console.log(chalk.dim('\nRun `ccasp wizard` anytime to return.\n'));
1353
+ break;
1354
+ }
1355
+ }
1356
+ }
1357
+
1358
+ /**
1359
+ * Advanced options submenu - Issue #8: Moved less-used options here
1360
+ */
1361
+ async function showAdvancedOptions() {
1362
+ let inSubmenu = true;
1363
+
1364
+ while (inSubmenu) {
1365
+ const { action } = await inquirer.prompt([
1366
+ {
1367
+ type: 'list',
1368
+ name: 'action',
1369
+ message: 'Advanced Options:',
1370
+ choices: ADVANCED_OPTIONS,
1371
+ pageSize: 6,
1372
+ },
1373
+ ]);
1374
+
1375
+ switch (action) {
1376
+ case 'custom':
1377
+ await runInit({ interactive: true });
1378
+ showRestartReminder();
1379
+ inSubmenu = false;
1380
+ break;
1381
+
1326
1382
  case 'templates':
1327
1383
  await showTemplates();
1328
1384
  break;
@@ -1334,13 +1390,12 @@ export async function runSetupWizard(options = {}) {
1334
1390
  case 'remove':
1335
1391
  const removed = await runRemove();
1336
1392
  if (removed) {
1337
- running = false; // Exit wizard after removal
1393
+ inSubmenu = false;
1338
1394
  }
1339
1395
  break;
1340
1396
 
1341
- case 'exit':
1342
- running = false;
1343
- console.log(chalk.dim('\nRun `ccasp wizard` anytime to return.\n'));
1397
+ case 'back':
1398
+ inSubmenu = false;
1344
1399
  break;
1345
1400
  }
1346
1401
  }
@@ -1,5 +1,35 @@
1
1
  {
2
2
  "releases": [
3
+ {
4
+ "version": "1.8.6",
5
+ "date": "2026-01-31",
6
+ "summary": "Release notes pending",
7
+ "highlights": [],
8
+ "newFeatures": {
9
+ "commands": [],
10
+ "agents": [],
11
+ "skills": [],
12
+ "hooks": [],
13
+ "other": []
14
+ },
15
+ "breaking": [],
16
+ "deprecated": []
17
+ },
18
+ {
19
+ "version": "1.8.5",
20
+ "date": "2026-01-31",
21
+ "summary": "Release notes pending",
22
+ "highlights": [],
23
+ "newFeatures": {
24
+ "commands": [],
25
+ "agents": [],
26
+ "skills": [],
27
+ "hooks": [],
28
+ "other": []
29
+ },
30
+ "breaking": [],
31
+ "deprecated": []
32
+ },
3
33
  {
4
34
  "version": "1.8.4",
5
35
  "date": "2026-01-31",
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Happy CLI Detection Utility
3
+ *
4
+ * Detects if CCASP is running inside Happy Coder mobile CLI wrapper.
5
+ * Happy CLI sets HAPPY_* environment variables when active.
6
+ *
7
+ * @see https://github.com/slopus/happy-cli
8
+ */
9
+
10
+ /**
11
+ * Check if running inside Happy CLI environment
12
+ * @returns {boolean} True if Happy CLI detected
13
+ */
14
+ export function isHappyMode() {
15
+ return !!(
16
+ process.env.HAPPY_HOME_DIR ||
17
+ process.env.HAPPY_SERVER_URL ||
18
+ process.env.HAPPY_WEBAPP_URL ||
19
+ process.env.HAPPY_EXPERIMENTAL
20
+ );
21
+ }
22
+
23
+ /**
24
+ * Get Happy CLI configuration from environment
25
+ * @returns {object} Happy configuration details
26
+ */
27
+ export function getHappyConfig() {
28
+ return {
29
+ detected: isHappyMode(),
30
+ homeDir: process.env.HAPPY_HOME_DIR || null,
31
+ serverUrl: process.env.HAPPY_SERVER_URL || 'https://api.cluster-fluster.com',
32
+ webappUrl: process.env.HAPPY_WEBAPP_URL || 'https://app.happy.engineering',
33
+ experimental: process.env.HAPPY_EXPERIMENTAL === 'true',
34
+ disableCaffeinate: process.env.HAPPY_DISABLE_CAFFEINATE === 'true',
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Get recommended terminal width for mobile display
40
+ * @returns {number} Optimal width for mobile screens
41
+ */
42
+ export function getMobileWidth() {
43
+ // Happy mobile UI typically works best at 40 chars
44
+ // to avoid horizontal scrolling on phone screens
45
+ return 40;
46
+ }
47
+
48
+ /**
49
+ * Check if we should use mobile-optimized UI
50
+ * Respects both Happy CLI detection and tech-stack.json happyMode.enabled
51
+ * @param {object} techStack - Optional tech-stack.json config
52
+ * @returns {boolean} True if mobile UI should be used
53
+ */
54
+ export function shouldUseMobileUI(techStack = null) {
55
+ // Auto-detect Happy CLI environment
56
+ if (isHappyMode()) {
57
+ return true;
58
+ }
59
+
60
+ // Check tech-stack.json happyMode.enabled setting
61
+ if (techStack?.happyMode?.enabled) {
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
@@ -19,8 +19,9 @@ const PACKAGE_NAME = 'claude-cli-advanced-starter-pack';
19
19
  // Cache duration: 1 hour (in milliseconds)
20
20
  const CACHE_DURATION = 60 * 60 * 1000;
21
21
 
22
- // Update notification duration: 1 day (in milliseconds)
23
- const UPDATE_NOTIFICATION_DURATION = 24 * 60 * 60 * 1000;
22
+ // Update notification reminder: Show reminder again after 7 days
23
+ // Issue #8: Changed from 1-day suppression to 7-day reminder
24
+ const UPDATE_NOTIFICATION_REMINDER = 7 * 24 * 60 * 60 * 1000;
24
25
 
25
26
  /**
26
27
  * Get the current installed version from package.json
@@ -313,19 +314,52 @@ export function compareVersions(v1, v2) {
313
314
  /**
314
315
  * Check npm registry for the latest version
315
316
  * Returns null if check fails (network error, etc.)
317
+ * Issue #8: Added npm registry API fallback for Windows compatibility
316
318
  */
317
319
  export async function checkLatestVersion() {
320
+ // Try npm CLI first
318
321
  try {
319
- // Use npm view command to get latest version
320
322
  const result = execSync(`npm view ${PACKAGE_NAME} version`, {
321
323
  encoding: 'utf8',
322
- timeout: 10000, // 10 second timeout
324
+ timeout: 10000,
323
325
  stdio: ['pipe', 'pipe', 'pipe'],
324
326
  });
325
327
 
326
- return result.trim();
328
+ const version = result.trim();
329
+ if (version && /^\d+\.\d+\.\d+/.test(version)) {
330
+ return version;
331
+ }
332
+ } catch {
333
+ // npm CLI failed, try fallback
334
+ }
335
+
336
+ // Fallback: Direct npm registry API call (Issue #8 fix)
337
+ try {
338
+ const https = await import('https');
339
+ return new Promise((resolve) => {
340
+ const req = https.default.get(
341
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
342
+ { timeout: 8000 },
343
+ (res) => {
344
+ let data = '';
345
+ res.on('data', (chunk) => (data += chunk));
346
+ res.on('end', () => {
347
+ try {
348
+ const pkg = JSON.parse(data);
349
+ resolve(pkg.version || null);
350
+ } catch {
351
+ resolve(null);
352
+ }
353
+ });
354
+ }
355
+ );
356
+ req.on('error', () => resolve(null));
357
+ req.on('timeout', () => {
358
+ req.destroy();
359
+ resolve(null);
360
+ });
361
+ });
327
362
  } catch {
328
- // Silently fail - network might be unavailable
329
363
  return null;
330
364
  }
331
365
  }
@@ -436,17 +470,9 @@ export function shouldShowUpdateNotification(state, latestVersion) {
436
470
  return false;
437
471
  }
438
472
 
439
- // Check if we have a cached check result with timestamp
440
- if (state.lastCheckResult && state.lastCheckTimestamp) {
441
- const timeSinceCheck = Date.now() - state.lastCheckTimestamp;
442
-
443
- // If check is more than 1 day old, don't show notification
444
- // (user needs to run check again to see new updates)
445
- if (timeSinceCheck > UPDATE_NOTIFICATION_DURATION) {
446
- return false;
447
- }
448
- }
449
-
473
+ // Issue #8: Always show notification if update is available
474
+ // The old logic suppressed notifications after 1 day, which was counterproductive
475
+ // Now we always show if there's an update, regardless of cache age
450
476
  return true;
451
477
  }
452
478
 
@@ -197,6 +197,78 @@ gh issue edit [NUMBER] --body "$(gh issue view [NUMBER] --json body -q .body)
197
197
 
198
198
  ---
199
199
 
200
+ ### Step 7: After Task Completion - Close Issue Prompt
201
+
202
+ **CRITICAL: After ALL TodoWrite tasks are marked complete AND a commit is created, ALWAYS offer to close the issue.**
203
+
204
+ This step triggers when:
205
+ 1. All tasks in TodoWrite are marked `completed`
206
+ 2. A git commit has been made with changes
207
+
208
+ Display completion summary:
209
+
210
+ ```
211
+ ╔═══════════════════════════════════════════════════════════════╗
212
+ ║ ✅ All Tasks Completed ║
213
+ ╠═══════════════════════════════════════════════════════════════╣
214
+ ║ ║
215
+ ║ Issue: #[NUMBER] - [TITLE] ║
216
+ ║ Commit: [SHORT_SHA] - [COMMIT_MSG_FIRST_LINE] ║
217
+ ║ Tasks: [X] completed ║
218
+ ║ ║
219
+ ╠═══════════════════════════════════════════════════════════════╣
220
+ ║ [C] Close issue with comment ║
221
+ ║ [P] Push to origin + close issue ║
222
+ ║ [K] Keep issue open ║
223
+ ╚═══════════════════════════════════════════════════════════════╝
224
+ ```
225
+
226
+ Then ask:
227
+
228
+ ```
229
+ header: "Issue"
230
+ question: "All tasks complete. Close issue #[NUMBER]?"
231
+ options:
232
+ - label: "C - Close with comment"
233
+ description: "Add completion summary and close"
234
+ - label: "P - Push + Close"
235
+ description: "Push commit to origin, then close"
236
+ - label: "K - Keep open"
237
+ description: "Leave issue open for follow-up"
238
+ ```
239
+
240
+ **Handle Close Actions:**
241
+
242
+ **C (Close with comment):**
243
+ ```bash
244
+ gh issue close [NUMBER] --comment "All tasks completed in commit [SHA].
245
+
246
+ ## Completed Tasks
247
+ - ✅ Task 1
248
+ - ✅ Task 2
249
+ ...
250
+
251
+ Ready for release."
252
+ ```
253
+
254
+ **P (Push + Close):**
255
+ ```bash
256
+ git push origin HEAD
257
+ gh issue close [NUMBER] --comment "All tasks completed and pushed in commit [SHA].
258
+
259
+ ## Completed Tasks
260
+ - ✅ Task 1
261
+ - ✅ Task 2
262
+ ...
263
+
264
+ Ready for release."
265
+ ```
266
+
267
+ **K (Keep open):**
268
+ Display: "Issue #[NUMBER] kept open for follow-up."
269
+
270
+ ---
271
+
200
272
  ## ERROR HANDLING
201
273
 
202
274
  | Error | Action |
@@ -874,6 +874,79 @@ After all tasks are complete, display a summary:
874
874
 
875
875
  ---
876
876
 
877
+ ## CLOSE ISSUE PROMPT (When Working From GitHub Issue)
878
+
879
+ **CRITICAL: If this task list was created for a GitHub issue, ALWAYS offer to close the issue after ALL TodoWrite tasks are marked complete AND a commit is created.**
880
+
881
+ This step triggers when:
882
+ 1. The task list originated from a GitHub issue (via `/create-task-list for issue #N` or `/menu-issues-list`)
883
+ 2. All tasks in TodoWrite are marked `completed`
884
+ 3. A git commit has been made with changes
885
+
886
+ Display completion summary:
887
+
888
+ ```
889
+ ╔═══════════════════════════════════════════════════════════════╗
890
+ ║ ✅ All Tasks Completed ║
891
+ ╠═══════════════════════════════════════════════════════════════╣
892
+ ║ ║
893
+ ║ Issue: #[NUMBER] - [TITLE] ║
894
+ ║ Commit: [SHORT_SHA] - [COMMIT_MSG_FIRST_LINE] ║
895
+ ║ Tasks: [X] completed ║
896
+ ║ ║
897
+ ╠═══════════════════════════════════════════════════════════════╣
898
+ ║ [C] Close issue with comment ║
899
+ ║ [P] Push to origin + close issue ║
900
+ ║ [K] Keep issue open ║
901
+ ╚═══════════════════════════════════════════════════════════════╝
902
+ ```
903
+
904
+ Then ask:
905
+
906
+ ```
907
+ header: "Issue"
908
+ question: "All tasks complete. Close issue #[NUMBER]?"
909
+ options:
910
+ - label: "C - Close with comment"
911
+ description: "Add completion summary and close"
912
+ - label: "P - Push + Close"
913
+ description: "Push commit to origin, then close"
914
+ - label: "K - Keep open"
915
+ description: "Leave issue open for follow-up"
916
+ ```
917
+
918
+ **Handle Close Actions:**
919
+
920
+ **C (Close with comment):**
921
+ ```bash
922
+ gh issue close [NUMBER] --comment "All tasks completed in commit [SHA].
923
+
924
+ ## Completed Tasks
925
+ - ✅ Task 1
926
+ - ✅ Task 2
927
+ ...
928
+
929
+ Ready for release."
930
+ ```
931
+
932
+ **P (Push + Close):**
933
+ ```bash
934
+ git push origin HEAD
935
+ gh issue close [NUMBER] --comment "All tasks completed and pushed in commit [SHA].
936
+
937
+ ## Completed Tasks
938
+ - ✅ Task 1
939
+ - ✅ Task 2
940
+ ...
941
+
942
+ Ready for release."
943
+ ```
944
+
945
+ **K (Keep open):**
946
+ Display: "Issue #[NUMBER] kept open for follow-up."
947
+
948
+ ---
949
+
877
950
  ## ERROR HANDLING
878
951
 
879
952
  | Situation | Action |