create-claude-workspace 2.3.20 → 2.3.21

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.
@@ -18,6 +18,90 @@ export function detectCIPlatform(projectDir) {
18
18
  catch { /* ignore */ }
19
19
  return 'none';
20
20
  }
21
+ /**
22
+ * Check if the CLI tool for a given platform is installed and authenticated.
23
+ * Returns null if OK, or an error message describing what's missing.
24
+ */
25
+ export function checkPlatformCLI(platform) {
26
+ if (platform === 'none')
27
+ return null;
28
+ const cli = platform === 'github' ? 'gh' : 'glab';
29
+ // Check if binary exists
30
+ try {
31
+ execFileSync(cli, ['--version'], { stdio: 'pipe', timeout: 10_000 });
32
+ }
33
+ catch (err) {
34
+ const code = err.code;
35
+ if (code === 'ENOENT') {
36
+ return `${cli} CLI is not installed`;
37
+ }
38
+ return `${cli} CLI error: ${err.message?.split('\n')[0]}`;
39
+ }
40
+ // Check if authenticated
41
+ try {
42
+ if (platform === 'github') {
43
+ execFileSync('gh', ['auth', 'status'], { stdio: 'pipe', timeout: 10_000 });
44
+ }
45
+ else {
46
+ // glab doesn't have a clean auth status command — try a harmless API call
47
+ execFileSync('glab', ['api', 'version'], { stdio: 'pipe', timeout: 10_000 });
48
+ }
49
+ }
50
+ catch {
51
+ return `${cli} CLI is installed but not authenticated — run: ${cli} auth login`;
52
+ }
53
+ return null;
54
+ }
55
+ /**
56
+ * Attempt to install the CLI tool for a given platform.
57
+ * Returns true if installation succeeded, false otherwise.
58
+ * Tries multiple installation methods depending on the OS.
59
+ */
60
+ export function installPlatformCLI(platform) {
61
+ if (platform === 'none')
62
+ return { success: false, error: 'No platform detected' };
63
+ const cli = platform === 'github' ? 'gh' : 'glab';
64
+ const isWindows = process.platform === 'win32';
65
+ // Try winget (Windows)
66
+ if (isWindows) {
67
+ const wingetPkg = platform === 'github' ? 'GitHub.cli' : 'GLab.GLab';
68
+ try {
69
+ execFileSync('winget', ['install', '--id', wingetPkg, '-e', '--accept-source-agreements', '--accept-package-agreements'], { stdio: 'pipe', timeout: 300_000 });
70
+ return { success: true, method: `winget install ${wingetPkg}` };
71
+ }
72
+ catch { /* try next */ }
73
+ // Try scoop
74
+ try {
75
+ execFileSync('scoop', ['install', cli], { stdio: 'pipe', timeout: 300_000 });
76
+ return { success: true, method: `scoop install ${cli}` };
77
+ }
78
+ catch { /* try next */ }
79
+ // Try choco
80
+ try {
81
+ execFileSync('choco', ['install', cli, '-y'], { stdio: 'pipe', timeout: 300_000 });
82
+ return { success: true, method: `choco install ${cli}` };
83
+ }
84
+ catch { /* exhausted */ }
85
+ }
86
+ // Try brew (macOS / Linux)
87
+ if (!isWindows) {
88
+ const brewPkg = platform === 'github' ? 'gh' : 'glab';
89
+ try {
90
+ execFileSync('brew', ['install', brewPkg], { stdio: 'pipe', timeout: 300_000 });
91
+ return { success: true, method: `brew install ${brewPkg}` };
92
+ }
93
+ catch { /* try next */ }
94
+ // Try apt (Debian/Ubuntu)
95
+ if (platform === 'github') {
96
+ try {
97
+ execFileSync('sh', ['-c', 'type apt-get >/dev/null 2>&1 && (curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && sudo apt-get update && sudo apt-get install gh -y)'], { stdio: 'pipe', timeout: 300_000 });
98
+ return { success: true, method: 'apt-get install gh' };
99
+ }
100
+ catch { /* exhausted */ }
101
+ }
102
+ }
103
+ return { success: false, error: `Could not auto-install ${cli}. Install manually: https://${platform === 'github' ? 'cli.github.com' : 'gitlab.com/gitlab-org/cli'}` };
104
+ }
21
105
  export async function watchPipeline(branch, platform, projectDir, logger, signal) {
22
106
  logger.info(`Watching CI pipeline for branch: ${branch} (${platform})`);
23
107
  if (platform === 'none') {
@@ -11,7 +11,7 @@ import { recordSession, getSession, clearSession } from './state/session.mjs';
11
11
  import { createWorktree, commitInWorktree, getChangedFiles, cleanupWorktree, mergeToMain, syncMain, pushWorktree, forcePushWorktree, rebaseOnMain, cleanMainForMerge, popStash, getMainBranch, listWorktrees, listOrphanedWorktrees, isBranchMerged, getCurrentBranch, hasUncommittedChanges, deleteBranchRemote, cleanMergedBranches, pruneRemoteBranches, findStaleUnmergedBranches, } from './git/manager.mjs';
12
12
  import { createPR, getPRStatus, getPRComments, mergePR, closePR } from './git/pr-manager.mjs';
13
13
  import { scanAgents } from './agents/health-checker.mjs';
14
- import { detectCIPlatform, fetchFailureLogs } from './git/ci-watcher.mjs';
14
+ import { detectCIPlatform, checkPlatformCLI, installPlatformCLI, fetchFailureLogs } from './git/ci-watcher.mjs';
15
15
  import { createRelease } from './git/release.mjs';
16
16
  import { processInbox, addTaskMessageToTask } from './tasks/inbox.mjs';
17
17
  import { buildPlanPrompt, buildImplementPrompt, buildQAPrompt, buildReviewPrompt, buildReworkPrompt, buildCIFixPrompt, buildPRCommentPrompt, } from './agents/prompt-builder.mjs';
@@ -62,6 +62,29 @@ export async function runIteration(deps) {
62
62
  // Caller (scheduler.mts) handles pause state
63
63
  }
64
64
  }
65
+ // Pre-flight: ensure platform CLI is available
66
+ if (!state._recoveryDone) {
67
+ const ciPlatformPreflight = detectCIPlatform(projectDir);
68
+ if (ciPlatformPreflight !== 'none') {
69
+ const cliError = checkPlatformCLI(ciPlatformPreflight);
70
+ if (cliError) {
71
+ const cli = ciPlatformPreflight === 'github' ? 'gh' : 'glab';
72
+ logger.warn(`${cliError} — attempting auto-install of ${cli}`);
73
+ const installResult = installPlatformCLI(ciPlatformPreflight);
74
+ if (installResult.success) {
75
+ logger.info(`Installed ${cli} via ${installResult.method}`);
76
+ // Check auth after install
77
+ const authError = checkPlatformCLI(ciPlatformPreflight);
78
+ if (authError?.includes('not authenticated')) {
79
+ logger.warn(`${cli} installed but needs authentication. Run: ${cli} auth login`);
80
+ }
81
+ }
82
+ else {
83
+ logger.error(`Failed to install ${cli}: ${installResult.error}`);
84
+ }
85
+ }
86
+ }
87
+ }
65
88
  // Pre-flight: commit uncommitted changes on main before any work
66
89
  if (!state._recoveryDone) {
67
90
  if (hasUncommittedChanges(projectDir)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "2.3.20",
3
+ "version": "2.3.21",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",