vibeman 0.0.16 → 0.0.18

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 +735 -144
  2. package/dist/commit.txt +1 -1
  3. package/dist/ui/assets/{index-CdwIPvvC.js → index-B-8CajaA.js} +1 -1
  4. package/dist/ui/assets/{index-DPgndyQt.js → index-B1FSfHLI.js} +1 -1
  5. package/dist/ui/assets/{index-DRYG0hWl.js → index-B92ZPtji.js} +1 -1
  6. package/dist/ui/assets/{index-C61bzN1F.js → index-BTczj1rc.js} +1 -1
  7. package/dist/ui/assets/{index-D_--wkOk.js → index-BkKHUQw9.js} +1 -1
  8. package/dist/ui/assets/{index-mhz4dktY.js → index-BoxXumAe.js} +1 -1
  9. package/dist/ui/assets/{index-B77m9jwg.js → index-BvKWFrTc.js} +1 -1
  10. package/dist/ui/assets/{index-Cl5D1lr0.js → index-CC4BSgs2.js} +1 -1
  11. package/dist/ui/assets/{index-DJxs2IHl.js → index-Cd7yEUOm.js} +1 -1
  12. package/dist/ui/assets/{index-ssu5S1KA.js → index-Csir9ls6.js} +1 -1
  13. package/dist/ui/assets/{index-Db2EhJOX.js → index-CtYo0drE.js} +1 -1
  14. package/dist/ui/assets/index-Cxa7P1xU.js +1105 -0
  15. package/dist/ui/assets/{index-CnWjvgnt.js → index-D6wz33v1.js} +1 -1
  16. package/dist/ui/assets/{index-b2CKrEE6.js → index-Dd7O0n3u.js} +1 -1
  17. package/dist/ui/assets/{index-CHinfK5y.js → index-DfOxbKSr.js} +1 -1
  18. package/dist/ui/assets/{index-B49cVd68.js → index-Di4kXroA.js} +1 -1
  19. package/dist/ui/assets/{index-CpEU6Vxs.js → index-JAx5oYb8.js} +1 -1
  20. package/dist/ui/assets/index-JuAf608w.css +1 -0
  21. package/dist/ui/assets/{index-DErcnUD0.js → index-N65elFFW.js} +1 -1
  22. package/dist/ui/assets/{index-DKTHpT6c.js → index-UepgO9mJ.js} +1 -1
  23. package/dist/ui/assets/{index-D6YdKIji.js → index-WhRFAD-g.js} +1 -1
  24. package/dist/ui/assets/{index-Dck1mk1E.js → index-cqRipg1U.js} +1 -1
  25. package/dist/ui/assets/{index-CkMEKMtG.js → index-r2QifZLg.js} +1 -1
  26. package/dist/ui/assets/{index-DARaaYLg.js → index-xQKZm7F-.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 +9 -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;
@@ -105316,7 +105357,7 @@ var init_workflows = __esm(() => {
105316
105357
 
105317
105358
  // ../api/src/server/routes/tasks.ts
105318
105359
  import { normalize as normalize9, resolve as resolve16, join as join5, relative as relative5, sep as sep2 } from "node:path";
105319
- import { writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
105360
+ import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir3, rm as rm2 } from "node:fs/promises";
105320
105361
  function normalizeFrontmatterTags(value) {
105321
105362
  if (Array.isArray(value)) {
105322
105363
  return value.map((tag) => String(tag).trim()).filter(Boolean);
@@ -105363,6 +105404,117 @@ function runBelongsToTask(payload, plan, explicitTaskId) {
105363
105404
  return true;
105364
105405
  return false;
105365
105406
  }
105407
+ function buildTaskDeleteCommitMessage(taskId, taskTitle) {
105408
+ const normalizedId = taskId.trim();
105409
+ const normalizedTitle = taskTitle?.trim() ?? "";
105410
+ const raw2 = `task: ${normalizedId} ${normalizedTitle} deleted`.replace(/\s+/g, " ").trim();
105411
+ return raw2 || `task: ${normalizedId} deleted`;
105412
+ }
105413
+ async function deleteTaskFileWithCommit(args) {
105414
+ for (const file2 of args.deletedFiles) {
105415
+ await rm2(resolve16(args.rootPath, file2.path), { force: true });
105416
+ }
105417
+ if (!args.commitDirect) {
105418
+ return { commit: null };
105419
+ }
105420
+ try {
105421
+ const commit = await args.git.commit(args.commitMessage, {
105422
+ paths: args.deletedFiles.map((file2) => file2.path)
105423
+ });
105424
+ return { commit };
105425
+ } catch (error48) {
105426
+ try {
105427
+ await Promise.all(args.deletedFiles.map((file2) => writeFile3(resolve16(args.rootPath, file2.path), file2.content)));
105428
+ } catch (restoreError) {
105429
+ const restoreMessage = restoreError instanceof Error ? restoreError.message : "Unknown restore error";
105430
+ const originalMessage = error48 instanceof Error ? error48.message : "Unknown commit error";
105431
+ throw new Error(`Unable to commit task delete (${originalMessage}). The task file could not be restored (${restoreMessage}).`);
105432
+ }
105433
+ throw error48;
105434
+ }
105435
+ }
105436
+ async function collectRestorableTaskDeleteFiles(args) {
105437
+ const deletedFiles = [
105438
+ { path: args.taskPath, content: args.taskContent }
105439
+ ];
105440
+ const assetPaths = collectTaskAssetPaths(args.taskContent);
105441
+ for (const assetPath of assetPaths) {
105442
+ try {
105443
+ deletedFiles.push({
105444
+ path: assetPath,
105445
+ content: await readFile5(resolve16(args.rootPath, assetPath))
105446
+ });
105447
+ } catch (error48) {
105448
+ if (error48 instanceof Error && error48.code === "ENOENT") {
105449
+ continue;
105450
+ }
105451
+ throw error48;
105452
+ }
105453
+ }
105454
+ return deletedFiles;
105455
+ }
105456
+ async function cleanupTaskGitArtifacts(rootPath, plan) {
105457
+ const git = createGitService(rootPath);
105458
+ const worktrees = await git.listWorktrees();
105459
+ const normalizedTarget = normalize9(plan.worktreePath);
105460
+ const rootPathNormalized = normalize9(resolve16(rootPath));
105461
+ const matchingWorktrees = worktrees.filter((worktree) => {
105462
+ const resolvedPath = normalize9(resolve16(rootPath, worktree.path));
105463
+ return resolvedPath === normalizedTarget || worktree.branch === plan.branchName;
105464
+ });
105465
+ for (const worktree of matchingWorktrees) {
105466
+ const resolvedPath = normalize9(resolve16(rootPath, worktree.path));
105467
+ const relativePath = relative5(rootPathNormalized, resolvedPath);
105468
+ const isWithinRoot2 = relativePath === "" || !relativePath.startsWith("..") && !relativePath.startsWith(`..${sep2}`);
105469
+ if (isWithinRoot2) {
105470
+ continue;
105471
+ }
105472
+ await git.removeWorktree(worktree.path, { force: true });
105473
+ }
105474
+ await git.pruneWorktrees();
105475
+ const hasBranch = await git.branchExists(plan.branchName);
105476
+ if (!hasBranch) {
105477
+ return;
105478
+ }
105479
+ const currentBranch = await git.getCurrentBranch();
105480
+ if (currentBranch === plan.branchName) {
105481
+ const localBranches = await git.listLocalBranches();
105482
+ const fallbackCandidates = [await git.getDefaultBranch(), "main", "master", ...localBranches];
105483
+ const fallbackBranch = fallbackCandidates.find((branch) => branch && branch !== plan.branchName && localBranches.includes(branch)) ?? "";
105484
+ if (!fallbackBranch) {
105485
+ throw new Error(`Cannot delete branch "${plan.branchName}" because it is currently checked out.`);
105486
+ }
105487
+ await git.checkoutBranch(fallbackBranch);
105488
+ }
105489
+ await git.removeBranch(plan.branchName, { force: true });
105490
+ }
105491
+ async function cleanupTaskWorkflowRuns(args) {
105492
+ let deletedRuns = 0;
105493
+ let cancelledRuns = 0;
105494
+ const runs = await args.db.workflowRun.findMany({
105495
+ where: { deletedAt: null },
105496
+ select: { id: true, status: true, runPayload: true }
105497
+ });
105498
+ const relatedRuns = runs.filter((run2) => runBelongsToTask(run2.runPayload ?? null, args.plan, args.explicitTaskId));
105499
+ const workflowService = createWorkflowService({ db: args.db, root: args.rootPath });
105500
+ const cancellableRuns = relatedRuns.filter((run2) => {
105501
+ const status = String(run2.status).toLowerCase();
105502
+ return status === "running" || status === "pending" || status === "paused";
105503
+ });
105504
+ for (const run2 of cancellableRuns) {
105505
+ await workflowService.cancelRun(run2.id, args.cancelReason);
105506
+ cancelledRuns += 1;
105507
+ }
105508
+ const runIds = relatedRuns.map((run2) => run2.id);
105509
+ if (runIds.length > 0) {
105510
+ const result = await args.db.workflowRun.updateMany({
105511
+ where: { id: { in: runIds } },
105512
+ data: { deletedAt: new Date }
105513
+ });
105514
+ deletedRuns = result.count;
105515
+ }
105516
+ return { deletedRuns, cancelledRuns };
105517
+ }
105366
105518
  function parseTaskFile(filename, content) {
105367
105519
  const parsed = import_gray_matter2.default(content);
105368
105520
  const frontmatter = { ...parsed.data };
@@ -105408,6 +105560,7 @@ var init_tasks2 = __esm(() => {
105408
105560
  init_log();
105409
105561
  init_task_markdown();
105410
105562
  init_task_id();
105563
+ init_task_commit_paths();
105411
105564
  init_tasks();
105412
105565
  init_workflows();
105413
105566
  init_trpc();
@@ -105763,44 +105916,8 @@ var init_tasks2 = __esm(() => {
105763
105916
  cause: error48 instanceof Error ? error48 : undefined
105764
105917
  });
105765
105918
  }
105766
- const git = createGitService(ctx.root);
105767
105919
  try {
105768
- const worktrees = await git.listWorktrees();
105769
- const normalizedTarget = normalize9(plan.worktreePath);
105770
- const rootPath = normalize9(resolve16(ctx.root));
105771
- const matchingWorktrees = worktrees.filter((worktree) => {
105772
- const resolvedPath = normalize9(resolve16(ctx.root, worktree.path));
105773
- return resolvedPath === normalizedTarget || worktree.branch === plan.branchName;
105774
- });
105775
- for (const worktree of matchingWorktrees) {
105776
- const resolvedPath = normalize9(resolve16(ctx.root, worktree.path));
105777
- const relativePath = relative5(rootPath, resolvedPath);
105778
- const isWithinRoot2 = relativePath === "" || !relativePath.startsWith("..") && !relativePath.startsWith(`..${sep2}`);
105779
- if (isWithinRoot2) {
105780
- continue;
105781
- }
105782
- await git.removeWorktree(worktree.path, { force: true });
105783
- }
105784
- await git.pruneWorktrees();
105785
- const hasBranch = await git.branchExists(plan.branchName);
105786
- if (hasBranch) {
105787
- const currentBranch = await git.getCurrentBranch();
105788
- if (currentBranch === plan.branchName) {
105789
- const localBranches = await git.listLocalBranches();
105790
- const fallbackCandidates = [
105791
- await git.getDefaultBranch(),
105792
- "main",
105793
- "master",
105794
- ...localBranches
105795
- ];
105796
- const fallbackBranch = fallbackCandidates.find((branch) => branch && branch !== plan.branchName && localBranches.includes(branch)) ?? "";
105797
- if (!fallbackBranch) {
105798
- throw new Error(`Cannot delete branch "${plan.branchName}" because it is currently checked out.`);
105799
- }
105800
- await git.checkoutBranch(fallbackBranch);
105801
- }
105802
- await git.removeBranch(plan.branchName, { force: true });
105803
- }
105920
+ await cleanupTaskGitArtifacts(ctx.root, plan);
105804
105921
  } catch (error48) {
105805
105922
  const message = error48 instanceof Error ? error48.message : "Unable to reset git worktree and branch";
105806
105923
  throw new TRPCError({
@@ -105812,28 +105929,13 @@ var init_tasks2 = __esm(() => {
105812
105929
  let deletedRuns = 0;
105813
105930
  let cancelledRuns = 0;
105814
105931
  try {
105815
- const runs = await ctx.db.workflowRun.findMany({
105816
- where: { deletedAt: null },
105817
- select: { id: true, status: true, runPayload: true }
105818
- });
105819
- const relatedRuns = runs.filter((run2) => runBelongsToTask(run2.runPayload ?? null, plan, input.taskId));
105820
- const workflowService = createWorkflowService({ db: ctx.db, root: ctx.root });
105821
- const cancellableRuns = relatedRuns.filter((run2) => {
105822
- const status = String(run2.status).toLowerCase();
105823
- return status === "running" || status === "pending" || status === "paused";
105824
- });
105825
- for (const run2 of cancellableRuns) {
105826
- await workflowService.cancelRun(run2.id, "Cancelled by task reset");
105827
- cancelledRuns += 1;
105828
- }
105829
- const runIds = relatedRuns.map((run2) => run2.id);
105830
- if (runIds.length > 0) {
105831
- const result = await ctx.db.workflowRun.updateMany({
105832
- where: { id: { in: runIds } },
105833
- data: { deletedAt: new Date }
105834
- });
105835
- deletedRuns = result.count;
105836
- }
105932
+ ({ deletedRuns, cancelledRuns } = await cleanupTaskWorkflowRuns({
105933
+ db: ctx.db,
105934
+ rootPath: ctx.root,
105935
+ plan,
105936
+ explicitTaskId: input.taskId,
105937
+ cancelReason: "Cancelled by task reset"
105938
+ }));
105837
105939
  } catch (error48) {
105838
105940
  const message = error48 instanceof Error ? error48.message : "Unable to reset workflow runs and states for task";
105839
105941
  throw new TRPCError({
@@ -105851,6 +105953,112 @@ var init_tasks2 = __esm(() => {
105851
105953
  deletedRuns
105852
105954
  });
105853
105955
  }),
105956
+ delete: dbProcedure.input(exports_external.object({
105957
+ filename: exports_external.string().min(1),
105958
+ taskId: exports_external.string().min(1).optional(),
105959
+ commitDirect: exports_external.boolean().optional(),
105960
+ commitMessage: exports_external.string().min(1).optional()
105961
+ })).mutation(async ({ ctx, input }) => {
105962
+ const taskPath = join5(".vibeman/tasks", input.filename);
105963
+ let plan;
105964
+ let taskTitle;
105965
+ let existingContent = "";
105966
+ try {
105967
+ plan = buildTaskExecutionPlan(ctx.root, taskPath);
105968
+ existingContent = await readFileContent(ctx.root, taskPath);
105969
+ const parsed = import_gray_matter2.default(existingContent);
105970
+ taskTitle = typeof parsed.data.title === "string" ? parsed.data.title : undefined;
105971
+ } catch (error48) {
105972
+ const message = error48 instanceof Error ? error48.message : "Unable to prepare task delete plan";
105973
+ throw new TRPCError({
105974
+ code: "BAD_REQUEST",
105975
+ message,
105976
+ cause: error48 instanceof Error ? error48 : undefined
105977
+ });
105978
+ }
105979
+ let deletedFiles;
105980
+ try {
105981
+ deletedFiles = await collectRestorableTaskDeleteFiles({
105982
+ rootPath: ctx.root,
105983
+ taskPath,
105984
+ taskContent: existingContent
105985
+ });
105986
+ } catch (error48) {
105987
+ const message = error48 instanceof Error ? error48.message : "Unable to prepare task attachments for delete";
105988
+ throw new TRPCError({
105989
+ code: "BAD_REQUEST",
105990
+ message,
105991
+ cause: error48 instanceof Error ? error48 : undefined
105992
+ });
105993
+ }
105994
+ const commitDirect = input.commitDirect ?? true;
105995
+ let commitResult = null;
105996
+ const git = createGitService(ctx.root);
105997
+ if (commitDirect) {
105998
+ try {
105999
+ ({ commit: commitResult } = await deleteTaskFileWithCommit({
106000
+ rootPath: ctx.root,
106001
+ deletedFiles,
106002
+ commitDirect,
106003
+ commitMessage: input.commitMessage?.trim() || buildTaskDeleteCommitMessage(plan.taskId, taskTitle),
106004
+ git
106005
+ }));
106006
+ } catch (error48) {
106007
+ const message = error48 instanceof Error ? error48.message : "Unable to commit task delete";
106008
+ throw new TRPCError({
106009
+ code: "BAD_REQUEST",
106010
+ message,
106011
+ cause: error48 instanceof Error ? error48 : undefined
106012
+ });
106013
+ }
106014
+ } else {
106015
+ try {
106016
+ ({ commit: commitResult } = await deleteTaskFileWithCommit({
106017
+ rootPath: ctx.root,
106018
+ deletedFiles,
106019
+ commitDirect,
106020
+ commitMessage: "",
106021
+ git
106022
+ }));
106023
+ } catch (error48) {
106024
+ const message = error48 instanceof Error ? error48.message : "Unable to delete task file";
106025
+ throw new TRPCError({
106026
+ code: "INTERNAL_SERVER_ERROR",
106027
+ message,
106028
+ cause: error48 instanceof Error ? error48 : undefined
106029
+ });
106030
+ }
106031
+ }
106032
+ let deletedRuns = 0;
106033
+ let cancelledRuns = 0;
106034
+ const cleanupWarnings = [];
106035
+ try {
106036
+ await cleanupTaskGitArtifacts(ctx.root, plan);
106037
+ } catch (error48) {
106038
+ cleanupWarnings.push(error48 instanceof Error ? error48.message : "Unable to delete task worktree and branch");
106039
+ }
106040
+ try {
106041
+ ({ deletedRuns, cancelledRuns } = await cleanupTaskWorkflowRuns({
106042
+ db: ctx.db,
106043
+ rootPath: ctx.root,
106044
+ plan,
106045
+ explicitTaskId: input.taskId,
106046
+ cancelReason: "Cancelled by task delete"
106047
+ }));
106048
+ } catch (error48) {
106049
+ cleanupWarnings.push(error48 instanceof Error ? error48.message : "Unable to delete workflow runs and states for task");
106050
+ }
106051
+ return createResponse(ctx, {
106052
+ taskPath: plan.taskPath,
106053
+ taskName: plan.taskName,
106054
+ branch: plan.branchName,
106055
+ worktree: plan.worktreePath,
106056
+ cancelledRuns,
106057
+ deletedRuns,
106058
+ commit: commitResult,
106059
+ cleanupWarnings
106060
+ });
106061
+ }),
105854
106062
  setup: dbProcedure.input(exports_external.object({ filename: exports_external.string().min(1) })).mutation(async ({ ctx, input }) => {
105855
106063
  const taskPath = join5(".vibeman/tasks", input.filename);
105856
106064
  let plan;
@@ -105928,7 +106136,7 @@ function classifyMergeReadiness(input) {
105928
106136
 
105929
106137
  // ../api/src/server/routes/workflows.ts
105930
106138
  import { normalize as normalize10, relative as relative6, resolve as resolve17 } from "node:path";
105931
- import { readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
106139
+ import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
105932
106140
  import { execFile as execFile4 } from "node:child_process";
105933
106141
  import { promisify } from "node:util";
105934
106142
  function workflowRecency(workflow) {
@@ -106354,7 +106562,7 @@ function resolvePathWithinRoot(rootPath, pathInput) {
106354
106562
  }
106355
106563
  async function markTaskFrontmatterDone(rootPath, taskPath) {
106356
106564
  const filePath = resolvePathWithinRoot(rootPath, taskPath);
106357
- const raw2 = await readFile5(filePath, "utf8");
106565
+ const raw2 = await readFile6(filePath, "utf8");
106358
106566
  const match = raw2.match(/^---\n([\s\S]*?)\n---\n?/);
106359
106567
  if (!match) {
106360
106568
  return false;
@@ -107968,10 +108176,11 @@ var init_remote_access = __esm(() => {
107968
108176
  });
107969
108177
 
107970
108178
  // ../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";
108179
+ import { execFile as execFile5, spawn as spawn7 } from "node:child_process";
108180
+ import { resolve as resolve18, relative as relative7, sep as sep3, join as join6, extname } from "node:path";
108181
+ import { access as access3, mkdtemp, readFile as readFile7, rm as rm3 } from "node:fs/promises";
108182
+ import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
108183
+ import { promisify as promisify2 } from "node:util";
107975
108184
  function isWithin2(rootPath, targetPath) {
107976
108185
  const relativePath = relative7(rootPath, targetPath);
107977
108186
  return relativePath === "" || !relativePath.startsWith("..") && !relativePath.startsWith(`..${sep3}`);
@@ -108003,11 +108212,108 @@ async function isAnyDetectionPathAccessible(paths) {
108003
108212
  }
108004
108213
  return false;
108005
108214
  }
108215
+ async function resolveAccessibleDetectionPath(paths) {
108216
+ for (const rawPath of paths) {
108217
+ const candidate = resolveDetectionPath(rawPath);
108218
+ try {
108219
+ await access3(candidate);
108220
+ return candidate;
108221
+ } catch {}
108222
+ }
108223
+ return null;
108224
+ }
108225
+ function normalizeIconFileName(value) {
108226
+ if (typeof value !== "string" || value.trim().length === 0)
108227
+ return null;
108228
+ const trimmed2 = value.trim();
108229
+ return extname(trimmed2) ? trimmed2 : `${trimmed2}.icns`;
108230
+ }
108231
+ function extractIconFileName(plist) {
108232
+ const directCandidates = [
108233
+ plist.CFBundleIconFile,
108234
+ plist.CFBundleIconName,
108235
+ plist.CFBundlePrimaryIcon?.CFBundleIconFile
108236
+ ];
108237
+ for (const candidate of directCandidates) {
108238
+ const normalized = normalizeIconFileName(candidate);
108239
+ if (normalized)
108240
+ return normalized;
108241
+ }
108242
+ const bundleIcons = plist.CFBundleIcons;
108243
+ if (bundleIcons && typeof bundleIcons === "object") {
108244
+ const primaryIcon = bundleIcons.CFBundlePrimaryIcon;
108245
+ if (primaryIcon && typeof primaryIcon === "object") {
108246
+ const iconFiles = primaryIcon.CFBundleIconFiles;
108247
+ if (Array.isArray(iconFiles)) {
108248
+ for (const candidate of [...iconFiles].reverse()) {
108249
+ const normalized = normalizeIconFileName(candidate);
108250
+ if (normalized)
108251
+ return normalized;
108252
+ }
108253
+ }
108254
+ }
108255
+ }
108256
+ return null;
108257
+ }
108258
+ function toDataUrl(buffer, extension) {
108259
+ const normalized = extension.toLowerCase();
108260
+ if (normalized === ".svg") {
108261
+ return `data:image/svg+xml;base64,${buffer.toString("base64")}`;
108262
+ }
108263
+ if (normalized === ".jpg" || normalized === ".jpeg") {
108264
+ return `data:image/jpeg;base64,${buffer.toString("base64")}`;
108265
+ }
108266
+ return `data:image/png;base64,${buffer.toString("base64")}`;
108267
+ }
108268
+ async function convertIcnsToPngDataUrl(iconPath) {
108269
+ const tempDir = await mkdtemp(join6(tmpdir2(), "vibeman-app-icon-"));
108270
+ const pngPath = join6(tempDir, "icon.png");
108271
+ try {
108272
+ await execFileAsync2("sips", ["-s", "format", "png", iconPath, "--out", pngPath]);
108273
+ const pngBuffer = await readFile7(pngPath);
108274
+ return toDataUrl(pngBuffer, ".png");
108275
+ } finally {
108276
+ await rm3(tempDir, { recursive: true, force: true });
108277
+ }
108278
+ }
108279
+ async function readAppIconDataUrl(appPath) {
108280
+ const cached2 = appIconCache.get(appPath);
108281
+ if (cached2 !== undefined)
108282
+ return cached2;
108283
+ const infoPlistPath = join6(appPath, "Contents", "Info.plist");
108284
+ try {
108285
+ const { stdout } = await execFileAsync2("plutil", [
108286
+ "-convert",
108287
+ "json",
108288
+ "-o",
108289
+ "-",
108290
+ infoPlistPath
108291
+ ]);
108292
+ const plist = JSON.parse(stdout);
108293
+ const iconFileName = extractIconFileName(plist);
108294
+ if (!iconFileName) {
108295
+ appIconCache.set(appPath, null);
108296
+ return null;
108297
+ }
108298
+ const iconPath = join6(appPath, "Contents", "Resources", iconFileName);
108299
+ await access3(iconPath);
108300
+ const extension = extname(iconPath).toLowerCase();
108301
+ const dataUrl = extension === ".icns" ? await convertIcnsToPngDataUrl(iconPath) : toDataUrl(await readFile7(iconPath), extension);
108302
+ appIconCache.set(appPath, dataUrl);
108303
+ return dataUrl;
108304
+ } catch {
108305
+ appIconCache.set(appPath, null);
108306
+ return null;
108307
+ }
108308
+ }
108006
108309
  async function listAvailableApps(category) {
108007
108310
  const defs = appCatalog.filter((app) => app.category === category);
108008
108311
  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;
108312
+ const installedPath = await resolveAccessibleDetectionPath(app.detectionPaths);
108313
+ if (!installedPath)
108314
+ return null;
108315
+ const iconDataUrl = await readAppIconDataUrl(installedPath);
108316
+ return { id: app.id, label: app.label, iconDataUrl };
108011
108317
  }));
108012
108318
  return results.filter(Boolean);
108013
108319
  }
@@ -108059,7 +108365,7 @@ async function openInApp(appName, targetPath) {
108059
108365
  });
108060
108366
  });
108061
108367
  }
108062
- var appCategories, appCatalog, systemRouter;
108368
+ var appCategories, execFileAsync2, appIconCache, appCatalog, systemRouter;
108063
108369
  var init_system2 = __esm(() => {
108064
108370
  init_dist4();
108065
108371
  init_zod();
@@ -108067,6 +108373,8 @@ var init_system2 = __esm(() => {
108067
108373
  init_env_policy();
108068
108374
  init_remote_access();
108069
108375
  appCategories = ["terminal", "editor"];
108376
+ execFileAsync2 = promisify2(execFile5);
108377
+ appIconCache = new Map;
108070
108378
  appCatalog = [
108071
108379
  {
108072
108380
  id: "warp",
@@ -108113,6 +108421,13 @@ var init_system2 = __esm(() => {
108113
108421
  openAppName: "Antigravity",
108114
108422
  detectionPaths: ["/Applications/Antigravity.app", "~/Applications/Antigravity.app"]
108115
108423
  },
108424
+ {
108425
+ id: "zed",
108426
+ category: "editor",
108427
+ label: "Zed",
108428
+ openAppName: "Zed",
108429
+ detectionPaths: ["/Applications/Zed.app", "~/Applications/Zed.app"]
108430
+ },
108116
108431
  {
108117
108432
  id: "vscode",
108118
108433
  category: "editor",
@@ -108310,7 +108625,7 @@ var init_system2 = __esm(() => {
108310
108625
 
108311
108626
  // ../api/src/services/assets.ts
108312
108627
  import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
108313
- import { extname, resolve as resolve19, sep as sep4 } from "node:path";
108628
+ import { extname as extname2, resolve as resolve19, sep as sep4 } from "node:path";
108314
108629
  import { randomUUID } from "node:crypto";
108315
108630
  function getImagesDir(rootPath) {
108316
108631
  return resolve19(rootPath, ".vibeman/assets/images");
@@ -108322,7 +108637,7 @@ async function writeImageAsset(options2) {
108322
108637
  const imagesDir = getImagesDir(options2.rootPath);
108323
108638
  await mkdir4(imagesDir, { recursive: true });
108324
108639
  const extFromMime = imageMimeToExt[options2.mimeType] ?? null;
108325
- const extFromNameRaw = options2.originalName ? sanitizeExt(extname(options2.originalName)) : null;
108640
+ const extFromNameRaw = options2.originalName ? sanitizeExt(extname2(options2.originalName)) : null;
108326
108641
  const extFromName = extFromNameRaw ? imageExtAliases[extFromNameRaw] ?? null : null;
108327
108642
  const ext = extFromMime ?? extFromName ?? null;
108328
108643
  if (!ext) {
@@ -108647,12 +108962,12 @@ var init_model_catalog = __esm(() => {
108647
108962
  });
108648
108963
 
108649
108964
  // ../api/src/server/routes/cli-settings.ts
108650
- import { delimiter as delimiter4, dirname as dirname5 } from "node:path";
108965
+ import { delimiter as delimiter4, dirname as dirname6 } from "node:path";
108651
108966
  function withExecutableOnPath(env, executable) {
108652
108967
  if (!executable) {
108653
108968
  return env;
108654
108969
  }
108655
- const dir = dirname5(executable);
108970
+ const dir = dirname6(executable);
108656
108971
  const basePath = env.PATH ?? process.env.PATH ?? "";
108657
108972
  const combined = [dir, basePath].filter(Boolean).join(delimiter4);
108658
108973
  return { ...env, PATH: combined };
@@ -112852,7 +113167,7 @@ var init_github = __esm(() => {
112852
113167
  });
112853
113168
 
112854
113169
  // ../api/src/services/integrations/github-sync.ts
112855
- import { join as join6, resolve as resolve20 } from "node:path";
113170
+ import { join as join7, resolve as resolve20 } from "node:path";
112856
113171
  import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
112857
113172
  function mapIssueStateToTaskStatus(state2) {
112858
113173
  return state2 === "open" ? "backlog" : "done";
@@ -112873,7 +113188,7 @@ async function findTaskForIssue(rootPath, owner, repo, issueNumber) {
112873
113188
  continue;
112874
113189
  }
112875
113190
  try {
112876
- const content = await readFileContent(rootPath, join6(tasksPath, file2.name));
113191
+ const content = await readFileContent(rootPath, join7(tasksPath, file2.name));
112877
113192
  const parsed = import_gray_matter3.default(content);
112878
113193
  if (isTaskLinkedToIssue(parsed.data, owner, repo, issueNumber)) {
112879
113194
  return {
@@ -112923,7 +113238,7 @@ async function syncIssueToTask(rootPath, owner, repo, issue2, options2) {
112923
113238
  };
112924
113239
  const content = import_gray_matter3.default.stringify(taskBody, updatedFrontmatter, frontmatterYamlOptions2);
112925
113240
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
112926
- await writeFile6(join6(tasksDir, existingTask.filename), content);
113241
+ await writeFile6(join7(tasksDir, existingTask.filename), content);
112927
113242
  return { action: "updated", filename: existingTask.filename };
112928
113243
  } else {
112929
113244
  const taskId = generateTaskIdFromIssue(issue2);
@@ -112943,7 +113258,7 @@ async function syncIssueToTask(rootPath, owner, repo, issue2, options2) {
112943
113258
  const content = import_gray_matter3.default.stringify(taskBody, frontmatter, frontmatterYamlOptions2);
112944
113259
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
112945
113260
  await mkdir5(tasksDir, { recursive: true });
112946
- await writeFile6(join6(tasksDir, filename), content);
113261
+ await writeFile6(join7(tasksDir, filename), content);
112947
113262
  return { action: "created", filename };
112948
113263
  }
112949
113264
  }
@@ -113008,7 +113323,7 @@ async function syncTaskToGitHub(db, rootPath, taskFilename) {
113008
113323
  throw new Error("GitHub integration is not configured");
113009
113324
  }
113010
113325
  const tasksPath = ".vibeman/tasks";
113011
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113326
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113012
113327
  const parsed = import_gray_matter3.default(content);
113013
113328
  const githubRepo = parsed.data.github_repo;
113014
113329
  const githubIssueNumberRaw = parsed.data.github_issue_number;
@@ -113037,7 +113352,7 @@ async function syncTaskToGitHub(db, rootPath, taskFilename) {
113037
113352
  };
113038
113353
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113039
113354
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113040
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113355
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113041
113356
  }
113042
113357
  async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113043
113358
  const config2 = await getGitHubConfig(db);
@@ -113045,7 +113360,7 @@ async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113045
113360
  throw new Error("GitHub integration is not configured");
113046
113361
  }
113047
113362
  const tasksPath = ".vibeman/tasks";
113048
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113363
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113049
113364
  const parsed = import_gray_matter3.default(content);
113050
113365
  const githubRepo = parsed.data.github_repo;
113051
113366
  const githubIssueNumberRaw = parsed.data.github_issue_number;
@@ -113065,7 +113380,7 @@ async function syncIssueToTaskFromGitHub(db, rootPath, taskFilename) {
113065
113380
  }
113066
113381
  async function linkTaskToGitHubIssue(rootPath, taskFilename, owner, repo, issueNumber, issueUrl) {
113067
113382
  const tasksPath = ".vibeman/tasks";
113068
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113383
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113069
113384
  const parsed = import_gray_matter3.default(content);
113070
113385
  const repoIdentifier = `${owner}/${repo}`;
113071
113386
  const githubMetadata = {
@@ -113081,11 +113396,11 @@ async function linkTaskToGitHubIssue(rootPath, taskFilename, owner, repo, issueN
113081
113396
  };
113082
113397
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113083
113398
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113084
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113399
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113085
113400
  }
113086
113401
  async function unlinkTaskFromGitHubIssue(rootPath, taskFilename) {
113087
113402
  const tasksPath = ".vibeman/tasks";
113088
- const content = await readFileContent(rootPath, join6(tasksPath, taskFilename));
113403
+ const content = await readFileContent(rootPath, join7(tasksPath, taskFilename));
113089
113404
  const parsed = import_gray_matter3.default(content);
113090
113405
  const updatedFrontmatter = { ...parsed.data };
113091
113406
  delete updatedFrontmatter.github_repo;
@@ -113095,7 +113410,7 @@ async function unlinkTaskFromGitHubIssue(rootPath, taskFilename) {
113095
113410
  updatedFrontmatter.updated_at = new Date().toISOString();
113096
113411
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, updatedFrontmatter, stringifyOptions);
113097
113412
  const tasksDir = resolve20(rootPath, ".vibeman/tasks");
113098
- await writeFile6(join6(tasksDir, taskFilename), updatedContent);
113413
+ await writeFile6(join7(tasksDir, taskFilename), updatedContent);
113099
113414
  }
113100
113415
  var import_gray_matter3, stringifyOptions, parseTimestamp = (value) => {
113101
113416
  if (typeof value !== "string")
@@ -113127,7 +113442,7 @@ var import_gray_matter3, stringifyOptions, parseTimestamp = (value) => {
113127
113442
  continue;
113128
113443
  }
113129
113444
  try {
113130
- const content = await readFileContent(rootPath, join6(tasksPath, file2.name));
113445
+ const content = await readFileContent(rootPath, join7(tasksPath, file2.name));
113131
113446
  const parsed = import_gray_matter3.default(content);
113132
113447
  if (!shouldPushTaskToGitHub(parsed.data, owner, repo))
113133
113448
  continue;
@@ -113358,9 +113673,283 @@ var init_github3 = __esm(() => {
113358
113673
  });
113359
113674
  });
113360
113675
 
113676
+ // ../api/src/services/feedback.ts
113677
+ function shouldRedactUnixPath(path3) {
113678
+ if (path3 === "~")
113679
+ return false;
113680
+ return path3.startsWith("~/") || path3.startsWith("/");
113681
+ }
113682
+ function isSensitiveEnvKey(key) {
113683
+ return /(token|secret|password|passwd|auth|session|cookie|api_?key)/i.test(key);
113684
+ }
113685
+ function sanitizeText(value) {
113686
+ 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) => {
113687
+ return `${prefix}[REDACTED_PATH]`;
113688
+ }).replace(ABSOLUTE_UNIX_PATH_PATTERN, (_, prefix, path3) => {
113689
+ return shouldRedactUnixPath(path3) ? `${prefix}[REDACTED_PATH]` : `${prefix}${path3}`;
113690
+ }).replace(ENV_ASSIGNMENT_PATTERN, (match, key) => {
113691
+ return isSensitiveEnvKey(key) ? `${key}=[REDACTED_TOKEN]` : match;
113692
+ });
113693
+ }
113694
+ function collapseBlankLines(value) {
113695
+ return value.replace(/\n{3,}/g, `
113696
+
113697
+ `).trim();
113698
+ }
113699
+ function sanitizeFeedbackText(value) {
113700
+ return collapseBlankLines(sanitizeText(value.trim()));
113701
+ }
113702
+ function sanitizeBrowserFeedbackContext(input) {
113703
+ if (!input)
113704
+ return;
113705
+ const entries = Object.entries(input).flatMap(([key, value]) => {
113706
+ if (typeof value !== "string")
113707
+ return [];
113708
+ const sanitized = sanitizeFeedbackText(value);
113709
+ return sanitized ? [[key, sanitized]] : [];
113710
+ });
113711
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
113712
+ }
113713
+ function fallbackTitleFromBody(body) {
113714
+ const line = body.split(`
113715
+ `).map((entry) => entry.trim()).find((entry) => entry.length > 0 && !entry.startsWith("#") && !entry.startsWith("- "));
113716
+ if (!line)
113717
+ return "Feedback";
113718
+ return line.slice(0, FEEDBACK_TITLE_MAX_LENGTH);
113719
+ }
113720
+ function normalizeFeedbackIssueDraft(input) {
113721
+ const title = sanitizeFeedbackText(input.title ?? "").replace(/\s+/g, " ").trim();
113722
+ const body = sanitizeFeedbackText(input.body ?? "");
113723
+ return {
113724
+ title: (title || fallbackTitleFromBody(body) || "Feedback").slice(0, FEEDBACK_TITLE_MAX_LENGTH),
113725
+ body: body.slice(0, FEEDBACK_BODY_MAX_LENGTH) || "No additional details provided."
113726
+ };
113727
+ }
113728
+ function sanitizeFeedbackIssueDraft(input) {
113729
+ return normalizeFeedbackIssueDraft(input);
113730
+ }
113731
+ function parsePolishedFeedbackOutput(output) {
113732
+ const trimmed2 = output.trim();
113733
+ if (!trimmed2)
113734
+ return null;
113735
+ const fencedJsonMatch = trimmed2.match(/```(?:json)?\s*([\s\S]*?)```/i);
113736
+ const jsonCandidate = fencedJsonMatch?.[1] ?? trimmed2;
113737
+ const jsonMatch = jsonCandidate.match(/\{[\s\S]*\}/);
113738
+ if (jsonMatch) {
113739
+ try {
113740
+ return feedbackIssueDraftSchema.parse(JSON.parse(jsonMatch[0]));
113741
+ } catch {}
113742
+ }
113743
+ const titleMatch = trimmed2.match(/(?:^|\n)TITLE:\s*(.+?)(?:\n|$)/i);
113744
+ const bodyMatch = trimmed2.match(/(?:^|\n)BODY:\s*([\s\S]+)/i);
113745
+ if (titleMatch && bodyMatch) {
113746
+ return normalizeFeedbackIssueDraft({
113747
+ title: titleMatch[1],
113748
+ body: bodyMatch[1]
113749
+ });
113750
+ }
113751
+ return null;
113752
+ }
113753
+ function buildBrowserContextSection(browserContext) {
113754
+ const entries = [
113755
+ browserContext?.platform ? `- Platform: ${browserContext.platform}` : null,
113756
+ browserContext?.operatingSystem ? `- OS: ${browserContext.operatingSystem}` : null,
113757
+ browserContext?.browser ? `- Browser: ${browserContext.browser}` : null,
113758
+ browserContext?.viewport ? `- Viewport: ${browserContext.viewport}` : null,
113759
+ browserContext?.devicePixelRatio ? `- Device Pixel Ratio: ${browserContext.devicePixelRatio}` : null,
113760
+ browserContext?.language ? `- Language: ${browserContext.language}` : null,
113761
+ browserContext?.touchSupport ? `- Touch Support: ${browserContext.touchSupport}` : null,
113762
+ browserContext?.walletContext ? `- Wallet/Web3 Context: ${browserContext.walletContext}` : null,
113763
+ browserContext?.appVersion ? `- App Version: ${browserContext.appVersion}` : null
113764
+ ].filter(Boolean);
113765
+ if (entries.length === 0)
113766
+ return "Not provided.";
113767
+ return ["Browser context captured from the web app:", ...entries].join(`
113768
+ `);
113769
+ }
113770
+ function buildReproductionContextTemplate() {
113771
+ return [
113772
+ "- Platform: Not provided.",
113773
+ "- OS: Not provided.",
113774
+ "- Browser: Not provided.",
113775
+ "- Viewport: Not provided.",
113776
+ "- Wallet/Web3 Context: Not provided.",
113777
+ "- App Version: Not provided."
113778
+ ].join(`
113779
+ `);
113780
+ }
113781
+ function buildFeedbackPolishPrompt(input, browserContext) {
113782
+ return [
113783
+ "Rewrite this user feedback into a GitHub issue draft.",
113784
+ "Return ONLY valid JSON with this shape:",
113785
+ '{"title":"string","body":"string"}',
113786
+ "",
113787
+ "Rules:",
113788
+ "- Keep the result deterministic and concise.",
113789
+ "- Do not include private information, secrets, local paths, or email addresses.",
113790
+ "- Use this exact markdown template for body sections and preserve the headings/order:",
113791
+ "## Summary",
113792
+ "## Problem",
113793
+ "## Reproduction Context",
113794
+ "## Desired Outcome",
113795
+ '- Use bullet points under "## Reproduction Context", with one context field per line prefixed by "-".',
113796
+ "- Prefer these reproduction context fields when relevant: Platform, OS, Browser, Viewport, Wallet/Web3 Context, App Version.",
113797
+ "- Use the browser context below when it helps reproducibility, but keep it compact and non-sensitive.",
113798
+ '- If a section has no useful details, write "Not provided."',
113799
+ "",
113800
+ `Current title: ${input.title}`,
113801
+ "Current details:",
113802
+ input.body,
113803
+ "",
113804
+ "Available reproduction context:",
113805
+ buildBrowserContextSection(browserContext)
113806
+ ].join(`
113807
+ `);
113808
+ }
113809
+ function buildFeedbackDraftFromInput(input) {
113810
+ const normalized = normalizeFeedbackIssueDraft({
113811
+ title: input.title,
113812
+ body: input.body
113813
+ });
113814
+ return {
113815
+ title: normalized.title,
113816
+ body: [
113817
+ "## Summary",
113818
+ normalized.title,
113819
+ "",
113820
+ "## Problem",
113821
+ normalized.body || "Not provided.",
113822
+ "",
113823
+ "## Reproduction Context",
113824
+ buildReproductionContextTemplate(),
113825
+ "",
113826
+ "## Desired Outcome",
113827
+ "Not provided."
113828
+ ].join(`
113829
+ `)
113830
+ };
113831
+ }
113832
+ function buildGitHubIssueCreateUrl(input) {
113833
+ const params = new URLSearchParams({
113834
+ title: input.draft.title,
113835
+ body: input.draft.body,
113836
+ labels: "feedback"
113837
+ });
113838
+ return `https://github.com/${input.owner}/${input.repo}/issues/new?${params.toString()}`;
113839
+ }
113840
+ 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;
113841
+ var init_feedback = __esm(() => {
113842
+ init_zod();
113843
+ FEEDBACK_SANITIZED_FIELDS = [
113844
+ "Email addresses",
113845
+ "Bearer/API/GitHub-style tokens",
113846
+ "Absolute local filesystem paths",
113847
+ "Sensitive env assignments such as TOKEN=..."
113848
+ ];
113849
+ feedbackIssueDraftSchema = exports_external.object({
113850
+ title: exports_external.string().trim().min(1),
113851
+ body: exports_external.string().trim().min(1)
113852
+ });
113853
+ ENV_ASSIGNMENT_PATTERN = /\b([A-Za-z_][A-Za-z0-9_]*)=([^\s]+)/g;
113854
+ ABSOLUTE_UNIX_PATH_PATTERN = /(^|[\s([{'"`])((?:~|\/)[^\s)\]}'"`]+)(?=$|[\s)\]},'"`.!?;:])/gm;
113855
+ ABSOLUTE_WINDOWS_PATH_PATTERN = /(^|[\s([{'"`])([A-Za-z]:\\[^\s)\]}'"`]+)(?=$|[\s)\]},'"`.!?;:])/gm;
113856
+ });
113857
+
113858
+ // ../api/src/server/routes/feedback.ts
113859
+ function getFeedbackPolishFailureMessage(result) {
113860
+ if (result.aborted)
113861
+ return FEEDBACK_POLISH_TIMEOUT_MESSAGE;
113862
+ return result.error ?? "Failed to polish feedback draft.";
113863
+ }
113864
+ 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;
113865
+ var init_feedback2 = __esm(() => {
113866
+ init_dist4();
113867
+ init_zod();
113868
+ init_trpc();
113869
+ init_agents();
113870
+ init_feedback();
113871
+ feedbackDraftSchema = exports_external.object({
113872
+ title: exports_external.string().trim().max(200).optional(),
113873
+ body: exports_external.string().trim().max(12000)
113874
+ });
113875
+ browserFeedbackContextSchema = exports_external.object({
113876
+ platform: exports_external.string().trim().max(40).optional(),
113877
+ operatingSystem: exports_external.string().trim().max(80).optional(),
113878
+ browser: exports_external.string().trim().max(80).optional(),
113879
+ viewport: exports_external.string().trim().max(40).optional(),
113880
+ devicePixelRatio: exports_external.string().trim().max(20).optional(),
113881
+ language: exports_external.string().trim().max(40).optional(),
113882
+ touchSupport: exports_external.string().trim().max(20).optional(),
113883
+ walletContext: exports_external.string().trim().max(240).optional(),
113884
+ appVersion: exports_external.string().trim().max(80).optional()
113885
+ });
113886
+ feedbackPolishInputSchema = feedbackDraftSchema.extend({
113887
+ browserContext: browserFeedbackContextSchema.optional()
113888
+ });
113889
+ FEEDBACK_REPOSITORY = {
113890
+ owner: "brucexu-eth",
113891
+ repo: "vibeman"
113892
+ };
113893
+ feedbackRouter = t.router({
113894
+ polishDraft: dbProcedure.input(feedbackPolishInputSchema).mutation(async ({ ctx, input }) => {
113895
+ const sanitizedInput = normalizeFeedbackIssueDraft(input);
113896
+ const browserContext = sanitizeBrowserFeedbackContext(input.browserContext);
113897
+ const fallbackDraft = buildFeedbackDraftFromInput(sanitizedInput);
113898
+ const timeoutController = new AbortController;
113899
+ const timeoutId = setTimeout(() => {
113900
+ timeoutController.abort();
113901
+ }, FEEDBACK_POLISH_TIMEOUT_MS);
113902
+ const result = await executeAgentExecutionRequest(ctx.db, {
113903
+ source: "task",
113904
+ runId: `feedback-polish-${Date.now()}`,
113905
+ nodeKey: "feedback-polish",
113906
+ root: ctx.root,
113907
+ prompt: buildFeedbackPolishPrompt(sanitizedInput, browserContext),
113908
+ resumeThread: false,
113909
+ executorConfig: {
113910
+ permissionMode: "read-only"
113911
+ },
113912
+ signal: timeoutController.signal,
113913
+ logContext: { module: "feedback" }
113914
+ }).finally(() => {
113915
+ clearTimeout(timeoutId);
113916
+ });
113917
+ if (!result.success) {
113918
+ throw new TRPCError({
113919
+ code: "INTERNAL_SERVER_ERROR",
113920
+ message: getFeedbackPolishFailureMessage(result)
113921
+ });
113922
+ }
113923
+ const polished = parsePolishedFeedbackOutput(result.output ?? "");
113924
+ const draft = sanitizeFeedbackIssueDraft(polished ?? fallbackDraft);
113925
+ return createResponse(ctx, {
113926
+ draft,
113927
+ provider: result.provider,
113928
+ model: result.model,
113929
+ sanitizedFields: FEEDBACK_SANITIZED_FIELDS
113930
+ });
113931
+ }),
113932
+ prepareSubmission: dbProcedure.input(feedbackDraftSchema).mutation(async ({ ctx, input }) => {
113933
+ const draft = sanitizeFeedbackIssueDraft(input);
113934
+ const url2 = buildGitHubIssueCreateUrl({
113935
+ owner: FEEDBACK_REPOSITORY.owner,
113936
+ repo: FEEDBACK_REPOSITORY.repo,
113937
+ draft
113938
+ });
113939
+ return createResponse(ctx, {
113940
+ draft,
113941
+ url: url2,
113942
+ owner: FEEDBACK_REPOSITORY.owner,
113943
+ repo: FEEDBACK_REPOSITORY.repo,
113944
+ sanitizedFields: FEEDBACK_SANITIZED_FIELDS
113945
+ });
113946
+ })
113947
+ });
113948
+ });
113949
+
113361
113950
  // ../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";
113951
+ import { readFile as readFile8, readdir as readdir4, rename as rename2, rm as rm4, mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
113952
+ import { basename as basename2, join as join8, resolve as resolve21 } from "node:path";
113364
113953
  import { spawn as spawn8 } from "node:child_process";
113365
113954
  function buildInitialOnboardingState(nowIso) {
113366
113955
  return {
@@ -113413,10 +114002,10 @@ ${err instanceof Error ? err.message : String(err)}`,
113413
114002
  });
113414
114003
  }
113415
114004
  async function moveDirectoryContents(srcDir, destDir) {
113416
- const entries = await readdir3(srcDir);
114005
+ const entries = await readdir4(srcDir);
113417
114006
  const moved = [];
113418
114007
  for (const entry of entries) {
113419
- await rename2(join7(srcDir, entry), join7(destDir, entry));
114008
+ await rename2(join8(srcDir, entry), join8(destDir, entry));
113420
114009
  moved.push(entry);
113421
114010
  }
113422
114011
  return moved;
@@ -113491,7 +114080,7 @@ function buildTemplateWorkspace(root) {
113491
114080
  async function patchGeneratedPackageName(root, desiredName) {
113492
114081
  const packageJsonPath = resolve21(root, "package.json");
113493
114082
  try {
113494
- const raw2 = await readFile6(packageJsonPath, "utf8");
114083
+ const raw2 = await readFile8(packageJsonPath, "utf8");
113495
114084
  const pkg = JSON.parse(raw2);
113496
114085
  const currentName = typeof pkg.name === "string" ? pkg.name.trim() : "";
113497
114086
  if (currentName.length === 0 || currentName.includes("vibeman-init-tmp")) {
@@ -113510,7 +114099,7 @@ async function patchGeneratedT3ImportAlias(root, desiredAlias) {
113510
114099
  }
113511
114100
  const tsconfigPath = resolve21(root, "tsconfig.json");
113512
114101
  try {
113513
- const raw2 = await readFile6(tsconfigPath, "utf8");
114102
+ const raw2 = await readFile8(tsconfigPath, "utf8");
113514
114103
  const config2 = JSON.parse(raw2);
113515
114104
  const paths = config2.compilerOptions?.paths;
113516
114105
  const current = paths?.["~/*"];
@@ -113712,7 +114301,7 @@ var init_onboarding = __esm(() => {
113712
114301
  let packageName = null;
113713
114302
  let packageDescription = null;
113714
114303
  try {
113715
- const raw2 = await readFile6(resolve21(ctx.root, "package.json"), "utf8");
114304
+ const raw2 = await readFile8(resolve21(ctx.root, "package.json"), "utf8");
113716
114305
  const pkg = JSON.parse(raw2);
113717
114306
  if (typeof pkg.name === "string" && pkg.name.trim()) {
113718
114307
  packageName = pkg.name.trim();
@@ -113729,7 +114318,7 @@ var init_onboarding = __esm(() => {
113729
114318
  let hasPackageJson = false;
113730
114319
  let detectedFramework = null;
113731
114320
  try {
113732
- const entries = await readdir3(ctx.root, { withFileTypes: true });
114321
+ const entries = await readdir4(ctx.root, { withFileTypes: true });
113733
114322
  for (const entry of entries) {
113734
114323
  if (IGNORED.has(entry.name))
113735
114324
  continue;
@@ -113742,7 +114331,7 @@ var init_onboarding = __esm(() => {
113742
114331
  } catch {}
113743
114332
  if (hasPackageJson) {
113744
114333
  try {
113745
- const raw2 = await readFile6(resolve21(ctx.root, "package.json"), "utf8");
114334
+ const raw2 = await readFile8(resolve21(ctx.root, "package.json"), "utf8");
113746
114335
  const pkg = JSON.parse(raw2);
113747
114336
  const all = { ...pkg.dependencies, ...pkg.devDependencies };
113748
114337
  if (all["next"] && all["@trpc/server"])
@@ -113782,13 +114371,13 @@ var init_onboarding = __esm(() => {
113782
114371
  const scaffoldPath = shouldRunInTmpDir ? resolve21(tmpPath, workspace.projectDirName) : resolve21(ctx.root, workspace.scaffoldDir);
113783
114372
  const command = buildTemplateInitCommand(input, commandTargetDir);
113784
114373
  try {
113785
- await rm(tmpPath, { recursive: true, force: true });
114374
+ await rm4(tmpPath, { recursive: true, force: true });
113786
114375
  } catch {}
113787
114376
  await mkdir6(tmpPath, { recursive: true });
113788
114377
  const result = await runShellCommand(command, commandCwd);
113789
114378
  if (!result.success) {
113790
114379
  try {
113791
- await rm(tmpPath, { recursive: true, force: true });
114380
+ await rm4(tmpPath, { recursive: true, force: true });
113792
114381
  } catch {}
113793
114382
  const detail = (result.stderr || result.stdout).trim().slice(-2000);
113794
114383
  throw new TRPCError({
@@ -113819,7 +114408,7 @@ ${detail}`
113819
114408
  throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: msg });
113820
114409
  } finally {
113821
114410
  try {
113822
- await rm(tmpPath, { recursive: true, force: true });
114411
+ await rm4(tmpPath, { recursive: true, force: true });
113823
114412
  } catch {}
113824
114413
  }
113825
114414
  return createResponse(ctx, {
@@ -113990,7 +114579,7 @@ Rules:
113990
114579
  };
113991
114580
  const body = task2.body.trim() || task2.title;
113992
114581
  const content = stringifyTaskMarkdown(body, frontmatter);
113993
- await writeFile7(join7(tasksDir, filename), content);
114582
+ await writeFile7(join8(tasksDir, filename), content);
113994
114583
  created.push(filename);
113995
114584
  }
113996
114585
  return createResponse(ctx, { created });
@@ -114013,6 +114602,7 @@ var init_router2 = __esm(() => {
114013
114602
  init_settings2();
114014
114603
  init_cli_settings();
114015
114604
  init_github3();
114605
+ init_feedback2();
114016
114606
  init_onboarding();
114017
114607
  init_trpc();
114018
114608
  appRouter = t.router({
@@ -114028,6 +114618,7 @@ var init_router2 = __esm(() => {
114028
114618
  settings: settingsRouter,
114029
114619
  cliSettings: cliSettingsRouter,
114030
114620
  github: githubRouter,
114621
+ feedback: feedbackRouter,
114031
114622
  onboarding: onboardingRouter
114032
114623
  });
114033
114624
  });
@@ -122216,7 +122807,7 @@ var require_mime_types = __commonJS((exports) => {
122216
122807
  * MIT Licensed
122217
122808
  */
122218
122809
  var db = require_mime_db();
122219
- var extname2 = __require("path").extname;
122810
+ var extname3 = __require("path").extname;
122220
122811
  var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
122221
122812
  var TEXT_TYPE_REGEXP = /^text\//i;
122222
122813
  exports.charset = charset;
@@ -122271,7 +122862,7 @@ var require_mime_types = __commonJS((exports) => {
122271
122862
  if (!path3 || typeof path3 !== "string") {
122272
122863
  return false;
122273
122864
  }
122274
- var extension2 = extname2("x." + path3).toLowerCase().substr(1);
122865
+ var extension2 = extname3("x." + path3).toLowerCase().substr(1);
122275
122866
  if (!extension2) {
122276
122867
  return false;
122277
122868
  }
@@ -122735,10 +123326,10 @@ var require_error = __commonJS((exports, module) => {
122735
123326
 
122736
123327
  // ../../node_modules/serve-handler/src/index.js
122737
123328
  var require_src3 = __commonJS((exports, module) => {
122738
- var { promisify: promisify2 } = __require("util");
123329
+ var { promisify: promisify3 } = __require("util");
122739
123330
  var path3 = __require("path");
122740
123331
  var { createHash: createHash2 } = __require("crypto");
122741
- var { realpath, lstat: lstat2, createReadStream, readdir: readdir4 } = __require("fs");
123332
+ var { realpath, lstat: lstat3, createReadStream, readdir: readdir5 } = __require("fs");
122742
123333
  var url2 = __require("url");
122743
123334
  var slasher = require_glob_slash();
122744
123335
  var minimatch = require_minimatch();
@@ -123126,10 +123717,10 @@ var require_src3 = __commonJS((exports, module) => {
123126
123717
  return sendError(...args);
123127
123718
  };
123128
123719
  var getHandlers = (methods) => Object.assign({
123129
- lstat: promisify2(lstat2),
123130
- realpath: promisify2(realpath),
123720
+ lstat: promisify3(lstat3),
123721
+ realpath: promisify3(realpath),
123131
123722
  createReadStream,
123132
- readdir: promisify2(readdir4),
123723
+ readdir: promisify3(readdir5),
123133
123724
  sendError
123134
123725
  }, methods);
123135
123726
  module.exports = async (request2, response, config2 = {}, methods = {}) => {
@@ -123490,7 +124081,7 @@ var init_port_utils = () => {};
123490
124081
  // ../api/src/services/pty-session.ts
123491
124082
  import { chmodSync, statSync as statSync3 } from "node:fs";
123492
124083
  import { createRequire as createRequire3 } from "node:module";
123493
- import { dirname as dirname6, join as join8 } from "node:path";
124084
+ import { dirname as dirname7, join as join9 } from "node:path";
123494
124085
  import * as pty from "node-pty";
123495
124086
  import { randomUUID as randomUUID2 } from "node:crypto";
123496
124087
  import { fileURLToPath as fileURLToPath4 } from "node:url";
@@ -123522,9 +124113,9 @@ function ensureNodePtySpawnHelperExecutable() {
123522
124113
  const helperCandidates = new Set;
123523
124114
  try {
123524
124115
  const packageJsonPath = require2.resolve("node-pty/package.json");
123525
- helperCandidates.add(join8(dirname6(packageJsonPath), "prebuilds", `darwin-${process.arch}`, "spawn-helper"));
124116
+ helperCandidates.add(join9(dirname7(packageJsonPath), "prebuilds", `darwin-${process.arch}`, "spawn-helper"));
123526
124117
  } catch {}
123527
- const bundledDistHelperPath = join8(dirname6(fileURLToPath4(import.meta.url)), "prebuilds", `darwin-${process.arch}`, "spawn-helper");
124118
+ const bundledDistHelperPath = join9(dirname7(fileURLToPath4(import.meta.url)), "prebuilds", `darwin-${process.arch}`, "spawn-helper");
123528
124119
  helperCandidates.add(bundledDistHelperPath);
123529
124120
  for (const helperPath of helperCandidates) {
123530
124121
  try {
@@ -123727,19 +124318,19 @@ var init_pty_session = __esm(() => {
123727
124318
  });
123728
124319
 
123729
124320
  // ../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";
124321
+ import { dirname as dirname8, resolve as resolve23, sep as sep6 } from "node:path";
124322
+ import { existsSync as existsSync15, statSync as statSync4 } from "node:fs";
123732
124323
  function validateCwd(cwd2, root) {
123733
124324
  if (!cwd2 || typeof cwd2 !== "string")
123734
124325
  return null;
123735
124326
  const resolved = resolve23(cwd2);
123736
124327
  const resolvedRoot = resolve23(root);
123737
- const parentDir = dirname7(resolvedRoot) + sep6;
124328
+ const parentDir = dirname8(resolvedRoot) + sep6;
123738
124329
  const isWithinRoot2 = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + sep6);
123739
124330
  const isSibling = resolved.startsWith(parentDir);
123740
124331
  if (!isWithinRoot2 && !isSibling)
123741
124332
  return null;
123742
- if (!existsSync14(resolved))
124333
+ if (!existsSync15(resolved))
123743
124334
  return null;
123744
124335
  try {
123745
124336
  if (!statSync4(resolved).isDirectory())
@@ -123940,10 +124531,10 @@ __export(exports_http, {
123940
124531
  startServer: () => startServer
123941
124532
  });
123942
124533
  import { createServer as createServer2 } from "node:http";
123943
- import { existsSync as existsSync15 } from "node:fs";
124534
+ import { existsSync as existsSync16 } from "node:fs";
123944
124535
  import { createReadStream } from "node:fs";
123945
124536
  import { stat as stat2 } from "node:fs/promises";
123946
- import { extname as extname2, resolve as resolve24, sep as sep7 } from "node:path";
124537
+ import { extname as extname3, resolve as resolve24, sep as sep7 } from "node:path";
123947
124538
  async function startServer(options2) {
123948
124539
  const startedAt = Date.now();
123949
124540
  const taskFileWatch = createTaskFileWatchService(options2.root);
@@ -123965,7 +124556,7 @@ async function startServer(options2) {
123965
124556
  logger.error(`tRPC request failed ${JSON.stringify(details, (_key, value) => value === undefined ? "[undefined]" : value)}`);
123966
124557
  }
123967
124558
  });
123968
- const hasUi = Boolean(options2.uiRoot && existsSync15(options2.uiRoot));
124559
+ const hasUi = Boolean(options2.uiRoot && existsSync16(options2.uiRoot));
123969
124560
  const server = createServer2(async (req, res) => {
123970
124561
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
123971
124562
  if (url2.pathname === "/api/health/live") {
@@ -124187,7 +124778,7 @@ function safeDecode3(value) {
124187
124778
  }
124188
124779
  }
124189
124780
  function guessContentType(absolutePath) {
124190
- const ext = extname2(absolutePath).toLowerCase();
124781
+ const ext = extname3(absolutePath).toLowerCase();
124191
124782
  switch (ext) {
124192
124783
  case ".png":
124193
124784
  return "image/png";