berget 2.2.6 → 2.2.8
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/.github/workflows/publish.yml +2 -2
- package/.github/workflows/test.yml +10 -4
- package/.husky/pre-commit +1 -0
- package/.prettierignore +15 -0
- package/.prettierrc +7 -3
- package/CONTRIBUTING.md +38 -0
- package/README.md +2 -148
- package/dist/index.js +10 -11
- package/dist/package.json +30 -2
- package/dist/src/agents/app.js +28 -0
- package/dist/src/agents/backend.js +25 -0
- package/dist/src/agents/devops.js +34 -0
- package/dist/src/agents/frontend.js +25 -0
- package/dist/src/agents/fullstack.js +25 -0
- package/dist/src/agents/index.js +61 -0
- package/dist/src/agents/quality.js +70 -0
- package/dist/src/agents/security.js +26 -0
- package/dist/src/agents/types.js +2 -0
- package/dist/src/client.js +97 -117
- package/dist/src/commands/api-keys.js +75 -90
- package/dist/src/commands/auth.js +7 -16
- package/dist/src/commands/autocomplete.js +1 -1
- package/dist/src/commands/billing.js +6 -17
- package/dist/src/commands/chat.js +68 -101
- package/dist/src/commands/clusters.js +9 -18
- package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
- package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
- package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
- package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
- package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
- package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
- package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
- package/dist/src/commands/code/auth-sync.js +270 -0
- package/dist/src/commands/code/errors.js +12 -9
- package/dist/src/commands/code/ports/auth-services.js +2 -0
- package/dist/src/commands/code/setup.js +387 -281
- package/dist/src/commands/code.js +205 -332
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +6 -17
- package/dist/src/commands/users.js +5 -16
- package/dist/src/constants/command-structure.js +104 -104
- package/dist/src/services/api-key-service.js +132 -157
- package/dist/src/services/auth-service.js +89 -342
- package/dist/src/services/browser-auth.js +268 -0
- package/dist/src/services/chat-service.js +371 -401
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +10 -25
- package/dist/src/services/flux-service.js +14 -29
- package/dist/src/services/helm-service.js +10 -25
- package/dist/src/services/kubectl-service.js +16 -33
- package/dist/src/utils/config-checker.js +3 -3
- package/dist/src/utils/config-loader.js +95 -95
- package/dist/src/utils/default-api-key.js +124 -134
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +20 -21
- package/dist/src/utils/logger.js +72 -65
- package/dist/src/utils/markdown-renderer.js +27 -27
- package/dist/src/utils/opencode-validator.js +63 -68
- package/dist/src/utils/token-manager.js +74 -45
- package/dist/tests/commands/chat.test.js +16 -25
- package/dist/tests/commands/code.test.js +95 -104
- package/dist/tests/utils/config-loader.test.js +48 -48
- package/dist/tests/utils/env-manager.test.js +43 -52
- package/dist/tests/utils/opencode-validator.test.js +22 -21
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +67 -0
- package/index.ts +35 -42
- package/package.json +30 -2
- package/src/agents/app.ts +27 -0
- package/src/agents/backend.ts +24 -0
- package/src/agents/devops.ts +33 -0
- package/src/agents/frontend.ts +24 -0
- package/src/agents/fullstack.ts +24 -0
- package/src/agents/index.ts +73 -0
- package/src/agents/quality.ts +69 -0
- package/src/agents/security.ts +26 -0
- package/src/agents/types.ts +17 -0
- package/src/client.ts +118 -152
- package/src/commands/api-keys.ts +241 -333
- package/src/commands/auth.ts +22 -27
- package/src/commands/autocomplete.ts +9 -9
- package/src/commands/billing.ts +20 -24
- package/src/commands/chat.ts +248 -338
- package/src/commands/clusters.ts +27 -26
- package/src/commands/code/__tests__/auth-sync.test.ts +482 -0
- package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
- package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
- package/src/commands/code/__tests__/fake-command-runner.ts +45 -42
- package/src/commands/code/__tests__/fake-file-store.ts +32 -23
- package/src/commands/code/__tests__/fake-prompter.ts +116 -77
- package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
- package/src/commands/code/adapters/clack-prompter.ts +53 -39
- package/src/commands/code/adapters/fs-file-store.ts +32 -27
- package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
- package/src/commands/code/auth-sync.ts +329 -0
- package/src/commands/code/errors.ts +18 -18
- package/src/commands/code/ports/auth-services.ts +14 -0
- package/src/commands/code/ports/command-runner.ts +8 -4
- package/src/commands/code/ports/file-store.ts +5 -4
- package/src/commands/code/ports/prompter.ts +24 -18
- package/src/commands/code/setup.ts +570 -340
- package/src/commands/code.ts +338 -539
- package/src/commands/index.ts +20 -19
- package/src/commands/models.ts +28 -32
- package/src/commands/users.ts +15 -21
- package/src/constants/command-structure.ts +134 -157
- package/src/services/api-key-service.ts +105 -122
- package/src/services/auth-service.ts +99 -345
- package/src/services/browser-auth.ts +296 -0
- package/src/services/chat-service.ts +265 -299
- package/src/services/cluster-service.ts +42 -45
- package/src/services/collaborator-service.ts +14 -19
- package/src/services/flux-service.ts +23 -25
- package/src/services/helm-service.ts +19 -21
- package/src/services/kubectl-service.ts +17 -19
- package/src/types/api.d.ts +1905 -1907
- package/src/types/json.d.ts +2 -2
- package/src/utils/config-checker.ts +10 -10
- package/src/utils/config-loader.ts +162 -178
- package/src/utils/default-api-key.ts +114 -125
- package/src/utils/env-manager.ts +53 -57
- package/src/utils/error-handler.ts +61 -56
- package/src/utils/logger.ts +79 -73
- package/src/utils/markdown-renderer.ts +31 -31
- package/src/utils/opencode-validator.ts +85 -89
- package/src/utils/token-manager.ts +108 -87
- package/templates/agents/app.md +1 -0
- package/templates/agents/backend.md +1 -0
- package/templates/agents/devops.md +2 -0
- package/templates/agents/frontend.md +1 -0
- package/templates/agents/fullstack.md +1 -0
- package/templates/agents/quality.md +45 -40
- package/templates/agents/security.md +1 -0
- package/tests/commands/chat.test.ts +53 -62
- package/tests/commands/code.test.ts +265 -310
- package/tests/utils/config-loader.test.ts +189 -188
- package/tests/utils/env-manager.test.ts +110 -113
- package/tests/utils/opencode-validator.test.ts +52 -56
- package/tsconfig.json +4 -3
- package/vitest.config.ts +3 -3
- package/AGENTS.md +0 -374
- package/TODO.md +0 -19
|
@@ -22,266 +22,20 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
37
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
29
|
exports.registerCodeCommands = void 0;
|
|
39
30
|
const chalk_1 = __importDefault(require("chalk"));
|
|
40
|
-
const
|
|
31
|
+
const node_child_process_1 = require("node:child_process");
|
|
32
|
+
const fs = __importStar(require("node:fs"));
|
|
33
|
+
const promises_1 = require("node:fs/promises");
|
|
34
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
35
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
41
36
|
const command_structure_1 = require("../constants/command-structure");
|
|
42
37
|
const error_handler_1 = require("../utils/error-handler");
|
|
43
38
|
const setup_1 = require("./code/setup");
|
|
44
|
-
const fs = __importStar(require("fs"));
|
|
45
|
-
const promises_1 = require("fs/promises");
|
|
46
|
-
const path_1 = __importDefault(require("path"));
|
|
47
|
-
const child_process_1 = require("child_process");
|
|
48
|
-
/**
|
|
49
|
-
* Check if current directory has git
|
|
50
|
-
*/
|
|
51
|
-
function hasGit() {
|
|
52
|
-
try {
|
|
53
|
-
return fs.existsSync(path_1.default.join(process.cwd(), '.git'));
|
|
54
|
-
}
|
|
55
|
-
catch (_a) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Helper function to get user confirmation
|
|
61
|
-
*/
|
|
62
|
-
function confirm(question, autoYes = false) {
|
|
63
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
if (autoYes) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
return new Promise((resolve) => {
|
|
68
|
-
const rl = readline_1.default.createInterface({
|
|
69
|
-
input: process.stdin,
|
|
70
|
-
output: process.stdout,
|
|
71
|
-
});
|
|
72
|
-
rl.question(question, (answer) => {
|
|
73
|
-
rl.close();
|
|
74
|
-
resolve(answer.toLowerCase() === 'y' ||
|
|
75
|
-
answer.toLowerCase() === 'yes' ||
|
|
76
|
-
answer === '');
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Helper function to get user input
|
|
83
|
-
*/
|
|
84
|
-
function getInput(question, defaultValue, autoYes = false) {
|
|
85
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
-
if (autoYes) {
|
|
87
|
-
return defaultValue;
|
|
88
|
-
}
|
|
89
|
-
const rl = readline_1.default.createInterface({
|
|
90
|
-
input: process.stdin,
|
|
91
|
-
output: process.stdout,
|
|
92
|
-
});
|
|
93
|
-
return new Promise((resolve) => {
|
|
94
|
-
rl.question(question, (answer) => {
|
|
95
|
-
rl.close();
|
|
96
|
-
resolve(answer.trim() || defaultValue);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Get project name from current directory or package.json
|
|
103
|
-
*/
|
|
104
|
-
function getProjectName() {
|
|
105
|
-
try {
|
|
106
|
-
const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
|
|
107
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
108
|
-
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
109
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
110
|
-
return packageJson.name || path_1.default.basename(process.cwd());
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
// Ignore error and fallback to directory name
|
|
115
|
-
}
|
|
116
|
-
return path_1.default.basename(process.cwd());
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get the path to the bundled agent templates directory
|
|
120
|
-
*/
|
|
121
|
-
function getAgentTemplatesDir() {
|
|
122
|
-
return path_1.default.resolve(__dirname, '../../templates/agents');
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Parse a markdown agent file with YAML frontmatter into an agent config object
|
|
126
|
-
*/
|
|
127
|
-
function parseAgentMarkdown(content) {
|
|
128
|
-
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
129
|
-
if (!frontmatterMatch) {
|
|
130
|
-
throw new Error('Invalid agent markdown: missing frontmatter');
|
|
131
|
-
}
|
|
132
|
-
const yamlStr = frontmatterMatch[1];
|
|
133
|
-
const promptBody = frontmatterMatch[2].trim();
|
|
134
|
-
const config = { prompt: promptBody };
|
|
135
|
-
for (const line of yamlStr.split('\n')) {
|
|
136
|
-
const trimmed = line.trim();
|
|
137
|
-
if (!trimmed || trimmed.startsWith('#'))
|
|
138
|
-
continue;
|
|
139
|
-
const colonIdx = trimmed.indexOf(':');
|
|
140
|
-
if (colonIdx === -1)
|
|
141
|
-
continue;
|
|
142
|
-
const key = trimmed.substring(0, colonIdx).trim();
|
|
143
|
-
const value = trimmed.substring(colonIdx + 1).trim();
|
|
144
|
-
if (key === 'permission')
|
|
145
|
-
continue;
|
|
146
|
-
if (value === 'true') {
|
|
147
|
-
config[key] = true;
|
|
148
|
-
}
|
|
149
|
-
else if (value === 'false') {
|
|
150
|
-
config[key] = false;
|
|
151
|
-
}
|
|
152
|
-
else if (!isNaN(Number(value)) && value !== '') {
|
|
153
|
-
config[key] = Number(value);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
config[key] = value;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const permission = {};
|
|
160
|
-
const permMatch = yamlStr.match(/permission:\s*\n((?:\s+\w+:.*\n?)*)/);
|
|
161
|
-
if (permMatch) {
|
|
162
|
-
for (const permLine of permMatch[1].split('\n')) {
|
|
163
|
-
const permTrimmed = permLine.trim();
|
|
164
|
-
if (!permTrimmed)
|
|
165
|
-
continue;
|
|
166
|
-
const permColonIdx = permTrimmed.indexOf(':');
|
|
167
|
-
if (permColonIdx === -1)
|
|
168
|
-
continue;
|
|
169
|
-
const permKey = permTrimmed.substring(0, permColonIdx).trim();
|
|
170
|
-
const permValue = permTrimmed.substring(permColonIdx + 1).trim();
|
|
171
|
-
if (permKey && permValue) {
|
|
172
|
-
permission[permKey] = permValue;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (Object.keys(permission).length > 0) {
|
|
177
|
-
config.permission = permission;
|
|
178
|
-
}
|
|
179
|
-
return config;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Load the latest agent configuration from bundled markdown templates
|
|
183
|
-
*/
|
|
184
|
-
function loadLatestAgentConfig() {
|
|
185
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
186
|
-
const templatesDir = getAgentTemplatesDir();
|
|
187
|
-
const agents = {};
|
|
188
|
-
const files = fs.readdirSync(templatesDir).filter((f) => f.endsWith('.md'));
|
|
189
|
-
for (const file of files) {
|
|
190
|
-
const agentName = path_1.default.basename(file, '.md');
|
|
191
|
-
const filePath = path_1.default.join(templatesDir, file);
|
|
192
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
193
|
-
try {
|
|
194
|
-
agents[agentName] = parseAgentMarkdown(content);
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
console.warn(chalk_1.default.yellow(`Warning: Failed to parse agent template ${file}: ${error}`));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return agents;
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Check if opencode is installed
|
|
205
|
-
*/
|
|
206
|
-
function checkOpencodeInstalled() {
|
|
207
|
-
return new Promise((resolve) => {
|
|
208
|
-
const child = (0, child_process_1.spawn)('which', ['opencode'], {
|
|
209
|
-
stdio: 'pipe',
|
|
210
|
-
});
|
|
211
|
-
child.on('close', (code) => {
|
|
212
|
-
resolve(code === 0);
|
|
213
|
-
});
|
|
214
|
-
child.on('error', () => {
|
|
215
|
-
resolve(false);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Install opencode via npm
|
|
221
|
-
*/
|
|
222
|
-
function installOpencode() {
|
|
223
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
224
|
-
console.log(chalk_1.default.cyan('Installing OpenCode via npm...'));
|
|
225
|
-
try {
|
|
226
|
-
yield new Promise((resolve, reject) => {
|
|
227
|
-
const install = (0, child_process_1.spawn)('npm', ['install', '-g', 'opencode-ai@1.3'], {
|
|
228
|
-
stdio: 'inherit',
|
|
229
|
-
});
|
|
230
|
-
install.on('close', (code) => {
|
|
231
|
-
if (code === 0) {
|
|
232
|
-
console.log(chalk_1.default.green('✓ OpenCode installed successfully!'));
|
|
233
|
-
resolve();
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
reject(new Error(`Installation failed with code ${code}`));
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
install.on('error', reject);
|
|
240
|
-
});
|
|
241
|
-
// Verify installation
|
|
242
|
-
const opencodeInstalled = yield checkOpencodeInstalled();
|
|
243
|
-
if (!opencodeInstalled) {
|
|
244
|
-
console.log(chalk_1.default.yellow('Installation completed but opencode command not found.'));
|
|
245
|
-
console.log(chalk_1.default.yellow('You may need to restart your terminal or check your PATH.'));
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
catch (error) {
|
|
251
|
-
console.error(chalk_1.default.red('Failed to install OpenCode:'));
|
|
252
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
253
|
-
console.log(chalk_1.default.blue('\nAlternative installation methods:'));
|
|
254
|
-
console.log(chalk_1.default.blue(' curl -fsSL https://opencode.ai/install | sh'));
|
|
255
|
-
console.log(chalk_1.default.blue(' Or visit: https://opencode.ai/docs'));
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Ensure opencode is installed, offering to install if not
|
|
262
|
-
*/
|
|
263
|
-
function ensureOpencodeInstalled(autoYes = false) {
|
|
264
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
-
let opencodeInstalled = yield checkOpencodeInstalled();
|
|
266
|
-
if (!opencodeInstalled) {
|
|
267
|
-
if (!autoYes) {
|
|
268
|
-
console.log(chalk_1.default.red('OpenCode is not installed.'));
|
|
269
|
-
console.log(chalk_1.default.blue('OpenCode is required for the AI coding assistant.'));
|
|
270
|
-
}
|
|
271
|
-
if (yield confirm('Would you like to install OpenCode automatically? (Y/n): ', autoYes)) {
|
|
272
|
-
opencodeInstalled = yield installOpencode();
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
if (!autoYes) {
|
|
276
|
-
console.log(chalk_1.default.blue('\nInstallation cancelled.'));
|
|
277
|
-
console.log(chalk_1.default.blue('To install manually: curl -fsSL https://opencode.ai/install | bash'));
|
|
278
|
-
console.log(chalk_1.default.blue('Or visit: https://opencode.ai/docs'));
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return opencodeInstalled;
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
39
|
/**
|
|
286
40
|
* Register code commands
|
|
287
41
|
*/
|
|
@@ -293,14 +47,14 @@ function registerCodeCommands(program) {
|
|
|
293
47
|
code
|
|
294
48
|
.command('setup')
|
|
295
49
|
.description('Interactive setup for Berget AI coding tools')
|
|
296
|
-
.action(() =>
|
|
50
|
+
.action(async () => {
|
|
297
51
|
try {
|
|
298
|
-
|
|
52
|
+
await (0, setup_1.runSetupCommand)();
|
|
299
53
|
}
|
|
300
54
|
catch (error) {
|
|
301
55
|
(0, error_handler_1.handleError)('Setup failed', error);
|
|
302
56
|
}
|
|
303
|
-
})
|
|
57
|
+
});
|
|
304
58
|
}
|
|
305
59
|
code
|
|
306
60
|
.command(command_structure_1.SUBCOMMANDS.CODE.INIT)
|
|
@@ -308,17 +62,17 @@ function registerCodeCommands(program) {
|
|
|
308
62
|
.option('-n, --name <name>', 'Project name (defaults to directory name)')
|
|
309
63
|
.option('-f, --force', 'Overwrite existing configuration')
|
|
310
64
|
.option('-y, --yes', 'Automatically answer yes to all prompts (for automation)')
|
|
311
|
-
.action((options) =>
|
|
65
|
+
.action(async (options) => {
|
|
312
66
|
try {
|
|
313
67
|
const projectName = options.name || getProjectName();
|
|
314
|
-
const configPath =
|
|
68
|
+
const configPath = node_path_1.default.join(process.cwd(), 'opencode.json');
|
|
315
69
|
// Check if already initialized
|
|
316
70
|
if (fs.existsSync(configPath) && !options.force) {
|
|
317
71
|
if (!options.yes) {
|
|
318
72
|
console.log(chalk_1.default.yellow('Project already initialized for OpenCode.'));
|
|
319
73
|
console.log(chalk_1.default.dim(`Config file: ${configPath}`));
|
|
320
74
|
}
|
|
321
|
-
if (
|
|
75
|
+
if (await confirm('Do you want to reinitialize? (Y/n): ', options.yes)) {
|
|
322
76
|
// Continue with reinitialization
|
|
323
77
|
}
|
|
324
78
|
else {
|
|
@@ -326,7 +80,7 @@ function registerCodeCommands(program) {
|
|
|
326
80
|
}
|
|
327
81
|
}
|
|
328
82
|
// Ensure opencode is installed
|
|
329
|
-
if (!(
|
|
83
|
+
if (!(await ensureOpencodeInstalled(options.yes))) {
|
|
330
84
|
return;
|
|
331
85
|
}
|
|
332
86
|
console.log(chalk_1.default.cyan(`Initializing OpenCode for project: ${projectName}`));
|
|
@@ -334,7 +88,7 @@ function registerCodeCommands(program) {
|
|
|
334
88
|
$schema: 'https://opencode.ai/config.json',
|
|
335
89
|
plugin: ['@bergetai/opencode-auth@1.0.16'],
|
|
336
90
|
};
|
|
337
|
-
const agentsDir =
|
|
91
|
+
const agentsDir = node_path_1.default.join(process.cwd(), '.opencode', 'agents');
|
|
338
92
|
const templatesDir = getAgentTemplatesDir();
|
|
339
93
|
if (!options.yes) {
|
|
340
94
|
console.log(chalk_1.default.blue('\nAbout to create configuration files:'));
|
|
@@ -342,19 +96,17 @@ function registerCodeCommands(program) {
|
|
|
342
96
|
console.log(chalk_1.default.dim(`Agents: ${agentsDir}/`));
|
|
343
97
|
console.log(chalk_1.default.dim('This will configure OpenCode with the Berget auth plugin.'));
|
|
344
98
|
}
|
|
345
|
-
if (
|
|
99
|
+
if (await confirm('\nCreate configuration files? (Y/n): ', options.yes)) {
|
|
346
100
|
try {
|
|
347
|
-
|
|
101
|
+
await (0, promises_1.writeFile)(configPath, JSON.stringify(config, null, 2));
|
|
348
102
|
console.log(chalk_1.default.green('✓ Created opencode.json'));
|
|
349
103
|
console.log(chalk_1.default.dim(' Plugin: @bergetai/opencode-auth'));
|
|
350
104
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
351
|
-
const templateFiles = fs
|
|
352
|
-
.readdirSync(templatesDir)
|
|
353
|
-
.filter((f) => f.endsWith('.md'));
|
|
105
|
+
const templateFiles = fs.readdirSync(templatesDir).filter((f) => f.endsWith('.md'));
|
|
354
106
|
for (const file of templateFiles) {
|
|
355
|
-
const
|
|
356
|
-
const
|
|
357
|
-
fs.copyFileSync(
|
|
107
|
+
const source = node_path_1.default.join(templatesDir, file);
|
|
108
|
+
const destination = node_path_1.default.join(agentsDir, file);
|
|
109
|
+
fs.copyFileSync(source, destination);
|
|
358
110
|
}
|
|
359
111
|
console.log(chalk_1.default.green(`✓ Created ${templateFiles.length} agent definitions in .opencode/agents/`));
|
|
360
112
|
}
|
|
@@ -379,7 +131,7 @@ function registerCodeCommands(program) {
|
|
|
379
131
|
catch (error) {
|
|
380
132
|
(0, error_handler_1.handleError)('Failed to initialize project', error);
|
|
381
133
|
}
|
|
382
|
-
})
|
|
134
|
+
});
|
|
383
135
|
code
|
|
384
136
|
.command(command_structure_1.SUBCOMMANDS.CODE.RUN)
|
|
385
137
|
.description('Run AI coding assistant')
|
|
@@ -388,22 +140,22 @@ function registerCodeCommands(program) {
|
|
|
388
140
|
.option('-a, --analysis', 'Use fast analysis model for context building')
|
|
389
141
|
.option('--no-config', 'Run without loading project config')
|
|
390
142
|
.option('-y, --yes', 'Automatically answer yes to all prompts (for automation)')
|
|
391
|
-
.action((prompt, options) =>
|
|
143
|
+
.action(async (prompt, options) => {
|
|
392
144
|
try {
|
|
393
|
-
const configPath =
|
|
145
|
+
const configPath = node_path_1.default.join(process.cwd(), 'opencode.json');
|
|
394
146
|
// Ensure opencode is installed
|
|
395
|
-
if (!(
|
|
147
|
+
if (!(await ensureOpencodeInstalled(options.yes))) {
|
|
396
148
|
return;
|
|
397
149
|
}
|
|
398
150
|
let config = null;
|
|
399
151
|
if (!options.noConfig && fs.existsSync(configPath)) {
|
|
400
152
|
try {
|
|
401
|
-
const configContent =
|
|
153
|
+
const configContent = await (0, promises_1.readFile)(configPath, 'utf8');
|
|
402
154
|
config = JSON.parse(configContent);
|
|
403
155
|
console.log(chalk_1.default.dim(`Loaded config for project: ${config.projectName}`));
|
|
404
156
|
console.log(chalk_1.default.dim(`Models: Analysis=${config.analysisModel}, Build=${config.buildModel}`));
|
|
405
157
|
}
|
|
406
|
-
catch
|
|
158
|
+
catch {
|
|
407
159
|
console.log(chalk_1.default.yellow('Warning: Failed to load opencode.json'));
|
|
408
160
|
}
|
|
409
161
|
}
|
|
@@ -413,24 +165,24 @@ function registerCodeCommands(program) {
|
|
|
413
165
|
return;
|
|
414
166
|
}
|
|
415
167
|
// Prepare opencode command
|
|
416
|
-
const
|
|
417
|
-
const
|
|
168
|
+
const environment = { ...process.env };
|
|
169
|
+
const opencodeArguments = [];
|
|
418
170
|
// Read --stage and --local from root program options
|
|
419
171
|
// (these flags are registered at program level, not subcommand level)
|
|
420
172
|
const isStage = process.argv.includes('--stage');
|
|
421
173
|
const isLocal = process.argv.includes('--local');
|
|
422
174
|
if (isStage) {
|
|
423
175
|
console.log(chalk_1.default.cyan('Using Berget stage environment'));
|
|
424
|
-
|
|
425
|
-
|
|
176
|
+
environment.BERGET_API_URL = 'https://api.stage.berget.ai';
|
|
177
|
+
environment.BERGET_INFERENCE_URL = 'https://api.stage.berget.ai/v1';
|
|
426
178
|
}
|
|
427
179
|
else if (isLocal) {
|
|
428
180
|
console.log(chalk_1.default.cyan('Using local development environment'));
|
|
429
|
-
|
|
430
|
-
|
|
181
|
+
environment.BERGET_API_URL = 'http://localhost:3000';
|
|
182
|
+
environment.BERGET_INFERENCE_URL = 'http://localhost:3000/v1';
|
|
431
183
|
}
|
|
432
184
|
if (prompt) {
|
|
433
|
-
|
|
185
|
+
opencodeArguments.push('run', prompt);
|
|
434
186
|
}
|
|
435
187
|
// Choose model based on analysis flag or override
|
|
436
188
|
let selectedModel = options.model || config.buildModel;
|
|
@@ -438,13 +190,13 @@ function registerCodeCommands(program) {
|
|
|
438
190
|
selectedModel = config.analysisModel;
|
|
439
191
|
}
|
|
440
192
|
if (selectedModel) {
|
|
441
|
-
|
|
193
|
+
opencodeArguments.push('--model', selectedModel);
|
|
442
194
|
}
|
|
443
195
|
console.log(chalk_1.default.cyan('Starting OpenCode...'));
|
|
444
196
|
// Spawn opencode process
|
|
445
|
-
const opencode = (0,
|
|
197
|
+
const opencode = (0, node_child_process_1.spawn)('opencode', opencodeArguments, {
|
|
198
|
+
env: environment,
|
|
446
199
|
stdio: 'inherit',
|
|
447
|
-
env: env,
|
|
448
200
|
});
|
|
449
201
|
opencode.on('close', (code) => {
|
|
450
202
|
if (code !== 0) {
|
|
@@ -459,30 +211,30 @@ function registerCodeCommands(program) {
|
|
|
459
211
|
catch (error) {
|
|
460
212
|
(0, error_handler_1.handleError)('Failed to run OpenCode', error);
|
|
461
213
|
}
|
|
462
|
-
})
|
|
214
|
+
});
|
|
463
215
|
code
|
|
464
216
|
.command(command_structure_1.SUBCOMMANDS.CODE.SERVE)
|
|
465
217
|
.description('Start OpenCode web server')
|
|
466
218
|
.option('-p, --port <port>', 'Port to run the server on (default: 3000)')
|
|
467
219
|
.option('-h, --host <host>', 'Host to bind the server to (default: localhost)')
|
|
468
220
|
.option('-y, --yes', 'Automatically answer yes to all prompts (for automation)')
|
|
469
|
-
.action((options) =>
|
|
221
|
+
.action(async (options) => {
|
|
470
222
|
try {
|
|
471
223
|
// Ensure opencode is installed
|
|
472
|
-
if (!(
|
|
224
|
+
if (!(await ensureOpencodeInstalled(options.yes))) {
|
|
473
225
|
return;
|
|
474
226
|
}
|
|
475
227
|
console.log(chalk_1.default.cyan('🚀 Starting OpenCode web server...'));
|
|
476
228
|
// Prepare opencode serve command
|
|
477
|
-
const
|
|
229
|
+
const serveArguments = ['serve'];
|
|
478
230
|
if (options.port) {
|
|
479
|
-
|
|
231
|
+
serveArguments.push('--port', options.port);
|
|
480
232
|
}
|
|
481
233
|
if (options.host) {
|
|
482
|
-
|
|
234
|
+
serveArguments.push('--host', options.host);
|
|
483
235
|
}
|
|
484
236
|
// Spawn opencode serve process
|
|
485
|
-
const opencode = (0,
|
|
237
|
+
const opencode = (0, node_child_process_1.spawn)('opencode', serveArguments, {
|
|
486
238
|
stdio: 'inherit',
|
|
487
239
|
});
|
|
488
240
|
opencode.on('close', (code) => {
|
|
@@ -498,20 +250,20 @@ function registerCodeCommands(program) {
|
|
|
498
250
|
catch (error) {
|
|
499
251
|
(0, error_handler_1.handleError)('Failed to start OpenCode server', error);
|
|
500
252
|
}
|
|
501
|
-
})
|
|
253
|
+
});
|
|
502
254
|
code
|
|
503
255
|
.command(command_structure_1.SUBCOMMANDS.CODE.UPDATE)
|
|
504
256
|
.description('Update OpenCode and agents to latest versions')
|
|
505
257
|
.option('-f, --force', 'Force update even if already latest')
|
|
506
258
|
.option('-y, --yes', 'Automatically answer yes to all prompts (for automation)')
|
|
507
|
-
.action((options) =>
|
|
259
|
+
.action(async (options) => {
|
|
508
260
|
try {
|
|
509
261
|
console.log(chalk_1.default.cyan('🔄 Updating OpenCode configuration...'));
|
|
510
262
|
// Ensure opencode is installed first
|
|
511
|
-
if (!(
|
|
263
|
+
if (!(await ensureOpencodeInstalled(options.yes))) {
|
|
512
264
|
return;
|
|
513
265
|
}
|
|
514
|
-
const configPath =
|
|
266
|
+
const configPath = node_path_1.default.join(process.cwd(), 'opencode.json');
|
|
515
267
|
// Check if project is initialized
|
|
516
268
|
if (!fs.existsSync(configPath)) {
|
|
517
269
|
console.log(chalk_1.default.red('❌ No OpenCode configuration found.'));
|
|
@@ -521,7 +273,7 @@ function registerCodeCommands(program) {
|
|
|
521
273
|
// Read current configuration
|
|
522
274
|
let currentConfig;
|
|
523
275
|
try {
|
|
524
|
-
const configContent =
|
|
276
|
+
const configContent = await (0, promises_1.readFile)(configPath, 'utf8');
|
|
525
277
|
currentConfig = JSON.parse(configContent);
|
|
526
278
|
}
|
|
527
279
|
catch (error) {
|
|
@@ -533,30 +285,21 @@ function registerCodeCommands(program) {
|
|
|
533
285
|
if (currentConfig.model) {
|
|
534
286
|
console.log(chalk_1.default.dim(` Model: ${currentConfig.model}`));
|
|
535
287
|
}
|
|
536
|
-
const agentsDir =
|
|
288
|
+
const agentsDir = node_path_1.default.join(process.cwd(), '.opencode', 'agents');
|
|
537
289
|
const templatesDir = getAgentTemplatesDir();
|
|
538
|
-
const templateFiles = fs
|
|
539
|
-
.readdirSync(templatesDir)
|
|
540
|
-
.filter((f) => f.endsWith('.md'));
|
|
541
|
-
const latestConfig = {
|
|
542
|
-
$schema: 'https://opencode.ai/config.json',
|
|
543
|
-
plugin: ['@bergetai/opencode-auth@1.0.16'],
|
|
544
|
-
};
|
|
290
|
+
const templateFiles = fs.readdirSync(templatesDir).filter((f) => f.endsWith('.md'));
|
|
545
291
|
// Check if agent definitions need updating
|
|
546
292
|
let agentsNeedUpdate = false;
|
|
547
|
-
const existingAgentFiles = fs.existsSync(agentsDir)
|
|
548
|
-
? fs.readdirSync(agentsDir).filter((f) => f.endsWith('.md'))
|
|
549
|
-
: [];
|
|
550
293
|
for (const file of templateFiles) {
|
|
551
|
-
const
|
|
552
|
-
const
|
|
553
|
-
if (!fs.existsSync(
|
|
294
|
+
const source = node_path_1.default.join(templatesDir, file);
|
|
295
|
+
const destination = node_path_1.default.join(agentsDir, file);
|
|
296
|
+
if (!fs.existsSync(destination)) {
|
|
554
297
|
agentsNeedUpdate = true;
|
|
555
298
|
break;
|
|
556
299
|
}
|
|
557
|
-
const
|
|
558
|
-
const
|
|
559
|
-
if (
|
|
300
|
+
const sourceContent = fs.readFileSync(source, 'utf8');
|
|
301
|
+
const destinationContent = fs.readFileSync(destination, 'utf8');
|
|
302
|
+
if (sourceContent !== destinationContent) {
|
|
560
303
|
agentsNeedUpdate = true;
|
|
561
304
|
break;
|
|
562
305
|
}
|
|
@@ -582,37 +325,37 @@ function registerCodeCommands(program) {
|
|
|
582
325
|
if (!options.yes) {
|
|
583
326
|
console.log(chalk_1.default.blue('\nThis will update your agent definitions and OpenCode configuration.'));
|
|
584
327
|
const hasGitRepo = hasGit();
|
|
585
|
-
if (
|
|
586
|
-
console.log(chalk_1.default.
|
|
328
|
+
if (hasGitRepo) {
|
|
329
|
+
console.log(chalk_1.default.green('✓ Git repository detected - changes are tracked'));
|
|
587
330
|
}
|
|
588
331
|
else {
|
|
589
|
-
console.log(chalk_1.default.
|
|
332
|
+
console.log(chalk_1.default.yellow('⚠️ No .git repository detected - backup will be created'));
|
|
590
333
|
}
|
|
591
334
|
}
|
|
592
|
-
if (
|
|
335
|
+
if (await confirm('\nProceed with update? (Y/n): ', options.yes)) {
|
|
593
336
|
try {
|
|
594
337
|
let backupPath = null;
|
|
595
338
|
if (!hasGit()) {
|
|
596
339
|
backupPath = `${configPath}.backup.${Date.now()}`;
|
|
597
|
-
|
|
598
|
-
console.log(chalk_1.default.green(`✓ Backed up current config to ${
|
|
340
|
+
await (0, promises_1.writeFile)(backupPath, JSON.stringify(currentConfig, null, 2));
|
|
341
|
+
console.log(chalk_1.default.green(`✓ Backed up current config to ${node_path_1.default.basename(backupPath)}`));
|
|
599
342
|
}
|
|
600
343
|
// Remove inline agent section from opencode.json if present
|
|
601
344
|
if (currentConfig.agent) {
|
|
602
345
|
delete currentConfig.agent;
|
|
603
|
-
|
|
346
|
+
await (0, promises_1.writeFile)(configPath, JSON.stringify(currentConfig, null, 2));
|
|
604
347
|
console.log(chalk_1.default.green('✓ Removed inline agent config from opencode.json'));
|
|
605
348
|
}
|
|
606
349
|
// Sync agent markdown files from templates
|
|
607
350
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
608
351
|
let updatedCount = 0;
|
|
609
352
|
for (const file of templateFiles) {
|
|
610
|
-
const
|
|
611
|
-
const
|
|
612
|
-
const agentName =
|
|
613
|
-
if (!fs.existsSync(
|
|
614
|
-
fs.readFileSync(
|
|
615
|
-
fs.copyFileSync(
|
|
353
|
+
const source = node_path_1.default.join(templatesDir, file);
|
|
354
|
+
const destination = node_path_1.default.join(agentsDir, file);
|
|
355
|
+
const agentName = node_path_1.default.basename(file, '.md');
|
|
356
|
+
if (!fs.existsSync(destination) ||
|
|
357
|
+
fs.readFileSync(source, 'utf8') !== fs.readFileSync(destination, 'utf8')) {
|
|
358
|
+
fs.copyFileSync(source, destination);
|
|
616
359
|
updatedCount++;
|
|
617
360
|
console.log(chalk_1.default.cyan(` • Updated agent: ${agentName}`));
|
|
618
361
|
}
|
|
@@ -621,7 +364,7 @@ function registerCodeCommands(program) {
|
|
|
621
364
|
console.log(chalk_1.default.green(`✓ Updated ${updatedCount} agent definition(s)`));
|
|
622
365
|
}
|
|
623
366
|
// Update AGENTS.md if it doesn't exist
|
|
624
|
-
const agentsMdPath =
|
|
367
|
+
const agentsMdPath = node_path_1.default.join(process.cwd(), 'AGENTS.md');
|
|
625
368
|
if (!fs.existsSync(agentsMdPath)) {
|
|
626
369
|
const agentsMdContent = `# Berget Code Agents
|
|
627
370
|
|
|
@@ -672,7 +415,7 @@ See https://opencode.ai/docs/agents/ for available options.
|
|
|
672
415
|
|
|
673
416
|
*Updated by berget code update*
|
|
674
417
|
`;
|
|
675
|
-
|
|
418
|
+
await (0, promises_1.writeFile)(agentsMdPath, agentsMdContent);
|
|
676
419
|
console.log(chalk_1.default.green('✓ Created AGENTS.md documentation'));
|
|
677
420
|
}
|
|
678
421
|
console.log(chalk_1.default.green('\n✅ Update completed successfully!'));
|
|
@@ -681,10 +424,10 @@ See https://opencode.ai/docs/agents/ for available options.
|
|
|
681
424
|
console.error(chalk_1.default.red('Failed to update configuration:'));
|
|
682
425
|
(0, error_handler_1.handleError)('Update failed', error);
|
|
683
426
|
try {
|
|
684
|
-
|
|
427
|
+
await (0, promises_1.writeFile)(configPath, JSON.stringify(currentConfig, null, 2));
|
|
685
428
|
console.log(chalk_1.default.yellow('📁 Restored original configuration from backup'));
|
|
686
429
|
}
|
|
687
|
-
catch
|
|
430
|
+
catch {
|
|
688
431
|
console.error(chalk_1.default.red('Failed to restore backup:'));
|
|
689
432
|
}
|
|
690
433
|
}
|
|
@@ -693,9 +436,139 @@ See https://opencode.ai/docs/agents/ for available options.
|
|
|
693
436
|
console.log(chalk_1.default.yellow('Update cancelled.'));
|
|
694
437
|
}
|
|
695
438
|
}
|
|
696
|
-
catch
|
|
697
|
-
(
|
|
439
|
+
catch {
|
|
440
|
+
console.error(chalk_1.default.red('Failed to update OpenCode configuration'));
|
|
698
441
|
}
|
|
699
|
-
})
|
|
442
|
+
});
|
|
700
443
|
}
|
|
701
444
|
exports.registerCodeCommands = registerCodeCommands;
|
|
445
|
+
/**
|
|
446
|
+
* Check if opencode is installed
|
|
447
|
+
*/
|
|
448
|
+
function checkOpencodeInstalled() {
|
|
449
|
+
return new Promise((resolve) => {
|
|
450
|
+
const child = (0, node_child_process_1.spawn)('which', ['opencode'], {
|
|
451
|
+
stdio: 'pipe',
|
|
452
|
+
});
|
|
453
|
+
child.on('close', (code) => {
|
|
454
|
+
resolve(code === 0);
|
|
455
|
+
});
|
|
456
|
+
child.on('error', () => {
|
|
457
|
+
resolve(false);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Helper function to get user confirmation
|
|
463
|
+
*/
|
|
464
|
+
async function confirm(question, autoYes = false) {
|
|
465
|
+
if (autoYes) {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
return new Promise((resolve) => {
|
|
469
|
+
const rl = node_readline_1.default.createInterface({
|
|
470
|
+
input: process.stdin,
|
|
471
|
+
output: process.stdout,
|
|
472
|
+
});
|
|
473
|
+
rl.question(question, (answer) => {
|
|
474
|
+
rl.close();
|
|
475
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes' || answer === '');
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Ensure opencode is installed, offering to install if not
|
|
481
|
+
*/
|
|
482
|
+
async function ensureOpencodeInstalled(autoYes = false) {
|
|
483
|
+
let opencodeInstalled = await checkOpencodeInstalled();
|
|
484
|
+
if (!opencodeInstalled) {
|
|
485
|
+
if (!autoYes) {
|
|
486
|
+
console.log(chalk_1.default.red('OpenCode is not installed.'));
|
|
487
|
+
console.log(chalk_1.default.blue('OpenCode is required for the AI coding assistant.'));
|
|
488
|
+
}
|
|
489
|
+
if (await confirm('Would you like to install OpenCode automatically? (Y/n): ', autoYes)) {
|
|
490
|
+
opencodeInstalled = await installOpencode();
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
if (!autoYes) {
|
|
494
|
+
console.log(chalk_1.default.blue('\nInstallation cancelled.'));
|
|
495
|
+
console.log(chalk_1.default.blue('To install manually: curl -fsSL https://opencode.ai/install | bash'));
|
|
496
|
+
console.log(chalk_1.default.blue('Or visit: https://opencode.ai/docs'));
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return opencodeInstalled;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get the path to the bundled agent templates directory
|
|
504
|
+
*/
|
|
505
|
+
function getAgentTemplatesDir() {
|
|
506
|
+
return node_path_1.default.resolve(__dirname, '../../templates/agents');
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Get project name from current directory or package.json
|
|
510
|
+
*/
|
|
511
|
+
function getProjectName() {
|
|
512
|
+
try {
|
|
513
|
+
const packageJsonPath = node_path_1.default.join(process.cwd(), 'package.json');
|
|
514
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
515
|
+
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
516
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
517
|
+
return packageJson.name || node_path_1.default.basename(process.cwd());
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
// Ignore error and fallback to directory name
|
|
522
|
+
}
|
|
523
|
+
return node_path_1.default.basename(process.cwd());
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Check if current directory has git
|
|
527
|
+
*/
|
|
528
|
+
function hasGit() {
|
|
529
|
+
try {
|
|
530
|
+
return fs.existsSync(node_path_1.default.join(process.cwd(), '.git'));
|
|
531
|
+
}
|
|
532
|
+
catch {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Install opencode via npm
|
|
538
|
+
*/
|
|
539
|
+
async function installOpencode() {
|
|
540
|
+
console.log(chalk_1.default.cyan('Installing OpenCode via npm...'));
|
|
541
|
+
try {
|
|
542
|
+
await new Promise((resolve, reject) => {
|
|
543
|
+
const install = (0, node_child_process_1.spawn)('npm', ['install', '-g', 'opencode-ai@1.3'], {
|
|
544
|
+
stdio: 'inherit',
|
|
545
|
+
});
|
|
546
|
+
install.on('close', (code) => {
|
|
547
|
+
if (code === 0) {
|
|
548
|
+
console.log(chalk_1.default.green('✓ OpenCode installed successfully!'));
|
|
549
|
+
resolve();
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
reject(new Error(`Installation failed with code ${code}`));
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
install.on('error', reject);
|
|
556
|
+
});
|
|
557
|
+
// Verify installation
|
|
558
|
+
const opencodeInstalled = await checkOpencodeInstalled();
|
|
559
|
+
if (!opencodeInstalled) {
|
|
560
|
+
console.log(chalk_1.default.yellow('Installation completed but opencode command not found.'));
|
|
561
|
+
console.log(chalk_1.default.yellow('You may need to restart your terminal or check your PATH.'));
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
console.error(chalk_1.default.red('Failed to install OpenCode:'));
|
|
568
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
569
|
+
console.log(chalk_1.default.blue('\nAlternative installation methods:'));
|
|
570
|
+
console.log(chalk_1.default.blue(' curl -fsSL https://opencode.ai/install | sh'));
|
|
571
|
+
console.log(chalk_1.default.blue(' Or visit: https://opencode.ai/docs'));
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
}
|