stashes 0.1.55 → 0.1.57
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/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ var __require = import.meta.require;
|
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
import { readFileSync as readFileSync10 } from "fs";
|
|
23
|
-
import { join as
|
|
23
|
+
import { join as join14, dirname as dirname6 } from "path";
|
|
24
24
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
25
25
|
import { Command } from "commander";
|
|
26
26
|
|
|
@@ -31,9 +31,9 @@ import open from "open";
|
|
|
31
31
|
// ../server/dist/index.js
|
|
32
32
|
import { Hono as Hono2 } from "hono";
|
|
33
33
|
import { cors } from "hono/cors";
|
|
34
|
-
import { join as
|
|
34
|
+
import { join as join10, dirname as dirname3 } from "path";
|
|
35
35
|
import { fileURLToPath } from "url";
|
|
36
|
-
import { existsSync as
|
|
36
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
|
|
37
37
|
// ../shared/dist/constants/index.js
|
|
38
38
|
var STASHES_PORT = 4000;
|
|
39
39
|
var DEFAULT_STASH_COUNT = 3;
|
|
@@ -56,12 +56,12 @@ var DEFAULT_DIRECTIVES = [
|
|
|
56
56
|
];
|
|
57
57
|
// ../server/dist/routes/api.js
|
|
58
58
|
import { Hono } from "hono";
|
|
59
|
-
import { join as
|
|
60
|
-
import { existsSync as
|
|
59
|
+
import { join as join9, basename } from "path";
|
|
60
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
61
61
|
|
|
62
62
|
// ../core/dist/generation.js
|
|
63
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
64
|
-
import { join as
|
|
63
|
+
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
64
|
+
import { join as join6 } from "path";
|
|
65
65
|
var {spawn: spawn3 } = globalThis.Bun;
|
|
66
66
|
import simpleGit3 from "simple-git";
|
|
67
67
|
|
|
@@ -544,65 +544,19 @@ class PersistenceService {
|
|
|
544
544
|
|
|
545
545
|
// ../core/dist/ai-process.js
|
|
546
546
|
var {spawn } = globalThis.Bun;
|
|
547
|
-
import { writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
548
|
-
import { join as join4 } from "path";
|
|
549
|
-
import { tmpdir } from "os";
|
|
550
547
|
var CLAUDE_BIN = "/opt/homebrew/bin/claude";
|
|
551
|
-
function getPlaywrightMcpConfigPath() {
|
|
552
|
-
const configDir = join4(tmpdir(), "stashes-mcp");
|
|
553
|
-
const configPath = join4(configDir, "playwright.json");
|
|
554
|
-
if (!existsSync4(configPath)) {
|
|
555
|
-
mkdirSync3(configDir, { recursive: true });
|
|
556
|
-
writeFileSync2(configPath, JSON.stringify({
|
|
557
|
-
mcpServers: {
|
|
558
|
-
playwright: { command: "npx", args: ["@playwright/mcp@latest"] }
|
|
559
|
-
}
|
|
560
|
-
}), "utf-8");
|
|
561
|
-
}
|
|
562
|
-
return configPath;
|
|
563
|
-
}
|
|
564
|
-
var OVERHEAD_TOOLS = [
|
|
565
|
-
"Agent",
|
|
566
|
-
"TodoWrite",
|
|
567
|
-
"TaskCreate",
|
|
568
|
-
"TaskUpdate",
|
|
569
|
-
"TaskList",
|
|
570
|
-
"TaskGet",
|
|
571
|
-
"Skill",
|
|
572
|
-
"ToolSearch",
|
|
573
|
-
"EnterPlanMode",
|
|
574
|
-
"ExitPlanMode",
|
|
575
|
-
"WebSearch",
|
|
576
|
-
"WebFetch",
|
|
577
|
-
"NotebookEdit",
|
|
578
|
-
"mcp__UseAI__*",
|
|
579
|
-
"mcp__stashes__*",
|
|
580
|
-
"mcp__plugin_drills*",
|
|
581
|
-
"mcp__plugin_coverit*"
|
|
582
|
-
];
|
|
583
548
|
var processes = new Map;
|
|
584
549
|
function startAiProcess(idOrOpts, prompt, cwd, resumeSessionId, model) {
|
|
585
550
|
const opts = typeof idOrOpts === "string" ? { id: idOrOpts, prompt, cwd, resumeSessionId, model } : idOrOpts;
|
|
586
|
-
const restricted = opts.tools !== undefined;
|
|
587
551
|
killAiProcess(opts.id);
|
|
588
552
|
logger.info("claude", `spawning process: ${opts.id}`, {
|
|
589
553
|
cwd: opts.cwd,
|
|
590
554
|
promptLength: opts.prompt.length,
|
|
591
555
|
promptPreview: opts.prompt.substring(0, 100),
|
|
592
556
|
resumeSessionId: opts.resumeSessionId,
|
|
593
|
-
model: opts.model
|
|
594
|
-
restricted,
|
|
595
|
-
tools: restricted ? opts.tools.join(",") || "none" : "all"
|
|
557
|
+
model: opts.model
|
|
596
558
|
});
|
|
597
559
|
const cmd = [CLAUDE_BIN, "-p", opts.prompt, "--output-format=stream-json", "--verbose", "--dangerously-skip-permissions"];
|
|
598
|
-
if (restricted) {
|
|
599
|
-
cmd.push("--tools", opts.tools.length > 0 ? opts.tools.join(",") : '""');
|
|
600
|
-
cmd.push("--disallowedTools", OVERHEAD_TOOLS.join(","));
|
|
601
|
-
cmd.push("--strict-mcp-config");
|
|
602
|
-
if (opts.mcpConfigPath) {
|
|
603
|
-
cmd.push("--mcp-config", opts.mcpConfigPath);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
560
|
if (opts.resumeSessionId) {
|
|
607
561
|
cmd.push("--resume", opts.resumeSessionId);
|
|
608
562
|
}
|
|
@@ -733,35 +687,47 @@ async function* parseClaudeStream(proc) {
|
|
|
733
687
|
}
|
|
734
688
|
|
|
735
689
|
// ../core/dist/smart-screenshot.js
|
|
736
|
-
import { join as
|
|
737
|
-
import { mkdirSync as
|
|
690
|
+
import { join as join5 } from "path";
|
|
691
|
+
import { mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
738
692
|
import simpleGit2 from "simple-git";
|
|
739
693
|
|
|
740
694
|
// ../core/dist/screenshot.js
|
|
741
695
|
var {spawn: spawn2 } = globalThis.Bun;
|
|
742
|
-
import { join as
|
|
743
|
-
import { mkdirSync as
|
|
696
|
+
import { join as join4 } from "path";
|
|
697
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
|
|
744
698
|
var SCREENSHOTS_DIR = ".stashes/screenshots";
|
|
745
|
-
async function captureScreenshot(
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const
|
|
699
|
+
async function captureScreenshot(portOrOpts, projectPath, stashId) {
|
|
700
|
+
const opts = typeof portOrOpts === "number" ? { port: portOrOpts, projectPath, stashId } : portOrOpts;
|
|
701
|
+
const screenshotsDir = join4(opts.projectPath, SCREENSHOTS_DIR);
|
|
702
|
+
if (!existsSync4(screenshotsDir)) {
|
|
703
|
+
mkdirSync3(screenshotsDir, { recursive: true });
|
|
704
|
+
}
|
|
705
|
+
const filename = `${opts.stashId}.png`;
|
|
706
|
+
const outputPath = join4(screenshotsDir, filename);
|
|
707
|
+
const url = `http://localhost:${opts.port}${opts.route || "/"}`;
|
|
708
|
+
const scrollCode = opts.scrollToSelector ? `
|
|
709
|
+
try {
|
|
710
|
+
const el = await page.waitForSelector('${opts.scrollToSelector.replace(/'/g, "\\'")}', { timeout: 5000 });
|
|
711
|
+
if (el) {
|
|
712
|
+
await el.scrollIntoViewIfNeeded();
|
|
713
|
+
await page.waitForTimeout(500);
|
|
714
|
+
}
|
|
715
|
+
} catch(e) { /* selector not found, capture viewport */ }
|
|
716
|
+
` : "";
|
|
752
717
|
const playwrightScript = `
|
|
753
718
|
const { chromium } = require('playwright');
|
|
754
719
|
(async () => {
|
|
755
720
|
const browser = await chromium.launch({ headless: true });
|
|
756
721
|
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
|
757
722
|
try {
|
|
758
|
-
await page.goto('
|
|
723
|
+
await page.goto('${url}', { waitUntil: 'networkidle', timeout: 20000 });
|
|
759
724
|
await page.waitForTimeout(2000);
|
|
760
725
|
} catch(e) {
|
|
761
|
-
await page.goto('
|
|
726
|
+
await page.goto('${url}', { waitUntil: 'domcontentloaded', timeout: 10000 });
|
|
762
727
|
await page.waitForTimeout(3000);
|
|
763
728
|
}
|
|
764
|
-
|
|
729
|
+
${scrollCode}
|
|
730
|
+
await page.screenshot({ path: '${outputPath.replace(/'/g, "\\'")}', type: 'png'${opts.fullPage ? ", fullPage: true" : ""} });
|
|
765
731
|
await browser.close();
|
|
766
732
|
})();
|
|
767
733
|
`;
|
|
@@ -797,62 +763,56 @@ ${diffStat}
|
|
|
797
763
|
## Partial diff (truncated):
|
|
798
764
|
${truncatedDiff}`;
|
|
799
765
|
} catch (err) {
|
|
800
|
-
logger.warn("smart-screenshot", `git diff failed
|
|
766
|
+
logger.warn("smart-screenshot", `git diff failed`, {
|
|
801
767
|
error: err instanceof Error ? err.message : String(err)
|
|
802
768
|
});
|
|
803
769
|
return "";
|
|
804
770
|
}
|
|
805
771
|
}
|
|
806
772
|
function buildScreenshotPrompt(port, diff, screenshotDir, stashId) {
|
|
807
|
-
const outputPath =
|
|
773
|
+
const outputPath = join5(screenshotDir, `${stashId}.png`);
|
|
808
774
|
return [
|
|
809
|
-
"You are
|
|
810
|
-
"Be fast \u2014 you have a strict time limit.",
|
|
775
|
+
"## CRITICAL: You are an automated screenshot subprocess. Follow these rules exactly.",
|
|
811
776
|
"",
|
|
812
|
-
|
|
777
|
+
"FORBIDDEN \u2014 do NOT call any of these tools:",
|
|
778
|
+
"- ToolSearch, Skill, Agent, TodoWrite, TaskCreate, TaskUpdate, TaskList",
|
|
779
|
+
"- mcp__UseAI__useai_start, mcp__UseAI__useai_end, mcp__UseAI__useai_heartbeat",
|
|
780
|
+
"- mcp__stashes__*, mcp__plugin_drills__*, mcp__plugin_coverit__*",
|
|
781
|
+
"- EnterPlanMode, ExitPlanMode, WebSearch, WebFetch, LSP",
|
|
782
|
+
"- Read, Write, Edit, Glob, Grep (you do NOT need to read code)",
|
|
813
783
|
"",
|
|
814
|
-
"
|
|
815
|
-
"```",
|
|
816
|
-
diff,
|
|
817
|
-
"```",
|
|
784
|
+
"YOUR ONLY JOB: navigate to the app and take a screenshot using Playwright.",
|
|
818
785
|
"",
|
|
819
|
-
|
|
820
|
-
"Use mcp__playwright__browser_run_code to navigate AND screenshot in a single call.",
|
|
821
|
-
"From the diff, determine the route/section that shows the changes.",
|
|
786
|
+
`## App URL: http://localhost:${port}`,
|
|
822
787
|
"",
|
|
823
|
-
"
|
|
824
|
-
"```",
|
|
825
|
-
"mcp__playwright__browser_run_code",
|
|
788
|
+
"## Git diff (shows what changed \u2014 use this to decide where to navigate):",
|
|
826
789
|
"```",
|
|
827
|
-
|
|
828
|
-
"**With this code parameter** (adjust the URL path and scroll if needed):",
|
|
829
|
-
"```javascript",
|
|
830
|
-
`async (page) => {`,
|
|
831
|
-
` await page.setViewportSize({ width: 1280, height: 720 });`,
|
|
832
|
-
` await page.goto('http://localhost:${port}', { waitUntil: 'networkidle', timeout: 15000 });`,
|
|
833
|
-
` // If the changed component is further down, scroll to it:`,
|
|
834
|
-
` // await page.evaluate(() => window.scrollTo(0, 500));`,
|
|
835
|
-
` // await page.waitForTimeout(500);`,
|
|
836
|
-
` await page.waitForTimeout(2000);`,
|
|
837
|
-
` await page.screenshot({ path: '${outputPath.replace(/'/g, "\\'")}', type: 'png' });`,
|
|
838
|
-
` return 'saved';`,
|
|
839
|
-
`}`,
|
|
790
|
+
diff,
|
|
840
791
|
"```",
|
|
841
792
|
"",
|
|
842
|
-
"
|
|
843
|
-
|
|
793
|
+
"## Steps (do these in order, nothing else):",
|
|
794
|
+
`1. Navigate: call mcp__plugin_playwright_playwright__browser_navigate with url "http://localhost:${port}"`,
|
|
795
|
+
"2. Wait 3 seconds for the page to render",
|
|
796
|
+
"3. If the diff shows changes below the fold, scroll down using mcp__plugin_playwright_playwright__browser_evaluate",
|
|
797
|
+
`4. Take screenshot: call mcp__plugin_playwright_playwright__browser_take_screenshot with type "png"`,
|
|
798
|
+
` The screenshot will be saved automatically.`,
|
|
799
|
+
"5. Output ONLY this JSON (replace the screenshot path with the actual path returned):",
|
|
844
800
|
"",
|
|
845
|
-
|
|
801
|
+
"```json",
|
|
846
802
|
"{",
|
|
847
803
|
' "screenshots": [',
|
|
848
804
|
" {",
|
|
849
805
|
` "path": "${outputPath}",`,
|
|
850
|
-
' "label": "
|
|
851
|
-
' "route": "/
|
|
806
|
+
' "label": "Description of what is shown",',
|
|
807
|
+
' "route": "/",',
|
|
852
808
|
' "isPrimary": true',
|
|
853
809
|
" }",
|
|
854
810
|
" ]",
|
|
855
|
-
"}"
|
|
811
|
+
"}",
|
|
812
|
+
"```",
|
|
813
|
+
"",
|
|
814
|
+
"REMEMBER: Do NOT call ToolSearch, Skill, UseAI, Read, or any tool not listed above.",
|
|
815
|
+
"You have a strict time limit. Just navigate, screenshot, output JSON, done."
|
|
856
816
|
].join(`
|
|
857
817
|
`);
|
|
858
818
|
}
|
|
@@ -887,9 +847,9 @@ async function fallbackScreenshot(port, projectPath, stashId) {
|
|
|
887
847
|
}
|
|
888
848
|
async function captureSmartScreenshots(opts) {
|
|
889
849
|
const { projectPath, stashId, stashBranch, parentBranch, worktreePath, port, model = "sonnet", timeout = DEFAULT_TIMEOUT } = opts;
|
|
890
|
-
const screenshotDir =
|
|
891
|
-
if (!
|
|
892
|
-
|
|
850
|
+
const screenshotDir = join5(projectPath, SCREENSHOTS_DIR2);
|
|
851
|
+
if (!existsSync5(screenshotDir)) {
|
|
852
|
+
mkdirSync4(screenshotDir, { recursive: true });
|
|
893
853
|
}
|
|
894
854
|
const diff = await getStashDiff(worktreePath, parentBranch);
|
|
895
855
|
if (!diff) {
|
|
@@ -903,9 +863,7 @@ async function captureSmartScreenshots(opts) {
|
|
|
903
863
|
id: processId,
|
|
904
864
|
prompt,
|
|
905
865
|
cwd: worktreePath,
|
|
906
|
-
model: modelFlag
|
|
907
|
-
tools: [],
|
|
908
|
-
mcpConfigPath: getPlaywrightMcpConfigPath()
|
|
866
|
+
model: modelFlag
|
|
909
867
|
});
|
|
910
868
|
let textOutput = "";
|
|
911
869
|
let timedOut = false;
|
|
@@ -931,6 +889,15 @@ async function captureSmartScreenshots(opts) {
|
|
|
931
889
|
}
|
|
932
890
|
const result = parseAiResult(textOutput);
|
|
933
891
|
if (!result || !result.screenshots || result.screenshots.length === 0) {
|
|
892
|
+
const expectedPath = join5(screenshotDir, `${stashId}.png`);
|
|
893
|
+
if (existsSync5(expectedPath)) {
|
|
894
|
+
logger.info("smart-screenshot", `AI saved screenshot for ${stashId} (no JSON response, but file exists)`);
|
|
895
|
+
const url = `/api/screenshots/${stashId}.png`;
|
|
896
|
+
return {
|
|
897
|
+
primary: url,
|
|
898
|
+
screenshots: [{ url, label: "AI screenshot", route: "/", isPrimary: true }]
|
|
899
|
+
};
|
|
900
|
+
}
|
|
934
901
|
logger.info("smart-screenshot", `AI returned no screenshots for ${stashId} (timedOut=${timedOut}), falling back`);
|
|
935
902
|
return fallbackScreenshot(port, projectPath, stashId);
|
|
936
903
|
}
|
|
@@ -938,18 +905,12 @@ async function captureSmartScreenshots(opts) {
|
|
|
938
905
|
let primaryUrl = "";
|
|
939
906
|
for (const shot of result.screenshots) {
|
|
940
907
|
const filename = shot.path.split("/").pop() || "";
|
|
941
|
-
if (!
|
|
908
|
+
if (!existsSync5(shot.path)) {
|
|
942
909
|
logger.warn("smart-screenshot", `Screenshot file not found: ${shot.path}`);
|
|
943
910
|
continue;
|
|
944
911
|
}
|
|
945
912
|
const url = `/api/screenshots/${filename}`;
|
|
946
|
-
|
|
947
|
-
url,
|
|
948
|
-
label: shot.label,
|
|
949
|
-
route: shot.route,
|
|
950
|
-
isPrimary: shot.isPrimary
|
|
951
|
-
};
|
|
952
|
-
screenshots.push(screenshot);
|
|
913
|
+
screenshots.push({ url, label: shot.label, route: shot.route, isPrimary: shot.isPrimary });
|
|
953
914
|
if (shot.isPrimary)
|
|
954
915
|
primaryUrl = url;
|
|
955
916
|
}
|
|
@@ -1032,8 +993,8 @@ async function generate(opts) {
|
|
|
1032
993
|
const selectedDirectives = directives.slice(0, count);
|
|
1033
994
|
let sourceCode = "";
|
|
1034
995
|
if (component?.filePath) {
|
|
1035
|
-
const sourceFile =
|
|
1036
|
-
if (
|
|
996
|
+
const sourceFile = join6(projectPath, component.filePath);
|
|
997
|
+
if (existsSync6(sourceFile)) {
|
|
1037
998
|
sourceCode = readFileSync2(sourceFile, "utf-8");
|
|
1038
999
|
}
|
|
1039
1000
|
}
|
|
@@ -1403,8 +1364,8 @@ async function cleanup(projectPath) {
|
|
|
1403
1364
|
logger.info("manage", "cleanup complete");
|
|
1404
1365
|
}
|
|
1405
1366
|
// ../server/dist/services/stash-service.js
|
|
1406
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
1407
|
-
import { join as
|
|
1367
|
+
import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
|
|
1368
|
+
import { join as join7 } from "path";
|
|
1408
1369
|
|
|
1409
1370
|
// ../server/dist/services/app-proxy.js
|
|
1410
1371
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -1940,8 +1901,7 @@ class StashService {
|
|
|
1940
1901
|
id: "resolve-component",
|
|
1941
1902
|
prompt,
|
|
1942
1903
|
cwd: this.projectPath,
|
|
1943
|
-
model: "claude-haiku-4-5-20251001"
|
|
1944
|
-
tools: ["Read", "Grep", "Glob", "Bash"]
|
|
1904
|
+
model: "claude-haiku-4-5-20251001"
|
|
1945
1905
|
});
|
|
1946
1906
|
let resolvedPath = "";
|
|
1947
1907
|
try {
|
|
@@ -2003,8 +1963,8 @@ class StashService {
|
|
|
2003
1963
|
let sourceCode = "";
|
|
2004
1964
|
const filePath = component?.filePath || "";
|
|
2005
1965
|
if (filePath && filePath !== "auto-detect") {
|
|
2006
|
-
const sourceFile =
|
|
2007
|
-
if (
|
|
1966
|
+
const sourceFile = join7(this.projectPath, filePath);
|
|
1967
|
+
if (existsSync7(sourceFile)) {
|
|
2008
1968
|
sourceCode = readFileSync3(sourceFile, "utf-8");
|
|
2009
1969
|
}
|
|
2010
1970
|
}
|
|
@@ -2356,8 +2316,8 @@ ${refDescriptions.join(`
|
|
|
2356
2316
|
}
|
|
2357
2317
|
|
|
2358
2318
|
// ../server/dist/services/activity-store.js
|
|
2359
|
-
import { appendFileSync as appendFileSync2, readFileSync as readFileSync4, existsSync as
|
|
2360
|
-
import { join as
|
|
2319
|
+
import { appendFileSync as appendFileSync2, readFileSync as readFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync5, rmSync as rmSync3 } from "fs";
|
|
2320
|
+
import { join as join8, dirname as dirname2 } from "path";
|
|
2361
2321
|
|
|
2362
2322
|
class ActivityStore {
|
|
2363
2323
|
cache = new Map;
|
|
@@ -2366,7 +2326,7 @@ class ActivityStore {
|
|
|
2366
2326
|
this.projectPath = projectPath;
|
|
2367
2327
|
}
|
|
2368
2328
|
jsonlPath(stashId) {
|
|
2369
|
-
return
|
|
2329
|
+
return join8(this.projectPath, ".stashes", "activity", `${stashId}.jsonl`);
|
|
2370
2330
|
}
|
|
2371
2331
|
append(event) {
|
|
2372
2332
|
const existing = this.cache.get(event.stashId) ?? [];
|
|
@@ -2374,8 +2334,8 @@ class ActivityStore {
|
|
|
2374
2334
|
this.cache.set(event.stashId, existing);
|
|
2375
2335
|
const filePath = this.jsonlPath(event.stashId);
|
|
2376
2336
|
const dir = dirname2(filePath);
|
|
2377
|
-
if (!
|
|
2378
|
-
|
|
2337
|
+
if (!existsSync8(dir))
|
|
2338
|
+
mkdirSync5(dir, { recursive: true });
|
|
2379
2339
|
appendFileSync2(filePath, JSON.stringify(event) + `
|
|
2380
2340
|
`, "utf-8");
|
|
2381
2341
|
}
|
|
@@ -2384,7 +2344,7 @@ class ActivityStore {
|
|
|
2384
2344
|
if (cached && cached.length > 0)
|
|
2385
2345
|
return cached;
|
|
2386
2346
|
const filePath = this.jsonlPath(stashId);
|
|
2387
|
-
if (!
|
|
2347
|
+
if (!existsSync8(filePath))
|
|
2388
2348
|
return [];
|
|
2389
2349
|
const lines = readFileSync4(filePath, "utf-8").trim().split(`
|
|
2390
2350
|
`).filter(Boolean);
|
|
@@ -2410,14 +2370,14 @@ class ActivityStore {
|
|
|
2410
2370
|
clear(stashId) {
|
|
2411
2371
|
this.cache.delete(stashId);
|
|
2412
2372
|
const filePath = this.jsonlPath(stashId);
|
|
2413
|
-
if (
|
|
2373
|
+
if (existsSync8(filePath)) {
|
|
2414
2374
|
rmSync3(filePath);
|
|
2415
2375
|
}
|
|
2416
2376
|
}
|
|
2417
2377
|
has(stashId) {
|
|
2418
2378
|
if (this.cache.has(stashId) && (this.cache.get(stashId)?.length ?? 0) > 0)
|
|
2419
2379
|
return true;
|
|
2420
|
-
return
|
|
2380
|
+
return existsSync8(this.jsonlPath(stashId));
|
|
2421
2381
|
}
|
|
2422
2382
|
}
|
|
2423
2383
|
|
|
@@ -2659,8 +2619,8 @@ app.get("/dev-server-status", async (c) => {
|
|
|
2659
2619
|
});
|
|
2660
2620
|
app.get("/screenshots/:filename", (c) => {
|
|
2661
2621
|
const filename = c.req.param("filename");
|
|
2662
|
-
const filePath =
|
|
2663
|
-
if (!
|
|
2622
|
+
const filePath = join9(serverState.projectPath, ".stashes", "screenshots", filename);
|
|
2623
|
+
if (!existsSync9(filePath))
|
|
2664
2624
|
return c.json({ error: "Not found" }, 404);
|
|
2665
2625
|
const content = readFileSync5(filePath);
|
|
2666
2626
|
return new Response(content, {
|
|
@@ -2712,12 +2672,12 @@ app2.route("/api", apiRoutes);
|
|
|
2712
2672
|
app2.get("/*", async (c) => {
|
|
2713
2673
|
const path = c.req.path;
|
|
2714
2674
|
const selfDir = dirname3(fileURLToPath(import.meta.url));
|
|
2715
|
-
const bundledWebDir =
|
|
2716
|
-
const monorepoWebDir =
|
|
2717
|
-
const webDistDir =
|
|
2675
|
+
const bundledWebDir = join10(selfDir, "web");
|
|
2676
|
+
const monorepoWebDir = join10(selfDir, "../../web/dist");
|
|
2677
|
+
const webDistDir = existsSync10(join10(bundledWebDir, "index.html")) ? bundledWebDir : monorepoWebDir;
|
|
2718
2678
|
const requestPath = path === "/" ? "/index.html" : path;
|
|
2719
|
-
const filePath =
|
|
2720
|
-
if (
|
|
2679
|
+
const filePath = join10(webDistDir, requestPath);
|
|
2680
|
+
if (existsSync10(filePath) && !filePath.includes("..")) {
|
|
2721
2681
|
const content = readFileSync6(filePath);
|
|
2722
2682
|
const ext = filePath.split(".").pop() || "";
|
|
2723
2683
|
const contentTypes = {
|
|
@@ -2736,8 +2696,8 @@ app2.get("/*", async (c) => {
|
|
|
2736
2696
|
headers: { "content-type": contentTypes[ext] || "application/octet-stream" }
|
|
2737
2697
|
});
|
|
2738
2698
|
}
|
|
2739
|
-
const indexPath =
|
|
2740
|
-
if (
|
|
2699
|
+
const indexPath = join10(webDistDir, "index.html");
|
|
2700
|
+
if (existsSync10(indexPath)) {
|
|
2741
2701
|
const html = readFileSync6(indexPath, "utf-8");
|
|
2742
2702
|
return new Response(html, {
|
|
2743
2703
|
headers: { "content-type": "text/html; charset=utf-8" }
|
|
@@ -2798,11 +2758,11 @@ async function startServer(projectPath, userDevPort, requestedPort = STASHES_POR
|
|
|
2798
2758
|
}
|
|
2799
2759
|
|
|
2800
2760
|
// ../server/dist/services/detector.js
|
|
2801
|
-
import { existsSync as
|
|
2802
|
-
import { join as
|
|
2761
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
2762
|
+
import { join as join11 } from "path";
|
|
2803
2763
|
function detectFramework(projectPath) {
|
|
2804
|
-
const packageJsonPath =
|
|
2805
|
-
if (!
|
|
2764
|
+
const packageJsonPath = join11(projectPath, "package.json");
|
|
2765
|
+
if (!existsSync11(packageJsonPath)) {
|
|
2806
2766
|
return {
|
|
2807
2767
|
framework: "unknown",
|
|
2808
2768
|
devCommand: "npm run dev",
|
|
@@ -2864,7 +2824,7 @@ function getDevCommand(packageJson, fallback) {
|
|
|
2864
2824
|
}
|
|
2865
2825
|
function findConfig(projectPath, candidates) {
|
|
2866
2826
|
for (const candidate of candidates) {
|
|
2867
|
-
if (
|
|
2827
|
+
if (existsSync11(join11(projectPath, candidate))) {
|
|
2868
2828
|
return candidate;
|
|
2869
2829
|
}
|
|
2870
2830
|
}
|
|
@@ -3056,8 +3016,8 @@ Cleaning up all stashes and worktrees...`);
|
|
|
3056
3016
|
}
|
|
3057
3017
|
|
|
3058
3018
|
// src/commands/setup.ts
|
|
3059
|
-
import { existsSync as
|
|
3060
|
-
import { dirname as dirname4, join as
|
|
3019
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync2, mkdirSync as mkdirSync6 } from "fs";
|
|
3020
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
3061
3021
|
import { homedir } from "os";
|
|
3062
3022
|
import * as p from "@clack/prompts";
|
|
3063
3023
|
import pc from "picocolors";
|
|
@@ -3076,60 +3036,60 @@ var MCP_ENTRY_ZED = {
|
|
|
3076
3036
|
};
|
|
3077
3037
|
function buildToolDefinitions() {
|
|
3078
3038
|
const home = homedir();
|
|
3079
|
-
const appSupport =
|
|
3039
|
+
const appSupport = join12(home, "Library", "Application Support");
|
|
3080
3040
|
return [
|
|
3081
3041
|
{
|
|
3082
3042
|
id: "claude-code",
|
|
3083
3043
|
name: "Claude Code",
|
|
3084
|
-
configPath:
|
|
3044
|
+
configPath: join12(home, ".claude.json"),
|
|
3085
3045
|
serversKey: "mcpServers",
|
|
3086
3046
|
format: "standard",
|
|
3087
|
-
detect: () =>
|
|
3047
|
+
detect: () => existsSync12(join12(home, ".claude.json")) || existsSync12(join12(home, ".claude"))
|
|
3088
3048
|
},
|
|
3089
3049
|
{
|
|
3090
3050
|
id: "claude-desktop",
|
|
3091
3051
|
name: "Claude Desktop",
|
|
3092
|
-
configPath:
|
|
3052
|
+
configPath: join12(appSupport, "Claude", "claude_desktop_config.json"),
|
|
3093
3053
|
serversKey: "mcpServers",
|
|
3094
3054
|
format: "standard",
|
|
3095
|
-
detect: () =>
|
|
3055
|
+
detect: () => existsSync12(join12(appSupport, "Claude")) || existsSync12("/Applications/Claude.app")
|
|
3096
3056
|
},
|
|
3097
3057
|
{
|
|
3098
3058
|
id: "vscode",
|
|
3099
3059
|
name: "VS Code",
|
|
3100
|
-
configPath:
|
|
3060
|
+
configPath: join12(appSupport, "Code", "User", "mcp.json"),
|
|
3101
3061
|
serversKey: "servers",
|
|
3102
3062
|
format: "standard",
|
|
3103
|
-
detect: () =>
|
|
3063
|
+
detect: () => existsSync12(join12(appSupport, "Code", "User"))
|
|
3104
3064
|
},
|
|
3105
3065
|
{
|
|
3106
3066
|
id: "cursor",
|
|
3107
3067
|
name: "Cursor",
|
|
3108
|
-
configPath:
|
|
3068
|
+
configPath: join12(home, ".cursor", "mcp.json"),
|
|
3109
3069
|
serversKey: "mcpServers",
|
|
3110
3070
|
format: "standard",
|
|
3111
|
-
detect: () =>
|
|
3071
|
+
detect: () => existsSync12(join12(home, ".cursor"))
|
|
3112
3072
|
},
|
|
3113
3073
|
{
|
|
3114
3074
|
id: "windsurf",
|
|
3115
3075
|
name: "Windsurf",
|
|
3116
|
-
configPath:
|
|
3076
|
+
configPath: join12(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
3117
3077
|
serversKey: "mcpServers",
|
|
3118
3078
|
format: "standard",
|
|
3119
|
-
detect: () =>
|
|
3079
|
+
detect: () => existsSync12(join12(home, ".codeium", "windsurf"))
|
|
3120
3080
|
},
|
|
3121
3081
|
{
|
|
3122
3082
|
id: "zed",
|
|
3123
3083
|
name: "Zed",
|
|
3124
|
-
configPath:
|
|
3084
|
+
configPath: join12(appSupport, "Zed", "settings.json"),
|
|
3125
3085
|
serversKey: "context_servers",
|
|
3126
3086
|
format: "zed",
|
|
3127
|
-
detect: () =>
|
|
3087
|
+
detect: () => existsSync12(join12(appSupport, "Zed"))
|
|
3128
3088
|
}
|
|
3129
3089
|
];
|
|
3130
3090
|
}
|
|
3131
3091
|
function readJsonFile(path) {
|
|
3132
|
-
if (!
|
|
3092
|
+
if (!existsSync12(path))
|
|
3133
3093
|
return {};
|
|
3134
3094
|
try {
|
|
3135
3095
|
const raw = readFileSync8(path, "utf-8").trim();
|
|
@@ -3141,8 +3101,8 @@ function readJsonFile(path) {
|
|
|
3141
3101
|
}
|
|
3142
3102
|
}
|
|
3143
3103
|
function writeJsonFile(path, data) {
|
|
3144
|
-
|
|
3145
|
-
|
|
3104
|
+
mkdirSync6(dirname4(path), { recursive: true });
|
|
3105
|
+
writeFileSync2(path, JSON.stringify(data, null, 2) + `
|
|
3146
3106
|
`);
|
|
3147
3107
|
}
|
|
3148
3108
|
function isConfigured(tool) {
|
|
@@ -3280,15 +3240,15 @@ async function setupCommand(options) {
|
|
|
3280
3240
|
|
|
3281
3241
|
// src/commands/update.ts
|
|
3282
3242
|
import { execFileSync, execSync } from "child_process";
|
|
3283
|
-
import { writeFileSync as
|
|
3284
|
-
import { tmpdir
|
|
3285
|
-
import { join as
|
|
3243
|
+
import { writeFileSync as writeFileSync3, unlinkSync, chmodSync, readFileSync as readFileSync9 } from "fs";
|
|
3244
|
+
import { tmpdir } from "os";
|
|
3245
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
3286
3246
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3287
3247
|
import * as p2 from "@clack/prompts";
|
|
3288
3248
|
import pc2 from "picocolors";
|
|
3289
3249
|
function getCurrentVersion() {
|
|
3290
3250
|
const selfDir = dirname5(fileURLToPath2(import.meta.url));
|
|
3291
|
-
const pkgPath =
|
|
3251
|
+
const pkgPath = join13(selfDir, "..", "package.json");
|
|
3292
3252
|
return JSON.parse(readFileSync9(pkgPath, "utf-8")).version;
|
|
3293
3253
|
}
|
|
3294
3254
|
function fetchLatestVersion() {
|
|
@@ -3365,8 +3325,8 @@ async function updateCommand() {
|
|
|
3365
3325
|
}
|
|
3366
3326
|
s.stop(`Removed from ${configuredTools.length} tool${configuredTools.length === 1 ? "" : "s"}`);
|
|
3367
3327
|
}
|
|
3368
|
-
const scriptPath =
|
|
3369
|
-
|
|
3328
|
+
const scriptPath = join13(tmpdir(), `stashes-update-${Date.now()}.sh`);
|
|
3329
|
+
writeFileSync3(scriptPath, buildUpdateScript(), "utf-8");
|
|
3370
3330
|
chmodSync(scriptPath, 493);
|
|
3371
3331
|
try {
|
|
3372
3332
|
execFileSync("bash", [scriptPath], { stdio: "inherit" });
|
|
@@ -3384,7 +3344,7 @@ Update failed. Try manually:`);
|
|
|
3384
3344
|
|
|
3385
3345
|
// src/index.ts
|
|
3386
3346
|
var selfDir = dirname6(fileURLToPath3(import.meta.url));
|
|
3387
|
-
var pkgPath =
|
|
3347
|
+
var pkgPath = join14(selfDir, "..", "package.json");
|
|
3388
3348
|
var version = JSON.parse(readFileSync10(pkgPath, "utf-8")).version;
|
|
3389
3349
|
var program = new Command;
|
|
3390
3350
|
program.name("stashes").description("Generate AI-powered UI design explorations in your project").version(version, "-v, --version");
|