cortex-agents 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/agents/build.md +31 -86
- package/.opencode/agents/debug.md +64 -37
- package/.opencode/agents/devops.md +163 -90
- package/.opencode/agents/fullstack.md +97 -50
- package/.opencode/agents/plan.md +35 -30
- package/.opencode/agents/review.md +314 -0
- package/.opencode/agents/security.md +117 -63
- package/.opencode/agents/testing.md +177 -44
- package/README.md +24 -12
- package/dist/cli.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -2
- package/dist/registry.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ 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
|
-
// Agent
|
|
9
|
+
// ─── Agent Descriptions (for handover toasts) ───────────────────────────────
|
|
10
10
|
const AGENT_DESCRIPTIONS = {
|
|
11
11
|
build: "Development mode — ready to implement",
|
|
12
12
|
plan: "Planning mode — read-only analysis",
|
|
@@ -16,6 +16,95 @@ const AGENT_DESCRIPTIONS = {
|
|
|
16
16
|
security: "Security subagent — vulnerability audit",
|
|
17
17
|
devops: "DevOps subagent — CI/CD and deployment",
|
|
18
18
|
};
|
|
19
|
+
const TOOL_NOTIFICATIONS = {
|
|
20
|
+
task_finalize: {
|
|
21
|
+
successTitle: "Task Finalized",
|
|
22
|
+
successMsg: (args) => `Committed & pushed: ${(args.commitMessage ?? "").substring(0, 50)}`,
|
|
23
|
+
errorTitle: "Finalization Failed",
|
|
24
|
+
errorMsg: (_, out) => out
|
|
25
|
+
.replace(/^✗\s*/, "")
|
|
26
|
+
.split("\n")[0]
|
|
27
|
+
.substring(0, 100),
|
|
28
|
+
successDuration: 5000,
|
|
29
|
+
errorDuration: 10000,
|
|
30
|
+
},
|
|
31
|
+
plan_save: {
|
|
32
|
+
successTitle: "Plan Saved",
|
|
33
|
+
successMsg: (args) => args.title ?? "Plan saved",
|
|
34
|
+
errorTitle: "Plan Save Failed",
|
|
35
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
36
|
+
},
|
|
37
|
+
plan_delete: {
|
|
38
|
+
successTitle: "Plan Deleted",
|
|
39
|
+
successMsg: (args) => args.filename ?? "Plan deleted",
|
|
40
|
+
errorTitle: "Plan Delete Failed",
|
|
41
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
42
|
+
},
|
|
43
|
+
session_save: {
|
|
44
|
+
successTitle: "Session Saved",
|
|
45
|
+
successMsg: () => "Session summary recorded",
|
|
46
|
+
errorTitle: "Session Save Failed",
|
|
47
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
48
|
+
},
|
|
49
|
+
docs_save: {
|
|
50
|
+
successTitle: "Documentation Saved",
|
|
51
|
+
successMsg: (args) => `${args.type ?? "doc"}: ${args.title ?? "Untitled"}`,
|
|
52
|
+
errorTitle: "Doc Save Failed",
|
|
53
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
54
|
+
},
|
|
55
|
+
docs_init: {
|
|
56
|
+
successTitle: "Docs Initialized",
|
|
57
|
+
successMsg: () => "Documentation directory created",
|
|
58
|
+
errorTitle: "Docs Init Failed",
|
|
59
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
60
|
+
},
|
|
61
|
+
cortex_init: {
|
|
62
|
+
successTitle: "Project Initialized",
|
|
63
|
+
successMsg: () => ".cortex directory created",
|
|
64
|
+
errorTitle: "Init Failed",
|
|
65
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
66
|
+
},
|
|
67
|
+
cortex_configure: {
|
|
68
|
+
successTitle: "Models Configured",
|
|
69
|
+
successMsg: (args) => `Primary: ${args.primaryModel?.split("/").pop() || "set"}`,
|
|
70
|
+
errorTitle: "Configure Failed",
|
|
71
|
+
errorMsg: (_, out) => out.substring(0, 100),
|
|
72
|
+
},
|
|
73
|
+
branch_switch: {
|
|
74
|
+
successTitle: "Branch Switched",
|
|
75
|
+
successMsg: (args) => `Now on ${args.branch ?? "branch"}`,
|
|
76
|
+
errorTitle: "Branch Switch Failed",
|
|
77
|
+
errorMsg: (_, out) => out
|
|
78
|
+
.replace(/^✗\s*/, "")
|
|
79
|
+
.split("\n")[0]
|
|
80
|
+
.substring(0, 100),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
// ─── Error Message Extraction ────────────────────────────────────────────────
|
|
84
|
+
//
|
|
85
|
+
// Extracts a human-readable message from the session error union type
|
|
86
|
+
// (ProviderAuthError | UnknownError | MessageOutputLengthError |
|
|
87
|
+
// MessageAbortedError | ApiError).
|
|
88
|
+
function extractErrorMessage(error) {
|
|
89
|
+
if (!error)
|
|
90
|
+
return "An unknown error occurred";
|
|
91
|
+
const msg = typeof error.data?.message === "string" ? error.data.message : "";
|
|
92
|
+
switch (error.name) {
|
|
93
|
+
case "ProviderAuthError":
|
|
94
|
+
return `Auth error: ${msg || "Provider authentication failed"}`;
|
|
95
|
+
case "UnknownError":
|
|
96
|
+
return msg || "An unknown error occurred";
|
|
97
|
+
case "MessageOutputLengthError":
|
|
98
|
+
return "Output length exceeded — try compacting the session";
|
|
99
|
+
case "MessageAbortedError":
|
|
100
|
+
return `Aborted: ${msg || "Message was aborted"}`;
|
|
101
|
+
case "APIError":
|
|
102
|
+
return `API error: ${msg || "Request failed"}`;
|
|
103
|
+
default:
|
|
104
|
+
return `Error: ${error.name}`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ─── Plugin Entry ────────────────────────────────────────────────────────────
|
|
19
108
|
export const CortexPlugin = async (ctx) => {
|
|
20
109
|
return {
|
|
21
110
|
tool: {
|
|
@@ -50,9 +139,49 @@ export const CortexPlugin = async (ctx) => {
|
|
|
50
139
|
// Task tools - finalize workflow (commit, push, PR)
|
|
51
140
|
task_finalize: task.finalize,
|
|
52
141
|
},
|
|
53
|
-
//
|
|
142
|
+
// ── Post-execution toast notifications ────────────────────────────────
|
|
143
|
+
//
|
|
144
|
+
// Fires after every tool execution. Uses the TOOL_NOTIFICATIONS map
|
|
145
|
+
// to determine which tools get toasts and what content to display.
|
|
146
|
+
// Tools with existing factory-based toasts are excluded from the map.
|
|
147
|
+
"tool.execute.after": async (input, output) => {
|
|
148
|
+
const config = TOOL_NOTIFICATIONS[input.tool];
|
|
149
|
+
if (!config)
|
|
150
|
+
return; // No notification configured for this tool
|
|
151
|
+
try {
|
|
152
|
+
const result = output.output;
|
|
153
|
+
const isSuccess = result.startsWith("✓");
|
|
154
|
+
const isError = result.startsWith("✗");
|
|
155
|
+
if (isSuccess) {
|
|
156
|
+
await ctx.client.tui.showToast({
|
|
157
|
+
body: {
|
|
158
|
+
title: config.successTitle,
|
|
159
|
+
message: config.successMsg(input.args, result),
|
|
160
|
+
variant: "success",
|
|
161
|
+
duration: config.successDuration ?? 4000,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else if (isError) {
|
|
166
|
+
await ctx.client.tui.showToast({
|
|
167
|
+
body: {
|
|
168
|
+
title: config.errorTitle,
|
|
169
|
+
message: config.errorMsg(input.args, result),
|
|
170
|
+
variant: "error",
|
|
171
|
+
duration: config.errorDuration ?? 8000,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// Informational or warning outputs (⚠) — no toast to avoid noise
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Toast failure is non-fatal
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
// ── Event-driven notifications ───────────────────────────────────────
|
|
54
182
|
async event({ event }) {
|
|
55
183
|
try {
|
|
184
|
+
// Agent handover notifications
|
|
56
185
|
if (event.type === "message.part.updated" &&
|
|
57
186
|
"part" in event.properties &&
|
|
58
187
|
event.properties.part.type === "agent") {
|
|
@@ -67,6 +196,43 @@ export const CortexPlugin = async (ctx) => {
|
|
|
67
196
|
},
|
|
68
197
|
});
|
|
69
198
|
}
|
|
199
|
+
// Session error notifications
|
|
200
|
+
if (event.type === "session.error") {
|
|
201
|
+
const rawError = event.properties.error;
|
|
202
|
+
// Runtime validation before cast — ensure error has expected shape
|
|
203
|
+
const error = rawError &&
|
|
204
|
+
typeof rawError === "object" &&
|
|
205
|
+
"name" in rawError &&
|
|
206
|
+
typeof rawError.name === "string"
|
|
207
|
+
? rawError
|
|
208
|
+
: undefined;
|
|
209
|
+
const message = extractErrorMessage(error);
|
|
210
|
+
await ctx.client.tui.showToast({
|
|
211
|
+
body: {
|
|
212
|
+
title: "Session Error",
|
|
213
|
+
message,
|
|
214
|
+
variant: "error",
|
|
215
|
+
duration: 10000,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// PTY exited notifications (relevant for worktree terminal sessions)
|
|
220
|
+
if (event.type === "pty.exited") {
|
|
221
|
+
const rawExitCode = event.properties.exitCode;
|
|
222
|
+
const exitCode = typeof rawExitCode === "number" && Number.isInteger(rawExitCode)
|
|
223
|
+
? rawExitCode
|
|
224
|
+
: -1;
|
|
225
|
+
await ctx.client.tui.showToast({
|
|
226
|
+
body: {
|
|
227
|
+
title: "Terminal Exited",
|
|
228
|
+
message: exitCode === 0
|
|
229
|
+
? "Terminal session completed successfully"
|
|
230
|
+
: `Terminal exited with code ${exitCode}`,
|
|
231
|
+
variant: exitCode === 0 ? "success" : "warning",
|
|
232
|
+
duration: exitCode === 0 ? 4000 : 8000,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
70
236
|
}
|
|
71
237
|
catch {
|
|
72
238
|
// Toast failure is non-fatal — silently ignore
|
package/dist/registry.d.ts
CHANGED
|
@@ -19,11 +19,11 @@ 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 ["build", "plan", "debug"];
|
|
22
|
+
export declare const PRIMARY_AGENTS: readonly ["build", "plan", "debug", "review"];
|
|
23
23
|
/** Subagents receive a fast/cost-effective model */
|
|
24
24
|
export declare const SUBAGENTS: readonly ["fullstack", "testing", "security", "devops"];
|
|
25
25
|
/** All agent names combined */
|
|
26
|
-
export declare const ALL_AGENTS: readonly ["build", "plan", "debug", "fullstack", "testing", "security", "devops"];
|
|
26
|
+
export declare const ALL_AGENTS: readonly ["build", "plan", "debug", "review", "fullstack", "testing", "security", "devops"];
|
|
27
27
|
/**
|
|
28
28
|
* Build the interactive choices list for primary model selection.
|
|
29
29
|
* 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,+CAAgD,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,SAAS,yDAA0D,CAAC;AAEjF,+BAA+B;AAC/B,eAAO,MAAM,UAAU,6FAA6C,CAAC;AAErE;;;GAGG;AACH,wBAAgB,iBAAiB;;;;IAMhC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM;;;;IAcxD"}
|
package/dist/registry.js
CHANGED
|
@@ -105,7 +105,7 @@ export const MODEL_REGISTRY = [
|
|
|
105
105
|
},
|
|
106
106
|
];
|
|
107
107
|
/** Primary agents receive the best available model */
|
|
108
|
-
export const PRIMARY_AGENTS = ["build", "plan", "debug"];
|
|
108
|
+
export const PRIMARY_AGENTS = ["build", "plan", "debug", "review"];
|
|
109
109
|
/** Subagents receive a fast/cost-effective model */
|
|
110
110
|
export const SUBAGENTS = ["fullstack", "testing", "security", "devops"];
|
|
111
111
|
/** All agent names combined */
|
package/package.json
CHANGED