@sven1103/opencode-worktree-workflow 1.0.0-alpha.1 → 1.0.0-alpha.3
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/index.cjs +12 -0
- package/package.json +16 -3
- package/src/index.js +44 -60
package/index.cjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const plugin = {
|
|
4
|
+
id: "@sven1103/opencode-worktree-workflow",
|
|
5
|
+
async server(...args) {
|
|
6
|
+
const mod = await import("./src/index.js");
|
|
7
|
+
return mod.WorktreeWorkflowPlugin(...args);
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
module.exports = plugin;
|
|
12
|
+
module.exports.default = plugin;
|
package/package.json
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sven1103/opencode-worktree-workflow",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.3",
|
|
4
4
|
"description": "OpenCode plugin for creating and cleaning up git worktrees.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
6
|
+
"main": "./index.cjs",
|
|
7
7
|
"bin": {
|
|
8
8
|
"opencode-worktree-workflow": "./src/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
11
|
+
".": {
|
|
12
|
+
"require": "./index.cjs",
|
|
13
|
+
"import": "./src/index.js",
|
|
14
|
+
"default": "./index.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./server": {
|
|
17
|
+
"require": "./index.cjs",
|
|
18
|
+
"import": "./src/index.js",
|
|
19
|
+
"default": "./index.cjs"
|
|
20
|
+
}
|
|
12
21
|
},
|
|
22
|
+
"oc-plugin": [
|
|
23
|
+
"server"
|
|
24
|
+
],
|
|
13
25
|
"files": [
|
|
26
|
+
"index.cjs",
|
|
14
27
|
"src",
|
|
15
28
|
"schemas",
|
|
16
29
|
"skills"
|
package/src/index.js
CHANGED
|
@@ -163,6 +163,8 @@ export const __internal = {
|
|
|
163
163
|
hasOpaqueRepoRootAbsoluteReference,
|
|
164
164
|
};
|
|
165
165
|
|
|
166
|
+
export const pluginID = "@sven1103/opencode-worktree-workflow";
|
|
167
|
+
|
|
166
168
|
export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
167
169
|
const service = createWorktreeWorkflowService({
|
|
168
170
|
directory,
|
|
@@ -170,14 +172,14 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
170
172
|
stateStore: createRuntimeStateStore(),
|
|
171
173
|
});
|
|
172
174
|
|
|
173
|
-
async function onToolExecuteBefore(input) {
|
|
174
|
-
const toolName = input?.tool
|
|
175
|
-
const args =
|
|
175
|
+
async function onToolExecuteBefore(input, output) {
|
|
176
|
+
const toolName = input?.tool;
|
|
177
|
+
const args = output?.args || {};
|
|
176
178
|
const classification = classifyToolExecution({ toolName, args });
|
|
177
|
-
if (classification.bypass) return
|
|
179
|
+
if (classification.bypass) return;
|
|
178
180
|
const rewritePolicy = getToolRewritePolicy({ toolName });
|
|
179
181
|
|
|
180
|
-
const sessionID = input?.sessionID
|
|
182
|
+
const sessionID = input?.sessionID;
|
|
181
183
|
let binding = null;
|
|
182
184
|
|
|
183
185
|
if (classification.requiresIsolation) {
|
|
@@ -199,7 +201,7 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
199
201
|
if (activeTask?.worktree_path) binding = { repoRoot, task: activeTask };
|
|
200
202
|
}
|
|
201
203
|
|
|
202
|
-
if (!binding) return
|
|
204
|
+
if (!binding) return;
|
|
203
205
|
|
|
204
206
|
if (toolName === "task") {
|
|
205
207
|
const handoffPath = resolveSafeHandoffPath({
|
|
@@ -212,13 +214,11 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
212
214
|
}
|
|
213
215
|
const workspaceContext = buildWorkspaceContext({ task: binding.task, workspaceRole: deriveWorkspaceRole({ subagentType: args.subagent_type }) });
|
|
214
216
|
await enrichHandoffArtifact(handoffPath, workspaceContext);
|
|
215
|
-
|
|
216
|
-
...
|
|
217
|
-
args: {
|
|
218
|
-
...args,
|
|
219
|
-
prompt: `${args.prompt}\n\nWorkspace binding:\n- task_id: ${workspaceContext.task_id}\n- worktree_path: ${workspaceContext.worktree_path}\n- workspace_role: ${workspaceContext.workspace_role}`,
|
|
220
|
-
},
|
|
217
|
+
output.args = {
|
|
218
|
+
...args,
|
|
219
|
+
prompt: `${args.prompt}\n\nWorkspace binding:\n- task_id: ${workspaceContext.task_id}\n- worktree_path: ${workspaceContext.worktree_path}\n- workspace_role: ${workspaceContext.workspace_role}`,
|
|
221
220
|
};
|
|
221
|
+
return;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
const nextArgs = { ...args };
|
|
@@ -239,15 +239,15 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
output.args = nextArgs;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
async function onToolExecuteAfter(input) {
|
|
246
|
-
const toolName = input?.tool
|
|
245
|
+
async function onToolExecuteAfter(input, output) {
|
|
246
|
+
const toolName = input?.tool;
|
|
247
247
|
const args = input?.args || {};
|
|
248
|
-
const sessionID = input?.sessionID
|
|
248
|
+
const sessionID = input?.sessionID;
|
|
249
249
|
if (toolName === "worktree_prepare" && sessionID) {
|
|
250
|
-
const result =
|
|
250
|
+
const result = output?.metadata?.result;
|
|
251
251
|
if (result?.branch && result?.worktree_path) {
|
|
252
252
|
const repoRoot = await service.getRepoRoot();
|
|
253
253
|
await service.updateStateForPrepare(repoRoot, sessionID, result, "manual");
|
|
@@ -273,21 +273,14 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
273
273
|
});
|
|
274
274
|
if (persisted && lifecycle.signal === "complete") {
|
|
275
275
|
try {
|
|
276
|
-
const advisory = await service.buildCleanupAdvisoryPreview({ repoRoot, activeWorktree:
|
|
277
|
-
const parts = Array.isArray(input?.output?.parts) ? [...input.output.parts] : [];
|
|
278
|
-
parts.push({ type: "text", text: advisory.message });
|
|
276
|
+
const advisory = await service.buildCleanupAdvisoryPreview({ repoRoot, activeWorktree: directory });
|
|
279
277
|
await service.recordToolUsage({ sessionID });
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
output: {
|
|
283
|
-
|
|
284
|
-
parts,
|
|
285
|
-
},
|
|
286
|
-
metadata: {
|
|
287
|
-
...(input?.metadata && typeof input.metadata === "object" ? input.metadata : {}),
|
|
288
|
-
advisory_cleanup_preview: advisory,
|
|
289
|
-
},
|
|
278
|
+
output.output = output.output ? `${output.output}\n\n${advisory.message}` : advisory.message;
|
|
279
|
+
output.metadata = {
|
|
280
|
+
...(output?.metadata && typeof output.metadata === "object" ? output.metadata : {}),
|
|
281
|
+
advisory_cleanup_preview: advisory,
|
|
290
282
|
};
|
|
283
|
+
return;
|
|
291
284
|
} catch {
|
|
292
285
|
// Advisory preview is non-fatal.
|
|
293
286
|
}
|
|
@@ -299,53 +292,39 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
299
292
|
}
|
|
300
293
|
}
|
|
301
294
|
if (sessionID) await service.recordToolUsage({ sessionID });
|
|
302
|
-
return input;
|
|
303
295
|
}
|
|
304
296
|
|
|
305
|
-
async function onCommandExecuteBefore(input) {
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
if (normalizedName !== "wt-new" && normalizedName !== "wt-clean") return input;
|
|
297
|
+
async function onCommandExecuteBefore(input, output) {
|
|
298
|
+
const normalizedName = typeof input?.command === "string" ? input.command.replace(/^\//, "") : "";
|
|
299
|
+
if (normalizedName !== "wt-new" && normalizedName !== "wt-clean") return;
|
|
309
300
|
|
|
310
|
-
const argsText = typeof input?.arguments === "string" ? input.arguments :
|
|
301
|
+
const argsText = typeof input?.arguments === "string" ? input.arguments : "";
|
|
311
302
|
const parts = normalizedName === "wt-new" ? buildWtNewCommandPromptParts(argsText) : buildWtCleanCommandPromptParts(argsText);
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
...input,
|
|
315
|
-
output: {
|
|
316
|
-
...(input?.output && typeof input.output === "object" ? input.output : {}),
|
|
317
|
-
parts,
|
|
318
|
-
},
|
|
319
|
-
};
|
|
303
|
+
output.parts = parts;
|
|
320
304
|
}
|
|
321
305
|
|
|
322
|
-
async function onExperimentalChatSystemTransform(input) {
|
|
323
|
-
const sessionID = input?.sessionID
|
|
324
|
-
const existingSystem =
|
|
325
|
-
if (!sessionID || existingSystem.includes(WORKSPACE_SYSTEM_CONTEXT_MARKER)) return
|
|
306
|
+
async function onExperimentalChatSystemTransform(input, output) {
|
|
307
|
+
const sessionID = input?.sessionID;
|
|
308
|
+
const existingSystem = Array.isArray(output?.system) ? output.system : [];
|
|
309
|
+
if (!sessionID || existingSystem.some((entry) => entry.includes(WORKSPACE_SYSTEM_CONTEXT_MARKER))) return;
|
|
326
310
|
|
|
327
311
|
const repoRoot = await service.getRepoRoot();
|
|
328
312
|
const { activeTask } = await service.getSessionBinding({ repoRoot, sessionID });
|
|
329
|
-
if (!activeTask?.worktree_path) return
|
|
313
|
+
if (!activeTask?.worktree_path) return;
|
|
330
314
|
|
|
331
315
|
const workspaceContext = buildWorkspaceContext({
|
|
332
316
|
task: activeTask,
|
|
333
317
|
workspaceRole: activeTask.workspace_role,
|
|
334
318
|
});
|
|
335
319
|
const injected = formatWorkspaceSystemContext(workspaceContext);
|
|
336
|
-
|
|
337
|
-
...input,
|
|
338
|
-
system: existingSystem ? `${existingSystem}\n\n${injected}` : injected,
|
|
339
|
-
};
|
|
320
|
+
output.system = [...existingSystem, injected];
|
|
340
321
|
}
|
|
341
322
|
|
|
342
323
|
return {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"tool.execute.after": onToolExecuteAfter,
|
|
348
|
-
},
|
|
324
|
+
"command.execute.before": onCommandExecuteBefore,
|
|
325
|
+
"experimental.chat.system.transform": onExperimentalChatSystemTransform,
|
|
326
|
+
"tool.execute.before": onToolExecuteBefore,
|
|
327
|
+
"tool.execute.after": onToolExecuteAfter,
|
|
349
328
|
tool: {
|
|
350
329
|
worktree_prepare: tool({
|
|
351
330
|
description: "Create a synced git worktree from a descriptive title",
|
|
@@ -381,4 +360,9 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
381
360
|
};
|
|
382
361
|
};
|
|
383
362
|
|
|
384
|
-
|
|
363
|
+
const plugin = {
|
|
364
|
+
id: pluginID,
|
|
365
|
+
server: WorktreeWorkflowPlugin,
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
export default plugin;
|