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.
- package/dist/api.js +735 -144
- package/dist/commit.txt +1 -1
- package/dist/ui/assets/{index-CdwIPvvC.js → index-B-8CajaA.js} +1 -1
- package/dist/ui/assets/{index-DPgndyQt.js → index-B1FSfHLI.js} +1 -1
- package/dist/ui/assets/{index-DRYG0hWl.js → index-B92ZPtji.js} +1 -1
- package/dist/ui/assets/{index-C61bzN1F.js → index-BTczj1rc.js} +1 -1
- package/dist/ui/assets/{index-D_--wkOk.js → index-BkKHUQw9.js} +1 -1
- package/dist/ui/assets/{index-mhz4dktY.js → index-BoxXumAe.js} +1 -1
- package/dist/ui/assets/{index-B77m9jwg.js → index-BvKWFrTc.js} +1 -1
- package/dist/ui/assets/{index-Cl5D1lr0.js → index-CC4BSgs2.js} +1 -1
- package/dist/ui/assets/{index-DJxs2IHl.js → index-Cd7yEUOm.js} +1 -1
- package/dist/ui/assets/{index-ssu5S1KA.js → index-Csir9ls6.js} +1 -1
- package/dist/ui/assets/{index-Db2EhJOX.js → index-CtYo0drE.js} +1 -1
- package/dist/ui/assets/index-Cxa7P1xU.js +1105 -0
- package/dist/ui/assets/{index-CnWjvgnt.js → index-D6wz33v1.js} +1 -1
- package/dist/ui/assets/{index-b2CKrEE6.js → index-Dd7O0n3u.js} +1 -1
- package/dist/ui/assets/{index-CHinfK5y.js → index-DfOxbKSr.js} +1 -1
- package/dist/ui/assets/{index-B49cVd68.js → index-Di4kXroA.js} +1 -1
- package/dist/ui/assets/{index-CpEU6Vxs.js → index-JAx5oYb8.js} +1 -1
- package/dist/ui/assets/index-JuAf608w.css +1 -0
- package/dist/ui/assets/{index-DErcnUD0.js → index-N65elFFW.js} +1 -1
- package/dist/ui/assets/{index-DKTHpT6c.js → index-UepgO9mJ.js} +1 -1
- package/dist/ui/assets/{index-D6YdKIji.js → index-WhRFAD-g.js} +1 -1
- package/dist/ui/assets/{index-Dck1mk1E.js → index-cqRipg1U.js} +1 -1
- package/dist/ui/assets/{index-CkMEKMtG.js → index-r2QifZLg.js} +1 -1
- package/dist/ui/assets/{index-DARaaYLg.js → index-xQKZm7F-.js} +1 -1
- package/dist/ui/assets/vibeman-logo-on-dark-GVk_1Rmr.png +0 -0
- package/dist/ui/assets/vibeman-logo-on-light-4VCHa-wB.png +0 -0
- package/dist/ui/index.html +9 -2
- package/dist/ui/vibeman-apple-touch-icon.png +0 -0
- package/dist/ui/vibeman-favicon-16.png +0 -0
- package/dist/ui/vibeman-favicon-32.png +0 -0
- package/package.json +1 -1
- package/dist/ui/assets/index-CEeUnKFj.js +0 -1101
- 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
|
|
54572
|
+
"Cannot create a new task worktree while the repository root has uncommitted changes.",
|
|
54573
54573
|
"",
|
|
54574
|
-
"
|
|
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
|
-
"
|
|
54578
|
-
"
|
|
54579
|
-
"
|
|
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 {
|
|
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
|
|
60086
|
-
import { lstat, readlink, readdir as
|
|
60087
|
-
import { dirname as
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
|
60184
|
+
const existing = await lstat2(targetPath);
|
|
60144
60185
|
if (existing.isSymbolicLink()) {
|
|
60145
|
-
const linkTarget = await
|
|
60146
|
-
const resolvedTarget = normalize5(resolve12(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
105816
|
-
|
|
105817
|
-
|
|
105818
|
-
|
|
105819
|
-
|
|
105820
|
-
|
|
105821
|
-
|
|
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
|
|
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
|
|
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
|
|
108010
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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,
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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,
|
|
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,
|
|
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(
|
|
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,
|
|
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(
|
|
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,
|
|
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
|
|
113363
|
-
import { basename as basename2, join as
|
|
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
|
|
114005
|
+
const entries = await readdir4(srcDir);
|
|
113417
114006
|
const moved = [];
|
|
113418
114007
|
for (const entry of entries) {
|
|
113419
|
-
await rename2(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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:
|
|
123329
|
+
var { promisify: promisify3 } = __require("util");
|
|
122739
123330
|
var path3 = __require("path");
|
|
122740
123331
|
var { createHash: createHash2 } = __require("crypto");
|
|
122741
|
-
var { realpath, lstat:
|
|
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:
|
|
123130
|
-
realpath:
|
|
123720
|
+
lstat: promisify3(lstat3),
|
|
123721
|
+
realpath: promisify3(realpath),
|
|
123131
123722
|
createReadStream,
|
|
123132
|
-
readdir:
|
|
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
|
|
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(
|
|
124116
|
+
helperCandidates.add(join9(dirname7(packageJsonPath), "prebuilds", `darwin-${process.arch}`, "spawn-helper"));
|
|
123526
124117
|
} catch {}
|
|
123527
|
-
const bundledDistHelperPath =
|
|
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
|
|
123731
|
-
import { existsSync as
|
|
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 =
|
|
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 (!
|
|
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
|
|
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
|
|
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 &&
|
|
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 =
|
|
124781
|
+
const ext = extname3(absolutePath).toLowerCase();
|
|
124191
124782
|
switch (ext) {
|
|
124192
124783
|
case ".png":
|
|
124193
124784
|
return "image/png";
|