@pcoliveira90/pdd 0.3.1 → 0.4.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.en.md +2 -5
- package/README.md +2 -5
- package/README.pt-BR.md +2 -5
- package/package.json +1 -1
- package/src/cli/index.js +64 -22
- package/src/core/worktree-guard.js +42 -2
package/README.en.md
CHANGED
|
@@ -22,13 +22,10 @@ Language versions: [Default README](README.md) | [Português (Brasil)](README.pt
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
# 1)
|
|
26
|
-
git worktree add ../pdd-worktrees/my-change -b feature/my-change
|
|
27
|
-
|
|
28
|
-
# 2) Initialize PDD in the repository
|
|
25
|
+
# 1) Initialize PDD in the repository (if running in primary, PDD auto-creates a linked worktree)
|
|
29
26
|
pdd init --here
|
|
30
27
|
|
|
31
|
-
#
|
|
28
|
+
# 2) Run a fix workflow
|
|
32
29
|
pdd fix "login not saving incomeStatus"
|
|
33
30
|
```
|
|
34
31
|
|
package/README.md
CHANGED
|
@@ -22,13 +22,10 @@ Language versions: [English](README.en.md) | [Português (Brasil)](README.pt-BR.
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
# 1)
|
|
26
|
-
git worktree add ../pdd-worktrees/my-change -b feature/my-change
|
|
27
|
-
|
|
28
|
-
# 2) Initialize PDD in the repository
|
|
25
|
+
# 1) Initialize PDD in the repository (if running in primary, PDD auto-creates a linked worktree)
|
|
29
26
|
pdd init --here
|
|
30
27
|
|
|
31
|
-
#
|
|
28
|
+
# 2) Run a fix workflow
|
|
32
29
|
pdd fix "login not saving incomeStatus"
|
|
33
30
|
```
|
|
34
31
|
|
package/README.pt-BR.md
CHANGED
|
@@ -22,13 +22,10 @@ Versoes por idioma: [README padrao](README.md) | [English](README.en.md)
|
|
|
22
22
|
## Inicio rapido
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
# 1)
|
|
26
|
-
git worktree add ../pdd-worktrees/minha-mudanca -b feature/minha-mudanca
|
|
27
|
-
|
|
28
|
-
# 2) Inicialize o PDD no repositorio
|
|
25
|
+
# 1) Inicialize o PDD no repositorio (se estiver na principal, o PDD cria worktree vinculada automaticamente)
|
|
29
26
|
pdd init --here
|
|
30
27
|
|
|
31
|
-
#
|
|
28
|
+
# 2) Rode um fluxo de correcao
|
|
32
29
|
pdd fix "login nao salva incomeStatus"
|
|
33
30
|
```
|
|
34
31
|
|
package/package.json
CHANGED
package/src/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import { spawnSync } from 'child_process';
|
|
4
5
|
import { runValidation } from '../core/validator.js';
|
|
5
6
|
import { openPullRequest } from '../core/pr-manager.js';
|
|
6
7
|
import { generatePatchArtifacts } from '../core/patch-generator.js';
|
|
@@ -8,7 +9,7 @@ import { runInit } from './init-command.js';
|
|
|
8
9
|
import { runDoctor } from './doctor-command.js';
|
|
9
10
|
import { runStatus } from './status-command.js';
|
|
10
11
|
import { runResilientFixWorkflow } from '../core/fix-runner.js';
|
|
11
|
-
import {
|
|
12
|
+
import { createLinkedWorktree, detectWorktreeContext } from '../core/worktree-guard.js';
|
|
12
13
|
|
|
13
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
|
|
@@ -33,6 +34,44 @@ function parseFixArgs(argv) {
|
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
function maybeAutoRelocateToWorktree({
|
|
38
|
+
cwd,
|
|
39
|
+
argv,
|
|
40
|
+
commandName,
|
|
41
|
+
enabled
|
|
42
|
+
}) {
|
|
43
|
+
if (!enabled || argv.includes('--allow-main-worktree')) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const context = detectWorktreeContext(cwd);
|
|
48
|
+
if (!context.isGitRepo || !context.isPrimaryWorktree) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { worktreePath, branchName } = createLinkedWorktree({
|
|
53
|
+
baseDir: cwd,
|
|
54
|
+
commandName
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
console.log(`🔀 Primary worktree detected. Auto-created linked worktree: ${worktreePath}`);
|
|
58
|
+
console.log(`🪴 Branch: ${branchName}`);
|
|
59
|
+
console.log('▶️ Continuing command in the new worktree...');
|
|
60
|
+
|
|
61
|
+
const result = spawnSync(
|
|
62
|
+
process.execPath,
|
|
63
|
+
[process.argv[1], ...argv],
|
|
64
|
+
{ cwd: worktreePath, stdio: 'inherit' }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (result.error) {
|
|
68
|
+
throw result.error;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
process.exitCode = typeof result.status === 'number' ? result.status : 1;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
36
75
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
37
76
|
const command = argv[0];
|
|
38
77
|
const cwd = process.cwd();
|
|
@@ -43,27 +82,27 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
43
82
|
}
|
|
44
83
|
|
|
45
84
|
if (command === 'init') {
|
|
46
|
-
const allowMainWorktree = argv.includes('--allow-main-worktree');
|
|
47
85
|
const mutatesCurrentRepo = argv.includes('--here') || argv.includes('--upgrade');
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
if (maybeAutoRelocateToWorktree({
|
|
87
|
+
cwd,
|
|
88
|
+
argv,
|
|
89
|
+
commandName: 'init',
|
|
90
|
+
enabled: mutatesCurrentRepo
|
|
91
|
+
})) {
|
|
92
|
+
return;
|
|
54
93
|
}
|
|
55
94
|
await runInit(argv);
|
|
56
95
|
return;
|
|
57
96
|
}
|
|
58
97
|
|
|
59
98
|
if (command === 'doctor') {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
99
|
+
if (maybeAutoRelocateToWorktree({
|
|
100
|
+
cwd,
|
|
101
|
+
argv,
|
|
102
|
+
commandName: 'doctor-fix',
|
|
103
|
+
enabled: argv.includes('--fix')
|
|
104
|
+
})) {
|
|
105
|
+
return;
|
|
67
106
|
}
|
|
68
107
|
runDoctor(cwd, argv);
|
|
69
108
|
return;
|
|
@@ -75,7 +114,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
75
114
|
}
|
|
76
115
|
|
|
77
116
|
if (command === 'fix') {
|
|
78
|
-
const { issue, openPr, dryRun, noValidate
|
|
117
|
+
const { issue, openPr, dryRun, noValidate } = parseFixArgs(argv);
|
|
79
118
|
|
|
80
119
|
if (!issue) {
|
|
81
120
|
console.error('❌ Missing issue description.');
|
|
@@ -83,11 +122,14 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
83
122
|
process.exit(1);
|
|
84
123
|
}
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
125
|
+
if (maybeAutoRelocateToWorktree({
|
|
126
|
+
cwd,
|
|
127
|
+
argv,
|
|
88
128
|
commandName: 'fix',
|
|
89
|
-
|
|
90
|
-
})
|
|
129
|
+
enabled: true
|
|
130
|
+
})) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
91
133
|
|
|
92
134
|
console.log('🔧 PDD Fix Workflow');
|
|
93
135
|
console.log(`Issue: ${issue}`);
|
|
@@ -143,8 +185,8 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
143
185
|
console.log(' pdd version (or: pdd --version, pdd -v) Show CLI version');
|
|
144
186
|
console.log('');
|
|
145
187
|
console.log('Worktree policy:');
|
|
146
|
-
console.log(' Mutating commands
|
|
147
|
-
console.log('
|
|
188
|
+
console.log(' Mutating commands auto-create and use a linked git worktree when needed.');
|
|
189
|
+
console.log(' Use --allow-main-worktree only if you intentionally want to run in primary.');
|
|
148
190
|
console.log('');
|
|
149
191
|
console.log('AI command (official binary):');
|
|
150
192
|
console.log(' pdd-ai [--provider=openai|claude|openrouter] [--task=analysis|build|test|review] [--model=<id>] "issue"');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { execSync, execFileSync } from 'child_process';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
|
|
4
5
|
function runGit(command, baseDir) {
|
|
@@ -9,7 +10,7 @@ function normalize(p) {
|
|
|
9
10
|
return path.resolve(String(p || '')).toLowerCase();
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
function detectWorktreeContext(baseDir = process.cwd()) {
|
|
13
|
+
export function detectWorktreeContext(baseDir = process.cwd()) {
|
|
13
14
|
try {
|
|
14
15
|
const topLevel = runGit('git rev-parse --show-toplevel', baseDir);
|
|
15
16
|
const gitDir = runGit('git rev-parse --git-dir', baseDir);
|
|
@@ -31,6 +32,45 @@ function detectWorktreeContext(baseDir = process.cwd()) {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
function slug(value) {
|
|
36
|
+
return String(value || '')
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
39
|
+
.replace(/^-+|-+$/g, '')
|
|
40
|
+
.slice(0, 40);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createLinkedWorktree({
|
|
44
|
+
baseDir = process.cwd(),
|
|
45
|
+
commandName = 'change'
|
|
46
|
+
}) {
|
|
47
|
+
const context = detectWorktreeContext(baseDir);
|
|
48
|
+
if (!context.isGitRepo) {
|
|
49
|
+
throw new Error('Current directory is not a git repository.');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const topLevel = context.topLevel;
|
|
53
|
+
const repoName = slug(path.basename(topLevel)) || 'repo';
|
|
54
|
+
const commandSlug = slug(commandName) || 'change';
|
|
55
|
+
const stamp = Date.now();
|
|
56
|
+
const branchName = `feature/pdd-auto-${commandSlug}-${stamp}`;
|
|
57
|
+
|
|
58
|
+
const worktreesRoot = path.join(path.dirname(topLevel), 'pdd-worktrees');
|
|
59
|
+
fs.mkdirSync(worktreesRoot, { recursive: true });
|
|
60
|
+
const worktreePath = path.join(worktreesRoot, `${repoName}-${commandSlug}-${stamp}`);
|
|
61
|
+
|
|
62
|
+
execFileSync(
|
|
63
|
+
'git',
|
|
64
|
+
['worktree', 'add', '-b', branchName, worktreePath, 'HEAD'],
|
|
65
|
+
{ cwd: topLevel, stdio: 'pipe' }
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
worktreePath,
|
|
70
|
+
branchName
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
34
74
|
export function enforceLinkedWorktree({
|
|
35
75
|
baseDir = process.cwd(),
|
|
36
76
|
commandName = 'command',
|