@episoda/cli 0.2.178 → 0.2.179
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 +100 -3
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +56 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -3046,7 +3046,7 @@ var require_package = __commonJS({
|
|
|
3046
3046
|
"package.json"(exports2, module2) {
|
|
3047
3047
|
module2.exports = {
|
|
3048
3048
|
name: "@episoda/cli",
|
|
3049
|
-
version: "0.2.
|
|
3049
|
+
version: "0.2.179",
|
|
3050
3050
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
3051
3051
|
main: "dist/index.js",
|
|
3052
3052
|
types: "dist/index.d.ts",
|
|
@@ -12299,6 +12299,91 @@ async function getConfigForApi() {
|
|
|
12299
12299
|
}
|
|
12300
12300
|
return (0, import_core13.loadConfig)();
|
|
12301
12301
|
}
|
|
12302
|
+
function stripGitCredentials(repoUrl) {
|
|
12303
|
+
try {
|
|
12304
|
+
const parsed = new URL(repoUrl);
|
|
12305
|
+
if (parsed.protocol !== "https:") {
|
|
12306
|
+
return repoUrl;
|
|
12307
|
+
}
|
|
12308
|
+
parsed.username = "";
|
|
12309
|
+
parsed.password = "";
|
|
12310
|
+
return parsed.toString();
|
|
12311
|
+
} catch {
|
|
12312
|
+
return repoUrl;
|
|
12313
|
+
}
|
|
12314
|
+
}
|
|
12315
|
+
function withGitHubInstallationToken(repoUrl, token) {
|
|
12316
|
+
try {
|
|
12317
|
+
const parsed = new URL(stripGitCredentials(repoUrl));
|
|
12318
|
+
if (parsed.protocol !== "https:" || parsed.hostname !== "github.com") {
|
|
12319
|
+
return repoUrl;
|
|
12320
|
+
}
|
|
12321
|
+
parsed.username = "x-access-token";
|
|
12322
|
+
parsed.password = token;
|
|
12323
|
+
return parsed.toString();
|
|
12324
|
+
} catch {
|
|
12325
|
+
return repoUrl;
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12328
|
+
async function getFreshGithubRepoUrl(repoUrl, projectId) {
|
|
12329
|
+
if (!repoUrl.startsWith("https://")) {
|
|
12330
|
+
return repoUrl;
|
|
12331
|
+
}
|
|
12332
|
+
let parsed;
|
|
12333
|
+
try {
|
|
12334
|
+
parsed = new URL(repoUrl);
|
|
12335
|
+
} catch {
|
|
12336
|
+
return repoUrl;
|
|
12337
|
+
}
|
|
12338
|
+
if (parsed.hostname !== "github.com") {
|
|
12339
|
+
return repoUrl;
|
|
12340
|
+
}
|
|
12341
|
+
const config = await getConfigForApi();
|
|
12342
|
+
if (!config?.access_token) {
|
|
12343
|
+
return repoUrl;
|
|
12344
|
+
}
|
|
12345
|
+
const apiUrl = config.api_url || "https://episoda.dev";
|
|
12346
|
+
const headers = {
|
|
12347
|
+
"Authorization": `Bearer ${config.access_token}`,
|
|
12348
|
+
"Content-Type": "application/json",
|
|
12349
|
+
"User-Agent": "episoda-cli"
|
|
12350
|
+
};
|
|
12351
|
+
if (config.workspace_id) headers["x-workspace-id"] = config.workspace_id;
|
|
12352
|
+
if (config.workspace_slug) headers["x-workspace-uid"] = config.workspace_slug;
|
|
12353
|
+
if (config.project_id) headers["x-project-id"] = config.project_id;
|
|
12354
|
+
if (config.project_slug) headers["x-project-uid"] = config.project_slug;
|
|
12355
|
+
try {
|
|
12356
|
+
const response = await fetch(`${apiUrl}/api/github/installation-token`, {
|
|
12357
|
+
method: "POST",
|
|
12358
|
+
headers,
|
|
12359
|
+
body: JSON.stringify({ project_id: projectId })
|
|
12360
|
+
});
|
|
12361
|
+
if (!response.ok) {
|
|
12362
|
+
const body = await response.text();
|
|
12363
|
+
console.warn(`[Worktree] EP1435: Failed to refresh GitHub installation token (${response.status}): ${body}`);
|
|
12364
|
+
return repoUrl;
|
|
12365
|
+
}
|
|
12366
|
+
const payload = await response.json();
|
|
12367
|
+
const token = payload?.data?.token || payload?.token;
|
|
12368
|
+
if (!token) {
|
|
12369
|
+
console.warn("[Worktree] EP1435: Token refresh response missing token");
|
|
12370
|
+
return repoUrl;
|
|
12371
|
+
}
|
|
12372
|
+
return withGitHubInstallationToken(repoUrl, token);
|
|
12373
|
+
} catch (error) {
|
|
12374
|
+
console.warn(`[Worktree] EP1435: Could not refresh GitHub installation token: ${error.message}`);
|
|
12375
|
+
return repoUrl;
|
|
12376
|
+
}
|
|
12377
|
+
}
|
|
12378
|
+
async function readOriginUrl(bareRepoPath) {
|
|
12379
|
+
try {
|
|
12380
|
+
const { stdout } = await execAsync2(`git -C "${bareRepoPath}" config --get remote.origin.url`);
|
|
12381
|
+
const value = stdout.trim();
|
|
12382
|
+
return value.length > 0 ? value : null;
|
|
12383
|
+
} catch {
|
|
12384
|
+
return null;
|
|
12385
|
+
}
|
|
12386
|
+
}
|
|
12302
12387
|
var execAsync2 = (0, import_util2.promisify)(import_child_process14.exec);
|
|
12303
12388
|
function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
|
|
12304
12389
|
if (process.env.EPISODA_MODE !== "cloud") {
|
|
@@ -12377,14 +12462,15 @@ async function handleWorktreeCreate(request2) {
|
|
|
12377
12462
|
const projectPath = getProjectPath(workspaceSlug, projectSlug);
|
|
12378
12463
|
const bareRepoPath = path28.join(projectPath, ".bare");
|
|
12379
12464
|
const gitEnv = projectId ? { ...process.env, EPISODA_PROJECT_ID: projectId } : process.env;
|
|
12465
|
+
const refreshedRepoUrl = await getFreshGithubRepoUrl(repoUrl, projectId);
|
|
12380
12466
|
if (!fs28.existsSync(bareRepoPath)) {
|
|
12381
12467
|
console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
|
|
12382
|
-
console.log(`[Worktree] Repo URL: ${
|
|
12468
|
+
console.log(`[Worktree] Repo URL: ${stripGitCredentials(refreshedRepoUrl)}`);
|
|
12383
12469
|
const episodaDir = path28.join(projectPath, ".episoda");
|
|
12384
12470
|
fs28.mkdirSync(episodaDir, { recursive: true });
|
|
12385
12471
|
try {
|
|
12386
12472
|
console.log(`[Worktree] K1273: Starting git clone...`);
|
|
12387
|
-
await execAsync2(`git clone --bare "${
|
|
12473
|
+
await execAsync2(`git clone --bare "${refreshedRepoUrl}" "${bareRepoPath}"`, { env: gitEnv });
|
|
12388
12474
|
console.log(`[Worktree] K1273: Clone successful`);
|
|
12389
12475
|
await execAsync2(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`, { env: gitEnv });
|
|
12390
12476
|
const configPath = path28.join(episodaDir, "config.json");
|
|
@@ -12406,6 +12492,17 @@ async function handleWorktreeCreate(request2) {
|
|
|
12406
12492
|
};
|
|
12407
12493
|
}
|
|
12408
12494
|
} else {
|
|
12495
|
+
const currentOriginUrl = await readOriginUrl(bareRepoPath);
|
|
12496
|
+
const sourceUrl = currentOriginUrl || refreshedRepoUrl;
|
|
12497
|
+
const refreshedOriginUrl = await getFreshGithubRepoUrl(sourceUrl, projectId);
|
|
12498
|
+
if (refreshedOriginUrl !== sourceUrl) {
|
|
12499
|
+
try {
|
|
12500
|
+
await execAsync2(`git -C "${bareRepoPath}" remote set-url origin "${refreshedOriginUrl}"`, { env: gitEnv });
|
|
12501
|
+
console.log("[Worktree] EP1435: Refreshed bare repo origin URL with a fresh installation token");
|
|
12502
|
+
} catch (setUrlError) {
|
|
12503
|
+
console.warn(`[Worktree] EP1435: Failed to refresh origin URL: ${setUrlError.message}`);
|
|
12504
|
+
}
|
|
12505
|
+
}
|
|
12409
12506
|
console.log(`[Worktree] EP1373: Project exists, skipping handler-level fetch (manager handles narrow fetch)`);
|
|
12410
12507
|
}
|
|
12411
12508
|
const manager = new WorktreeManager(projectPath);
|