episoda 0.2.59 → 0.2.62
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/daemon/daemon-process.js +35 -2
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +74 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3178,6 +3178,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
3178
3178
|
/**
|
|
3179
3179
|
* Remove a worktree for a module
|
|
3180
3180
|
* P1-2: Wrapped entire operation in lock to prevent race with createWorktree
|
|
3181
|
+
* EP1070: Clean build caches before git worktree remove to prevent orphaned directories
|
|
3181
3182
|
*/
|
|
3182
3183
|
async removeWorktree(moduleUid, force = false) {
|
|
3183
3184
|
if (!validateModuleUid(moduleUid)) {
|
|
@@ -3201,6 +3202,7 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
3201
3202
|
error: `No worktree found for module ${moduleUid}`
|
|
3202
3203
|
};
|
|
3203
3204
|
}
|
|
3205
|
+
await this.cleanBuildCaches(existing.worktreePath);
|
|
3204
3206
|
const result = await this.gitExecutor.execute({
|
|
3205
3207
|
action: "worktree_remove",
|
|
3206
3208
|
path: existing.worktreePath,
|
|
@@ -3425,6 +3427,37 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
3425
3427
|
} catch {
|
|
3426
3428
|
}
|
|
3427
3429
|
}
|
|
3430
|
+
/**
|
|
3431
|
+
* EP1070: Clean build caches before worktree removal
|
|
3432
|
+
*
|
|
3433
|
+
* Removes common build cache directories that can cause:
|
|
3434
|
+
* 1. git worktree remove to fail (locked files on Windows)
|
|
3435
|
+
* 2. Orphaned directories if removal partially fails
|
|
3436
|
+
* 3. Disk space waste from abandoned build artifacts
|
|
3437
|
+
*
|
|
3438
|
+
* @param worktreePath - Absolute path to the worktree directory
|
|
3439
|
+
*/
|
|
3440
|
+
async cleanBuildCaches(worktreePath) {
|
|
3441
|
+
const cacheDirs = [
|
|
3442
|
+
".next",
|
|
3443
|
+
// Next.js build cache
|
|
3444
|
+
"node_modules/.cache",
|
|
3445
|
+
// Various build tool caches (babel, eslint, etc.)
|
|
3446
|
+
".turbo"
|
|
3447
|
+
// Turborepo cache
|
|
3448
|
+
];
|
|
3449
|
+
for (const cacheDir of cacheDirs) {
|
|
3450
|
+
const cachePath = path3.join(worktreePath, cacheDir);
|
|
3451
|
+
try {
|
|
3452
|
+
if (fs2.existsSync(cachePath)) {
|
|
3453
|
+
console.log(`[WorktreeManager] EP1070: Cleaning build cache: ${cacheDir}`);
|
|
3454
|
+
fs2.rmSync(cachePath, { recursive: true, force: true });
|
|
3455
|
+
}
|
|
3456
|
+
} catch (error) {
|
|
3457
|
+
console.warn(`[WorktreeManager] EP1070: Failed to clean ${cacheDir} (non-blocking):`, error.message);
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3428
3461
|
readConfig() {
|
|
3429
3462
|
try {
|
|
3430
3463
|
if (!fs2.existsSync(this.configPath)) {
|
|
@@ -5367,6 +5400,13 @@ async function setupWorktreeEnv(worktreePath, apiUrl, accessToken) {
|
|
|
5367
5400
|
}
|
|
5368
5401
|
|
|
5369
5402
|
// src/commands/checkout.ts
|
|
5403
|
+
function generateBranchName(moduleUid, title) {
|
|
5404
|
+
if (!title) {
|
|
5405
|
+
return moduleUid || "unnamed";
|
|
5406
|
+
}
|
|
5407
|
+
const slug = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 50);
|
|
5408
|
+
return `${moduleUid}-${slug}`;
|
|
5409
|
+
}
|
|
5370
5410
|
async function checkoutCommand(moduleUid, options = {}) {
|
|
5371
5411
|
if (!moduleUid || !moduleUid.match(/^EP\d+$/)) {
|
|
5372
5412
|
throw new Error(
|
|
@@ -5417,7 +5457,7 @@ The .bare directory or .episoda/config.json may be missing.`
|
|
|
5417
5457
|
moduleUid,
|
|
5418
5458
|
config.access_token
|
|
5419
5459
|
);
|
|
5420
|
-
const branchName = moduleDetails.branch_name ||
|
|
5460
|
+
const branchName = moduleDetails.branch_name || generateBranchName(moduleUid, moduleDetails.name);
|
|
5421
5461
|
let createBranch = !moduleDetails.branch_name || options.create;
|
|
5422
5462
|
if (createBranch && !moduleDetails.branch_name) {
|
|
5423
5463
|
const { GitExecutor: GitExecutor4 } = await Promise.resolve().then(() => __toESM(require_dist()));
|
|
@@ -5732,11 +5772,12 @@ async function listWorktrees(options) {
|
|
|
5732
5772
|
throw new Error(`Invalid worktree project at ${projectRoot}`);
|
|
5733
5773
|
}
|
|
5734
5774
|
const config = manager.getConfig();
|
|
5735
|
-
const
|
|
5775
|
+
const { valid, stale, orphaned } = await manager.validateWorktrees();
|
|
5736
5776
|
console.log("");
|
|
5737
5777
|
console.log(import_chalk2.default.bold(`Worktrees for ${config?.workspaceSlug}/${config?.projectSlug}`));
|
|
5738
5778
|
console.log("\u2500".repeat(60));
|
|
5739
|
-
|
|
5779
|
+
const hasAnyWorktrees = valid.length > 0 || stale.length > 0 || orphaned.length > 0;
|
|
5780
|
+
if (!hasAnyWorktrees) {
|
|
5740
5781
|
console.log("");
|
|
5741
5782
|
console.log(import_chalk2.default.gray(" No worktrees checked out"));
|
|
5742
5783
|
console.log("");
|
|
@@ -5745,7 +5786,7 @@ async function listWorktrees(options) {
|
|
|
5745
5786
|
return;
|
|
5746
5787
|
}
|
|
5747
5788
|
const gitExecutor = new import_core13.GitExecutor();
|
|
5748
|
-
for (const wt of
|
|
5789
|
+
for (const wt of valid) {
|
|
5749
5790
|
console.log("");
|
|
5750
5791
|
let statusIndicator = import_chalk2.default.green("\u25CF");
|
|
5751
5792
|
let statusNote = "";
|
|
@@ -5772,11 +5813,38 @@ async function listWorktrees(options) {
|
|
|
5772
5813
|
console.log(import_chalk2.default.gray(` Last accessed: ${new Date(wt.lastAccessed).toLocaleDateString()}`));
|
|
5773
5814
|
}
|
|
5774
5815
|
}
|
|
5816
|
+
if (stale.length > 0) {
|
|
5817
|
+
console.log("");
|
|
5818
|
+
console.log(import_chalk2.default.yellow(" Stale entries (in config but removed from git):"));
|
|
5819
|
+
for (const wt of stale) {
|
|
5820
|
+
console.log(import_chalk2.default.yellow(` \u26A0 ${wt.moduleUid} - ${wt.worktreePath}`));
|
|
5821
|
+
}
|
|
5822
|
+
console.log(import_chalk2.default.gray(" These will be cleaned up automatically on next daemon restart"));
|
|
5823
|
+
}
|
|
5824
|
+
if (orphaned.length > 0) {
|
|
5825
|
+
console.log("");
|
|
5826
|
+
console.log(import_chalk2.default.red(" Orphaned worktrees (in git but not in config):"));
|
|
5827
|
+
for (const wtPath of orphaned) {
|
|
5828
|
+
const moduleUid = path13.basename(wtPath);
|
|
5829
|
+
console.log(import_chalk2.default.red(` \u2717 ${moduleUid} - ${wtPath}`));
|
|
5830
|
+
}
|
|
5831
|
+
console.log(import_chalk2.default.gray(" These may be from crashed sessions. Run `episoda release <uid>` to clean up"));
|
|
5832
|
+
}
|
|
5775
5833
|
console.log("");
|
|
5776
5834
|
console.log(import_chalk2.default.gray("\u2500".repeat(60)));
|
|
5777
|
-
|
|
5835
|
+
const parts = [];
|
|
5836
|
+
if (valid.length > 0) {
|
|
5837
|
+
parts.push(`${valid.length} active`);
|
|
5838
|
+
}
|
|
5839
|
+
if (stale.length > 0) {
|
|
5840
|
+
parts.push(import_chalk2.default.yellow(`${stale.length} stale`));
|
|
5841
|
+
}
|
|
5842
|
+
if (orphaned.length > 0) {
|
|
5843
|
+
parts.push(import_chalk2.default.red(`${orphaned.length} orphaned`));
|
|
5844
|
+
}
|
|
5845
|
+
console.log(parts.join(", "));
|
|
5778
5846
|
console.log("");
|
|
5779
|
-
console.log(import_chalk2.default.gray("\u25CF clean ") + import_chalk2.default.yellow("\u25CF uncommitted
|
|
5847
|
+
console.log(import_chalk2.default.gray("\u25CF clean ") + import_chalk2.default.yellow("\u25CF uncommitted ") + import_chalk2.default.red("\u2717 orphaned"));
|
|
5780
5848
|
console.log("");
|
|
5781
5849
|
}
|
|
5782
5850
|
|