@bretwardjames/ghp-cli 0.12.0 → 0.14.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/dist/commands/dashboard-pipeline.d.ts +13 -0
- package/dist/commands/dashboard-pipeline.d.ts.map +1 -0
- package/dist/commands/dashboard-pipeline.js +475 -0
- package/dist/commands/dashboard-pipeline.js.map +1 -0
- package/dist/commands/pipeline-commands.d.ts +11 -0
- package/dist/commands/pipeline-commands.d.ts.map +1 -0
- package/dist/commands/pipeline-commands.js +101 -0
- package/dist/commands/pipeline-commands.js.map +1 -0
- package/dist/commands/review.d.ts +6 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +177 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +31 -9
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts +28 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +90 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tmux.d.ts +24 -0
- package/dist/commands/tmux.d.ts.map +1 -0
- package/dist/commands/tmux.js +197 -0
- package/dist/commands/tmux.js.map +1 -0
- package/dist/commands/worktree-swap-state.d.ts +19 -0
- package/dist/commands/worktree-swap-state.d.ts.map +1 -0
- package/dist/commands/worktree-swap-state.js +29 -0
- package/dist/commands/worktree-swap-state.js.map +1 -0
- package/dist/commands/worktree-swap.d.ts +48 -0
- package/dist/commands/worktree-swap.d.ts.map +1 -0
- package/dist/commands/worktree-swap.js +456 -0
- package/dist/commands/worktree-swap.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/exit.d.ts +5 -0
- package/dist/exit.d.ts.map +1 -1
- package/dist/exit.js +7 -0
- package/dist/exit.js.map +1 -1
- package/dist/git-utils.d.ts +9 -0
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +19 -0
- package/dist/git-utils.js.map +1 -1
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline-registry.d.ts +50 -0
- package/dist/pipeline-registry.d.ts.map +1 -0
- package/dist/pipeline-registry.js +186 -0
- package/dist/pipeline-registry.js.map +1 -0
- package/dist/terminal-utils.d.ts +20 -8
- package/dist/terminal-utils.d.ts.map +1 -1
- package/dist/terminal-utils.js +47 -33
- package/dist/terminal-utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { getParallelWorkConfig, setConfigByPath, loadConfig } from '../config.js';
|
|
7
|
+
import { isInsideTmux } from '../terminal-utils.js';
|
|
8
|
+
import { exit } from '../exit.js';
|
|
9
|
+
/**
|
|
10
|
+
* Resolve template vars in a title template string.
|
|
11
|
+
* Reads {issueNumber}, {issueTitle}, {branch} from GHP_SPAWN_CONTEXT env var.
|
|
12
|
+
*/
|
|
13
|
+
function resolveTitle(template) {
|
|
14
|
+
let issueNumber = '';
|
|
15
|
+
let issueTitle = '';
|
|
16
|
+
let branch = '';
|
|
17
|
+
const raw = process.env.GHP_SPAWN_CONTEXT;
|
|
18
|
+
if (raw) {
|
|
19
|
+
try {
|
|
20
|
+
const ctx = JSON.parse(raw);
|
|
21
|
+
issueNumber = String(ctx.issue?.number ?? '');
|
|
22
|
+
issueTitle = ctx.issue?.title ?? '';
|
|
23
|
+
branch = ctx.branch ?? '';
|
|
24
|
+
}
|
|
25
|
+
catch { /* ignore parse errors */ }
|
|
26
|
+
}
|
|
27
|
+
return template
|
|
28
|
+
.replace(/\{issueNumber\}/g, issueNumber)
|
|
29
|
+
.replace(/\{issueTitle\}/g, issueTitle)
|
|
30
|
+
.replace(/\{branch\}/g, branch);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Rename the current tmux window.
|
|
34
|
+
* `tmux rename-window` without a -t flag targets the window of the calling pane.
|
|
35
|
+
*/
|
|
36
|
+
async function renameTmuxWindow(name) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const child = spawn('tmux', ['rename-window', name], { stdio: 'ignore' });
|
|
39
|
+
child.on('error', reject);
|
|
40
|
+
child.on('close', (code) => {
|
|
41
|
+
if (code === 0)
|
|
42
|
+
resolve();
|
|
43
|
+
else
|
|
44
|
+
reject(new Error(`tmux rename-window exited with code ${code}`));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Rename the current tmux window to a given title or named template.
|
|
50
|
+
* Intended to be called from within a ghp parallel work pane (e.g. by Claude).
|
|
51
|
+
*
|
|
52
|
+
* Examples:
|
|
53
|
+
* ghp tmux rename "⏳ working"
|
|
54
|
+
* ghp tmux rename --template waiting
|
|
55
|
+
*/
|
|
56
|
+
export async function tmuxRenameCommand(title, options) {
|
|
57
|
+
if (!isInsideTmux()) {
|
|
58
|
+
// Silently no-op outside tmux — safe to call unconditionally from Claude hooks
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
let resolvedTitle;
|
|
62
|
+
if (options.template) {
|
|
63
|
+
const config = getParallelWorkConfig();
|
|
64
|
+
const templateStr = config.tmuxTitleTemplates[options.template];
|
|
65
|
+
if (!templateStr) {
|
|
66
|
+
const available = Object.keys(config.tmuxTitleTemplates);
|
|
67
|
+
console.error(chalk.red('Error:'), `Title template "${options.template}" not found.`);
|
|
68
|
+
if (available.length > 0) {
|
|
69
|
+
console.error(`Available templates: ${available.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.error('No title templates configured. Add them under parallelWork.tmux.titleTemplates in your config.');
|
|
73
|
+
}
|
|
74
|
+
exit(1);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
resolvedTitle = resolveTitle(templateStr);
|
|
78
|
+
}
|
|
79
|
+
else if (title) {
|
|
80
|
+
resolvedTitle = resolveTitle(title);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.error(chalk.red('Error:'), 'Provide a title or --template <name>');
|
|
84
|
+
exit(1);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await renameTmuxWindow(resolvedTitle);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error(chalk.red('Error:'), 'Failed to rename tmux window:', error instanceof Error ? error.message : String(error));
|
|
92
|
+
exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** The three lifecycle events we hook into */
|
|
96
|
+
const TMUX_HOOKS = [
|
|
97
|
+
{ event: 'SessionStart', template: 'working', description: 'Rename window when Claude starts working' },
|
|
98
|
+
{ event: 'Stop', template: 'done', description: 'Rename window when Claude finishes' },
|
|
99
|
+
{ event: 'Notification', template: 'waiting', description: 'Rename window when Claude needs attention' },
|
|
100
|
+
];
|
|
101
|
+
/** Default title templates to add if none are configured */
|
|
102
|
+
const DEFAULT_TITLE_TEMPLATES = {
|
|
103
|
+
working: '⚙️ {issueNumber}',
|
|
104
|
+
waiting: '⏳ {issueNumber}',
|
|
105
|
+
done: '✅ {issueNumber}',
|
|
106
|
+
};
|
|
107
|
+
function readJsonFile(filePath) {
|
|
108
|
+
if (!existsSync(filePath))
|
|
109
|
+
return {};
|
|
110
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(content);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
console.error(chalk.red('Error:'), `Failed to parse ${filePath}: ${err instanceof Error ? err.message : err}`);
|
|
116
|
+
console.error('Fix the JSON syntax error and try again.');
|
|
117
|
+
exit(1);
|
|
118
|
+
return {}; // unreachable — satisfies TypeScript
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function writeJsonFile(filePath, data) {
|
|
122
|
+
const dir = dirname(filePath);
|
|
123
|
+
if (!existsSync(dir))
|
|
124
|
+
mkdirSync(dir, { recursive: true });
|
|
125
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Install Claude Code lifecycle hooks that call `ghp tmux rename` automatically.
|
|
129
|
+
* Writes to .claude/settings.json (local) or ~/.claude/settings.json (--global).
|
|
130
|
+
* Also installs default title templates into .ghp/config.json if none exist.
|
|
131
|
+
*/
|
|
132
|
+
export async function tmuxInstallHooksCommand(options) {
|
|
133
|
+
// --- 1. Determine settings.json path ---
|
|
134
|
+
const settingsPath = options.global
|
|
135
|
+
? join(homedir(), '.claude', 'settings.json')
|
|
136
|
+
: join(process.cwd(), '.claude', 'settings.json');
|
|
137
|
+
const scopeLabel = options.global ? 'global (~/.claude/settings.json)' : 'local (.claude/settings.json)';
|
|
138
|
+
// --- 2. Load existing settings ---
|
|
139
|
+
const settings = readJsonFile(settingsPath);
|
|
140
|
+
const hooks = (settings.hooks ?? {});
|
|
141
|
+
// --- 3. Install each hook event ---
|
|
142
|
+
let installed = 0;
|
|
143
|
+
let skipped = 0;
|
|
144
|
+
for (const { event, template, description } of TMUX_HOOKS) {
|
|
145
|
+
const command = `ghp tmux rename --template ${template}`;
|
|
146
|
+
const newEntry = { matcher: '', hooks: [{ type: 'command', command }] };
|
|
147
|
+
const existing = (hooks[event] ?? []);
|
|
148
|
+
// Check if this exact command is already registered
|
|
149
|
+
const alreadyPresent = existing.some(entry => entry.hooks?.some(h => h.command === command));
|
|
150
|
+
if (alreadyPresent && !options.force) {
|
|
151
|
+
console.log(chalk.dim(` ○ ${event} — already registered`));
|
|
152
|
+
skipped++;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// Remove any existing ghp tmux rename entry if --force
|
|
156
|
+
if (options.force) {
|
|
157
|
+
hooks[event] = existing.filter(entry => !entry.hooks?.some(h => h.command?.startsWith('ghp tmux rename')));
|
|
158
|
+
}
|
|
159
|
+
(hooks[event] ??= []).push(newEntry);
|
|
160
|
+
console.log(chalk.green(' ✓'), `${event} — ${description}`);
|
|
161
|
+
installed++;
|
|
162
|
+
}
|
|
163
|
+
settings.hooks = hooks;
|
|
164
|
+
writeJsonFile(settingsPath, settings);
|
|
165
|
+
// --- 4. Install default title templates if none configured ---
|
|
166
|
+
const config = loadConfig();
|
|
167
|
+
const existingTemplates = config.parallelWork?.tmux?.titleTemplates ?? {};
|
|
168
|
+
const missingTemplates = {};
|
|
169
|
+
for (const [name, value] of Object.entries(DEFAULT_TITLE_TEMPLATES)) {
|
|
170
|
+
if (!existingTemplates[name]) {
|
|
171
|
+
missingTemplates[name] = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (Object.keys(missingTemplates).length > 0) {
|
|
175
|
+
for (const [name, value] of Object.entries(missingTemplates)) {
|
|
176
|
+
setConfigByPath(`parallelWork.tmux.titleTemplates.${name}`, value, 'user');
|
|
177
|
+
}
|
|
178
|
+
console.log();
|
|
179
|
+
console.log(chalk.green('✓'), 'Added default title templates to user config:');
|
|
180
|
+
for (const [name, value] of Object.entries(missingTemplates)) {
|
|
181
|
+
console.log(` ${chalk.cyan(name)}: ${chalk.dim(`"${value}"`)}`);
|
|
182
|
+
}
|
|
183
|
+
console.log(chalk.dim(' Customize with: ghp config parallelWork.tmux.titleTemplates.<name> "<value>"'));
|
|
184
|
+
}
|
|
185
|
+
// --- 5. Summary ---
|
|
186
|
+
console.log();
|
|
187
|
+
if (installed > 0) {
|
|
188
|
+
console.log(chalk.green('✓'), `${installed} hook(s) installed to ${scopeLabel}`);
|
|
189
|
+
}
|
|
190
|
+
if (skipped > 0) {
|
|
191
|
+
console.log(chalk.dim(`${skipped} hook(s) already present (use --force to overwrite)`));
|
|
192
|
+
}
|
|
193
|
+
if (installed === 0 && skipped > 0) {
|
|
194
|
+
console.log(chalk.dim('Nothing to do.'));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/commands/tmux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared swap state helpers — extracted so both worktree-swap.ts and status.ts
|
|
3
|
+
* can read/write swap state without a circular import.
|
|
4
|
+
*/
|
|
5
|
+
export interface SwapState {
|
|
6
|
+
/** Branch main was on before the swap */
|
|
7
|
+
mainBranch: string;
|
|
8
|
+
/** Absolute path to the worktree */
|
|
9
|
+
worktreePath: string;
|
|
10
|
+
/** Branch the worktree was (and should return to) */
|
|
11
|
+
worktreeBranch: string;
|
|
12
|
+
/** ISO timestamp */
|
|
13
|
+
swappedAt: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function getStateFilePath(repoRoot: string): string;
|
|
16
|
+
export declare function readSwapState(repoRoot: string): SwapState | null;
|
|
17
|
+
export declare function writeSwapState(repoRoot: string, state: SwapState): void;
|
|
18
|
+
export declare function clearSwapState(repoRoot: string): void;
|
|
19
|
+
//# sourceMappingURL=worktree-swap-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-swap-state.d.ts","sourceRoot":"","sources":["../../src/commands/worktree-swap-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,SAAS;IACtB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAQhE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAEvE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGrD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared swap state helpers — extracted so both worktree-swap.ts and status.ts
|
|
3
|
+
* can read/write swap state without a circular import.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
export function getStateFilePath(repoRoot) {
|
|
8
|
+
return join(repoRoot, '.git', 'ghp-wt-state.json');
|
|
9
|
+
}
|
|
10
|
+
export function readSwapState(repoRoot) {
|
|
11
|
+
const path = getStateFilePath(repoRoot);
|
|
12
|
+
if (!existsSync(path))
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function writeSwapState(repoRoot, state) {
|
|
22
|
+
writeFileSync(getStateFilePath(repoRoot), JSON.stringify(state, null, 2));
|
|
23
|
+
}
|
|
24
|
+
export function clearSwapState(repoRoot) {
|
|
25
|
+
const path = getStateFilePath(repoRoot);
|
|
26
|
+
if (existsSync(path))
|
|
27
|
+
unlinkSync(path);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=worktree-swap-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-swap-state.js","sourceRoot":"","sources":["../../src/commands/worktree-swap-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAa5B,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC7C,OAAO,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC1C,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAc,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,KAAgB;IAC7D,aAAa,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree branch-swapping commands for ghp CLI.
|
|
3
|
+
*
|
|
4
|
+
* Enables "move-to" testing workflow:
|
|
5
|
+
* ghp wt move-to <issue> — detach worktree HEAD, checkout branch in main repo
|
|
6
|
+
* ghp wt clean — reverse the swap, restore both repos to original state
|
|
7
|
+
*/
|
|
8
|
+
interface MoveToOptions {
|
|
9
|
+
force?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Swap a worktree's branch into the main repo for live testing.
|
|
13
|
+
*
|
|
14
|
+
* Steps:
|
|
15
|
+
* 1. Verify we're in the main worktree (not a linked one)
|
|
16
|
+
* 2. Verify no swap already in progress
|
|
17
|
+
* 3. Locate the worktree for the given issue
|
|
18
|
+
* 4. Save current state (main branch, worktree path/branch)
|
|
19
|
+
* 5. Detach worktree HEAD (so git allows main to check out the branch)
|
|
20
|
+
* 6. Checkout the branch in main
|
|
21
|
+
* 7. On failure at step 6: automatically re-attach worktree and abort
|
|
22
|
+
*/
|
|
23
|
+
export declare function worktreeMoveToCommand(issue: string, options: MoveToOptions): Promise<void>;
|
|
24
|
+
interface CleanOptions {
|
|
25
|
+
force?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reverse a worktree swap: restore main to its previous branch and re-attach
|
|
29
|
+
* the worktree. If main accumulated new commits during testing, safely advances
|
|
30
|
+
* the branch pointer before switching away.
|
|
31
|
+
*/
|
|
32
|
+
export declare function worktreeCleanCommand(options: CleanOptions): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Show the current swap state, if any.
|
|
35
|
+
*/
|
|
36
|
+
export declare function worktreeSwapStatusCommand(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Mark the current worktree's stage as complete — ready for integration testing.
|
|
39
|
+
* Auto-detects the issue from the current branch if not specified.
|
|
40
|
+
*/
|
|
41
|
+
export declare function worktreeReadyCommand(issueArg?: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Swap the next ready worktree into the main repo.
|
|
44
|
+
* Picks FIFO by stageEnteredAt unless a specific issue is given.
|
|
45
|
+
*/
|
|
46
|
+
export declare function worktreeNextCommand(issueArg?: string): Promise<void>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=worktree-swap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-swap.d.ts","sourceRoot":"","sources":["../../src/commands/worktree-swap.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4FH,UAAU,aAAa;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmIhG;AAMD,UAAU,YAAY;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoG/E;AAoBD;;GAEG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB/D;AAMD;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD3E;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C1E"}
|