@sven1103/opencode-worktree-workflow 0.6.1 → 0.6.2

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/README.md CHANGED
@@ -42,6 +42,11 @@ In practice:
42
42
  - if the native tools are unavailable, use the local CLI fallback from the same installed package
43
43
  - if the package is not installed, no CLI fallback is available
44
44
 
45
+ Important distinction:
46
+
47
+ - `worktree_prepare` and `worktree_cleanup` are native OpenCode tools, not shell commands
48
+ - from a terminal, use `npx opencode-worktree-workflow ...` or `./node_modules/.bin/opencode-worktree-workflow ...`
49
+
45
50
  ## Install in an OpenCode project
46
51
 
47
52
  Add the package as a project dependency, following the official docs style:
@@ -145,9 +150,11 @@ If your setup uses installed skill files, copy the released `SKILL.md` into a `w
145
150
 
146
151
  This package now ships the plugin capability, a CLI fallback surface, thin slash commands, and a co-shipped policy skill.
147
152
 
153
+ These native tools are exposed inside OpenCode after the plugin is loaded. They are not terminal commands.
154
+
148
155
  ## Structured contract
149
156
 
150
- The native tool results and CLI `--json` output now use a versioned structured contract with a `schema_version` field.
157
+ The package now exposes a versioned structured contract with a `schema_version` field. Native tools return human-readable text and publish the structured result in tool metadata, while CLI `--json` prints the same structured object directly.
151
158
 
152
159
  - current `schema_version`: `1.0.0`
153
160
  - contract overview: `docs/contract.md`
@@ -163,21 +170,33 @@ Human-readable output remains available through the result `message`, but caller
163
170
 
164
171
  The npm package also exposes a local CLI so agents can fall back to the same installed package when the native plugin tools are unavailable.
165
172
 
173
+ Use the CLI from a terminal when you want to run the workflow manually. Run it inside a real git repository. By default, the workflow expects a normal remote and base-branch setup such as `origin` plus the repository default branch, unless you override that in `.opencode/worktree-workflow.json`.
174
+
166
175
  Examples:
167
176
 
168
177
  ```sh
178
+ npx opencode-worktree-workflow --help
179
+ npx opencode-worktree-workflow wt-clean --help
169
180
  npx opencode-worktree-workflow wt-new "Improve checkout retry logic"
170
181
  npx opencode-worktree-workflow wt-new "Improve checkout retry logic" --json
171
182
  npx opencode-worktree-workflow wt-clean preview
172
183
  npx opencode-worktree-workflow wt-clean apply feature/foo --json
173
184
  ```
174
185
 
186
+ Direct local bin examples:
187
+
188
+ ```sh
189
+ ./node_modules/.bin/opencode-worktree-workflow --help
190
+ ./node_modules/.bin/opencode-worktree-workflow wt-clean preview
191
+ ```
192
+
175
193
  Defaults:
176
194
 
177
195
  - human-readable output by default
178
196
  - structured output with `--json`
179
197
  - the CLI shares the same underlying implementation and result contract as the native tools
180
198
  - the CLI fallback depends on the package already being installed in the project
199
+ - if you run it outside a git repo or without the expected remote context, the CLI returns an actionable error
181
200
 
182
201
  ## Compatibility model
183
202
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sven1103/opencode-worktree-workflow",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "OpenCode plugin for creating and cleaning up git worktrees.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/cli.js CHANGED
@@ -121,6 +121,15 @@ export async function run(argv = process.argv.slice(2)) {
121
121
  });
122
122
 
123
123
  let result;
124
+ let structuredResult = null;
125
+ const toolContext = {
126
+ metadata(input) {
127
+ if (input?.metadata?.result) {
128
+ structuredResult = input.metadata.result;
129
+ }
130
+ },
131
+ worktree: process.cwd(),
132
+ };
124
133
 
125
134
  if (command === "wt-new") {
126
135
  const title = rest.join(" ").trim();
@@ -129,26 +138,20 @@ export async function run(argv = process.argv.slice(2)) {
129
138
  throw new Error("wt-new requires a descriptive title.");
130
139
  }
131
140
 
132
- result = await plugin.tool.worktree_prepare.execute(
133
- { title },
134
- { metadata() {}, worktree: process.cwd() },
135
- );
141
+ result = await plugin.tool.worktree_prepare.execute({ title }, toolContext);
136
142
  } else if (command === "wt-clean") {
137
143
  const raw = rest.join(" ").trim();
138
- result = await plugin.tool.worktree_cleanup.execute(
139
- { raw, selectors: [] },
140
- { metadata() {}, worktree: process.cwd() },
141
- );
144
+ result = await plugin.tool.worktree_cleanup.execute({ raw, selectors: [] }, toolContext);
142
145
  } else {
143
146
  throw new Error(`Unknown command: ${command}`);
144
147
  }
145
148
 
146
149
  if (outputJson) {
147
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
150
+ process.stdout.write(`${JSON.stringify(structuredResult ?? { ok: true, message: result }, null, 2)}\n`);
148
151
  return;
149
152
  }
150
153
 
151
- process.stdout.write(`${result.message || JSON.stringify(result, null, 2)}\n`);
154
+ process.stdout.write(`${result}\n`);
152
155
  }
153
156
 
154
157
  export function isInvokedAsScript(argvPath = process.argv[1]) {
package/src/index.js CHANGED
@@ -261,6 +261,16 @@ function buildPrepareResult({ title, branch, worktreePath, defaultBranch, baseBr
261
261
  };
262
262
  }
263
263
 
264
+ function publishStructuredResult(context, result) {
265
+ context.metadata({
266
+ metadata: {
267
+ result,
268
+ },
269
+ });
270
+
271
+ return result.message || JSON.stringify(result, null, 2);
272
+ }
273
+
264
274
  function buildCleanupPreviewResult({ defaultBranch, baseBranch, baseRef, grouped }) {
265
275
  const structuredGroups = {
266
276
  safe: grouped.safe.map(toStructuredCleanupItem),
@@ -662,15 +672,18 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
662
672
  );
663
673
  }
664
674
 
665
- return buildPrepareResult({
666
- title: args.title,
667
- branch: branchName,
668
- worktreePath,
669
- defaultBranch,
670
- baseBranch,
671
- baseRef,
672
- baseCommit,
673
- });
675
+ return publishStructuredResult(
676
+ context,
677
+ buildPrepareResult({
678
+ title: args.title,
679
+ branch: branchName,
680
+ worktreePath,
681
+ defaultBranch,
682
+ baseBranch,
683
+ baseRef,
684
+ baseCommit,
685
+ }),
686
+ );
674
687
  },
675
688
  }),
676
689
  worktree_cleanup: tool({
@@ -726,12 +739,15 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
726
739
  }
727
740
 
728
741
  if (normalizedArgs.mode !== "apply") {
729
- return buildCleanupPreviewResult({
730
- defaultBranch,
731
- baseBranch,
732
- baseRef,
733
- grouped,
734
- });
742
+ return publishStructuredResult(
743
+ context,
744
+ buildCleanupPreviewResult({
745
+ defaultBranch,
746
+ baseBranch,
747
+ baseRef,
748
+ grouped,
749
+ }),
750
+ );
735
751
  }
736
752
 
737
753
  const requestedSelectors = [...new Set(normalizedArgs.selectors || [])];
@@ -818,14 +834,17 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
818
834
  allowFailure: true,
819
835
  });
820
836
 
821
- return buildCleanupApplyResult({
822
- defaultBranch,
823
- baseBranch,
824
- baseRef,
825
- removed,
826
- failed,
827
- requestedSelectors,
828
- });
837
+ return publishStructuredResult(
838
+ context,
839
+ buildCleanupApplyResult({
840
+ defaultBranch,
841
+ baseBranch,
842
+ baseRef,
843
+ removed,
844
+ failed,
845
+ requestedSelectors,
846
+ }),
847
+ );
829
848
  },
830
849
  }),
831
850
  },