whipped 0.6.0 → 0.8.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
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, 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;
|
|
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, runtimeWorktreeCopyEntrySchema, 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";
|
|
@@ -3890,8 +3890,13 @@ Do NOT include:
|
|
|
3890
3890
|
runtimeGithubConfigSchema = z.object({
|
|
3891
3891
|
token: z.string()
|
|
3892
3892
|
});
|
|
3893
|
+
runtimeWorktreeCopyEntrySchema = z.object({
|
|
3894
|
+
path: z.string().min(1),
|
|
3895
|
+
symlink: z.boolean().default(false)
|
|
3896
|
+
});
|
|
3893
3897
|
runtimeWorktreeSetupSchema = z.object({
|
|
3894
|
-
|
|
3898
|
+
// Legacy configs stored bare strings; accept and normalize them to copy entries.
|
|
3899
|
+
filesToCopy: z.array(z.union([z.string().transform((path2) => ({ path: path2, symlink: false })), runtimeWorktreeCopyEntrySchema])).default([]),
|
|
3895
3900
|
installCommand: z.string().default("")
|
|
3896
3901
|
});
|
|
3897
3902
|
runtimeProjectSecretSchema = z.object({
|
|
@@ -13557,11 +13562,15 @@ async function runLogs(options) {
|
|
|
13557
13562
|
process.exit(1);
|
|
13558
13563
|
}
|
|
13559
13564
|
if (options.follow) {
|
|
13560
|
-
const
|
|
13565
|
+
const [cmd, args] = process.platform === "win32" ? [
|
|
13566
|
+
"powershell",
|
|
13567
|
+
["-NoProfile", "-Command", `Get-Content -Path '${path2}' -Tail ${options.lines} -Wait`]
|
|
13568
|
+
] : ["tail", ["-f", "-n", String(options.lines), path2]];
|
|
13569
|
+
const child = spawn2(cmd, args, {
|
|
13561
13570
|
stdio: "inherit"
|
|
13562
13571
|
});
|
|
13563
13572
|
child.on("error", (err) => {
|
|
13564
|
-
console.error(`Failed to
|
|
13573
|
+
console.error(`Failed to follow log file: ${err.message}`);
|
|
13565
13574
|
process.exit(1);
|
|
13566
13575
|
});
|
|
13567
13576
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
@@ -13618,7 +13627,7 @@ import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:
|
|
|
13618
13627
|
import { createServer } from "node:http";
|
|
13619
13628
|
import { join as join22 } from "node:path";
|
|
13620
13629
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
13621
|
-
import * as
|
|
13630
|
+
import * as nodePty3 from "node-pty";
|
|
13622
13631
|
|
|
13623
13632
|
// node_modules/.pnpm/ws@8.20.0/node_modules/ws/wrapper.mjs
|
|
13624
13633
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -14397,6 +14406,16 @@ var slackNotifier = new SlackNotifier();
|
|
|
14397
14406
|
// src/server/runtime-server.ts
|
|
14398
14407
|
init_runtime_config();
|
|
14399
14408
|
init_logger();
|
|
14409
|
+
|
|
14410
|
+
// src/core/shell.ts
|
|
14411
|
+
function getShellInvocation(command) {
|
|
14412
|
+
if (process.platform === "win32") {
|
|
14413
|
+
return [process.env.ComSpec ?? "cmd.exe", ["/c", command]];
|
|
14414
|
+
}
|
|
14415
|
+
return [process.env.SHELL ?? "/bin/sh", ["-c", command]];
|
|
14416
|
+
}
|
|
14417
|
+
|
|
14418
|
+
// src/server/runtime-server.ts
|
|
14400
14419
|
init_task_id();
|
|
14401
14420
|
|
|
14402
14421
|
// src/notifications/sound-player.ts
|
|
@@ -14424,7 +14443,11 @@ async function playNotificationSound(event) {
|
|
|
14424
14443
|
}
|
|
14425
14444
|
}
|
|
14426
14445
|
function playOnHost(file) {
|
|
14427
|
-
const [command, args] = process.platform === "darwin" ? ["afplay", [file]] : process.platform === "
|
|
14446
|
+
const [command, args] = process.platform === "darwin" ? ["afplay", [file]] : process.platform === "win32" ? (
|
|
14447
|
+
// PowerShell's SoundPlayer plays the WAV chimes synchronously in the
|
|
14448
|
+
// detached child (it exits once done); no extra binary needed.
|
|
14449
|
+
["powershell", ["-NoProfile", "-Command", `(New-Object Media.SoundPlayer '${file}').PlaySync()`]]
|
|
14450
|
+
) : process.platform === "linux" ? ["paplay", [file]] : [null, null];
|
|
14428
14451
|
if (!command) return;
|
|
14429
14452
|
const child = spawn4(command, [...args], { stdio: "ignore", detached: true });
|
|
14430
14453
|
child.on("error", () => {
|
|
@@ -18047,7 +18070,7 @@ async function commitIfDirty(worktreePath, message) {
|
|
|
18047
18070
|
function attemptMerge(repoPath, effectiveWorktreeId, taskBranch) {
|
|
18048
18071
|
const worktreePath = join12(WORKTREES_DIR, effectiveWorktreeId);
|
|
18049
18072
|
if (existsSync5(worktreePath)) {
|
|
18050
|
-
rmSync2(worktreePath, { recursive: true, force: true });
|
|
18073
|
+
rmSync2(worktreePath, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
18051
18074
|
git(["worktree", "prune"], repoPath);
|
|
18052
18075
|
}
|
|
18053
18076
|
const statusResult = git(["status", "--porcelain"], repoPath);
|
|
@@ -18415,7 +18438,7 @@ async function removeWorktreeAsync(taskId, repoPath, branchName) {
|
|
|
18415
18438
|
const t0 = Date.now();
|
|
18416
18439
|
logger.info(`[cleanup:${taskId}] starting worktree removal`);
|
|
18417
18440
|
try {
|
|
18418
|
-
await rm2(worktreePath, { recursive: true, force: true });
|
|
18441
|
+
await rm2(worktreePath, { recursive: true, force: true, maxRetries: 10, retryDelay: 200 });
|
|
18419
18442
|
logger.info(`[cleanup:${taskId}] rm worktree dir done (${Date.now() - t0}ms)`);
|
|
18420
18443
|
} catch (err) {
|
|
18421
18444
|
logger.error({ err }, `[cleanup:${taskId}] rm worktree dir failed:`);
|
|
@@ -19149,12 +19172,34 @@ function getAvailableAgents() {
|
|
|
19149
19172
|
}
|
|
19150
19173
|
});
|
|
19151
19174
|
}
|
|
19175
|
+
var resolvedCommandCache = /* @__PURE__ */ new Map();
|
|
19176
|
+
function resolveCommandPath(command) {
|
|
19177
|
+
if (process.platform !== "win32") return command;
|
|
19178
|
+
const cached2 = resolvedCommandCache.get(command);
|
|
19179
|
+
if (cached2) return cached2;
|
|
19180
|
+
try {
|
|
19181
|
+
const result = spawnSync4("where.exe", [command], {
|
|
19182
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
19183
|
+
timeout: 5e3,
|
|
19184
|
+
encoding: "utf-8"
|
|
19185
|
+
});
|
|
19186
|
+
if (result.status === 0 && result.stdout) {
|
|
19187
|
+
const first = result.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)[0];
|
|
19188
|
+
if (first) {
|
|
19189
|
+
resolvedCommandCache.set(command, first);
|
|
19190
|
+
return first;
|
|
19191
|
+
}
|
|
19192
|
+
}
|
|
19193
|
+
} catch {
|
|
19194
|
+
}
|
|
19195
|
+
return command;
|
|
19196
|
+
}
|
|
19152
19197
|
function getAgentCommand(agentId) {
|
|
19153
19198
|
const agent = AGENT_DEFINITIONS.find((a) => a.id === agentId);
|
|
19154
19199
|
if (!agent) {
|
|
19155
19200
|
throw new Error(`Unknown agent: ${agentId}`);
|
|
19156
19201
|
}
|
|
19157
|
-
return agent.command;
|
|
19202
|
+
return resolveCommandPath(agent.command);
|
|
19158
19203
|
}
|
|
19159
19204
|
var READONLY_DISALLOWED_TOOLS = ["Edit", "Write", "NotebookEdit", "Bash"];
|
|
19160
19205
|
function buildAgentArgs(agentId, prompt, ctx = {}) {
|
|
@@ -20436,11 +20481,12 @@ init_workspace_state();
|
|
|
20436
20481
|
init_workspace_state();
|
|
20437
20482
|
|
|
20438
20483
|
// src/daemon/scheduler.ts
|
|
20439
|
-
|
|
20440
|
-
import {
|
|
20441
|
-
import { unlink as unlink2 } from "node:fs/promises";
|
|
20484
|
+
var import_tree_kill2 = __toESM(require_tree_kill(), 1);
|
|
20485
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
20486
|
+
import { cp, link, mkdir as mkdir3, stat as stat2, symlink, unlink as unlink2 } from "node:fs/promises";
|
|
20442
20487
|
import { dirname as dirname6, join as join17, resolve as resolve2 } from "node:path";
|
|
20443
20488
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
20489
|
+
import * as nodePty2 from "node-pty";
|
|
20444
20490
|
init_api_contract();
|
|
20445
20491
|
init_logger();
|
|
20446
20492
|
|
|
@@ -20626,7 +20672,7 @@ async function runReviewSlot(slot, card, streamId, options, customPrompt) {
|
|
|
20626
20672
|
useIncremental,
|
|
20627
20673
|
diffRef: priorReviewedSha ?? card.baseRef
|
|
20628
20674
|
};
|
|
20629
|
-
const
|
|
20675
|
+
const stat3 = getGitStat(worktreePath, card.baseRef);
|
|
20630
20676
|
const fullDiff = getGitFullDiff(worktreePath, useIncremental ? priorReviewedSha : card.baseRef);
|
|
20631
20677
|
const context = formatPriorComments(card);
|
|
20632
20678
|
let subtaskCards = [];
|
|
@@ -20636,7 +20682,7 @@ async function runReviewSlot(slot, card, streamId, options, customPrompt) {
|
|
|
20636
20682
|
const rawSystemPrompt = buildReviewSlotSystemPrompt(
|
|
20637
20683
|
slot,
|
|
20638
20684
|
card,
|
|
20639
|
-
|
|
20685
|
+
stat3,
|
|
20640
20686
|
fullDiff,
|
|
20641
20687
|
customPrompt,
|
|
20642
20688
|
context.text,
|
|
@@ -21218,16 +21264,16 @@ ${fullDiff}`;
|
|
|
21218
21264
|
return `Large changeset (${fullDiff.length.toLocaleString()} chars). Use \`git diff ${baseRef}...HEAD\` and read individual files to explore.`;
|
|
21219
21265
|
}
|
|
21220
21266
|
var FOLLOWUP_REVIEW_FOCUS = `**This is a follow-up review.** An earlier version of this work already passed review in a prior round \u2014 only the \`## New Feedback\` / \`## Current Iteration\` items triggered this run. Re-review ONLY: (1) whether those items were addressed in the changes below, and (2) whether the new changes introduced a regression or broke a caller (grep callers of anything touched to confirm). Do NOT re-litigate previously-approved code or raise issues unrelated to this round's feedback.`;
|
|
21221
|
-
function renderReviewDiff(
|
|
21267
|
+
function renderReviewDiff(stat3, fullDiff, baseRef, scope) {
|
|
21222
21268
|
if (!scope.useIncremental) {
|
|
21223
21269
|
return `## Changed files
|
|
21224
|
-
${
|
|
21270
|
+
${stat3}
|
|
21225
21271
|
|
|
21226
21272
|
## Diff
|
|
21227
21273
|
${formatDiffBlock(fullDiff, baseRef)}`;
|
|
21228
21274
|
}
|
|
21229
21275
|
return `## Changed files (full changeset vs \`${baseRef}\`, for context)
|
|
21230
|
-
${
|
|
21276
|
+
${stat3}
|
|
21231
21277
|
|
|
21232
21278
|
## Changes since your last review (review THIS)
|
|
21233
21279
|
_The diff below is only what changed since you last reviewed this card. The full changeset is summarised above; run \`git diff ${baseRef}...HEAD\` only if you need it to chase a regression._
|
|
@@ -21267,11 +21313,11 @@ Revise these values rather than rewriting from scratch, unless they no longer re
|
|
|
21267
21313
|
let statSection = "";
|
|
21268
21314
|
if (worktreePath) {
|
|
21269
21315
|
if (fullDiff) {
|
|
21270
|
-
const
|
|
21316
|
+
const stat3 = getGitStat(worktreePath, statBase);
|
|
21271
21317
|
statSection = `
|
|
21272
21318
|
|
|
21273
21319
|
## Current worktree state (vs ${statBase})
|
|
21274
|
-
${
|
|
21320
|
+
${stat3}
|
|
21275
21321
|
|
|
21276
21322
|
## Diff (vs ${statBase})
|
|
21277
21323
|
${formatDiffBlock(fullDiff, statBase, "Git diff")}`;
|
|
@@ -21282,11 +21328,11 @@ ${formatDiffBlock(fullDiff, statBase, "Git diff")}`;
|
|
|
21282
21328
|
|
|
21283
21329
|
This is the initial dev run on this card. The worktree is clean and branched from \`${statBase}\` \u2014 there is no prior diff to inspect. Skip \`git diff\` and start implementing.`;
|
|
21284
21330
|
} else {
|
|
21285
|
-
const
|
|
21331
|
+
const stat3 = getGitStat(worktreePath, statBase);
|
|
21286
21332
|
statSection = `
|
|
21287
21333
|
|
|
21288
21334
|
## Current worktree state (vs ${statBase})
|
|
21289
|
-
${
|
|
21335
|
+
${stat3}`;
|
|
21290
21336
|
}
|
|
21291
21337
|
}
|
|
21292
21338
|
const descAttachNote = (card.descriptionAttachments?.length ?? 0) > 0 ? `
|
|
@@ -21395,12 +21441,12 @@ ${systemPrompt.trim()}`);
|
|
|
21395
21441
|
${effectiveGitInstructions}`);
|
|
21396
21442
|
return { text: parts.join("\n\n"), files: context.files };
|
|
21397
21443
|
}
|
|
21398
|
-
function buildReviewSlotSystemPrompt(slot, card,
|
|
21444
|
+
function buildReviewSlotSystemPrompt(slot, card, stat3, fullDiff, customPrompt, priorContext, scope, secrets = [], systemPrompt, autoCommit = true, subtaskCards = [], browserEnabled = false) {
|
|
21399
21445
|
if (slot.type === "orch") {
|
|
21400
21446
|
return buildOrchSystemPrompt(
|
|
21401
21447
|
slot,
|
|
21402
21448
|
card,
|
|
21403
|
-
|
|
21449
|
+
stat3,
|
|
21404
21450
|
fullDiff,
|
|
21405
21451
|
customPrompt,
|
|
21406
21452
|
priorContext,
|
|
@@ -21414,7 +21460,7 @@ function buildReviewSlotSystemPrompt(slot, card, stat2, fullDiff, customPrompt,
|
|
|
21414
21460
|
return buildMergedReviewSystemPrompt(
|
|
21415
21461
|
slot,
|
|
21416
21462
|
card,
|
|
21417
|
-
|
|
21463
|
+
stat3,
|
|
21418
21464
|
fullDiff,
|
|
21419
21465
|
customPrompt,
|
|
21420
21466
|
priorContext,
|
|
@@ -21424,7 +21470,7 @@ function buildReviewSlotSystemPrompt(slot, card, stat2, fullDiff, customPrompt,
|
|
|
21424
21470
|
browserEnabled
|
|
21425
21471
|
);
|
|
21426
21472
|
}
|
|
21427
|
-
function buildMergedReviewSystemPrompt(slot, card,
|
|
21473
|
+
function buildMergedReviewSystemPrompt(slot, card, stat3, fullDiff, customPrompt, priorContext, scope, secrets, systemPrompt, browserEnabled = false) {
|
|
21428
21474
|
const custom = customPrompt.trim() ? `
|
|
21429
21475
|
|
|
21430
21476
|
## Project-specific instructions
|
|
@@ -21460,7 +21506,7 @@ When you set status "fail" (reopening for rework), you can right-size the **tier
|
|
|
21460
21506
|
## Task to review
|
|
21461
21507
|
${card.description ?? ""}${descAttachSection}${priorContext}
|
|
21462
21508
|
|
|
21463
|
-
${renderReviewDiff(
|
|
21509
|
+
${renderReviewDiff(stat3, fullDiff, card.baseRef, scope)}
|
|
21464
21510
|
|
|
21465
21511
|
${ITERATION_SCOPING_NOTE}
|
|
21466
21512
|
|
|
@@ -21488,7 +21534,7 @@ ${secretsSection}` : ""}${projectContext}${runningAppSection}${levelAdjustSectio
|
|
|
21488
21534
|
|
|
21489
21535
|
This MCP call is required \u2014 without it the pipeline has no record of your verdict.`;
|
|
21490
21536
|
}
|
|
21491
|
-
function buildOrchSystemPrompt(slot, card,
|
|
21537
|
+
function buildOrchSystemPrompt(slot, card, stat3, fullDiff, customPrompt, priorContext, scope, secrets, systemPrompt, autoCommit = true, subtaskCards = []) {
|
|
21492
21538
|
const commentType = slotCommentType(slot);
|
|
21493
21539
|
const custom = customPrompt.trim() ? `
|
|
21494
21540
|
|
|
@@ -21534,7 +21580,7 @@ ${card.description}
|
|
|
21534
21580
|
|
|
21535
21581
|
${subtasksSection}${priorContext}
|
|
21536
21582
|
|
|
21537
|
-
${renderReviewDiff(
|
|
21583
|
+
${renderReviewDiff(stat3, fullDiff, card.baseRef, scope)}
|
|
21538
21584
|
|
|
21539
21585
|
${ITERATION_SCOPING_NOTE}
|
|
21540
21586
|
|
|
@@ -21747,6 +21793,12 @@ var TaskScheduler = class {
|
|
|
21747
21793
|
planPhaseManuallyStopped = /* @__PURE__ */ new Set();
|
|
21748
21794
|
// Individual review stream IDs stopped by a manual stopTask() call.
|
|
21749
21795
|
manuallyStoppedStreams = /* @__PURE__ */ new Set();
|
|
21796
|
+
// Worktree-setup install commands currently running, keyed by taskId — so stopTask()
|
|
21797
|
+
// can kill the install PTY before the dev agent has even started.
|
|
21798
|
+
runningInstalls = /* @__PURE__ */ new Map();
|
|
21799
|
+
// Tasks whose install was manually stopped — signals the install runner to reset the
|
|
21800
|
+
// task to its initial state instead of proceeding to the agent.
|
|
21801
|
+
manuallyStoppedInstalls = /* @__PURE__ */ new Set();
|
|
21750
21802
|
// Shared worktree IDs currently in use by a dev agent — prevents sibling cards from
|
|
21751
21803
|
// running concurrently in the same worktree directory.
|
|
21752
21804
|
runningSharedWorktrees = /* @__PURE__ */ new Set();
|
|
@@ -22066,44 +22118,112 @@ ${assistantSystemPrompt}` : assistantSystemPrompt;
|
|
|
22066
22118
|
const { filesToCopy, installCommand } = projectConfig.worktreeSetup;
|
|
22067
22119
|
if (filesToCopy.length > 0) {
|
|
22068
22120
|
const copied = [];
|
|
22069
|
-
|
|
22070
|
-
|
|
22121
|
+
const linked = [];
|
|
22122
|
+
for (const entry of filesToCopy) {
|
|
22123
|
+
const src = join17(repoPath, entry.path);
|
|
22071
22124
|
if (!existsSync10(src)) continue;
|
|
22072
|
-
const dst = join17(worktree.path,
|
|
22073
|
-
|
|
22125
|
+
const dst = join17(worktree.path, entry.path);
|
|
22126
|
+
await mkdir3(dirname6(dst), { recursive: true });
|
|
22074
22127
|
try {
|
|
22075
|
-
|
|
22076
|
-
|
|
22077
|
-
|
|
22128
|
+
if (entry.symlink) {
|
|
22129
|
+
await shareIntoWorktree(src, dst);
|
|
22130
|
+
linked.push(entry.path);
|
|
22131
|
+
} else {
|
|
22132
|
+
await cp(src, dst, { recursive: true, dereference: true });
|
|
22133
|
+
copied.push(entry.path);
|
|
22134
|
+
}
|
|
22135
|
+
} catch (err) {
|
|
22136
|
+
logger.warn(
|
|
22137
|
+
{ err },
|
|
22138
|
+
`[scheduler] worktree setup: failed to ${entry.symlink ? "link" : "copy"} ${entry.path}`
|
|
22139
|
+
);
|
|
22078
22140
|
}
|
|
22079
22141
|
}
|
|
22080
|
-
|
|
22081
|
-
|
|
22142
|
+
const summary = [
|
|
22143
|
+
copied.length ? `Copied: ${copied.join(", ")}` : "",
|
|
22144
|
+
linked.length ? `Linked: ${linked.join(", ")}` : ""
|
|
22145
|
+
].filter(Boolean).join(" \xB7 ");
|
|
22146
|
+
if (summary) {
|
|
22147
|
+
await appendActivityLog(workspaceId, taskId, `Worktree setup \u2014 ${summary}`);
|
|
22082
22148
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22083
22149
|
}
|
|
22084
22150
|
}
|
|
22085
22151
|
if (installCommand.trim()) {
|
|
22086
|
-
|
|
22152
|
+
const installCmd = installCommand.trim();
|
|
22153
|
+
await appendActivityLog(workspaceId, taskId, `Running: ${installCmd}`);
|
|
22154
|
+
const installStartedAt = Date.now();
|
|
22155
|
+
const installStreamId = `${taskId}-install-${installStartedAt}`;
|
|
22156
|
+
await appendTerminalSession(workspaceId, taskId, {
|
|
22157
|
+
streamId: installStreamId,
|
|
22158
|
+
type: "install",
|
|
22159
|
+
startedAt: installStartedAt,
|
|
22160
|
+
state: "running"
|
|
22161
|
+
});
|
|
22087
22162
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22088
|
-
|
|
22089
|
-
|
|
22163
|
+
let installBuffer = "";
|
|
22164
|
+
const emitInstall = (data) => {
|
|
22165
|
+
installBuffer += data;
|
|
22166
|
+
stateHub.broadcastTerminalOutput(workspaceId, installStreamId, data);
|
|
22167
|
+
};
|
|
22168
|
+
emitInstall(`\x1B[1;36m$ ${installCmd}\x1B[0m\r
|
|
22169
|
+
`);
|
|
22170
|
+
const exitCode = await new Promise((resolveExit) => {
|
|
22171
|
+
const [shell, shellArgs] = getShellInvocation(installCmd);
|
|
22172
|
+
const proc = nodePty2.spawn(shell, shellArgs, {
|
|
22173
|
+
name: "xterm-256color",
|
|
22174
|
+
cols: 220,
|
|
22175
|
+
rows: 50,
|
|
22090
22176
|
cwd: worktree.path,
|
|
22091
|
-
|
|
22092
|
-
env: { ...process.env, REPO_PATH: repoPath }
|
|
22093
|
-
});
|
|
22094
|
-
proc.on("close", (code) => {
|
|
22095
|
-
if (code !== 0) {
|
|
22096
|
-
logger.error(`[scheduler] Install command failed (code ${code}) for task ${taskId}`);
|
|
22097
|
-
void appendActivityLog(
|
|
22098
|
-
workspaceId,
|
|
22099
|
-
taskId,
|
|
22100
|
-
`Install command failed (code ${code}) \u2014 proceeding anyway`
|
|
22101
|
-
);
|
|
22102
|
-
}
|
|
22103
|
-
resolve5();
|
|
22177
|
+
env: { ...process.env, REPO_PATH: repoPath, TERM: "xterm-256color" }
|
|
22104
22178
|
});
|
|
22179
|
+
this.runningInstalls.set(taskId, proc);
|
|
22180
|
+
proc.onData(emitInstall);
|
|
22181
|
+
proc.onExit(({ exitCode: exitCode2 }) => resolveExit(exitCode2 ?? 0));
|
|
22105
22182
|
});
|
|
22106
|
-
|
|
22183
|
+
this.runningInstalls.delete(taskId);
|
|
22184
|
+
this.setRecentBuffer(installStreamId, installBuffer);
|
|
22185
|
+
if (this.isShuttingDown) {
|
|
22186
|
+
await saveTerminalBuffer(workspaceId, installStreamId, installBuffer);
|
|
22187
|
+
return;
|
|
22188
|
+
}
|
|
22189
|
+
if (this.manuallyStoppedInstalls.delete(taskId)) {
|
|
22190
|
+
emitInstall("\r\n\x1B[1;33mInstall stopped \u2014 task reset\x1B[0m\r\n");
|
|
22191
|
+
await saveTerminalBuffer(workspaceId, installStreamId, installBuffer);
|
|
22192
|
+
await endTerminalSession(workspaceId, taskId, installStreamId, Date.now(), "stopped");
|
|
22193
|
+
if (hasSharedWorktree) this.runningSharedWorktrees.delete(effectiveWorktreeId);
|
|
22194
|
+
await removeWorktreeAsync(effectiveWorktreeId, repoPath, worktree.branch);
|
|
22195
|
+
await clearCardSession(workspaceId, taskId);
|
|
22196
|
+
await updateCard(workspaceId, taskId, { readyForDev: false });
|
|
22197
|
+
const stoppedBoard = await loadBoard(workspaceId);
|
|
22198
|
+
if (stoppedBoard.cards[taskId]?.columnId === "in_progress") {
|
|
22199
|
+
await moveCard(workspaceId, taskId, "todo");
|
|
22200
|
+
await appendActivityLog(workspaceId, taskId, "Moved back to Todo");
|
|
22201
|
+
}
|
|
22202
|
+
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22203
|
+
return;
|
|
22204
|
+
}
|
|
22205
|
+
if (exitCode !== 0) {
|
|
22206
|
+
logger.error(`[scheduler] Install command failed (code ${exitCode}) for task ${taskId}`);
|
|
22207
|
+
emitInstall(`\r
|
|
22208
|
+
\x1B[1;31mInstall command failed (code ${exitCode}) \u2014 proceeding anyway\x1B[0m\r
|
|
22209
|
+
`);
|
|
22210
|
+
await appendActivityLog(
|
|
22211
|
+
workspaceId,
|
|
22212
|
+
taskId,
|
|
22213
|
+
`Install command failed (code ${exitCode}) \u2014 proceeding anyway`
|
|
22214
|
+
);
|
|
22215
|
+
} else {
|
|
22216
|
+
emitInstall("\r\n\x1B[1;32mInstall complete\x1B[0m\r\n");
|
|
22217
|
+
await appendActivityLog(workspaceId, taskId, "Install complete");
|
|
22218
|
+
}
|
|
22219
|
+
await saveTerminalBuffer(workspaceId, installStreamId, installBuffer);
|
|
22220
|
+
await endTerminalSession(
|
|
22221
|
+
workspaceId,
|
|
22222
|
+
taskId,
|
|
22223
|
+
installStreamId,
|
|
22224
|
+
Date.now(),
|
|
22225
|
+
exitCode === 0 ? "completed" : "failed"
|
|
22226
|
+
);
|
|
22107
22227
|
stateHub.broadcastWorkspaceUpdate(workspaceId);
|
|
22108
22228
|
}
|
|
22109
22229
|
}
|
|
@@ -22355,6 +22475,15 @@ ${devSystemPromptResult.text}`;
|
|
|
22355
22475
|
}
|
|
22356
22476
|
}
|
|
22357
22477
|
stopTask(taskId) {
|
|
22478
|
+
const installProc = this.runningInstalls.get(taskId);
|
|
22479
|
+
if (installProc) {
|
|
22480
|
+
logger.info(`[scheduler] stopTask: install running \u2014 stopping task ${taskId}`);
|
|
22481
|
+
this.manuallyStoppedInstalls.add(taskId);
|
|
22482
|
+
this.runningInstalls.delete(taskId);
|
|
22483
|
+
killInstallProcess(installProc);
|
|
22484
|
+
void appendActivityLog(this.options.workspaceId, taskId, "Install stopped manually");
|
|
22485
|
+
return;
|
|
22486
|
+
}
|
|
22358
22487
|
const task = this.running.get(taskId);
|
|
22359
22488
|
if (task) {
|
|
22360
22489
|
logger.info(`[scheduler] stopTask: dev agent running \u2014 stopping task ${taskId}`);
|
|
@@ -22610,6 +22739,10 @@ ${devSystemPromptResult.text}`;
|
|
|
22610
22739
|
for (const [taskId] of this.running) {
|
|
22611
22740
|
this.stopTask(taskId);
|
|
22612
22741
|
}
|
|
22742
|
+
for (const proc of this.runningInstalls.values()) {
|
|
22743
|
+
killInstallProcess(proc);
|
|
22744
|
+
}
|
|
22745
|
+
this.runningInstalls.clear();
|
|
22613
22746
|
this.stopAssistantAgent();
|
|
22614
22747
|
}
|
|
22615
22748
|
// Call before stopAll() during graceful shutdown so onExit handlers bail out
|
|
@@ -22618,6 +22751,28 @@ ${devSystemPromptResult.text}`;
|
|
|
22618
22751
|
this.isShuttingDown = true;
|
|
22619
22752
|
}
|
|
22620
22753
|
};
|
|
22754
|
+
function killInstallProcess(proc) {
|
|
22755
|
+
try {
|
|
22756
|
+
(0, import_tree_kill2.default)(proc.pid, "SIGKILL");
|
|
22757
|
+
} catch {
|
|
22758
|
+
}
|
|
22759
|
+
}
|
|
22760
|
+
async function shareIntoWorktree(src, dst) {
|
|
22761
|
+
const isDir = (await stat2(src)).isDirectory();
|
|
22762
|
+
if (process.platform !== "win32") {
|
|
22763
|
+
await symlink(src, dst, isDir ? "dir" : "file");
|
|
22764
|
+
return;
|
|
22765
|
+
}
|
|
22766
|
+
if (isDir) {
|
|
22767
|
+
await symlink(src, dst, "junction");
|
|
22768
|
+
return;
|
|
22769
|
+
}
|
|
22770
|
+
try {
|
|
22771
|
+
await link(src, dst);
|
|
22772
|
+
} catch {
|
|
22773
|
+
await cp(src, dst, { recursive: true, dereference: true });
|
|
22774
|
+
}
|
|
22775
|
+
}
|
|
22621
22776
|
function getMcpServerPath() {
|
|
22622
22777
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
22623
22778
|
const thisDir = dirname6(thisFile);
|
|
@@ -26500,7 +26655,8 @@ function appExists(bundle) {
|
|
|
26500
26655
|
return paths.some((p2) => existsSync11(p2));
|
|
26501
26656
|
}
|
|
26502
26657
|
function binaryExists(bin) {
|
|
26503
|
-
const
|
|
26658
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
26659
|
+
const r = spawnSync7(finder, [bin], { stdio: ["ignore", "pipe", "ignore"], encoding: "utf-8" });
|
|
26504
26660
|
return r.status === 0 && r.stdout.trim().length > 0;
|
|
26505
26661
|
}
|
|
26506
26662
|
function listTerminalApps() {
|
|
@@ -26941,8 +27097,8 @@ var checkProjectPath = async (repoPath) => {
|
|
|
26941
27097
|
return { valid: false, isGitRepo: false, error: null, name: null, branch: null, remote: null, branches: [] };
|
|
26942
27098
|
const { statSync: statSync2 } = await import("node:fs");
|
|
26943
27099
|
try {
|
|
26944
|
-
const
|
|
26945
|
-
if (!
|
|
27100
|
+
const stat3 = statSync2(repoPath);
|
|
27101
|
+
if (!stat3.isDirectory())
|
|
26946
27102
|
return {
|
|
26947
27103
|
valid: false,
|
|
26948
27104
|
isGitRepo: false,
|
|
@@ -26998,8 +27154,8 @@ var checkProjectPath = async (repoPath) => {
|
|
|
26998
27154
|
var addProject = async (repoPath, initialConfig) => {
|
|
26999
27155
|
const { statSync: statSync2 } = await import("node:fs");
|
|
27000
27156
|
try {
|
|
27001
|
-
const
|
|
27002
|
-
if (!
|
|
27157
|
+
const stat3 = statSync2(repoPath);
|
|
27158
|
+
if (!stat3.isDirectory()) throw new Error("Not a directory");
|
|
27003
27159
|
} catch {
|
|
27004
27160
|
throw BadRequestError(`Path does not exist: ${repoPath}`);
|
|
27005
27161
|
}
|
|
@@ -27336,13 +27492,13 @@ import { z as z14 } from "zod";
|
|
|
27336
27492
|
init_runtime_config();
|
|
27337
27493
|
|
|
27338
27494
|
// src/tunnel/cloudflare-setup.ts
|
|
27339
|
-
init_runtime_config();
|
|
27340
|
-
init_logger();
|
|
27341
27495
|
import { execFile as execFile9, spawn as spawn7 } from "node:child_process";
|
|
27342
|
-
import { mkdir as
|
|
27496
|
+
import { mkdir as mkdir4, writeFile as writeFile3, readFile as readFile3, access, unlink as unlink4 } from "node:fs/promises";
|
|
27343
27497
|
import { homedir as homedir5 } from "node:os";
|
|
27344
27498
|
import { join as join20 } from "node:path";
|
|
27345
27499
|
import { promisify as promisify9 } from "node:util";
|
|
27500
|
+
init_runtime_config();
|
|
27501
|
+
init_logger();
|
|
27346
27502
|
var execFileAsync7 = promisify9(execFile9);
|
|
27347
27503
|
var CLOUDFLARED_DIR = join20(homedir5(), ".cloudflared");
|
|
27348
27504
|
async function checkCloudflaredInstalled() {
|
|
@@ -27385,7 +27541,8 @@ async function openCloudflaredLogin(force = false) {
|
|
|
27385
27541
|
resolved = true;
|
|
27386
27542
|
const loginUrl = match2[1].trim();
|
|
27387
27543
|
logger.info(`[cloudflared-login] Auth URL: ${loginUrl}`);
|
|
27388
|
-
|
|
27544
|
+
open_default(loginUrl).catch(() => {
|
|
27545
|
+
});
|
|
27389
27546
|
proc.unref();
|
|
27390
27547
|
resolve5({ alreadyLoggedIn: false, loginUrl });
|
|
27391
27548
|
}
|
|
@@ -27445,7 +27602,7 @@ async function writeTunnelConfig(tunnelId, tunnelName, domain) {
|
|
|
27445
27602
|
` service: http://127.0.0.1:${DEFAULT_PORT}`,
|
|
27446
27603
|
` - service: http_status:404`
|
|
27447
27604
|
].join("\n");
|
|
27448
|
-
await
|
|
27605
|
+
await mkdir4(CLOUDFLARED_DIR, { recursive: true });
|
|
27449
27606
|
await writeFile3(join20(CLOUDFLARED_DIR, "config.yml"), config, "utf-8");
|
|
27450
27607
|
logger.info(`[tunnel-setup] Wrote ~/.cloudflared/config.yml for tunnel ${tunnelName}`);
|
|
27451
27608
|
}
|
|
@@ -27534,7 +27691,7 @@ import { z as z15 } from "zod";
|
|
|
27534
27691
|
// src/api/services/workflows-service.ts
|
|
27535
27692
|
init_workspace_state();
|
|
27536
27693
|
import { existsSync as existsSync13 } from "node:fs";
|
|
27537
|
-
import { mkdir as
|
|
27694
|
+
import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
27538
27695
|
import { dirname as dirname8, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
|
|
27539
27696
|
var resolvePromptPath = async (workspaceId, requestedPath) => {
|
|
27540
27697
|
const workspaces = await listWorkspaces();
|
|
@@ -27572,7 +27729,7 @@ var deleteWorkflow = async (workspaceId, workflowId) => {
|
|
|
27572
27729
|
};
|
|
27573
27730
|
var writePromptFile = async (workspaceId, path2, content) => {
|
|
27574
27731
|
const targetPath = await resolvePromptPath(workspaceId, path2);
|
|
27575
|
-
await
|
|
27732
|
+
await mkdir5(dirname8(targetPath), { recursive: true });
|
|
27576
27733
|
await writeFile4(targetPath, content, "utf-8");
|
|
27577
27734
|
return { path: path2 };
|
|
27578
27735
|
};
|
|
@@ -27902,8 +28059,8 @@ async function createRuntimeServer(options) {
|
|
|
27902
28059
|
const runTerminalListeners = /* @__PURE__ */ new Map();
|
|
27903
28060
|
function startRun(workspaceId, cardId, command, cwd) {
|
|
27904
28061
|
stopRun(workspaceId);
|
|
27905
|
-
const shell =
|
|
27906
|
-
const pty =
|
|
28062
|
+
const [shell, shellArgs] = getShellInvocation(command);
|
|
28063
|
+
const pty = nodePty3.spawn(shell, shellArgs, {
|
|
27907
28064
|
name: "xterm-256color",
|
|
27908
28065
|
cols: 120,
|
|
27909
28066
|
rows: 40,
|
|
@@ -28613,7 +28770,7 @@ process.on("uncaughtException", (err) => {
|
|
|
28613
28770
|
if (err.code === "EPIPE" || err.code === "ECONNRESET") return;
|
|
28614
28771
|
throw err;
|
|
28615
28772
|
});
|
|
28616
|
-
var VERSION9 = true ? "0.
|
|
28773
|
+
var VERSION9 = true ? "0.8.0" : "0.0.0-dev";
|
|
28617
28774
|
async function isPortAvailable(port, host) {
|
|
28618
28775
|
return new Promise((resolve5) => {
|
|
28619
28776
|
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, 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;
|
|
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, runtimeWorktreeCopyEntrySchema, 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";
|
|
@@ -394,8 +394,13 @@ Do NOT include:
|
|
|
394
394
|
runtimeGithubConfigSchema = z.object({
|
|
395
395
|
token: z.string()
|
|
396
396
|
});
|
|
397
|
+
runtimeWorktreeCopyEntrySchema = z.object({
|
|
398
|
+
path: z.string().min(1),
|
|
399
|
+
symlink: z.boolean().default(false)
|
|
400
|
+
});
|
|
397
401
|
runtimeWorktreeSetupSchema = z.object({
|
|
398
|
-
|
|
402
|
+
// Legacy configs stored bare strings; accept and normalize them to copy entries.
|
|
403
|
+
filesToCopy: z.array(z.union([z.string().transform((path) => ({ path, symlink: false })), runtimeWorktreeCopyEntrySchema])).default([]),
|
|
399
404
|
installCommand: z.string().default("")
|
|
400
405
|
});
|
|
401
406
|
runtimeProjectSecretSchema = z.object({
|
|
@@ -6460,6 +6460,10 @@
|
|
|
6460
6460
|
color: #7a7a40;
|
|
6461
6461
|
}
|
|
6462
6462
|
|
|
6463
|
+
.text-\[\#7aa2f7\] {
|
|
6464
|
+
color: #7aa2f7;
|
|
6465
|
+
}
|
|
6466
|
+
|
|
6463
6467
|
.text-\[\#7c6aff\] {
|
|
6464
6468
|
color: #7c6aff;
|
|
6465
6469
|
}
|
|
@@ -6472,6 +6476,10 @@
|
|
|
6472
6476
|
color: #8888a0;
|
|
6473
6477
|
}
|
|
6474
6478
|
|
|
6479
|
+
.text-\[\#45455a\] {
|
|
6480
|
+
color: #45455a;
|
|
6481
|
+
}
|
|
6482
|
+
|
|
6475
6483
|
.text-\[\#60607a\] {
|
|
6476
6484
|
color: #60607a;
|
|
6477
6485
|
}
|
|
@@ -7054,6 +7062,10 @@
|
|
|
7054
7062
|
background-color: #15151b;
|
|
7055
7063
|
}
|
|
7056
7064
|
|
|
7065
|
+
.hover\:bg-\[\#17171f\]:hover {
|
|
7066
|
+
background-color: #17171f;
|
|
7067
|
+
}
|
|
7068
|
+
|
|
7057
7069
|
.hover\:bg-\[\#252510\]:hover {
|
|
7058
7070
|
background-color: #252510;
|
|
7059
7071
|
}
|
|
@@ -7140,6 +7152,10 @@
|
|
|
7140
7152
|
color: #7c6aff;
|
|
7141
7153
|
}
|
|
7142
7154
|
|
|
7155
|
+
.hover\:text-\[\#9a9ab0\]:hover {
|
|
7156
|
+
color: #9a9ab0;
|
|
7157
|
+
}
|
|
7158
|
+
|
|
7143
7159
|
.hover\:text-\[\#22c55e\]:hover {
|
|
7144
7160
|
color: #22c55e;
|
|
7145
7161
|
}
|
|
@@ -27603,8 +27603,13 @@ const runtimeGlobalConfigSchema = object({
|
|
|
27603
27603
|
const runtimeGithubConfigSchema = object({
|
|
27604
27604
|
token: string$2()
|
|
27605
27605
|
});
|
|
27606
|
+
const runtimeWorktreeCopyEntrySchema = object({
|
|
27607
|
+
path: string$2().min(1),
|
|
27608
|
+
symlink: boolean$1().default(false)
|
|
27609
|
+
});
|
|
27606
27610
|
const runtimeWorktreeSetupSchema = object({
|
|
27607
|
-
|
|
27611
|
+
// Legacy configs stored bare strings; accept and normalize them to copy entries.
|
|
27612
|
+
filesToCopy: array(union([string$2().transform((path2) => ({ path: path2, symlink: false })), runtimeWorktreeCopyEntrySchema])).default([]),
|
|
27608
27613
|
installCommand: string$2().default("")
|
|
27609
27614
|
});
|
|
27610
27615
|
const runtimeProjectSecretSchema = object({
|
|
@@ -50176,6 +50181,9 @@ const AGENT_DISPLAY = {
|
|
|
50176
50181
|
dotColor: "bg-[#fb8147]"
|
|
50177
50182
|
}
|
|
50178
50183
|
};
|
|
50184
|
+
const SESSION_TYPE_LABELS = {
|
|
50185
|
+
install: "Install"
|
|
50186
|
+
};
|
|
50179
50187
|
function formatElapsed(sec) {
|
|
50180
50188
|
return `${Math.floor(sec / 60)}m ${(sec % 60).toString().padStart(2, "0")}s`;
|
|
50181
50189
|
}
|
|
@@ -50506,7 +50514,7 @@ function WorkflowPipeline({
|
|
|
50506
50514
|
/* Collapsed: icon-only timeline centered */
|
|
50507
50515
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col items-center pb-4 gap-0", children: sessions.length > 0 ? sessions.map((session, idx) => {
|
|
50508
50516
|
var _a3;
|
|
50509
|
-
const slotName = ((_a3 = workflowSlots == null ? void 0 : workflowSlots.find((s16) => s16.id === session.type)) == null ? void 0 : _a3.name) ?? session.type;
|
|
50517
|
+
const slotName = ((_a3 = workflowSlots == null ? void 0 : workflowSlots.find((s16) => s16.id === session.type)) == null ? void 0 : _a3.name) ?? SESSION_TYPE_LABELS[session.type] ?? session.type;
|
|
50510
50518
|
const status = sessionStatus(session);
|
|
50511
50519
|
const isFocused = activeStreamId === session.streamId;
|
|
50512
50520
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center", children: [
|
|
@@ -50541,7 +50549,7 @@ function WorkflowPipeline({
|
|
|
50541
50549
|
/* Expanded: full rows */
|
|
50542
50550
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col px-[18px] pb-4 max-h-72 overflow-y-auto", children: sessions.length > 0 ? sessions.map((session, idx) => {
|
|
50543
50551
|
var _a3;
|
|
50544
|
-
const slotName = ((_a3 = workflowSlots == null ? void 0 : workflowSlots.find((s16) => s16.id === session.type)) == null ? void 0 : _a3.name) ?? session.type;
|
|
50552
|
+
const slotName = ((_a3 = workflowSlots == null ? void 0 : workflowSlots.find((s16) => s16.id === session.type)) == null ? void 0 : _a3.name) ?? SESSION_TYPE_LABELS[session.type] ?? session.type;
|
|
50545
50553
|
const status = sessionStatus(session);
|
|
50546
50554
|
const duration2 = slotDuration(session.startedAt, session.endedAt);
|
|
50547
50555
|
const isFocused = activeStreamId === session.streamId;
|
|
@@ -78188,6 +78196,9 @@ const globalConfigFormSchema = runtimeGlobalConfigSchema.extend({
|
|
|
78188
78196
|
});
|
|
78189
78197
|
const notificationSoundsFormSchema = notificationSoundsConfigSchema;
|
|
78190
78198
|
const environmentFormSchema = runtimeWorktreeSetupSchema.extend({
|
|
78199
|
+
// The form always works with normalized copy entries (legacy-string tolerance
|
|
78200
|
+
// lives in the persistence schema), so the RHF value type stays clean.
|
|
78201
|
+
filesToCopy: array(runtimeWorktreeCopyEntrySchema).default([]),
|
|
78191
78202
|
startCommand: string$2().default("")
|
|
78192
78203
|
});
|
|
78193
78204
|
object({
|
|
@@ -79867,39 +79878,70 @@ function FilesBox({
|
|
|
79867
79878
|
}, [filesError]);
|
|
79868
79879
|
const rootFiles = (data == null ? void 0 : data.files) ?? null;
|
|
79869
79880
|
const discoveredSet = new Set(rootFiles ?? []);
|
|
79870
|
-
const
|
|
79881
|
+
const byPath = new Map(filesToCopy.map((e) => [e.path, e]));
|
|
79882
|
+
const allFiles = [.../* @__PURE__ */ new Set([...rootFiles ?? [], ...filesToCopy.map((e) => e.path)])].sort();
|
|
79871
79883
|
const toggle = (file, checked) => {
|
|
79872
|
-
|
|
79884
|
+
if (checked) {
|
|
79885
|
+
if (!byPath.has(file)) onChange([...filesToCopy, { path: file, symlink: false }]);
|
|
79886
|
+
} else {
|
|
79887
|
+
onChange(filesToCopy.filter((e) => e.path !== file));
|
|
79888
|
+
}
|
|
79889
|
+
};
|
|
79890
|
+
const setSymlink = (file, symlink) => {
|
|
79891
|
+
onChange(filesToCopy.map((e) => e.path === file ? { ...e, symlink } : e));
|
|
79873
79892
|
};
|
|
79874
79893
|
const addManual = () => {
|
|
79875
79894
|
const val = addInput.trim();
|
|
79876
79895
|
if (!val) return;
|
|
79877
|
-
|
|
79896
|
+
if (!byPath.has(val)) onChange([...filesToCopy, { path: val, symlink: false }]);
|
|
79878
79897
|
setAddInput("");
|
|
79879
79898
|
};
|
|
79880
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-
|
|
79899
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-0.5 bg-[#0c0c0f] border border-[#2a2a35] rounded-md px-3 py-2 flex-1", children: [
|
|
79881
79900
|
rootFiles === null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] py-1 text-[#4a4a5a]", children: "Scanning..." }),
|
|
79882
79901
|
rootFiles !== null && allFiles.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] py-1 text-[#4a4a5a]", children: "No gitignored files found in repo root" }),
|
|
79883
79902
|
allFiles.map((file) => {
|
|
79884
|
-
const
|
|
79903
|
+
const entry = byPath.get(file);
|
|
79904
|
+
const checked = !!entry;
|
|
79885
79905
|
const isManual = !discoveredSet.has(file);
|
|
79886
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
79887
|
-
|
|
79888
|
-
|
|
79889
|
-
|
|
79890
|
-
|
|
79891
|
-
|
|
79892
|
-
|
|
79893
|
-
|
|
79894
|
-
|
|
79895
|
-
|
|
79896
|
-
|
|
79897
|
-
|
|
79898
|
-
|
|
79899
|
-
|
|
79900
|
-
|
|
79906
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
79907
|
+
"label",
|
|
79908
|
+
{
|
|
79909
|
+
className: "flex items-center gap-2 cursor-pointer group -mx-2 px-2 py-1 rounded transition-colors hover:bg-[#17171f]",
|
|
79910
|
+
children: [
|
|
79911
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 w-4 flex justify-center", children: entry && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
79912
|
+
"button",
|
|
79913
|
+
{
|
|
79914
|
+
type: "button",
|
|
79915
|
+
title: entry.symlink ? "Symlinked (shared from repo). Click to copy instead." : "Copied into worktree. Click to symlink (share from repo, e.g. node_modules).",
|
|
79916
|
+
onClick: (e) => {
|
|
79917
|
+
e.preventDefault();
|
|
79918
|
+
setSymlink(file, !entry.symlink);
|
|
79919
|
+
},
|
|
79920
|
+
className: `transition-colors ${entry.symlink ? "text-[#7aa2f7]" : "text-[#45455a] hover:text-[#9a9ab0]"}`,
|
|
79921
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { size: 12 })
|
|
79922
|
+
}
|
|
79923
|
+
) }),
|
|
79924
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CustomCheckbox, { checked, onChange: (v2) => toggle(file, v2) }),
|
|
79925
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[12px] font-mono text-[#c0c0d0]", children: file }),
|
|
79926
|
+
isManual && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
79927
|
+
"button",
|
|
79928
|
+
{
|
|
79929
|
+
type: "button",
|
|
79930
|
+
onClick: (e) => {
|
|
79931
|
+
e.preventDefault();
|
|
79932
|
+
onChange(filesToCopy.filter((f) => f.path !== file));
|
|
79933
|
+
},
|
|
79934
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity text-[#60607a]",
|
|
79935
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 11 })
|
|
79936
|
+
}
|
|
79937
|
+
)
|
|
79938
|
+
]
|
|
79939
|
+
},
|
|
79940
|
+
file
|
|
79941
|
+
);
|
|
79901
79942
|
}),
|
|
79902
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 pt-1", children: [
|
|
79943
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 pt-1.5", children: [
|
|
79944
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 w-4" }),
|
|
79903
79945
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-4 h-4 border border-[#2a2a35] rounded-[3px]" }),
|
|
79904
79946
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
79905
79947
|
"input",
|
package/dist/web-ui/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
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-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CuGz83Sg.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CRXPsGTP.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whipped",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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,7 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=22"
|
|
24
24
|
},
|
|
25
|
+
"packageManager": "pnpm@11.8.0",
|
|
25
26
|
"scripts": {
|
|
26
27
|
"clean": "rm -rf dist",
|
|
27
28
|
"build": "pnpm clean && pnpm web:build && node scripts/build.mjs",
|
|
@@ -67,15 +68,5 @@
|
|
|
67
68
|
"esbuild": "^0.27.4",
|
|
68
69
|
"tsx": "^4.20.3",
|
|
69
70
|
"typescript": "^5.9.3"
|
|
70
|
-
},
|
|
71
|
-
"pnpm": {
|
|
72
|
-
"onlyBuiltDependencies": [
|
|
73
|
-
"better-sqlite3",
|
|
74
|
-
"esbuild",
|
|
75
|
-
"node-pty"
|
|
76
|
-
],
|
|
77
|
-
"overrides": {
|
|
78
|
-
"hono": "4.12.23"
|
|
79
|
-
}
|
|
80
71
|
}
|
|
81
|
-
}
|
|
72
|
+
}
|