episoda 0.2.67 → 0.2.69
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 +99 -15
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +37 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -2337,12 +2337,18 @@ var require_websocket_client = __commonJS({
|
|
|
2337
2337
|
/**
|
|
2338
2338
|
* EP701: Emit a client-side event to registered handlers
|
|
2339
2339
|
* Used for events like 'disconnected' that originate from the client, not server
|
|
2340
|
+
* EP1095: Fixed to handle async handlers - catches both sync errors and promise rejections
|
|
2340
2341
|
*/
|
|
2341
2342
|
emit(event) {
|
|
2342
2343
|
const handlers = this.eventHandlers.get(event.type) || [];
|
|
2343
2344
|
handlers.forEach((handler) => {
|
|
2344
2345
|
try {
|
|
2345
|
-
handler(event);
|
|
2346
|
+
const result = handler(event);
|
|
2347
|
+
if (result && typeof result === "object" && "catch" in result && typeof result.catch === "function") {
|
|
2348
|
+
result.catch((error) => {
|
|
2349
|
+
console.error(`[EpisodaClient] Async handler error for ${event.type}:`, error);
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2346
2352
|
} catch (error) {
|
|
2347
2353
|
console.error(`[EpisodaClient] Handler error for ${event.type}:`, error);
|
|
2348
2354
|
}
|
|
@@ -2730,7 +2736,7 @@ var require_package = __commonJS({
|
|
|
2730
2736
|
"package.json"(exports2, module2) {
|
|
2731
2737
|
module2.exports = {
|
|
2732
2738
|
name: "episoda",
|
|
2733
|
-
version: "0.2.
|
|
2739
|
+
version: "0.2.69",
|
|
2734
2740
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2735
2741
|
main: "dist/index.js",
|
|
2736
2742
|
types: "dist/index.d.ts",
|
|
@@ -8902,6 +8908,27 @@ var Daemon = class _Daemon {
|
|
|
8902
8908
|
console.log(`[Daemon] EP949: Received token refresh for ${projectId}`);
|
|
8903
8909
|
client.updateToken(tokenMsg.accessToken);
|
|
8904
8910
|
});
|
|
8911
|
+
client.on("machine_uuid_update", async (message) => {
|
|
8912
|
+
try {
|
|
8913
|
+
const uuidMsg = message;
|
|
8914
|
+
if (uuidMsg.machineUuid) {
|
|
8915
|
+
this.machineUuid = uuidMsg.machineUuid;
|
|
8916
|
+
console.log(`[Daemon] EP1095: Machine UUID updated: ${this.machineUuid}`);
|
|
8917
|
+
await this.cacheMachineUuid(uuidMsg.machineUuid);
|
|
8918
|
+
this.syncMachineProjectPath(projectId, projectPath).catch((err) => {
|
|
8919
|
+
console.warn("[Daemon] EP1095: Deferred project path sync failed:", err.message);
|
|
8920
|
+
});
|
|
8921
|
+
const connection2 = this.connections.get(projectPath);
|
|
8922
|
+
if (connection2) {
|
|
8923
|
+
this.reconcileWorktrees(projectId, projectPath, connection2.client).catch((err) => {
|
|
8924
|
+
console.warn("[Daemon] EP1095: Deferred reconciliation failed:", err.message);
|
|
8925
|
+
});
|
|
8926
|
+
}
|
|
8927
|
+
}
|
|
8928
|
+
} catch (error) {
|
|
8929
|
+
console.error("[Daemon] EP1095: Error handling machine_uuid_update:", error instanceof Error ? error.message : error);
|
|
8930
|
+
}
|
|
8931
|
+
});
|
|
8905
8932
|
client.on("disconnected", (event) => {
|
|
8906
8933
|
const disconnectEvent = event;
|
|
8907
8934
|
console.log(`[Daemon] Connection closed for ${projectId}: code=${disconnectEvent.code}, willReconnect=${disconnectEvent.willReconnect}`);
|
|
@@ -8984,12 +9011,47 @@ var Daemon = class _Daemon {
|
|
|
8984
9011
|
process.on("SIGTERM", () => shutdownHandler("SIGTERM"));
|
|
8985
9012
|
process.on("SIGINT", () => shutdownHandler("SIGINT"));
|
|
8986
9013
|
}
|
|
9014
|
+
/**
|
|
9015
|
+
* EP1095: Get git directory and working directory for a project path
|
|
9016
|
+
* Handles both traditional (.git directory) and worktree (.bare directory) structures
|
|
9017
|
+
* Returns { gitDir, workDir } where:
|
|
9018
|
+
* - gitDir: The --git-dir value to use with git commands
|
|
9019
|
+
* - workDir: The directory to run git commands in (cwd)
|
|
9020
|
+
*/
|
|
9021
|
+
getGitDirs(projectPath) {
|
|
9022
|
+
const bareDir = path19.join(projectPath, ".bare");
|
|
9023
|
+
const gitPath = path19.join(projectPath, ".git");
|
|
9024
|
+
if (fs18.existsSync(bareDir) && fs18.statSync(bareDir).isDirectory()) {
|
|
9025
|
+
return { gitDir: bareDir, workDir: projectPath };
|
|
9026
|
+
}
|
|
9027
|
+
if (fs18.existsSync(gitPath) && fs18.statSync(gitPath).isDirectory()) {
|
|
9028
|
+
return { gitDir: null, workDir: projectPath };
|
|
9029
|
+
}
|
|
9030
|
+
if (fs18.existsSync(gitPath) && fs18.statSync(gitPath).isFile()) {
|
|
9031
|
+
return { gitDir: null, workDir: projectPath };
|
|
9032
|
+
}
|
|
9033
|
+
const entries = fs18.readdirSync(projectPath, { withFileTypes: true });
|
|
9034
|
+
for (const entry of entries) {
|
|
9035
|
+
if (entry.isDirectory() && entry.name.startsWith("EP")) {
|
|
9036
|
+
const worktreePath = path19.join(projectPath, entry.name);
|
|
9037
|
+
const worktreeGit = path19.join(worktreePath, ".git");
|
|
9038
|
+
if (fs18.existsSync(worktreeGit)) {
|
|
9039
|
+
return { gitDir: null, workDir: worktreePath };
|
|
9040
|
+
}
|
|
9041
|
+
}
|
|
9042
|
+
}
|
|
9043
|
+
if (fs18.existsSync(bareDir)) {
|
|
9044
|
+
return { gitDir: bareDir, workDir: projectPath };
|
|
9045
|
+
}
|
|
9046
|
+
return { gitDir: null, workDir: projectPath };
|
|
9047
|
+
}
|
|
8987
9048
|
/**
|
|
8988
9049
|
* EP595: Configure git with user and workspace ID for post-checkout hook
|
|
8989
9050
|
* EP655: Added machineId for device isolation in multi-device environments
|
|
8990
9051
|
* EP725: Added projectId for main branch badge tracking
|
|
8991
9052
|
* EP726: Added machineUuid (UUID) for unified device identification
|
|
8992
9053
|
* EP1091: Renamed deviceId param to machineUuid for consistency
|
|
9054
|
+
* EP1095: Added worktree structure support (uses .bare as gitDir)
|
|
8993
9055
|
*
|
|
8994
9056
|
* This stores the IDs in .git/config so the post-checkout hook can
|
|
8995
9057
|
* update module.checkout_* fields when git operations happen from terminal.
|
|
@@ -8997,29 +9059,31 @@ var Daemon = class _Daemon {
|
|
|
8997
9059
|
async configureGitUser(projectPath, userId, workspaceId, machineId, projectId, machineUuid) {
|
|
8998
9060
|
try {
|
|
8999
9061
|
const { execSync: execSync9 } = await import("child_process");
|
|
9000
|
-
|
|
9001
|
-
|
|
9062
|
+
const { gitDir, workDir } = this.getGitDirs(projectPath);
|
|
9063
|
+
const gitCmd = gitDir ? `git --git-dir="${gitDir}"` : "git";
|
|
9064
|
+
execSync9(`${gitCmd} config episoda.userId ${userId}`, {
|
|
9065
|
+
cwd: workDir,
|
|
9002
9066
|
encoding: "utf8",
|
|
9003
9067
|
stdio: "pipe"
|
|
9004
9068
|
});
|
|
9005
|
-
execSync9(
|
|
9006
|
-
cwd:
|
|
9069
|
+
execSync9(`${gitCmd} config episoda.workspaceId ${workspaceId}`, {
|
|
9070
|
+
cwd: workDir,
|
|
9007
9071
|
encoding: "utf8",
|
|
9008
9072
|
stdio: "pipe"
|
|
9009
9073
|
});
|
|
9010
|
-
execSync9(
|
|
9011
|
-
cwd:
|
|
9074
|
+
execSync9(`${gitCmd} config episoda.machineId ${machineId}`, {
|
|
9075
|
+
cwd: workDir,
|
|
9012
9076
|
encoding: "utf8",
|
|
9013
9077
|
stdio: "pipe"
|
|
9014
9078
|
});
|
|
9015
|
-
execSync9(
|
|
9016
|
-
cwd:
|
|
9079
|
+
execSync9(`${gitCmd} config episoda.projectId ${projectId}`, {
|
|
9080
|
+
cwd: workDir,
|
|
9017
9081
|
encoding: "utf8",
|
|
9018
9082
|
stdio: "pipe"
|
|
9019
9083
|
});
|
|
9020
9084
|
if (machineUuid) {
|
|
9021
|
-
execSync9(
|
|
9022
|
-
cwd:
|
|
9085
|
+
execSync9(`${gitCmd} config episoda.deviceId ${machineUuid}`, {
|
|
9086
|
+
cwd: workDir,
|
|
9023
9087
|
encoding: "utf8",
|
|
9024
9088
|
stdio: "pipe"
|
|
9025
9089
|
});
|
|
@@ -9031,6 +9095,7 @@ var Daemon = class _Daemon {
|
|
|
9031
9095
|
}
|
|
9032
9096
|
/**
|
|
9033
9097
|
* EP610: Install git hooks from bundled files
|
|
9098
|
+
* EP1095: Added worktree structure support (hooks in .bare/hooks)
|
|
9034
9099
|
*
|
|
9035
9100
|
* Installs post-checkout and pre-commit hooks to enable:
|
|
9036
9101
|
* - Branch tracking (post-checkout updates module.checkout_* fields)
|
|
@@ -9038,10 +9103,29 @@ var Daemon = class _Daemon {
|
|
|
9038
9103
|
*/
|
|
9039
9104
|
async installGitHooks(projectPath) {
|
|
9040
9105
|
const hooks = ["post-checkout", "pre-commit", "post-commit"];
|
|
9041
|
-
|
|
9106
|
+
let hooksDir;
|
|
9107
|
+
const bareHooksDir = path19.join(projectPath, ".bare", "hooks");
|
|
9108
|
+
const gitHooksDir = path19.join(projectPath, ".git", "hooks");
|
|
9109
|
+
if (fs18.existsSync(bareHooksDir)) {
|
|
9110
|
+
hooksDir = bareHooksDir;
|
|
9111
|
+
} else if (fs18.existsSync(gitHooksDir) && fs18.statSync(path19.join(projectPath, ".git")).isDirectory()) {
|
|
9112
|
+
hooksDir = gitHooksDir;
|
|
9113
|
+
} else {
|
|
9114
|
+
const parentBareHooks = path19.join(projectPath, "..", ".bare", "hooks");
|
|
9115
|
+
if (fs18.existsSync(parentBareHooks)) {
|
|
9116
|
+
hooksDir = parentBareHooks;
|
|
9117
|
+
} else {
|
|
9118
|
+
console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
|
|
9119
|
+
return;
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9042
9122
|
if (!fs18.existsSync(hooksDir)) {
|
|
9043
|
-
|
|
9044
|
-
|
|
9123
|
+
try {
|
|
9124
|
+
fs18.mkdirSync(hooksDir, { recursive: true });
|
|
9125
|
+
} catch (error) {
|
|
9126
|
+
console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
|
|
9127
|
+
return;
|
|
9128
|
+
}
|
|
9045
9129
|
}
|
|
9046
9130
|
for (const hookName of hooks) {
|
|
9047
9131
|
try {
|