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') {
|
package/dist/scheduler/loop.mjs
CHANGED
|
@@ -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)) {
|