cortex-agents 2.1.0 → 2.2.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 +71 -16
- package/.opencode/agents/plan.md +11 -4
- package/README.md +248 -364
- package/dist/cli.js +25 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/tools/cortex.js +1 -1
- package/dist/tools/task.d.ts +20 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +302 -0
- package/dist/tools/worktree.d.ts +32 -0
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +403 -2
- package/dist/utils/plan-extract.d.ts +37 -0
- package/dist/utils/plan-extract.d.ts.map +1 -0
- package/dist/utils/plan-extract.js +137 -0
- package/dist/utils/propagate.d.ts +22 -0
- package/dist/utils/propagate.d.ts.map +1 -0
- package/dist/utils/propagate.js +64 -0
- package/dist/utils/worktree-detect.d.ts +20 -0
- package/dist/utils/worktree-detect.d.ts.map +1 -0
- package/dist/utils/worktree-detect.js +42 -0
- package/package.json +9 -6
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.2.0";
|
|
8
8
|
const PLUGIN_NAME = "cortex-agents";
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -387,8 +387,8 @@ function status() {
|
|
|
387
387
|
function help() {
|
|
388
388
|
console.log(`${PLUGIN_NAME} v${VERSION}
|
|
389
389
|
|
|
390
|
-
|
|
391
|
-
|
|
390
|
+
Supercharge OpenCode with structured workflows, intelligent agents,
|
|
391
|
+
and automated development practices.
|
|
392
392
|
|
|
393
393
|
USAGE:
|
|
394
394
|
npx ${PLUGIN_NAME} <command> [options]
|
|
@@ -407,28 +407,34 @@ EXAMPLES:
|
|
|
407
407
|
npx ${PLUGIN_NAME} configure --reset # Reset to default models
|
|
408
408
|
npx ${PLUGIN_NAME} status # Check status
|
|
409
409
|
|
|
410
|
-
|
|
411
|
-
Primary
|
|
410
|
+
AGENTS:
|
|
411
|
+
Primary (build, plan, debug):
|
|
412
412
|
Handle complex tasks — select your best model.
|
|
413
413
|
|
|
414
414
|
Subagents (fullstack, testing, security, devops):
|
|
415
415
|
Handle focused tasks — a fast/cheap model works great.
|
|
416
416
|
|
|
417
|
-
|
|
418
|
-
cortex_init, cortex_status
|
|
419
|
-
worktree_create, worktree_list
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
417
|
+
TOOLS (22):
|
|
418
|
+
cortex_init, cortex_status .cortex directory management
|
|
419
|
+
worktree_create, worktree_list Git worktree management
|
|
420
|
+
worktree_remove, worktree_open
|
|
421
|
+
worktree_launch Launch worktree (terminal/PTY/background)
|
|
422
|
+
branch_create, branch_status Git branch operations
|
|
423
|
+
branch_switch
|
|
424
|
+
plan_save, plan_list Plan persistence
|
|
425
|
+
plan_load, plan_delete
|
|
426
|
+
session_save, session_list Session management
|
|
427
|
+
session_load
|
|
428
|
+
docs_init, docs_save Mermaid documentation
|
|
429
|
+
docs_list, docs_index
|
|
430
|
+
task_finalize Commit, push, and create PR
|
|
424
431
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
deployment-automation, code-quality, git-workflow
|
|
432
|
+
SKILLS (14):
|
|
433
|
+
web-development, frontend-development, backend-development,
|
|
434
|
+
mobile-development, desktop-development, database-design,
|
|
435
|
+
api-design, architecture-patterns, design-patterns,
|
|
436
|
+
testing-strategies, security-hardening, deployment-automation,
|
|
437
|
+
performance-optimization, code-quality, git-workflow
|
|
432
438
|
`);
|
|
433
439
|
}
|
|
434
440
|
// ─── 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;AAsBlD,eAAO,MAAM,YAAY,EAAE,MAmE1B,CAAC;AAGF,eAAe,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as branch from "./tools/branch";
|
|
|
5
5
|
import * as plan from "./tools/plan";
|
|
6
6
|
import * as session from "./tools/session";
|
|
7
7
|
import * as docs from "./tools/docs";
|
|
8
|
+
import * as task from "./tools/task";
|
|
8
9
|
// Agent descriptions for handover toast notifications
|
|
9
10
|
const AGENT_DESCRIPTIONS = {
|
|
10
11
|
build: "Development mode — ready to implement",
|
|
@@ -26,6 +27,8 @@ export const CortexPlugin = async (ctx) => {
|
|
|
26
27
|
worktree_list: worktree.list,
|
|
27
28
|
worktree_remove: worktree.remove,
|
|
28
29
|
worktree_open: worktree.open,
|
|
30
|
+
// Dynamic tool: needs client + shell via factory (closure injection)
|
|
31
|
+
worktree_launch: worktree.createLaunch(ctx.client, ctx.$),
|
|
29
32
|
// Branch tools - git branch operations
|
|
30
33
|
branch_create: branch.create,
|
|
31
34
|
branch_status: branch.status,
|
|
@@ -44,6 +47,8 @@ export const CortexPlugin = async (ctx) => {
|
|
|
44
47
|
docs_save: docs.save,
|
|
45
48
|
docs_list: docs.list,
|
|
46
49
|
docs_index: docs.index,
|
|
50
|
+
// Task tools - finalize workflow (commit, push, PR)
|
|
51
|
+
task_finalize: task.finalize,
|
|
47
52
|
},
|
|
48
53
|
// Agent handover toast notifications
|
|
49
54
|
async event({ event }) {
|
package/dist/tools/cortex.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const finalize: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
commitMessage: import("zod").ZodString;
|
|
5
|
+
prTitle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
6
|
+
prBody: import("zod").ZodOptional<import("zod").ZodString>;
|
|
7
|
+
baseBranch: import("zod").ZodOptional<import("zod").ZodString>;
|
|
8
|
+
planFilename: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
draft: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
10
|
+
};
|
|
11
|
+
execute(args: {
|
|
12
|
+
commitMessage: string;
|
|
13
|
+
prTitle?: string | undefined;
|
|
14
|
+
prBody?: string | undefined;
|
|
15
|
+
baseBranch?: string | undefined;
|
|
16
|
+
planFilename?: string | undefined;
|
|
17
|
+
draft?: boolean | undefined;
|
|
18
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=task.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"AAyGA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;CA0OnB,CAAC"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { detectWorktreeInfo } from "../utils/worktree-detect.js";
|
|
5
|
+
import { findPlanContent, extractPlanSections, buildPrBodyFromPlan, } from "../utils/plan-extract.js";
|
|
6
|
+
const PROTECTED_BRANCHES = ["main", "master", "develop", "production", "staging"];
|
|
7
|
+
const DOCS_DIR = "docs";
|
|
8
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Check if `gh` CLI is installed and authenticated.
|
|
11
|
+
*/
|
|
12
|
+
async function checkGhCli(cwd) {
|
|
13
|
+
// Check if gh exists
|
|
14
|
+
try {
|
|
15
|
+
await Bun.$ `which gh`.quiet().text();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: "GitHub CLI (gh) is not installed. Install it from https://cli.github.com/ and run `gh auth login`.",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Check if authenticated
|
|
24
|
+
try {
|
|
25
|
+
await Bun.$ `gh auth status`.cwd(cwd).quiet().text();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: "GitHub CLI is not authenticated. Run `gh auth login` to authenticate.",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return { ok: true };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if a remote named "origin" is configured.
|
|
37
|
+
*/
|
|
38
|
+
async function checkRemote(cwd) {
|
|
39
|
+
try {
|
|
40
|
+
const remotes = await Bun.$ `git -C ${cwd} remote -v`.quiet().text();
|
|
41
|
+
if (!remotes.includes("origin")) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
error: "No 'origin' remote configured. Add one with: git remote add origin <url>",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { ok: true };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return { ok: false, error: "Could not check git remotes." };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check whether docs/ has any content beyond .gitkeep files.
|
|
55
|
+
*/
|
|
56
|
+
function checkDocsExist(worktree) {
|
|
57
|
+
const docsRoot = path.join(worktree, DOCS_DIR);
|
|
58
|
+
if (!fs.existsSync(docsRoot)) {
|
|
59
|
+
return { exists: false, count: 0 };
|
|
60
|
+
}
|
|
61
|
+
let count = 0;
|
|
62
|
+
const subDirs = ["decisions", "features", "flows"];
|
|
63
|
+
for (const sub of subDirs) {
|
|
64
|
+
const subPath = path.join(docsRoot, sub);
|
|
65
|
+
if (fs.existsSync(subPath)) {
|
|
66
|
+
const files = fs.readdirSync(subPath).filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
67
|
+
count += files.length;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { exists: count > 0, count };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get a summary of commits that will be in the PR (commits ahead of base).
|
|
74
|
+
*/
|
|
75
|
+
async function getCommitLog(cwd, baseBranch) {
|
|
76
|
+
try {
|
|
77
|
+
const log = await Bun.$ `git -C ${cwd} log ${baseBranch}..HEAD --oneline`.quiet().text();
|
|
78
|
+
return log.trim();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// If base branch doesn't exist locally, try origin/<base>
|
|
82
|
+
try {
|
|
83
|
+
const log = await Bun.$ `git -C ${cwd} log origin/${baseBranch}..HEAD --oneline`.quiet().text();
|
|
84
|
+
return log.trim();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ─── Tool ────────────────────────────────────────────────────────────────────
|
|
92
|
+
export const finalize = tool({
|
|
93
|
+
description: "Finalize a completed task: stage all changes, commit, push to origin, and create a PR via GitHub CLI. " +
|
|
94
|
+
"Auto-detects worktrees and targets the main branch. " +
|
|
95
|
+
"Auto-populates the PR body from .cortex/plans/ if a plan exists. " +
|
|
96
|
+
"Run docs_list and session_save BEFORE calling this tool.",
|
|
97
|
+
args: {
|
|
98
|
+
commitMessage: tool.schema
|
|
99
|
+
.string()
|
|
100
|
+
.describe("Commit message in conventional format (e.g., 'feat: add worktree launch tool')"),
|
|
101
|
+
prTitle: tool.schema
|
|
102
|
+
.string()
|
|
103
|
+
.optional()
|
|
104
|
+
.describe("PR title (defaults to the commit message)"),
|
|
105
|
+
prBody: tool.schema
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("Custom PR body in markdown. If omitted, auto-generated from .cortex/plans/ or commit log."),
|
|
109
|
+
baseBranch: tool.schema
|
|
110
|
+
.string()
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Target branch for PR (auto-detected: 'main' for worktrees, default branch otherwise)"),
|
|
113
|
+
planFilename: tool.schema
|
|
114
|
+
.string()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("Plan filename from .cortex/plans/ to include in PR body"),
|
|
117
|
+
draft: tool.schema
|
|
118
|
+
.boolean()
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("Create as draft PR (default: false)"),
|
|
121
|
+
},
|
|
122
|
+
async execute(args, context) {
|
|
123
|
+
const { commitMessage, prTitle, prBody: customPrBody, baseBranch: customBaseBranch, planFilename, draft = false, } = args;
|
|
124
|
+
const cwd = context.worktree;
|
|
125
|
+
const output = [];
|
|
126
|
+
const warnings = [];
|
|
127
|
+
// ── 1. Validate: git repo ─────────────────────────────────
|
|
128
|
+
try {
|
|
129
|
+
await Bun.$ `git -C ${cwd} rev-parse --git-dir`.quiet().text();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return "✗ Error: Not in a git repository.";
|
|
133
|
+
}
|
|
134
|
+
// ── 2. Detect worktree + branch ───────────────────────────
|
|
135
|
+
const wtInfo = await detectWorktreeInfo(cwd);
|
|
136
|
+
const branchName = wtInfo.currentBranch;
|
|
137
|
+
if (!branchName || branchName === "(unknown)") {
|
|
138
|
+
return "✗ Error: Could not determine current branch.";
|
|
139
|
+
}
|
|
140
|
+
if (PROTECTED_BRANCHES.includes(branchName)) {
|
|
141
|
+
return `✗ Error: Cannot finalize on protected branch '${branchName}'.
|
|
142
|
+
Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
143
|
+
}
|
|
144
|
+
// ── 3. Determine base branch ──────────────────────────────
|
|
145
|
+
let baseBranch = customBaseBranch || "";
|
|
146
|
+
if (!baseBranch) {
|
|
147
|
+
if (wtInfo.isWorktree) {
|
|
148
|
+
baseBranch = "main";
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Try to detect default branch from origin
|
|
152
|
+
try {
|
|
153
|
+
const defaultRef = await Bun.$ `git -C ${cwd} symbolic-ref refs/remotes/origin/HEAD`.quiet().text();
|
|
154
|
+
baseBranch = defaultRef.trim().replace("refs/remotes/origin/", "");
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
baseBranch = "main"; // Sensible default
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
output.push(`Branch: ${branchName} → ${baseBranch}`);
|
|
162
|
+
if (wtInfo.isWorktree) {
|
|
163
|
+
output.push(`Worktree detected (main tree: ${wtInfo.mainWorktreePath})`);
|
|
164
|
+
}
|
|
165
|
+
// ── 4. Check prerequisites ────────────────────────────────
|
|
166
|
+
const ghCheck = await checkGhCli(cwd);
|
|
167
|
+
if (!ghCheck.ok) {
|
|
168
|
+
return `✗ ${ghCheck.error}`;
|
|
169
|
+
}
|
|
170
|
+
const remoteCheck = await checkRemote(cwd);
|
|
171
|
+
if (!remoteCheck.ok) {
|
|
172
|
+
return `✗ ${remoteCheck.error}`;
|
|
173
|
+
}
|
|
174
|
+
// ── 5. Check docs (warning only) ─────────────────────────
|
|
175
|
+
const docsCheck = checkDocsExist(cwd);
|
|
176
|
+
if (!docsCheck.exists) {
|
|
177
|
+
warnings.push("No documentation found in docs/. Consider creating docs with docs_save before finalizing.");
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
output.push(`Documentation: ${docsCheck.count} doc(s) found`);
|
|
181
|
+
}
|
|
182
|
+
// ── 6. Stage all changes ──────────────────────────────────
|
|
183
|
+
try {
|
|
184
|
+
await Bun.$ `git -C ${cwd} add -A`.quiet();
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return `✗ Error staging changes: ${error.message || error}`;
|
|
188
|
+
}
|
|
189
|
+
// ── 7. Commit ─────────────────────────────────────────────
|
|
190
|
+
let commitHash = "";
|
|
191
|
+
let commitSkipped = false;
|
|
192
|
+
try {
|
|
193
|
+
// Check if there's anything to commit
|
|
194
|
+
const status = await Bun.$ `git -C ${cwd} status --porcelain`.quiet().text();
|
|
195
|
+
if (!status.trim()) {
|
|
196
|
+
commitSkipped = true;
|
|
197
|
+
output.push("No new changes to commit (working tree clean)");
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
await Bun.$ `git -C ${cwd} commit -m ${commitMessage}`.quiet();
|
|
201
|
+
const hash = await Bun.$ `git -C ${cwd} rev-parse --short HEAD`.quiet().text();
|
|
202
|
+
commitHash = hash.trim();
|
|
203
|
+
output.push(`Committed: ${commitHash} — ${commitMessage}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
return `✗ Error committing: ${error.message || error}`;
|
|
208
|
+
}
|
|
209
|
+
// ── 8. Push to origin ─────────────────────────────────────
|
|
210
|
+
try {
|
|
211
|
+
await Bun.$ `git -C ${cwd} push -u origin ${branchName}`.quiet();
|
|
212
|
+
output.push(`Pushed to origin/${branchName}`);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
return `✗ Error pushing to origin: ${error.message || error}
|
|
216
|
+
|
|
217
|
+
All previous steps succeeded (changes committed). Try pushing manually:
|
|
218
|
+
git push -u origin ${branchName}`;
|
|
219
|
+
}
|
|
220
|
+
// ── 9. Build PR body ──────────────────────────────────────
|
|
221
|
+
let prBodyContent = customPrBody || "";
|
|
222
|
+
if (!prBodyContent) {
|
|
223
|
+
// Try to build from plan
|
|
224
|
+
const plan = findPlanContent(cwd, planFilename, branchName);
|
|
225
|
+
if (plan) {
|
|
226
|
+
const sections = extractPlanSections(plan.content, plan.filename);
|
|
227
|
+
prBodyContent = buildPrBodyFromPlan(sections);
|
|
228
|
+
output.push(`PR body generated from plan: ${plan.filename}`);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Fall back to commit log
|
|
232
|
+
const commitLog = await getCommitLog(cwd, baseBranch);
|
|
233
|
+
if (commitLog) {
|
|
234
|
+
prBodyContent = `## Changes\n\n\`\`\`\n${commitLog}\n\`\`\``;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
prBodyContent = `Implementation on branch \`${branchName}\``;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// ── 10. Create PR via gh ──────────────────────────────────
|
|
242
|
+
const finalPrTitle = prTitle || commitMessage;
|
|
243
|
+
let prUrl = "";
|
|
244
|
+
try {
|
|
245
|
+
// Check if PR already exists for this branch
|
|
246
|
+
const existingPr = await Bun.$ `gh pr view ${branchName} --json url --jq .url`
|
|
247
|
+
.cwd(cwd).quiet().nothrow().text();
|
|
248
|
+
if (existingPr.trim()) {
|
|
249
|
+
prUrl = existingPr.trim();
|
|
250
|
+
output.push(`PR already exists: ${prUrl}`);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
// Create new PR
|
|
254
|
+
const draftFlag = draft ? "--draft" : "";
|
|
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
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
// PR creation failed but everything else succeeded
|
|
285
|
+
output.push(`⚠ PR creation failed: ${error.message || error}`);
|
|
286
|
+
output.push("");
|
|
287
|
+
output.push("Changes are committed and pushed. Create the PR manually:");
|
|
288
|
+
output.push(` gh pr create --base ${baseBranch} --title "${finalPrTitle}"`);
|
|
289
|
+
}
|
|
290
|
+
// ── Build final output ────────────────────────────────────
|
|
291
|
+
let finalOutput = `✓ Task finalized\n\n`;
|
|
292
|
+
finalOutput += output.join("\n");
|
|
293
|
+
if (warnings.length > 0) {
|
|
294
|
+
finalOutput += `\n\nWarnings:\n${warnings.map((w) => ` ⚠ ${w}`).join("\n")}`;
|
|
295
|
+
}
|
|
296
|
+
if (wtInfo.isWorktree) {
|
|
297
|
+
finalOutput += `\n\nThis is a worktree. When the PR is merged, you can clean up with:
|
|
298
|
+
worktree_remove (name: "${path.basename(cwd)}", deleteBranch: true)`;
|
|
299
|
+
}
|
|
300
|
+
return finalOutput;
|
|
301
|
+
},
|
|
302
|
+
});
|
package/dist/tools/worktree.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
type Client = PluginInput["client"];
|
|
3
|
+
type Shell = PluginInput["$"];
|
|
1
4
|
export declare const create: {
|
|
2
5
|
description: string;
|
|
3
6
|
args: {
|
|
@@ -42,4 +45,33 @@ export declare const open: {
|
|
|
42
45
|
name: string;
|
|
43
46
|
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
44
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Factory function that creates the worktree_launch tool with access
|
|
50
|
+
* to the OpenCode client (for PTY and toast) and shell.
|
|
51
|
+
*
|
|
52
|
+
* This uses a closure to capture `client` and `shell` since ToolContext
|
|
53
|
+
* does not provide access to the OpenCode client API.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createLaunch(client: Client, shell: Shell): {
|
|
56
|
+
description: string;
|
|
57
|
+
args: {
|
|
58
|
+
name: import("zod").ZodString;
|
|
59
|
+
mode: import("zod").ZodEnum<{
|
|
60
|
+
terminal: "terminal";
|
|
61
|
+
pty: "pty";
|
|
62
|
+
background: "background";
|
|
63
|
+
}>;
|
|
64
|
+
plan: import("zod").ZodOptional<import("zod").ZodString>;
|
|
65
|
+
agent: import("zod").ZodOptional<import("zod").ZodString>;
|
|
66
|
+
prompt: import("zod").ZodOptional<import("zod").ZodString>;
|
|
67
|
+
};
|
|
68
|
+
execute(args: {
|
|
69
|
+
name: string;
|
|
70
|
+
mode: "terminal" | "pty" | "background";
|
|
71
|
+
plan?: string | undefined;
|
|
72
|
+
agent?: string | undefined;
|
|
73
|
+
prompt?: string | undefined;
|
|
74
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
75
|
+
};
|
|
76
|
+
export {};
|
|
45
77
|
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/tools/worktree.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/tools/worktree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAQvD,KAAK,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AACpC,KAAK,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;AAE9B,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;CA8DjB,CAAC;AAEH,eAAO,MAAM,IAAI;;;;CAiCf,CAAC;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;CA4DjB,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;CAgDf,CAAC;AA4VH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;;;;;;;;;EAoIxD"}
|