opencode-gitwt 0.2.0 → 0.2.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 +3 -11
- package/package.json +3 -4
- package/src/index.js +95 -56
package/README.md
CHANGED
|
@@ -37,17 +37,9 @@ change the session directory. Use `gitwt_list` to inspect copies and
|
|
|
37
37
|
|
|
38
38
|
## Configuration
|
|
39
39
|
|
|
40
|
-
The plugin uses
|
|
41
|
-
and `~/.config/gitwt/config.
|
|
40
|
+
The plugin uses plain JSON: `.gitwt.json` in the project
|
|
41
|
+
and `~/.config/gitwt/config.json` globally. Options include `remote`, `base`,
|
|
42
42
|
`prefix`, `worktreeDir`, and `hooks`. See the core repository for details.
|
|
43
43
|
|
|
44
44
|
For the standalone `gitwt` command, run `npm install -g @voischev/gitwt`.
|
|
45
|
-
|
|
46
|
-
settings from `~/.config/opencode/gitwt.jsonc` to `~/.config/gitwt/config.jsonc`.
|
|
47
|
-
|
|
48
|
-
## Development
|
|
49
|
-
|
|
50
|
-
GitHub is the primary repository; SourceCraft is a mirror. Releases publish to
|
|
51
|
-
npm from GitHub with `NPM_TOKEN`.
|
|
52
|
-
|
|
53
|
-
Run `npm ci --ignore-scripts`, `npm run check`, and `npm test`.
|
|
45
|
+
Move existing settings to these paths and remove comments and trailing commas.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-gitwt",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Git worktree
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Git worktree tools for OpenCode, powered by gitwt",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
"release": "node scripts/release.js"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@voischev/gitwt": "^0.1.
|
|
27
|
-
"zod": "4.1.8"
|
|
26
|
+
"@voischev/gitwt": "^0.1.4"
|
|
28
27
|
},
|
|
29
28
|
"devDependencies": {
|
|
30
29
|
"@biomejs/biome": "2.6.3"
|
package/src/index.js
CHANGED
|
@@ -1,64 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
createWorktree,
|
|
3
|
+
GitwtError,
|
|
4
|
+
listWorktrees,
|
|
5
|
+
removeWorktree,
|
|
6
|
+
resolveWorktree,
|
|
7
|
+
} from "@voischev/gitwt";
|
|
3
8
|
|
|
4
9
|
export async function GitwtPlugin({ directory }, config = {}) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.optional()
|
|
16
|
-
.describe("Явная локальная ссылка или проверенный commit вместо remote-базы"),
|
|
17
|
-
path: z.string().optional().describe("Полный путь нового worktree"),
|
|
18
|
-
noHooks: z.boolean().optional().describe("Явно отключить хуки для создаваемого worktree"),
|
|
10
|
+
const tool = {
|
|
11
|
+
gitwt_create: {
|
|
12
|
+
description:
|
|
13
|
+
"Create and verify a new worktree. Use worktreePath for commands and files in the current session. Keep the worktree when pausing or handing off a task.",
|
|
14
|
+
args: {
|
|
15
|
+
branch: { type: "string", description: "New branch name" },
|
|
16
|
+
base: { type: "string", description: "Remote base branch" },
|
|
17
|
+
from: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Local ref or verified commit instead of a remote base",
|
|
19
20
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
await createWorktree(ctx.directory ?? directory, {
|
|
23
|
-
...args,
|
|
24
|
-
signal: ctx.abort,
|
|
25
|
-
config: { ...config, base: args.base ?? config.base },
|
|
26
|
-
}),
|
|
27
|
-
),
|
|
28
|
-
},
|
|
29
|
-
gitwt_list: {
|
|
30
|
-
description:
|
|
31
|
-
"Показать worktree из реестра Git. status проверяет dirty и доступные ahead/behind; null означает неизвестное состояние.",
|
|
32
|
-
args: { status: z.boolean().optional() },
|
|
33
|
-
execute: async (args, ctx) =>
|
|
34
|
-
JSON.stringify(await listWorktrees(ctx.directory ?? directory, args)),
|
|
35
|
-
},
|
|
36
|
-
gitwt_cd: {
|
|
37
|
-
description:
|
|
38
|
-
"Найти worktree по точной ветке или полному пути и вернуть его путь, HEAD и статус. Каталог текущей сессии не меняется: используйте worktreePath явно.",
|
|
39
|
-
args: { target: z.string() },
|
|
40
|
-
execute: async ({ target }, ctx) =>
|
|
41
|
-
JSON.stringify(
|
|
42
|
-
await resolveWorktree(ctx.directory ?? directory, target, { status: true }),
|
|
43
|
-
),
|
|
21
|
+
path: { type: "string", description: "Destination path" },
|
|
22
|
+
noHooks: { type: "boolean", description: "Disable hooks for this worktree" },
|
|
44
23
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
24
|
+
execute: async (args, ctx) =>
|
|
25
|
+
JSON.stringify(
|
|
26
|
+
await createWorktree(ctx.directory ?? directory, {
|
|
27
|
+
...args,
|
|
28
|
+
signal: ctx.abort,
|
|
29
|
+
config: { ...config, base: args.base ?? config.base },
|
|
30
|
+
}),
|
|
31
|
+
),
|
|
32
|
+
},
|
|
33
|
+
gitwt_list: {
|
|
34
|
+
description:
|
|
35
|
+
"List Git worktrees. With status, check dirty and available ahead/behind counts; null means unknown.",
|
|
36
|
+
args: { status: { type: "boolean", description: "Check live worktree status" } },
|
|
37
|
+
execute: async (args, ctx) =>
|
|
38
|
+
JSON.stringify(await listWorktrees(ctx.directory ?? directory, args)),
|
|
39
|
+
},
|
|
40
|
+
gitwt_cd: {
|
|
41
|
+
description:
|
|
42
|
+
"Resolve a branch or full path to a worktree with HEAD and status. Use worktreePath explicitly; this does not change the session directory.",
|
|
43
|
+
args: { target: { type: "string", description: "Exact branch name or full worktree path" } },
|
|
44
|
+
execute: async ({ target }, ctx) =>
|
|
45
|
+
JSON.stringify(await resolveWorktree(ctx.directory ?? directory, target, { status: true })),
|
|
46
|
+
},
|
|
47
|
+
gitwt_remove: {
|
|
48
|
+
description:
|
|
49
|
+
"Remove a worktree only when explicitly requested and no longer in use. Force discards local changes but does not bypass a failing preRemove hook.",
|
|
50
|
+
args: {
|
|
51
|
+
target: { type: "string", description: "Exact branch name or full worktree path" },
|
|
52
|
+
force: { type: "boolean", description: "Allow discarding local changes" },
|
|
53
|
+
keepBranch: { type: "boolean", description: "Keep the branch after removing the worktree" },
|
|
61
54
|
},
|
|
55
|
+
execute: async ({ target, force, keepBranch }, ctx) =>
|
|
56
|
+
JSON.stringify(
|
|
57
|
+
await removeWorktree(ctx.directory ?? directory, target, {
|
|
58
|
+
force,
|
|
59
|
+
deleteBranch: !keepBranch,
|
|
60
|
+
signal: ctx.abort,
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const required = {
|
|
66
|
+
gitwt_create: ["branch"],
|
|
67
|
+
gitwt_list: [],
|
|
68
|
+
gitwt_cd: ["target"],
|
|
69
|
+
gitwt_remove: ["target"],
|
|
70
|
+
};
|
|
71
|
+
for (const [id, definition] of Object.entries(tool)) {
|
|
72
|
+
const execute = definition.execute;
|
|
73
|
+
definition.execute = async (args, ctx) => {
|
|
74
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) {
|
|
75
|
+
throw new GitwtError("invalid_arguments", `${id}: expected an argument object`);
|
|
76
|
+
}
|
|
77
|
+
for (const key of Object.keys(args)) {
|
|
78
|
+
if (!Object.hasOwn(definition.args, key)) {
|
|
79
|
+
throw new GitwtError("invalid_arguments", `${id}: unknown argument ${key}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const [key, schema] of Object.entries(definition.args)) {
|
|
83
|
+
if (args[key] === undefined && !required[id].includes(key)) continue;
|
|
84
|
+
if (typeof args[key] !== schema.type) {
|
|
85
|
+
throw new GitwtError("invalid_arguments", `${id}: ${key} must be ${schema.type}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return execute(args, ctx);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
tool,
|
|
93
|
+
"tool.definition": async ({ toolID }, output) => {
|
|
94
|
+
if (!Object.hasOwn(tool, toolID)) return;
|
|
95
|
+
output.jsonSchema = {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: tool[toolID].args,
|
|
98
|
+
required: required[toolID],
|
|
99
|
+
additionalProperties: false,
|
|
100
|
+
};
|
|
62
101
|
},
|
|
63
102
|
};
|
|
64
103
|
}
|