@junheep/gwt 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/README.md +40 -4
- package/bin/gwt.mjs +207 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,38 @@ confirmation. The integration also provides Zsh completion for commands,
|
|
|
33
33
|
options, worktrees, and Git refs. It only changes directories; it does not load
|
|
34
34
|
environment variables or run project hooks.
|
|
35
35
|
|
|
36
|
+
## Coding agents
|
|
37
|
+
|
|
38
|
+
Coding agents do not know about `gwt` and reach for `git worktree add`, which
|
|
39
|
+
skips the copied files, assigned ports, and setup hooks. Install a skill that
|
|
40
|
+
tells them otherwise:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
gwt skill install claude
|
|
44
|
+
gwt skill install codex
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The installer shows the target path and asks for confirmation before writing.
|
|
48
|
+
Both agents read the same `SKILL.md` format and differ only in location, so
|
|
49
|
+
the installed skill is identical:
|
|
50
|
+
|
|
51
|
+
| Agent | Default | With `--project` |
|
|
52
|
+
| ------ | ------------------------------ | ---------------------------- |
|
|
53
|
+
| Claude | `~/.claude/skills/gwt/SKILL.md` | `.claude/skills/gwt/SKILL.md` |
|
|
54
|
+
| Codex | `~/.agents/skills/gwt/SKILL.md` | `.agents/skills/gwt/SKILL.md` |
|
|
55
|
+
|
|
56
|
+
`--project` writes into the primary worktree so the skill can be committed for
|
|
57
|
+
the team.
|
|
58
|
+
|
|
59
|
+
The skill covers what `gwt --help` does not: that gwt is preferred over native
|
|
60
|
+
`git worktree`, that project hooks need `gwt trust`, that a failed setup is
|
|
61
|
+
retried rather than recreated, that ports come from `gwt info`, and that
|
|
62
|
+
removal is destructive. It points at `gwt <command> --help` for command
|
|
63
|
+
details instead of repeating them, so it does not go stale as gwt changes.
|
|
64
|
+
Reinstall after upgrading to pick up a revised skill; an unchanged file is
|
|
65
|
+
reported as already installed, and a modified one is replaced only after
|
|
66
|
+
confirmation.
|
|
67
|
+
|
|
36
68
|
## Configuration
|
|
37
69
|
|
|
38
70
|
Create user configuration for the current repository:
|
|
@@ -141,7 +173,8 @@ pnpm install --frozen-lockfile
|
|
|
141
173
|
|
|
142
174
|
Hook paths in user config are resolved relative to the directory containing
|
|
143
175
|
`config.json`; hook paths in `.gwt.json` are resolved relative to the target
|
|
144
|
-
worktree. Both run with the target worktree as their working directory
|
|
176
|
+
worktree. Both run with the target worktree as their working directory, and
|
|
177
|
+
their standard output and errors are streamed directly to the terminal.
|
|
145
178
|
|
|
146
179
|
Hooks in user config are trusted because the user added them directly. Hooks
|
|
147
180
|
from a committed `.gwt.json` require explicit trust because they execute
|
|
@@ -166,6 +199,7 @@ gwt trust [--revoke]
|
|
|
166
199
|
gwt config create [--project]
|
|
167
200
|
gwt config show
|
|
168
201
|
gwt shell install zsh [--dry-run] [--yes]
|
|
202
|
+
gwt skill install <claude|codex> [--project] [--dry-run] [--yes]
|
|
169
203
|
```
|
|
170
204
|
|
|
171
205
|
Run `gwt --help` for the command overview, or `gwt <command> --help` for
|
|
@@ -184,6 +218,8 @@ arrow keys, `j`/`k`, or Ctrl-n/Ctrl-p to move; press 1–9 to select a numbered
|
|
|
184
218
|
row immediately; or press `/` to filter by branch, ID, or path. Enter switches
|
|
185
219
|
to the selected worktree. Escape leaves filter mode or cancels the picker.
|
|
186
220
|
|
|
187
|
-
`gwt remove` refuses dirty worktrees
|
|
188
|
-
`git branch -d
|
|
189
|
-
|
|
221
|
+
`gwt remove` refuses dirty worktrees and first tries to delete the branch with
|
|
222
|
+
`git branch -d`. If Git rejects safe deletion, an interactive terminal asks
|
|
223
|
+
whether to force-delete the branch; non-interactive use keeps it and prints a
|
|
224
|
+
command for deleting it later. `--discard --yes` explicitly allows dirty
|
|
225
|
+
worktree removal and forced branch deletion.
|
package/bin/gwt.mjs
CHANGED
|
@@ -23,12 +23,13 @@ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path"
|
|
|
23
23
|
import { emitKeypressEvents } from "node:readline"
|
|
24
24
|
import { createInterface } from "node:readline/promises"
|
|
25
25
|
|
|
26
|
-
const VERSION = "0.1.0"
|
|
27
26
|
const PROJECT_CONFIG_FILE = ".gwt.json"
|
|
28
27
|
const PORT_MIN = 20_000
|
|
29
28
|
const PORT_MAX = 39_999
|
|
30
29
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/
|
|
31
30
|
const DEFAULT_CONFIG = { worktreeDirectory: ".worktrees", copyFiles: [], ports: [] }
|
|
31
|
+
const SKILL_DIRECTORIES = { claude: ".claude", codex: ".agents" }
|
|
32
|
+
const SKILL_USAGE = `Usage: gwt skill install <${Object.keys(SKILL_DIRECTORIES).join("|")}> [--project] [--dry-run] [--yes]`
|
|
32
33
|
|
|
33
34
|
class CliError extends Error {}
|
|
34
35
|
|
|
@@ -496,14 +497,14 @@ function runHook(name, repository, configDocument, worktree, metadata) {
|
|
|
496
497
|
GWT_BRANCH: context.branch,
|
|
497
498
|
...Object.fromEntries(Object.entries(context.ports).map(([key, value]) => [key, String(value)])),
|
|
498
499
|
}
|
|
500
|
+
console.log(`Running ${name}...`)
|
|
499
501
|
const result = run(hook.path, [], {
|
|
500
502
|
cwd: context.path,
|
|
501
503
|
env,
|
|
502
504
|
input: `${JSON.stringify(context)}\n`,
|
|
503
505
|
allowFailure: true,
|
|
506
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
504
507
|
})
|
|
505
|
-
if (result.stdout) process.stdout.write(result.stdout)
|
|
506
|
-
if (result.stderr) process.stderr.write(result.stderr)
|
|
507
508
|
if (result.status !== 0) throw new CliError(`${name} failed with status ${result.status}`)
|
|
508
509
|
}
|
|
509
510
|
|
|
@@ -817,18 +818,46 @@ function worktreeRows(repository) {
|
|
|
817
818
|
return rows
|
|
818
819
|
}
|
|
819
820
|
|
|
821
|
+
function displayWidth(value) {
|
|
822
|
+
let width = 0
|
|
823
|
+
for (const character of value.normalize("NFC")) {
|
|
824
|
+
const codePoint = character.codePointAt(0)
|
|
825
|
+
if (/\p{Mark}/u.test(character) || codePoint === 0x200d) continue
|
|
826
|
+
const fullWidth = codePoint >= 0x1100 && (
|
|
827
|
+
codePoint <= 0x115f
|
|
828
|
+
|| codePoint === 0x2329
|
|
829
|
+
|| codePoint === 0x232a
|
|
830
|
+
|| (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f)
|
|
831
|
+
|| (codePoint >= 0xac00 && codePoint <= 0xd7a3)
|
|
832
|
+
|| (codePoint >= 0xf900 && codePoint <= 0xfaff)
|
|
833
|
+
|| (codePoint >= 0xfe10 && codePoint <= 0xfe19)
|
|
834
|
+
|| (codePoint >= 0xfe30 && codePoint <= 0xfe6f)
|
|
835
|
+
|| (codePoint >= 0xff00 && codePoint <= 0xff60)
|
|
836
|
+
|| (codePoint >= 0xffe0 && codePoint <= 0xffe6)
|
|
837
|
+
|| (codePoint >= 0x1f300 && codePoint <= 0x1faff)
|
|
838
|
+
|| (codePoint >= 0x20000 && codePoint <= 0x3fffd)
|
|
839
|
+
)
|
|
840
|
+
width += fullWidth ? 2 : 1
|
|
841
|
+
}
|
|
842
|
+
return width
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
function padDisplay(value, width) {
|
|
846
|
+
return `${value}${" ".repeat(Math.max(0, width - displayWidth(value)))}`
|
|
847
|
+
}
|
|
848
|
+
|
|
820
849
|
function commandList(args) {
|
|
821
850
|
if (args.length > 0) throw new CliError("Usage: gwt list")
|
|
822
851
|
const repository = discoverRepository()
|
|
823
852
|
const rows = worktreeRows(repository)
|
|
824
853
|
const widths = {
|
|
825
|
-
id: Math.max(2, ...rows.map((row) => row.id
|
|
826
|
-
branch: Math.max(6, ...rows.map((row) => row.branch
|
|
827
|
-
setup: Math.max(5, ...rows.map((row) => row.setup
|
|
854
|
+
id: Math.max(2, ...rows.map((row) => displayWidth(row.id))),
|
|
855
|
+
branch: Math.max(6, ...rows.map((row) => displayWidth(row.branch))),
|
|
856
|
+
setup: Math.max(5, ...rows.map((row) => displayWidth(row.setup))),
|
|
828
857
|
}
|
|
829
|
-
console.log(` ${"ID"
|
|
858
|
+
console.log(` ${padDisplay("ID", widths.id)} ${padDisplay("BRANCH", widths.branch)} ${padDisplay("SETUP", widths.setup)} PATH`)
|
|
830
859
|
for (const row of rows) {
|
|
831
|
-
console.log(`${row.current ? "*" : " "} ${row.id
|
|
860
|
+
console.log(`${row.current ? "*" : " "} ${padDisplay(row.id, widths.id)} ${padDisplay(row.branch, widths.branch)} ${padDisplay(row.setup, widths.setup)} ${row.path}`)
|
|
832
861
|
}
|
|
833
862
|
}
|
|
834
863
|
|
|
@@ -890,6 +919,7 @@ async function commandRemove(args) {
|
|
|
890
919
|
const removeArgs = ["worktree", "remove"]
|
|
891
920
|
if (options.discard) removeArgs.push("--force")
|
|
892
921
|
removeArgs.push(targetPath)
|
|
922
|
+
console.log(`Removing worktree ${metadata?.id ?? targetPath}...`)
|
|
893
923
|
git(removeArgs, repository.primaryPath)
|
|
894
924
|
if (metadata?.metadataPath && existsSync(metadata.metadataPath)) unlinkSync(metadata.metadataPath)
|
|
895
925
|
|
|
@@ -897,7 +927,20 @@ async function commandRemove(args) {
|
|
|
897
927
|
if (worktree.branch && !options["keep-branch"]) {
|
|
898
928
|
const deleteArgs = ["branch", options.discard ? "-D" : "-d", "--", worktree.branch]
|
|
899
929
|
const result = git(deleteArgs, repository.primaryPath, { allowFailure: true })
|
|
900
|
-
|
|
930
|
+
if (result.status === 0) {
|
|
931
|
+
branchMessage = `Deleted branch: ${worktree.branch}`
|
|
932
|
+
} else if (!options.discard) {
|
|
933
|
+
console.log(`Branch '${worktree.branch}' could not be deleted safely.`)
|
|
934
|
+
const forceDelete = await ask("Force-delete the branch? [y/N] ")
|
|
935
|
+
if (forceDelete) {
|
|
936
|
+
git(["branch", "-D", "--", worktree.branch], repository.primaryPath)
|
|
937
|
+
branchMessage = `Deleted branch: ${worktree.branch}`
|
|
938
|
+
} else {
|
|
939
|
+
branchMessage = `Kept branch: ${worktree.branch}\nDelete later: git branch -D -- ${worktree.branch}`
|
|
940
|
+
}
|
|
941
|
+
} else {
|
|
942
|
+
branchMessage = `Kept branch: ${worktree.branch}`
|
|
943
|
+
}
|
|
901
944
|
} else if (worktree.branch) branchMessage = `Kept branch: ${worktree.branch}`
|
|
902
945
|
|
|
903
946
|
console.log(`Removed worktree: ${metadata?.id ?? targetPath}`)
|
|
@@ -1034,6 +1077,7 @@ if command -v gwt >/dev/null 2>&1; then
|
|
|
1034
1077
|
'trust:Approve project hooks'
|
|
1035
1078
|
'config:Manage user and project configuration'
|
|
1036
1079
|
'shell:Install shell integration'
|
|
1080
|
+
'skill:Install the gwt skill for coding agents'
|
|
1037
1081
|
)
|
|
1038
1082
|
|
|
1039
1083
|
if (( CURRENT == 2 )); then
|
|
@@ -1091,6 +1135,15 @@ if command -v gwt >/dev/null 2>&1; then
|
|
|
1091
1135
|
'--yes[skip installation confirmation]' \
|
|
1092
1136
|
'(-h --help)'{-h,--help}'[show help]'
|
|
1093
1137
|
;;
|
|
1138
|
+
skill)
|
|
1139
|
+
_arguments \
|
|
1140
|
+
'2:action:(install)' \
|
|
1141
|
+
'3:agent:(claude codex)' \
|
|
1142
|
+
'--project[install into the repository instead of the home directory]' \
|
|
1143
|
+
'--dry-run[show the change without writing]' \
|
|
1144
|
+
'--yes[skip installation confirmation]' \
|
|
1145
|
+
'(-h --help)'{-h,--help}'[show help]'
|
|
1146
|
+
;;
|
|
1094
1147
|
esac
|
|
1095
1148
|
}
|
|
1096
1149
|
|
|
@@ -1100,6 +1153,92 @@ if command -v gwt >/dev/null 2>&1; then
|
|
|
1100
1153
|
fi`
|
|
1101
1154
|
}
|
|
1102
1155
|
|
|
1156
|
+
function agentSkill() {
|
|
1157
|
+
return `---
|
|
1158
|
+
name: gwt
|
|
1159
|
+
description: Use gwt to create, list, switch, and remove Git worktrees. Use whenever a task needs an isolated worktree, or in place of running 'git worktree' directly.
|
|
1160
|
+
---
|
|
1161
|
+
|
|
1162
|
+
gwt wraps native Git worktrees and prepares each one with the project's local
|
|
1163
|
+
files, assigned ports, and setup hooks.
|
|
1164
|
+
|
|
1165
|
+
## Prefer gwt over 'git worktree'
|
|
1166
|
+
|
|
1167
|
+
Create worktrees with \`gwt new\`, not \`git worktree add\`. A worktree added with
|
|
1168
|
+
plain Git skips the configured file copies, port assignment, and postCreate
|
|
1169
|
+
hook, and records no gwt metadata, so \`gwt list\` and \`gwt remove\` cannot manage
|
|
1170
|
+
it. Adopt an existing one with \`gwt setup <path>\`.
|
|
1171
|
+
|
|
1172
|
+
## Read the help instead of guessing flags
|
|
1173
|
+
|
|
1174
|
+
\`gwt --help\` lists the commands, \`gwt <command> --help\` documents arguments,
|
|
1175
|
+
options, and behavior, and nested commands such as \`gwt config create --help\`
|
|
1176
|
+
have their own help. This skill does not repeat command signatures so that they
|
|
1177
|
+
stay accurate across versions.
|
|
1178
|
+
|
|
1179
|
+
## What the help does not make obvious
|
|
1180
|
+
|
|
1181
|
+
- Hooks declared by a committed \`.gwt.json\` do not run until the repository is
|
|
1182
|
+
approved with \`gwt trust\`. Approval is invalidated whenever the config or a
|
|
1183
|
+
hook changes, so a repository that worked before can start asking again.
|
|
1184
|
+
- A failed setup keeps the worktree and records the failure. Retry it with
|
|
1185
|
+
\`gwt setup <id>\` rather than removing and recreating the worktree.
|
|
1186
|
+
- Ports are assigned per worktree. Read them from \`gwt info\` instead of assuming
|
|
1187
|
+
a project default; two worktrees of the same project never share a port.
|
|
1188
|
+
- \`gwt switch\` changes the shell's directory only when the shell integration is
|
|
1189
|
+
installed. Otherwise it just prints the path.
|
|
1190
|
+
- \`gwt switch\` with no target opens an interactive picker, so always pass an
|
|
1191
|
+
explicit target when running non-interactively.
|
|
1192
|
+
|
|
1193
|
+
## Removal is destructive
|
|
1194
|
+
|
|
1195
|
+
\`gwt remove\` deletes the worktree and, by default, its branch. Confirm with the
|
|
1196
|
+
user before running it, and never pass \`--discard --yes\` on your own: together
|
|
1197
|
+
they discard uncommitted changes and force-delete an unmerged branch.
|
|
1198
|
+
`
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
function skillPath(agent, project) {
|
|
1202
|
+
const base = project ? discoverRepository().primaryPath : homedir()
|
|
1203
|
+
return join(base, SKILL_DIRECTORIES[agent], "skills", "gwt", "SKILL.md")
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
async function installSkill(agent, args) {
|
|
1207
|
+
const { options, positionals } = parseOptions(args, {
|
|
1208
|
+
"--project": "boolean",
|
|
1209
|
+
"--dry-run": "boolean",
|
|
1210
|
+
"--yes": "boolean",
|
|
1211
|
+
})
|
|
1212
|
+
if (positionals.length > 0) throw new CliError(SKILL_USAGE)
|
|
1213
|
+
|
|
1214
|
+
const path = skillPath(agent, options.project)
|
|
1215
|
+
const contents = agentSkill()
|
|
1216
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : null
|
|
1217
|
+
if (existing === contents) {
|
|
1218
|
+
console.log(`Skill is already installed in ${path}`)
|
|
1219
|
+
return
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
const verb = existing === null ? "Create" : "Replace"
|
|
1223
|
+
console.log(`${verb} ${path}`)
|
|
1224
|
+
if (options["dry-run"]) {
|
|
1225
|
+
console.log(`\n${contents}`)
|
|
1226
|
+
return
|
|
1227
|
+
}
|
|
1228
|
+
if (!options.yes && !(await ask(`${verb}? [y/N] `))) throw new CliError("Skill installation cancelled")
|
|
1229
|
+
|
|
1230
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
1231
|
+
writeFileSync(path, contents)
|
|
1232
|
+
console.log(`Installed skill in ${path}`)
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
async function commandSkill(args) {
|
|
1236
|
+
if (args[0] === "install" && Object.hasOwn(SKILL_DIRECTORIES, args[1])) {
|
|
1237
|
+
return installSkill(args[1], args.slice(2))
|
|
1238
|
+
}
|
|
1239
|
+
throw new CliError(SKILL_USAGE)
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1103
1242
|
function zshConfigPath() {
|
|
1104
1243
|
return join(process.env.ZDOTDIR ? resolve(process.env.ZDOTDIR) : homedir(), ".zshrc")
|
|
1105
1244
|
}
|
|
@@ -1169,10 +1308,15 @@ function commandComplete(args) {
|
|
|
1169
1308
|
throw new CliError("Invalid completion request")
|
|
1170
1309
|
}
|
|
1171
1310
|
|
|
1311
|
+
function version() {
|
|
1312
|
+
const path = join(import.meta.dirname, "..", "package.json")
|
|
1313
|
+
return JSON.parse(readFileSync(path, "utf8")).version
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1172
1316
|
function help(command, subcommand) {
|
|
1173
1317
|
const topic = [command, subcommand].filter(Boolean).join(" ")
|
|
1174
1318
|
const texts = {
|
|
1175
|
-
"": `gwt ${
|
|
1319
|
+
"": `gwt ${version()} - lightweight native Git worktree workflows
|
|
1176
1320
|
|
|
1177
1321
|
Usage:
|
|
1178
1322
|
gwt <command> [options]
|
|
@@ -1187,6 +1331,7 @@ Commands:
|
|
|
1187
1331
|
trust Approve or revoke repository project hooks
|
|
1188
1332
|
config Create or inspect configuration
|
|
1189
1333
|
shell Install shell integration
|
|
1334
|
+
skill Install the gwt skill for coding agents
|
|
1190
1335
|
|
|
1191
1336
|
Options:
|
|
1192
1337
|
-h, --help Show help.
|
|
@@ -1198,6 +1343,7 @@ Examples:
|
|
|
1198
1343
|
gwt remove
|
|
1199
1344
|
gwt config create
|
|
1200
1345
|
gwt shell install zsh
|
|
1346
|
+
gwt skill install claude
|
|
1201
1347
|
|
|
1202
1348
|
Run 'gwt <command> --help' for command behavior and more examples.`,
|
|
1203
1349
|
new: `Create a worktree, prepare its development environment, and switch to it.
|
|
@@ -1311,9 +1457,10 @@ Options:
|
|
|
1311
1457
|
|
|
1312
1458
|
Behavior:
|
|
1313
1459
|
Without --discard, dirty worktrees are rejected and branches are deleted only
|
|
1314
|
-
when 'git branch -d' considers deletion safe.
|
|
1315
|
-
|
|
1316
|
-
primary worktree.
|
|
1460
|
+
when 'git branch -d' considers deletion safe. If safe deletion fails, an
|
|
1461
|
+
interactive terminal asks whether to force-delete the branch; non-interactive
|
|
1462
|
+
use keeps it. The primary worktree cannot be removed. Removing the current
|
|
1463
|
+
worktree returns an integrated shell to the primary worktree.
|
|
1317
1464
|
|
|
1318
1465
|
Examples:
|
|
1319
1466
|
gwt remove
|
|
@@ -1417,6 +1564,50 @@ when ZDOTDIR is set. Restart Zsh or source the file after installation.
|
|
|
1417
1564
|
Examples:
|
|
1418
1565
|
gwt shell install zsh
|
|
1419
1566
|
gwt shell install zsh --dry-run`,
|
|
1567
|
+
skill: `Install the gwt skill so coding agents use gwt correctly.
|
|
1568
|
+
|
|
1569
|
+
Usage:
|
|
1570
|
+
gwt skill install <claude|codex> [--project] [--dry-run] [--yes]
|
|
1571
|
+
|
|
1572
|
+
Options:
|
|
1573
|
+
-h, --help Show help for this command.
|
|
1574
|
+
|
|
1575
|
+
The skill teaches an agent to prefer gwt over native 'git worktree', to read
|
|
1576
|
+
'gwt <command> --help' for command details, and to treat removal as
|
|
1577
|
+
destructive. It does not duplicate command signatures, so it stays accurate
|
|
1578
|
+
as gwt changes.
|
|
1579
|
+
|
|
1580
|
+
Examples:
|
|
1581
|
+
gwt skill install claude
|
|
1582
|
+
gwt skill install codex`,
|
|
1583
|
+
"skill install": `Install the gwt skill for a coding agent.
|
|
1584
|
+
|
|
1585
|
+
Usage:
|
|
1586
|
+
gwt skill install <claude|codex> [--project] [--dry-run] [--yes]
|
|
1587
|
+
|
|
1588
|
+
Arguments:
|
|
1589
|
+
claude Install for Claude Code, under .claude/skills.
|
|
1590
|
+
codex Install for Codex, under .agents/skills.
|
|
1591
|
+
|
|
1592
|
+
Options:
|
|
1593
|
+
--project Write the skill inside the primary worktree, so it can be
|
|
1594
|
+
committed for the team, instead of the home directory.
|
|
1595
|
+
--dry-run Print the target path and the skill without writing it.
|
|
1596
|
+
--yes Install without asking for confirmation.
|
|
1597
|
+
-h, --help Show help for this command.
|
|
1598
|
+
|
|
1599
|
+
Both agents read the same SKILL.md format and only differ in location, so the
|
|
1600
|
+
installed skill is identical. Install it once per agent.
|
|
1601
|
+
|
|
1602
|
+
Reinstall after upgrading gwt to pick up a revised skill. The command reports
|
|
1603
|
+
an unchanged file as already installed and asks before replacing a modified
|
|
1604
|
+
one.
|
|
1605
|
+
|
|
1606
|
+
Examples:
|
|
1607
|
+
gwt skill install claude
|
|
1608
|
+
gwt skill install codex
|
|
1609
|
+
gwt skill install codex --project
|
|
1610
|
+
gwt skill install claude --dry-run`,
|
|
1420
1611
|
}
|
|
1421
1612
|
|
|
1422
1613
|
if (!Object.hasOwn(texts, topic)) throw new CliError(`Unknown help topic: ${topic}`)
|
|
@@ -1427,9 +1618,9 @@ async function main() {
|
|
|
1427
1618
|
const [command, ...args] = process.argv.slice(2)
|
|
1428
1619
|
if (!command || command === "--help" || command === "-h") return help()
|
|
1429
1620
|
if (command === "help") return help(args[0], args[1])
|
|
1430
|
-
if (command === "--version" || command === "-V") return console.log(
|
|
1621
|
+
if (command === "--version" || command === "-V") return console.log(version())
|
|
1431
1622
|
if (args.includes("--help") || args.includes("-h")) {
|
|
1432
|
-
const subcommand = ["config", "shell"].includes(command)
|
|
1623
|
+
const subcommand = ["config", "shell", "skill"].includes(command)
|
|
1433
1624
|
? args.find((argument) => !argument.startsWith("-"))
|
|
1434
1625
|
: undefined
|
|
1435
1626
|
return help(command, subcommand)
|
|
@@ -1443,6 +1634,7 @@ async function main() {
|
|
|
1443
1634
|
if (command === "trust") return commandTrust(args)
|
|
1444
1635
|
if (command === "config") return commandConfig(args)
|
|
1445
1636
|
if (command === "shell") return commandShell(args)
|
|
1637
|
+
if (command === "skill") return commandSkill(args)
|
|
1446
1638
|
if (command === "__complete") return commandComplete(args)
|
|
1447
1639
|
throw new CliError(`Unknown command: ${command}`)
|
|
1448
1640
|
}
|