@ship-cli/opencode 0.1.0 → 0.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/package.json +6 -6
- package/src/plugin.ts +69 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ship-cli/opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Ship - Linear task management integration",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"prepare": "effect-language-service patch --module typescript"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@opencode-ai/plugin": "^1.0.
|
|
44
|
-
"@opencode-ai/sdk": "^1.0.
|
|
45
|
-
"effect": "^3.19.
|
|
43
|
+
"@opencode-ai/plugin": "^1.0.210",
|
|
44
|
+
"@opencode-ai/sdk": "^1.0.210",
|
|
45
|
+
"effect": "^3.19.14"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@effect/language-service": "^0.
|
|
49
|
-
"@effect/vitest": "^0.
|
|
48
|
+
"@effect/language-service": "^0.64.1",
|
|
49
|
+
"@effect/vitest": "^0.27.0",
|
|
50
50
|
"@types/bun": "latest",
|
|
51
51
|
"@types/node": "^25.0.3",
|
|
52
52
|
"oxfmt": "^0.21.0",
|
package/src/plugin.ts
CHANGED
|
@@ -375,7 +375,8 @@ const ShellService = Context.GenericTag<ShellService>("ShellService");
|
|
|
375
375
|
const makeShellService = (_$: BunShell, defaultCwd?: string): ShellService => {
|
|
376
376
|
const getCommand = (): string[] => {
|
|
377
377
|
if (process.env.NODE_ENV === "development") {
|
|
378
|
-
|
|
378
|
+
// Use node with tsx loader directly to avoid pnpm re-escaping arguments with newlines
|
|
379
|
+
return ["node", "--import=tsx", "packages/cli/src/bin.ts"];
|
|
379
380
|
}
|
|
380
381
|
return ["ship"];
|
|
381
382
|
};
|
|
@@ -2210,44 +2211,72 @@ const executeAction = (
|
|
|
2210
2211
|
// =============================================================================
|
|
2211
2212
|
|
|
2212
2213
|
/**
|
|
2213
|
-
*
|
|
2214
|
-
*
|
|
2215
|
-
* @param $ - Bun shell from opencode
|
|
2216
|
-
* @param directory - Current working directory from opencode (Instance.directory)
|
|
2217
|
-
* @returns ToolDefinition for the ship tool
|
|
2214
|
+
* Build the tool description based on whether the project is a jj repo.
|
|
2215
|
+
* Only includes jj-specific hints when the project uses jj for VCS.
|
|
2218
2216
|
*/
|
|
2219
|
-
const
|
|
2220
|
-
const
|
|
2221
|
-
const ShellServiceLive = Layer.succeed(ShellService, shellService);
|
|
2222
|
-
const ShipServiceLive = Layer.effect(ShipService, makeShipService).pipe(
|
|
2223
|
-
Layer.provide(ShellServiceLive),
|
|
2224
|
-
);
|
|
2217
|
+
const buildToolDescription = (isJjRepo: boolean): string => {
|
|
2218
|
+
const baseDescription = `Linear task management and VCS operations for the current project.`;
|
|
2225
2219
|
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
return createTool({
|
|
2230
|
-
description: `Linear task management and VCS operations for the current project.
|
|
2220
|
+
const jjHints = isJjRepo
|
|
2221
|
+
? `
|
|
2231
2222
|
|
|
2232
2223
|
IMPORTANT: Always use this tool for VCS operations. NEVER run jj, gh, or git commands directly via bash.
|
|
2233
2224
|
- Use stack-create instead of: jj new, jj describe, jj bookmark create
|
|
2234
2225
|
- Use stack-describe instead of: jj describe
|
|
2235
2226
|
- Use stack-submit instead of: jj git push, gh pr create
|
|
2236
|
-
- Use stack-sync instead of: jj git fetch, jj rebase
|
|
2227
|
+
- Use stack-sync instead of: jj git fetch, jj rebase`
|
|
2228
|
+
: "";
|
|
2237
2229
|
|
|
2230
|
+
const taskFeatures = `
|
|
2238
2231
|
Use this tool to:
|
|
2239
2232
|
- List tasks ready to work on (no blockers)
|
|
2240
2233
|
- View task details
|
|
2241
2234
|
- Start/complete tasks
|
|
2242
2235
|
- Create new tasks
|
|
2243
2236
|
- Manage task dependencies (blocking relationships)
|
|
2244
|
-
- Get AI-optimized context about current work
|
|
2237
|
+
- Get AI-optimized context about current work`;
|
|
2238
|
+
|
|
2239
|
+
const jjFeatures = isJjRepo
|
|
2240
|
+
? `
|
|
2245
2241
|
- Manage stacked changes (jj workflow)
|
|
2246
2242
|
- Start/stop GitHub webhook forwarding for real-time event notifications
|
|
2247
|
-
- Subscribe to PR events via the webhook daemon (multi-session support)
|
|
2243
|
+
- Subscribe to PR events via the webhook daemon (multi-session support)`
|
|
2244
|
+
: "";
|
|
2245
|
+
|
|
2246
|
+
const footer = `
|
|
2248
2247
|
|
|
2249
2248
|
Requires ship to be configured in the project (.ship/config.yaml).
|
|
2250
|
-
Run 'ship init' in the terminal first if not configured
|
|
2249
|
+
Run 'ship init' in the terminal first if not configured.`;
|
|
2250
|
+
|
|
2251
|
+
return baseDescription + jjHints + taskFeatures + jjFeatures + footer;
|
|
2252
|
+
};
|
|
2253
|
+
|
|
2254
|
+
/**
|
|
2255
|
+
* Create the ship tool with the opencode context.
|
|
2256
|
+
*
|
|
2257
|
+
* @param $ - Bun shell from opencode
|
|
2258
|
+
* @param directory - Current working directory from opencode (Instance.directory)
|
|
2259
|
+
* @param serverUrl - OpenCode server URL for webhook routing
|
|
2260
|
+
* @param isJjRepo - Whether the directory is a jj repository
|
|
2261
|
+
* @returns ToolDefinition for the ship tool
|
|
2262
|
+
*/
|
|
2263
|
+
const createShipTool = (
|
|
2264
|
+
$: BunShell,
|
|
2265
|
+
directory: string,
|
|
2266
|
+
serverUrl?: string,
|
|
2267
|
+
isJjRepo?: boolean,
|
|
2268
|
+
): ToolDefinition => {
|
|
2269
|
+
const shellService = makeShellService($, directory);
|
|
2270
|
+
const ShellServiceLive = Layer.succeed(ShellService, shellService);
|
|
2271
|
+
const ShipServiceLive = Layer.effect(ShipService, makeShipService).pipe(
|
|
2272
|
+
Layer.provide(ShellServiceLive),
|
|
2273
|
+
);
|
|
2274
|
+
|
|
2275
|
+
const runEffect = <A, E>(effect: Effect.Effect<A, E, ShipService>): Promise<A> =>
|
|
2276
|
+
Effect.runPromise(Effect.provide(effect, ShipServiceLive));
|
|
2277
|
+
|
|
2278
|
+
return createTool({
|
|
2279
|
+
description: buildToolDescription(isJjRepo ?? false),
|
|
2251
2280
|
|
|
2252
2281
|
args: {
|
|
2253
2282
|
action: createTool.schema
|
|
@@ -2312,7 +2341,7 @@ Run 'ship init' in the terminal first if not configured.`,
|
|
|
2312
2341
|
.string()
|
|
2313
2342
|
.optional()
|
|
2314
2343
|
.describe(
|
|
2315
|
-
"
|
|
2344
|
+
"For task create: REQUIRED - use template from skill (## Summary, ## Acceptance Criteria with checkboxes, ## Notes). For task update: optional changes. For stack-describe: commit body after title.",
|
|
2316
2345
|
),
|
|
2317
2346
|
priority: createTool.schema
|
|
2318
2347
|
.enum(["urgent", "high", "medium", "low", "none"])
|
|
@@ -2662,18 +2691,35 @@ type ExtendedPluginInput = Parameters<Plugin>[0] & {
|
|
|
2662
2691
|
serverUrl?: URL;
|
|
2663
2692
|
};
|
|
2664
2693
|
|
|
2694
|
+
/**
|
|
2695
|
+
* Check if a directory is a jj repository by looking for the .jj directory.
|
|
2696
|
+
* This is a simple filesystem check that doesn't require jj to be installed.
|
|
2697
|
+
*/
|
|
2698
|
+
const checkIsJjRepo = async (directory: string): Promise<boolean> => {
|
|
2699
|
+
try {
|
|
2700
|
+
const jjPath = `${directory}/.jj`;
|
|
2701
|
+
const file = Bun.file(jjPath);
|
|
2702
|
+
// Bun.file().exists() returns true for directories too
|
|
2703
|
+
return await file.exists();
|
|
2704
|
+
} catch {
|
|
2705
|
+
return false;
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2708
|
+
|
|
2665
2709
|
export const ShipPlugin = async (input: ExtendedPluginInput) => {
|
|
2666
2710
|
const { $, directory, serverUrl } = input;
|
|
2667
2711
|
const shellService = makeShellService($, directory);
|
|
2668
2712
|
// Convert URL object to string for passing to CLI commands
|
|
2669
2713
|
const serverUrlString = serverUrl?.toString();
|
|
2714
|
+
// Check if this is a jj repository
|
|
2715
|
+
const isJjRepo = await checkIsJjRepo(directory);
|
|
2670
2716
|
|
|
2671
2717
|
return {
|
|
2672
2718
|
config: async (config: Parameters<NonNullable<Awaited<ReturnType<Plugin>>["config"]>>[0]) => {
|
|
2673
2719
|
config.command = { ...config.command, ...SHIP_COMMANDS };
|
|
2674
2720
|
},
|
|
2675
2721
|
tool: {
|
|
2676
|
-
ship: createShipTool($, directory, serverUrlString),
|
|
2722
|
+
ship: createShipTool($, directory, serverUrlString, isJjRepo),
|
|
2677
2723
|
},
|
|
2678
2724
|
"tool.execute.after": createToolExecuteAfterHook(),
|
|
2679
2725
|
"experimental.session.compacting": createCompactionHook(shellService),
|