whipped 0.5.1 → 0.6.0
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/cli.js +119 -67
- package/dist/mcp-server.js +11 -1
- package/dist/sounds/blocked.wav +0 -0
- package/dist/sounds/done.wav +0 -0
- package/dist/sounds/pr-comment.wav +0 -0
- package/dist/sounds/ready-for-review.wav +0 -0
- package/dist/sounds/reopened.wav +0 -0
- package/dist/sounds/run-error.wav +0 -0
- package/dist/web-ui/assets/{index-BBh0-Z42.js → index-peNzhkq8.js} +125 -22
- package/dist/web-ui/index.html +1 -1
- package/package.json +25 -14
package/dist/cli.js
CHANGED
|
@@ -3529,7 +3529,7 @@ function isResumableSessionState(state) {
|
|
|
3529
3529
|
function normalizeTag(raw2) {
|
|
3530
3530
|
return raw2.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3531
3531
|
}
|
|
3532
|
-
var ASSISTANT_AGENT_PREFIX, runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeBulkCardImportItemSchema, runtimeBulkCardsCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
3532
|
+
var ASSISTANT_AGENT_PREFIX, runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, notificationSoundsConfigSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeBulkCardImportItemSchema, runtimeBulkCardsCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
3533
3533
|
var init_api_contract = __esm({
|
|
3534
3534
|
"src/core/api-contract.ts"() {
|
|
3535
3535
|
"use strict";
|
|
@@ -3847,6 +3847,15 @@ Do NOT include:
|
|
|
3847
3847
|
columns: z.array(runtimeBoardColumnSchema),
|
|
3848
3848
|
cards: z.record(z.string(), runtimeBoardCardSchema)
|
|
3849
3849
|
});
|
|
3850
|
+
notificationSoundsConfigSchema = z.object({
|
|
3851
|
+
enabled: z.boolean().default(false),
|
|
3852
|
+
readyForReview: z.boolean().default(true),
|
|
3853
|
+
prComment: z.boolean().default(true),
|
|
3854
|
+
done: z.boolean().default(true),
|
|
3855
|
+
reopened: z.boolean().default(true),
|
|
3856
|
+
blocked: z.boolean().default(true),
|
|
3857
|
+
runError: z.boolean().default(true)
|
|
3858
|
+
});
|
|
3850
3859
|
runtimeGlobalConfigSchema = z.object({
|
|
3851
3860
|
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
3852
3861
|
maxParallelTasks: z.number().int().positive().default(4),
|
|
@@ -3855,6 +3864,7 @@ Do NOT include:
|
|
|
3855
3864
|
pollingIntervalSeconds: z.number().int().positive().default(30),
|
|
3856
3865
|
prPollingIntervalSeconds: z.number().int().positive().default(60),
|
|
3857
3866
|
terminalApp: z.string().optional(),
|
|
3867
|
+
notificationSounds: notificationSoundsConfigSchema.prefault({}),
|
|
3858
3868
|
slackEnabled: z.boolean().default(true),
|
|
3859
3869
|
slackBotToken: z.string().optional(),
|
|
3860
3870
|
slackSigningSecret: z.string().optional(),
|
|
@@ -8973,7 +8983,7 @@ var require_tree_kill = __commonJS({
|
|
|
8973
8983
|
"node_modules/.pnpm/tree-kill@1.2.2/node_modules/tree-kill/index.js"(exports, module) {
|
|
8974
8984
|
"use strict";
|
|
8975
8985
|
var childProcess4 = __require("child_process");
|
|
8976
|
-
var
|
|
8986
|
+
var spawn9 = childProcess4.spawn;
|
|
8977
8987
|
var exec = childProcess4.exec;
|
|
8978
8988
|
module.exports = function(pid, signal, callback) {
|
|
8979
8989
|
if (typeof signal === "function" && callback === void 0) {
|
|
@@ -8998,7 +9008,7 @@ var require_tree_kill = __commonJS({
|
|
|
8998
9008
|
break;
|
|
8999
9009
|
case "darwin":
|
|
9000
9010
|
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
|
|
9001
|
-
return
|
|
9011
|
+
return spawn9("pgrep", ["-P", parentPid]);
|
|
9002
9012
|
}, function() {
|
|
9003
9013
|
killAll(tree, signal, callback);
|
|
9004
9014
|
});
|
|
@@ -9010,7 +9020,7 @@ var require_tree_kill = __commonJS({
|
|
|
9010
9020
|
// break;
|
|
9011
9021
|
default:
|
|
9012
9022
|
buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
|
|
9013
|
-
return
|
|
9023
|
+
return spawn9("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
|
|
9014
9024
|
}, function() {
|
|
9015
9025
|
killAll(tree, signal, callback);
|
|
9016
9026
|
});
|
|
@@ -13606,8 +13616,8 @@ init_logger();
|
|
|
13606
13616
|
// src/server/runtime-server.ts
|
|
13607
13617
|
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
13608
13618
|
import { createServer } from "node:http";
|
|
13609
|
-
import { join as
|
|
13610
|
-
import { fileURLToPath as
|
|
13619
|
+
import { join as join22 } from "node:path";
|
|
13620
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
13611
13621
|
import * as nodePty2 from "node-pty";
|
|
13612
13622
|
|
|
13613
13623
|
// node_modules/.pnpm/ws@8.20.0/node_modules/ws/wrapper.mjs
|
|
@@ -14389,6 +14399,39 @@ init_runtime_config();
|
|
|
14389
14399
|
init_logger();
|
|
14390
14400
|
init_task_id();
|
|
14391
14401
|
|
|
14402
|
+
// src/notifications/sound-player.ts
|
|
14403
|
+
init_runtime_config();
|
|
14404
|
+
init_logger();
|
|
14405
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
14406
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
14407
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
14408
|
+
var SOUNDS_DIR = join11(dirname4(fileURLToPath3(import.meta.url)), "sounds");
|
|
14409
|
+
var SOUND_FILES = {
|
|
14410
|
+
readyForReview: "ready-for-review.wav",
|
|
14411
|
+
prComment: "pr-comment.wav",
|
|
14412
|
+
done: "done.wav",
|
|
14413
|
+
reopened: "reopened.wav",
|
|
14414
|
+
blocked: "blocked.wav",
|
|
14415
|
+
runError: "run-error.wav"
|
|
14416
|
+
};
|
|
14417
|
+
async function playNotificationSound(event) {
|
|
14418
|
+
try {
|
|
14419
|
+
const { notificationSounds } = await loadGlobalConfig();
|
|
14420
|
+
if (!notificationSounds.enabled || !notificationSounds[event]) return;
|
|
14421
|
+
playOnHost(join11(SOUNDS_DIR, SOUND_FILES[event]));
|
|
14422
|
+
} catch (err) {
|
|
14423
|
+
logger.debug({ err }, `[sound] could not play notification sound for ${event}`);
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14426
|
+
function playOnHost(file) {
|
|
14427
|
+
const [command, args] = process.platform === "darwin" ? ["afplay", [file]] : process.platform === "linux" ? ["paplay", [file]] : [null, null];
|
|
14428
|
+
if (!command) return;
|
|
14429
|
+
const child = spawn4(command, [...args], { stdio: "ignore", detached: true });
|
|
14430
|
+
child.on("error", () => {
|
|
14431
|
+
});
|
|
14432
|
+
child.unref();
|
|
14433
|
+
}
|
|
14434
|
+
|
|
14392
14435
|
// src/daemon/poller.ts
|
|
14393
14436
|
init_runtime_config();
|
|
14394
14437
|
init_logger();
|
|
@@ -14400,7 +14443,7 @@ import { existsSync as existsSync8 } from "node:fs";
|
|
|
14400
14443
|
import { execFile as execFile7, spawnSync } from "node:child_process";
|
|
14401
14444
|
import { existsSync as existsSync5, mkdirSync as mkdirSync7, rmSync as rmSync2 } from "node:fs";
|
|
14402
14445
|
import { homedir as homedir2 } from "node:os";
|
|
14403
|
-
import { dirname as
|
|
14446
|
+
import { dirname as dirname5, join as join12, resolve, sep as sep2 } from "node:path";
|
|
14404
14447
|
import { promisify as promisify7 } from "node:util";
|
|
14405
14448
|
|
|
14406
14449
|
// node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
|
|
@@ -17953,7 +17996,7 @@ var Octokit2 = Octokit.plugin(requestLog, legacyRestEndpointMethods, paginateRes
|
|
|
17953
17996
|
// src/git/merge-operations.ts
|
|
17954
17997
|
init_logger();
|
|
17955
17998
|
var execFileAsync5 = promisify7(execFile7);
|
|
17956
|
-
var WORKTREES_DIR =
|
|
17999
|
+
var WORKTREES_DIR = join12(homedir2(), ".whipped", "worktrees");
|
|
17957
18000
|
function git(args, cwd) {
|
|
17958
18001
|
const r = spawnSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
17959
18002
|
return { stdout: r.stdout?.trim() ?? "", stderr: r.stderr?.trim() ?? "", ok: r.status === 0 };
|
|
@@ -18002,7 +18045,7 @@ async function commitIfDirty(worktreePath, message) {
|
|
|
18002
18045
|
return true;
|
|
18003
18046
|
}
|
|
18004
18047
|
function attemptMerge(repoPath, effectiveWorktreeId, taskBranch) {
|
|
18005
|
-
const worktreePath =
|
|
18048
|
+
const worktreePath = join12(WORKTREES_DIR, effectiveWorktreeId);
|
|
18006
18049
|
if (existsSync5(worktreePath)) {
|
|
18007
18050
|
rmSync2(worktreePath, { recursive: true, force: true });
|
|
18008
18051
|
git(["worktree", "prune"], repoPath);
|
|
@@ -18040,10 +18083,10 @@ async function pushBranch(worktreePath, branch) {
|
|
|
18040
18083
|
throw new Error(`Failed to push: ${detail}`);
|
|
18041
18084
|
});
|
|
18042
18085
|
}
|
|
18043
|
-
var YOLO_DIR =
|
|
18086
|
+
var YOLO_DIR = join12(WORKTREES_DIR, ".yolo");
|
|
18044
18087
|
function createYoloWorktree(repoPath, workspaceId, cardId, baseRef) {
|
|
18045
|
-
const tmpPath =
|
|
18046
|
-
mkdirSync7(
|
|
18088
|
+
const tmpPath = join12(YOLO_DIR, workspaceId, `${cardId}-${Date.now()}`);
|
|
18089
|
+
mkdirSync7(dirname5(tmpPath), { recursive: true });
|
|
18047
18090
|
git(["worktree", "prune"], repoPath);
|
|
18048
18091
|
const res = git(["worktree", "add", "--detach", tmpPath, baseRef], repoPath);
|
|
18049
18092
|
if (!res.ok) throw new Error(`Failed to create YOLO worktree at ${tmpPath}: ${res.stderr}`);
|
|
@@ -18268,10 +18311,10 @@ init_logger();
|
|
|
18268
18311
|
import { execFile as execFile8, spawnSync as spawnSync2 } from "node:child_process";
|
|
18269
18312
|
import { existsSync as existsSync6, mkdirSync as mkdirSync8 } from "node:fs";
|
|
18270
18313
|
import { rm as rm2 } from "node:fs/promises";
|
|
18271
|
-
import { join as
|
|
18314
|
+
import { join as join13 } from "node:path";
|
|
18272
18315
|
import { promisify as promisify8 } from "node:util";
|
|
18273
18316
|
var execFileAsync6 = promisify8(execFile8);
|
|
18274
|
-
var WORKTREES_DIR2 =
|
|
18317
|
+
var WORKTREES_DIR2 = join13(WHIPPED_HOME_DIR, "worktrees");
|
|
18275
18318
|
function git2(args, cwd) {
|
|
18276
18319
|
const result = spawnSync2("git", args, {
|
|
18277
18320
|
cwd,
|
|
@@ -18289,7 +18332,7 @@ function getCardBranch(card) {
|
|
|
18289
18332
|
function createWorktree(taskId, repoPath, baseRef, branchName) {
|
|
18290
18333
|
mkdirSync8(WORKTREES_DIR2, { recursive: true });
|
|
18291
18334
|
let branch = branchName ?? `task/${taskId}`;
|
|
18292
|
-
const worktreePath =
|
|
18335
|
+
const worktreePath = join13(WORKTREES_DIR2, taskId);
|
|
18293
18336
|
logger.info(`[worktree:create] taskId=${taskId} branch=${branch} baseRef=${baseRef} worktreePath=${worktreePath}`);
|
|
18294
18337
|
if (existsSync6(worktreePath)) {
|
|
18295
18338
|
const actualBranch = git2(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath);
|
|
@@ -18367,7 +18410,7 @@ function createWorktree(taskId, repoPath, baseRef, branchName) {
|
|
|
18367
18410
|
return { taskId, path: worktreePath, branch, isNew: true, conflictedFiles: [] };
|
|
18368
18411
|
}
|
|
18369
18412
|
async function removeWorktreeAsync(taskId, repoPath, branchName) {
|
|
18370
|
-
const worktreePath =
|
|
18413
|
+
const worktreePath = join13(WORKTREES_DIR2, taskId);
|
|
18371
18414
|
const branch = branchName ?? `task/${taskId}`;
|
|
18372
18415
|
const t0 = Date.now();
|
|
18373
18416
|
logger.info(`[cleanup:${taskId}] starting worktree removal`);
|
|
@@ -18389,7 +18432,7 @@ async function removeWorktreeAsync(taskId, repoPath, branchName) {
|
|
|
18389
18432
|
logger.info(`[cleanup:${taskId}] done in ${Date.now() - t0}ms`);
|
|
18390
18433
|
}
|
|
18391
18434
|
function getWorktreePath(taskId) {
|
|
18392
|
-
return
|
|
18435
|
+
return join13(WORKTREES_DIR2, taskId);
|
|
18393
18436
|
}
|
|
18394
18437
|
function resolveWorktreeOwnerId(cardId, cards) {
|
|
18395
18438
|
const story = Object.values(cards).find((c) => c.type === "story" && (c.subtaskIds ?? []).includes(cardId));
|
|
@@ -18849,6 +18892,7 @@ var BoardPoller = class {
|
|
|
18849
18892
|
`[poller] ${readyEntries.length} new comment(s) from GitHub PR for "${card.description?.split("\n")[0]?.slice(0, 60) ?? card.id}"`
|
|
18850
18893
|
);
|
|
18851
18894
|
await appendActivityLog(workspaceId, taskId, `${readyEntries.length} new comment(s) imported from GitHub PR`);
|
|
18895
|
+
void playNotificationSound("prComment");
|
|
18852
18896
|
}
|
|
18853
18897
|
updated = true;
|
|
18854
18898
|
}
|
|
@@ -18859,6 +18903,7 @@ var BoardPoller = class {
|
|
|
18859
18903
|
await moveCard(workspaceId, taskId, "done");
|
|
18860
18904
|
await clearCardSession(workspaceId, taskId);
|
|
18861
18905
|
await appendActivityLog(workspaceId, taskId, "PR merged on GitHub \u2192 Done");
|
|
18906
|
+
void playNotificationSound("done");
|
|
18862
18907
|
const boardAfterDone = await loadBoard(workspaceId);
|
|
18863
18908
|
const ownerId = resolveWorktreeOwnerId(taskId, boardAfterDone.cards);
|
|
18864
18909
|
const groupCards = Object.values(boardAfterDone.cards).filter(
|
|
@@ -18876,6 +18921,7 @@ var BoardPoller = class {
|
|
|
18876
18921
|
await moveCard(workspaceId, taskId, "blocked");
|
|
18877
18922
|
await clearCardSession(workspaceId, taskId);
|
|
18878
18923
|
await appendActivityLog(workspaceId, taskId, "PR closed without merging \u2192 Blocked");
|
|
18924
|
+
void playNotificationSound("blocked");
|
|
18879
18925
|
updated = true;
|
|
18880
18926
|
} else if (info2.mergeable === "CONFLICTING") {
|
|
18881
18927
|
if (!card.terminalSessions?.some((ts) => !ts.endedAt)) {
|
|
@@ -18892,6 +18938,7 @@ var BoardPoller = class {
|
|
|
18892
18938
|
await moveCard(workspaceId, taskId, "reopened");
|
|
18893
18939
|
await appendActivityLog(workspaceId, taskId, `${reason} \u2192 Reopened`);
|
|
18894
18940
|
await clearCardSession(workspaceId, taskId);
|
|
18941
|
+
void playNotificationSound("reopened");
|
|
18895
18942
|
updated = true;
|
|
18896
18943
|
}
|
|
18897
18944
|
if (updated) stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
@@ -19002,10 +19049,10 @@ function buildCodexEffortOverride(effort) {
|
|
|
19002
19049
|
|
|
19003
19050
|
// src/agents/playwright-mcp.ts
|
|
19004
19051
|
init_runtime_config();
|
|
19005
|
-
import { join as
|
|
19052
|
+
import { join as join14 } from "node:path";
|
|
19006
19053
|
var PLAYWRIGHT_MCP_SERVER_NAME = "playwright";
|
|
19007
19054
|
function buildBrowserMcpServer(cardId) {
|
|
19008
|
-
const outputDir =
|
|
19055
|
+
const outputDir = join14(ATTACHMENTS_DIR, cardId);
|
|
19009
19056
|
return {
|
|
19010
19057
|
command: "npx",
|
|
19011
19058
|
args: ["-y", "@playwright/mcp", "--headless", "--isolated", "--output-dir", outputDir],
|
|
@@ -20389,22 +20436,22 @@ init_workspace_state();
|
|
|
20389
20436
|
init_workspace_state();
|
|
20390
20437
|
|
|
20391
20438
|
// src/daemon/scheduler.ts
|
|
20392
|
-
import { spawn as
|
|
20439
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
20393
20440
|
import { cpSync, existsSync as existsSync10, mkdirSync as mkdirSync9 } from "node:fs";
|
|
20394
20441
|
import { unlink as unlink2 } from "node:fs/promises";
|
|
20395
|
-
import { dirname as
|
|
20396
|
-
import { fileURLToPath as
|
|
20442
|
+
import { dirname as dirname6, join as join17, resolve as resolve2 } from "node:path";
|
|
20443
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
20397
20444
|
init_api_contract();
|
|
20398
20445
|
init_logger();
|
|
20399
20446
|
|
|
20400
20447
|
// src/core/prompt-resolver.ts
|
|
20401
20448
|
init_logger();
|
|
20402
20449
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
20403
|
-
import { isAbsolute, join as
|
|
20450
|
+
import { isAbsolute, join as join15 } from "node:path";
|
|
20404
20451
|
function resolvePromptText(prompt, repoPath) {
|
|
20405
20452
|
if (!prompt) return "";
|
|
20406
20453
|
if (prompt.source === "inline") return prompt.text;
|
|
20407
|
-
const path2 = isAbsolute(prompt.path) ? prompt.path :
|
|
20454
|
+
const path2 = isAbsolute(prompt.path) ? prompt.path : join15(repoPath, prompt.path);
|
|
20408
20455
|
try {
|
|
20409
20456
|
return readFileSync5(path2, "utf-8");
|
|
20410
20457
|
} catch (err) {
|
|
@@ -20421,7 +20468,7 @@ init_workspace_state();
|
|
|
20421
20468
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
20422
20469
|
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
|
|
20423
20470
|
import { readdir, readFile as readFile2, stat, unlink } from "node:fs/promises";
|
|
20424
|
-
import { join as
|
|
20471
|
+
import { join as join16 } from "node:path";
|
|
20425
20472
|
init_runtime_config();
|
|
20426
20473
|
init_api_contract();
|
|
20427
20474
|
init_logger();
|
|
@@ -20706,7 +20753,7 @@ function getSlotTriggerWord(type) {
|
|
|
20706
20753
|
}
|
|
20707
20754
|
var SCREENSHOT_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "webp"]);
|
|
20708
20755
|
async function attachBrowserArtifacts(workspaceId, card, result, since) {
|
|
20709
|
-
const dir =
|
|
20756
|
+
const dir = join16(ATTACHMENTS_DIR, card.id);
|
|
20710
20757
|
let entries;
|
|
20711
20758
|
try {
|
|
20712
20759
|
entries = await readdir(dir);
|
|
@@ -20719,7 +20766,7 @@ async function attachBrowserArtifacts(workspaceId, card, result, since) {
|
|
|
20719
20766
|
for (const name of entries) {
|
|
20720
20767
|
const ext = name.split(".").pop()?.toLowerCase() ?? "";
|
|
20721
20768
|
if (!SCREENSHOT_EXTENSIONS.has(ext)) continue;
|
|
20722
|
-
const filePath =
|
|
20769
|
+
const filePath = join16(dir, name);
|
|
20723
20770
|
try {
|
|
20724
20771
|
const info2 = await stat(filePath);
|
|
20725
20772
|
if (!info2.isFile() || info2.mtimeMs < since) continue;
|
|
@@ -20862,6 +20909,7 @@ async function handleReviewSuccess(card, options) {
|
|
|
20862
20909
|
await moveCard(workspaceId, card.id, "ready_for_review");
|
|
20863
20910
|
await appendActivityLog(workspaceId, card.id, "All reviews passed \u2192 moved to Ready for Review");
|
|
20864
20911
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
20912
|
+
void playNotificationSound("readyForReview");
|
|
20865
20913
|
if (deliveryMode === "off") return;
|
|
20866
20914
|
if (card.type === "subtask") return;
|
|
20867
20915
|
if (deliveryMode === "yolo") {
|
|
@@ -21022,7 +21070,7 @@ ${diffParts.join("\n")}
|
|
|
21022
21070
|
if (newUntracked.length > 0) {
|
|
21023
21071
|
const newFileContents = [];
|
|
21024
21072
|
for (const file of newUntracked) {
|
|
21025
|
-
const content = readFileSafe(
|
|
21073
|
+
const content = readFileSafe(join16(worktreePath, file));
|
|
21026
21074
|
const ext = file.split(".").pop() ?? "";
|
|
21027
21075
|
newFileContents.push(content ? `### ${file}
|
|
21028
21076
|
\`\`\`${ext}
|
|
@@ -22019,10 +22067,10 @@ ${assistantSystemPrompt}` : assistantSystemPrompt;
|
|
|
22019
22067
|
if (filesToCopy.length > 0) {
|
|
22020
22068
|
const copied = [];
|
|
22021
22069
|
for (const relPath of filesToCopy) {
|
|
22022
|
-
const src =
|
|
22070
|
+
const src = join17(repoPath, relPath);
|
|
22023
22071
|
if (!existsSync10(src)) continue;
|
|
22024
|
-
const dst =
|
|
22025
|
-
mkdirSync9(
|
|
22072
|
+
const dst = join17(worktree.path, relPath);
|
|
22073
|
+
mkdirSync9(dirname6(dst), { recursive: true });
|
|
22026
22074
|
try {
|
|
22027
22075
|
cpSync(src, dst, { recursive: true });
|
|
22028
22076
|
copied.push(relPath);
|
|
@@ -22038,7 +22086,7 @@ ${assistantSystemPrompt}` : assistantSystemPrompt;
|
|
|
22038
22086
|
await appendActivityLog(workspaceId, taskId, `Running: ${installCommand.trim()}`);
|
|
22039
22087
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22040
22088
|
await new Promise((resolve5) => {
|
|
22041
|
-
const proc =
|
|
22089
|
+
const proc = spawn6("sh", ["-c", installCommand.trim()], {
|
|
22042
22090
|
cwd: worktree.path,
|
|
22043
22091
|
stdio: "ignore",
|
|
22044
22092
|
env: { ...process.env, REPO_PATH: repoPath }
|
|
@@ -22242,6 +22290,7 @@ ${devSystemPromptResult.text}`;
|
|
|
22242
22290
|
if (!hasReviewSlots) {
|
|
22243
22291
|
await moveCard(workspaceId, taskId, "ready_for_review");
|
|
22244
22292
|
await appendActivityLog(workspaceId, taskId, "Agent finished \u2192 moved to Ready for Review");
|
|
22293
|
+
void playNotificationSound("readyForReview");
|
|
22245
22294
|
} else {
|
|
22246
22295
|
await appendActivityLog(workspaceId, taskId, "Agent finished \u2192 AI review starting");
|
|
22247
22296
|
}
|
|
@@ -22268,6 +22317,7 @@ ${devSystemPromptResult.text}`;
|
|
|
22268
22317
|
);
|
|
22269
22318
|
}
|
|
22270
22319
|
await moveCard(workspaceId, taskId, destination);
|
|
22320
|
+
void playNotificationSound(destination === "blocked" ? "blocked" : "reopened");
|
|
22271
22321
|
}
|
|
22272
22322
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22273
22323
|
this.options.onTaskCompleted(taskId);
|
|
@@ -22469,6 +22519,7 @@ ${devSystemPromptResult.text}`;
|
|
|
22469
22519
|
if (!hookHasReview) {
|
|
22470
22520
|
await moveCard(workspaceId, taskId, "ready_for_review");
|
|
22471
22521
|
await appendActivityLog(workspaceId, taskId, "Agent finished \u2192 moved to Ready for Review");
|
|
22522
|
+
void playNotificationSound("readyForReview");
|
|
22472
22523
|
} else {
|
|
22473
22524
|
await appendActivityLog(workspaceId, taskId, "Agent finished \u2192 AI review starting");
|
|
22474
22525
|
}
|
|
@@ -22568,8 +22619,8 @@ ${devSystemPromptResult.text}`;
|
|
|
22568
22619
|
}
|
|
22569
22620
|
};
|
|
22570
22621
|
function getMcpServerPath() {
|
|
22571
|
-
const thisFile =
|
|
22572
|
-
const thisDir =
|
|
22622
|
+
const thisFile = fileURLToPath4(import.meta.url);
|
|
22623
|
+
const thisDir = dirname6(thisFile);
|
|
22573
22624
|
const isDev = thisFile.endsWith(".ts");
|
|
22574
22625
|
if (isDev) {
|
|
22575
22626
|
const projectRoot = resolve2(thisDir, "../..");
|
|
@@ -26406,13 +26457,13 @@ init_runtime_config();
|
|
|
26406
26457
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
26407
26458
|
import { existsSync as existsSync12, readdirSync as readdirSync2, statSync } from "node:fs";
|
|
26408
26459
|
import { homedir as homedir4 } from "node:os";
|
|
26409
|
-
import { dirname as
|
|
26460
|
+
import { dirname as dirname7, join as join19, resolve as resolve3 } from "node:path";
|
|
26410
26461
|
|
|
26411
26462
|
// src/core/terminal-apps.ts
|
|
26412
26463
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
26413
26464
|
import { existsSync as existsSync11 } from "node:fs";
|
|
26414
26465
|
import { homedir as homedir3 } from "node:os";
|
|
26415
|
-
import { join as
|
|
26466
|
+
import { join as join18 } from "node:path";
|
|
26416
26467
|
var MACOS_TERMINALS = [
|
|
26417
26468
|
{ bundle: "Terminal", label: "Terminal" },
|
|
26418
26469
|
{ bundle: "iTerm", label: "iTerm" },
|
|
@@ -26444,7 +26495,7 @@ function appExists(bundle) {
|
|
|
26444
26495
|
`/Applications/${bundle}.app`,
|
|
26445
26496
|
`/System/Applications/${bundle}.app`,
|
|
26446
26497
|
`/System/Applications/Utilities/${bundle}.app`,
|
|
26447
|
-
|
|
26498
|
+
join18(homedir3(), "Applications", `${bundle}.app`)
|
|
26448
26499
|
];
|
|
26449
26500
|
return paths.some((p2) => existsSync11(p2));
|
|
26450
26501
|
}
|
|
@@ -26520,15 +26571,15 @@ var openTerminal = async (path2) => {
|
|
|
26520
26571
|
};
|
|
26521
26572
|
var listDir = async (path2, includeFiles, showHidden) => {
|
|
26522
26573
|
let target = resolve3(path2 || homedir4());
|
|
26523
|
-
while (target !==
|
|
26524
|
-
target =
|
|
26574
|
+
while (target !== dirname7(target) && !(existsSync12(target) && statSync(target).isDirectory())) {
|
|
26575
|
+
target = dirname7(target);
|
|
26525
26576
|
}
|
|
26526
|
-
const parent =
|
|
26577
|
+
const parent = dirname7(target);
|
|
26527
26578
|
const visible = (name) => showHidden || !name.startsWith(".");
|
|
26528
26579
|
try {
|
|
26529
26580
|
const entries = readdirSync2(target, { withFileTypes: true });
|
|
26530
|
-
const dirs = entries.filter((e) => e.isDirectory() && visible(e.name)).map((e) => ({ name: e.name, path:
|
|
26531
|
-
const files = includeFiles ? entries.filter((e) => e.isFile() && visible(e.name)).map((e) => ({ name: e.name, path:
|
|
26581
|
+
const dirs = entries.filter((e) => e.isDirectory() && visible(e.name)).map((e) => ({ name: e.name, path: join19(target, e.name) })).sort((a, b2) => a.name.localeCompare(b2.name));
|
|
26582
|
+
const files = includeFiles ? entries.filter((e) => e.isFile() && visible(e.name)).map((e) => ({ name: e.name, path: join19(target, e.name) })).sort((a, b2) => a.name.localeCompare(b2.name)) : [];
|
|
26532
26583
|
return { current: target, parent: parent !== target ? parent : null, dirs, files };
|
|
26533
26584
|
} catch {
|
|
26534
26585
|
return { current: target, parent: parent !== target ? parent : null, dirs: [], files: [] };
|
|
@@ -26984,7 +27035,7 @@ var removeProject = async (workspaceId) => {
|
|
|
26984
27035
|
const cards = boardCards;
|
|
26985
27036
|
enqueueCleanup2(async () => {
|
|
26986
27037
|
const { rm: rm3 } = await import("node:fs/promises");
|
|
26987
|
-
const { join:
|
|
27038
|
+
const { join: join23 } = await import("node:path");
|
|
26988
27039
|
for (const [cardId, card] of Object.entries(cards)) {
|
|
26989
27040
|
if (resolveWorktreeOwnerId(cardId, cards) === cardId) {
|
|
26990
27041
|
await removeWorktreeAsync(cardId, repoPath, card.branchName).catch((err) => {
|
|
@@ -26992,11 +27043,11 @@ var removeProject = async (workspaceId) => {
|
|
|
26992
27043
|
});
|
|
26993
27044
|
}
|
|
26994
27045
|
}
|
|
26995
|
-
await rm3(
|
|
27046
|
+
await rm3(join23(WORKSPACES_DIR, workspaceId), { recursive: true, force: true }).catch((err) => {
|
|
26996
27047
|
logger.warn(`[cleanup:project:${workspaceId}] workspace dir failed: ${String(err)}`);
|
|
26997
27048
|
});
|
|
26998
27049
|
for (const cardId of Object.keys(cards)) {
|
|
26999
|
-
await rm3(
|
|
27050
|
+
await rm3(join23(ATTACHMENTS_DIR, cardId), { recursive: true, force: true }).catch(() => {
|
|
27000
27051
|
});
|
|
27001
27052
|
}
|
|
27002
27053
|
logger.info(`[cleanup:project:${workspaceId}] done`);
|
|
@@ -27287,13 +27338,13 @@ init_runtime_config();
|
|
|
27287
27338
|
// src/tunnel/cloudflare-setup.ts
|
|
27288
27339
|
init_runtime_config();
|
|
27289
27340
|
init_logger();
|
|
27290
|
-
import { execFile as execFile9, spawn as
|
|
27341
|
+
import { execFile as execFile9, spawn as spawn7 } from "node:child_process";
|
|
27291
27342
|
import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile3, access, unlink as unlink4 } from "node:fs/promises";
|
|
27292
27343
|
import { homedir as homedir5 } from "node:os";
|
|
27293
|
-
import { join as
|
|
27344
|
+
import { join as join20 } from "node:path";
|
|
27294
27345
|
import { promisify as promisify9 } from "node:util";
|
|
27295
27346
|
var execFileAsync7 = promisify9(execFile9);
|
|
27296
|
-
var CLOUDFLARED_DIR =
|
|
27347
|
+
var CLOUDFLARED_DIR = join20(homedir5(), ".cloudflared");
|
|
27297
27348
|
async function checkCloudflaredInstalled() {
|
|
27298
27349
|
try {
|
|
27299
27350
|
const { stdout } = await execFileAsync7("cloudflared", ["--version"]);
|
|
@@ -27305,7 +27356,7 @@ async function checkCloudflaredInstalled() {
|
|
|
27305
27356
|
}
|
|
27306
27357
|
async function checkCloudflaredAuth() {
|
|
27307
27358
|
try {
|
|
27308
|
-
await access(
|
|
27359
|
+
await access(join20(CLOUDFLARED_DIR, "cert.pem"));
|
|
27309
27360
|
return true;
|
|
27310
27361
|
} catch {
|
|
27311
27362
|
return false;
|
|
@@ -27316,12 +27367,12 @@ async function openCloudflaredLogin(force = false) {
|
|
|
27316
27367
|
if (alreadyLoggedIn && !force) return { alreadyLoggedIn: true };
|
|
27317
27368
|
if (force) {
|
|
27318
27369
|
try {
|
|
27319
|
-
await unlink4(
|
|
27370
|
+
await unlink4(join20(CLOUDFLARED_DIR, "cert.pem"));
|
|
27320
27371
|
} catch {
|
|
27321
27372
|
}
|
|
27322
27373
|
}
|
|
27323
27374
|
return new Promise((resolve5) => {
|
|
27324
|
-
const proc =
|
|
27375
|
+
const proc = spawn7("cloudflared", ["tunnel", "login"], {
|
|
27325
27376
|
stdio: ["ignore", "pipe", "pipe"]
|
|
27326
27377
|
});
|
|
27327
27378
|
let buffer = "";
|
|
@@ -27334,7 +27385,7 @@ async function openCloudflaredLogin(force = false) {
|
|
|
27334
27385
|
resolved = true;
|
|
27335
27386
|
const loginUrl = match2[1].trim();
|
|
27336
27387
|
logger.info(`[cloudflared-login] Auth URL: ${loginUrl}`);
|
|
27337
|
-
|
|
27388
|
+
spawn7("open", [loginUrl], { stdio: "ignore" });
|
|
27338
27389
|
proc.unref();
|
|
27339
27390
|
resolve5({ alreadyLoggedIn: false, loginUrl });
|
|
27340
27391
|
}
|
|
@@ -27384,7 +27435,7 @@ async function createTunnel(tunnelName) {
|
|
|
27384
27435
|
}
|
|
27385
27436
|
}
|
|
27386
27437
|
async function writeTunnelConfig(tunnelId, tunnelName, domain) {
|
|
27387
|
-
const credentialsFile =
|
|
27438
|
+
const credentialsFile = join20(CLOUDFLARED_DIR, `${tunnelId}.json`);
|
|
27388
27439
|
const config = [
|
|
27389
27440
|
`tunnel: ${tunnelId}`,
|
|
27390
27441
|
`credentials-file: ${credentialsFile}`,
|
|
@@ -27395,12 +27446,12 @@ async function writeTunnelConfig(tunnelId, tunnelName, domain) {
|
|
|
27395
27446
|
` - service: http_status:404`
|
|
27396
27447
|
].join("\n");
|
|
27397
27448
|
await mkdir3(CLOUDFLARED_DIR, { recursive: true });
|
|
27398
|
-
await writeFile3(
|
|
27449
|
+
await writeFile3(join20(CLOUDFLARED_DIR, "config.yml"), config, "utf-8");
|
|
27399
27450
|
logger.info(`[tunnel-setup] Wrote ~/.cloudflared/config.yml for tunnel ${tunnelName}`);
|
|
27400
27451
|
}
|
|
27401
27452
|
async function readTunnelConfig() {
|
|
27402
27453
|
try {
|
|
27403
|
-
const raw2 = await readFile3(
|
|
27454
|
+
const raw2 = await readFile3(join20(CLOUDFLARED_DIR, "config.yml"), "utf-8");
|
|
27404
27455
|
const tunnelMatch = raw2.match(/^tunnel:\s*(.+)$/m);
|
|
27405
27456
|
const hostnameMatch = raw2.match(/hostname:\s*(.+)$/m);
|
|
27406
27457
|
return {
|
|
@@ -27449,9 +27500,9 @@ var resetTunnel = async () => {
|
|
|
27449
27500
|
await updateGlobalConfig({ tunnelId: void 0, tunnelDomain: void 0, autoStartTunnel: false });
|
|
27450
27501
|
const { unlink: unlink5 } = await import("node:fs/promises");
|
|
27451
27502
|
const { homedir: homedir6 } = await import("node:os");
|
|
27452
|
-
const { join:
|
|
27503
|
+
const { join: join23 } = await import("node:path");
|
|
27453
27504
|
try {
|
|
27454
|
-
await unlink5(
|
|
27505
|
+
await unlink5(join23(homedir6(), ".cloudflared", "config.yml"));
|
|
27455
27506
|
} catch {
|
|
27456
27507
|
}
|
|
27457
27508
|
};
|
|
@@ -27484,7 +27535,7 @@ import { z as z15 } from "zod";
|
|
|
27484
27535
|
init_workspace_state();
|
|
27485
27536
|
import { existsSync as existsSync13 } from "node:fs";
|
|
27486
27537
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
27487
|
-
import { dirname as
|
|
27538
|
+
import { dirname as dirname8, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
|
|
27488
27539
|
var resolvePromptPath = async (workspaceId, requestedPath) => {
|
|
27489
27540
|
const workspaces = await listWorkspaces();
|
|
27490
27541
|
const ws = workspaces.find((w2) => w2.workspaceId === workspaceId);
|
|
@@ -27521,7 +27572,7 @@ var deleteWorkflow = async (workspaceId, workflowId) => {
|
|
|
27521
27572
|
};
|
|
27522
27573
|
var writePromptFile = async (workspaceId, path2, content) => {
|
|
27523
27574
|
const targetPath = await resolvePromptPath(workspaceId, path2);
|
|
27524
|
-
await mkdir4(
|
|
27575
|
+
await mkdir4(dirname8(targetPath), { recursive: true });
|
|
27525
27576
|
await writeFile4(targetPath, content, "utf-8");
|
|
27526
27577
|
return { path: path2 };
|
|
27527
27578
|
};
|
|
@@ -27745,8 +27796,8 @@ var RuntimeStateHub = class {
|
|
|
27745
27796
|
// src/core/update-check.ts
|
|
27746
27797
|
init_paths();
|
|
27747
27798
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
|
|
27748
|
-
import { join as
|
|
27749
|
-
var CACHE_FILE =
|
|
27799
|
+
import { join as join21 } from "node:path";
|
|
27800
|
+
var CACHE_FILE = join21(WHIPPED_HOME_DIR, "update-check.json");
|
|
27750
27801
|
var REGISTRY_URL = "https://registry.npmjs.org/whipped/latest";
|
|
27751
27802
|
var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
|
|
27752
27803
|
function readCache() {
|
|
@@ -27797,7 +27848,7 @@ function scheduleUpdateChecks(currentVersion, onUpdate) {
|
|
|
27797
27848
|
}
|
|
27798
27849
|
|
|
27799
27850
|
// src/server/runtime-server.ts
|
|
27800
|
-
var __dirname2 =
|
|
27851
|
+
var __dirname2 = fileURLToPath5(new URL(".", import.meta.url));
|
|
27801
27852
|
async function cleanupStaleTasks(workspaceId, hub) {
|
|
27802
27853
|
const board = await loadBoard(workspaceId);
|
|
27803
27854
|
const now = Date.now();
|
|
@@ -27894,6 +27945,7 @@ async function createRuntimeServer(options) {
|
|
|
27894
27945
|
session.status = "error";
|
|
27895
27946
|
session.errorMessage = `Process exited with code ${exitCode}`;
|
|
27896
27947
|
stateHub.broadcastRunSessionChange(workspaceId, cardId, "error", session.errorMessage);
|
|
27948
|
+
void playNotificationSound("runError");
|
|
27897
27949
|
}
|
|
27898
27950
|
});
|
|
27899
27951
|
}
|
|
@@ -28032,8 +28084,8 @@ async function createRuntimeServer(options) {
|
|
|
28032
28084
|
};
|
|
28033
28085
|
}
|
|
28034
28086
|
const apiApp = createApiApp(createContext());
|
|
28035
|
-
const webUiDistPath =
|
|
28036
|
-
const webUiIndexPath =
|
|
28087
|
+
const webUiDistPath = join22(__dirname2, "web-ui");
|
|
28088
|
+
const webUiIndexPath = join22(webUiDistPath, "index.html");
|
|
28037
28089
|
const hasWebUi = existsSync14(webUiIndexPath);
|
|
28038
28090
|
const httpServer = createServer(async (req, res) => {
|
|
28039
28091
|
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -28267,7 +28319,7 @@ async function createRuntimeServer(options) {
|
|
|
28267
28319
|
res.end("Bad request");
|
|
28268
28320
|
return;
|
|
28269
28321
|
}
|
|
28270
|
-
const filePath =
|
|
28322
|
+
const filePath = join22(ATTACHMENTS_DIR, cardId, filename);
|
|
28271
28323
|
const { readFile: readFile5 } = await import("node:fs/promises");
|
|
28272
28324
|
try {
|
|
28273
28325
|
const data = await readFile5(filePath);
|
|
@@ -28342,7 +28394,7 @@ async function createRuntimeServer(options) {
|
|
|
28342
28394
|
return;
|
|
28343
28395
|
}
|
|
28344
28396
|
if (hasWebUi) {
|
|
28345
|
-
const filePath = url.pathname === "/" || !url.pathname.includes(".") ? webUiIndexPath :
|
|
28397
|
+
const filePath = url.pathname === "/" || !url.pathname.includes(".") ? webUiIndexPath : join22(webUiDistPath, url.pathname);
|
|
28346
28398
|
if (existsSync14(filePath)) {
|
|
28347
28399
|
const content = readFileSync8(filePath);
|
|
28348
28400
|
res.writeHead(200, { "Content-Type": getContentType(filePath) });
|
|
@@ -28561,7 +28613,7 @@ process.on("uncaughtException", (err) => {
|
|
|
28561
28613
|
if (err.code === "EPIPE" || err.code === "ECONNRESET") return;
|
|
28562
28614
|
throw err;
|
|
28563
28615
|
});
|
|
28564
|
-
var VERSION9 = true ? "0.
|
|
28616
|
+
var VERSION9 = true ? "0.6.0" : "0.0.0-dev";
|
|
28565
28617
|
async function isPortAvailable(port, host) {
|
|
28566
28618
|
return new Promise((resolve5) => {
|
|
28567
28619
|
const probe = createServer2();
|
package/dist/mcp-server.js
CHANGED
|
@@ -33,7 +33,7 @@ function highestWorkflowLevel(workflow) {
|
|
|
33
33
|
}
|
|
34
34
|
return LEVEL_ORDER[bestIdx] ?? "medium";
|
|
35
35
|
}
|
|
36
|
-
var ASSISTANT_AGENT_PREFIX, runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeBulkCardImportItemSchema, runtimeBulkCardsCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
36
|
+
var ASSISTANT_AGENT_PREFIX, runtimeAgentIdSchema, effortLevelSchema, agentModelChoiceSchema, workflowSlotTypeSchema, tierLevelSchema, LEVEL_ORDER, modelPairSchema, pairSelectionModeSchema, SLOT_TOOL_IDS, slotToolSchema, slotModelConfigSchema, cardModelConfigSchema, promptValueSchema, EMPTY_INLINE_PROMPT, workflowSlotSchema, DEFAULT_MODEL_PAIR, DEFAULT_SLOT_MODEL_FIELDS, workflowSchema, DEFAULT_WORKFLOW, DEFAULT_STORY_WORKFLOW, DEFAULT_GIT_INSTRUCTIONS, runtimeBoardColumnIdSchema, BOARD_COLUMNS, reviewActorSchema, reviewIssueSchema, reviewAttachmentSchema, runtimeReviewCommentSchema, runtimeActivityEntrySchema, runtimeTaskSessionStateSchema, runtimeTerminalSessionEntrySchema, runtimeCardPrioritySchema, cardTypeSchema, runtimePrMetaSchema, runtimeBoardCardSchema, runtimeBoardColumnSchema, runtimeBoardDataSchema, notificationSoundsConfigSchema, runtimeGlobalConfigSchema, runtimeGithubConfigSchema, runtimeWorktreeSetupSchema, runtimeProjectSecretSchema, runtimeProjectConfigSchema, runtimeWorkspaceStateResponseSchema, runtimeWorkspaceStateSaveRequestSchema, runtimeVisualElementSchema, runtimeVisualCommentSchema, runtimeCardCreateRequestSchema, runtimeBulkCardImportItemSchema, runtimeBulkCardsCreateRequestSchema, runtimeCardMoveRequestSchema, runtimeCardUpdateRequestSchema, memoryScopeSchema, memoryTypeSchema, memorySourceTypeSchema, memoryStatusSchema, runtimeMemoryOriginAgentSchema, runtimeMemorySchema, recurringScheduleKindSchema, recurringScheduleSchema, recurringRunStatusSchema, recurringRunTriggerSchema, recurringAgentRunSchema, recurringAgentSchema, recurringAgentCreateRequestSchema, recurringAgentUpdateRequestSchema, projectFolderSchema, topLevelItemSchema, projectsLayoutSchema, runtimeProjectSchema;
|
|
37
37
|
var init_api_contract = __esm({
|
|
38
38
|
"src/core/api-contract.ts"() {
|
|
39
39
|
"use strict";
|
|
@@ -351,6 +351,15 @@ Do NOT include:
|
|
|
351
351
|
columns: z.array(runtimeBoardColumnSchema),
|
|
352
352
|
cards: z.record(z.string(), runtimeBoardCardSchema)
|
|
353
353
|
});
|
|
354
|
+
notificationSoundsConfigSchema = z.object({
|
|
355
|
+
enabled: z.boolean().default(false),
|
|
356
|
+
readyForReview: z.boolean().default(true),
|
|
357
|
+
prComment: z.boolean().default(true),
|
|
358
|
+
done: z.boolean().default(true),
|
|
359
|
+
reopened: z.boolean().default(true),
|
|
360
|
+
blocked: z.boolean().default(true),
|
|
361
|
+
runError: z.boolean().default(true)
|
|
362
|
+
});
|
|
354
363
|
runtimeGlobalConfigSchema = z.object({
|
|
355
364
|
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
356
365
|
maxParallelTasks: z.number().int().positive().default(4),
|
|
@@ -359,6 +368,7 @@ Do NOT include:
|
|
|
359
368
|
pollingIntervalSeconds: z.number().int().positive().default(30),
|
|
360
369
|
prPollingIntervalSeconds: z.number().int().positive().default(60),
|
|
361
370
|
terminalApp: z.string().optional(),
|
|
371
|
+
notificationSounds: notificationSoundsConfigSchema.prefault({}),
|
|
362
372
|
slackEnabled: z.boolean().default(true),
|
|
363
373
|
slackBotToken: z.string().optional(),
|
|
364
374
|
slackSigningSecret: z.string().optional(),
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -21339,22 +21339,39 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
21339
21339
|
* This source code is licensed under the ISC license.
|
|
21340
21340
|
* See the LICENSE file in the root directory of this source tree.
|
|
21341
21341
|
*/
|
|
21342
|
-
const __iconNode$
|
|
21342
|
+
const __iconNode$19 = [
|
|
21343
21343
|
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
21344
21344
|
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
21345
21345
|
];
|
|
21346
|
-
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$
|
|
21346
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$19);
|
|
21347
21347
|
/**
|
|
21348
21348
|
* @license lucide-react v0.577.0 - ISC
|
|
21349
21349
|
*
|
|
21350
21350
|
* This source code is licensed under the ISC license.
|
|
21351
21351
|
* See the LICENSE file in the root directory of this source tree.
|
|
21352
21352
|
*/
|
|
21353
|
-
const __iconNode$
|
|
21353
|
+
const __iconNode$18 = [
|
|
21354
21354
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
21355
21355
|
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
21356
21356
|
];
|
|
21357
|
-
const ArrowRight = createLucideIcon("arrow-right", __iconNode$
|
|
21357
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$18);
|
|
21358
|
+
/**
|
|
21359
|
+
* @license lucide-react v0.577.0 - ISC
|
|
21360
|
+
*
|
|
21361
|
+
* This source code is licensed under the ISC license.
|
|
21362
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
21363
|
+
*/
|
|
21364
|
+
const __iconNode$17 = [
|
|
21365
|
+
["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
|
|
21366
|
+
[
|
|
21367
|
+
"path",
|
|
21368
|
+
{
|
|
21369
|
+
d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",
|
|
21370
|
+
key: "11g9vi"
|
|
21371
|
+
}
|
|
21372
|
+
]
|
|
21373
|
+
];
|
|
21374
|
+
const Bell = createLucideIcon("bell", __iconNode$17);
|
|
21358
21375
|
/**
|
|
21359
21376
|
* @license lucide-react v0.577.0 - ISC
|
|
21360
21377
|
*
|
|
@@ -27543,6 +27560,15 @@ const runtimeBoardDataSchema = object({
|
|
|
27543
27560
|
columns: array(runtimeBoardColumnSchema),
|
|
27544
27561
|
cards: record(string$2(), runtimeBoardCardSchema)
|
|
27545
27562
|
});
|
|
27563
|
+
const notificationSoundsConfigSchema = object({
|
|
27564
|
+
enabled: boolean$1().default(false),
|
|
27565
|
+
readyForReview: boolean$1().default(true),
|
|
27566
|
+
prComment: boolean$1().default(true),
|
|
27567
|
+
done: boolean$1().default(true),
|
|
27568
|
+
reopened: boolean$1().default(true),
|
|
27569
|
+
blocked: boolean$1().default(true),
|
|
27570
|
+
runError: boolean$1().default(true)
|
|
27571
|
+
});
|
|
27546
27572
|
const runtimeGlobalConfigSchema = object({
|
|
27547
27573
|
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
27548
27574
|
maxParallelTasks: number$2().int().positive().default(4),
|
|
@@ -27551,6 +27577,7 @@ const runtimeGlobalConfigSchema = object({
|
|
|
27551
27577
|
pollingIntervalSeconds: number$2().int().positive().default(30),
|
|
27552
27578
|
prPollingIntervalSeconds: number$2().int().positive().default(60),
|
|
27553
27579
|
terminalApp: string$2().optional(),
|
|
27580
|
+
notificationSounds: notificationSoundsConfigSchema.prefault({}),
|
|
27554
27581
|
slackEnabled: boolean$1().default(true),
|
|
27555
27582
|
slackBotToken: string$2().optional(),
|
|
27556
27583
|
slackSigningSecret: string$2().optional(),
|
|
@@ -78159,6 +78186,7 @@ const globalConfigFormSchema = runtimeGlobalConfigSchema.extend({
|
|
|
78159
78186
|
pollingIntervalSeconds: number$1().int().positive(),
|
|
78160
78187
|
prPollingIntervalSeconds: number$1().int().positive()
|
|
78161
78188
|
});
|
|
78189
|
+
const notificationSoundsFormSchema = notificationSoundsConfigSchema;
|
|
78162
78190
|
const environmentFormSchema = runtimeWorktreeSetupSchema.extend({
|
|
78163
78191
|
startCommand: string$2().default("")
|
|
78164
78192
|
});
|
|
@@ -78180,19 +78208,19 @@ const instructionsFormSchema = object({
|
|
|
78180
78208
|
systemPrompt: string$2().optional(),
|
|
78181
78209
|
gitInstructions: string$2().optional()
|
|
78182
78210
|
});
|
|
78183
|
-
function PageHeader$
|
|
78211
|
+
function PageHeader$2({ title, description }) {
|
|
78184
78212
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex flex-col gap-1 px-10 py-6 border-b border-[#2a2a35]", children: [
|
|
78185
78213
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-xl font-semibold text-[#f0f0f5]", children: title }),
|
|
78186
78214
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#60607a]", children: description })
|
|
78187
78215
|
] });
|
|
78188
78216
|
}
|
|
78189
|
-
function SectionDivider$
|
|
78217
|
+
function SectionDivider$4({ title }) {
|
|
78190
78218
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
78191
78219
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[15px] font-semibold text-[#f0f0f5]", children: title }),
|
|
78192
78220
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px bg-[#1a1a1f]" })
|
|
78193
78221
|
] });
|
|
78194
78222
|
}
|
|
78195
|
-
function FieldRow$
|
|
78223
|
+
function FieldRow$2({ label, description, children }) {
|
|
78196
78224
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
78197
78225
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
|
|
78198
78226
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium text-[#c0c0d0]", children: label }),
|
|
@@ -78222,7 +78250,7 @@ function GlobalSettings({ section }) {
|
|
|
78222
78250
|
});
|
|
78223
78251
|
if (!config2) {
|
|
78224
78252
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col", children: [
|
|
78225
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$
|
|
78253
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$2, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
|
|
78226
78254
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20 text-sm text-[#60607a]", children: "Loading..." })
|
|
78227
78255
|
] });
|
|
78228
78256
|
}
|
|
@@ -78231,13 +78259,13 @@ function GlobalSettings({ section }) {
|
|
|
78231
78259
|
label: t2.label
|
|
78232
78260
|
}));
|
|
78233
78261
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
|
|
78234
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$
|
|
78262
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$2, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
|
|
78235
78263
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-10 py-6", children: [
|
|
78236
78264
|
/* @__PURE__ */ jsxRuntimeExports.jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit, className: "flex flex-col gap-6", children: [
|
|
78237
78265
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
78238
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$
|
|
78239
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78240
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78266
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Defaults" }),
|
|
78267
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Default Agent", description: "Agent binary for new workflow slots", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RHFSelect_default, { wrapperClassName: "w-fit", name: "defaultAgent", className: selectClassName, children: AGENT_BINARY_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value)) }) }),
|
|
78268
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Terminal App", description: "Application for opening terminals", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78241
78269
|
RHFSelect_default,
|
|
78242
78270
|
{
|
|
78243
78271
|
wrapperClassName: "w-fit",
|
|
@@ -78250,8 +78278,8 @@ function GlobalSettings({ section }) {
|
|
|
78250
78278
|
) })
|
|
78251
78279
|
] }),
|
|
78252
78280
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
78253
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$
|
|
78254
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78281
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Concurrency & Limits" }),
|
|
78282
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Parallel Tasks", description: "Concurrent task executions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78255
78283
|
RHFNumberInput_default,
|
|
78256
78284
|
{
|
|
78257
78285
|
name: "maxParallelTasks",
|
|
@@ -78260,7 +78288,7 @@ function GlobalSettings({ section }) {
|
|
|
78260
78288
|
inputClassName: "text-center"
|
|
78261
78289
|
}
|
|
78262
78290
|
) }),
|
|
78263
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78291
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Parallel QA", description: "Concurrent QA slot runs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78264
78292
|
RHFNumberInput_default,
|
|
78265
78293
|
{
|
|
78266
78294
|
name: "maxParallelQA",
|
|
@@ -78269,7 +78297,7 @@ function GlobalSettings({ section }) {
|
|
|
78269
78297
|
inputClassName: "text-center"
|
|
78270
78298
|
}
|
|
78271
78299
|
) }),
|
|
78272
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Auto-Fix Attempts", description: "Retries before marking blocked", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78273
78301
|
RHFNumberInput_default,
|
|
78274
78302
|
{
|
|
78275
78303
|
name: "maxAutoFixAttempts",
|
|
@@ -78280,8 +78308,8 @@ function GlobalSettings({ section }) {
|
|
|
78280
78308
|
) })
|
|
78281
78309
|
] }),
|
|
78282
78310
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
78283
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$
|
|
78284
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78311
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Polling" }),
|
|
78312
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Polling Interval", description: "Board refresh interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78285
78313
|
RHFNumberInput_default,
|
|
78286
78314
|
{
|
|
78287
78315
|
name: "pollingIntervalSeconds",
|
|
@@ -78290,7 +78318,7 @@ function GlobalSettings({ section }) {
|
|
|
78290
78318
|
inputClassName: "text-center"
|
|
78291
78319
|
}
|
|
78292
78320
|
) }),
|
|
78293
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78321
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "PR Poll Interval", description: "PR status check interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78294
78322
|
RHFNumberInput_default,
|
|
78295
78323
|
{
|
|
78296
78324
|
name: "prPollingIntervalSeconds",
|
|
@@ -78303,12 +78331,86 @@ function GlobalSettings({ section }) {
|
|
|
78303
78331
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end pt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button_default, { type: "submit", disabled: saving, children: saving ? "Saving..." : "Save" }) })
|
|
78304
78332
|
] }) }),
|
|
78305
78333
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4 pt-6 mt-6 border-t border-[#1a1a1f]", children: [
|
|
78306
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$
|
|
78307
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$
|
|
78334
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Session" }),
|
|
78335
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Sign out", description: "End your session on this browser. Local access stays open.", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button_default, { variant: "outlined", onClick: () => logout(), children: "Sign out" }) })
|
|
78308
78336
|
] })
|
|
78309
78337
|
] })
|
|
78310
78338
|
] });
|
|
78311
78339
|
}
|
|
78340
|
+
function PageHeader$1({ title, description }) {
|
|
78341
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex flex-col gap-1 px-10 py-6 border-b border-[#2a2a35]", children: [
|
|
78342
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-xl font-semibold text-[#f0f0f5]", children: title }),
|
|
78343
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#60607a]", children: description })
|
|
78344
|
+
] });
|
|
78345
|
+
}
|
|
78346
|
+
function SectionDivider$3({ title }) {
|
|
78347
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
78348
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[15px] font-semibold text-[#f0f0f5]", children: title }),
|
|
78349
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px bg-[#1a1a1f]" })
|
|
78350
|
+
] });
|
|
78351
|
+
}
|
|
78352
|
+
function FieldRow$1({ label, description, children }) {
|
|
78353
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
78354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
|
|
78355
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium text-[#c0c0d0]", children: label }),
|
|
78356
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-[#60607a]", children: description })
|
|
78357
|
+
] }),
|
|
78358
|
+
children
|
|
78359
|
+
] });
|
|
78360
|
+
}
|
|
78361
|
+
const PER_EVENT_ROWS = [
|
|
78362
|
+
{ name: "readyForReview", label: "Ready for Review", description: "A task finished and is waiting for your review" },
|
|
78363
|
+
{ name: "prComment", label: "New PR comment", description: "A reviewer commented on a task's pull request" },
|
|
78364
|
+
{ name: "done", label: "Done / PR merged", description: "A task's pull request was merged" },
|
|
78365
|
+
{ name: "reopened", label: "Reopened", description: "Changes were requested — the task needs another pass" },
|
|
78366
|
+
{ name: "blocked", label: "Blocked", description: "A task was blocked (PR closed, or auto-fix attempts exhausted)" },
|
|
78367
|
+
{ name: "runError", label: "Run error", description: "A run/preview process exited with an error" }
|
|
78368
|
+
];
|
|
78369
|
+
function NotificationsSettings() {
|
|
78370
|
+
const { data: config2 } = useRead((api) => api("config").GET());
|
|
78371
|
+
const { trigger: saveConfig, loading: saving } = useWrite((api) => api("config").PUT());
|
|
78372
|
+
const methods = useForm({
|
|
78373
|
+
resolver: u(notificationSoundsFormSchema),
|
|
78374
|
+
values: config2 == null ? void 0 : config2.notificationSounds
|
|
78375
|
+
});
|
|
78376
|
+
const onSubmit = methods.handleSubmit(async (values) => {
|
|
78377
|
+
const res = await saveConfig({ body: { notificationSounds: values } });
|
|
78378
|
+
if (res.error) {
|
|
78379
|
+
toast.error("Failed to save settings");
|
|
78380
|
+
return;
|
|
78381
|
+
}
|
|
78382
|
+
methods.reset(values);
|
|
78383
|
+
toast.success("Settings saved");
|
|
78384
|
+
});
|
|
78385
|
+
if (!config2) {
|
|
78386
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col", children: [
|
|
78387
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Notifications", description: "Sounds played on the daemon host when tasks need you" }),
|
|
78388
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20 text-sm text-[#60607a]", children: "Loading..." })
|
|
78389
|
+
] });
|
|
78390
|
+
}
|
|
78391
|
+
const enabled = methods.watch("enabled");
|
|
78392
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
|
|
78393
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Notifications", description: "Sounds played on the daemon host when tasks need you" }),
|
|
78394
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto px-10 py-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit, className: "flex flex-col gap-6", children: [
|
|
78395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
78396
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Sounds" }),
|
|
78397
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78398
|
+
FieldRow$1,
|
|
78399
|
+
{
|
|
78400
|
+
label: "Notification sounds",
|
|
78401
|
+
description: "Play a sound on the machine running Whipped — works even when no browser is open",
|
|
78402
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(RHFSwitch_default, { name: "enabled" })
|
|
78403
|
+
}
|
|
78404
|
+
)
|
|
78405
|
+
] }),
|
|
78406
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: enabled ? "flex flex-col gap-4" : "flex flex-col gap-4 opacity-50", children: [
|
|
78407
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Events" }),
|
|
78408
|
+
PER_EVENT_ROWS.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: row.label, description: row.description, children: /* @__PURE__ */ jsxRuntimeExports.jsx(RHFSwitch_default, { name: row.name }) }, row.name))
|
|
78409
|
+
] }),
|
|
78410
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end pt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button_default, { type: "submit", disabled: saving, children: saving ? "Saving..." : "Save" }) })
|
|
78411
|
+
] }) }) })
|
|
78412
|
+
] });
|
|
78413
|
+
}
|
|
78312
78414
|
function FilePickerDialog({ initialPath, onSelect, onClose }) {
|
|
78313
78415
|
const [path2, setPath] = reactExports.useState(initialPath ?? "");
|
|
78314
78416
|
const [selectedFile, setSelectedFile] = reactExports.useState(null);
|
|
@@ -81797,6 +81899,7 @@ const PROJECT_NAV = [
|
|
|
81797
81899
|
];
|
|
81798
81900
|
const GLOBAL_NAV = [
|
|
81799
81901
|
{ id: "runtime", label: "Runtime Config", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { size: 15 }) },
|
|
81902
|
+
{ id: "notifications", label: "Notifications", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Bell, { size: 15 }) },
|
|
81800
81903
|
{ id: "tunnel", label: "Tunnel", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { size: 15 }) },
|
|
81801
81904
|
{ id: "slack", label: "Slack", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Slack, { size: 15 }) }
|
|
81802
81905
|
];
|
|
@@ -81930,7 +82033,7 @@ function SettingsPage() {
|
|
|
81930
82033
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-4" })
|
|
81931
82034
|
] })
|
|
81932
82035
|
] }),
|
|
81933
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-hidden flex flex-col", children: isProject ? /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectSettings, { workspaceId, section }) : section === "slack" ? /* @__PURE__ */ jsxRuntimeExports.jsx(SlackSettings, {}) : section === "tunnel" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TunnelSettings, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(GlobalSettings, { section }) })
|
|
82036
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-hidden flex flex-col", children: isProject ? /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectSettings, { workspaceId, section }) : section === "slack" ? /* @__PURE__ */ jsxRuntimeExports.jsx(SlackSettings, {}) : section === "tunnel" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TunnelSettings, {}) : section === "notifications" ? /* @__PURE__ */ jsxRuntimeExports.jsx(NotificationsSettings, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(GlobalSettings, { section }) })
|
|
81934
82037
|
] });
|
|
81935
82038
|
}
|
|
81936
82039
|
function NavItem({
|
package/dist/web-ui/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
7
7
|
<title>whipped</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-peNzhkq8.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-Do7b5IJu.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whipped",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Autonomous AI agent kanban board for Claude, Codex, Opencode, and Cursor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/nxnom/whipped#readme",
|
|
@@ -22,6 +22,20 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=22"
|
|
24
24
|
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"clean": "rm -rf dist",
|
|
27
|
+
"build": "pnpm clean && pnpm web:build && node scripts/build.mjs",
|
|
28
|
+
"prepublishOnly": "pnpm build",
|
|
29
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
30
|
+
"dev": "NODE_ENV=development tsx src/cli.ts",
|
|
31
|
+
"dev:full": "node scripts/dev-full.mjs",
|
|
32
|
+
"web:dev": "pnpm --filter @whipped/web dev",
|
|
33
|
+
"web:build": "pnpm --filter @whipped/web build",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"web:typecheck": "pnpm --filter @whipped/web typecheck",
|
|
36
|
+
"lint": "biome lint src web-ui/src",
|
|
37
|
+
"format": "biome format --write ."
|
|
38
|
+
},
|
|
25
39
|
"dependencies": {
|
|
26
40
|
"@hono/zod-validator": "^0.8.0",
|
|
27
41
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -54,17 +68,14 @@
|
|
|
54
68
|
"tsx": "^4.20.3",
|
|
55
69
|
"typescript": "^5.9.3"
|
|
56
70
|
},
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"web:typecheck": "pnpm --filter @whipped/web typecheck",
|
|
67
|
-
"lint": "biome lint src web-ui/src",
|
|
68
|
-
"format": "biome format --write ."
|
|
71
|
+
"pnpm": {
|
|
72
|
+
"onlyBuiltDependencies": [
|
|
73
|
+
"better-sqlite3",
|
|
74
|
+
"esbuild",
|
|
75
|
+
"node-pty"
|
|
76
|
+
],
|
|
77
|
+
"overrides": {
|
|
78
|
+
"hono": "4.12.23"
|
|
79
|
+
}
|
|
69
80
|
}
|
|
70
|
-
}
|
|
81
|
+
}
|