@episoda/cli 0.2.157 → 0.2.159
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 +248 -93
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +179 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1653,10 +1653,6 @@ var require_git_executor = __commonJS({
|
|
|
1653
1653
|
};
|
|
1654
1654
|
} catch {
|
|
1655
1655
|
}
|
|
1656
|
-
try {
|
|
1657
|
-
await this.runGitCommand(["fetch", "--all", "--prune"], cwd, options);
|
|
1658
|
-
} catch {
|
|
1659
|
-
}
|
|
1660
1656
|
const args = ["worktree", "add"];
|
|
1661
1657
|
if (command.detach) {
|
|
1662
1658
|
args.push("--detach", command.path);
|
|
@@ -2913,7 +2909,7 @@ var require_package = __commonJS({
|
|
|
2913
2909
|
"package.json"(exports2, module2) {
|
|
2914
2910
|
module2.exports = {
|
|
2915
2911
|
name: "@episoda/cli",
|
|
2916
|
-
version: "0.2.
|
|
2912
|
+
version: "0.2.159",
|
|
2917
2913
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2918
2914
|
main: "dist/index.js",
|
|
2919
2915
|
types: "dist/index.d.ts",
|
|
@@ -4936,6 +4932,8 @@ var ClaudePersistentRuntime = class {
|
|
|
4936
4932
|
this.maxStderrTailBytes = 8192;
|
|
4937
4933
|
// Stdout JSONL parsing state
|
|
4938
4934
|
this.stdoutBuffer = "";
|
|
4935
|
+
this.stdoutLineQueue = [];
|
|
4936
|
+
this.drainingStdoutQueue = false;
|
|
4939
4937
|
this.parsedLineCount = 0;
|
|
4940
4938
|
this.chunksSent = 0;
|
|
4941
4939
|
this.hasContent = false;
|
|
@@ -4998,21 +4996,9 @@ var ClaudePersistentRuntime = class {
|
|
|
4998
4996
|
this.stdoutBuffer += data.toString();
|
|
4999
4997
|
const lines = this.stdoutBuffer.split("\n");
|
|
5000
4998
|
this.stdoutBuffer = lines.pop() || "";
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
const parsed = JSON.parse(line);
|
|
5005
|
-
this.parsedLineCount++;
|
|
5006
|
-
if (this.parsedLineCount === 1) {
|
|
5007
|
-
const ttftMs = Date.now() - this.spawnTimestamp;
|
|
5008
|
-
console.log(`[ClaudePersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
|
|
5009
|
-
}
|
|
5010
|
-
this.handleParsedEvent(parsed);
|
|
5011
|
-
} catch {
|
|
5012
|
-
if (line.trim() && this.callbacks) {
|
|
5013
|
-
this.callbacks.onChunk(line + "\n");
|
|
5014
|
-
}
|
|
5015
|
-
}
|
|
4999
|
+
if (lines.length > 0) {
|
|
5000
|
+
this.stdoutLineQueue.push(...lines);
|
|
5001
|
+
this.drainStdoutQueue();
|
|
5016
5002
|
}
|
|
5017
5003
|
});
|
|
5018
5004
|
this.process.on("exit", (code, signal) => {
|
|
@@ -5118,6 +5104,41 @@ var ClaudePersistentRuntime = class {
|
|
|
5118
5104
|
// -------------------------------------------------------------------------
|
|
5119
5105
|
// Event handling
|
|
5120
5106
|
// -------------------------------------------------------------------------
|
|
5107
|
+
drainStdoutQueue() {
|
|
5108
|
+
if (this.drainingStdoutQueue) return;
|
|
5109
|
+
this.drainingStdoutQueue = true;
|
|
5110
|
+
const BATCH_SIZE = 5;
|
|
5111
|
+
const processBatch = () => {
|
|
5112
|
+
let processed = 0;
|
|
5113
|
+
while (processed < BATCH_SIZE && this.stdoutLineQueue.length > 0) {
|
|
5114
|
+
const line = this.stdoutLineQueue.shift();
|
|
5115
|
+
processed++;
|
|
5116
|
+
if (!line.trim()) continue;
|
|
5117
|
+
try {
|
|
5118
|
+
const parsed = JSON.parse(line);
|
|
5119
|
+
this.parsedLineCount++;
|
|
5120
|
+
if (this.parsedLineCount === 1) {
|
|
5121
|
+
const ttftMs = Date.now() - this.spawnTimestamp;
|
|
5122
|
+
console.log(`[ClaudePersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
|
|
5123
|
+
}
|
|
5124
|
+
this.handleParsedEvent(parsed);
|
|
5125
|
+
} catch {
|
|
5126
|
+
if (line.trim() && this.callbacks) {
|
|
5127
|
+
this.callbacks.onChunk(line + "\n");
|
|
5128
|
+
}
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
if (this.stdoutLineQueue.length > 0) {
|
|
5132
|
+
setImmediate(processBatch);
|
|
5133
|
+
return;
|
|
5134
|
+
}
|
|
5135
|
+
this.drainingStdoutQueue = false;
|
|
5136
|
+
if (this.stdoutLineQueue.length > 0) {
|
|
5137
|
+
this.drainStdoutQueue();
|
|
5138
|
+
}
|
|
5139
|
+
};
|
|
5140
|
+
processBatch();
|
|
5141
|
+
}
|
|
5121
5142
|
handleParsedEvent(parsed) {
|
|
5122
5143
|
const type = parsed.type;
|
|
5123
5144
|
if (this._turnState === "waiting_for_echo") {
|
|
@@ -5429,6 +5450,8 @@ var CodexPersistentRuntime = class {
|
|
|
5429
5450
|
this.stderrTail = "";
|
|
5430
5451
|
this.maxStderrTailBytes = 8192;
|
|
5431
5452
|
this.stdoutBuffer = "";
|
|
5453
|
+
this.stdoutLineQueue = [];
|
|
5454
|
+
this.drainingStdoutQueue = false;
|
|
5432
5455
|
this.parsedLineCount = 0;
|
|
5433
5456
|
// Per-turn accounting
|
|
5434
5457
|
this.turnStartTime = 0;
|
|
@@ -5483,21 +5506,9 @@ var CodexPersistentRuntime = class {
|
|
|
5483
5506
|
this.stdoutBuffer += data.toString();
|
|
5484
5507
|
const lines = this.stdoutBuffer.split("\n");
|
|
5485
5508
|
this.stdoutBuffer = lines.pop() || "";
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
const parsed = JSON.parse(line);
|
|
5490
|
-
this.parsedLineCount++;
|
|
5491
|
-
if (this.parsedLineCount === 1) {
|
|
5492
|
-
const ttftMs = Date.now() - this.spawnTimestamp;
|
|
5493
|
-
console.log(`[CodexPersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
|
|
5494
|
-
}
|
|
5495
|
-
this.handleJsonRpcMessage(parsed);
|
|
5496
|
-
} catch {
|
|
5497
|
-
if (line.trim() && this.callbacks) {
|
|
5498
|
-
this.callbacks.onChunk(line + "\n");
|
|
5499
|
-
}
|
|
5500
|
-
}
|
|
5509
|
+
if (lines.length > 0) {
|
|
5510
|
+
this.stdoutLineQueue.push(...lines);
|
|
5511
|
+
this.drainStdoutQueue();
|
|
5501
5512
|
}
|
|
5502
5513
|
});
|
|
5503
5514
|
this.process.on("exit", (code, signal) => {
|
|
@@ -5608,6 +5619,41 @@ var CodexPersistentRuntime = class {
|
|
|
5608
5619
|
// -------------------------------------------------------------------------
|
|
5609
5620
|
// JSON-RPC plumbing
|
|
5610
5621
|
// -------------------------------------------------------------------------
|
|
5622
|
+
drainStdoutQueue() {
|
|
5623
|
+
if (this.drainingStdoutQueue) return;
|
|
5624
|
+
this.drainingStdoutQueue = true;
|
|
5625
|
+
const BATCH_SIZE = 5;
|
|
5626
|
+
const processBatch = () => {
|
|
5627
|
+
let processed = 0;
|
|
5628
|
+
while (processed < BATCH_SIZE && this.stdoutLineQueue.length > 0) {
|
|
5629
|
+
const line = this.stdoutLineQueue.shift();
|
|
5630
|
+
processed++;
|
|
5631
|
+
if (!line.trim()) continue;
|
|
5632
|
+
try {
|
|
5633
|
+
const parsed = JSON.parse(line);
|
|
5634
|
+
this.parsedLineCount++;
|
|
5635
|
+
if (this.parsedLineCount === 1) {
|
|
5636
|
+
const ttftMs = Date.now() - this.spawnTimestamp;
|
|
5637
|
+
console.log(`[CodexPersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
|
|
5638
|
+
}
|
|
5639
|
+
this.handleJsonRpcMessage(parsed);
|
|
5640
|
+
} catch {
|
|
5641
|
+
if (line.trim() && this.callbacks) {
|
|
5642
|
+
this.callbacks.onChunk(line + "\n");
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
if (this.stdoutLineQueue.length > 0) {
|
|
5647
|
+
setImmediate(processBatch);
|
|
5648
|
+
return;
|
|
5649
|
+
}
|
|
5650
|
+
this.drainingStdoutQueue = false;
|
|
5651
|
+
if (this.stdoutLineQueue.length > 0) {
|
|
5652
|
+
this.drainStdoutQueue();
|
|
5653
|
+
}
|
|
5654
|
+
};
|
|
5655
|
+
processBatch();
|
|
5656
|
+
}
|
|
5611
5657
|
handleJsonRpcMessage(msg) {
|
|
5612
5658
|
if (RUNTIME_DEBUG2 && this.debugTraceCount < 20) {
|
|
5613
5659
|
this.debugTraceCount++;
|
|
@@ -8109,6 +8155,7 @@ var AgentCommandQueue = class {
|
|
|
8109
8155
|
// src/daemon/worktree-manager.ts
|
|
8110
8156
|
var fs11 = __toESM(require("fs"));
|
|
8111
8157
|
var path12 = __toESM(require("path"));
|
|
8158
|
+
var import_child_process11 = require("child_process");
|
|
8112
8159
|
var import_core10 = __toESM(require_dist());
|
|
8113
8160
|
function validateModuleUid(moduleUid) {
|
|
8114
8161
|
if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
|
|
@@ -8125,6 +8172,38 @@ function validateModuleUid(moduleUid) {
|
|
|
8125
8172
|
}
|
|
8126
8173
|
return true;
|
|
8127
8174
|
}
|
|
8175
|
+
function isValidDefaultBranchName(name) {
|
|
8176
|
+
if (!name || typeof name !== "string") return false;
|
|
8177
|
+
const trimmed = name.trim();
|
|
8178
|
+
if (trimmed !== name) return false;
|
|
8179
|
+
if (name.length > 255) return false;
|
|
8180
|
+
if (name.startsWith("-")) return false;
|
|
8181
|
+
if (name.startsWith("/")) return false;
|
|
8182
|
+
if (name.endsWith("/")) return false;
|
|
8183
|
+
if (name.endsWith(".")) return false;
|
|
8184
|
+
if (name.endsWith(".lock")) return false;
|
|
8185
|
+
if (name.includes("..")) return false;
|
|
8186
|
+
if (name.includes("@{")) return false;
|
|
8187
|
+
if (name.includes("//")) return false;
|
|
8188
|
+
if (name.includes("\\")) return false;
|
|
8189
|
+
if (/[ ~^:?*\[\]\s]/.test(name)) return false;
|
|
8190
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(name)) return false;
|
|
8191
|
+
return true;
|
|
8192
|
+
}
|
|
8193
|
+
function runGit(args, cwd, timeoutMs) {
|
|
8194
|
+
const res = (0, import_child_process11.spawnSync)("git", args, {
|
|
8195
|
+
cwd,
|
|
8196
|
+
encoding: "utf-8",
|
|
8197
|
+
timeout: timeoutMs,
|
|
8198
|
+
windowsHide: true,
|
|
8199
|
+
shell: false
|
|
8200
|
+
});
|
|
8201
|
+
return {
|
|
8202
|
+
success: res.status === 0,
|
|
8203
|
+
stdout: (res.stdout || "").toString(),
|
|
8204
|
+
stderr: (res.stderr || "").toString()
|
|
8205
|
+
};
|
|
8206
|
+
}
|
|
8128
8207
|
var WorktreeManager = class _WorktreeManager {
|
|
8129
8208
|
constructor(projectRoot) {
|
|
8130
8209
|
// ============================================================
|
|
@@ -8182,22 +8261,24 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
8182
8261
|
*/
|
|
8183
8262
|
async ensureFetchRefspecConfigured() {
|
|
8184
8263
|
try {
|
|
8185
|
-
const { execSync: execSync10 } = require("child_process");
|
|
8186
8264
|
let fetchRefspec = null;
|
|
8187
8265
|
try {
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
}).trim();
|
|
8266
|
+
const res = runGit(["config", "--get", "remote.origin.fetch"], this.bareRepoPath, 5e3);
|
|
8267
|
+
if (res.success) {
|
|
8268
|
+
fetchRefspec = res.stdout.trim();
|
|
8269
|
+
}
|
|
8193
8270
|
} catch {
|
|
8194
8271
|
}
|
|
8195
8272
|
if (!fetchRefspec) {
|
|
8196
8273
|
console.log("[WorktreeManager] EP1014: Configuring missing fetch refspec for bare repo");
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8274
|
+
const setRes = runGit(
|
|
8275
|
+
["config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"],
|
|
8276
|
+
this.bareRepoPath,
|
|
8277
|
+
5e3
|
|
8278
|
+
);
|
|
8279
|
+
if (!setRes.success) {
|
|
8280
|
+
throw new Error(setRes.stderr || "Failed to configure fetch refspec");
|
|
8281
|
+
}
|
|
8201
8282
|
console.log("[WorktreeManager] EP1014: Fetch refspec configured successfully");
|
|
8202
8283
|
}
|
|
8203
8284
|
} catch (error) {
|
|
@@ -8230,11 +8311,44 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
8230
8311
|
manager.writeConfig(config);
|
|
8231
8312
|
return manager;
|
|
8232
8313
|
}
|
|
8314
|
+
/**
|
|
8315
|
+
* EP1373: Resolve the default branch name using a 3-level fallback:
|
|
8316
|
+
* 1. Explicit defaultBranch parameter (from project GitHub config)
|
|
8317
|
+
* 2. Git-derived: refs/remotes/origin/HEAD symbolic-ref target
|
|
8318
|
+
* 3. Final fallback: 'main' (with warning)
|
|
8319
|
+
*/
|
|
8320
|
+
async resolveDefaultBranch(explicitDefault) {
|
|
8321
|
+
if (explicitDefault) {
|
|
8322
|
+
if (isValidDefaultBranchName(explicitDefault)) {
|
|
8323
|
+
return explicitDefault;
|
|
8324
|
+
}
|
|
8325
|
+
console.warn(`[WorktreeManager] EP1373: Invalid defaultBranch provided ("${explicitDefault}"), ignoring`);
|
|
8326
|
+
}
|
|
8327
|
+
try {
|
|
8328
|
+
const res = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], this.bareRepoPath, 5e3);
|
|
8329
|
+
if (!res.success) {
|
|
8330
|
+
throw new Error(res.stderr || "symbolic-ref failed");
|
|
8331
|
+
}
|
|
8332
|
+
const symref = res.stdout.trim();
|
|
8333
|
+
const match = symref.match(/^refs\/remotes\/origin\/(.+)$/);
|
|
8334
|
+
if (match && match[1]) {
|
|
8335
|
+
const derived = match[1];
|
|
8336
|
+
if (isValidDefaultBranchName(derived)) {
|
|
8337
|
+
return derived;
|
|
8338
|
+
}
|
|
8339
|
+
console.warn(`[WorktreeManager] EP1373: Derived default branch from origin/HEAD is invalid ("${derived}"), ignoring`);
|
|
8340
|
+
}
|
|
8341
|
+
} catch {
|
|
8342
|
+
}
|
|
8343
|
+
console.warn('[WorktreeManager] EP1373: Could not resolve default branch, falling back to "main"');
|
|
8344
|
+
return "main";
|
|
8345
|
+
}
|
|
8233
8346
|
/**
|
|
8234
8347
|
* Create a worktree for a module
|
|
8235
8348
|
* The entire operation is locked to prevent race conditions
|
|
8349
|
+
* EP1373: Added defaultBranch parameter for explicit default branch resolution
|
|
8236
8350
|
*/
|
|
8237
|
-
async createWorktree(moduleUid, branchName, createBranch = false) {
|
|
8351
|
+
async createWorktree(moduleUid, branchName, createBranch = false, defaultBranch, correlationId) {
|
|
8238
8352
|
if (!validateModuleUid(moduleUid)) {
|
|
8239
8353
|
return {
|
|
8240
8354
|
success: false,
|
|
@@ -8300,25 +8414,63 @@ var WorktreeManager = class _WorktreeManager {
|
|
|
8300
8414
|
console.warn("[WorktreeManager] EP1265: Failed to prune worktrees (continuing):", pruneResult.output);
|
|
8301
8415
|
}
|
|
8302
8416
|
}
|
|
8303
|
-
const
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
};
|
|
8417
|
+
const resolvedDefault = await this.resolveDefaultBranch(defaultBranch);
|
|
8418
|
+
let shouldCreateBranch = createBranch;
|
|
8419
|
+
let startPoint;
|
|
8420
|
+
if (createBranch) {
|
|
8421
|
+
const managerFetchStartMs = Date.now();
|
|
8422
|
+
const fetchResult = await this.gitExecutor.execute({
|
|
8423
|
+
action: "fetch",
|
|
8424
|
+
remote: "origin",
|
|
8425
|
+
branch: `+refs/heads/${resolvedDefault}:refs/remotes/origin/${resolvedDefault}`
|
|
8426
|
+
}, { cwd: this.bareRepoPath });
|
|
8427
|
+
console.log(`[WorktreeManager] EP1373: manager_fetch phase=manager_fetch durationMs=${Date.now() - managerFetchStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} defaultBranch=${resolvedDefault} success=${fetchResult.success}`);
|
|
8428
|
+
if (!fetchResult.success) {
|
|
8429
|
+
console.error("[worktree-manager] Failed to fetch from origin:", fetchResult.output);
|
|
8430
|
+
return {
|
|
8431
|
+
success: false,
|
|
8432
|
+
error: "Failed to fetch latest refs from origin. Cannot create worktree with stale refs."
|
|
8433
|
+
};
|
|
8434
|
+
}
|
|
8435
|
+
startPoint = `origin/${resolvedDefault}`;
|
|
8436
|
+
} else {
|
|
8437
|
+
const existingBranchFetchStartMs = Date.now();
|
|
8438
|
+
const branchFetchResult = await this.gitExecutor.execute({
|
|
8439
|
+
action: "fetch",
|
|
8440
|
+
remote: "origin",
|
|
8441
|
+
branch: `+refs/heads/${branchName}:refs/remotes/origin/${branchName}`
|
|
8442
|
+
}, { cwd: this.bareRepoPath });
|
|
8443
|
+
console.log(`[WorktreeManager] EP1373: existing_branch_fetch phase=existing_branch_fetch durationMs=${Date.now() - existingBranchFetchStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} branch=${branchName} success=${branchFetchResult.success}`);
|
|
8444
|
+
const localBranchExists = runGit(
|
|
8445
|
+
["show-ref", "--verify", `refs/heads/${branchName}`],
|
|
8446
|
+
this.bareRepoPath,
|
|
8447
|
+
5e3
|
|
8448
|
+
).success;
|
|
8449
|
+
const remoteBranchExists = runGit(
|
|
8450
|
+
["show-ref", "--verify", `refs/remotes/origin/${branchName}`],
|
|
8451
|
+
this.bareRepoPath,
|
|
8452
|
+
5e3
|
|
8453
|
+
).success;
|
|
8454
|
+
if (!localBranchExists && remoteBranchExists) {
|
|
8455
|
+
shouldCreateBranch = true;
|
|
8456
|
+
startPoint = `origin/${branchName}`;
|
|
8457
|
+
console.log(`[WorktreeManager] EP1373: remote_only_branch phase=remote_only_branch moduleUid=${moduleUid} correlationId=${correlationId || "none"} branch=${branchName}`);
|
|
8458
|
+
} else if (!localBranchExists && !remoteBranchExists) {
|
|
8459
|
+
return {
|
|
8460
|
+
success: false,
|
|
8461
|
+
error: `Branch "${branchName}" not found locally or on origin`
|
|
8462
|
+
};
|
|
8463
|
+
}
|
|
8314
8464
|
}
|
|
8465
|
+
const gitWorktreeAddStartMs = Date.now();
|
|
8315
8466
|
const result = await this.gitExecutor.execute({
|
|
8316
8467
|
action: "worktree_add",
|
|
8317
8468
|
path: worktreePath,
|
|
8318
8469
|
branch: branchName,
|
|
8319
|
-
create:
|
|
8320
|
-
startPoint
|
|
8470
|
+
create: shouldCreateBranch,
|
|
8471
|
+
startPoint
|
|
8321
8472
|
}, { cwd: this.bareRepoPath });
|
|
8473
|
+
console.log(`[WorktreeManager] EP1373: git_worktree_add phase=git_worktree_add durationMs=${Date.now() - gitWorktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${result.success}`);
|
|
8322
8474
|
if (!result.success) {
|
|
8323
8475
|
return {
|
|
8324
8476
|
success: false,
|
|
@@ -9959,7 +10111,7 @@ async function handleFileMkdir(command, projectPath) {
|
|
|
9959
10111
|
}
|
|
9960
10112
|
|
|
9961
10113
|
// src/daemon/handlers/exec-handler.ts
|
|
9962
|
-
var
|
|
10114
|
+
var import_child_process12 = require("child_process");
|
|
9963
10115
|
var DEFAULT_TIMEOUT = 3e4;
|
|
9964
10116
|
var MAX_TIMEOUT = 3e5;
|
|
9965
10117
|
async function handleExec(command, projectPath) {
|
|
@@ -9981,7 +10133,7 @@ async function handleExec(command, projectPath) {
|
|
|
9981
10133
|
resolve4(result);
|
|
9982
10134
|
};
|
|
9983
10135
|
try {
|
|
9984
|
-
const proc = (0,
|
|
10136
|
+
const proc = (0, import_child_process12.spawn)(cmd, {
|
|
9985
10137
|
shell: true,
|
|
9986
10138
|
cwd,
|
|
9987
10139
|
env: { ...process.env, ...env },
|
|
@@ -10045,7 +10197,7 @@ async function handleExec(command, projectPath) {
|
|
|
10045
10197
|
var path23 = __toESM(require("path"));
|
|
10046
10198
|
var fs22 = __toESM(require("fs"));
|
|
10047
10199
|
var os10 = __toESM(require("os"));
|
|
10048
|
-
var
|
|
10200
|
+
var import_child_process15 = require("child_process");
|
|
10049
10201
|
var import_util2 = require("util");
|
|
10050
10202
|
|
|
10051
10203
|
// src/preview/types.ts
|
|
@@ -10072,7 +10224,7 @@ var import_events3 = require("events");
|
|
|
10072
10224
|
var import_fs = require("fs");
|
|
10073
10225
|
|
|
10074
10226
|
// src/preview/dev-server-runner.ts
|
|
10075
|
-
var
|
|
10227
|
+
var import_child_process14 = require("child_process");
|
|
10076
10228
|
var http = __toESM(require("http"));
|
|
10077
10229
|
var fs20 = __toESM(require("fs"));
|
|
10078
10230
|
var path21 = __toESM(require("path"));
|
|
@@ -10210,7 +10362,7 @@ No cached values available as fallback.`
|
|
|
10210
10362
|
var fs19 = __toESM(require("fs"));
|
|
10211
10363
|
var path20 = __toESM(require("path"));
|
|
10212
10364
|
var os9 = __toESM(require("os"));
|
|
10213
|
-
var
|
|
10365
|
+
var import_child_process13 = require("child_process");
|
|
10214
10366
|
var DEV_SERVER_REGISTRY_DIR = path20.join(os9.homedir(), ".episoda", "dev-servers");
|
|
10215
10367
|
var DevServerRegistry = class {
|
|
10216
10368
|
constructor() {
|
|
@@ -10365,7 +10517,7 @@ var DevServerRegistry = class {
|
|
|
10365
10517
|
*/
|
|
10366
10518
|
getProcessCwd(pid) {
|
|
10367
10519
|
try {
|
|
10368
|
-
const output = (0,
|
|
10520
|
+
const output = (0, import_child_process13.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
|
|
10369
10521
|
encoding: "utf8",
|
|
10370
10522
|
timeout: 5e3
|
|
10371
10523
|
}).trim();
|
|
@@ -10390,7 +10542,7 @@ var DevServerRegistry = class {
|
|
|
10390
10542
|
findProcessesInWorktree(worktreePath) {
|
|
10391
10543
|
const pids = [];
|
|
10392
10544
|
try {
|
|
10393
|
-
const output = (0,
|
|
10545
|
+
const output = (0, import_child_process13.execSync)(
|
|
10394
10546
|
`lsof -c node -c next | grep "${worktreePath}" | awk '{print $2}' | sort -u`,
|
|
10395
10547
|
{ encoding: "utf8", timeout: 5e3 }
|
|
10396
10548
|
).trim();
|
|
@@ -10451,7 +10603,7 @@ var DevServerRegistry = class {
|
|
|
10451
10603
|
*/
|
|
10452
10604
|
findProcessesOnPort(port) {
|
|
10453
10605
|
try {
|
|
10454
|
-
const output = (0,
|
|
10606
|
+
const output = (0, import_child_process13.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
|
|
10455
10607
|
if (!output) {
|
|
10456
10608
|
return [];
|
|
10457
10609
|
}
|
|
@@ -10705,7 +10857,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
|
|
|
10705
10857
|
*/
|
|
10706
10858
|
async killProcessOnPort(port) {
|
|
10707
10859
|
try {
|
|
10708
|
-
const result = (0,
|
|
10860
|
+
const result = (0, import_child_process14.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
|
|
10709
10861
|
if (!result) {
|
|
10710
10862
|
return true;
|
|
10711
10863
|
}
|
|
@@ -10713,15 +10865,15 @@ var DevServerRunner = class extends import_events2.EventEmitter {
|
|
|
10713
10865
|
console.log(`[DevServerRunner] Found ${pids.length} process(es) on port ${port}`);
|
|
10714
10866
|
for (const pid of pids) {
|
|
10715
10867
|
try {
|
|
10716
|
-
(0,
|
|
10868
|
+
(0, import_child_process14.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
|
|
10717
10869
|
} catch {
|
|
10718
10870
|
}
|
|
10719
10871
|
}
|
|
10720
10872
|
await this.wait(1e3);
|
|
10721
10873
|
for (const pid of pids) {
|
|
10722
10874
|
try {
|
|
10723
|
-
(0,
|
|
10724
|
-
(0,
|
|
10875
|
+
(0, import_child_process14.execSync)(`kill -0 ${pid} 2>/dev/null`);
|
|
10876
|
+
(0, import_child_process14.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
|
|
10725
10877
|
} catch {
|
|
10726
10878
|
}
|
|
10727
10879
|
}
|
|
@@ -10770,7 +10922,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
|
|
|
10770
10922
|
PORT: String(port),
|
|
10771
10923
|
NODE_OPTIONS: enhancedNodeOptions
|
|
10772
10924
|
};
|
|
10773
|
-
const proc = (0,
|
|
10925
|
+
const proc = (0, import_child_process14.spawn)(cmd, args, {
|
|
10774
10926
|
cwd: projectPath,
|
|
10775
10927
|
env: mergedEnv,
|
|
10776
10928
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -11571,7 +11723,7 @@ async function getConfigForApi() {
|
|
|
11571
11723
|
}
|
|
11572
11724
|
return (0, import_core13.loadConfig)();
|
|
11573
11725
|
}
|
|
11574
|
-
var execAsync2 = (0, import_util2.promisify)(
|
|
11726
|
+
var execAsync2 = (0, import_util2.promisify)(import_child_process15.exec);
|
|
11575
11727
|
function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
|
|
11576
11728
|
if (process.env.EPISODA_MODE !== "cloud") {
|
|
11577
11729
|
return;
|
|
@@ -11644,8 +11796,11 @@ async function handleWorktreeCreate(request2) {
|
|
|
11644
11796
|
envVars,
|
|
11645
11797
|
setupScript,
|
|
11646
11798
|
// EP1229: detachedHead removed - planning worktrees no longer exist
|
|
11647
|
-
moduleType
|
|
11799
|
+
moduleType,
|
|
11800
|
+
defaultBranch,
|
|
11801
|
+
correlationId
|
|
11648
11802
|
} = request2;
|
|
11803
|
+
const worktreeStartMs = Date.now();
|
|
11649
11804
|
console.log(`[Worktree] K1273: Creating worktree for ${moduleUid}`);
|
|
11650
11805
|
console.log(`[Worktree] Project: ${projectSlug}`);
|
|
11651
11806
|
console.log(`[Worktree] Branch: ${branchName} (create: ${createBranch})`);
|
|
@@ -11689,12 +11844,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
11689
11844
|
};
|
|
11690
11845
|
}
|
|
11691
11846
|
} else {
|
|
11692
|
-
console.log(`[Worktree]
|
|
11693
|
-
try {
|
|
11694
|
-
await execAsync2(`git -C "${bareRepoPath}" fetch origin --prune`, { env: gitEnv });
|
|
11695
|
-
} catch (fetchError) {
|
|
11696
|
-
console.warn(`[Worktree] K1273: Fetch failed (continuing anyway): ${fetchError.message}`);
|
|
11697
|
-
}
|
|
11847
|
+
console.log(`[Worktree] EP1373: Project exists, skipping handler-level fetch (manager handles narrow fetch)`);
|
|
11698
11848
|
}
|
|
11699
11849
|
const manager = new WorktreeManager(projectPath);
|
|
11700
11850
|
const initialized2 = await manager.initialize();
|
|
@@ -11704,7 +11854,8 @@ async function handleWorktreeCreate(request2) {
|
|
|
11704
11854
|
error: `Failed to initialize WorktreeManager at ${projectPath}`
|
|
11705
11855
|
};
|
|
11706
11856
|
}
|
|
11707
|
-
const
|
|
11857
|
+
const worktreeAddStartMs = Date.now();
|
|
11858
|
+
const result = await manager.createWorktree(moduleUid, branchName, createBranch, defaultBranch, correlationId);
|
|
11708
11859
|
if (!result.success) {
|
|
11709
11860
|
return {
|
|
11710
11861
|
success: false,
|
|
@@ -11712,6 +11863,7 @@ async function handleWorktreeCreate(request2) {
|
|
|
11712
11863
|
};
|
|
11713
11864
|
}
|
|
11714
11865
|
const worktreePath = result.worktreePath;
|
|
11866
|
+
console.log(`[Worktree] EP1373: worktree_add phase=worktree_add durationMs=${Date.now() - worktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"}`);
|
|
11715
11867
|
console.log(`[Worktree] EP1143: Worktree created at ${worktreePath}`);
|
|
11716
11868
|
const config = await getConfigForApi();
|
|
11717
11869
|
let finalStatus = "ready";
|
|
@@ -11743,6 +11895,7 @@ ${buildCmd}` : buildCmd;
|
|
|
11743
11895
|
}
|
|
11744
11896
|
}
|
|
11745
11897
|
if (effectiveSetupScript) {
|
|
11898
|
+
const setupStartMs = Date.now();
|
|
11746
11899
|
await manager.updateWorktreeStatus(moduleUid, "setup");
|
|
11747
11900
|
if (config?.access_token) {
|
|
11748
11901
|
await updateWorktree(config, {
|
|
@@ -11755,6 +11908,7 @@ ${buildCmd}` : buildCmd;
|
|
|
11755
11908
|
}
|
|
11756
11909
|
console.log(`[Worktree] EP1143: Running setup script...`);
|
|
11757
11910
|
const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
|
|
11911
|
+
console.log(`[Worktree] EP1373: setup_script phase=worktree_setup durationMs=${Date.now() - setupStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${scriptResult.success}`);
|
|
11758
11912
|
if (!scriptResult.success) {
|
|
11759
11913
|
console.error(`[Worktree] EP1143: Setup script failed: ${scriptResult.error}`);
|
|
11760
11914
|
await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
|
|
@@ -11814,6 +11968,7 @@ ${buildCmd}` : buildCmd;
|
|
|
11814
11968
|
console.error(`[Worktree] EP1143: Failed to update worktrees table: ${apiError.message}`);
|
|
11815
11969
|
}
|
|
11816
11970
|
}
|
|
11971
|
+
console.log(`[Worktree] EP1373: worktree_create_total phase=worktree_create_total durationMs=${Date.now() - worktreeStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} status=${finalStatus}`);
|
|
11817
11972
|
console.log(`[Worktree] EP1143: Worktree ready for ${moduleUid}`);
|
|
11818
11973
|
return {
|
|
11819
11974
|
success: true,
|
|
@@ -12116,7 +12271,7 @@ async function handleProjectSetup(params) {
|
|
|
12116
12271
|
}
|
|
12117
12272
|
|
|
12118
12273
|
// src/utils/dev-server.ts
|
|
12119
|
-
var
|
|
12274
|
+
var import_child_process16 = require("child_process");
|
|
12120
12275
|
var import_core14 = __toESM(require_dist());
|
|
12121
12276
|
var fs24 = __toESM(require("fs"));
|
|
12122
12277
|
var path25 = __toESM(require("path"));
|
|
@@ -12165,7 +12320,7 @@ function writeToLog(logPath, line, isError = false) {
|
|
|
12165
12320
|
}
|
|
12166
12321
|
async function killProcessOnPort(port) {
|
|
12167
12322
|
try {
|
|
12168
|
-
const result = (0,
|
|
12323
|
+
const result = (0, import_child_process16.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
|
|
12169
12324
|
if (!result) {
|
|
12170
12325
|
console.log(`[DevServer] EP929: No process found on port ${port}`);
|
|
12171
12326
|
return true;
|
|
@@ -12174,7 +12329,7 @@ async function killProcessOnPort(port) {
|
|
|
12174
12329
|
console.log(`[DevServer] EP929: Found ${pids.length} process(es) on port ${port}: ${pids.join(", ")}`);
|
|
12175
12330
|
for (const pid of pids) {
|
|
12176
12331
|
try {
|
|
12177
|
-
(0,
|
|
12332
|
+
(0, import_child_process16.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
|
|
12178
12333
|
console.log(`[DevServer] EP929: Sent SIGTERM to PID ${pid}`);
|
|
12179
12334
|
} catch {
|
|
12180
12335
|
}
|
|
@@ -12182,8 +12337,8 @@ async function killProcessOnPort(port) {
|
|
|
12182
12337
|
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
12183
12338
|
for (const pid of pids) {
|
|
12184
12339
|
try {
|
|
12185
|
-
(0,
|
|
12186
|
-
(0,
|
|
12340
|
+
(0, import_child_process16.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
|
|
12341
|
+
(0, import_child_process16.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
|
|
12187
12342
|
console.log(`[DevServer] EP929: Force killed PID ${pid}`);
|
|
12188
12343
|
} catch {
|
|
12189
12344
|
}
|
|
@@ -12234,7 +12389,7 @@ function spawnDevServerProcess(projectPath, port, moduleUid, logPath, customComm
|
|
|
12234
12389
|
if (injectedCount > 0) {
|
|
12235
12390
|
console.log(`[DevServer] EP998: Injecting ${injectedCount} env vars from database`);
|
|
12236
12391
|
}
|
|
12237
|
-
const devProcess = (0,
|
|
12392
|
+
const devProcess = (0, import_child_process16.spawn)(cmd, args, {
|
|
12238
12393
|
cwd: projectPath,
|
|
12239
12394
|
env: mergedEnv,
|
|
12240
12395
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -12682,11 +12837,11 @@ var IPCRouter = class {
|
|
|
12682
12837
|
// src/daemon/update-manager.ts
|
|
12683
12838
|
var fs25 = __toESM(require("fs"));
|
|
12684
12839
|
var path26 = __toESM(require("path"));
|
|
12685
|
-
var
|
|
12840
|
+
var import_child_process18 = require("child_process");
|
|
12686
12841
|
var import_core17 = __toESM(require_dist());
|
|
12687
12842
|
|
|
12688
12843
|
// src/utils/update-checker.ts
|
|
12689
|
-
var
|
|
12844
|
+
var import_child_process17 = require("child_process");
|
|
12690
12845
|
var semver = __toESM(require("semver"));
|
|
12691
12846
|
|
|
12692
12847
|
// src/ipc/ipc-client.ts
|
|
@@ -12697,7 +12852,7 @@ var PACKAGE_NAME = "@episoda/cli";
|
|
|
12697
12852
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
12698
12853
|
function isFileLinkedInstall() {
|
|
12699
12854
|
try {
|
|
12700
|
-
const output = (0,
|
|
12855
|
+
const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
|
|
12701
12856
|
stdio: ["pipe", "pipe", "pipe"],
|
|
12702
12857
|
timeout: 1e4
|
|
12703
12858
|
}).toString();
|
|
@@ -12741,7 +12896,7 @@ async function checkForUpdates(currentVersion) {
|
|
|
12741
12896
|
}
|
|
12742
12897
|
function performSyncUpdate(targetVersion) {
|
|
12743
12898
|
try {
|
|
12744
|
-
(0,
|
|
12899
|
+
(0, import_child_process17.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion}`, {
|
|
12745
12900
|
stdio: ["pipe", "pipe", "pipe"],
|
|
12746
12901
|
timeout: 12e4
|
|
12747
12902
|
// 2 minute timeout
|
|
@@ -12756,7 +12911,7 @@ function performSyncUpdate(targetVersion) {
|
|
|
12756
12911
|
}
|
|
12757
12912
|
function getInstalledVersion() {
|
|
12758
12913
|
try {
|
|
12759
|
-
const output = (0,
|
|
12914
|
+
const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
|
|
12760
12915
|
stdio: ["pipe", "pipe", "pipe"],
|
|
12761
12916
|
timeout: 1e4
|
|
12762
12917
|
}).toString();
|
|
@@ -12891,7 +13046,7 @@ var UpdateManager = class _UpdateManager {
|
|
|
12891
13046
|
const configDir = (0, import_core17.getConfigDir)();
|
|
12892
13047
|
const logPath = path26.join(configDir, "daemon.log");
|
|
12893
13048
|
const logFd = fs25.openSync(logPath, "a");
|
|
12894
|
-
const child = (0,
|
|
13049
|
+
const child = (0, import_child_process18.spawn)("node", [this.daemonEntryFile], {
|
|
12895
13050
|
detached: true,
|
|
12896
13051
|
stdio: ["ignore", logFd, logFd],
|
|
12897
13052
|
env: { ...process.env, EPISODA_DAEMON_MODE: "1" }
|