cortex-agents 2.2.0 → 2.3.0
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/.opencode/agents/build.md +123 -20
- package/.opencode/agents/debug.md +97 -11
- package/.opencode/agents/devops.md +75 -7
- package/.opencode/agents/fullstack.md +89 -1
- package/.opencode/agents/plan.md +75 -5
- package/.opencode/agents/security.md +60 -1
- package/.opencode/agents/testing.md +45 -1
- package/README.md +82 -30
- package/dist/cli.js +207 -48
- package/dist/index.js +6 -6
- package/dist/tools/branch.d.ts +7 -1
- package/dist/tools/branch.d.ts.map +1 -1
- package/dist/tools/branch.js +88 -53
- package/dist/tools/cortex.d.ts +19 -0
- package/dist/tools/cortex.d.ts.map +1 -1
- package/dist/tools/cortex.js +109 -0
- package/dist/tools/session.d.ts.map +1 -1
- package/dist/tools/session.js +3 -1
- package/dist/tools/task.d.ts.map +1 -1
- package/dist/tools/task.js +65 -57
- package/dist/tools/worktree.d.ts +10 -2
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +320 -246
- package/dist/utils/shell.d.ts +53 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +118 -0
- package/dist/utils/terminal.d.ts +66 -0
- package/dist/utils/terminal.d.ts.map +1 -0
- package/dist/utils/terminal.js +627 -0
- package/dist/utils/worktree-detect.d.ts.map +1 -1
- package/dist/utils/worktree-detect.js +5 -4
- package/package.json +5 -4
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as path from "path";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import prompts from "prompts";
|
|
6
6
|
import { PRIMARY_AGENTS, SUBAGENTS, ALL_AGENTS, getPrimaryChoices, getSubagentChoices, } from "./registry.js";
|
|
7
|
-
const VERSION = "2.
|
|
7
|
+
const VERSION = "2.3.0";
|
|
8
8
|
const PLUGIN_NAME = "cortex-agents";
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -38,6 +38,66 @@ function writeConfig(configPath, config) {
|
|
|
38
38
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
39
39
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
40
40
|
}
|
|
41
|
+
// ─── Per-Project Model Config (.opencode/models.json) ───────────────────────
|
|
42
|
+
const PROJECT_MODELS_FILE = "models.json";
|
|
43
|
+
function getProjectModelsPath() {
|
|
44
|
+
return path.join(process.cwd(), ".opencode", PROJECT_MODELS_FILE);
|
|
45
|
+
}
|
|
46
|
+
function hasProjectModelsConfig() {
|
|
47
|
+
return fs.existsSync(getProjectModelsPath());
|
|
48
|
+
}
|
|
49
|
+
function readProjectModels() {
|
|
50
|
+
const modelsPath = getProjectModelsPath();
|
|
51
|
+
if (!fs.existsSync(modelsPath))
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(fs.readFileSync(modelsPath, "utf-8"));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function writeProjectModels(primary, subagent) {
|
|
61
|
+
const modelsPath = getProjectModelsPath();
|
|
62
|
+
const dir = path.dirname(modelsPath);
|
|
63
|
+
if (!fs.existsSync(dir)) {
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
const config = {
|
|
67
|
+
primary: { model: primary },
|
|
68
|
+
subagent: { model: subagent },
|
|
69
|
+
agents: {},
|
|
70
|
+
};
|
|
71
|
+
for (const name of PRIMARY_AGENTS) {
|
|
72
|
+
config.agents[name] = { model: primary };
|
|
73
|
+
}
|
|
74
|
+
for (const name of SUBAGENTS) {
|
|
75
|
+
config.agents[name] = { model: subagent };
|
|
76
|
+
}
|
|
77
|
+
fs.writeFileSync(modelsPath, JSON.stringify(config, null, 2) + "\n");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Sync .opencode/models.json → local opencode.json agent model settings.
|
|
81
|
+
* Creates or merges into local opencode.json at project root.
|
|
82
|
+
*/
|
|
83
|
+
function syncProjectModelsToConfig() {
|
|
84
|
+
const models = readProjectModels();
|
|
85
|
+
if (!models)
|
|
86
|
+
return false;
|
|
87
|
+
const localPath = path.join(process.cwd(), "opencode.json");
|
|
88
|
+
const config = fs.existsSync(localPath)
|
|
89
|
+
? readConfig(localPath)
|
|
90
|
+
: { $schema: "https://opencode.ai/config.json" };
|
|
91
|
+
if (!config.agent)
|
|
92
|
+
config.agent = {};
|
|
93
|
+
for (const [name, entry] of Object.entries(models.agents)) {
|
|
94
|
+
if (!config.agent[name])
|
|
95
|
+
config.agent[name] = {};
|
|
96
|
+
config.agent[name].model = entry.model;
|
|
97
|
+
}
|
|
98
|
+
writeConfig(localPath, config);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
41
101
|
// ─── File Copy Helpers ───────────────────────────────────────────────────────
|
|
42
102
|
function copyDirRecursive(src, dest) {
|
|
43
103
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -137,8 +197,16 @@ function install() {
|
|
|
137
197
|
// Copy agents and skills into the global opencode config dir
|
|
138
198
|
console.log("Installing agents and skills...");
|
|
139
199
|
installAgentsAndSkills(globalDir);
|
|
200
|
+
// Sync per-project models if .opencode/models.json exists
|
|
201
|
+
if (hasProjectModelsConfig()) {
|
|
202
|
+
console.log("\nPer-project model config found (.opencode/models.json)");
|
|
203
|
+
if (syncProjectModelsToConfig()) {
|
|
204
|
+
console.log(" Synced model settings to local opencode.json");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
140
207
|
console.log("\nDone! Next steps:");
|
|
141
|
-
console.log(` 1. Run 'npx ${PLUGIN_NAME} configure' to select your models`);
|
|
208
|
+
console.log(` 1. Run 'npx ${PLUGIN_NAME} configure' to select your models (global)`);
|
|
209
|
+
console.log(` Or 'npx ${PLUGIN_NAME} configure --project' for per-project config`);
|
|
142
210
|
console.log(" 2. Restart OpenCode to load the plugin\n");
|
|
143
211
|
}
|
|
144
212
|
function uninstall() {
|
|
@@ -180,23 +248,82 @@ function uninstall() {
|
|
|
180
248
|
async function configure() {
|
|
181
249
|
const args = process.argv.slice(3);
|
|
182
250
|
const isReset = args.includes("--reset");
|
|
251
|
+
const isProject = args.includes("--project");
|
|
183
252
|
// Handle --reset flag
|
|
184
253
|
if (isReset) {
|
|
185
|
-
return configureReset();
|
|
254
|
+
return configureReset(isProject);
|
|
255
|
+
}
|
|
256
|
+
const scope = isProject ? "Per-Project" : "Global";
|
|
257
|
+
console.log(`\n🔧 Cortex Agents — ${scope} Model Configuration\n`);
|
|
258
|
+
if (isProject) {
|
|
259
|
+
const opencodeDir = path.join(process.cwd(), ".opencode");
|
|
260
|
+
if (!fs.existsSync(opencodeDir)) {
|
|
261
|
+
console.log(`⚠ No .opencode/ directory found in ${process.cwd()}.`);
|
|
262
|
+
console.log(` Run 'npx ${PLUGIN_NAME} install' first, or use 'configure' without --project for global config.\n`);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
console.log(`Project: ${process.cwd()}`);
|
|
266
|
+
console.log(`Config: .opencode/models.json + opencode.json\n`);
|
|
186
267
|
}
|
|
187
|
-
|
|
188
|
-
// Ensure plugin is installed first
|
|
268
|
+
// Ensure plugin is installed first (for global mode)
|
|
189
269
|
const configInfo = findOpencodeConfig();
|
|
190
270
|
const config = configInfo
|
|
191
271
|
? readConfig(configInfo.path)
|
|
192
272
|
: { $schema: "https://opencode.ai/config.json" };
|
|
193
|
-
if (!config.plugin?.includes(PLUGIN_NAME)) {
|
|
273
|
+
if (!isProject && !config.plugin?.includes(PLUGIN_NAME)) {
|
|
194
274
|
console.log(`⚠ Plugin not installed. Adding '${PLUGIN_NAME}' to config first.\n`);
|
|
195
275
|
if (!config.plugin)
|
|
196
276
|
config.plugin = [];
|
|
197
277
|
config.plugin.push(PLUGIN_NAME);
|
|
198
278
|
}
|
|
199
279
|
// ── Primary model selection ────────────────────────────────
|
|
280
|
+
const { primary, subagent } = await promptModelSelection();
|
|
281
|
+
// ── Write config ───────────────────────────────────────────
|
|
282
|
+
if (isProject) {
|
|
283
|
+
// Per-project: write .opencode/models.json + sync to local opencode.json
|
|
284
|
+
writeProjectModels(primary, subagent);
|
|
285
|
+
syncProjectModelsToConfig();
|
|
286
|
+
const modelsPath = getProjectModelsPath();
|
|
287
|
+
const localConfigPath = path.join(process.cwd(), "opencode.json");
|
|
288
|
+
console.log("━".repeat(50));
|
|
289
|
+
console.log(`✓ Per-project config saved:\n`);
|
|
290
|
+
console.log(` Models: ${modelsPath}`);
|
|
291
|
+
console.log(` Runtime: ${localConfigPath}\n`);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
// Global: write to opencode.json (existing behavior)
|
|
295
|
+
if (!config.agent)
|
|
296
|
+
config.agent = {};
|
|
297
|
+
for (const name of PRIMARY_AGENTS) {
|
|
298
|
+
if (!config.agent[name])
|
|
299
|
+
config.agent[name] = {};
|
|
300
|
+
config.agent[name].model = primary;
|
|
301
|
+
}
|
|
302
|
+
for (const name of SUBAGENTS) {
|
|
303
|
+
if (!config.agent[name])
|
|
304
|
+
config.agent[name] = {};
|
|
305
|
+
config.agent[name].model = subagent;
|
|
306
|
+
}
|
|
307
|
+
const targetPath = configInfo?.path || path.join(getGlobalDir(), "opencode.json");
|
|
308
|
+
writeConfig(targetPath, config);
|
|
309
|
+
console.log("━".repeat(50));
|
|
310
|
+
console.log(`✓ Configuration saved to ${targetPath}\n`);
|
|
311
|
+
}
|
|
312
|
+
console.log(" Primary agents:");
|
|
313
|
+
for (const name of PRIMARY_AGENTS) {
|
|
314
|
+
console.log(` ${name.padEnd(10)} → ${primary}`);
|
|
315
|
+
}
|
|
316
|
+
console.log("\n Subagents:");
|
|
317
|
+
for (const name of SUBAGENTS) {
|
|
318
|
+
console.log(` ${name.padEnd(10)} → ${subagent}`);
|
|
319
|
+
}
|
|
320
|
+
console.log("\nRestart OpenCode to apply changes.\n");
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Interactive prompt for primary + subagent model selection.
|
|
324
|
+
* Shared between global and per-project configure flows.
|
|
325
|
+
*/
|
|
326
|
+
async function promptModelSelection() {
|
|
200
327
|
const primaryChoices = getPrimaryChoices();
|
|
201
328
|
primaryChoices.push({
|
|
202
329
|
title: "Enter custom model ID",
|
|
@@ -211,7 +338,6 @@ async function configure() {
|
|
|
211
338
|
choices: primaryChoices,
|
|
212
339
|
hint: "Use arrow keys, Enter to confirm",
|
|
213
340
|
});
|
|
214
|
-
// User cancelled (Ctrl+C)
|
|
215
341
|
if (primaryModel === undefined) {
|
|
216
342
|
console.log("\nConfiguration cancelled.\n");
|
|
217
343
|
process.exit(0);
|
|
@@ -265,36 +391,54 @@ async function configure() {
|
|
|
265
391
|
subagent = custom;
|
|
266
392
|
}
|
|
267
393
|
console.log(`✓ Subagent model: ${subagent}\n`);
|
|
268
|
-
|
|
269
|
-
if (!config.agent)
|
|
270
|
-
config.agent = {};
|
|
271
|
-
for (const name of PRIMARY_AGENTS) {
|
|
272
|
-
if (!config.agent[name])
|
|
273
|
-
config.agent[name] = {};
|
|
274
|
-
config.agent[name].model = primary;
|
|
275
|
-
}
|
|
276
|
-
for (const name of SUBAGENTS) {
|
|
277
|
-
if (!config.agent[name])
|
|
278
|
-
config.agent[name] = {};
|
|
279
|
-
config.agent[name].model = subagent;
|
|
280
|
-
}
|
|
281
|
-
const targetPath = configInfo?.path || path.join(getGlobalDir(), "opencode.json");
|
|
282
|
-
writeConfig(targetPath, config);
|
|
283
|
-
// ── Print summary ──────────────────────────────────────────
|
|
284
|
-
console.log("━".repeat(50));
|
|
285
|
-
console.log(`✓ Configuration saved to ${targetPath}\n`);
|
|
286
|
-
console.log(" Primary agents:");
|
|
287
|
-
for (const name of PRIMARY_AGENTS) {
|
|
288
|
-
console.log(` ${name.padEnd(10)} → ${primary}`);
|
|
289
|
-
}
|
|
290
|
-
console.log("\n Subagents:");
|
|
291
|
-
for (const name of SUBAGENTS) {
|
|
292
|
-
console.log(` ${name.padEnd(10)} → ${subagent}`);
|
|
293
|
-
}
|
|
294
|
-
console.log("\nRestart OpenCode to apply changes.\n");
|
|
394
|
+
return { primary, subagent };
|
|
295
395
|
}
|
|
296
|
-
function configureReset() {
|
|
297
|
-
|
|
396
|
+
function configureReset(isProject = false) {
|
|
397
|
+
const scope = isProject ? "Per-Project" : "Global";
|
|
398
|
+
console.log(`\n🔧 Cortex Agents — Reset ${scope} Model Configuration\n`);
|
|
399
|
+
if (isProject) {
|
|
400
|
+
// Reset per-project config
|
|
401
|
+
const modelsPath = getProjectModelsPath();
|
|
402
|
+
let removedModels = false;
|
|
403
|
+
if (fs.existsSync(modelsPath)) {
|
|
404
|
+
fs.unlinkSync(modelsPath);
|
|
405
|
+
console.log(`✓ Removed ${modelsPath}`);
|
|
406
|
+
removedModels = true;
|
|
407
|
+
}
|
|
408
|
+
// Also clean agent models from local opencode.json
|
|
409
|
+
const localConfigPath = path.join(process.cwd(), "opencode.json");
|
|
410
|
+
if (fs.existsSync(localConfigPath)) {
|
|
411
|
+
const config = readConfig(localConfigPath);
|
|
412
|
+
if (config.agent) {
|
|
413
|
+
let resetCount = 0;
|
|
414
|
+
for (const name of ALL_AGENTS) {
|
|
415
|
+
if (config.agent[name]?.model) {
|
|
416
|
+
delete config.agent[name].model;
|
|
417
|
+
resetCount++;
|
|
418
|
+
if (Object.keys(config.agent[name]).length === 0) {
|
|
419
|
+
delete config.agent[name];
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (Object.keys(config.agent).length === 0) {
|
|
424
|
+
delete config.agent;
|
|
425
|
+
}
|
|
426
|
+
if (resetCount > 0) {
|
|
427
|
+
writeConfig(localConfigPath, config);
|
|
428
|
+
console.log(`✓ Removed ${resetCount} agent model entries from ${localConfigPath}`);
|
|
429
|
+
removedModels = true;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (!removedModels) {
|
|
434
|
+
console.log("No per-project model configuration found. Nothing to reset.\n");
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
console.log("\nAgents will now fall back to global or OpenCode default models.");
|
|
438
|
+
console.log("Restart OpenCode to apply changes.\n");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
// Global reset (existing behavior)
|
|
298
442
|
const configInfo = findOpencodeConfig();
|
|
299
443
|
if (!configInfo) {
|
|
300
444
|
console.log("No OpenCode config found. Nothing to reset.\n");
|
|
@@ -355,12 +499,20 @@ function status() {
|
|
|
355
499
|
: 0;
|
|
356
500
|
console.log(`\nAgents installed: ${agentCount}`);
|
|
357
501
|
console.log(`Skills installed: ${skillCount}`);
|
|
358
|
-
// Show model configuration
|
|
502
|
+
// Show per-project model configuration
|
|
503
|
+
const projectModels = readProjectModels();
|
|
504
|
+
if (projectModels) {
|
|
505
|
+
console.log("\nPer-Project Models (.opencode/models.json):");
|
|
506
|
+
console.log(` Primary agents: ${projectModels.primary.model}`);
|
|
507
|
+
console.log(` Subagents: ${projectModels.subagent.model}`);
|
|
508
|
+
}
|
|
509
|
+
// Show global/active model configuration
|
|
359
510
|
if (config.agent) {
|
|
360
511
|
const primaryModels = PRIMARY_AGENTS.map((n) => config.agent?.[n]?.model).filter(Boolean);
|
|
361
512
|
const subagentModels = SUBAGENTS.map((n) => config.agent?.[n]?.model).filter(Boolean);
|
|
362
513
|
if (primaryModels.length > 0 || subagentModels.length > 0) {
|
|
363
|
-
|
|
514
|
+
const source = projectModels ? "Active" : "Global";
|
|
515
|
+
console.log(`\n${source} Model Configuration (opencode.json):`);
|
|
364
516
|
if (primaryModels.length > 0) {
|
|
365
517
|
const unique = [...new Set(primaryModels)];
|
|
366
518
|
console.log(` Primary agents: ${unique.join(", ")}`);
|
|
@@ -370,14 +522,16 @@ function status() {
|
|
|
370
522
|
console.log(` Subagents: ${unique.join(", ")}`);
|
|
371
523
|
}
|
|
372
524
|
}
|
|
373
|
-
else {
|
|
525
|
+
else if (!projectModels) {
|
|
374
526
|
console.log("\nModels: Not configured (using OpenCode defaults)");
|
|
375
|
-
console.log(` Run 'npx ${PLUGIN_NAME} configure'
|
|
527
|
+
console.log(` Run 'npx ${PLUGIN_NAME} configure' for global config`);
|
|
528
|
+
console.log(` Run 'npx ${PLUGIN_NAME} configure --project' for per-project config`);
|
|
376
529
|
}
|
|
377
530
|
}
|
|
378
|
-
else {
|
|
531
|
+
else if (!projectModels) {
|
|
379
532
|
console.log("\nModels: Not configured (using OpenCode defaults)");
|
|
380
|
-
console.log(` Run 'npx ${PLUGIN_NAME} configure'
|
|
533
|
+
console.log(` Run 'npx ${PLUGIN_NAME} configure' for global config`);
|
|
534
|
+
console.log(` Run 'npx ${PLUGIN_NAME} configure --project' for per-project config`);
|
|
381
535
|
}
|
|
382
536
|
if (!isInstalled) {
|
|
383
537
|
console.log(`\nRun 'npx ${PLUGIN_NAME} install' to add to config.`);
|
|
@@ -395,17 +549,21 @@ USAGE:
|
|
|
395
549
|
|
|
396
550
|
COMMANDS:
|
|
397
551
|
install Install plugin, agents, and skills into OpenCode config
|
|
398
|
-
configure Interactive model selection
|
|
552
|
+
configure Interactive model selection (global)
|
|
553
|
+
configure --project Interactive model selection (per-project, saves to .opencode/)
|
|
399
554
|
configure --reset Reset model configuration to OpenCode defaults
|
|
555
|
+
configure --project --reset Reset per-project model configuration
|
|
400
556
|
uninstall Remove plugin, agents, skills, and model config
|
|
401
557
|
status Show installation and model configuration status
|
|
402
558
|
help Show this help message
|
|
403
559
|
|
|
404
560
|
EXAMPLES:
|
|
405
|
-
npx ${PLUGIN_NAME} install
|
|
406
|
-
npx ${PLUGIN_NAME} configure
|
|
407
|
-
npx ${PLUGIN_NAME} configure --
|
|
408
|
-
npx ${PLUGIN_NAME}
|
|
561
|
+
npx ${PLUGIN_NAME} install # Install plugin
|
|
562
|
+
npx ${PLUGIN_NAME} configure # Global model selection
|
|
563
|
+
npx ${PLUGIN_NAME} configure --project # Per-project models (.opencode/models.json)
|
|
564
|
+
npx ${PLUGIN_NAME} configure --reset # Reset global models
|
|
565
|
+
npx ${PLUGIN_NAME} configure --project --reset # Reset per-project models
|
|
566
|
+
npx ${PLUGIN_NAME} status # Check status
|
|
409
567
|
|
|
410
568
|
AGENTS:
|
|
411
569
|
Primary (build, plan, debug):
|
|
@@ -414,8 +572,9 @@ AGENTS:
|
|
|
414
572
|
Subagents (fullstack, testing, security, devops):
|
|
415
573
|
Handle focused tasks — a fast/cheap model works great.
|
|
416
574
|
|
|
417
|
-
TOOLS (
|
|
575
|
+
TOOLS (23):
|
|
418
576
|
cortex_init, cortex_status .cortex directory management
|
|
577
|
+
cortex_configure Per-project model configuration
|
|
419
578
|
worktree_create, worktree_list Git worktree management
|
|
420
579
|
worktree_remove, worktree_open
|
|
421
580
|
worktree_launch Launch worktree (terminal/PTY/background)
|
package/dist/index.js
CHANGED
|
@@ -22,15 +22,15 @@ export const CortexPlugin = async (ctx) => {
|
|
|
22
22
|
// Cortex tools - .cortex directory management
|
|
23
23
|
cortex_init: cortex.init,
|
|
24
24
|
cortex_status: cortex.status,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
cortex_configure: cortex.configure,
|
|
26
|
+
// Worktree tools - git worktree management (factories for toast notifications)
|
|
27
|
+
worktree_create: worktree.createCreate(ctx.client),
|
|
27
28
|
worktree_list: worktree.list,
|
|
28
|
-
worktree_remove: worktree.
|
|
29
|
+
worktree_remove: worktree.createRemove(ctx.client),
|
|
29
30
|
worktree_open: worktree.open,
|
|
30
|
-
// Dynamic tool: needs client + shell via factory (closure injection)
|
|
31
31
|
worktree_launch: worktree.createLaunch(ctx.client, ctx.$),
|
|
32
|
-
// Branch tools - git branch operations
|
|
33
|
-
branch_create: branch.
|
|
32
|
+
// Branch tools - git branch operations (factory for toast notifications)
|
|
33
|
+
branch_create: branch.createCreate(ctx.client),
|
|
34
34
|
branch_status: branch.status,
|
|
35
35
|
branch_switch: branch.switch_,
|
|
36
36
|
// Plan tools - implementation plan persistence
|
package/dist/tools/branch.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
type Client = PluginInput["client"];
|
|
3
|
+
/**
|
|
4
|
+
* Factory function that creates the branch_create tool with access
|
|
5
|
+
* to the OpenCode client for toast notifications.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createCreate(client: Client): {
|
|
2
8
|
description: string;
|
|
3
9
|
args: {
|
|
4
10
|
name: import("zod").ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/tools/branch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/tools/branch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD,KAAK,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;EA0E1C;AAED,eAAO,MAAM,MAAM;;;;CAkGjB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;CAmClB,CAAC;AAGH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC"}
|
package/dist/tools/branch.js
CHANGED
|
@@ -1,57 +1,91 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { git } from "../utils/shell.js";
|
|
2
3
|
const PROTECTED_BRANCHES = ["main", "master", "develop", "production", "staging"];
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Factory function that creates the branch_create tool with access
|
|
6
|
+
* to the OpenCode client for toast notifications.
|
|
7
|
+
*/
|
|
8
|
+
export function createCreate(client) {
|
|
9
|
+
return tool({
|
|
10
|
+
description: "Create and checkout a new git branch with proper naming convention",
|
|
11
|
+
args: {
|
|
12
|
+
name: tool.schema
|
|
13
|
+
.string()
|
|
14
|
+
.describe("Branch name slug (e.g., 'user-authentication', 'fix-login')"),
|
|
15
|
+
type: tool.schema
|
|
16
|
+
.enum(["feature", "bugfix", "hotfix", "refactor", "docs", "test", "chore"])
|
|
17
|
+
.describe("Branch type - determines prefix"),
|
|
18
|
+
},
|
|
19
|
+
async execute(args, context) {
|
|
20
|
+
const { name, type } = args;
|
|
21
|
+
const branchName = `${type}/${name}`;
|
|
22
|
+
// Check if we're in a git repository
|
|
23
|
+
try {
|
|
24
|
+
await git(context.worktree, "rev-parse", "--git-dir");
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return "✗ Error: Not in a git repository";
|
|
28
|
+
}
|
|
29
|
+
// Check if branch already exists
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await git(context.worktree, "branch", "--list", branchName);
|
|
32
|
+
if (stdout.trim()) {
|
|
33
|
+
return `✗ Error: Branch '${branchName}' already exists.
|
|
28
34
|
|
|
29
35
|
Use branch_switch to switch to it, or choose a different name.`;
|
|
36
|
+
}
|
|
30
37
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
catch {
|
|
39
|
+
// Ignore error, branch check is optional
|
|
40
|
+
}
|
|
41
|
+
// Create and checkout the branch
|
|
42
|
+
try {
|
|
43
|
+
await git(context.worktree, "checkout", "-b", branchName);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
try {
|
|
47
|
+
await client.tui.showToast({
|
|
48
|
+
body: {
|
|
49
|
+
title: `Branch: ${branchName}`,
|
|
50
|
+
message: `Failed to create: ${error.message || error}`,
|
|
51
|
+
variant: "error",
|
|
52
|
+
duration: 8000,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Toast failure is non-fatal
|
|
58
|
+
}
|
|
59
|
+
return `✗ Error creating branch: ${error.message || error}`;
|
|
60
|
+
}
|
|
61
|
+
// Notify via toast
|
|
62
|
+
try {
|
|
63
|
+
await client.tui.showToast({
|
|
64
|
+
body: {
|
|
65
|
+
title: `Branch: ${branchName}`,
|
|
66
|
+
message: `Created and checked out`,
|
|
67
|
+
variant: "success",
|
|
68
|
+
duration: 4000,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Toast failure is non-fatal
|
|
74
|
+
}
|
|
75
|
+
return `✓ Created and switched to branch: ${branchName}
|
|
43
76
|
|
|
44
77
|
You are now on branch '${branchName}'.
|
|
45
78
|
Make your changes and commit when ready.`;
|
|
46
|
-
|
|
47
|
-
});
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
48
82
|
export const status = tool({
|
|
49
83
|
description: "Get current git branch status - branch name, uncommitted changes, and whether on protected branch",
|
|
50
84
|
args: {},
|
|
51
85
|
async execute(args, context) {
|
|
52
86
|
// Check if we're in a git repository
|
|
53
87
|
try {
|
|
54
|
-
await
|
|
88
|
+
await git(context.worktree, "rev-parse", "--git-dir");
|
|
55
89
|
}
|
|
56
90
|
catch {
|
|
57
91
|
return "✗ Not in a git repository";
|
|
@@ -64,7 +98,8 @@ export const status = tool({
|
|
|
64
98
|
let aheadBehind = "";
|
|
65
99
|
// Get current branch
|
|
66
100
|
try {
|
|
67
|
-
|
|
101
|
+
const { stdout } = await git(context.worktree, "branch", "--show-current");
|
|
102
|
+
currentBranch = stdout.trim();
|
|
68
103
|
if (!currentBranch) {
|
|
69
104
|
currentBranch = "(detached HEAD)";
|
|
70
105
|
}
|
|
@@ -76,17 +111,17 @@ export const status = tool({
|
|
|
76
111
|
isProtected = PROTECTED_BRANCHES.includes(currentBranch);
|
|
77
112
|
// Check for changes
|
|
78
113
|
try {
|
|
79
|
-
const
|
|
80
|
-
const lines =
|
|
114
|
+
const { stdout } = await git(context.worktree, "status", "--porcelain");
|
|
115
|
+
const lines = stdout.trim().split("\n").filter((l) => l);
|
|
81
116
|
for (const line of lines) {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
117
|
+
const st = line.substring(0, 2);
|
|
118
|
+
if (st[0] !== " " && st[0] !== "?") {
|
|
84
119
|
stagedChanges = true;
|
|
85
120
|
}
|
|
86
|
-
if (
|
|
121
|
+
if (st[1] !== " " && st[1] !== "?") {
|
|
87
122
|
hasChanges = true;
|
|
88
123
|
}
|
|
89
|
-
if (
|
|
124
|
+
if (st === "??") {
|
|
90
125
|
untrackedFiles = true;
|
|
91
126
|
}
|
|
92
127
|
}
|
|
@@ -96,8 +131,8 @@ export const status = tool({
|
|
|
96
131
|
}
|
|
97
132
|
// Check ahead/behind
|
|
98
133
|
try {
|
|
99
|
-
const
|
|
100
|
-
const [ahead, behind] =
|
|
134
|
+
const { stdout } = await git(context.worktree, "rev-list", "--left-right", "--count", "HEAD...@{upstream}");
|
|
135
|
+
const [ahead, behind] = stdout.trim().split(/\s+/);
|
|
101
136
|
if (parseInt(ahead) > 0 || parseInt(behind) > 0) {
|
|
102
137
|
aheadBehind = `Ahead: ${ahead}, Behind: ${behind}`;
|
|
103
138
|
}
|
|
@@ -146,10 +181,10 @@ export const switch_ = tool({
|
|
|
146
181
|
const { branch } = args;
|
|
147
182
|
// Check if branch exists
|
|
148
183
|
try {
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
184
|
+
const { stdout } = await git(context.worktree, "branch", "--list", branch);
|
|
185
|
+
if (!stdout.trim()) {
|
|
151
186
|
// Try remote branch
|
|
152
|
-
const remoteBranches = await
|
|
187
|
+
const { stdout: remoteBranches } = await git(context.worktree, "branch", "-r", "--list", `origin/${branch}`);
|
|
153
188
|
if (!remoteBranches.trim()) {
|
|
154
189
|
return `✗ Error: Branch '${branch}' not found locally or on origin.
|
|
155
190
|
|
|
@@ -162,7 +197,7 @@ Use branch_create to create a new branch.`;
|
|
|
162
197
|
}
|
|
163
198
|
// Switch to branch
|
|
164
199
|
try {
|
|
165
|
-
await
|
|
200
|
+
await git(context.worktree, "checkout", branch);
|
|
166
201
|
}
|
|
167
202
|
catch (error) {
|
|
168
203
|
return `✗ Error switching branch: ${error.message || error}
|
package/dist/tools/cortex.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
export declare const init: {
|
|
2
3
|
description: string;
|
|
3
4
|
args: {};
|
|
@@ -8,4 +9,22 @@ export declare const status: {
|
|
|
8
9
|
args: {};
|
|
9
10
|
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* cortex_configure — Write per-project model configuration to ./opencode.json.
|
|
14
|
+
*
|
|
15
|
+
* Accepts a primary model (for build/plan/debug) and a subagent model
|
|
16
|
+
* (for fullstack/testing/security/devops). Merges into any existing
|
|
17
|
+
* opencode.json at the project root, preserving other settings.
|
|
18
|
+
*/
|
|
19
|
+
export declare const configure: {
|
|
20
|
+
description: string;
|
|
21
|
+
args: {
|
|
22
|
+
primaryModel: z.ZodString;
|
|
23
|
+
subagentModel: z.ZodString;
|
|
24
|
+
};
|
|
25
|
+
execute(args: {
|
|
26
|
+
primaryModel: string;
|
|
27
|
+
subagentModel: string;
|
|
28
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
29
|
+
};
|
|
11
30
|
//# sourceMappingURL=cortex.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cortex.d.ts","sourceRoot":"","sources":["../../src/tools/cortex.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cortex.d.ts","sourceRoot":"","sources":["../../src/tools/cortex.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAqExB,eAAO,MAAM,IAAI;;;;CAkDf,CAAC;AAEH,eAAO,MAAM,MAAM;;;;CAyDjB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;CAkHpB,CAAC"}
|