@kw-yeh/vibeflow 4.0.2 → 4.0.4
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/README.md +14 -0
- package/dist/postinstall.mjs +57 -0
- package/dist/vibeflow.mjs +37 -6
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/chunks/{4270-6c9c75303137e3a5.js → 5896-9ec24bfe388d6661.js} +2 -2
- package/dist/web/_next/static/chunks/pages/{_app-320afeed07d86516.js → _app-fde992b12936b886.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-132f9ce2b08bd09d.js +11 -0
- package/dist/web/_next/static/css/5576c1267923e491.css +2 -0
- package/dist/web/_next/static/{2aQtkEcIfRS2Nbk-qwUwY → zygbxZW3DHGve5whWS7yR}/_buildManifest.js +1 -1
- package/dist/web/home/index.html +1 -1
- package/package.json +4 -1
- package/dist/web/_next/static/chunks/pages/home-efefddd4b88b018d.js +0 -11
- package/dist/web/_next/static/css/edcc6abb24dfd492.css +0 -2
- /package/dist/web/_next/static/{2aQtkEcIfRS2Nbk-qwUwY → zygbxZW3DHGve5whWS7yR}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -82,6 +82,20 @@ vibeflow doctor
|
|
|
82
82
|
npm i -g @kw-yeh/vibeflow@latest
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
### 安裝時出現 `EACCES: permission denied`
|
|
86
|
+
|
|
87
|
+
代表 npm 的全域目錄屬於系統管理員(從 nodejs.org 下載安裝檔裝 Node 時常見)。建議不要用 `sudo`,改成讓全域套件裝在你自己的家目錄:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mkdir -p ~/.npm-global
|
|
91
|
+
npm config set prefix ~/.npm-global
|
|
92
|
+
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
|
|
93
|
+
source ~/.zshrc
|
|
94
|
+
npm i -g @kw-yeh/vibeflow@latest
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
用 Homebrew(`brew install node`)或 [nvm](https://github.com/nvm-sh/nvm) 裝的 Node 本來就不需要 `sudo`。已經用 `sudo` 裝好也能正常使用;若 `vibeflow doctor` 回報終端機模組沒有執行權限,照它列出的 `sudo chmod +x …` 指令執行一次即可。
|
|
98
|
+
|
|
85
99
|
---
|
|
86
100
|
|
|
87
101
|
## 常用指令
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createRequire as __vfCreateRequire } from 'node:module';
|
|
2
|
+
const require = __vfCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// packages/core/src/pty-helper.ts
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { createRequire } from "module";
|
|
8
|
+
function nodePtyRoot() {
|
|
9
|
+
try {
|
|
10
|
+
return path.dirname(createRequire(import.meta.url).resolve("node-pty/package.json"));
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function ensurePtySpawnHelper(root = nodePtyRoot()) {
|
|
16
|
+
if (process.platform === "win32" || !root) return [];
|
|
17
|
+
const candidates = [
|
|
18
|
+
path.join(root, "build", "Release", "spawn-helper"),
|
|
19
|
+
path.join(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper")
|
|
20
|
+
];
|
|
21
|
+
const failures = [];
|
|
22
|
+
for (const file of candidates) {
|
|
23
|
+
let stat;
|
|
24
|
+
try {
|
|
25
|
+
stat = fs.statSync(file);
|
|
26
|
+
} catch {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
fs.accessSync(file, fs.constants.X_OK);
|
|
31
|
+
continue;
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
fs.chmodSync(file, stat.mode & 4095 | 73);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
const uid = process.getuid?.();
|
|
38
|
+
failures.push({ path: file, error: err.message, ownedByOther: uid !== void 0 && stat.uid !== uid });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return failures;
|
|
42
|
+
}
|
|
43
|
+
function spawnHelperFixCommand(failures) {
|
|
44
|
+
const sudo = failures.some((f) => f.ownedByOther) ? "sudo " : "";
|
|
45
|
+
return `${sudo}chmod +x ${failures.map((f) => `"${f.path}"`).join(" ")}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// packages/cli/src/postinstall.ts
|
|
49
|
+
try {
|
|
50
|
+
const failures = ensurePtySpawnHelper();
|
|
51
|
+
if (failures.length > 0) {
|
|
52
|
+
console.warn(`[vibeflow] node-pty spawn-helper \u7121\u6CD5\u8A2D\u70BA\u53EF\u57F7\u884C\uFF0C\u7D42\u7AEF\u6A5F\u6703\u7121\u6CD5\u555F\u52D5\u3002\u8ACB\u57F7\u884C\uFF1A
|
|
53
|
+
${spawnHelperFixCommand(failures)}`);
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.warn(`[vibeflow] postinstall \u7565\u904E\uFF1A${err.message}`);
|
|
57
|
+
}
|
package/dist/vibeflow.mjs
CHANGED
|
@@ -257,6 +257,11 @@ var init_pty = __esm({
|
|
|
257
257
|
scrollback(key) {
|
|
258
258
|
return this.scrollbacks.get(key) ?? null;
|
|
259
259
|
}
|
|
260
|
+
async isScrolledBack() {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
async scrollToBottom() {
|
|
264
|
+
}
|
|
260
265
|
shutdown() {
|
|
261
266
|
for (const key of Array.from(this.sessions.keys())) this.killNow(key);
|
|
262
267
|
}
|
|
@@ -416,6 +421,20 @@ var init_tmux_backend = __esm({
|
|
|
416
421
|
scrollback() {
|
|
417
422
|
return null;
|
|
418
423
|
}
|
|
424
|
+
/** The attached client sits on the alternate screen, so history is tmux copy-mode. */
|
|
425
|
+
async isScrolledBack(key) {
|
|
426
|
+
const { code: code2, stdout } = await this.tmux(
|
|
427
|
+
"display-message",
|
|
428
|
+
"-p",
|
|
429
|
+
"-t",
|
|
430
|
+
`=${this.sessionName(key)}:`,
|
|
431
|
+
"#{pane_in_mode}"
|
|
432
|
+
);
|
|
433
|
+
return code2 === 0 && stdout.trim() === "1";
|
|
434
|
+
}
|
|
435
|
+
async scrollToBottom(key) {
|
|
436
|
+
await this.tmux("send-keys", "-t", `=${this.sessionName(key)}:`, "-X", "cancel");
|
|
437
|
+
}
|
|
419
438
|
attachArgs(key) {
|
|
420
439
|
return ["-L", TMUX_SOCKET, "-f", this.confPath, "attach-session", "-t", `=${this.sessionName(key)}`];
|
|
421
440
|
}
|
|
@@ -1840,6 +1859,10 @@ function createBridge(t) {
|
|
|
1840
1859
|
resize: (sessionKey, cols, rows) => t.send("pty:resize", { sessionKey, cols, rows }),
|
|
1841
1860
|
/** Kill a task's PTY session (tears down the session and its watchers). */
|
|
1842
1861
|
kill: (sessionKey) => t.send("pty:kill", sessionKey),
|
|
1862
|
+
/** Whether the session's own history view (tmux copy-mode) is off the live output. */
|
|
1863
|
+
isScrolledBack: (sessionKey) => t.invoke("pty:scrolled", sessionKey),
|
|
1864
|
+
/** Return the session's own history view to the live output. */
|
|
1865
|
+
scrollToBottom: (sessionKey) => t.invoke("pty:scroll-bottom", sessionKey),
|
|
1843
1866
|
/** Whether the task's pinned Claude conversation already exists on disk. */
|
|
1844
1867
|
sessionExists: (taskId) => t.invoke("claude:sessionExists", taskId),
|
|
1845
1868
|
/**
|
|
@@ -1899,9 +1922,9 @@ function ensurePtySpawnHelper(root = nodePtyRoot()) {
|
|
|
1899
1922
|
];
|
|
1900
1923
|
const failures = [];
|
|
1901
1924
|
for (const file of candidates) {
|
|
1902
|
-
let
|
|
1925
|
+
let stat;
|
|
1903
1926
|
try {
|
|
1904
|
-
|
|
1927
|
+
stat = fs4.statSync(file);
|
|
1905
1928
|
} catch {
|
|
1906
1929
|
continue;
|
|
1907
1930
|
}
|
|
@@ -1911,13 +1934,18 @@ function ensurePtySpawnHelper(root = nodePtyRoot()) {
|
|
|
1911
1934
|
} catch {
|
|
1912
1935
|
}
|
|
1913
1936
|
try {
|
|
1914
|
-
fs4.chmodSync(file, mode & 4095 | 73);
|
|
1937
|
+
fs4.chmodSync(file, stat.mode & 4095 | 73);
|
|
1915
1938
|
} catch (err) {
|
|
1916
|
-
|
|
1939
|
+
const uid = process.getuid?.();
|
|
1940
|
+
failures.push({ path: file, error: err.message, ownedByOther: uid !== void 0 && stat.uid !== uid });
|
|
1917
1941
|
}
|
|
1918
1942
|
}
|
|
1919
1943
|
return failures;
|
|
1920
1944
|
}
|
|
1945
|
+
function spawnHelperFixCommand(failures) {
|
|
1946
|
+
const sudo = failures.some((f) => f.ownedByOther) ? "sudo " : "";
|
|
1947
|
+
return `${sudo}chmod +x ${failures.map((f) => `"${f.path}"`).join(" ")}`;
|
|
1948
|
+
}
|
|
1921
1949
|
|
|
1922
1950
|
// packages/cli/src/task-command.ts
|
|
1923
1951
|
import { parseArgs } from "node:util";
|
|
@@ -4936,6 +4964,9 @@ function createCore({ sessions, bus, version }) {
|
|
|
4936
4964
|
sessions.resize(requireSessionKey(p.sessionKey), p.cols, p.rows);
|
|
4937
4965
|
},
|
|
4938
4966
|
"pty:kill": (sessionKey) => teardownSession(requireSessionKey(sessionKey)),
|
|
4967
|
+
// History a frontend cannot scroll itself (tmux copy-mode).
|
|
4968
|
+
"pty:scrolled": (sessionKey) => sessions.isScrolledBack(requireSessionKey(sessionKey)),
|
|
4969
|
+
"pty:scroll-bottom": (sessionKey) => sessions.scrollToBottom(requireSessionKey(sessionKey)),
|
|
4939
4970
|
// Does the task's pinned Claude conversation exist on disk? Used to decide
|
|
4940
4971
|
// whether selecting a task may auto-resume (session present) or should
|
|
4941
4972
|
// leave the interactive terminal for manual commands.
|
|
@@ -5641,8 +5672,8 @@ async function checkNodePty() {
|
|
|
5641
5672
|
id: "node-pty",
|
|
5642
5673
|
name: "node-pty",
|
|
5643
5674
|
level: "fail",
|
|
5644
|
-
detail: `spawn-helper \u6C92\u6709\u57F7\u884C\u6B0A\u9650\uFF1A${unrepaired[0].error}`,
|
|
5645
|
-
fix: unrepaired
|
|
5675
|
+
detail: unrepaired.some((f) => f.ownedByOther) ? "spawn-helper \u6C92\u6709\u57F7\u884C\u6B0A\u9650\uFF0C\u800C\u4E14\u6A94\u6848\u5C6C\u65BC\u5176\u4ED6\u4F7F\u7528\u8005\uFF08\u901A\u5E38\u662F\u7528 sudo \u5168\u57DF\u5B89\u88DD\uFF09\uFF0CVibeFlow \u7121\u6CD5\u81EA\u884C\u4FEE\u6B63" : `spawn-helper \u6C92\u6709\u57F7\u884C\u6B0A\u9650\uFF1A${unrepaired[0].error}`,
|
|
5676
|
+
fix: spawnHelperFixCommand(unrepaired)
|
|
5646
5677
|
};
|
|
5647
5678
|
}
|
|
5648
5679
|
try {
|
package/dist/web/404/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href="/favicon.ico" sizes="any" data-next-head=""/><link rel="icon" href="/logo.svg" type="image/svg+xml" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon.png" data-next-head=""/><title data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href="/favicon.ico" sizes="any" data-next-head=""/><link rel="icon" href="/logo.svg" type="image/svg+xml" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon.png" data-next-head=""/><title data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/5576c1267923e491.css" as="style"/><link rel="stylesheet" href="/_next/static/css/5576c1267923e491.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-c8aa5df0425f6b7b.js" defer=""></script><script src="/_next/static/chunks/framework-b92a367cf1ad4bf7.js" defer=""></script><script src="/_next/static/chunks/main-ec7fd4c371d06729.js" defer=""></script><script src="/_next/static/chunks/pages/_app-fde992b12936b886.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/zygbxZW3DHGve5whWS7yR/_buildManifest.js" defer=""></script><script src="/_next/static/zygbxZW3DHGve5whWS7yR/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"zygbxZW3DHGve5whWS7yR","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
package/dist/web/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href="/favicon.ico" sizes="any" data-next-head=""/><link rel="icon" href="/logo.svg" type="image/svg+xml" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon.png" data-next-head=""/><title data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href="/favicon.ico" sizes="any" data-next-head=""/><link rel="icon" href="/logo.svg" type="image/svg+xml" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon.png" data-next-head=""/><title data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/5576c1267923e491.css" as="style"/><link rel="stylesheet" href="/_next/static/css/5576c1267923e491.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-c8aa5df0425f6b7b.js" defer=""></script><script src="/_next/static/chunks/framework-b92a367cf1ad4bf7.js" defer=""></script><script src="/_next/static/chunks/main-ec7fd4c371d06729.js" defer=""></script><script src="/_next/static/chunks/pages/_app-fde992b12936b886.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/zygbxZW3DHGve5whWS7yR/_buildManifest.js" defer=""></script><script src="/_next/static/zygbxZW3DHGve5whWS7yR/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"zygbxZW3DHGve5whWS7yR","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|