cortex-agents 2.3.0 → 3.4.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/{plan.md → architect.md} +104 -45
- package/.opencode/agents/audit.md +314 -0
- package/.opencode/agents/crosslayer.md +218 -0
- package/.opencode/agents/{debug.md → fix.md} +75 -46
- package/.opencode/agents/guard.md +202 -0
- package/.opencode/agents/{build.md → implement.md} +151 -107
- package/.opencode/agents/qa.md +265 -0
- package/.opencode/agents/ship.md +249 -0
- package/README.md +119 -31
- package/dist/cli.js +87 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +215 -9
- package/dist/registry.d.ts +8 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +16 -2
- package/dist/tools/cortex.d.ts +2 -2
- package/dist/tools/cortex.js +7 -7
- package/dist/tools/environment.d.ts +31 -0
- package/dist/tools/environment.d.ts.map +1 -0
- package/dist/tools/environment.js +93 -0
- package/dist/tools/github.d.ts +42 -0
- package/dist/tools/github.d.ts.map +1 -0
- package/dist/tools/github.js +200 -0
- package/dist/tools/repl.d.ts +50 -0
- package/dist/tools/repl.d.ts.map +1 -0
- package/dist/tools/repl.js +240 -0
- package/dist/tools/task.d.ts +2 -0
- package/dist/tools/task.d.ts.map +1 -1
- package/dist/tools/task.js +25 -30
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +22 -11
- package/dist/utils/github.d.ts +104 -0
- package/dist/utils/github.d.ts.map +1 -0
- package/dist/utils/github.js +243 -0
- package/dist/utils/ide.d.ts +76 -0
- package/dist/utils/ide.d.ts.map +1 -0
- package/dist/utils/ide.js +307 -0
- package/dist/utils/plan-extract.d.ts +7 -0
- package/dist/utils/plan-extract.d.ts.map +1 -1
- package/dist/utils/plan-extract.js +25 -1
- package/dist/utils/repl.d.ts +114 -0
- package/dist/utils/repl.d.ts.map +1 -0
- package/dist/utils/repl.js +434 -0
- package/dist/utils/terminal.d.ts +53 -1
- package/dist/utils/terminal.d.ts.map +1 -1
- package/dist/utils/terminal.js +642 -5
- package/package.json +1 -1
- package/.opencode/agents/devops.md +0 -176
- package/.opencode/agents/fullstack.md +0 -171
- package/.opencode/agents/security.md +0 -148
- package/.opencode/agents/testing.md +0 -132
- package/dist/plugin.d.ts +0 -1
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -4
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,8 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import prompts from "prompts";
|
|
6
|
-
import { PRIMARY_AGENTS, SUBAGENTS, ALL_AGENTS, getPrimaryChoices, getSubagentChoices, } from "./registry.js";
|
|
7
|
-
const VERSION = "
|
|
6
|
+
import { PRIMARY_AGENTS, SUBAGENTS, ALL_AGENTS, DISABLED_BUILTIN_AGENTS, STALE_AGENT_FILES, getPrimaryChoices, getSubagentChoices, } from "./registry.js";
|
|
7
|
+
const VERSION = "3.4.0";
|
|
8
8
|
const PLUGIN_NAME = "cortex-agents";
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -138,6 +138,23 @@ function installAgentsAndSkills(targetDir) {
|
|
|
138
138
|
console.log(` Installed ${count} skills -> ${skillsDest}`);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
+
function cleanupStaleAgents(globalDir) {
|
|
142
|
+
const agentsDir = path.join(globalDir, "agents");
|
|
143
|
+
if (!fs.existsSync(agentsDir))
|
|
144
|
+
return;
|
|
145
|
+
for (const file of STALE_AGENT_FILES) {
|
|
146
|
+
const filePath = path.join(agentsDir, file);
|
|
147
|
+
try {
|
|
148
|
+
if (fs.existsSync(filePath)) {
|
|
149
|
+
fs.unlinkSync(filePath);
|
|
150
|
+
console.log(` Cleaned up stale agent: ${file}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
console.warn(` Warning: Could not remove stale agent ${file}: ${err.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
141
158
|
function removeAgentsAndSkills(targetDir) {
|
|
142
159
|
const agentsSrc = path.join(PACKAGE_OPENCODE_DIR, "agents");
|
|
143
160
|
const skillsSrc = path.join(PACKAGE_OPENCODE_DIR, "skills");
|
|
@@ -173,9 +190,15 @@ function install() {
|
|
|
173
190
|
fs.mkdirSync(globalDir, { recursive: true });
|
|
174
191
|
}
|
|
175
192
|
const globalPath = path.join(globalDir, "opencode.json");
|
|
193
|
+
const disabledAgents = {};
|
|
194
|
+
for (const name of DISABLED_BUILTIN_AGENTS) {
|
|
195
|
+
disabledAgents[name] = { disable: true };
|
|
196
|
+
}
|
|
176
197
|
const newConfig = {
|
|
177
198
|
$schema: "https://opencode.ai/config.json",
|
|
178
199
|
plugin: [PLUGIN_NAME],
|
|
200
|
+
default_agent: "architect",
|
|
201
|
+
agent: disabledAgents,
|
|
179
202
|
};
|
|
180
203
|
writeConfig(globalPath, newConfig);
|
|
181
204
|
console.log(`Created config: ${globalPath}`);
|
|
@@ -187,16 +210,26 @@ function install() {
|
|
|
187
210
|
config.plugin = [];
|
|
188
211
|
if (!config.plugin.includes(PLUGIN_NAME)) {
|
|
189
212
|
config.plugin.push(PLUGIN_NAME);
|
|
190
|
-
writeConfig(configInfo.path, config);
|
|
191
|
-
console.log(`Added plugin to config: ${configInfo.path}\n`);
|
|
192
213
|
}
|
|
193
|
-
|
|
194
|
-
|
|
214
|
+
// Disable built-in agents that cortex-agents replaces
|
|
215
|
+
if (!config.agent)
|
|
216
|
+
config.agent = {};
|
|
217
|
+
for (const name of DISABLED_BUILTIN_AGENTS) {
|
|
218
|
+
if (!config.agent[name])
|
|
219
|
+
config.agent[name] = {};
|
|
220
|
+
config.agent[name].disable = true;
|
|
195
221
|
}
|
|
222
|
+
// Set default_agent, clean legacy camelCase key
|
|
223
|
+
config.default_agent = "architect";
|
|
224
|
+
delete config.defaultAgent;
|
|
225
|
+
writeConfig(configInfo.path, config);
|
|
226
|
+
console.log(`Updated config: ${configInfo.path}\n`);
|
|
196
227
|
}
|
|
197
228
|
// Copy agents and skills into the global opencode config dir
|
|
198
229
|
console.log("Installing agents and skills...");
|
|
199
230
|
installAgentsAndSkills(globalDir);
|
|
231
|
+
// Clean up stale agent files from previous cortex-agents versions
|
|
232
|
+
cleanupStaleAgents(globalDir);
|
|
200
233
|
// Sync per-project models if .opencode/models.json exists
|
|
201
234
|
if (hasProjectModelsConfig()) {
|
|
202
235
|
console.log("\nPer-project model config found (.opencode/models.json)");
|
|
@@ -233,11 +266,23 @@ function uninstall() {
|
|
|
233
266
|
}
|
|
234
267
|
}
|
|
235
268
|
}
|
|
269
|
+
// Re-enable built-in agents
|
|
270
|
+
for (const name of DISABLED_BUILTIN_AGENTS) {
|
|
271
|
+
if (config.agent[name]) {
|
|
272
|
+
delete config.agent[name].disable;
|
|
273
|
+
if (Object.keys(config.agent[name]).length === 0) {
|
|
274
|
+
delete config.agent[name];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
236
278
|
// Clean up empty agent object
|
|
237
279
|
if (Object.keys(config.agent).length === 0) {
|
|
238
280
|
delete config.agent;
|
|
239
281
|
}
|
|
240
282
|
}
|
|
283
|
+
// Remove default_agent + clean legacy key
|
|
284
|
+
delete config.default_agent;
|
|
285
|
+
delete config.defaultAgent;
|
|
241
286
|
writeConfig(configInfo.path, config);
|
|
242
287
|
// Remove agents and skills
|
|
243
288
|
const globalDir = getGlobalDir();
|
|
@@ -276,6 +321,12 @@ async function configure() {
|
|
|
276
321
|
config.plugin = [];
|
|
277
322
|
config.plugin.push(PLUGIN_NAME);
|
|
278
323
|
}
|
|
324
|
+
// Set default agent to architect (planning-first workflow)
|
|
325
|
+
if (!config.default_agent) {
|
|
326
|
+
config.default_agent = "architect";
|
|
327
|
+
}
|
|
328
|
+
// Clean legacy camelCase key
|
|
329
|
+
delete config.defaultAgent;
|
|
279
330
|
// ── Primary model selection ────────────────────────────────
|
|
280
331
|
const { primary, subagent } = await promptModelSelection();
|
|
281
332
|
// ── Write config ───────────────────────────────────────────
|
|
@@ -283,6 +334,14 @@ async function configure() {
|
|
|
283
334
|
// Per-project: write .opencode/models.json + sync to local opencode.json
|
|
284
335
|
writeProjectModels(primary, subagent);
|
|
285
336
|
syncProjectModelsToConfig();
|
|
337
|
+
// Ensure default agent is set in local opencode.json
|
|
338
|
+
const localConfig = readConfig(path.join(process.cwd(), "opencode.json"));
|
|
339
|
+
if (!localConfig.default_agent) {
|
|
340
|
+
localConfig.default_agent = "architect";
|
|
341
|
+
}
|
|
342
|
+
// Clean legacy camelCase key
|
|
343
|
+
delete localConfig.defaultAgent;
|
|
344
|
+
writeConfig(path.join(process.cwd(), "opencode.json"), localConfig);
|
|
286
345
|
const modelsPath = getProjectModelsPath();
|
|
287
346
|
const localConfigPath = path.join(process.cwd(), "opencode.json");
|
|
288
347
|
console.log("━".repeat(50));
|
|
@@ -304,6 +363,12 @@ async function configure() {
|
|
|
304
363
|
config.agent[name] = {};
|
|
305
364
|
config.agent[name].model = subagent;
|
|
306
365
|
}
|
|
366
|
+
// Re-assert disable entries for built-in agents
|
|
367
|
+
for (const name of DISABLED_BUILTIN_AGENTS) {
|
|
368
|
+
if (!config.agent[name])
|
|
369
|
+
config.agent[name] = {};
|
|
370
|
+
config.agent[name].disable = true;
|
|
371
|
+
}
|
|
307
372
|
const targetPath = configInfo?.path || path.join(getGlobalDir(), "opencode.json");
|
|
308
373
|
writeConfig(targetPath, config);
|
|
309
374
|
console.log("━".repeat(50));
|
|
@@ -330,7 +395,7 @@ async function promptModelSelection() {
|
|
|
330
395
|
description: "provider/model format",
|
|
331
396
|
value: "__custom__",
|
|
332
397
|
});
|
|
333
|
-
console.log("Primary agents (
|
|
398
|
+
console.log("Primary agents (implement, architect, fix, audit) handle complex tasks.\nUse your best available model.\n");
|
|
334
399
|
const { primaryModel } = await prompts({
|
|
335
400
|
type: "select",
|
|
336
401
|
name: "primaryModel",
|
|
@@ -364,7 +429,7 @@ async function promptModelSelection() {
|
|
|
364
429
|
description: "provider/model format",
|
|
365
430
|
value: "__custom__",
|
|
366
431
|
});
|
|
367
|
-
console.log("Subagents (
|
|
432
|
+
console.log("Subagents (crosslayer, qa, guard, ship) handle focused tasks.\nA faster/cheaper model works great here.\n");
|
|
368
433
|
const { subagentModel } = await prompts({
|
|
369
434
|
type: "select",
|
|
370
435
|
name: "subagentModel",
|
|
@@ -566,18 +631,20 @@ EXAMPLES:
|
|
|
566
631
|
npx ${PLUGIN_NAME} status # Check status
|
|
567
632
|
|
|
568
633
|
AGENTS:
|
|
569
|
-
Primary (
|
|
634
|
+
Primary (implement, architect, fix, audit):
|
|
570
635
|
Handle complex tasks — select your best model.
|
|
571
636
|
|
|
572
|
-
Subagents (
|
|
637
|
+
Subagents (crosslayer, qa, guard, ship):
|
|
573
638
|
Handle focused tasks — a fast/cheap model works great.
|
|
574
639
|
|
|
575
|
-
TOOLS (
|
|
640
|
+
TOOLS (32):
|
|
576
641
|
cortex_init, cortex_status .cortex directory management
|
|
577
642
|
cortex_configure Per-project model configuration
|
|
578
643
|
worktree_create, worktree_list Git worktree management
|
|
579
644
|
worktree_remove, worktree_open
|
|
580
645
|
worktree_launch Launch worktree (terminal/PTY/background)
|
|
646
|
+
detect_environment Detect IDE/terminal for launch options
|
|
647
|
+
get_environment_info Quick environment info for agents
|
|
581
648
|
branch_create, branch_status Git branch operations
|
|
582
649
|
branch_switch
|
|
583
650
|
plan_save, plan_list Plan persistence
|
|
@@ -587,13 +654,17 @@ TOOLS (23):
|
|
|
587
654
|
docs_init, docs_save Mermaid documentation
|
|
588
655
|
docs_list, docs_index
|
|
589
656
|
task_finalize Commit, push, and create PR
|
|
657
|
+
github_status, github_issues GitHub issue and project browsing
|
|
658
|
+
github_projects
|
|
659
|
+
repl_init, repl_status Iterative task-by-task implementation loop
|
|
660
|
+
repl_report, repl_summary
|
|
590
661
|
|
|
591
662
|
SKILLS (14):
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
663
|
+
frontend-development, backend-development, mobile-development,
|
|
664
|
+
desktop-development, database-design, api-design,
|
|
665
|
+
architecture-patterns, design-patterns, testing-strategies,
|
|
666
|
+
security-hardening, deployment-automation, performance-optimization,
|
|
667
|
+
code-quality, git-workflow
|
|
597
668
|
`);
|
|
598
669
|
}
|
|
599
670
|
// ─── CLI Entry Point ─────────────────────────────────────────────────────────
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAiLlD,eAAO,MAAM,YAAY,EAAE,MAsK1B,CAAC;AAGF,eAAe,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,16 +6,133 @@ import * as plan from "./tools/plan";
|
|
|
6
6
|
import * as session from "./tools/session";
|
|
7
7
|
import * as docs from "./tools/docs";
|
|
8
8
|
import * as task from "./tools/task";
|
|
9
|
-
|
|
9
|
+
import * as environment from "./tools/environment";
|
|
10
|
+
import * as github from "./tools/github";
|
|
11
|
+
import * as repl from "./tools/repl";
|
|
12
|
+
// ─── Agent Descriptions (for handover toasts) ───────────────────────────────
|
|
10
13
|
const AGENT_DESCRIPTIONS = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
implement: "Development mode — ready to implement",
|
|
15
|
+
architect: "Planning mode — read-only analysis",
|
|
16
|
+
fix: "Debug mode — troubleshooting and fixes",
|
|
17
|
+
audit: "Review mode — code quality assessment",
|
|
18
|
+
crosslayer: "Crosslayer subagent — end-to-end implementation",
|
|
19
|
+
qa: "QA subagent — writing tests",
|
|
20
|
+
guard: "Security subagent — vulnerability audit",
|
|
21
|
+
ship: "DevOps subagent — CI/CD and deployment",
|
|
18
22
|
};
|
|
23
|
+
const TOOL_NOTIFICATIONS = {
|
|
24
|
+
task_finalize: {
|
|
25
|
+
successTitle: "Task Finalized",
|
|
26
|
+
successMsg: (args) => `Committed & pushed: ${(args.commitMessage ?? "").substring(0, 50)}`,
|
|
27
|
+
errorTitle: "Finalization Failed",
|
|
28
|
+
errorMsg: (_, out) => out
|
|
29
|
+
.replace(/^✗\s*/, "")
|
|
30
|
+
.split("\n")[0]
|
|
31
|
+
.substring(0, 100),
|
|
32
|
+
successDuration: 5000,
|
|
33
|
+
errorDuration: 10000,
|
|
34
|
+
},
|
|
35
|
+
plan_save: {
|
|
36
|
+
successTitle: "Plan Saved",
|
|
37
|
+
successMsg: (args) => args.title ?? "Plan saved",
|
|
38
|
+
errorTitle: "Plan Save Failed",
|
|
39
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
40
|
+
},
|
|
41
|
+
plan_delete: {
|
|
42
|
+
successTitle: "Plan Deleted",
|
|
43
|
+
successMsg: (args) => args.filename ?? "Plan deleted",
|
|
44
|
+
errorTitle: "Plan Delete Failed",
|
|
45
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
46
|
+
},
|
|
47
|
+
session_save: {
|
|
48
|
+
successTitle: "Session Saved",
|
|
49
|
+
successMsg: () => "Session summary recorded",
|
|
50
|
+
errorTitle: "Session Save Failed",
|
|
51
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
52
|
+
},
|
|
53
|
+
docs_save: {
|
|
54
|
+
successTitle: "Documentation Saved",
|
|
55
|
+
successMsg: (args) => `${args.type ?? "doc"}: ${args.title ?? "Untitled"}`,
|
|
56
|
+
errorTitle: "Doc Save Failed",
|
|
57
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
58
|
+
},
|
|
59
|
+
docs_init: {
|
|
60
|
+
successTitle: "Docs Initialized",
|
|
61
|
+
successMsg: () => "Documentation directory created",
|
|
62
|
+
errorTitle: "Docs Init Failed",
|
|
63
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
64
|
+
},
|
|
65
|
+
cortex_init: {
|
|
66
|
+
successTitle: "Project Initialized",
|
|
67
|
+
successMsg: () => ".cortex directory created",
|
|
68
|
+
errorTitle: "Init Failed",
|
|
69
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
70
|
+
},
|
|
71
|
+
cortex_configure: {
|
|
72
|
+
successTitle: "Models Configured",
|
|
73
|
+
successMsg: (args) => `Primary: ${args.primaryModel?.split("/").pop() || "set"}`,
|
|
74
|
+
errorTitle: "Configure Failed",
|
|
75
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
76
|
+
},
|
|
77
|
+
branch_switch: {
|
|
78
|
+
successTitle: "Branch Switched",
|
|
79
|
+
successMsg: (args) => `Now on ${args.branch ?? "branch"}`,
|
|
80
|
+
errorTitle: "Branch Switch Failed",
|
|
81
|
+
errorMsg: (_, out) => out
|
|
82
|
+
.replace(/^✗\s*/, "")
|
|
83
|
+
.split("\n")[0]
|
|
84
|
+
.substring(0, 100),
|
|
85
|
+
},
|
|
86
|
+
github_status: {
|
|
87
|
+
successTitle: "GitHub Connected",
|
|
88
|
+
successMsg: (_args, output) => {
|
|
89
|
+
const repoMatch = output.match(/Repository:\s+(.+)/);
|
|
90
|
+
return repoMatch ? `Connected to ${repoMatch[1].substring(0, 100)}` : "GitHub CLI available";
|
|
91
|
+
},
|
|
92
|
+
errorTitle: "GitHub Not Available",
|
|
93
|
+
errorMsg: (_, out) => out
|
|
94
|
+
.replace(/^✗\s*/, "")
|
|
95
|
+
.split("\n")[0]
|
|
96
|
+
.substring(0, 100),
|
|
97
|
+
},
|
|
98
|
+
repl_init: {
|
|
99
|
+
successTitle: "REPL Loop Started",
|
|
100
|
+
successMsg: (args) => `${(args.planFilename ?? "Plan").split("/").pop()?.substring(0, 40)} — tasks loaded`,
|
|
101
|
+
errorTitle: "REPL Init Failed",
|
|
102
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
103
|
+
},
|
|
104
|
+
repl_report: {
|
|
105
|
+
successTitle: "Task Update",
|
|
106
|
+
successMsg: (args) => `Result: ${args.result ?? "reported"}`,
|
|
107
|
+
errorTitle: "Report Failed",
|
|
108
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
// ─── Error Message Extraction ────────────────────────────────────────────────
|
|
112
|
+
//
|
|
113
|
+
// Extracts a human-readable message from the session error union type
|
|
114
|
+
// (ProviderAuthError | UnknownError | MessageOutputLengthError |
|
|
115
|
+
// MessageAbortedError | ApiError).
|
|
116
|
+
function extractErrorMessage(error) {
|
|
117
|
+
if (!error)
|
|
118
|
+
return "An unknown error occurred";
|
|
119
|
+
const msg = typeof error.data?.message === "string" ? error.data.message : "";
|
|
120
|
+
switch (error.name) {
|
|
121
|
+
case "ProviderAuthError":
|
|
122
|
+
return `Auth error: ${msg || "Provider authentication failed"}`;
|
|
123
|
+
case "UnknownError":
|
|
124
|
+
return msg || "An unknown error occurred";
|
|
125
|
+
case "MessageOutputLengthError":
|
|
126
|
+
return "Output length exceeded — try compacting the session";
|
|
127
|
+
case "MessageAbortedError":
|
|
128
|
+
return `Aborted: ${msg || "Message was aborted"}`;
|
|
129
|
+
case "APIError":
|
|
130
|
+
return `API error: ${msg || "Request failed"}`;
|
|
131
|
+
default:
|
|
132
|
+
return `Error: ${error.name}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ─── Plugin Entry ────────────────────────────────────────────────────────────
|
|
19
136
|
export const CortexPlugin = async (ctx) => {
|
|
20
137
|
return {
|
|
21
138
|
tool: {
|
|
@@ -49,10 +166,62 @@ export const CortexPlugin = async (ctx) => {
|
|
|
49
166
|
docs_index: docs.index,
|
|
50
167
|
// Task tools - finalize workflow (commit, push, PR)
|
|
51
168
|
task_finalize: task.finalize,
|
|
169
|
+
// Environment tools - IDE/terminal detection for contextual options
|
|
170
|
+
detect_environment: environment.detectEnvironment,
|
|
171
|
+
get_environment_info: environment.getEnvironmentInfo,
|
|
172
|
+
// GitHub integration tools - work item listing, issue selection, project boards
|
|
173
|
+
github_status: github.status,
|
|
174
|
+
github_issues: github.issues,
|
|
175
|
+
github_projects: github.projects,
|
|
176
|
+
// REPL loop tools - iterative task-by-task implementation
|
|
177
|
+
repl_init: repl.init,
|
|
178
|
+
repl_status: repl.status,
|
|
179
|
+
repl_report: repl.report,
|
|
180
|
+
repl_summary: repl.summary,
|
|
52
181
|
},
|
|
53
|
-
//
|
|
182
|
+
// ── Post-execution toast notifications ────────────────────────────────
|
|
183
|
+
//
|
|
184
|
+
// Fires after every tool execution. Uses the TOOL_NOTIFICATIONS map
|
|
185
|
+
// to determine which tools get toasts and what content to display.
|
|
186
|
+
// Tools with existing factory-based toasts are excluded from the map.
|
|
187
|
+
"tool.execute.after": async (input, output) => {
|
|
188
|
+
const config = TOOL_NOTIFICATIONS[input.tool];
|
|
189
|
+
if (!config)
|
|
190
|
+
return; // No notification configured for this tool
|
|
191
|
+
try {
|
|
192
|
+
const result = output.output;
|
|
193
|
+
const isSuccess = result.startsWith("✓");
|
|
194
|
+
const isError = result.startsWith("✗");
|
|
195
|
+
if (isSuccess) {
|
|
196
|
+
await ctx.client.tui.showToast({
|
|
197
|
+
body: {
|
|
198
|
+
title: config.successTitle,
|
|
199
|
+
message: config.successMsg(input.args, result),
|
|
200
|
+
variant: "success",
|
|
201
|
+
duration: config.successDuration ?? 4000,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else if (isError) {
|
|
206
|
+
await ctx.client.tui.showToast({
|
|
207
|
+
body: {
|
|
208
|
+
title: config.errorTitle,
|
|
209
|
+
message: config.errorMsg(input.args, result),
|
|
210
|
+
variant: "error",
|
|
211
|
+
duration: config.errorDuration ?? 8000,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Informational or warning outputs (⚠) — no toast to avoid noise
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Toast failure is non-fatal
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
// ── Event-driven notifications ───────────────────────────────────────
|
|
54
222
|
async event({ event }) {
|
|
55
223
|
try {
|
|
224
|
+
// Agent handover notifications
|
|
56
225
|
if (event.type === "message.part.updated" &&
|
|
57
226
|
"part" in event.properties &&
|
|
58
227
|
event.properties.part.type === "agent") {
|
|
@@ -67,6 +236,43 @@ export const CortexPlugin = async (ctx) => {
|
|
|
67
236
|
},
|
|
68
237
|
});
|
|
69
238
|
}
|
|
239
|
+
// Session error notifications
|
|
240
|
+
if (event.type === "session.error") {
|
|
241
|
+
const rawError = event.properties.error;
|
|
242
|
+
// Runtime validation before cast — ensure error has expected shape
|
|
243
|
+
const error = rawError &&
|
|
244
|
+
typeof rawError === "object" &&
|
|
245
|
+
"name" in rawError &&
|
|
246
|
+
typeof rawError.name === "string"
|
|
247
|
+
? rawError
|
|
248
|
+
: undefined;
|
|
249
|
+
const message = extractErrorMessage(error);
|
|
250
|
+
await ctx.client.tui.showToast({
|
|
251
|
+
body: {
|
|
252
|
+
title: "Session Error",
|
|
253
|
+
message,
|
|
254
|
+
variant: "error",
|
|
255
|
+
duration: 10000,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
// PTY exited notifications (relevant for worktree terminal sessions)
|
|
260
|
+
if (event.type === "pty.exited") {
|
|
261
|
+
const rawExitCode = event.properties.exitCode;
|
|
262
|
+
const exitCode = typeof rawExitCode === "number" && Number.isInteger(rawExitCode)
|
|
263
|
+
? rawExitCode
|
|
264
|
+
: -1;
|
|
265
|
+
await ctx.client.tui.showToast({
|
|
266
|
+
body: {
|
|
267
|
+
title: "Terminal Exited",
|
|
268
|
+
message: exitCode === 0
|
|
269
|
+
? "Terminal session completed successfully"
|
|
270
|
+
: `Terminal exited with code ${exitCode}`,
|
|
271
|
+
variant: exitCode === 0 ? "success" : "warning",
|
|
272
|
+
duration: exitCode === 0 ? 4000 : 8000,
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
}
|
|
70
276
|
}
|
|
71
277
|
catch {
|
|
72
278
|
// Toast failure is non-fatal — silently ignore
|
package/dist/registry.d.ts
CHANGED
|
@@ -19,11 +19,16 @@ export interface ModelEntry {
|
|
|
19
19
|
}
|
|
20
20
|
export declare const MODEL_REGISTRY: ModelEntry[];
|
|
21
21
|
/** Primary agents receive the best available model */
|
|
22
|
-
export declare const PRIMARY_AGENTS: readonly ["
|
|
22
|
+
export declare const PRIMARY_AGENTS: readonly ["implement", "architect", "fix", "audit"];
|
|
23
23
|
/** Subagents receive a fast/cost-effective model */
|
|
24
|
-
export declare const SUBAGENTS: readonly ["
|
|
24
|
+
export declare const SUBAGENTS: readonly ["crosslayer", "qa", "guard", "ship"];
|
|
25
25
|
/** All agent names combined */
|
|
26
|
-
export declare const ALL_AGENTS: readonly ["
|
|
26
|
+
export declare const ALL_AGENTS: readonly ["implement", "architect", "fix", "audit", "crosslayer", "qa", "guard", "ship"];
|
|
27
|
+
/** OpenCode built-in agents disabled when cortex-agents is installed.
|
|
28
|
+
* Replaced by cortex equivalents: build → implement, plan → architect */
|
|
29
|
+
export declare const DISABLED_BUILTIN_AGENTS: readonly ["build", "plan"];
|
|
30
|
+
/** Old agent files to clean up from previous cortex-agents versions */
|
|
31
|
+
export declare const STALE_AGENT_FILES: readonly ["build.md", "plan.md", "debug.md", "review.md", "fullstack.md", "testing.md", "security.md", "devops.md"];
|
|
27
32
|
/**
|
|
28
33
|
* Build the interactive choices list for primary model selection.
|
|
29
34
|
* Shows premium and standard tier models (excluding fast).
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACtC,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,UAAU,EAuGtC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,UAAU;IACzB,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACtC,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,UAAU,EAuGtC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,cAAc,qDAAsD,CAAC;AAElF,oDAAoD;AACpD,eAAO,MAAM,SAAS,gDAAiD,CAAC;AAExE,+BAA+B;AAC/B,eAAO,MAAM,UAAU,0FAA6C,CAAC;AAErE;0EAC0E;AAC1E,eAAO,MAAM,uBAAuB,4BAA6B,CAAC;AAElE,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,qHASpB,CAAC;AAEX;;;GAGG;AACH,wBAAgB,iBAAiB;;;;IAMhC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM;;;;IAcxD"}
|
package/dist/registry.js
CHANGED
|
@@ -105,11 +105,25 @@ export const MODEL_REGISTRY = [
|
|
|
105
105
|
},
|
|
106
106
|
];
|
|
107
107
|
/** Primary agents receive the best available model */
|
|
108
|
-
export const PRIMARY_AGENTS = ["
|
|
108
|
+
export const PRIMARY_AGENTS = ["implement", "architect", "fix", "audit"];
|
|
109
109
|
/** Subagents receive a fast/cost-effective model */
|
|
110
|
-
export const SUBAGENTS = ["
|
|
110
|
+
export const SUBAGENTS = ["crosslayer", "qa", "guard", "ship"];
|
|
111
111
|
/** All agent names combined */
|
|
112
112
|
export const ALL_AGENTS = [...PRIMARY_AGENTS, ...SUBAGENTS];
|
|
113
|
+
/** OpenCode built-in agents disabled when cortex-agents is installed.
|
|
114
|
+
* Replaced by cortex equivalents: build → implement, plan → architect */
|
|
115
|
+
export const DISABLED_BUILTIN_AGENTS = ["build", "plan"];
|
|
116
|
+
/** Old agent files to clean up from previous cortex-agents versions */
|
|
117
|
+
export const STALE_AGENT_FILES = [
|
|
118
|
+
"build.md",
|
|
119
|
+
"plan.md",
|
|
120
|
+
"debug.md",
|
|
121
|
+
"review.md",
|
|
122
|
+
"fullstack.md",
|
|
123
|
+
"testing.md",
|
|
124
|
+
"security.md",
|
|
125
|
+
"devops.md",
|
|
126
|
+
];
|
|
113
127
|
/**
|
|
114
128
|
* Build the interactive choices list for primary model selection.
|
|
115
129
|
* Shows premium and standard tier models (excluding fast).
|
package/dist/tools/cortex.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export declare const status: {
|
|
|
12
12
|
/**
|
|
13
13
|
* cortex_configure — Write per-project model configuration to ./opencode.json.
|
|
14
14
|
*
|
|
15
|
-
* Accepts a primary model (for
|
|
16
|
-
* (for
|
|
15
|
+
* Accepts a primary model (for implement/architect/fix/audit) and a subagent model
|
|
16
|
+
* (for crosslayer/qa/guard/ship). Merges into any existing
|
|
17
17
|
* opencode.json at the project root, preserving other settings.
|
|
18
18
|
*/
|
|
19
19
|
export declare const configure: {
|
package/dist/tools/cortex.js
CHANGED
|
@@ -151,13 +151,13 @@ Plans: ${planCount}`;
|
|
|
151
151
|
/**
|
|
152
152
|
* cortex_configure — Write per-project model configuration to ./opencode.json.
|
|
153
153
|
*
|
|
154
|
-
* Accepts a primary model (for
|
|
155
|
-
* (for
|
|
154
|
+
* Accepts a primary model (for implement/architect/fix/audit) and a subagent model
|
|
155
|
+
* (for crosslayer/qa/guard/ship). Merges into any existing
|
|
156
156
|
* opencode.json at the project root, preserving other settings.
|
|
157
157
|
*/
|
|
158
158
|
export const configure = tool({
|
|
159
159
|
description: "Save per-project model configuration to ./opencode.json. " +
|
|
160
|
-
"Sets the model for primary agents (
|
|
160
|
+
"Sets the model for primary agents (implement, architect, fix, audit) and subagents (crosslayer, qa, guard, ship). " +
|
|
161
161
|
"Available models — Premium: " +
|
|
162
162
|
MODEL_REGISTRY.filter((m) => m.tier === "premium")
|
|
163
163
|
.map((m) => `${m.name} (${m.id})`)
|
|
@@ -174,10 +174,10 @@ export const configure = tool({
|
|
|
174
174
|
args: {
|
|
175
175
|
primaryModel: z
|
|
176
176
|
.string()
|
|
177
|
-
.describe("Model ID for primary agents (
|
|
177
|
+
.describe("Model ID for primary agents (implement, architect, fix, audit). Format: provider/model-name"),
|
|
178
178
|
subagentModel: z
|
|
179
179
|
.string()
|
|
180
|
-
.describe("Model ID for subagents (
|
|
180
|
+
.describe("Model ID for subagents (crosslayer, qa, guard, ship). Format: provider/model-name"),
|
|
181
181
|
},
|
|
182
182
|
async execute(args, context) {
|
|
183
183
|
const configPath = path.join(context.worktree, "opencode.json");
|
|
@@ -246,10 +246,10 @@ export const configure = tool({
|
|
|
246
246
|
return `✓ Model configuration saved to:
|
|
247
247
|
${savedTo}
|
|
248
248
|
|
|
249
|
-
Primary agents (
|
|
249
|
+
Primary agents (implement, architect, fix, audit):
|
|
250
250
|
→ ${primaryDisplay} (${args.primaryModel})
|
|
251
251
|
|
|
252
|
-
Subagents (
|
|
252
|
+
Subagents (crosslayer, qa, guard, ship):
|
|
253
253
|
→ ${subagentDisplay} (${args.subagentModel})
|
|
254
254
|
|
|
255
255
|
Restart OpenCode to apply changes.`;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Detection Tool
|
|
3
|
+
*
|
|
4
|
+
* Provides agents with information about the current development environment
|
|
5
|
+
* (IDE, terminal, editor) to offer contextually appropriate worktree launch options.
|
|
6
|
+
*
|
|
7
|
+
* Uses two detection systems:
|
|
8
|
+
* - IDE detection (ide.ts) — for "Open in IDE" options
|
|
9
|
+
* - Terminal detection (terminal.ts) — for "Open in terminal tab" options
|
|
10
|
+
*
|
|
11
|
+
* The terminal detection uses a multi-strategy chain:
|
|
12
|
+
* 1. Environment variables (fast, synchronous)
|
|
13
|
+
* 2. Process-tree walk (finds terminal in parent processes)
|
|
14
|
+
* 3. Frontmost app detection (macOS only)
|
|
15
|
+
* 4. User preference (.cortex/config.json)
|
|
16
|
+
*/
|
|
17
|
+
export declare const detectEnvironment: {
|
|
18
|
+
description: string;
|
|
19
|
+
args: {};
|
|
20
|
+
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Quick environment check tool for agents.
|
|
24
|
+
* Returns a simplified response for quick decision-making.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getEnvironmentInfo: {
|
|
27
|
+
description: string;
|
|
28
|
+
args: {};
|
|
29
|
+
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/tools/environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,eAAO,MAAM,iBAAiB;;;;CAgD5B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;CA4B7B,CAAC"}
|