whipped 0.5.1 → 0.7.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.
@@ -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, 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";
@@ -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(),
@@ -384,8 +394,13 @@ Do NOT include:
384
394
  runtimeGithubConfigSchema = z.object({
385
395
  token: z.string()
386
396
  });
397
+ runtimeWorktreeCopyEntrySchema = z.object({
398
+ path: z.string().min(1),
399
+ symlink: z.boolean().default(false)
400
+ });
387
401
  runtimeWorktreeSetupSchema = z.object({
388
- filesToCopy: z.array(z.string()).default([]),
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([]),
389
404
  installCommand: z.string().default("")
390
405
  });
391
406
  runtimeProjectSecretSchema = z.object({
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$18 = [
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$18);
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$17 = [
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$17);
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(),
@@ -27576,8 +27603,13 @@ const runtimeGlobalConfigSchema = object({
27576
27603
  const runtimeGithubConfigSchema = object({
27577
27604
  token: string$2()
27578
27605
  });
27606
+ const runtimeWorktreeCopyEntrySchema = object({
27607
+ path: string$2().min(1),
27608
+ symlink: boolean$1().default(false)
27609
+ });
27579
27610
  const runtimeWorktreeSetupSchema = object({
27580
- filesToCopy: array(string$2()).default([]),
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([]),
27581
27613
  installCommand: string$2().default("")
27582
27614
  });
27583
27615
  const runtimeProjectSecretSchema = object({
@@ -78159,7 +78191,11 @@ const globalConfigFormSchema = runtimeGlobalConfigSchema.extend({
78159
78191
  pollingIntervalSeconds: number$1().int().positive(),
78160
78192
  prPollingIntervalSeconds: number$1().int().positive()
78161
78193
  });
78194
+ const notificationSoundsFormSchema = notificationSoundsConfigSchema;
78162
78195
  const environmentFormSchema = runtimeWorktreeSetupSchema.extend({
78196
+ // The form always works with normalized copy entries (legacy-string tolerance
78197
+ // lives in the persistence schema), so the RHF value type stays clean.
78198
+ filesToCopy: array(runtimeWorktreeCopyEntrySchema).default([]),
78163
78199
  startCommand: string$2().default("")
78164
78200
  });
78165
78201
  object({
@@ -78180,19 +78216,19 @@ const instructionsFormSchema = object({
78180
78216
  systemPrompt: string$2().optional(),
78181
78217
  gitInstructions: string$2().optional()
78182
78218
  });
78183
- function PageHeader$1({ title, description }) {
78219
+ function PageHeader$2({ title, description }) {
78184
78220
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex flex-col gap-1 px-10 py-6 border-b border-[#2a2a35]", children: [
78185
78221
  /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-xl font-semibold text-[#f0f0f5]", children: title }),
78186
78222
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#60607a]", children: description })
78187
78223
  ] });
78188
78224
  }
78189
- function SectionDivider$3({ title }) {
78225
+ function SectionDivider$4({ title }) {
78190
78226
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
78191
78227
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[15px] font-semibold text-[#f0f0f5]", children: title }),
78192
78228
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px bg-[#1a1a1f]" })
78193
78229
  ] });
78194
78230
  }
78195
- function FieldRow$1({ label, description, children }) {
78231
+ function FieldRow$2({ label, description, children }) {
78196
78232
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
78197
78233
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
78198
78234
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium text-[#c0c0d0]", children: label }),
@@ -78222,7 +78258,7 @@ function GlobalSettings({ section }) {
78222
78258
  });
78223
78259
  if (!config2) {
78224
78260
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col", children: [
78225
- /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
78261
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$2, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
78226
78262
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20 text-sm text-[#60607a]", children: "Loading..." })
78227
78263
  ] });
78228
78264
  }
@@ -78231,13 +78267,13 @@ function GlobalSettings({ section }) {
78231
78267
  label: t2.label
78232
78268
  }));
78233
78269
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
78234
- /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
78270
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$2, { title: "Global Runtime Config", description: "Settings that apply across all projects" }),
78235
78271
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-10 py-6", children: [
78236
78272
  /* @__PURE__ */ jsxRuntimeExports.jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit, className: "flex flex-col gap-6", children: [
78237
78273
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
78238
- /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Defaults" }),
78239
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { 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)) }) }),
78240
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "Terminal App", description: "Application for opening terminals", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78274
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Defaults" }),
78275
+ /* @__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)) }) }),
78276
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Terminal App", description: "Application for opening terminals", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78241
78277
  RHFSelect_default,
78242
78278
  {
78243
78279
  wrapperClassName: "w-fit",
@@ -78250,8 +78286,8 @@ function GlobalSettings({ section }) {
78250
78286
  ) })
78251
78287
  ] }),
78252
78288
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
78253
- /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Concurrency & Limits" }),
78254
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "Max Parallel Tasks", description: "Concurrent task executions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78289
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Concurrency & Limits" }),
78290
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Parallel Tasks", description: "Concurrent task executions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78255
78291
  RHFNumberInput_default,
78256
78292
  {
78257
78293
  name: "maxParallelTasks",
@@ -78260,7 +78296,7 @@ function GlobalSettings({ section }) {
78260
78296
  inputClassName: "text-center"
78261
78297
  }
78262
78298
  ) }),
78263
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "Max Parallel QA", description: "Concurrent QA slot runs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78299
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Parallel QA", description: "Concurrent QA slot runs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78264
78300
  RHFNumberInput_default,
78265
78301
  {
78266
78302
  name: "maxParallelQA",
@@ -78269,7 +78305,7 @@ function GlobalSettings({ section }) {
78269
78305
  inputClassName: "text-center"
78270
78306
  }
78271
78307
  ) }),
78272
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "Max Auto-Fix Attempts", description: "Retries before marking blocked", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78308
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Max Auto-Fix Attempts", description: "Retries before marking blocked", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78273
78309
  RHFNumberInput_default,
78274
78310
  {
78275
78311
  name: "maxAutoFixAttempts",
@@ -78280,8 +78316,8 @@ function GlobalSettings({ section }) {
78280
78316
  ) })
78281
78317
  ] }),
78282
78318
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
78283
- /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Polling" }),
78284
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "Polling Interval", description: "Board refresh interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78319
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Polling" }),
78320
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "Polling Interval", description: "Board refresh interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78285
78321
  RHFNumberInput_default,
78286
78322
  {
78287
78323
  name: "pollingIntervalSeconds",
@@ -78290,7 +78326,7 @@ function GlobalSettings({ section }) {
78290
78326
  inputClassName: "text-center"
78291
78327
  }
78292
78328
  ) }),
78293
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { label: "PR Poll Interval", description: "PR status check interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78329
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$2, { label: "PR Poll Interval", description: "PR status check interval (seconds)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
78294
78330
  RHFNumberInput_default,
78295
78331
  {
78296
78332
  name: "prPollingIntervalSeconds",
@@ -78303,12 +78339,86 @@ function GlobalSettings({ section }) {
78303
78339
  /* @__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
78340
  ] }) }),
78305
78341
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4 pt-6 mt-6 border-t border-[#1a1a1f]", children: [
78306
- /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Session" }),
78307
- /* @__PURE__ */ jsxRuntimeExports.jsx(FieldRow$1, { 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" }) })
78342
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$4, { title: "Session" }),
78343
+ /* @__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
78344
  ] })
78309
78345
  ] })
78310
78346
  ] });
78311
78347
  }
78348
+ function PageHeader$1({ title, description }) {
78349
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex flex-col gap-1 px-10 py-6 border-b border-[#2a2a35]", children: [
78350
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-xl font-semibold text-[#f0f0f5]", children: title }),
78351
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#60607a]", children: description })
78352
+ ] });
78353
+ }
78354
+ function SectionDivider$3({ title }) {
78355
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
78356
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[15px] font-semibold text-[#f0f0f5]", children: title }),
78357
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px bg-[#1a1a1f]" })
78358
+ ] });
78359
+ }
78360
+ function FieldRow$1({ label, description, children }) {
78361
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
78362
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
78363
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium text-[#c0c0d0]", children: label }),
78364
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-[#60607a]", children: description })
78365
+ ] }),
78366
+ children
78367
+ ] });
78368
+ }
78369
+ const PER_EVENT_ROWS = [
78370
+ { name: "readyForReview", label: "Ready for Review", description: "A task finished and is waiting for your review" },
78371
+ { name: "prComment", label: "New PR comment", description: "A reviewer commented on a task's pull request" },
78372
+ { name: "done", label: "Done / PR merged", description: "A task's pull request was merged" },
78373
+ { name: "reopened", label: "Reopened", description: "Changes were requested — the task needs another pass" },
78374
+ { name: "blocked", label: "Blocked", description: "A task was blocked (PR closed, or auto-fix attempts exhausted)" },
78375
+ { name: "runError", label: "Run error", description: "A run/preview process exited with an error" }
78376
+ ];
78377
+ function NotificationsSettings() {
78378
+ const { data: config2 } = useRead((api) => api("config").GET());
78379
+ const { trigger: saveConfig, loading: saving } = useWrite((api) => api("config").PUT());
78380
+ const methods = useForm({
78381
+ resolver: u(notificationSoundsFormSchema),
78382
+ values: config2 == null ? void 0 : config2.notificationSounds
78383
+ });
78384
+ const onSubmit = methods.handleSubmit(async (values) => {
78385
+ const res = await saveConfig({ body: { notificationSounds: values } });
78386
+ if (res.error) {
78387
+ toast.error("Failed to save settings");
78388
+ return;
78389
+ }
78390
+ methods.reset(values);
78391
+ toast.success("Settings saved");
78392
+ });
78393
+ if (!config2) {
78394
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col", children: [
78395
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Notifications", description: "Sounds played on the daemon host when tasks need you" }),
78396
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20 text-sm text-[#60607a]", children: "Loading..." })
78397
+ ] });
78398
+ }
78399
+ const enabled = methods.watch("enabled");
78400
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
78401
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PageHeader$1, { title: "Notifications", description: "Sounds played on the daemon host when tasks need you" }),
78402
+ /* @__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: [
78403
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
78404
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Sounds" }),
78405
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
78406
+ FieldRow$1,
78407
+ {
78408
+ label: "Notification sounds",
78409
+ description: "Play a sound on the machine running Whipped — works even when no browser is open",
78410
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(RHFSwitch_default, { name: "enabled" })
78411
+ }
78412
+ )
78413
+ ] }),
78414
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: enabled ? "flex flex-col gap-4" : "flex flex-col gap-4 opacity-50", children: [
78415
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDivider$3, { title: "Events" }),
78416
+ 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))
78417
+ ] }),
78418
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end pt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button_default, { type: "submit", disabled: saving, children: saving ? "Saving..." : "Save" }) })
78419
+ ] }) }) })
78420
+ ] });
78421
+ }
78312
78422
  function FilePickerDialog({ initialPath, onSelect, onClose }) {
78313
78423
  const [path2, setPath] = reactExports.useState(initialPath ?? "");
78314
78424
  const [selectedFile, setSelectedFile] = reactExports.useState(null);
@@ -79765,39 +79875,70 @@ function FilesBox({
79765
79875
  }, [filesError]);
79766
79876
  const rootFiles = (data == null ? void 0 : data.files) ?? null;
79767
79877
  const discoveredSet = new Set(rootFiles ?? []);
79768
- const allFiles = [.../* @__PURE__ */ new Set([...rootFiles ?? [], ...filesToCopy])].sort();
79878
+ const byPath = new Map(filesToCopy.map((e) => [e.path, e]));
79879
+ const allFiles = [.../* @__PURE__ */ new Set([...rootFiles ?? [], ...filesToCopy.map((e) => e.path)])].sort();
79769
79880
  const toggle = (file, checked) => {
79770
- onChange(checked ? [.../* @__PURE__ */ new Set([...filesToCopy, file])] : filesToCopy.filter((f) => f !== file));
79881
+ if (checked) {
79882
+ if (!byPath.has(file)) onChange([...filesToCopy, { path: file, symlink: false }]);
79883
+ } else {
79884
+ onChange(filesToCopy.filter((e) => e.path !== file));
79885
+ }
79886
+ };
79887
+ const setSymlink = (file, symlink) => {
79888
+ onChange(filesToCopy.map((e) => e.path === file ? { ...e, symlink } : e));
79771
79889
  };
79772
79890
  const addManual = () => {
79773
79891
  const val = addInput.trim();
79774
79892
  if (!val) return;
79775
- onChange([.../* @__PURE__ */ new Set([...filesToCopy, val])]);
79893
+ if (!byPath.has(val)) onChange([...filesToCopy, { path: val, symlink: false }]);
79776
79894
  setAddInput("");
79777
79895
  };
79778
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5 bg-[#0c0c0f] border border-[#2a2a35] rounded-md px-3 py-2 flex-1", children: [
79896
+ 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: [
79779
79897
  rootFiles === null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] py-1 text-[#4a4a5a]", children: "Scanning..." }),
79780
79898
  rootFiles !== null && allFiles.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] py-1 text-[#4a4a5a]", children: "No gitignored files found in repo root" }),
79781
79899
  allFiles.map((file) => {
79782
- const checked = filesToCopy.includes(file);
79900
+ const entry = byPath.get(file);
79901
+ const checked = !!entry;
79783
79902
  const isManual = !discoveredSet.has(file);
79784
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 cursor-pointer group", children: [
79785
- /* @__PURE__ */ jsxRuntimeExports.jsx(CustomCheckbox, { checked, onChange: (v2) => toggle(file, v2) }),
79786
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[12px] font-mono text-[#c0c0d0]", children: file }),
79787
- isManual && /* @__PURE__ */ jsxRuntimeExports.jsx(
79788
- "button",
79789
- {
79790
- onClick: (e) => {
79791
- e.preventDefault();
79792
- onChange(filesToCopy.filter((f) => f !== file));
79793
- },
79794
- className: "opacity-0 group-hover:opacity-100 transition-opacity text-[#60607a]",
79795
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 11 })
79796
- }
79797
- )
79798
- ] }, file);
79903
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
79904
+ "label",
79905
+ {
79906
+ className: "flex items-center gap-2 cursor-pointer group -mx-2 px-2 py-1 rounded transition-colors hover:bg-[#17171f]",
79907
+ children: [
79908
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 w-4 flex justify-center", children: entry && /* @__PURE__ */ jsxRuntimeExports.jsx(
79909
+ "button",
79910
+ {
79911
+ type: "button",
79912
+ title: entry.symlink ? "Symlinked (shared from repo). Click to copy instead." : "Copied into worktree. Click to symlink (share from repo, e.g. node_modules).",
79913
+ onClick: (e) => {
79914
+ e.preventDefault();
79915
+ setSymlink(file, !entry.symlink);
79916
+ },
79917
+ className: `transition-colors ${entry.symlink ? "text-[#7aa2f7]" : "text-[#45455a] hover:text-[#9a9ab0]"}`,
79918
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { size: 12 })
79919
+ }
79920
+ ) }),
79921
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CustomCheckbox, { checked, onChange: (v2) => toggle(file, v2) }),
79922
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[12px] font-mono text-[#c0c0d0]", children: file }),
79923
+ isManual && /* @__PURE__ */ jsxRuntimeExports.jsx(
79924
+ "button",
79925
+ {
79926
+ type: "button",
79927
+ onClick: (e) => {
79928
+ e.preventDefault();
79929
+ onChange(filesToCopy.filter((f) => f.path !== file));
79930
+ },
79931
+ className: "opacity-0 group-hover:opacity-100 transition-opacity text-[#60607a]",
79932
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 11 })
79933
+ }
79934
+ )
79935
+ ]
79936
+ },
79937
+ file
79938
+ );
79799
79939
  }),
79800
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 pt-1", children: [
79940
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 pt-1.5", children: [
79941
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 w-4" }),
79801
79942
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-4 h-4 border border-[#2a2a35] rounded-[3px]" }),
79802
79943
  /* @__PURE__ */ jsxRuntimeExports.jsx(
79803
79944
  "input",
@@ -81797,6 +81938,7 @@ const PROJECT_NAV = [
81797
81938
  ];
81798
81939
  const GLOBAL_NAV = [
81799
81940
  { id: "runtime", label: "Runtime Config", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { size: 15 }) },
81941
+ { id: "notifications", label: "Notifications", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Bell, { size: 15 }) },
81800
81942
  { id: "tunnel", label: "Tunnel", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { size: 15 }) },
81801
81943
  { id: "slack", label: "Slack", icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Slack, { size: 15 }) }
81802
81944
  ];
@@ -81930,7 +82072,7 @@ function SettingsPage() {
81930
82072
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-4" })
81931
82073
  ] })
81932
82074
  ] }),
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 }) })
82075
+ /* @__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
82076
  ] });
81935
82077
  }
81936
82078
  function NavItem({
@@ -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
  }
@@ -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-BBh0-Z42.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-Do7b5IJu.css">
8
+ <script type="module" crossorigin src="/assets/index-BDiIsuhZ.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.5.1",
3
+ "version": "0.7.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",