feat-forge 1.0.3 → 1.2.3
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 +36 -5
- package/dist/cli.js +33 -1
- package/dist/commands/AliasCommands.js +245 -0
- package/dist/commands/BranchCommands.js +12 -0
- package/dist/commands/CompletionCommands.js +809 -290
- package/dist/commands/SubBranchCommands.js +4 -0
- package/dist/foundation/PortAllocator.js +2 -0
- package/dist/foundation/Proxy.js +5 -2
- package/dist/foundation/types/Services.js +6 -0
- package/dist/lib/proxy-dashboard.js +51 -27
- package/dist/lib/services.js +2 -0
- package/dist/templates/agent/CONTEXT.code.md +7 -7
- package/dist/templates/agent/CONTEXT.spec.md +9 -9
- package/dist/templates/agent/Copilot/Specs.agent.md +3 -3
- package/dist/templates/agent/Copilot/SpecsCommit.agent.md +1 -1
- package/dist/templates/agent/Copilot/TODO-Reader.agent.md +2 -2
- package/package.json +18 -15
package/README.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# FeatForge
|
|
2
2
|
|
|
3
|
+
[](https://github.com/lixus3d/feat-forge-cli/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/feat-forge)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://vitest.dev/)
|
|
7
|
+
[](https://github.com/lixus3d/feat-forge-cli/pulls)
|
|
8
|
+
|
|
3
9
|
**FeatForge** is a feature-first workflow and CLI (`forge`) to help you build software at scale, with (or without) AI agents.
|
|
4
10
|
|
|
5
11
|
Its goal is to make the specification of features explicit and separate the thinking/specifying phase from the coding/implementation phase, across multiple agents and repositories, while keeping everything organized and traceable.
|
|
6
12
|
|
|
7
|
-
With **FeatForge** you will be able to
|
|
13
|
+
With **FeatForge** you will be able to:
|
|
8
14
|
|
|
9
15
|
- Parallelize work on multiple features:
|
|
10
16
|
- across multiple repositories.
|
|
11
|
-
-
|
|
17
|
+
- across multiple agents.
|
|
12
18
|
- while keeping track of everything.
|
|
13
19
|
- Come back to any feature after days/weeks and immediately understand its initial specifications.
|
|
14
20
|
- Change agent configurations and prompts on a per-feature basis.
|
|
@@ -20,7 +26,7 @@ With **FeatForge** you will be able to :
|
|
|
20
26
|
- Not opinionated about how you specify features, how you implement them, or how you use agents. It just provides a structure (yet customizable) and a workflow to keep everything organized and traceable.
|
|
21
27
|
- Partially tested with : Copilot, Codex, Claude code (+Ollama, LM-Studio). But it should work with any agent that can be configured to read/write files in the `.active-spec` folders.
|
|
22
28
|
|
|
23
|
-
**_This is an
|
|
29
|
+
**_This is an experiment, trying to mix between classic development and vibe-coding in large project with quality and sustainability in mind by making specification explicit and separating thinking from coding across multiple agents and repositories._**
|
|
24
30
|
|
|
25
31
|
## Key Concepts
|
|
26
32
|
|
|
@@ -37,7 +43,7 @@ With **FeatForge** you will be able to :
|
|
|
37
43
|
## Installation
|
|
38
44
|
|
|
39
45
|
```bash
|
|
40
|
-
npm install -g feat-forge
|
|
46
|
+
npm install -g feat-forge
|
|
41
47
|
forge --version
|
|
42
48
|
```
|
|
43
49
|
|
|
@@ -110,7 +116,7 @@ forge-project-root/
|
|
|
110
116
|
## Modes
|
|
111
117
|
|
|
112
118
|
Each branch has a mode stored in `.specs/<slug>/.forge-mode`. Switching modes updates agent adapter files with the corresponding templates.
|
|
113
|
-
Agent
|
|
119
|
+
Agent names are useful when calling subagents.
|
|
114
120
|
|
|
115
121
|
Built-in modes:
|
|
116
122
|
|
|
@@ -296,6 +302,23 @@ Refresh agent adapter files for the nearest branch.
|
|
|
296
302
|
|
|
297
303
|
Scan repositories for service declarations and generate configuration with allocated ports.
|
|
298
304
|
|
|
305
|
+
Service declarations are read from `.forge/services.json` in each repository. You can define an optional dedicated health endpoint per service:
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"services": [
|
|
310
|
+
{
|
|
311
|
+
"name": "api",
|
|
312
|
+
"type": "http",
|
|
313
|
+
"path": "/api",
|
|
314
|
+
"healthCheckPath": "/health"
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
If `healthCheckPath` is omitted, proxy health checks fallback to `path`, then `/`.
|
|
321
|
+
|
|
299
322
|
---
|
|
300
323
|
|
|
301
324
|
### `forge services list [branch]`
|
|
@@ -348,3 +371,11 @@ For all commands and options:
|
|
|
348
371
|
```bash
|
|
349
372
|
forge --help
|
|
350
373
|
```
|
|
374
|
+
|
|
375
|
+
## Contributing
|
|
376
|
+
|
|
377
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and contribution workflow.
|
|
378
|
+
|
|
379
|
+
# License
|
|
380
|
+
|
|
381
|
+
[](./LICENSE)
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import 'reflect-metadata';
|
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { AgentCommands } from './commands/AgentCommands.js';
|
|
6
6
|
import { MaintenanceCommands } from './commands/MaintenanceCommands.js';
|
|
7
|
+
import { AliasCommands } from './commands/AliasCommands.js';
|
|
7
8
|
import { CompletionCommands } from './commands/CompletionCommands.js';
|
|
8
9
|
import { FeatureCommands } from './commands/FeatureCommands.js';
|
|
9
10
|
import { InitCommands } from './commands/InitCommands.js';
|
|
@@ -91,6 +92,11 @@ function genericBranchTypeCommands(baseCommand, handlers, subType = null) {
|
|
|
91
92
|
.argument(`[${argName}]`, argDesc)
|
|
92
93
|
.description(`Open the given ${subType ? subType + ' ' : ''}branch in the configured IDE (if no ${subType ? subType + ' ' : ''}branch is given, opens the nearest ${subType ? subType + ' ' : ''}branch)`)
|
|
93
94
|
.action(handlers.open.bind(handlers));
|
|
95
|
+
baseCommand
|
|
96
|
+
.command('path')
|
|
97
|
+
.argument(`[${argName}]`, argDesc)
|
|
98
|
+
.description(`Print the worktree path of a ${subType ? subType + ' ' : ''}branch (useful for shell integration: cd "$(forge path <name>)")`)
|
|
99
|
+
.action(handlers.path.bind(handlers));
|
|
94
100
|
baseCommand
|
|
95
101
|
.command('merge')
|
|
96
102
|
.argument(`<${argName}>`, argDesc)
|
|
@@ -221,6 +227,29 @@ function registerProxyCommands(program, context) {
|
|
|
221
227
|
await handlers.start(options);
|
|
222
228
|
});
|
|
223
229
|
}
|
|
230
|
+
/*
|
|
231
|
+
* Register alias commands with the CLI.
|
|
232
|
+
* This command works without config.
|
|
233
|
+
*/
|
|
234
|
+
function registerAliasCommands(program) {
|
|
235
|
+
const handlers = new AliasCommands();
|
|
236
|
+
const validShells = [ShellName.Bash, ShellName.Zsh, ShellName.Fish, ShellName.PowerShell, ShellName.Pwsh];
|
|
237
|
+
function isValidShellName(value) {
|
|
238
|
+
return validShells.includes(value);
|
|
239
|
+
}
|
|
240
|
+
program
|
|
241
|
+
.command('alias <shell>')
|
|
242
|
+
.description(`Generate shell aliases for feat-forge (${validShells.join(', ')})`)
|
|
243
|
+
.option('--prefix <prefix>', 'Prefix for alias names', 'ff')
|
|
244
|
+
.action((shell, options) => {
|
|
245
|
+
if (!isValidShellName(shell)) {
|
|
246
|
+
console.error(`Error: Unsupported shell type "${shell}". Supported shells: ${validShells.join(', ')}`);
|
|
247
|
+
process.exitCode = 1;
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
handlers.generate(shell, options.prefix);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
224
253
|
/*
|
|
225
254
|
* Register completion commands with the CLI.
|
|
226
255
|
* This command works both with and without config.
|
|
@@ -263,13 +292,16 @@ async function main() {
|
|
|
263
292
|
program.name('forge').description('Feat-Forge workflow CLI').version(packageJson.version);
|
|
264
293
|
// Init command doesn't need config
|
|
265
294
|
registerInitCommands(program);
|
|
295
|
+
// Alias command doesn't need config
|
|
296
|
+
registerAliasCommands(program);
|
|
266
297
|
// Completion command should work with or without config
|
|
267
298
|
// Register it early so it's available even without .feat-forge.json
|
|
268
299
|
let context;
|
|
269
300
|
// Load config for other commands
|
|
270
301
|
const isInitCommand = process.argv[2] === 'init';
|
|
302
|
+
const isAliasCommand = process.argv[2] === 'alias';
|
|
271
303
|
const isCompletionCommand = process.argv[2] === 'completion';
|
|
272
|
-
if (!isInitCommand) {
|
|
304
|
+
if (!isInitCommand && !isAliasCommand) {
|
|
273
305
|
try {
|
|
274
306
|
context = await loadForgeContext();
|
|
275
307
|
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { ShellName } from '../foundation/types/ShellName.js';
|
|
2
|
+
/**
|
|
3
|
+
* Commands for generating shell aliases for feat-forge.
|
|
4
|
+
*/
|
|
5
|
+
export class AliasCommands {
|
|
6
|
+
/**
|
|
7
|
+
* Generate and print shell aliases for the specified shell.
|
|
8
|
+
*/
|
|
9
|
+
generate(shell, prefix) {
|
|
10
|
+
let output;
|
|
11
|
+
switch (shell) {
|
|
12
|
+
case ShellName.Bash:
|
|
13
|
+
output = this.generateBashAliases(prefix);
|
|
14
|
+
break;
|
|
15
|
+
case ShellName.Zsh:
|
|
16
|
+
output = this.generateZshAliases(prefix);
|
|
17
|
+
break;
|
|
18
|
+
case ShellName.Fish:
|
|
19
|
+
output = this.generateFishAliases(prefix);
|
|
20
|
+
break;
|
|
21
|
+
case ShellName.PowerShell:
|
|
22
|
+
case ShellName.Pwsh:
|
|
23
|
+
output = this.generatePowerShellAliases(prefix);
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
throw new Error(`Unsupported shell: ${shell}`);
|
|
27
|
+
}
|
|
28
|
+
console.log(output);
|
|
29
|
+
}
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// PRIVATE METHODS
|
|
32
|
+
// ============================================================================
|
|
33
|
+
generateBashAliases(p) {
|
|
34
|
+
return `# feat-forge aliases (generated by: forge alias bash --prefix ${p})
|
|
35
|
+
# Add to your ~/.bashrc: source <(forge alias bash${p !== 'ff' ? ` --prefix ${p}` : ''})
|
|
36
|
+
|
|
37
|
+
# Group aliases
|
|
38
|
+
alias ${p}='forge'
|
|
39
|
+
alias ${p}f='forge feature'
|
|
40
|
+
alias ${p}i='forge fix'
|
|
41
|
+
alias ${p}r='forge release'
|
|
42
|
+
|
|
43
|
+
# Command shortcuts
|
|
44
|
+
alias ${p}s='forge start'
|
|
45
|
+
alias ${p}x='forge stop'
|
|
46
|
+
alias ${p}c='forge create'
|
|
47
|
+
alias ${p}o='forge open'
|
|
48
|
+
alias ${p}l='forge list'
|
|
49
|
+
alias ${p}m='forge merge'
|
|
50
|
+
alias ${p}a='forge archive'
|
|
51
|
+
|
|
52
|
+
# Feature shortcuts
|
|
53
|
+
alias ${p}fs='forge feature start'
|
|
54
|
+
alias ${p}fx='forge feature stop'
|
|
55
|
+
alias ${p}fc='forge feature create'
|
|
56
|
+
alias ${p}fo='forge feature open'
|
|
57
|
+
alias ${p}fl='forge feature list'
|
|
58
|
+
alias ${p}fm='forge feature merge'
|
|
59
|
+
alias ${p}fa='forge feature archive'
|
|
60
|
+
|
|
61
|
+
# Fix shortcuts
|
|
62
|
+
alias ${p}is='forge fix start'
|
|
63
|
+
alias ${p}ix='forge fix stop'
|
|
64
|
+
alias ${p}ic='forge fix create'
|
|
65
|
+
alias ${p}io='forge fix open'
|
|
66
|
+
alias ${p}il='forge fix list'
|
|
67
|
+
alias ${p}im='forge fix merge'
|
|
68
|
+
alias ${p}ia='forge fix archive'
|
|
69
|
+
|
|
70
|
+
# Release shortcuts
|
|
71
|
+
alias ${p}rs='forge release start'
|
|
72
|
+
alias ${p}rx='forge release stop'
|
|
73
|
+
alias ${p}rc='forge release create'
|
|
74
|
+
alias ${p}ro='forge release open'
|
|
75
|
+
alias ${p}rl='forge release list'
|
|
76
|
+
alias ${p}rm='forge release merge'
|
|
77
|
+
alias ${p}ra='forge release archive'
|
|
78
|
+
|
|
79
|
+
# cd into branch worktree
|
|
80
|
+
${p}cd() { cd "$(forge path "$@")"; }
|
|
81
|
+
${p}fcd() { cd "$(forge feature path "$@")"; }
|
|
82
|
+
${p}icd() { cd "$(forge fix path "$@")"; }
|
|
83
|
+
${p}rcd() { cd "$(forge release path "$@")"; }
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
generateZshAliases(p) {
|
|
87
|
+
return `# feat-forge aliases (generated by: forge alias zsh --prefix ${p})
|
|
88
|
+
# Add to your ~/.zshrc: source <(forge alias zsh${p !== 'ff' ? ` --prefix ${p}` : ''})
|
|
89
|
+
|
|
90
|
+
# Group aliases
|
|
91
|
+
alias ${p}='forge'
|
|
92
|
+
alias ${p}f='forge feature'
|
|
93
|
+
alias ${p}i='forge fix'
|
|
94
|
+
alias ${p}r='forge release'
|
|
95
|
+
|
|
96
|
+
# Command shortcuts
|
|
97
|
+
alias ${p}s='forge start'
|
|
98
|
+
alias ${p}x='forge stop'
|
|
99
|
+
alias ${p}c='forge create'
|
|
100
|
+
alias ${p}o='forge open'
|
|
101
|
+
alias ${p}l='forge list'
|
|
102
|
+
alias ${p}m='forge merge'
|
|
103
|
+
alias ${p}a='forge archive'
|
|
104
|
+
|
|
105
|
+
# Feature shortcuts
|
|
106
|
+
alias ${p}fs='forge feature start'
|
|
107
|
+
alias ${p}fx='forge feature stop'
|
|
108
|
+
alias ${p}fc='forge feature create'
|
|
109
|
+
alias ${p}fo='forge feature open'
|
|
110
|
+
alias ${p}fl='forge feature list'
|
|
111
|
+
alias ${p}fm='forge feature merge'
|
|
112
|
+
alias ${p}fa='forge feature archive'
|
|
113
|
+
|
|
114
|
+
# Fix shortcuts
|
|
115
|
+
alias ${p}is='forge fix start'
|
|
116
|
+
alias ${p}ix='forge fix stop'
|
|
117
|
+
alias ${p}ic='forge fix create'
|
|
118
|
+
alias ${p}io='forge fix open'
|
|
119
|
+
alias ${p}il='forge fix list'
|
|
120
|
+
alias ${p}im='forge fix merge'
|
|
121
|
+
alias ${p}ia='forge fix archive'
|
|
122
|
+
|
|
123
|
+
# Release shortcuts
|
|
124
|
+
alias ${p}rs='forge release start'
|
|
125
|
+
alias ${p}rx='forge release stop'
|
|
126
|
+
alias ${p}rc='forge release create'
|
|
127
|
+
alias ${p}ro='forge release open'
|
|
128
|
+
alias ${p}rl='forge release list'
|
|
129
|
+
alias ${p}rm='forge release merge'
|
|
130
|
+
alias ${p}ra='forge release archive'
|
|
131
|
+
|
|
132
|
+
# cd into branch worktree
|
|
133
|
+
${p}cd() { cd "$(forge path "$@")"; }
|
|
134
|
+
${p}fcd() { cd "$(forge feature path "$@")"; }
|
|
135
|
+
${p}icd() { cd "$(forge fix path "$@")"; }
|
|
136
|
+
${p}rcd() { cd "$(forge release path "$@")"; }
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
generateFishAliases(p) {
|
|
140
|
+
return `# feat-forge aliases (generated by: forge alias fish --prefix ${p})
|
|
141
|
+
# Add to your ~/.config/fish/config.fish: forge alias fish${p !== 'ff' ? ` --prefix ${p}` : ''} | source
|
|
142
|
+
|
|
143
|
+
# Group aliases
|
|
144
|
+
abbr -a ${p} forge
|
|
145
|
+
abbr -a ${p}f 'forge feature'
|
|
146
|
+
abbr -a ${p}i 'forge fix'
|
|
147
|
+
abbr -a ${p}r 'forge release'
|
|
148
|
+
|
|
149
|
+
# Command shortcuts
|
|
150
|
+
abbr -a ${p}s 'forge start'
|
|
151
|
+
abbr -a ${p}x 'forge stop'
|
|
152
|
+
abbr -a ${p}c 'forge create'
|
|
153
|
+
abbr -a ${p}o 'forge open'
|
|
154
|
+
abbr -a ${p}l 'forge list'
|
|
155
|
+
abbr -a ${p}m 'forge merge'
|
|
156
|
+
abbr -a ${p}a 'forge archive'
|
|
157
|
+
|
|
158
|
+
# Feature shortcuts
|
|
159
|
+
abbr -a ${p}fs 'forge feature start'
|
|
160
|
+
abbr -a ${p}fx 'forge feature stop'
|
|
161
|
+
abbr -a ${p}fc 'forge feature create'
|
|
162
|
+
abbr -a ${p}fo 'forge feature open'
|
|
163
|
+
abbr -a ${p}fl 'forge feature list'
|
|
164
|
+
abbr -a ${p}fm 'forge feature merge'
|
|
165
|
+
abbr -a ${p}fa 'forge feature archive'
|
|
166
|
+
|
|
167
|
+
# Fix shortcuts
|
|
168
|
+
abbr -a ${p}is 'forge fix start'
|
|
169
|
+
abbr -a ${p}ix 'forge fix stop'
|
|
170
|
+
abbr -a ${p}ic 'forge fix create'
|
|
171
|
+
abbr -a ${p}io 'forge fix open'
|
|
172
|
+
abbr -a ${p}il 'forge fix list'
|
|
173
|
+
abbr -a ${p}im 'forge fix merge'
|
|
174
|
+
abbr -a ${p}ia 'forge fix archive'
|
|
175
|
+
|
|
176
|
+
# Release shortcuts
|
|
177
|
+
abbr -a ${p}rs 'forge release start'
|
|
178
|
+
abbr -a ${p}rx 'forge release stop'
|
|
179
|
+
abbr -a ${p}rc 'forge release create'
|
|
180
|
+
abbr -a ${p}ro 'forge release open'
|
|
181
|
+
abbr -a ${p}rl 'forge release list'
|
|
182
|
+
abbr -a ${p}rm 'forge release merge'
|
|
183
|
+
abbr -a ${p}ra 'forge release archive'
|
|
184
|
+
|
|
185
|
+
# cd into branch worktree
|
|
186
|
+
function ${p}cd; cd (forge path $argv); end
|
|
187
|
+
function ${p}fcd; cd (forge feature path $argv); end
|
|
188
|
+
function ${p}icd; cd (forge fix path $argv); end
|
|
189
|
+
function ${p}rcd; cd (forge release path $argv); end
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
generatePowerShellAliases(p) {
|
|
193
|
+
return `# feat-forge aliases (generated by: forge alias powershell --prefix ${p})
|
|
194
|
+
# Add to your $PROFILE: forge alias powershell${p !== 'ff' ? ` --prefix ${p}` : ''} | Out-String | Invoke-Expression
|
|
195
|
+
|
|
196
|
+
# Group functions
|
|
197
|
+
function ${p} { forge @args }
|
|
198
|
+
function ${p}f { forge feature @args }
|
|
199
|
+
function ${p}i { forge fix @args }
|
|
200
|
+
function ${p}r { forge release @args }
|
|
201
|
+
|
|
202
|
+
# Command shortcuts
|
|
203
|
+
function ${p}s { forge start @args }
|
|
204
|
+
function ${p}x { forge stop @args }
|
|
205
|
+
function ${p}c { forge create @args }
|
|
206
|
+
function ${p}o { forge open @args }
|
|
207
|
+
function ${p}l { forge list @args }
|
|
208
|
+
function ${p}m { forge merge @args }
|
|
209
|
+
function ${p}a { forge archive @args }
|
|
210
|
+
|
|
211
|
+
# Feature shortcuts
|
|
212
|
+
function ${p}fs { forge feature start @args }
|
|
213
|
+
function ${p}fx { forge feature stop @args }
|
|
214
|
+
function ${p}fc { forge feature create @args }
|
|
215
|
+
function ${p}fo { forge feature open @args }
|
|
216
|
+
function ${p}fl { forge feature list @args }
|
|
217
|
+
function ${p}fm { forge feature merge @args }
|
|
218
|
+
function ${p}fa { forge feature archive @args }
|
|
219
|
+
|
|
220
|
+
# Fix shortcuts
|
|
221
|
+
function ${p}is { forge fix start @args }
|
|
222
|
+
function ${p}ix { forge fix stop @args }
|
|
223
|
+
function ${p}ic { forge fix create @args }
|
|
224
|
+
function ${p}io { forge fix open @args }
|
|
225
|
+
function ${p}il { forge fix list @args }
|
|
226
|
+
function ${p}im { forge fix merge @args }
|
|
227
|
+
function ${p}ia { forge fix archive @args }
|
|
228
|
+
|
|
229
|
+
# Release shortcuts
|
|
230
|
+
function ${p}rs { forge release start @args }
|
|
231
|
+
function ${p}rx { forge release stop @args }
|
|
232
|
+
function ${p}rc { forge release create @args }
|
|
233
|
+
function ${p}ro { forge release open @args }
|
|
234
|
+
function ${p}rl { forge release list @args }
|
|
235
|
+
function ${p}rm { forge release merge @args }
|
|
236
|
+
function ${p}ra { forge release archive @args }
|
|
237
|
+
|
|
238
|
+
# cd into branch worktree
|
|
239
|
+
function ${p}cd { Set-Location (forge path @args) }
|
|
240
|
+
function ${p}fcd { Set-Location (forge feature path @args) }
|
|
241
|
+
function ${p}icd { Set-Location (forge fix path @args) }
|
|
242
|
+
function ${p}rcd { Set-Location (forge release path @args) }
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
@@ -192,6 +192,18 @@ export class BranchCommands extends AbstractCommands {
|
|
|
192
192
|
process.exitCode = 1;
|
|
193
193
|
});
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Print the path of a branch worktree directory.
|
|
197
|
+
* Outputs only the path to stdout, suitable for shell capture: cd "$(forge path <branch>)"
|
|
198
|
+
*
|
|
199
|
+
* @param rawSlug - Optional branch slug. If not provided, finds the nearest branch context.
|
|
200
|
+
*/
|
|
201
|
+
async path(rawSlug) {
|
|
202
|
+
const branchContext = rawSlug
|
|
203
|
+
? await this.context.loadBranchContext(await confirmSlugOrThrow(rawSlug))
|
|
204
|
+
: await BranchContext.findNearestBranchContext(this.context);
|
|
205
|
+
process.stdout.write(branchContext.path);
|
|
206
|
+
}
|
|
195
207
|
async merge(rawSlug) {
|
|
196
208
|
const branchName = await confirmSlugOrThrow(rawSlug);
|
|
197
209
|
let targetRepos;
|