@haystackeditor/cli 0.7.2 → 0.8.1
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/README.md +59 -12
- package/dist/assets/hooks/agent-context/detect.ts +136 -0
- package/dist/assets/hooks/agent-context/format.ts +99 -0
- package/dist/assets/hooks/agent-context/index.ts +39 -0
- package/dist/assets/hooks/agent-context/parsers/claude.ts +253 -0
- package/dist/assets/hooks/agent-context/parsers/gemini.ts +155 -0
- package/dist/assets/hooks/agent-context/parsers/opencode.ts +174 -0
- package/dist/assets/hooks/agent-context/tsconfig.json +13 -0
- package/dist/assets/hooks/agent-context/types.ts +58 -0
- package/dist/assets/hooks/llm-rules-template.md +35 -0
- package/dist/assets/hooks/package.json +11 -0
- package/dist/assets/hooks/scripts/commit-msg.sh +4 -0
- package/dist/assets/hooks/scripts/post-commit.sh +4 -0
- package/dist/assets/hooks/scripts/pre-commit.sh +92 -0
- package/dist/assets/hooks/scripts/pre-push.sh +5 -0
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +3 -0
- package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +528 -0
- package/dist/assets/hooks/truncation-checker/index.ts +595 -0
- package/dist/assets/hooks/truncation-checker/tsconfig.json +13 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.js +89 -0
- package/dist/commands/hooks.d.ts +17 -0
- package/dist/commands/hooks.js +269 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +20 -239
- package/dist/commands/secrets.d.ts +15 -0
- package/dist/commands/secrets.js +83 -0
- package/dist/commands/skills.d.ts +8 -0
- package/dist/commands/skills.js +215 -0
- package/dist/index.js +107 -7
- package/dist/types.d.ts +32 -8
- package/dist/utils/hooks.d.ts +26 -0
- package/dist/utils/hooks.js +226 -0
- package/dist/utils/skill.d.ts +1 -1
- package/dist/utils/skill.js +481 -13
- package/package.json +2 -2
package/dist/commands/config.js
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { loadToken } from './login.js';
|
|
6
6
|
const API_BASE = 'https://haystackeditor.com/api/preferences';
|
|
7
|
+
const AGENTIC_TOOL_LABELS = {
|
|
8
|
+
'opencode': 'OpenCode (Haystack billing)',
|
|
9
|
+
'claude-code': 'Claude Code (your Claude Max subscription)',
|
|
10
|
+
'codex': 'Codex CLI (your ChatGPT subscription)',
|
|
11
|
+
};
|
|
7
12
|
async function requireAuth() {
|
|
8
13
|
const token = await loadToken();
|
|
9
14
|
if (!token) {
|
|
@@ -131,3 +136,87 @@ export async function handleSandbox(action) {
|
|
|
131
136
|
process.exit(1);
|
|
132
137
|
}
|
|
133
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Get current agentic tool setting
|
|
141
|
+
*/
|
|
142
|
+
export async function getAgenticToolStatus() {
|
|
143
|
+
const token = await requireAuth();
|
|
144
|
+
console.log(chalk.dim('\nFetching preferences...\n'));
|
|
145
|
+
try {
|
|
146
|
+
const response = await apiRequest('GET', token);
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
if (response.status === 401) {
|
|
149
|
+
console.error(chalk.red('Session expired. Run `haystack login` again.\n'));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
throw new Error(`Failed to get preferences: ${response.status}`);
|
|
153
|
+
}
|
|
154
|
+
const data = await response.json();
|
|
155
|
+
const currentTool = data.agentic_tool || 'opencode';
|
|
156
|
+
console.log(chalk.bold('Agentic tool:'), chalk.cyan(AGENTIC_TOOL_LABELS[currentTool]));
|
|
157
|
+
console.log();
|
|
158
|
+
console.log(chalk.dim('Available options:'));
|
|
159
|
+
for (const [key, label] of Object.entries(AGENTIC_TOOL_LABELS)) {
|
|
160
|
+
const marker = key === currentTool ? chalk.green(' ✓ ') : ' ';
|
|
161
|
+
console.log(`${marker}${chalk.dim(key)} - ${label}`);
|
|
162
|
+
}
|
|
163
|
+
console.log();
|
|
164
|
+
console.log(chalk.dim('Change with: haystack config agentic-tool <tool>'));
|
|
165
|
+
console.log();
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error(chalk.red(`\nError: ${error.message}\n`));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Set agentic tool preference
|
|
174
|
+
*/
|
|
175
|
+
export async function setAgenticTool(tool) {
|
|
176
|
+
const token = await requireAuth();
|
|
177
|
+
console.log(chalk.dim(`\nSetting agentic tool to ${tool}...`));
|
|
178
|
+
try {
|
|
179
|
+
const response = await apiRequest('PUT', token, { agentic_tool: tool });
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
if (response.status === 401) {
|
|
182
|
+
console.error(chalk.red('Session expired. Run `haystack login` again.\n'));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
const error = await response.json().catch(() => ({}));
|
|
186
|
+
throw new Error(error.error || `Failed to update preferences: ${response.status}`);
|
|
187
|
+
}
|
|
188
|
+
console.log(chalk.green(`\nAgentic tool set to: ${AGENTIC_TOOL_LABELS[tool]}\n`));
|
|
189
|
+
if (tool === 'claude-code') {
|
|
190
|
+
console.log(chalk.dim('Note: Requires Claude Max subscription.'));
|
|
191
|
+
console.log(chalk.dim('Connect your account in the dashboard settings.\n'));
|
|
192
|
+
}
|
|
193
|
+
else if (tool === 'codex') {
|
|
194
|
+
console.log(chalk.dim('Note: Requires ChatGPT Plus, Pro, or Team subscription.'));
|
|
195
|
+
console.log(chalk.dim('Connect your account in the dashboard settings.\n'));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
console.error(chalk.red(`\nError: ${error.message}\n`));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Handle agentic-tool subcommand
|
|
205
|
+
*/
|
|
206
|
+
export async function handleAgenticTool(tool) {
|
|
207
|
+
const validTools = ['opencode', 'claude-code', 'codex'];
|
|
208
|
+
if (!tool || tool === 'status') {
|
|
209
|
+
return getAgenticToolStatus();
|
|
210
|
+
}
|
|
211
|
+
const normalizedTool = tool.toLowerCase();
|
|
212
|
+
if (!validTools.includes(normalizedTool)) {
|
|
213
|
+
console.error(chalk.red(`\nUnknown tool: ${tool}`));
|
|
214
|
+
console.log('\nValid options:');
|
|
215
|
+
for (const [key, label] of Object.entries(AGENTIC_TOOL_LABELS)) {
|
|
216
|
+
console.log(` ${chalk.cyan(key)} - ${label}`);
|
|
217
|
+
}
|
|
218
|
+
console.log('\nUsage: haystack config agentic-tool [opencode|claude-code|codex|status]\n');
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
return setAgenticTool(normalizedTool);
|
|
222
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* haystack hooks - Install and manage git hooks for AI agent quality checks
|
|
3
|
+
*
|
|
4
|
+
* Installs:
|
|
5
|
+
* - Entire CLI binary (session tracking, powered by https://entire.dev)
|
|
6
|
+
* - Pre-commit hook (agent detection, truncation checking, LLM rules review)
|
|
7
|
+
* - Git hooks for session logging (commit-msg, post-commit, pre-push, prepare-commit-msg)
|
|
8
|
+
*/
|
|
9
|
+
interface HooksInstallOptions {
|
|
10
|
+
version?: string;
|
|
11
|
+
force?: boolean;
|
|
12
|
+
skipEntire?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function hooksInstall(options: HooksInstallOptions): Promise<void>;
|
|
15
|
+
export declare function hooksStatus(): Promise<void>;
|
|
16
|
+
export declare function hooksUpdate(): Promise<void>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* haystack hooks - Install and manage git hooks for AI agent quality checks
|
|
3
|
+
*
|
|
4
|
+
* Installs:
|
|
5
|
+
* - Entire CLI binary (session tracking, powered by https://entire.dev)
|
|
6
|
+
* - Pre-commit hook (agent detection, truncation checking, LLM rules review)
|
|
7
|
+
* - Git hooks for session logging (commit-msg, post-commit, pre-push, prepare-commit-msg)
|
|
8
|
+
*/
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { existsSync, accessSync, constants } from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { execSync } from 'child_process';
|
|
13
|
+
import { findGitRoot, ENTIRE_DEFAULT_VERSION, ENTIRE_BIN_PATH, getInstalledEntireVersion, getLatestEntireVersion, downloadEntireBinary, copyHookFiles, installHookDeps, copyLlmRulesTemplate, createEntireConfig, updateGitignore, } from '../utils/hooks.js';
|
|
14
|
+
export async function hooksInstall(options) {
|
|
15
|
+
console.log(chalk.cyan('\nHaystack Hooks Setup\n'));
|
|
16
|
+
// Step 1: Validate git repo
|
|
17
|
+
const gitRoot = findGitRoot();
|
|
18
|
+
if (!gitRoot) {
|
|
19
|
+
console.error(chalk.red('Not a git repository. Run this from inside a git repo.\n'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const hooksDir = path.join(gitRoot, 'hooks');
|
|
23
|
+
// Step 2: Check for existing installation
|
|
24
|
+
if (existsSync(hooksDir) && !options.force) {
|
|
25
|
+
console.error(chalk.yellow('hooks/ directory already exists. Use --force to overwrite.\n'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
if (existsSync(hooksDir) && options.force) {
|
|
29
|
+
console.log(chalk.yellow('Overwriting existing hooks...'));
|
|
30
|
+
}
|
|
31
|
+
// Step 3: Download Entire binary
|
|
32
|
+
if (!options.skipEntire) {
|
|
33
|
+
const version = options.version || ENTIRE_DEFAULT_VERSION;
|
|
34
|
+
const installedVersion = await getInstalledEntireVersion();
|
|
35
|
+
if (installedVersion === version) {
|
|
36
|
+
console.log(chalk.green(`✓ Entire CLI v${version} already installed`));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.log(chalk.dim(`Downloading Entire CLI v${version}...`));
|
|
40
|
+
try {
|
|
41
|
+
await downloadEntireBinary(version);
|
|
42
|
+
console.log(chalk.green(`✓ Entire CLI v${version} installed to ~/.haystack/bin/entire`));
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
console.error(chalk.red(`Failed to download Entire CLI: ${message}\n`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log(chalk.dim('Skipping Entire CLI download (--skip-entire)'));
|
|
53
|
+
}
|
|
54
|
+
// Step 4: Copy hook files
|
|
55
|
+
try {
|
|
56
|
+
await copyHookFiles(hooksDir);
|
|
57
|
+
console.log(chalk.green('✓ Hook scripts installed to hooks/'));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
61
|
+
console.error(chalk.red(`Failed to copy hook files: ${message}\n`));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
// Step 5: Install hook dependencies
|
|
65
|
+
console.log(chalk.dim('Installing hook dependencies (tree-sitter)...'));
|
|
66
|
+
try {
|
|
67
|
+
await installHookDeps(hooksDir);
|
|
68
|
+
console.log(chalk.green('✓ Hook dependencies installed'));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
console.log(chalk.yellow('⚠ Failed to install hook dependencies. Run `npm install` in hooks/ manually.'));
|
|
72
|
+
}
|
|
73
|
+
// Step 6: Configure git hooks path
|
|
74
|
+
try {
|
|
75
|
+
execSync('git config core.hooksPath hooks', { cwd: gitRoot, stdio: 'pipe' });
|
|
76
|
+
console.log(chalk.green('✓ Git configured to use hooks/ directory'));
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
80
|
+
console.error(chalk.red(`Failed to set git hooks path: ${message}\n`));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
// Step 7: Create .entire/ configuration
|
|
84
|
+
try {
|
|
85
|
+
await createEntireConfig(gitRoot);
|
|
86
|
+
console.log(chalk.green('✓ Created .entire/settings.json'));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
console.log(chalk.yellow('⚠ Failed to create .entire/ configuration'));
|
|
90
|
+
}
|
|
91
|
+
// Step 8: Create LLM_RULES.md if needed
|
|
92
|
+
try {
|
|
93
|
+
const created = await copyLlmRulesTemplate(gitRoot);
|
|
94
|
+
if (created) {
|
|
95
|
+
console.log(chalk.green('✓ Created LLM_RULES.md (customize this for your project)'));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(chalk.dim(' LLM_RULES.md already exists'));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
console.log(chalk.yellow('⚠ Failed to create LLM_RULES.md'));
|
|
103
|
+
}
|
|
104
|
+
// Step 9: Update .gitignore
|
|
105
|
+
try {
|
|
106
|
+
const updated = await updateGitignore(gitRoot);
|
|
107
|
+
if (updated) {
|
|
108
|
+
console.log(chalk.green('✓ Updated .gitignore'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
console.log(chalk.yellow('⚠ Failed to update .gitignore'));
|
|
113
|
+
}
|
|
114
|
+
// Summary
|
|
115
|
+
console.log(chalk.green('\n✓ Haystack hooks installed!\n'));
|
|
116
|
+
console.log(chalk.dim('Hooks installed:'));
|
|
117
|
+
console.log(chalk.dim(' pre-commit Agent detection, truncation check, LLM rules review'));
|
|
118
|
+
console.log(chalk.dim(' commit-msg Session tracking (powered by Entire)'));
|
|
119
|
+
console.log(chalk.dim(' post-commit Session condensing (powered by Entire)'));
|
|
120
|
+
console.log(chalk.dim(' pre-push Session log push (powered by Entire)'));
|
|
121
|
+
console.log(chalk.dim(' prepare-commit-msg Commit preparation (powered by Entire)'));
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(chalk.dim('Files to commit:'));
|
|
124
|
+
console.log(chalk.dim(' hooks/ Hook scripts and TypeScript modules'));
|
|
125
|
+
console.log(chalk.dim(' .entire/settings.json'));
|
|
126
|
+
console.log(chalk.dim(' .entire/.gitignore'));
|
|
127
|
+
console.log(chalk.dim(' LLM_RULES.md Customize this for your project'));
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
// ============================================================================
|
|
131
|
+
// haystack hooks status
|
|
132
|
+
// ============================================================================
|
|
133
|
+
export async function hooksStatus() {
|
|
134
|
+
const gitRoot = findGitRoot();
|
|
135
|
+
if (!gitRoot) {
|
|
136
|
+
console.error(chalk.red('Not a git repository.\n'));
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
console.log(chalk.cyan('\nHaystack Hooks Status\n'));
|
|
140
|
+
const hooksDir = path.join(gitRoot, 'hooks');
|
|
141
|
+
// Check hooks directory
|
|
142
|
+
if (!existsSync(hooksDir)) {
|
|
143
|
+
console.log(chalk.red('✗ hooks/ directory not found'));
|
|
144
|
+
console.log(chalk.dim(' Run: haystack hooks install\n'));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(chalk.green('✓ hooks/ directory exists'));
|
|
148
|
+
// Check each hook script
|
|
149
|
+
const requiredHooks = [
|
|
150
|
+
'pre-commit',
|
|
151
|
+
'commit-msg',
|
|
152
|
+
'post-commit',
|
|
153
|
+
'pre-push',
|
|
154
|
+
'prepare-commit-msg',
|
|
155
|
+
];
|
|
156
|
+
for (const hook of requiredHooks) {
|
|
157
|
+
const hookPath = path.join(hooksDir, hook);
|
|
158
|
+
if (existsSync(hookPath)) {
|
|
159
|
+
try {
|
|
160
|
+
accessSync(hookPath, constants.X_OK);
|
|
161
|
+
console.log(chalk.green(`✓ ${hook}`));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
console.log(chalk.yellow(`⚠ ${hook} (not executable)`));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
console.log(chalk.red(`✗ ${hook} missing`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Check TypeScript modules
|
|
172
|
+
const agentContextDir = path.join(hooksDir, 'agent-context');
|
|
173
|
+
const truncationDir = path.join(hooksDir, 'truncation-checker');
|
|
174
|
+
console.log(existsSync(agentContextDir)
|
|
175
|
+
? chalk.green('✓ agent-context/ module')
|
|
176
|
+
: chalk.red('✗ agent-context/ missing'));
|
|
177
|
+
console.log(existsSync(truncationDir)
|
|
178
|
+
? chalk.green('✓ truncation-checker/ module')
|
|
179
|
+
: chalk.red('✗ truncation-checker/ missing'));
|
|
180
|
+
// Check hook dependencies
|
|
181
|
+
const nodeModules = path.join(hooksDir, 'node_modules');
|
|
182
|
+
console.log(existsSync(nodeModules)
|
|
183
|
+
? chalk.green('✓ Hook dependencies installed')
|
|
184
|
+
: chalk.yellow('⚠ Hook dependencies not installed (run npm install in hooks/)'));
|
|
185
|
+
// Check git core.hooksPath
|
|
186
|
+
try {
|
|
187
|
+
const hooksPath = execSync('git config core.hooksPath', {
|
|
188
|
+
cwd: gitRoot,
|
|
189
|
+
encoding: 'utf-8',
|
|
190
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
191
|
+
}).trim();
|
|
192
|
+
if (hooksPath === 'hooks') {
|
|
193
|
+
console.log(chalk.green('✓ Git core.hooksPath = hooks'));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(chalk.yellow(`⚠ Git core.hooksPath = ${hooksPath} (expected: hooks)`));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
console.log(chalk.red('✗ Git core.hooksPath not set'));
|
|
201
|
+
}
|
|
202
|
+
// Check Entire binary
|
|
203
|
+
const installedVersion = await getInstalledEntireVersion();
|
|
204
|
+
if (installedVersion) {
|
|
205
|
+
console.log(chalk.green(`✓ Entire CLI v${installedVersion}`));
|
|
206
|
+
}
|
|
207
|
+
else if (existsSync(ENTIRE_BIN_PATH)) {
|
|
208
|
+
console.log(chalk.yellow('⚠ Entire CLI binary exists but failed to run'));
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
console.log(chalk.yellow('⚠ Entire CLI not installed (~/.haystack/bin/entire)'));
|
|
212
|
+
}
|
|
213
|
+
// Check .entire/settings.json
|
|
214
|
+
const settingsPath = path.join(gitRoot, '.entire', 'settings.json');
|
|
215
|
+
if (existsSync(settingsPath)) {
|
|
216
|
+
console.log(chalk.green('✓ .entire/settings.json'));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log(chalk.yellow('⚠ .entire/settings.json not found'));
|
|
220
|
+
}
|
|
221
|
+
// Check LLM_RULES.md
|
|
222
|
+
const rulesPath = path.join(gitRoot, 'LLM_RULES.md');
|
|
223
|
+
if (existsSync(rulesPath)) {
|
|
224
|
+
console.log(chalk.green('✓ LLM_RULES.md'));
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.log(chalk.yellow('⚠ LLM_RULES.md not found'));
|
|
228
|
+
}
|
|
229
|
+
console.log('');
|
|
230
|
+
}
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// haystack hooks update
|
|
233
|
+
// ============================================================================
|
|
234
|
+
export async function hooksUpdate() {
|
|
235
|
+
console.log(chalk.cyan('\nUpdating Entire CLI...\n'));
|
|
236
|
+
// Check current version
|
|
237
|
+
const currentVersion = await getInstalledEntireVersion();
|
|
238
|
+
if (currentVersion) {
|
|
239
|
+
console.log(chalk.dim(`Current version: v${currentVersion}`));
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
console.log(chalk.dim('Entire CLI not currently installed.'));
|
|
243
|
+
}
|
|
244
|
+
// Fetch latest version
|
|
245
|
+
let latestVersion;
|
|
246
|
+
try {
|
|
247
|
+
latestVersion = await getLatestEntireVersion();
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
251
|
+
console.error(chalk.red(`Failed to check for updates: ${message}\n`));
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
console.log(chalk.dim(`Latest version: v${latestVersion}`));
|
|
255
|
+
if (currentVersion === latestVersion) {
|
|
256
|
+
console.log(chalk.green('\n✓ Already up to date.\n'));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// Download and install
|
|
260
|
+
try {
|
|
261
|
+
await downloadEntireBinary(latestVersion);
|
|
262
|
+
console.log(chalk.green(`\n✓ Updated Entire CLI to v${latestVersion}\n`));
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
266
|
+
console.error(chalk.red(`Failed to update: ${message}\n`));
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
}
|