gsd-pi 2.33.1-dev.9bafd68 → 2.33.1-dev.b1c6556
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/resource-loader.js +3 -1
- package/dist/resources/extensions/gsd/auto-start.js +300 -288
- package/dist/resources/extensions/gsd/auto-worktree.js +71 -0
- package/dist/resources/extensions/gsd/auto.js +11 -1
- package/dist/resources/extensions/gsd/session-lock.js +13 -0
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +5498 -3645
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +2595 -742
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/src/models.generated.ts +2852 -999
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +9 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +9 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +32 -2
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/src/utils.ts +28 -2
- package/src/resources/extensions/gsd/auto-start.ts +22 -10
- package/src/resources/extensions/gsd/auto-worktree.ts +71 -0
- package/src/resources/extensions/gsd/auto.ts +11 -0
- package/src/resources/extensions/gsd/session-lock.ts +11 -0
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
|
@@ -140,6 +140,77 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
140
140
|
}
|
|
141
141
|
return { synced };
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Sync milestone artifacts from worktree back to the main external state directory.
|
|
145
|
+
* Called before milestone merge to ensure completion artifacts (SUMMARY, VALIDATION,
|
|
146
|
+
* updated ROADMAP) are visible from the project root (#1412).
|
|
147
|
+
*
|
|
148
|
+
* Only syncs .gsd/milestones/ content — root-level files (DECISIONS, REQUIREMENTS, etc.)
|
|
149
|
+
* are handled by the merge itself.
|
|
150
|
+
*/
|
|
151
|
+
export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
152
|
+
const mainGsd = gsdRoot(mainBasePath);
|
|
153
|
+
const wtGsd = gsdRoot(worktreePath);
|
|
154
|
+
const synced = [];
|
|
155
|
+
// If both resolve to the same directory (symlink), no sync needed
|
|
156
|
+
try {
|
|
157
|
+
const mainResolved = realpathSync(mainGsd);
|
|
158
|
+
const wtResolved = realpathSync(wtGsd);
|
|
159
|
+
if (mainResolved === wtResolved)
|
|
160
|
+
return { synced };
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// Can't resolve — proceed with sync
|
|
164
|
+
}
|
|
165
|
+
const wtMilestoneDir = join(wtGsd, "milestones", milestoneId);
|
|
166
|
+
const mainMilestoneDir = join(mainGsd, "milestones", milestoneId);
|
|
167
|
+
if (!existsSync(wtMilestoneDir))
|
|
168
|
+
return { synced };
|
|
169
|
+
mkdirSync(mainMilestoneDir, { recursive: true });
|
|
170
|
+
// Sync milestone-level files (SUMMARY, VALIDATION, ROADMAP, CONTEXT)
|
|
171
|
+
try {
|
|
172
|
+
for (const entry of readdirSync(wtMilestoneDir, { withFileTypes: true })) {
|
|
173
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
174
|
+
const src = join(wtMilestoneDir, entry.name);
|
|
175
|
+
const dst = join(mainMilestoneDir, entry.name);
|
|
176
|
+
try {
|
|
177
|
+
cpSync(src, dst, { force: true });
|
|
178
|
+
synced.push(`milestones/${milestoneId}/${entry.name}`);
|
|
179
|
+
}
|
|
180
|
+
catch { /* non-fatal */ }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch { /* non-fatal */ }
|
|
185
|
+
// Sync slice-level files (summaries, UATs)
|
|
186
|
+
const wtSlicesDir = join(wtMilestoneDir, "slices");
|
|
187
|
+
const mainSlicesDir = join(mainMilestoneDir, "slices");
|
|
188
|
+
if (existsSync(wtSlicesDir)) {
|
|
189
|
+
try {
|
|
190
|
+
for (const sliceEntry of readdirSync(wtSlicesDir, { withFileTypes: true })) {
|
|
191
|
+
if (!sliceEntry.isDirectory())
|
|
192
|
+
continue;
|
|
193
|
+
const sid = sliceEntry.name;
|
|
194
|
+
const wtSliceDir = join(wtSlicesDir, sid);
|
|
195
|
+
const mainSliceDir = join(mainSlicesDir, sid);
|
|
196
|
+
mkdirSync(mainSliceDir, { recursive: true });
|
|
197
|
+
for (const fileEntry of readdirSync(wtSliceDir, { withFileTypes: true })) {
|
|
198
|
+
if (fileEntry.isFile() && fileEntry.name.endsWith(".md")) {
|
|
199
|
+
const src = join(wtSliceDir, fileEntry.name);
|
|
200
|
+
const dst = join(mainSliceDir, fileEntry.name);
|
|
201
|
+
try {
|
|
202
|
+
cpSync(src, dst, { force: true });
|
|
203
|
+
synced.push(`milestones/${milestoneId}/slices/${sid}/${fileEntry.name}`);
|
|
204
|
+
}
|
|
205
|
+
catch { /* non-fatal */ }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch { /* non-fatal */ }
|
|
211
|
+
}
|
|
212
|
+
return { synced };
|
|
213
|
+
}
|
|
143
214
|
// ─── Worktree Post-Create Hook (#597) ────────────────────────────────────────
|
|
144
215
|
/**
|
|
145
216
|
* Run the user-configured post-create hook script after worktree creation.
|
|
@@ -41,7 +41,7 @@ import { atomicWriteSync } from "./atomic-write.js";
|
|
|
41
41
|
import { autoCommitCurrentBranch, captureIntegrationBranch, detectWorktreeName, getCurrentBranch, getMainBranch, setActiveMilestoneId, } from "./worktree.js";
|
|
42
42
|
import { createGitService } from "./git-service.js";
|
|
43
43
|
import { getPriorSliceCompletionBlocker } from "./dispatch-guard.js";
|
|
44
|
-
import { createAutoWorktree, enterAutoWorktree, teardownAutoWorktree, isInAutoWorktree, getAutoWorktreePath, mergeMilestoneToMain, autoWorktreeBranch, } from "./auto-worktree.js";
|
|
44
|
+
import { createAutoWorktree, enterAutoWorktree, teardownAutoWorktree, isInAutoWorktree, getAutoWorktreePath, mergeMilestoneToMain, autoWorktreeBranch, syncWorktreeStateBack, } from "./auto-worktree.js";
|
|
45
45
|
import { pruneQueueOrder } from "./queue-order.js";
|
|
46
46
|
import { showNextAction } from "../shared/mod.js";
|
|
47
47
|
import { debugLog, debugTime, isDebugEnabled, writeDebugSummary } from "./debug-logger.js";
|
|
@@ -228,6 +228,16 @@ function tryMergeMilestone(ctx, milestoneId, mode) {
|
|
|
228
228
|
// Worktree merge path
|
|
229
229
|
if (isInAutoWorktree(s.basePath) && s.originalBasePath) {
|
|
230
230
|
try {
|
|
231
|
+
// Sync completion artifacts from worktree → external state before merge (#1412)
|
|
232
|
+
try {
|
|
233
|
+
const { synced } = syncWorktreeStateBack(s.originalBasePath, s.basePath, milestoneId);
|
|
234
|
+
if (synced.length > 0) {
|
|
235
|
+
debugLog("worktree-reverse-sync", { milestoneId, synced: synced.length });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch (syncErr) {
|
|
239
|
+
debugLog("worktree-reverse-sync-failed", { milestoneId, error: getErrorMessage(syncErr) });
|
|
240
|
+
}
|
|
231
241
|
const roadmapPath = resolveMilestoneFile(s.originalBasePath, milestoneId, "ROADMAP");
|
|
232
242
|
if (!roadmapPath) {
|
|
233
243
|
teardownAutoWorktree(s.originalBasePath, milestoneId);
|
|
@@ -129,6 +129,18 @@ function ensureExitHandler(gsdDir) {
|
|
|
129
129
|
*/
|
|
130
130
|
export function acquireSessionLock(basePath) {
|
|
131
131
|
const lp = lockPath(basePath);
|
|
132
|
+
// Re-entrant acquire on the same path: release our current OS lock first so
|
|
133
|
+
// proper-lockfile clears its update timer before we acquire a fresh lock.
|
|
134
|
+
if (_releaseFunction && _lockedPath === basePath) {
|
|
135
|
+
try {
|
|
136
|
+
_releaseFunction();
|
|
137
|
+
}
|
|
138
|
+
catch { /* may already be released */ }
|
|
139
|
+
_releaseFunction = null;
|
|
140
|
+
_lockedPath = null;
|
|
141
|
+
_lockPid = 0;
|
|
142
|
+
_lockCompromised = false;
|
|
143
|
+
}
|
|
132
144
|
// Ensure the directory exists
|
|
133
145
|
mkdirSync(dirname(lp), { recursive: true });
|
|
134
146
|
// Clean up numbered lock file variants from cloud sync conflicts (#1315)
|
|
@@ -206,6 +218,7 @@ export function acquireSessionLock(basePath) {
|
|
|
206
218
|
_releaseFunction = release;
|
|
207
219
|
_lockedPath = basePath;
|
|
208
220
|
_lockPid = process.pid;
|
|
221
|
+
_lockCompromised = false;
|
|
209
222
|
// Safety net — uses centralized handler to avoid double-registration
|
|
210
223
|
ensureExitHandler(gsdDir);
|
|
211
224
|
atomicWriteSync(lp, JSON.stringify(lockData, null, 2));
|