vibeman 0.0.16 → 0.0.17

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.
Files changed (35) hide show
  1. package/dist/api.js +506 -82
  2. package/dist/commit.txt +1 -1
  3. package/dist/ui/assets/{index-CkMEKMtG.js → index-B0WvXt0J.js} +1 -1
  4. package/dist/ui/assets/index-B1LpYbIL.css +1 -0
  5. package/dist/ui/assets/{index-DRYG0hWl.js → index-B9j1Z7xH.js} +1 -1
  6. package/dist/ui/assets/index-BGSXwEof.js +1103 -0
  7. package/dist/ui/assets/{index-DJxs2IHl.js → index-BMvqb2S0.js} +1 -1
  8. package/dist/ui/assets/{index-Db2EhJOX.js → index-BaTjy202.js} +1 -1
  9. package/dist/ui/assets/{index-Dck1mk1E.js → index-Bf-sg7t1.js} +1 -1
  10. package/dist/ui/assets/{index-ssu5S1KA.js → index-BjP484xW.js} +1 -1
  11. package/dist/ui/assets/{index-mhz4dktY.js → index-CHaxebS-.js} +1 -1
  12. package/dist/ui/assets/{index-DARaaYLg.js → index-CM8fvy_3.js} +1 -1
  13. package/dist/ui/assets/{index-DErcnUD0.js → index-CgPm7uHs.js} +1 -1
  14. package/dist/ui/assets/{index-b2CKrEE6.js → index-CgR7ieU_.js} +1 -1
  15. package/dist/ui/assets/{index-DKTHpT6c.js → index-CmRfv-pq.js} +1 -1
  16. package/dist/ui/assets/{index-CnWjvgnt.js → index-DJPvnRwe.js} +1 -1
  17. package/dist/ui/assets/{index-DPgndyQt.js → index-DVUZnv4I.js} +1 -1
  18. package/dist/ui/assets/{index-B77m9jwg.js → index-DWOryZN1.js} +1 -1
  19. package/dist/ui/assets/{index-CpEU6Vxs.js → index-DhCgwoTQ.js} +1 -1
  20. package/dist/ui/assets/{index-B49cVd68.js → index-Dl7WFkDL.js} +1 -1
  21. package/dist/ui/assets/{index-C61bzN1F.js → index-DxYZT2Q7.js} +1 -1
  22. package/dist/ui/assets/{index-CHinfK5y.js → index-JyRtNGro.js} +1 -1
  23. package/dist/ui/assets/{index-Cl5D1lr0.js → index-RO6e7ud2.js} +1 -1
  24. package/dist/ui/assets/{index-CdwIPvvC.js → index-dZUCDdRl.js} +1 -1
  25. package/dist/ui/assets/{index-D_--wkOk.js → index-h0c542Uj.js} +1 -1
  26. package/dist/ui/assets/{index-D6YdKIji.js → index-qhLd2sra.js} +1 -1
  27. package/dist/ui/assets/vibeman-logo-on-dark-GVk_1Rmr.png +0 -0
  28. package/dist/ui/assets/vibeman-logo-on-light-4VCHa-wB.png +0 -0
  29. package/dist/ui/index.html +5 -2
  30. package/dist/ui/vibeman-apple-touch-icon.png +0 -0
  31. package/dist/ui/vibeman-favicon-16.png +0 -0
  32. package/dist/ui/vibeman-favicon-32.png +0 -0
  33. package/package.json +1 -1
  34. package/dist/ui/assets/index-CEeUnKFj.js +0 -1101
  35. package/dist/ui/assets/index-DcDF1o3A.css +0 -1
package/dist/api.js CHANGED
@@ -54569,22 +54569,18 @@ async function getRepoDirtyBeforeWorktreeCreateMessage(repoRoot, worktreePath, g
54569
54569
  }
54570
54570
  const { branch, lines, suffix } = await readGitStatusDetails(gitService);
54571
54571
  return [
54572
- "Cannot create a new task worktree because the repository root has uncommitted changes.",
54572
+ "Cannot create a new task worktree while the repository root has uncommitted changes.",
54573
54573
  "",
54574
- "Why this happens:",
54575
- "A new worktree starts from the latest committed state. Uncommitted changes in the main repository are not copied into the new worktree, so it would open with stale code.",
54574
+ "A new worktree starts from the latest committed state. Any uncommitted repository root changes would be missing from the new task worktree.",
54576
54575
  "",
54577
- "How to fix:",
54578
- "- Commit the changes in the main repository, or",
54579
- "- Stash them if you are not ready to commit, or",
54580
- "- Discard them if they are no longer needed.",
54576
+ "Use the header Commit Changes button to review and commit the repository root changes.",
54577
+ "If you are not ready to commit, stash or discard the root changes first.",
54578
+ "Retry creating the worktree after the repository root is clean.",
54581
54579
  "",
54582
- "Then try creating the worktree again.",
54583
- "",
54584
- `Planned worktree:
54585
- ${worktreePath}`,
54586
54580
  `Repository root:
54587
54581
  ${repoRoot}`,
54582
+ `Planned worktree:
54583
+ ${worktreePath}`,
54588
54584
  `Branch:
54589
54585
  ${branch}`,
54590
54586
  `Changes:
@@ -55694,6 +55690,7 @@ async function listLatestTaskWorkflowStatusByTaskId(db, taskIds) {
55694
55690
  taskId,
55695
55691
  workflowType,
55696
55692
  status,
55693
+ updatedAt,
55697
55694
  ROW_NUMBER() OVER (
55698
55695
  PARTITION BY taskId, workflowType
55699
55696
  ORDER BY updatedAt DESC, createdAt DESC, runId DESC
@@ -55703,7 +55700,7 @@ async function listLatestTaskWorkflowStatusByTaskId(db, taskIds) {
55703
55700
  AND taskId <> ''
55704
55701
  ${taskFilterSql}
55705
55702
  )
55706
- SELECT taskId, workflowType, status
55703
+ SELECT taskId, workflowType, status, updatedAt
55707
55704
  FROM ranked_runs
55708
55705
  WHERE rownum = 1
55709
55706
  ORDER BY taskId ASC, workflowType ASC
@@ -55723,7 +55720,8 @@ async function listLatestTaskWorkflowStatusByTaskId(db, taskIds) {
55723
55720
  }
55724
55721
  statusByTaskId[row.taskId]?.push({
55725
55722
  workflowType,
55726
- status
55723
+ status,
55724
+ updatedAt: row.updatedAt instanceof Date ? row.updatedAt.toISOString() : String(row.updatedAt)
55727
55725
  });
55728
55726
  }
55729
55727
  for (const taskId of Object.keys(statusByTaskId)) {
@@ -59532,9 +59530,10 @@ var init_model_aliases = __esm(() => {
59532
59530
  });
59533
59531
 
59534
59532
  // ../api/src/services/agents/runtime-backend.ts
59535
- import { mkdir as mkdir2 } from "node:fs/promises";
59533
+ import { existsSync as existsSync13 } from "node:fs";
59534
+ import { mkdir as mkdir2, lstat, readdir as readdir2, readlink, rm, symlink } from "node:fs/promises";
59536
59535
  import { tmpdir } from "node:os";
59537
- import { join as join4 } from "node:path";
59536
+ import { dirname as dirname4, join as join4, resolve as resolvePath4 } from "node:path";
59538
59537
  function isPlainObject4(value) {
59539
59538
  return typeof value === "object" && value !== null && !Array.isArray(value);
59540
59539
  }
@@ -59793,6 +59792,45 @@ async function applyClaudeRuntimeIsolation(request, env) {
59793
59792
  XDG_DATA_HOME: xdgDataHome
59794
59793
  };
59795
59794
  }
59795
+ function resolveCodexHome(env) {
59796
+ const configured = env.CODEX_HOME?.trim();
59797
+ if (configured) {
59798
+ return resolvePath4(configured);
59799
+ }
59800
+ const home = env.HOME?.trim();
59801
+ if (!home) {
59802
+ return;
59803
+ }
59804
+ return resolvePath4(home, ".codex");
59805
+ }
59806
+ async function ensureSymlinkTarget(targetPath, sourcePath) {
59807
+ try {
59808
+ const stats = await lstat(targetPath);
59809
+ if (stats.isSymbolicLink()) {
59810
+ const existingTarget = await readlink(targetPath);
59811
+ if (resolvePath4(dirname4(targetPath), existingTarget) === resolvePath4(sourcePath)) {
59812
+ return;
59813
+ }
59814
+ }
59815
+ await rm(targetPath, { recursive: true, force: true });
59816
+ } catch {}
59817
+ await symlink(sourcePath, targetPath);
59818
+ }
59819
+ async function applyCodexRuntimeIsolation(request, env) {
59820
+ const sourceCodexHome = resolveCodexHome(env);
59821
+ if (!sourceCodexHome || !existsSync13(sourceCodexHome)) {
59822
+ return env;
59823
+ }
59824
+ const runId = toSafePathSegment(request.runId);
59825
+ const isolationRoot = join4(tmpdir(), "vibeman", "runtime", "runs", runId, "codex-home");
59826
+ await mkdir2(isolationRoot, { recursive: true });
59827
+ const entries = await readdir2(sourceCodexHome, { withFileTypes: true });
59828
+ await Promise.all(entries.filter((entry) => entry.name !== "superpowers").map((entry) => ensureSymlinkTarget(join4(isolationRoot, entry.name), join4(sourceCodexHome, entry.name))));
59829
+ return {
59830
+ ...env,
59831
+ CODEX_HOME: isolationRoot
59832
+ };
59833
+ }
59796
59834
  function shouldIsolateClaudeRuntime(env) {
59797
59835
  const anthropicAuthToken = env.ANTHROPIC_AUTH_TOKEN?.trim();
59798
59836
  const anthropicApiKey = env.ANTHROPIC_API_KEY?.trim();
@@ -59865,6 +59903,9 @@ async function compileAgentExecutionPlan(db, request) {
59865
59903
  ...resolvedLegacyEnv,
59866
59904
  ...resolvedOverrideEnv
59867
59905
  };
59906
+ if (provider === "codex-cli") {
59907
+ env = await applyCodexRuntimeIsolation(request, env);
59908
+ }
59868
59909
  if (provider === "claude-code" && shouldIsolateClaudeRuntime(env)) {
59869
59910
  env = await applyClaudeRuntimeIsolation(request, env);
59870
59911
  }
@@ -60082,22 +60123,22 @@ var init_agents = __esm(() => {
60082
60123
 
60083
60124
  // ../api/src/services/env-symlinks.ts
60084
60125
  import { spawnSync } from "node:child_process";
60085
- import { existsSync as existsSync13 } from "node:fs";
60086
- import { lstat, readlink, readdir as readdir2, symlink } from "node:fs/promises";
60087
- import { dirname as dirname4, normalize as normalize5, resolve as resolve12 } from "node:path";
60126
+ import { existsSync as existsSync14 } from "node:fs";
60127
+ import { lstat as lstat2, readlink as readlink2, readdir as readdir3, symlink as symlink2 } from "node:fs/promises";
60128
+ import { dirname as dirname5, normalize as normalize5, resolve as resolve12 } from "node:path";
60088
60129
  async function ensureEnvSymlinks(options2) {
60089
60130
  const log = logger.child({ module: "env-symlinks", ...options2.logContext });
60090
- if (!existsSync13(options2.repoRoot)) {
60131
+ if (!existsSync14(options2.repoRoot)) {
60091
60132
  log.warn({ repoRoot: options2.repoRoot }, "Repo root does not exist; skipping env symlinks.");
60092
60133
  return;
60093
60134
  }
60094
- if (!existsSync13(options2.targetRoot)) {
60135
+ if (!existsSync14(options2.targetRoot)) {
60095
60136
  log.warn({ targetRoot: options2.targetRoot }, "Target root does not exist; skipping env symlinks.");
60096
60137
  return;
60097
60138
  }
60098
60139
  let entries;
60099
60140
  try {
60100
- entries = await readdir2(options2.repoRoot);
60141
+ entries = await readdir3(options2.repoRoot);
60101
60142
  } catch (error48) {
60102
60143
  log.warn({ error: error48 }, "Failed to read repo root for env symlinks.");
60103
60144
  return;
@@ -60116,7 +60157,7 @@ async function ensureEnvSymlinks(options2) {
60116
60157
  const sourcePath = resolve12(options2.repoRoot, name2);
60117
60158
  const targetPath = resolve12(options2.targetRoot, name2);
60118
60159
  try {
60119
- const sourceStat = await lstat(sourcePath);
60160
+ const sourceStat = await lstat2(sourcePath);
60120
60161
  if (!sourceStat.isFile()) {
60121
60162
  log.info({ file: name2 }, "Skipping env entry that is not a regular file.");
60122
60163
  continue;
@@ -60140,10 +60181,10 @@ function isGitIgnored(repoRoot, relativePath, log) {
60140
60181
  }
60141
60182
  async function ensureSymlink(sourcePath, targetPath, log, filename) {
60142
60183
  try {
60143
- const existing = await lstat(targetPath);
60184
+ const existing = await lstat2(targetPath);
60144
60185
  if (existing.isSymbolicLink()) {
60145
- const linkTarget = await readlink(targetPath);
60146
- const resolvedTarget = normalize5(resolve12(dirname4(targetPath), linkTarget));
60186
+ const linkTarget = await readlink2(targetPath);
60187
+ const resolvedTarget = normalize5(resolve12(dirname5(targetPath), linkTarget));
60147
60188
  const resolvedSource = normalize5(resolve12(sourcePath));
60148
60189
  if (resolvedTarget === resolvedSource) {
60149
60190
  return;
@@ -60160,7 +60201,7 @@ async function ensureSymlink(sourcePath, targetPath, log, filename) {
60160
60201
  }
60161
60202
  }
60162
60203
  try {
60163
- await symlink(sourcePath, targetPath, "file");
60204
+ await symlink2(sourcePath, targetPath, "file");
60164
60205
  } catch (error48) {
60165
60206
  log.warn({ error: error48, file: filename, target: targetPath }, "Failed to create env symlink.");
60166
60207
  }
@@ -102232,7 +102273,7 @@ var init_prompt_builder = __esm(() => {
102232
102273
  // ../api/src/services/workflows/executor.ts
102233
102274
  import { spawn as spawn5 } from "node:child_process";
102234
102275
  import { readFileSync as readFileSync4 } from "node:fs";
102235
- import { resolve as resolvePath4 } from "node:path";
102276
+ import { resolve as resolvePath5 } from "node:path";
102236
102277
  function createExecutorControl() {
102237
102278
  const abortController = new AbortController;
102238
102279
  let child = null;
@@ -103132,7 +103173,7 @@ function normalizeEnvPath(raw2) {
103132
103173
  const trimmed2 = raw2.trim();
103133
103174
  if (trimmed2.length === 0)
103134
103175
  return null;
103135
- return resolvePath4(trimmed2);
103176
+ return resolvePath5(trimmed2);
103136
103177
  }
103137
103178
  function summarizeShellFailure(command, result) {
103138
103179
  const SNIPPET_LINES = 30;
@@ -107968,10 +108009,11 @@ var init_remote_access = __esm(() => {
107968
108009
  });
107969
108010
 
107970
108011
  // ../api/src/server/routes/system.ts
107971
- import { spawn as spawn7 } from "node:child_process";
107972
- import { resolve as resolve18, relative as relative7, sep as sep3 } from "node:path";
107973
- import { access as access3 } from "node:fs/promises";
107974
- import { homedir as homedir2 } from "node:os";
108012
+ import { execFile as execFile5, spawn as spawn7 } from "node:child_process";
108013
+ import { resolve as resolve18, relative as relative7, sep as sep3, join as join6, extname } from "node:path";
108014
+ import { access as access3, mkdtemp, readFile as readFile6, rm as rm2 } from "node:fs/promises";
108015
+ import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
108016
+ import { promisify as promisify2 } from "node:util";
107975
108017
  function isWithin2(rootPath, targetPath) {
107976
108018
  const relativePath = relative7(rootPath, targetPath);
107977
108019
  return relativePath === "" || !relativePath.startsWith("..") && !relativePath.startsWith(`..${sep3}`);
@@ -108003,11 +108045,108 @@ async function isAnyDetectionPathAccessible(paths) {
108003
108045
  }
108004
108046
  return false;
108005
108047
  }
108048
+ async function resolveAccessibleDetectionPath(paths) {
108049
+ for (const rawPath of paths) {
108050
+ const candidate = resolveDetectionPath(rawPath);
108051
+ try {
108052
+ await access3(candidate);
108053
+ return candidate;
108054
+ } catch {}
108055
+ }
108056
+ return null;
108057
+ }
108058
+ function normalizeIconFileName(value) {
108059
+ if (typeof value !== "string" || value.trim().length === 0)
108060
+ return null;
108061
+ const trimmed2 = value.trim();
108062
+ return extname(trimmed2) ? trimmed2 : `${trimmed2}.icns`;
108063
+ }
108064
+ function extractIconFileName(plist) {
108065
+ const directCandidates = [
108066
+ plist.CFBundleIconFile,
108067
+ plist.CFBundleIconName,
108068
+ plist.CFBundlePrimaryIcon?.CFBundleIconFile
108069
+ ];
108070
+ for (const candidate of directCandidates) {
108071
+ const normalized = normalizeIconFileName(candidate);
108072
+ if (normalized)
108073
+ return normalized;
108074
+ }
108075
+ const bundleIcons = plist.CFBundleIcons;
108076
+ if (bundleIcons && typeof bundleIcons === "object") {
108077
+ const primaryIcon = bundleIcons.CFBundlePrimaryIcon;
108078
+ if (primaryIcon && typeof primaryIcon === "object") {
108079
+ const iconFiles = primaryIcon.CFBundleIconFiles;
108080
+ if (Array.isArray(iconFiles)) {
108081
+ for (const candidate of [...iconFiles].reverse()) {
108082
+ const normalized = normalizeIconFileName(candidate);
108083
+ if (normalized)
108084
+ return normalized;
108085
+ }
108086
+ }
108087
+ }
108088
+ }
108089
+ return null;
108090
+ }
108091
+ function toDataUrl(buffer, extension) {
108092
+ const normalized = extension.toLowerCase();
108093
+ if (normalized === ".svg") {
108094
+ return `data:image/svg+xml;base64,${buffer.toString("base64")}`;
108095
+ }
108096
+ if (normalized === ".jpg" || normalized === ".jpeg") {
108097
+ return `data:image/jpeg;base64,${buffer.toString("base64")}`;
108098
+ }
108099
+ return `data:image/png;base64,${buffer.toString("base64")}`;
108100
+ }
108101
+ async function convertIcnsToPngDataUrl(iconPath) {
108102
+ const tempDir = await mkdtemp(join6(tmpdir2(), "vibeman-app-icon-"));
108103
+ const pngPath = join6(tempDir, "icon.png");
108104
+ try {
108105
+ await execFileAsync2("sips", ["-s", "format", "png", iconPath, "--out", pngPath]);
108106
+ const pngBuffer = await readFile6(pngPath);
108107
+ return toDataUrl(pngBuffer, ".png");
108108
+ } finally {
108109
+ await rm2(tempDir, { recursive: true, force: true });
108110
+ }
108111
+ }
108112
+ async function readAppIconDataUrl(appPath) {
108113
+ const cached2 = appIconCache.get(appPath);
108114
+ if (cached2 !== undefined)
108115
+ return cached2;
108116
+ const infoPlistPath = join6(appPath, "Contents", "Info.plist");
108117
+ try {
108118
+ const { stdout } = await execFileAsync2("plutil", [
108119
+ "-convert",
108120
+ "json",
108121
+ "-o",
108122
+ "-",
108123
+ infoPlistPath
108124
+ ]);
108125
+ const plist = JSON.parse(stdout);
108126
+ const iconFileName = extractIconFileName(plist);
108127
+ if (!iconFileName) {
108128
+ appIconCache.set(appPath, null);
108129
+ return null;
108130
+ }
108131
+ const iconPath = join6(appPath, "Contents", "Resources", iconFileName);
108132
+ await access3(iconPath);
108133
+ const extension = extname(iconPath).toLowerCase();
108134
+ const dataUrl = extension === ".icns" ? await convertIcnsToPngDataUrl(iconPath) : toDataUrl(await readFile6(iconPath), extension);
108135
+ appIconCache.set(appPath, dataUrl);
108136
+ return dataUrl;
108137
+ } catch {
108138
+ appIconCache.set(appPath, null);
108139
+ return null;
108140
+ }
108141
+ }
108006
108142
  async function listAvailableApps(category) {
108007
108143
  const defs = appCatalog.filter((app) => app.category === category);
108008
108144
  const results = await Promise.all(defs.map(async (app) => {
108009
- const installed = await isAnyDetectionPathAccessible(app.detectionPaths);
108010
- return installed ? { id: app.id, label: app.label } : null;
108145
+ const installedPath = await resolveAccessibleDetectionPath(app.detectionPaths);
108146
+ if (!installedPath)
108147
+ return null;
108148
+ const iconDataUrl = await readAppIconDataUrl(installedPath);
108149
+ return { id: app.id, label: app.label, iconDataUrl };
108011
108150
  }));
108012
108151
  return results.filter(Boolean);
108013
108152
  }
@@ -108059,7 +108198,7 @@ async function openInApp(appName, targetPath) {
108059
108198
  });
108060
108199
  });
108061
108200
  }
108062
- var appCategories, appCatalog, systemRouter;
108201
+ var appCategories, execFileAsync2, appIconCache, appCatalog, systemRouter;
108063
108202
  var init_system2 = __esm(() => {
108064
108203
  init_dist4();
108065
108204
  init_zod();
@@ -108067,6 +108206,8 @@ var init_system2 = __esm(() => {
108067
108206
  init_env_policy();
108068
108207
  init_remote_access();
108069
108208
  appCategories = ["terminal", "editor"];
108209
+ execFileAsync2 = promisify2(execFile5);
108210
+ appIconCache = new Map;
108070
108211
  appCatalog = [
108071
108212
  {
108072
108213
  id: "warp",
@@ -108113,6 +108254,13 @@ var init_system2 = __esm(() => {
108113
108254
  openAppName: "Antigravity",
108114
108255
  detectionPaths: ["/Applications/Antigravity.app", "~/Applications/Antigravity.app"]
108115
108256
  },
108257
+ {
108258
+ id: "zed",
108259
+ category: "editor",
108260
+ label: "Zed",
108261
+ openAppName: "Zed",
108262
+ detectionPaths: ["/Applications/Zed.app", "~/Applications/Zed.app"]
108263
+ },
108116
108264
  {
108117
108265
  id: "vscode",
108118
108266
  category: "editor",
@@ -108310,7 +108458,7 @@ var init_system2 = __esm(() => {
108310
108458
 
108311
108459
  // ../api/src/services/assets.ts
108312
108460
  import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
108313
- import { extname, resolve as resolve19, sep as sep4 } from "node:path";
108461
+ import { extname as extname2, resolve as resolve19, sep as sep4 } from "node:path";
108314
108462
  import { randomUUID } from "node:crypto";
108315
108463
  function getImagesDir(rootPath) {
108316
108464
  return resolve19(rootPath, ".vibeman/assets/images");
@@ -108322,7 +108470,7 @@ async function writeImageAsset(options2) {
108322
108470
  const imagesDir = getImagesDir(options2.rootPath);
108323
108471
  await mkdir4(imagesDir, { recursive: true });
108324
108472
  const extFromMime = imageMimeToExt[options2.mimeType] ?? null;
108325
- const extFromNameRaw = options2.originalName ? sanitizeExt(extname(options2.originalName)) : null;
108473
+ const extFromNameRaw = options2.originalName ? sanitizeExt(extname2(options2.originalName)) : null;
108326
108474
  const extFromName = extFromNameRaw ? imageExtAliases[extFromNameRaw] ?? null : null;
108327
108475
  const ext = extFromMime ?? extFromName ?? null;
108328
108476
  if (!ext) {
@@ -108647,12 +108795,12 @@ var init_model_catalog = __esm(() => {
108647
108795
  });
108648
108796
 
108649
108797
  // ../api/src/server/routes/cli-settings.ts
108650
- import { delimiter as delimiter4, dirname as dirname5 } from "node:path";
108798
+ import { delimiter as delimiter4, dirname as dirname6 } from "node:path";
108651
108799
  function withExecutableOnPath(env, executable) {
108652
108800
  if (!executable) {
108653
108801
  return env;
108654
108802
  }
108655
- const dir = dirname5(executable);
108803
+ const dir = dirname6(executable);
108656
108804
  const basePath = env.PATH ?? process.env.PATH ?? "";
108657
108805
  const combined = [dir, basePath].filter(Boolean).join(delimiter4);
108658
108806
  return { ...env, PATH: combined };
@@ -112852,7 +113000,7 @@ var init_github = __esm(() => {
112852
113000
  });
112853
113001
 
112854
113002
  // ../api/src/services/integrations/github-sync.ts
112855
- import { join as join6, resolve as resolve20 } from "node:path";
113003
+ import { join as join7, resolve as resolve20 } from "node:path";
112856
113004
  import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
112857
113005
  function mapIssueStateToTaskStatus(state2) {
112858
113006
  return state2 === "open" ? "backlog" : "done";
@@ -112873,7 +113021,7 @@ async function findTaskForIssue(rootPath, owner, repo, issueNumber) {
112873
113021
  continue;
112874
113022
  }
112875
113023
  try {
112876
- const content = await readFileContent(rootPath, join6(tasksPath, file2.name));
113024
+ const content = await readFileContent(rootPath, join7(tasksPath, file2.name));
112877
113025
  const parsed = import_gray_matter3.default(content);
112878
113026
  if (isTaskLinkedToIssue(parsed.data, owner, repo, issueNumber)) {
112879
113027
  return {
@@ -112923,7 +113071,7 @@ async function syncIssueToTask(rootPath, owner, repo, issue2, options2) {
112923
113071
  };
112924
113072
  const content = import_gray_matter3.default.stringify(taskBody, updatedFrontmatter, frontmatterYamlOptions2);
112925
113073
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
112926
- await writeFile6(join6(tasksDir, existingTask.filename), content);
113074
+ await writeFile6(join7(tasksDir, existingTask.filename), content);
112927
113075
  return { action: "updated", filename: existingTask.filename };
112928
113076
  } else {
112929
113077
  const taskId = generateTaskIdFromIssue(issue2);
@@ -112943,7 +113091,7 @@ async function syncIssueToTask(rootPath, owner, repo, issue2, options2) {
112943
113091
  const content = import_gray_matter3.default.stringify(taskBody, frontmatter, frontmatterYamlOptions2);
112944
113092
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
112945
113093
  await mkdir5(tasksDir, { recursive: true });
112946
- await writeFile6(join6(tasksDir, filename), content);
113094
+ await writeFile6(join7(tasksDir, filename), content);
112947
113095
  return { action: "created", filename };
112948
113096
  }
112949
113097
  }
@@ -113008,7 +113156,7 @@ async function syncTaskToGitHub(db, rootPath, taskFilename) {
113008
113156
  throw new Error("GitHub integration is not configured");
113009
113157
  }
113010
113158
  const tasksPath = ".vibeman/tasks";
113011
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113159
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113012
113160
  const parsed = import_gray_matter3.default(content);
113013
113161
  const githubRepo = parsed.data.github_repo;
113014
113162
  const githubIssueNumberRaw = parsed.data.github_issue_number;
@@ -113037,7 +113185,7 @@ async function syncTaskToGitHub(db, rootPath, taskFilename) {
113037
113185
  };
113038
113186
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113039
113187
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113040
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113188
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113041
113189
  }
113042
113190
  async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113043
113191
  const config2 = await getGitHubConfig(db);
@@ -113045,7 +113193,7 @@ async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113045
113193
  throw new Error("GitHub integration is not configured");
113046
113194
  }
113047
113195
  const tasksPath = ".vibeman/tasks";
113048
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113196
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113049
113197
  const parsed = import_gray_matter3.default(content);
113050
113198
  const githubRepo = parsed.data.github_repo;
113051
113199
  const githubIssueNumberRaw = parsed.data.github_issue_number;
@@ -113065,7 +113213,7 @@ async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113065
113213
  }
113066
113214
  async function linkTaskToGitHubIssue(rootPath, taskFilename, owner, repo, issueNumber, issueUrl) {
113067
113215
  const tasksPath = ".vibeman/tasks";
113068
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113216
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113069
113217
  const parsed = import_gray_matter3.default(content);
113070
113218
  const repoIdentifier = `${owner}/${repo}`;
113071
113219
  const githubMetadata = {
@@ -113081,11 +113229,11 @@ async function linkTaskToGitHubIssue(rootPath, taskFilename, owner, repo, issueN
113081
113229
  };
113082
113230
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113083
113231
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113084
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113232
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113085
113233
  }
113086
113234
  async function unlinkTaskFromGitHubIssue(rootPath, taskFilename) {
113087
113235
  const tasksPath = ".vibeman/tasks";
113088
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113236
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113089
113237
  const parsed = import_gray_matter3.default(content);
113090
113238
  const updatedFrontmatter = { ...parsed.data };
113091
113239
  delete updatedFrontmatter.github_repo;
@@ -113095,7 +113243,7 @@ async function unlinkTaskFromGitHubIssue(rootPath, taskFilename) {
113095
113243
  updatedFrontmatter.updated_at = new Date().toISOString();
113096
113244
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113097
113245
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113098
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113246
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113099
113247
  }
113100
113248
  var import_gray_matter3, stringifyOptions, parseTimestamp = (value) => {
113101
113249
  if (typeof value !== "string")
@@ -113127,7 +113275,7 @@ var import_gray_matter3, stringifyOptions, parseTimestamp = (value) => {
113127
113275
  continue;
113128
113276
  }
113129
113277
  try {
113130
- const content = await readFileContent(rootPath, join6(tasksPath, file2.name));
113278
+ const content = await readFileContent(rootPath, join7(tasksPath, file2.name));
113131
113279
  const parsed = import_gray_matter3.default(content);
113132
113280
  if (!shouldPushTaskToGitHub(parsed.data, owner, repo))
113133
113281
  continue;
@@ -113358,9 +113506,283 @@ var init_github3 = __esm(() => {
113358
113506
  });
113359
113507
  });
113360
113508
 
113509
+ // ../api/src/services/feedback.ts
113510
+ function shouldRedactUnixPath(path3) {
113511
+ if (path3 === "~")
113512
+ return false;
113513
+ return path3.startsWith("~/") || path3.startsWith("/");
113514
+ }
113515
+ function isSensitiveEnvKey(key) {
113516
+ return /(token|secret|password|passwd|auth|session|cookie|api_?key)/i.test(key);
113517
+ }
113518
+ function sanitizeText(value) {
113519
+ return value.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[REDACTED_EMAIL]").replace(/\b(Bearer\s+)[A-Za-z0-9._\-]+/gi, "$1[REDACTED_TOKEN]").replace(/\b(sk-[A-Za-z0-9]{12,})\b/g, "[REDACTED_TOKEN]").replace(/\b(gh[pousr]_[A-Za-z0-9]{12,})\b/g, "[REDACTED_TOKEN]").replace(/\b(github_pat_[A-Za-z0-9_]{20,})\b/g, "[REDACTED_TOKEN]").replace(/\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, "[REDACTED_TOKEN]").replace(ABSOLUTE_WINDOWS_PATH_PATTERN, (_, prefix, path3) => {
113520
+ return `${prefix}[REDACTED_PATH]`;
113521
+ }).replace(ABSOLUTE_UNIX_PATH_PATTERN, (_, prefix, path3) => {
113522
+ return shouldRedactUnixPath(path3) ? `${prefix}[REDACTED_PATH]` : `${prefix}${path3}`;
113523
+ }).replace(ENV_ASSIGNMENT_PATTERN, (match, key) => {
113524
+ return isSensitiveEnvKey(key) ? `${key}=[REDACTED_TOKEN]` : match;
113525
+ });
113526
+ }
113527
+ function collapseBlankLines(value) {
113528
+ return value.replace(/\n{3,}/g, `
113529
+
113530
+ `).trim();
113531
+ }
113532
+ function sanitizeFeedbackText(value) {
113533
+ return collapseBlankLines(sanitizeText(value.trim()));
113534
+ }
113535
+ function sanitizeBrowserFeedbackContext(input) {
113536
+ if (!input)
113537
+ return;
113538
+ const entries = Object.entries(input).flatMap(([key, value]) => {
113539
+ if (typeof value !== "string")
113540
+ return [];
113541
+ const sanitized = sanitizeFeedbackText(value);
113542
+ return sanitized ? [[key, sanitized]] : [];
113543
+ });
113544
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
113545
+ }
113546
+ function fallbackTitleFromBody(body) {
113547
+ const line = body.split(`
113548
+ `).map((entry) => entry.trim()).find((entry) => entry.length > 0 && !entry.startsWith("#") && !entry.startsWith("- "));
113549
+ if (!line)
113550
+ return "Feedback";
113551
+ return line.slice(0, FEEDBACK_TITLE_MAX_LENGTH);
113552
+ }
113553
+ function normalizeFeedbackIssueDraft(input) {
113554
+ const title = sanitizeFeedbackText(input.title ?? "").replace(/\s+/g, " ").trim();
113555
+ const body = sanitizeFeedbackText(input.body ?? "");
113556
+ return {
113557
+ title: (title || fallbackTitleFromBody(body) || "Feedback").slice(0, FEEDBACK_TITLE_MAX_LENGTH),
113558
+ body: body.slice(0, FEEDBACK_BODY_MAX_LENGTH) || "No additional details provided."
113559
+ };
113560
+ }
113561
+ function sanitizeFeedbackIssueDraft(input) {
113562
+ return normalizeFeedbackIssueDraft(input);
113563
+ }
113564
+ function parsePolishedFeedbackOutput(output) {
113565
+ const trimmed2 = output.trim();
113566
+ if (!trimmed2)
113567
+ return null;
113568
+ const fencedJsonMatch = trimmed2.match(/```(?:json)?\s*([\s\S]*?)```/i);
113569
+ const jsonCandidate = fencedJsonMatch?.[1] ?? trimmed2;
113570
+ const jsonMatch = jsonCandidate.match(/\{[\s\S]*\}/);
113571
+ if (jsonMatch) {
113572
+ try {
113573
+ return feedbackIssueDraftSchema.parse(JSON.parse(jsonMatch[0]));
113574
+ } catch {}
113575
+ }
113576
+ const titleMatch = trimmed2.match(/(?:^|\n)TITLE:\s*(.+?)(?:\n|$)/i);
113577
+ const bodyMatch = trimmed2.match(/(?:^|\n)BODY:\s*([\s\S]+)/i);
113578
+ if (titleMatch && bodyMatch) {
113579
+ return normalizeFeedbackIssueDraft({
113580
+ title: titleMatch[1],
113581
+ body: bodyMatch[1]
113582
+ });
113583
+ }
113584
+ return null;
113585
+ }
113586
+ function buildBrowserContextSection(browserContext) {
113587
+ const entries = [
113588
+ browserContext?.platform ? `- Platform: ${browserContext.platform}` : null,
113589
+ browserContext?.operatingSystem ? `- OS: ${browserContext.operatingSystem}` : null,
113590
+ browserContext?.browser ? `- Browser: ${browserContext.browser}` : null,
113591
+ browserContext?.viewport ? `- Viewport: ${browserContext.viewport}` : null,
113592
+ browserContext?.devicePixelRatio ? `- Device Pixel Ratio: ${browserContext.devicePixelRatio}` : null,
113593
+ browserContext?.language ? `- Language: ${browserContext.language}` : null,
113594
+ browserContext?.touchSupport ? `- Touch Support: ${browserContext.touchSupport}` : null,
113595
+ browserContext?.walletContext ? `- Wallet/Web3 Context: ${browserContext.walletContext}` : null,
113596
+ browserContext?.appVersion ? `- App Version: ${browserContext.appVersion}` : null
113597
+ ].filter(Boolean);
113598
+ if (entries.length === 0)
113599
+ return "Not provided.";
113600
+ return ["Browser context captured from the web app:", ...entries].join(`
113601
+ `);
113602
+ }
113603
+ function buildReproductionContextTemplate() {
113604
+ return [
113605
+ "- Platform: Not provided.",
113606
+ "- OS: Not provided.",
113607
+ "- Browser: Not provided.",
113608
+ "- Viewport: Not provided.",
113609
+ "- Wallet/Web3 Context: Not provided.",
113610
+ "- App Version: Not provided."
113611
+ ].join(`
113612
+ `);
113613
+ }
113614
+ function buildFeedbackPolishPrompt(input, browserContext) {
113615
+ return [
113616
+ "Rewrite this user feedback into a GitHub issue draft.",
113617
+ "Return ONLY valid JSON with this shape:",
113618
+ '{"title":"string","body":"string"}',
113619
+ "",
113620
+ "Rules:",
113621
+ "- Keep the result deterministic and concise.",
113622
+ "- Do not include private information, secrets, local paths, or email addresses.",
113623
+ "- Use this exact markdown template for body sections and preserve the headings/order:",
113624
+ "## Summary",
113625
+ "## Problem",
113626
+ "## Reproduction Context",
113627
+ "## Desired Outcome",
113628
+ '- Use bullet points under "## Reproduction Context", with one context field per line prefixed by "-".',
113629
+ "- Prefer these reproduction context fields when relevant: Platform, OS, Browser, Viewport, Wallet/Web3 Context, App Version.",
113630
+ "- Use the browser context below when it helps reproducibility, but keep it compact and non-sensitive.",
113631
+ '- If a section has no useful details, write "Not provided."',
113632
+ "",
113633
+ `Current title: ${input.title}`,
113634
+ "Current details:",
113635
+ input.body,
113636
+ "",
113637
+ "Available reproduction context:",
113638
+ buildBrowserContextSection(browserContext)
113639
+ ].join(`
113640
+ `);
113641
+ }
113642
+ function buildFeedbackDraftFromInput(input) {
113643
+ const normalized = normalizeFeedbackIssueDraft({
113644
+ title: input.title,
113645
+ body: input.body
113646
+ });
113647
+ return {
113648
+ title: normalized.title,
113649
+ body: [
113650
+ "## Summary",
113651
+ normalized.title,
113652
+ "",
113653
+ "## Problem",
113654
+ normalized.body || "Not provided.",
113655
+ "",
113656
+ "## Reproduction Context",
113657
+ buildReproductionContextTemplate(),
113658
+ "",
113659
+ "## Desired Outcome",
113660
+ "Not provided."
113661
+ ].join(`
113662
+ `)
113663
+ };
113664
+ }
113665
+ function buildGitHubIssueCreateUrl(input) {
113666
+ const params = new URLSearchParams({
113667
+ title: input.draft.title,
113668
+ body: input.draft.body,
113669
+ labels: "feedback"
113670
+ });
113671
+ return `https://github.com/${input.owner}/${input.repo}/issues/new?${params.toString()}`;
113672
+ }
113673
+ var FEEDBACK_SANITIZED_FIELDS, feedbackIssueDraftSchema, FEEDBACK_TITLE_MAX_LENGTH = 120, FEEDBACK_BODY_MAX_LENGTH = 8000, ENV_ASSIGNMENT_PATTERN, ABSOLUTE_UNIX_PATH_PATTERN, ABSOLUTE_WINDOWS_PATH_PATTERN;
113674
+ var init_feedback = __esm(() => {
113675
+ init_zod();
113676
+ FEEDBACK_SANITIZED_FIELDS = [
113677
+ "Email addresses",
113678
+ "Bearer/API/GitHub-style tokens",
113679
+ "Absolute local filesystem paths",
113680
+ "Sensitive env assignments such as TOKEN=..."
113681
+ ];
113682
+ feedbackIssueDraftSchema = exports_external.object({
113683
+ title: exports_external.string().trim().min(1),
113684
+ body: exports_external.string().trim().min(1)
113685
+ });
113686
+ ENV_ASSIGNMENT_PATTERN = /\b([A-Za-z_][A-Za-z0-9_]*)=([^\s]+)/g;
113687
+ ABSOLUTE_UNIX_PATH_PATTERN = /(^|[\s([{'"`])((?:~|\/)[^\s)\]}'"`]+)(?=$|[\s)\]},'"`.!?;:])/gm;
113688
+ ABSOLUTE_WINDOWS_PATH_PATTERN = /(^|[\s([{'"`])([A-Za-z]:\\[^\s)\]}'"`]+)(?=$|[\s)\]},'"`.!?;:])/gm;
113689
+ });
113690
+
113691
+ // ../api/src/server/routes/feedback.ts
113692
+ function getFeedbackPolishFailureMessage(result) {
113693
+ if (result.aborted)
113694
+ return FEEDBACK_POLISH_TIMEOUT_MESSAGE;
113695
+ return result.error ?? "Failed to polish feedback draft.";
113696
+ }
113697
+ var feedbackDraftSchema, browserFeedbackContextSchema, feedbackPolishInputSchema, FEEDBACK_POLISH_TIMEOUT_MS = 30000, FEEDBACK_POLISH_TIMEOUT_MESSAGE = "Polish timed out after 30 seconds. Try again with a shorter draft or verify the default coding agent is available.", FEEDBACK_REPOSITORY, feedbackRouter;
113698
+ var init_feedback2 = __esm(() => {
113699
+ init_dist4();
113700
+ init_zod();
113701
+ init_trpc();
113702
+ init_agents();
113703
+ init_feedback();
113704
+ feedbackDraftSchema = exports_external.object({
113705
+ title: exports_external.string().trim().max(200).optional(),
113706
+ body: exports_external.string().trim().max(12000)
113707
+ });
113708
+ browserFeedbackContextSchema = exports_external.object({
113709
+ platform: exports_external.string().trim().max(40).optional(),
113710
+ operatingSystem: exports_external.string().trim().max(80).optional(),
113711
+ browser: exports_external.string().trim().max(80).optional(),
113712
+ viewport: exports_external.string().trim().max(40).optional(),
113713
+ devicePixelRatio: exports_external.string().trim().max(20).optional(),
113714
+ language: exports_external.string().trim().max(40).optional(),
113715
+ touchSupport: exports_external.string().trim().max(20).optional(),
113716
+ walletContext: exports_external.string().trim().max(240).optional(),
113717
+ appVersion: exports_external.string().trim().max(80).optional()
113718
+ });
113719
+ feedbackPolishInputSchema = feedbackDraftSchema.extend({
113720
+ browserContext: browserFeedbackContextSchema.optional()
113721
+ });
113722
+ FEEDBACK_REPOSITORY = {
113723
+ owner: "brucexu-eth",
113724
+ repo: "vibeman"
113725
+ };
113726
+ feedbackRouter = t.router({
113727
+ polishDraft: dbProcedure.input(feedbackPolishInputSchema).mutation(async ({ ctx, input }) => {
113728
+ const sanitizedInput = normalizeFeedbackIssueDraft(input);
113729
+ const browserContext = sanitizeBrowserFeedbackContext(input.browserContext);
113730
+ const fallbackDraft = buildFeedbackDraftFromInput(sanitizedInput);
113731
+ const timeoutController = new AbortController;
113732
+ const timeoutId = setTimeout(() => {
113733
+ timeoutController.abort();
113734
+ }, FEEDBACK_POLISH_TIMEOUT_MS);
113735
+ const result = await executeAgentExecutionRequest(ctx.db, {
113736
+ source: "task",
113737
+ runId: `feedback-polish-${Date.now()}`,
113738
+ nodeKey: "feedback-polish",
113739
+ root: ctx.root,
113740
+ prompt: buildFeedbackPolishPrompt(sanitizedInput, browserContext),
113741
+ resumeThread: false,
113742
+ executorConfig: {
113743
+ permissionMode: "read-only"
113744
+ },
113745
+ signal: timeoutController.signal,
113746
+ logContext: { module: "feedback" }
113747
+ }).finally(() => {
113748
+ clearTimeout(timeoutId);
113749
+ });
113750
+ if (!result.success) {
113751
+ throw new TRPCError({
113752
+ code: "INTERNAL_SERVER_ERROR",
113753
+ message: getFeedbackPolishFailureMessage(result)
113754
+ });
113755
+ }
113756
+ const polished = parsePolishedFeedbackOutput(result.output ?? "");
113757
+ const draft = sanitizeFeedbackIssueDraft(polished ?? fallbackDraft);
113758
+ return createResponse(ctx, {
113759
+ draft,
113760
+ provider: result.provider,
113761
+ model: result.model,
113762
+ sanitizedFields: FEEDBACK_SANITIZED_FIELDS
113763
+ });
113764
+ }),
113765
+ prepareSubmission: dbProcedure.input(feedbackDraftSchema).mutation(async ({ ctx, input }) => {
113766
+ const draft = sanitizeFeedbackIssueDraft(input);
113767
+ const url2 = buildGitHubIssueCreateUrl({
113768
+ owner: FEEDBACK_REPOSITORY.owner,
113769
+ repo: FEEDBACK_REPOSITORY.repo,
113770
+ draft
113771
+ });
113772
+ return createResponse(ctx, {
113773
+ draft,
113774
+ url: url2,
113775
+ owner: FEEDBACK_REPOSITORY.owner,
113776
+ repo: FEEDBACK_REPOSITORY.repo,
113777
+ sanitizedFields: FEEDBACK_SANITIZED_FIELDS
113778
+ });
113779
+ })
113780
+ });
113781
+ });
113782
+
113361
113783
  // ../api/src/server/routes/onboarding.ts
113362
- import { readFile as readFile6, readdir as readdir3, rename as rename2, rm, mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
113363
- import { basename as basename2, join as join7, resolve as resolve21 } from "node:path";
113784
+ import { readFile as readFile7, readdir as readdir4, rename as rename2, rm as rm3, mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
113785
+ import { basename as basename2, join as join8, resolve as resolve21 } from "node:path";
113364
113786
  import { spawn as spawn8 } from "node:child_process";
113365
113787
  function buildInitialOnboardingState(nowIso) {
113366
113788
  return {
@@ -113413,10 +113835,10 @@ ${err instanceof Error ? err.message : String(err)}`,
113413
113835
  });
113414
113836
  }
113415
113837
  async function moveDirectoryContents(srcDir, destDir) {
113416
- const entries = await readdir3(srcDir);
113838
+ const entries = await readdir4(srcDir);
113417
113839
  const moved = [];
113418
113840
  for (const entry of entries) {
113419
- await rename2(join7(srcDir, entry), join7(destDir, entry));
113841
+ await rename2(join8(srcDir, entry), join8(destDir, entry));
113420
113842
  moved.push(entry);
113421
113843
  }
113422
113844
  return moved;
@@ -113491,7 +113913,7 @@ function buildTemplateWorkspace(root) {
113491
113913
  async function patchGeneratedPackageName(root, desiredName) {
113492
113914
  const packageJsonPath = resolve21(root, "package.json");
113493
113915
  try {
113494
- const raw2 = await readFile6(packageJsonPath, "utf8");
113916
+ const raw2 = await readFile7(packageJsonPath, "utf8");
113495
113917
  const pkg = JSON.parse(raw2);
113496
113918
  const currentName = typeof pkg.name === "string" ? pkg.name.trim() : "";
113497
113919
  if (currentName.length === 0 || currentName.includes("vibeman-init-tmp")) {
@@ -113510,7 +113932,7 @@ async function patchGeneratedT3ImportAlias(root, desiredAlias) {
113510
113932
  }
113511
113933
  const tsconfigPath = resolve21(root, "tsconfig.json");
113512
113934
  try {
113513
- const raw2 = await readFile6(tsconfigPath, "utf8");
113935
+ const raw2 = await readFile7(tsconfigPath, "utf8");
113514
113936
  const config2 = JSON.parse(raw2);
113515
113937
  const paths = config2.compilerOptions?.paths;
113516
113938
  const current = paths?.["~/*"];
@@ -113712,7 +114134,7 @@ var init_onboarding = __esm(() => {
113712
114134
  let packageName = null;
113713
114135
  let packageDescription = null;
113714
114136
  try {
113715
- const raw2 = await readFile6(resolve21(ctx.root, "package.json"), "utf8");
114137
+ const raw2 = await readFile7(resolve21(ctx.root, "package.json"), "utf8");
113716
114138
  const pkg = JSON.parse(raw2);
113717
114139
  if (typeof pkg.name === "string" && pkg.name.trim()) {
113718
114140
  packageName = pkg.name.trim();
@@ -113729,7 +114151,7 @@ var init_onboarding = __esm(() => {
113729
114151
  let hasPackageJson = false;
113730
114152
  let detectedFramework = null;
113731
114153
  try {
113732
- const entries = await readdir3(ctx.root, { withFileTypes: true });
114154
+ const entries = await readdir4(ctx.root, { withFileTypes: true });
113733
114155
  for (const entry of entries) {
113734
114156
  if (IGNORED.has(entry.name))
113735
114157
  continue;
@@ -113742,7 +114164,7 @@ var init_onboarding = __esm(() => {
113742
114164
  } catch {}
113743
114165
  if (hasPackageJson) {
113744
114166
  try {
113745
- const raw2 = await readFile6(resolve21(ctx.root, "package.json"), "utf8");
114167
+ const raw2 = await readFile7(resolve21(ctx.root, "package.json"), "utf8");
113746
114168
  const pkg = JSON.parse(raw2);
113747
114169
  const all = { ...pkg.dependencies, ...pkg.devDependencies };
113748
114170
  if (all["next"] && all["@trpc/server"])
@@ -113782,13 +114204,13 @@ var init_onboarding = __esm(() => {
113782
114204
  const scaffoldPath = shouldRunInTmpDir ? resolve21(tmpPath, workspace.projectDirName) : resolve21(ctx.root, workspace.scaffoldDir);
113783
114205
  const command = buildTemplateInitCommand(input, commandTargetDir);
113784
114206
  try {
113785
- await rm(tmpPath, { recursive: true, force: true });
114207
+ await rm3(tmpPath, { recursive: true, force: true });
113786
114208
  } catch {}
113787
114209
  await mkdir6(tmpPath, { recursive: true });
113788
114210
  const result = await runShellCommand(command, commandCwd);
113789
114211
  if (!result.success) {
113790
114212
  try {
113791
- await rm(tmpPath, { recursive: true, force: true });
114213
+ await rm3(tmpPath, { recursive: true, force: true });
113792
114214
  } catch {}
113793
114215
  const detail = (result.stderr || result.stdout).trim().slice(-2000);
113794
114216
  throw new TRPCError({
@@ -113819,7 +114241,7 @@ ${detail}`
113819
114241
  throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: msg });
113820
114242
  } finally {
113821
114243
  try {
113822
- await rm(tmpPath, { recursive: true, force: true });
114244
+ await rm3(tmpPath, { recursive: true, force: true });
113823
114245
  } catch {}
113824
114246
  }
113825
114247
  return createResponse(ctx, {
@@ -113990,7 +114412,7 @@ Rules:
113990
114412
  };
113991
114413
  const body = task2.body.trim() || task2.title;
113992
114414
  const content = stringifyTaskMarkdown(body, frontmatter);
113993
- await writeFile7(join7(tasksDir, filename), content);
114415
+ await writeFile7(join8(tasksDir, filename), content);
113994
114416
  created.push(filename);
113995
114417
  }
113996
114418
  return createResponse(ctx, { created });
@@ -114013,6 +114435,7 @@ var init_router2 = __esm(() => {
114013
114435
  init_settings2();
114014
114436
  init_cli_settings();
114015
114437
  init_github3();
114438
+ init_feedback2();
114016
114439
  init_onboarding();
114017
114440
  init_trpc();
114018
114441
  appRouter = t.router({
@@ -114028,6 +114451,7 @@ var init_router2 = __esm(() => {
114028
114451
  settings: settingsRouter,
114029
114452
  cliSettings: cliSettingsRouter,
114030
114453
  github: githubRouter,
114454
+ feedback: feedbackRouter,
114031
114455
  onboarding: onboardingRouter
114032
114456
  });
114033
114457
  });
@@ -122216,7 +122640,7 @@ var require_mime_types = __commonJS((exports) => {
122216
122640
  * MIT Licensed
122217
122641
  */
122218
122642
  var db = require_mime_db();
122219
- var extname2 = __require("path").extname;
122643
+ var extname3 = __require("path").extname;
122220
122644
  var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
122221
122645
  var TEXT_TYPE_REGEXP = /^text\//i;
122222
122646
  exports.charset = charset;
@@ -122271,7 +122695,7 @@ var require_mime_types = __commonJS((exports) => {
122271
122695
  if (!path3 || typeof path3 !== "string") {
122272
122696
  return false;
122273
122697
  }
122274
- var extension2 = extname2("x." + path3).toLowerCase().substr(1);
122698
+ var extension2 = extname3("x." + path3).toLowerCase().substr(1);
122275
122699
  if (!extension2) {
122276
122700
  return false;
122277
122701
  }
@@ -122735,10 +123159,10 @@ var require_error = __commonJS((exports, module) => {
122735
123159
 
122736
123160
  // ../../node_modules/serve-handler/src/index.js
122737
123161
  var require_src3 = __commonJS((exports, module) => {
122738
- var { promisify: promisify2 } = __require("util");
123162
+ var { promisify: promisify3 } = __require("util");
122739
123163
  var path3 = __require("path");
122740
123164
  var { createHash: createHash2 } = __require("crypto");
122741
- var { realpath, lstat: lstat2, createReadStream, readdir: readdir4 } = __require("fs");
123165
+ var { realpath, lstat: lstat3, createReadStream, readdir: readdir5 } = __require("fs");
122742
123166
  var url2 = __require("url");
122743
123167
  var slasher = require_glob_slash();
122744
123168
  var minimatch = require_minimatch();
@@ -123126,10 +123550,10 @@ var require_src3 = __commonJS((exports, module) => {
123126
123550
  return sendError(...args);
123127
123551
  };
123128
123552
  var getHandlers = (methods) => Object.assign({
123129
- lstat: promisify2(lstat2),
123130
- realpath: promisify2(realpath),
123553
+ lstat: promisify3(lstat3),
123554
+ realpath: promisify3(realpath),
123131
123555
  createReadStream,
123132
- readdir: promisify2(readdir4),
123556
+ readdir: promisify3(readdir5),
123133
123557
  sendError
123134
123558
  }, methods);
123135
123559
  module.exports = async (request2, response, config2 = {}, methods = {}) => {
@@ -123490,7 +123914,7 @@ var init_port_utils = () => {};
123490
123914
  // ../api/src/services/pty-session.ts
123491
123915
  import { chmodSync, statSync as statSync3 } from "node:fs";
123492
123916
  import { createRequire as createRequire3 } from "node:module";
123493
- import { dirname as dirname6, join as join8 } from "node:path";
123917
+ import { dirname as dirname7, join as join9 } from "node:path";
123494
123918
  import * as pty from "node-pty";
123495
123919
  import { randomUUID as randomUUID2 } from "node:crypto";
123496
123920
  import { fileURLToPath as fileURLToPath4 } from "node:url";
@@ -123522,9 +123946,9 @@ function ensureNodePtySpawnHelperExecutable() {
123522
123946
  const helperCandidates = new Set;
123523
123947
  try {
123524
123948
  const packageJsonPath = require2.resolve("node-pty/package.json");
123525
- helperCandidates.add(join8(dirname6(packageJsonPath), "prebuilds", `darwin-${process.arch}`, "spawn-helper"));
123949
+ helperCandidates.add(join9(dirname7(packageJsonPath), "prebuilds", `darwin-${process.arch}`, "spawn-helper"));
123526
123950
  } catch {}
123527
- const bundledDistHelperPath = join8(dirname6(fileURLToPath4(import.meta.url)), "prebuilds", `darwin-${process.arch}`, "spawn-helper");
123951
+ const bundledDistHelperPath = join9(dirname7(fileURLToPath4(import.meta.url)), "prebuilds", `darwin-${process.arch}`, "spawn-helper");
123528
123952
  helperCandidates.add(bundledDistHelperPath);
123529
123953
  for (const helperPath of helperCandidates) {
123530
123954
  try {
@@ -123727,19 +124151,19 @@ var init_pty_session = __esm(() => {
123727
124151
  });
123728
124152
 
123729
124153
  // ../api/src/server/terminal-ws.ts
123730
- import { dirname as dirname7, resolve as resolve23, sep as sep6 } from "node:path";
123731
- import { existsSync as existsSync14, statSync as statSync4 } from "node:fs";
124154
+ import { dirname as dirname8, resolve as resolve23, sep as sep6 } from "node:path";
124155
+ import { existsSync as existsSync15, statSync as statSync4 } from "node:fs";
123732
124156
  function validateCwd(cwd2, root) {
123733
124157
  if (!cwd2 || typeof cwd2 !== "string")
123734
124158
  return null;
123735
124159
  const resolved = resolve23(cwd2);
123736
124160
  const resolvedRoot = resolve23(root);
123737
- const parentDir = dirname7(resolvedRoot) + sep6;
124161
+ const parentDir = dirname8(resolvedRoot) + sep6;
123738
124162
  const isWithinRoot2 = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + sep6);
123739
124163
  const isSibling = resolved.startsWith(parentDir);
123740
124164
  if (!isWithinRoot2 && !isSibling)
123741
124165
  return null;
123742
- if (!existsSync14(resolved))
124166
+ if (!existsSync15(resolved))
123743
124167
  return null;
123744
124168
  try {
123745
124169
  if (!statSync4(resolved).isDirectory())
@@ -123940,10 +124364,10 @@ __export(exports_http, {
123940
124364
  startServer: () => startServer
123941
124365
  });
123942
124366
  import { createServer as createServer2 } from "node:http";
123943
- import { existsSync as existsSync15 } from "node:fs";
124367
+ import { existsSync as existsSync16 } from "node:fs";
123944
124368
  import { createReadStream } from "node:fs";
123945
124369
  import { stat as stat2 } from "node:fs/promises";
123946
- import { extname as extname2, resolve as resolve24, sep as sep7 } from "node:path";
124370
+ import { extname as extname3, resolve as resolve24, sep as sep7 } from "node:path";
123947
124371
  async function startServer(options2) {
123948
124372
  const startedAt = Date.now();
123949
124373
  const taskFileWatch = createTaskFileWatchService(options2.root);
@@ -123965,7 +124389,7 @@ async function startServer(options2) {
123965
124389
  logger.error(`tRPC request failed ${JSON.stringify(details, (_key, value) => value === undefined ? "[undefined]" : value)}`);
123966
124390
  }
123967
124391
  });
123968
- const hasUi = Boolean(options2.uiRoot && existsSync15(options2.uiRoot));
124392
+ const hasUi = Boolean(options2.uiRoot && existsSync16(options2.uiRoot));
123969
124393
  const server = createServer2(async (req, res) => {
123970
124394
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
123971
124395
  if (url2.pathname === "/api/health/live") {
@@ -124187,7 +124611,7 @@ function safeDecode3(value) {
124187
124611
  }
124188
124612
  }
124189
124613
  function guessContentType(absolutePath) {
124190
- const ext = extname2(absolutePath).toLowerCase();
124614
+ const ext = extname3(absolutePath).toLowerCase();
124191
124615
  switch (ext) {
124192
124616
  case ".png":
124193
124617
  return "image/png";