cortex-agents 2.2.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 +118 -70
- package/.opencode/agents/debug.md +132 -19
- package/.opencode/agents/devops.md +213 -72
- package/.opencode/agents/fullstack.md +183 -48
- package/.opencode/agents/plan.md +79 -4
- package/.opencode/agents/review.md +314 -0
- package/.opencode/agents/security.md +166 -53
- package/.opencode/agents/testing.md +215 -38
- package/README.md +98 -34
- package/dist/cli.js +209 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +174 -8
- package/dist/registry.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- 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/tools/task.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { detectWorktreeInfo } from "../utils/worktree-detect.js";
|
|
5
5
|
import { findPlanContent, extractPlanSections, buildPrBodyFromPlan, } from "../utils/plan-extract.js";
|
|
6
|
+
import { git, gh, which } from "../utils/shell.js";
|
|
6
7
|
const PROTECTED_BRANCHES = ["main", "master", "develop", "production", "staging"];
|
|
7
8
|
const DOCS_DIR = "docs";
|
|
8
9
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -11,10 +12,8 @@ const DOCS_DIR = "docs";
|
|
|
11
12
|
*/
|
|
12
13
|
async function checkGhCli(cwd) {
|
|
13
14
|
// Check if gh exists
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
15
|
+
const ghPath = await which("gh");
|
|
16
|
+
if (!ghPath) {
|
|
18
17
|
return {
|
|
19
18
|
ok: false,
|
|
20
19
|
error: "GitHub CLI (gh) is not installed. Install it from https://cli.github.com/ and run `gh auth login`.",
|
|
@@ -22,7 +21,7 @@ async function checkGhCli(cwd) {
|
|
|
22
21
|
}
|
|
23
22
|
// Check if authenticated
|
|
24
23
|
try {
|
|
25
|
-
await
|
|
24
|
+
await gh(cwd, "auth", "status");
|
|
26
25
|
}
|
|
27
26
|
catch {
|
|
28
27
|
return {
|
|
@@ -37,8 +36,8 @@ async function checkGhCli(cwd) {
|
|
|
37
36
|
*/
|
|
38
37
|
async function checkRemote(cwd) {
|
|
39
38
|
try {
|
|
40
|
-
const
|
|
41
|
-
if (!
|
|
39
|
+
const { stdout } = await git(cwd, "remote", "-v");
|
|
40
|
+
if (!stdout.includes("origin")) {
|
|
42
41
|
return {
|
|
43
42
|
ok: false,
|
|
44
43
|
error: "No 'origin' remote configured. Add one with: git remote add origin <url>",
|
|
@@ -74,14 +73,14 @@ function checkDocsExist(worktree) {
|
|
|
74
73
|
*/
|
|
75
74
|
async function getCommitLog(cwd, baseBranch) {
|
|
76
75
|
try {
|
|
77
|
-
const
|
|
78
|
-
return
|
|
76
|
+
const { stdout } = await git(cwd, "log", `${baseBranch}..HEAD`, "--oneline");
|
|
77
|
+
return stdout.trim();
|
|
79
78
|
}
|
|
80
79
|
catch {
|
|
81
80
|
// If base branch doesn't exist locally, try origin/<base>
|
|
82
81
|
try {
|
|
83
|
-
const
|
|
84
|
-
return
|
|
82
|
+
const { stdout } = await git(cwd, "log", `origin/${baseBranch}..HEAD`, "--oneline");
|
|
83
|
+
return stdout.trim();
|
|
85
84
|
}
|
|
86
85
|
catch {
|
|
87
86
|
return "";
|
|
@@ -126,7 +125,7 @@ export const finalize = tool({
|
|
|
126
125
|
const warnings = [];
|
|
127
126
|
// ── 1. Validate: git repo ─────────────────────────────────
|
|
128
127
|
try {
|
|
129
|
-
await
|
|
128
|
+
await git(cwd, "rev-parse", "--git-dir");
|
|
130
129
|
}
|
|
131
130
|
catch {
|
|
132
131
|
return "✗ Error: Not in a git repository.";
|
|
@@ -150,8 +149,8 @@ Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
|
150
149
|
else {
|
|
151
150
|
// Try to detect default branch from origin
|
|
152
151
|
try {
|
|
153
|
-
const
|
|
154
|
-
baseBranch =
|
|
152
|
+
const { stdout } = await git(cwd, "symbolic-ref", "refs/remotes/origin/HEAD");
|
|
153
|
+
baseBranch = stdout.trim().replace("refs/remotes/origin/", "");
|
|
155
154
|
}
|
|
156
155
|
catch {
|
|
157
156
|
baseBranch = "main"; // Sensible default
|
|
@@ -181,7 +180,7 @@ Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
|
181
180
|
}
|
|
182
181
|
// ── 6. Stage all changes ──────────────────────────────────
|
|
183
182
|
try {
|
|
184
|
-
await
|
|
183
|
+
await git(cwd, "add", "-A");
|
|
185
184
|
}
|
|
186
185
|
catch (error) {
|
|
187
186
|
return `✗ Error staging changes: ${error.message || error}`;
|
|
@@ -191,15 +190,15 @@ Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
|
191
190
|
let commitSkipped = false;
|
|
192
191
|
try {
|
|
193
192
|
// Check if there's anything to commit
|
|
194
|
-
const
|
|
195
|
-
if (!
|
|
193
|
+
const { stdout: statusOut } = await git(cwd, "status", "--porcelain");
|
|
194
|
+
if (!statusOut.trim()) {
|
|
196
195
|
commitSkipped = true;
|
|
197
196
|
output.push("No new changes to commit (working tree clean)");
|
|
198
197
|
}
|
|
199
198
|
else {
|
|
200
|
-
await
|
|
201
|
-
const
|
|
202
|
-
commitHash =
|
|
199
|
+
await git(cwd, "commit", "-m", commitMessage);
|
|
200
|
+
const { stdout: hashOut } = await git(cwd, "rev-parse", "--short", "HEAD");
|
|
201
|
+
commitHash = hashOut.trim();
|
|
203
202
|
output.push(`Committed: ${commitHash} — ${commitMessage}`);
|
|
204
203
|
}
|
|
205
204
|
}
|
|
@@ -208,7 +207,7 @@ Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
|
208
207
|
}
|
|
209
208
|
// ── 8. Push to origin ─────────────────────────────────────
|
|
210
209
|
try {
|
|
211
|
-
await
|
|
210
|
+
await git(cwd, "push", "-u", "origin", branchName);
|
|
212
211
|
output.push(`Pushed to origin/${branchName}`);
|
|
213
212
|
}
|
|
214
213
|
catch (error) {
|
|
@@ -243,49 +242,29 @@ All previous steps succeeded (changes committed). Try pushing manually:
|
|
|
243
242
|
let prUrl = "";
|
|
244
243
|
try {
|
|
245
244
|
// Check if PR already exists for this branch
|
|
246
|
-
const existingPr = await
|
|
247
|
-
.cwd(cwd).quiet().nothrow().text();
|
|
245
|
+
const { stdout: existingPr } = await gh(cwd, "pr", "view", branchName, "--json", "url", "--jq", ".url");
|
|
248
246
|
if (existingPr.trim()) {
|
|
249
247
|
prUrl = existingPr.trim();
|
|
250
248
|
output.push(`PR already exists: ${prUrl}`);
|
|
251
249
|
}
|
|
252
250
|
else {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// Use a heredoc-style approach via stdin to handle complex body content
|
|
256
|
-
const bodyFile = path.join(cwd, ".cortex", ".pr-body-tmp.md");
|
|
257
|
-
const cortexDir = path.join(cwd, ".cortex");
|
|
258
|
-
if (!fs.existsSync(cortexDir)) {
|
|
259
|
-
fs.mkdirSync(cortexDir, { recursive: true });
|
|
260
|
-
}
|
|
261
|
-
fs.writeFileSync(bodyFile, prBodyContent);
|
|
262
|
-
try {
|
|
263
|
-
const createArgs = [
|
|
264
|
-
"gh", "pr", "create",
|
|
265
|
-
"--base", baseBranch,
|
|
266
|
-
"--title", finalPrTitle,
|
|
267
|
-
"--body-file", bodyFile,
|
|
268
|
-
];
|
|
269
|
-
if (draft)
|
|
270
|
-
createArgs.push("--draft");
|
|
271
|
-
const result = await Bun.$ `gh pr create --base ${baseBranch} --title ${finalPrTitle} --body-file ${bodyFile} ${draft ? "--draft" : ""}`.cwd(cwd).quiet().text();
|
|
272
|
-
prUrl = result.trim();
|
|
273
|
-
output.push(`PR created: ${prUrl}`);
|
|
274
|
-
}
|
|
275
|
-
finally {
|
|
276
|
-
// Clean up temp file
|
|
277
|
-
if (fs.existsSync(bodyFile)) {
|
|
278
|
-
fs.unlinkSync(bodyFile);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
251
|
+
prUrl = await createPr(cwd, baseBranch, finalPrTitle, prBodyContent, draft);
|
|
252
|
+
output.push(`PR created: ${prUrl}`);
|
|
281
253
|
}
|
|
282
254
|
}
|
|
283
|
-
catch
|
|
284
|
-
// PR
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
255
|
+
catch {
|
|
256
|
+
// PR doesn't exist yet, create it
|
|
257
|
+
try {
|
|
258
|
+
prUrl = await createPr(cwd, baseBranch, finalPrTitle, prBodyContent, draft);
|
|
259
|
+
output.push(`PR created: ${prUrl}`);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
// PR creation failed but everything else succeeded
|
|
263
|
+
output.push(`⚠ PR creation failed: ${error.message || error}`);
|
|
264
|
+
output.push("");
|
|
265
|
+
output.push("Changes are committed and pushed. Create the PR manually:");
|
|
266
|
+
output.push(` gh pr create --base ${baseBranch} --title "${finalPrTitle}"`);
|
|
267
|
+
}
|
|
289
268
|
}
|
|
290
269
|
// ── Build final output ────────────────────────────────────
|
|
291
270
|
let finalOutput = `✓ Task finalized\n\n`;
|
|
@@ -300,3 +279,32 @@ All previous steps succeeded (changes committed). Try pushing manually:
|
|
|
300
279
|
return finalOutput;
|
|
301
280
|
},
|
|
302
281
|
});
|
|
282
|
+
/**
|
|
283
|
+
* Create a PR using gh CLI with array-based args (no shell injection).
|
|
284
|
+
* Uses a temp body file to avoid shell escaping issues with PR body content.
|
|
285
|
+
*/
|
|
286
|
+
async function createPr(cwd, baseBranch, title, body, draft) {
|
|
287
|
+
const bodyFile = path.join(cwd, ".cortex", ".pr-body-tmp.md");
|
|
288
|
+
const cortexDir = path.join(cwd, ".cortex");
|
|
289
|
+
if (!fs.existsSync(cortexDir)) {
|
|
290
|
+
fs.mkdirSync(cortexDir, { recursive: true });
|
|
291
|
+
}
|
|
292
|
+
fs.writeFileSync(bodyFile, body);
|
|
293
|
+
try {
|
|
294
|
+
const createArgs = [
|
|
295
|
+
"pr", "create",
|
|
296
|
+
"--base", baseBranch,
|
|
297
|
+
"--title", title,
|
|
298
|
+
"--body-file", bodyFile,
|
|
299
|
+
];
|
|
300
|
+
if (draft)
|
|
301
|
+
createArgs.push("--draft");
|
|
302
|
+
const { stdout } = await gh(cwd, ...createArgs);
|
|
303
|
+
return stdout.trim();
|
|
304
|
+
}
|
|
305
|
+
finally {
|
|
306
|
+
if (fs.existsSync(bodyFile)) {
|
|
307
|
+
fs.unlinkSync(bodyFile);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
package/dist/tools/worktree.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
2
|
type Client = PluginInput["client"];
|
|
3
3
|
type Shell = PluginInput["$"];
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Factory function that creates the worktree_create tool with access
|
|
6
|
+
* to the OpenCode client for toast notifications.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createCreate(client: Client): {
|
|
5
9
|
description: string;
|
|
6
10
|
args: {
|
|
7
11
|
name: import("zod").ZodString;
|
|
@@ -25,7 +29,11 @@ export declare const list: {
|
|
|
25
29
|
args: {};
|
|
26
30
|
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
27
31
|
};
|
|
28
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Factory function that creates the worktree_remove tool with access
|
|
34
|
+
* to the OpenCode client for toast notifications and PTY cleanup.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createRemove(client: Client): {
|
|
29
37
|
description: string;
|
|
30
38
|
args: {
|
|
31
39
|
name: import("zod").ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/tools/worktree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/tools/worktree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiBvD,KAAK,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AACpC,KAAK,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;AAE9B;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;EAuF1C;AAED,eAAO,MAAM,IAAI;;;;CAiCf,CAAC;AAEH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;EAkI1C;AAED,eAAO,MAAM,IAAI;;;;;;;;CAgDf,CAAC;AAkUH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;;;;;;;;;EAsIxD"}
|