@kw-yeh/vibeflow 4.6.0 → 4.6.2

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 CHANGED
@@ -137,7 +137,7 @@ vibeflow task create … # 不開 UI 直接建卡,選項見 vibeflow tas
137
137
 
138
138
  VibeFlow 的本機伺服器能啟動 agent、寫入終端機,因此:
139
139
 
140
- - 只綁定 `127.0.0.1`/`::1`,使用隨機 port。
140
+ - 只綁定 `127.0.0.1`/`::1`,預設固定用 port 47820(被占用時改用隨機 port),瀏覽器的通知權限才不會在 host 重啟後失效。
141
141
  - 每次啟動產生一組 token,網址帶上它才能進入;載入後換成 HttpOnly、SameSite=Strict 的 cookie,並從網址列移除。
142
142
  - WebSocket 連線同時檢查 cookie 與 `Origin`,`Host` 必須是 loopback,其他網頁無法從你的瀏覽器連進來。
143
143
  - API 只接受 VibeFlow 認得的卡片 id,不接受任意路徑或指令。
package/dist/vibeflow.mjs CHANGED
@@ -5428,12 +5428,22 @@ var SINCE_SLACK_MS = 5e3;
5428
5428
  function claudeProjectDir(home, cwd) {
5429
5429
  return path20.join(home, ".claude", "projects", cwd.replace(/[^a-zA-Z0-9]/g, "-"));
5430
5430
  }
5431
+ function pathAliases(p) {
5432
+ const resolved = path20.resolve(p);
5433
+ try {
5434
+ const real = fs16.realpathSync(resolved);
5435
+ return real === resolved ? [resolved] : [resolved, real];
5436
+ } catch {
5437
+ return [resolved];
5438
+ }
5439
+ }
5431
5440
  function samePath(a, b) {
5432
5441
  const norm = (p) => {
5433
- const r = path20.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "");
5442
+ const r = p.replace(/\\/g, "/").replace(/\/+$/, "");
5434
5443
  return process.platform === "win32" ? r.toLowerCase() : r;
5435
5444
  };
5436
- return norm(a) === norm(b);
5445
+ const bs = pathAliases(b).map(norm);
5446
+ return pathAliases(a).some((x) => bs.includes(norm(x)));
5437
5447
  }
5438
5448
  function listFiles(dir, test) {
5439
5449
  try {
@@ -5520,8 +5530,8 @@ function createProgressTracker(opts) {
5520
5530
  const belongsToRun = (target, startedAt) => target.since == null || startedAt != null && startedAt >= target.since - SINCE_SLACK_MS;
5521
5531
  function discoverClaude(entry) {
5522
5532
  const { target } = entry;
5523
- const dir = claudeProjectDir(home, target.worktreePath);
5524
- for (const file of listFiles(dir, (n) => n.endsWith(".jsonl"))) {
5533
+ const dirs = pathAliases(target.worktreePath).map((p) => claudeProjectDir(home, p));
5534
+ for (const file of dirs.flatMap((dir) => listFiles(dir, (n) => n.endsWith(".jsonl")))) {
5525
5535
  if (entry.claude.has(file) || entry.rejected.has(file)) continue;
5526
5536
  const session = path20.basename(file, ".jsonl");
5527
5537
  if (session !== target.sessionId) {
@@ -6611,7 +6621,13 @@ Content-Length: 0\r
6611
6621
  });
6612
6622
  });
6613
6623
  }
6614
- const v4 = await listen("127.0.0.1", port);
6624
+ let v4;
6625
+ try {
6626
+ v4 = await listen("127.0.0.1", port);
6627
+ } catch (err) {
6628
+ if (!options.fallbackToFreePort || port === 0 || err.code !== "EADDRINUSE") throw err;
6629
+ v4 = await listen("127.0.0.1", 0);
6630
+ }
6615
6631
  servers.push(v4);
6616
6632
  port = v4.address().port;
6617
6633
  try {
@@ -6629,6 +6645,7 @@ Content-Length: 0\r
6629
6645
  }
6630
6646
 
6631
6647
  // packages/cli/src/host.ts
6648
+ var DEFAULT_HOST_PORT = 47820;
6632
6649
  async function waitForPort(userDataDir, timeoutMs = 1e4) {
6633
6650
  const deadline = Date.now() + timeoutMs;
6634
6651
  while (Date.now() < deadline) {
@@ -6687,7 +6704,8 @@ async function startHost(options) {
6687
6704
  bus,
6688
6705
  token: lock.token,
6689
6706
  staticDir: options.staticDir,
6690
- port: options.port
6707
+ port: options.port ?? DEFAULT_HOST_PORT,
6708
+ fallbackToFreePort: options.port === void 0
6691
6709
  });
6692
6710
  lock.port = server.port;
6693
6711
  updateLock(options.userDataDir, lock);
@@ -7015,7 +7033,7 @@ Options:
7015
7033
  --profile dev|prod Store profile (dev = the "(development)" store npm run dev uses)
7016
7034
  --store-path <dir> Explicit store directory
7017
7035
  --backend auto|tmux|pty Session backend for a new host (default: auto = tmux when installed)
7018
- --port <n> Port for a new host (default: random)
7036
+ --port <n> Port for a new host (default: 47820, or a free one when taken)
7019
7037
  --no-open Do not open a browser
7020
7038
  --json Machine-readable output (status)
7021
7039
  -v, --version Print the version
@@ -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/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_buildManifest.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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":"67i9UjSLB0D3UHnpZ00eV","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
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/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_buildManifest.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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":"1-jD1GlcBxcAPCb5OcjRK","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/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_buildManifest.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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":"67i9UjSLB0D3UHnpZ00eV","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
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/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/pages/_error-8f65b0f8749f42d2.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_buildManifest.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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":"1-jD1GlcBxcAPCb5OcjRK","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
@@ -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="">VibeFlow</title><link rel="preload" href="/_next/static/css/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/8527-5442098d5121c96b.js" defer=""></script><script src="/_next/static/chunks/pages/home-f31c4cf97ed808cf.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_buildManifest.js" defer=""></script><script src="/_next/static/67i9UjSLB0D3UHnpZ00eV/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="bg-background text-foreground"><div class="flex min-h-screen items-center justify-center bg-background text-base text-muted-foreground">載入中…</div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/home","query":{},"buildId":"67i9UjSLB0D3UHnpZ00eV","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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="">VibeFlow</title><link rel="preload" href="/_next/static/css/7b78ec950bc90c91.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7b78ec950bc90c91.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-d965862fbafe3116.js" defer=""></script><script src="/_next/static/chunks/8527-5442098d5121c96b.js" defer=""></script><script src="/_next/static/chunks/pages/home-f31c4cf97ed808cf.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_buildManifest.js" defer=""></script><script src="/_next/static/1-jD1GlcBxcAPCb5OcjRK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="bg-background text-foreground"><div class="flex min-h-screen items-center justify-center bg-background text-base text-muted-foreground">載入中…</div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/home","query":{},"buildId":"1-jD1GlcBxcAPCb5OcjRK","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kw-yeh/vibeflow",
3
- "version": "4.6.0",
3
+ "version": "4.6.2",
4
4
  "description": "Intent-driven local kanban for coding agents: git worktree per card, Web UI and TUI.",
5
5
  "license": "MIT",
6
6
  "author": "KW-Yeh",