@cjvana/claude-auto 0.1.2 → 0.2.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.
Files changed (121) hide show
  1. package/dist/{chunk-24PS2XSV.js → chunk-27NCPABY.js} +4 -67
  2. package/dist/chunk-27NCPABY.js.map +1 -0
  3. package/dist/chunk-2CLZERVS.js +1703 -0
  4. package/dist/chunk-2CLZERVS.js.map +1 -0
  5. package/dist/{chunk-2D5E23XA.js → chunk-2G2KQJ2Q.js} +3 -3
  6. package/dist/chunk-2G2KQJ2Q.js.map +1 -0
  7. package/dist/{chunk-BY5YEOVG.js → chunk-3VNP3RVY.js} +2 -2
  8. package/dist/{chunk-M53MPY3U.js → chunk-4VUPUHND.js} +3 -3
  9. package/dist/chunk-76PDFLLR.js +1744 -0
  10. package/dist/chunk-76PDFLLR.js.map +1 -0
  11. package/dist/{chunk-WYU476R2.js → chunk-CFD6OA3U.js} +6 -1
  12. package/dist/chunk-CFD6OA3U.js.map +1 -0
  13. package/dist/{chunk-PFU5YLRH.js → chunk-DE5AVSQ4.js} +3 -3
  14. package/dist/{chunk-S6W4SURF.js → chunk-ETRY7XUT.js} +4 -4
  15. package/dist/{chunk-W2HBRERV.js → chunk-FXPJY6FJ.js} +3 -3
  16. package/dist/chunk-I4RM5O56.js +75 -0
  17. package/dist/chunk-I4RM5O56.js.map +1 -0
  18. package/dist/{chunk-QLRCFKLU.js → chunk-JKZUC53H.js} +4 -4
  19. package/dist/{chunk-SZRIZBWI.js → chunk-LW7XOWL2.js} +3 -3
  20. package/dist/{chunk-U35GRLBD.js → chunk-O3NXIT5A.js} +6 -1
  21. package/dist/chunk-O3NXIT5A.js.map +1 -0
  22. package/dist/{chunk-MI7OZ5XD.js → chunk-PDL7SDI3.js} +2 -2
  23. package/dist/{chunk-HF7PGQI3.js → chunk-QJIXXBMI.js} +2 -2
  24. package/dist/{chunk-LBH6SLHH.js → chunk-RWA7YWPE.js} +4 -4
  25. package/dist/{chunk-TAGHPCFT.js → chunk-SZA5UZBI.js} +3 -3
  26. package/dist/{chunk-QQTIJN3S.js → chunk-TKUHYD6T.js} +6 -1
  27. package/dist/chunk-TKUHYD6T.js.map +1 -0
  28. package/dist/{chunk-DVZC42TL.js → chunk-XCXFSLSS.js} +4 -4
  29. package/dist/{chunk-NB46PEG2.js → chunk-Y7ACM23C.js} +3 -3
  30. package/dist/{chunk-NB46PEG2.js.map → chunk-Y7ACM23C.js.map} +1 -1
  31. package/dist/claude-auto-run.js +9 -1683
  32. package/dist/claude-auto-run.js.map +1 -1
  33. package/dist/claude-auto.js +14 -8
  34. package/dist/claude-auto.js.map +1 -1
  35. package/dist/{create-U5WYKTD4.js → create-DC63FYWP.js} +4 -4
  36. package/dist/{create-T3BDDS6G.js → create-Z2OVC5JK.js} +5 -4
  37. package/dist/{crontab-CDMC2FDT.js → crontab-OMTYKJC7.js} +6 -1
  38. package/dist/crontab-OMTYKJC7.js.map +1 -0
  39. package/dist/{crontab-MAJ52FOK.js → crontab-YKFQ3AQA.js} +6 -1
  40. package/dist/crontab-YKFQ3AQA.js.map +1 -0
  41. package/dist/{crontab-PNEWANLW.js → crontab-ZZHAZ5OJ.js} +2 -2
  42. package/dist/{edit-77E3ZQHM.js → edit-O5T3UXM4.js} +4 -4
  43. package/dist/{edit-RVPRAAQ2.js → edit-ZGUTPFHQ.js} +5 -4
  44. package/dist/index.d.ts +319 -615
  45. package/dist/index.js +78 -1682
  46. package/dist/index.js.map +1 -1
  47. package/dist/{launchd-HNZIWLNC.js → launchd-5COTJSRK.js} +6 -1
  48. package/dist/launchd-5COTJSRK.js.map +1 -0
  49. package/dist/{launchd-7F27BIZB.js → launchd-6NKJDIYC.js} +6 -1
  50. package/dist/launchd-6NKJDIYC.js.map +1 -0
  51. package/dist/{launchd-LZGDP7BM.js → launchd-MZNYUY3Y.js} +2 -2
  52. package/dist/{list-OIGERGYJ.js → list-55ABTJVW.js} +4 -3
  53. package/dist/{list-T35RSQVU.js → list-AS7F4LFU.js} +3 -3
  54. package/dist/{pause-OJNUYBCJ.js → pause-72P4ERIU.js} +4 -4
  55. package/dist/{pause-JB42JGTB.js → pause-JCPZFBVZ.js} +3 -3
  56. package/dist/pause-TAS6BCYR.js +13 -0
  57. package/dist/{remove-UASXZCOR.js → remove-RMTSKUYN.js} +4 -4
  58. package/dist/remove-VBIVYREY.js +13 -0
  59. package/dist/{report-IYGK5HTC.js → report-53DC5DL2.js} +4 -3
  60. package/dist/{report-CHAJH2SA.js → report-6O43ICNG.js} +3 -3
  61. package/dist/{resume-3ATNZP6D.js → resume-3TB76AUU.js} +5 -4
  62. package/dist/{resume-JVTR7OEX.js → resume-4XSHJ4SN.js} +4 -4
  63. package/dist/{resume-6WVGU6XW.js → resume-A2PWKRLE.js} +3 -3
  64. package/dist/run-CXRPDX2S.js +34 -0
  65. package/dist/run-CXRPDX2S.js.map +1 -0
  66. package/dist/run-H3IF4QXQ.js +34 -0
  67. package/dist/run-H3IF4QXQ.js.map +1 -0
  68. package/dist/{schtasks-4V2IFD3A.js → schtasks-5IZCEIPB.js} +6 -1
  69. package/dist/schtasks-5IZCEIPB.js.map +1 -0
  70. package/dist/{schtasks-JGEPEKQS.js → schtasks-6GQ27GI2.js} +6 -1
  71. package/dist/schtasks-6GQ27GI2.js.map +1 -0
  72. package/dist/{schtasks-2EQAD3ES.js → schtasks-ZJ5NAIU6.js} +2 -2
  73. package/dist/{tui-6LOGPILA.js → tui-NVOPC5SD.js} +5 -5
  74. package/dist/{tui-2DUPCX3Q.js → tui-VKT4UBXQ.js} +4 -3
  75. package/package.json +1 -1
  76. package/dist/chunk-24PS2XSV.js.map +0 -1
  77. package/dist/chunk-2D5E23XA.js.map +0 -1
  78. package/dist/chunk-QQTIJN3S.js.map +0 -1
  79. package/dist/chunk-U35GRLBD.js.map +0 -1
  80. package/dist/chunk-WYU476R2.js.map +0 -1
  81. package/dist/crontab-CDMC2FDT.js.map +0 -1
  82. package/dist/crontab-MAJ52FOK.js.map +0 -1
  83. package/dist/launchd-7F27BIZB.js.map +0 -1
  84. package/dist/launchd-HNZIWLNC.js.map +0 -1
  85. package/dist/pause-2YOLFMAR.js +0 -12
  86. package/dist/remove-RXYKFYBI.js +0 -12
  87. package/dist/schtasks-4V2IFD3A.js.map +0 -1
  88. package/dist/schtasks-JGEPEKQS.js.map +0 -1
  89. /package/dist/{chunk-BY5YEOVG.js.map → chunk-3VNP3RVY.js.map} +0 -0
  90. /package/dist/{chunk-M53MPY3U.js.map → chunk-4VUPUHND.js.map} +0 -0
  91. /package/dist/{chunk-PFU5YLRH.js.map → chunk-DE5AVSQ4.js.map} +0 -0
  92. /package/dist/{chunk-DVZC42TL.js.map → chunk-ETRY7XUT.js.map} +0 -0
  93. /package/dist/{chunk-W2HBRERV.js.map → chunk-FXPJY6FJ.js.map} +0 -0
  94. /package/dist/{chunk-QLRCFKLU.js.map → chunk-JKZUC53H.js.map} +0 -0
  95. /package/dist/{chunk-SZRIZBWI.js.map → chunk-LW7XOWL2.js.map} +0 -0
  96. /package/dist/{chunk-MI7OZ5XD.js.map → chunk-PDL7SDI3.js.map} +0 -0
  97. /package/dist/{chunk-HF7PGQI3.js.map → chunk-QJIXXBMI.js.map} +0 -0
  98. /package/dist/{chunk-LBH6SLHH.js.map → chunk-RWA7YWPE.js.map} +0 -0
  99. /package/dist/{chunk-TAGHPCFT.js.map → chunk-SZA5UZBI.js.map} +0 -0
  100. /package/dist/{chunk-S6W4SURF.js.map → chunk-XCXFSLSS.js.map} +0 -0
  101. /package/dist/{create-U5WYKTD4.js.map → create-DC63FYWP.js.map} +0 -0
  102. /package/dist/{create-T3BDDS6G.js.map → create-Z2OVC5JK.js.map} +0 -0
  103. /package/dist/{crontab-PNEWANLW.js.map → crontab-ZZHAZ5OJ.js.map} +0 -0
  104. /package/dist/{edit-77E3ZQHM.js.map → edit-O5T3UXM4.js.map} +0 -0
  105. /package/dist/{edit-RVPRAAQ2.js.map → edit-ZGUTPFHQ.js.map} +0 -0
  106. /package/dist/{launchd-LZGDP7BM.js.map → launchd-MZNYUY3Y.js.map} +0 -0
  107. /package/dist/{list-OIGERGYJ.js.map → list-55ABTJVW.js.map} +0 -0
  108. /package/dist/{list-T35RSQVU.js.map → list-AS7F4LFU.js.map} +0 -0
  109. /package/dist/{pause-OJNUYBCJ.js.map → pause-72P4ERIU.js.map} +0 -0
  110. /package/dist/{pause-JB42JGTB.js.map → pause-JCPZFBVZ.js.map} +0 -0
  111. /package/dist/{pause-2YOLFMAR.js.map → pause-TAS6BCYR.js.map} +0 -0
  112. /package/dist/{remove-UASXZCOR.js.map → remove-RMTSKUYN.js.map} +0 -0
  113. /package/dist/{remove-RXYKFYBI.js.map → remove-VBIVYREY.js.map} +0 -0
  114. /package/dist/{report-IYGK5HTC.js.map → report-53DC5DL2.js.map} +0 -0
  115. /package/dist/{report-CHAJH2SA.js.map → report-6O43ICNG.js.map} +0 -0
  116. /package/dist/{resume-3ATNZP6D.js.map → resume-3TB76AUU.js.map} +0 -0
  117. /package/dist/{resume-JVTR7OEX.js.map → resume-4XSHJ4SN.js.map} +0 -0
  118. /package/dist/{resume-6WVGU6XW.js.map → resume-A2PWKRLE.js.map} +0 -0
  119. /package/dist/{schtasks-2EQAD3ES.js.map → schtasks-ZJ5NAIU6.js.map} +0 -0
  120. /package/dist/{tui-6LOGPILA.js.map → tui-NVOPC5SD.js.map} +0 -0
  121. /package/dist/{tui-2DUPCX3Q.js.map → tui-VKT4UBXQ.js.map} +0 -0
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-D4MBOIYQ.js";
12
12
  import {
13
13
  listJobs
14
- } from "./chunk-24PS2XSV.js";
14
+ } from "./chunk-3VNP3RVY.js";
15
15
 
16
16
  // src/cli/commands/list.ts
17
17
  function truncatePath(fullPath, segments = 2) {
@@ -66,4 +66,4 @@ async function listCommand(args) {
66
66
  export {
67
67
  listCommand
68
68
  };
69
- //# sourceMappingURL=chunk-HF7PGQI3.js.map
69
+ //# sourceMappingURL=chunk-QJIXXBMI.js.map
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-D4MBOIYQ.js";
10
10
  import {
11
11
  listJobs
12
- } from "./chunk-24PS2XSV.js";
12
+ } from "./chunk-3VNP3RVY.js";
13
13
 
14
14
  // src/tui/index.tsx
15
15
  import "react";
@@ -498,11 +498,11 @@ function App() {
498
498
  if (!job) return;
499
499
  try {
500
500
  if (job.enabled) {
501
- const { pauseCommand } = await import("./pause-2YOLFMAR.js");
501
+ const { pauseCommand } = await import("./pause-TAS6BCYR.js");
502
502
  await pauseCommand({ jobId });
503
503
  setStatusMessage(`Paused: ${job.name}`);
504
504
  } else {
505
- const { resumeCommand } = await import("./resume-3ATNZP6D.js");
505
+ const { resumeCommand } = await import("./resume-3TB76AUU.js");
506
506
  await resumeCommand({ jobId });
507
507
  setStatusMessage(`Resumed: ${job.name}`);
508
508
  }
@@ -540,4 +540,4 @@ async function launchDashboard() {
540
540
  export {
541
541
  launchDashboard
542
542
  };
543
- //# sourceMappingURL=chunk-LBH6SLHH.js.map
543
+ //# sourceMappingURL=chunk-RWA7YWPE.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createScheduler
3
- } from "./chunk-QLRCFKLU.js";
3
+ } from "./chunk-JKZUC53H.js";
4
4
  import {
5
5
  getNextRuns
6
6
  } from "./chunk-D4MBOIYQ.js";
7
7
  import {
8
8
  readJob,
9
9
  updateJob
10
- } from "./chunk-24PS2XSV.js";
10
+ } from "./chunk-3VNP3RVY.js";
11
11
 
12
12
  // src/cli/commands/resume.ts
13
13
  async function resumeCommand(args) {
@@ -44,4 +44,4 @@ async function resumeCommand(args) {
44
44
  export {
45
45
  resumeCommand
46
46
  };
47
- //# sourceMappingURL=chunk-TAGHPCFT.js.map
47
+ //# sourceMappingURL=chunk-SZA5UZBI.js.map
@@ -9,6 +9,7 @@ import {
9
9
  } from "./chunk-YMO45Z6G.js";
10
10
 
11
11
  // src/platform/launchd.ts
12
+ import { existsSync } from "fs";
12
13
  import { access, readdir, readFile, unlink, writeFile } from "fs/promises";
13
14
  import { homedir } from "os";
14
15
  import { dirname, join } from "path";
@@ -25,6 +26,10 @@ function getUid() {
25
26
  function getRunnerPath() {
26
27
  try {
27
28
  const currentDir = dirname(fileURLToPath(import.meta.url));
29
+ const siblingPath = join(currentDir, "claude-auto-run.js");
30
+ if (existsSync(siblingPath)) {
31
+ return siblingPath;
32
+ }
28
33
  return join(currentDir, "..", "..", "dist", "claude-auto-run.js");
29
34
  } catch {
30
35
  return join(process.cwd(), "dist", "claude-auto-run.js");
@@ -164,4 +169,4 @@ export {
164
169
  cronToCalendarIntervals,
165
170
  LaunchdScheduler
166
171
  };
167
- //# sourceMappingURL=chunk-QQTIJN3S.js.map
172
+ //# sourceMappingURL=chunk-TKUHYD6T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/platform/launchd.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { access, readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CronExpressionParser } from \"cron-parser\";\nimport plist from \"plist\";\nimport type { JobConfig } from \"../core/types.js\";\nimport { SchedulerError } from \"../util/errors.js\";\nimport { execCommand } from \"../util/exec.js\";\nimport { paths } from \"../util/paths.js\";\nimport type { RegisteredJob, Scheduler } from \"./scheduler.js\";\n\nexport interface CalendarInterval {\n\tMonth?: number;\n\tDay?: number;\n\tWeekday?: number;\n\tHour?: number;\n\tMinute?: number;\n}\n\nconst LABEL_PREFIX = \"com.claude-auto.\";\n\nfunction getLabel(jobId: string): string {\n\treturn `${LABEL_PREFIX}${jobId}`;\n}\n\nfunction getUid(): number {\n\treturn process.getuid?.() ?? 501;\n}\n\n/**\n * Resolve the runner script path.\n * When bundled by tsup, this file lives in dist/ alongside claude-auto-run.js.\n * When running from source (src/platform/), navigate up to project root.\n */\nfunction getRunnerPath(): string {\n\ttry {\n\t\tconst currentDir = dirname(fileURLToPath(import.meta.url));\n\t\t// Bundled: runner is a sibling in the same dist/ directory\n\t\tconst siblingPath = join(currentDir, \"claude-auto-run.js\");\n\t\tif (existsSync(siblingPath)) {\n\t\t\treturn siblingPath;\n\t\t}\n\t\t// Source: navigate from src/platform/ up to project root\n\t\treturn join(currentDir, \"..\", \"..\", \"dist\", \"claude-auto-run.js\");\n\t} catch {\n\t\treturn join(process.cwd(), \"dist\", \"claude-auto-run.js\");\n\t}\n}\n\n/**\n * Convert a 5-field cron expression to launchd scheduling config.\n *\n * For high-frequency \"every N minutes\" patterns, returns { startInterval: seconds }.\n * For specific times, returns { calendarIntervals: CalendarInterval[] }.\n *\n * Throws if the expression would produce more than 50 calendar intervals.\n */\nexport function cronToCalendarIntervals(cronExpr: string): {\n\tcalendarIntervals?: CalendarInterval[];\n\tstartInterval?: number;\n} {\n\tconst interval = CronExpressionParser.parse(cronExpr);\n\tconst fields = interval.fields;\n\n\tconst minutes = [...fields.minute.values].map(Number);\n\tconst hours = [...fields.hour.values].map(Number);\n\tconst daysOfMonth = [...fields.dayOfMonth.values].map(Number);\n\tconst months = [...fields.month.values].map(Number);\n\tconst daysOfWeek = [...fields.dayOfWeek.values].map(Number);\n\n\tconst isAllHours = hours.length === 24;\n\tconst isAllDays = daysOfMonth.length === 31;\n\tconst isAllMonths = months.length === 12;\n\t// cron-parser returns 0-7 for dayOfWeek (8 values since 0 and 7 both mean Sunday)\n\tconst isAllDow = daysOfWeek.length === 8;\n\n\t// Detect \"every N minutes\" pattern: hours/days/months/dow all wildcard, minutes have even spacing\n\tif (isAllHours && isAllDays && isAllMonths && isAllDow && minutes.length > 1) {\n\t\tconst step = minutes[1] - minutes[0];\n\t\tconst isEvenStep = minutes.every((m, i) => i === 0 || m - minutes[i - 1] === step);\n\t\tif (isEvenStep) {\n\t\t\treturn { startInterval: step * 60 };\n\t\t}\n\t}\n\n\t// Build calendar interval combinations\n\tconst intervals: CalendarInterval[] = [];\n\tconst effectiveHours = isAllHours ? [undefined] : hours;\n\t// Filter out duplicate Sunday (7) -- launchd uses 0 for Sunday\n\tconst effectiveDow = isAllDow ? [undefined] : daysOfWeek.filter((d) => d <= 6);\n\tconst effectiveDom = isAllDays ? [undefined] : daysOfMonth;\n\n\tfor (const minute of minutes) {\n\t\tfor (const hour of effectiveHours) {\n\t\t\tfor (const dow of effectiveDow) {\n\t\t\t\tfor (const dom of effectiveDom) {\n\t\t\t\t\tconst entry: CalendarInterval = { Minute: minute };\n\t\t\t\t\tif (hour !== undefined) entry.Hour = hour;\n\t\t\t\t\tif (dow !== undefined) entry.Weekday = dow;\n\t\t\t\t\tif (dom !== undefined) entry.Day = dom;\n\t\t\t\t\tintervals.push(entry);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intervals.length > 50) {\n\t\tthrow new Error(\n\t\t\t`Cron expression \"${cronExpr}\" would produce ${intervals.length} calendar intervals. ` +\n\t\t\t\t\"launchd StartCalendarInterval is not efficient for complex schedules. \" +\n\t\t\t\t\"Simplify the schedule or use a simpler pattern.\",\n\t\t);\n\t}\n\n\treturn { calendarIntervals: intervals };\n}\n\n/**\n * LaunchdScheduler implements the Scheduler interface for macOS.\n * Uses plist files in ~/Library/LaunchAgents/ and modern launchctl bootstrap/bootout.\n */\nexport class LaunchdScheduler implements Scheduler {\n\tasync register(job: JobConfig, env?: Record<string, string>): Promise<void> {\n\t\tconst registered = await this.isRegistered(job.id);\n\t\tif (registered) {\n\t\t\tthrow new SchedulerError(\"launchd\", `Job \"${job.id}\" is already registered`);\n\t\t}\n\n\t\tconst scheduling = cronToCalendarIntervals(job.schedule.cron);\n\t\tconst runnerPath = getRunnerPath();\n\t\tconst logPath = `${paths.jobLogs(job.id)}/launchd.log`;\n\t\tconst plistPath = paths.plistPath(job.id);\n\n\t\tconst obj: Record<string, unknown> = {\n\t\t\tLabel: getLabel(job.id),\n\t\t\tProgramArguments: [process.execPath, runnerPath, \"--job-id\", job.id],\n\t\t\tStandardOutPath: logPath,\n\t\t\tStandardErrorPath: logPath,\n\t\t\tEnvironmentVariables: {\n\t\t\t\tPATH: env?.PATH ?? process.env.PATH ?? \"\",\n\t\t\t\tHOME: env?.HOME ?? homedir(),\n\t\t\t\t...(env\n\t\t\t\t\t? Object.fromEntries(Object.entries(env).filter(([k]) => k !== \"PATH\" && k !== \"HOME\"))\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t\tRunAtLoad: false,\n\t\t\tKeepAlive: false,\n\t\t};\n\n\t\tif (scheduling.startInterval !== undefined) {\n\t\t\tobj.StartInterval = scheduling.startInterval;\n\t\t} else if (scheduling.calendarIntervals) {\n\t\t\tobj.StartCalendarInterval =\n\t\t\t\tscheduling.calendarIntervals.length === 1\n\t\t\t\t\t? scheduling.calendarIntervals[0]\n\t\t\t\t\t: scheduling.calendarIntervals;\n\t\t}\n\n\t\tconst xml = plist.build(obj as unknown as plist.PlistValue);\n\t\tawait writeFile(plistPath, xml, \"utf-8\");\n\n\t\tconst uid = getUid();\n\t\tawait execCommand(\"launchctl\", [\"bootstrap\", `gui/${uid}`, plistPath]);\n\t}\n\n\tasync unregister(jobId: string): Promise<void> {\n\t\tconst uid = getUid();\n\t\tconst label = getLabel(jobId);\n\t\tconst plistPath = paths.plistPath(jobId);\n\n\t\ttry {\n\t\t\tawait execCommand(\"launchctl\", [\"bootout\", `gui/${uid}/${label}`]);\n\t\t} catch {\n\t\t\t// Service may already be unloaded -- continue to delete plist\n\t\t}\n\n\t\ttry {\n\t\t\tawait unlink(plistPath);\n\t\t} catch {\n\t\t\t// Plist may already be deleted\n\t\t}\n\t}\n\n\tasync isRegistered(jobId: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait access(paths.plistPath(jobId));\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync list(): Promise<RegisteredJob[]> {\n\t\tconst jobs: RegisteredJob[] = [];\n\t\ttry {\n\t\t\tconst files = await readdir(paths.plistDir);\n\t\t\tconst plistFiles = files.filter((f) => f.startsWith(LABEL_PREFIX) && f.endsWith(\".plist\"));\n\n\t\t\tfor (const file of plistFiles) {\n\t\t\t\ttry {\n\t\t\t\t\tconst filePath = join(paths.plistDir, file);\n\t\t\t\t\tconst content = await readFile(filePath, \"utf-8\");\n\t\t\t\t\tconst parsed = plist.parse(content) as Record<string, unknown>;\n\t\t\t\t\tconst label = parsed.Label as string;\n\t\t\t\t\tconst jobId = label.replace(LABEL_PREFIX, \"\");\n\t\t\t\t\tconst progArgs = (parsed.ProgramArguments as string[]) ?? [];\n\n\t\t\t\t\tlet schedule = \"\";\n\t\t\t\t\tif (parsed.StartInterval) {\n\t\t\t\t\t\tschedule = `every ${parsed.StartInterval}s`;\n\t\t\t\t\t} else if (parsed.StartCalendarInterval) {\n\t\t\t\t\t\tschedule = \"calendar\";\n\t\t\t\t\t}\n\n\t\t\t\t\tjobs.push({\n\t\t\t\t\t\tjobId,\n\t\t\t\t\t\tschedule,\n\t\t\t\t\t\tcommand: progArgs.join(\" \"),\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\t// Skip malformed plists\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Directory may not exist\n\t\t}\n\t\treturn jobs;\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -16,18 +16,18 @@ function detectPlatform() {
16
16
  async function createScheduler() {
17
17
  const platform = detectPlatform();
18
18
  if (platform === "linux") {
19
- const { CrontabScheduler } = await import("./crontab-CDMC2FDT.js");
19
+ const { CrontabScheduler } = await import("./crontab-OMTYKJC7.js");
20
20
  return new CrontabScheduler();
21
21
  }
22
22
  if (platform === "win32") {
23
- const { SchtasksScheduler } = await import("./schtasks-JGEPEKQS.js");
23
+ const { SchtasksScheduler } = await import("./schtasks-6GQ27GI2.js");
24
24
  return new SchtasksScheduler();
25
25
  }
26
- const { LaunchdScheduler } = await import("./launchd-HNZIWLNC.js");
26
+ const { LaunchdScheduler } = await import("./launchd-5COTJSRK.js");
27
27
  return new LaunchdScheduler();
28
28
  }
29
29
 
30
30
  export {
31
31
  createScheduler
32
32
  };
33
- //# sourceMappingURL=chunk-DVZC42TL.js.map
33
+ //# sourceMappingURL=chunk-XCXFSLSS.js.map
@@ -54,8 +54,8 @@ var JobConfigSchema = z.object({
54
54
  focus: z.array(z.enum(["open-issues", "bug-discovery", "features", "documentation"])).default(["open-issues", "bug-discovery"]),
55
55
  systemPrompt: z.string().optional(),
56
56
  guardrails: z.object({
57
- maxTurns: z.number().int().positive().default(50),
58
- maxBudgetUsd: z.number().positive().default(5),
57
+ maxTurns: z.number().int().nonnegative().default(50),
58
+ maxBudgetUsd: z.number().nonnegative().default(5),
59
59
  noNewDependencies: z.boolean().default(false),
60
60
  noArchitectureChanges: z.boolean().default(false),
61
61
  bugFixOnly: z.boolean().default(false),
@@ -174,4 +174,4 @@ export {
174
174
  updateJob,
175
175
  listJobs
176
176
  };
177
- //# sourceMappingURL=chunk-NB46PEG2.js.map
177
+ //# sourceMappingURL=chunk-Y7ACM23C.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/job-manager.ts","../src/util/fs.ts","../src/core/config.ts","../src/core/types.ts"],"sourcesContent":["import { readdir, readFile, rm } from \"node:fs/promises\";\nimport { nanoid } from \"nanoid\";\nimport { parseDocument } from \"yaml\";\nimport { z } from \"zod\";\nimport { writeFileSafe } from \"../util/fs.js\";\nimport { paths } from \"../util/paths.js\";\nimport { loadJobConfig, saveJobConfig } from \"./config.js\";\nimport { type JobConfig, JobConfigSchema } from \"./types.js\";\n\n/**\n * Create a new job with a generated nanoid(12) identifier.\n * Writes the config to disk and returns the complete JobConfig.\n */\nexport async function createJob(input: Omit<JobConfig, \"id\">): Promise<JobConfig> {\n\tconst id = nanoid(12);\n\tconst config: JobConfig = { ...input, id };\n\tawait saveJobConfig(paths.jobConfig(id), config);\n\treturn config;\n}\n\n/**\n * Read and validate a job config by its ID.\n * Throws if the job doesn't exist (ENOENT) or config is invalid.\n */\nexport async function readJob(jobId: string): Promise<JobConfig> {\n\treturn loadJobConfig(paths.jobConfig(jobId));\n}\n\n/**\n * Update specified fields of a job config while preserving YAML comments.\n * Validates the result before writing. Rejects invalid updates.\n */\nexport async function updateJob(\n\tjobId: string,\n\tupdates: Partial<Omit<JobConfig, \"id\">>,\n): Promise<JobConfig> {\n\tconst configPath = paths.jobConfig(jobId);\n\tconst content = await readFile(configPath, \"utf-8\");\n\tconst doc = parseDocument(content);\n\n\t// Apply each update key to the Document, preserving comments\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tif (key === \"id\") continue; // Never update the id\n\t\tdoc.set(key, doc.createNode(value));\n\t}\n\n\t// Validate the modified document\n\tconst raw = doc.toJS();\n\tconst result = JobConfigSchema.safeParse(raw);\n\n\tif (!result.success) {\n\t\tthrow new Error(`Invalid config after update: ${z.prettifyError(result.error)}`);\n\t}\n\n\tawait writeFileSafe(configPath, doc.toString({ indent: 2 }));\n\treturn result.data;\n}\n\n/**\n * Delete a job and its entire directory.\n * Idempotent: does not throw if the job doesn't exist.\n */\nexport async function deleteJob(jobId: string): Promise<void> {\n\tawait rm(paths.jobDir(jobId), { recursive: true, force: true });\n}\n\n/**\n * List all valid job configs.\n * Skips invalid directories/configs. Returns empty array if no jobs directory exists.\n */\nexport async function listJobs(): Promise<JobConfig[]> {\n\tlet entries: import(\"node:fs\").Dirent<string>[];\n\ttry {\n\t\tentries = await readdir(paths.jobs, { withFileTypes: true, encoding: \"utf-8\" });\n\t} catch (error: unknown) {\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t\"code\" in error &&\n\t\t\t(error as NodeJS.ErrnoException).code === \"ENOENT\"\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tthrow error;\n\t}\n\n\tconst results: JobConfig[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.isDirectory()) continue;\n\t\ttry {\n\t\t\tconst config = await readJob(entry.name);\n\t\t\tresults.push(config);\n\t\t} catch {\n\t\t\t// Skip invalid directories/configs\n\t\t}\n\t}\n\n\treturn results;\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport writeFileAtomic from \"write-file-atomic\";\n\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait writeFileAtomic(filePath, content, \"utf-8\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport { Document, parseDocument } from \"yaml\";\nimport { z } from \"zod\";\nimport { ConfigParseError, ConfigValidationError } from \"../util/errors.js\";\nimport { writeFileSafe } from \"../util/fs.js\";\nimport { type JobConfig, JobConfigSchema } from \"./types.js\";\n\n/**\n * Read a YAML config file and return the parsed Document (preserves comments).\n * Throws ConfigParseError if the YAML syntax is invalid.\n */\nexport async function readConfigDocument(filePath: string): Promise<Document> {\n\tconst content = await readFile(filePath, \"utf-8\");\n\tconst doc = parseDocument(content);\n\n\tif (doc.errors.length > 0) {\n\t\tthrow new ConfigParseError(\n\t\t\tfilePath,\n\t\t\tdoc.errors.map((e) => ({ message: e.message })),\n\t\t);\n\t}\n\n\treturn doc;\n}\n\n/**\n * Validate a parsed YAML Document against the JobConfigSchema.\n * Returns the validated and typed JobConfig.\n * Throws ConfigValidationError if validation fails.\n */\nexport function validateConfig(filePath: string, doc: Document): JobConfig {\n\tconst raw = doc.toJS();\n\tconst result = JobConfigSchema.safeParse(raw);\n\n\tif (!result.success) {\n\t\tthrow new ConfigValidationError(filePath, z.prettifyError(result.error));\n\t}\n\n\treturn result.data;\n}\n\n/**\n * Load a job config from a YAML file, validating it against the schema.\n * Combines readConfigDocument + validateConfig.\n */\nexport async function loadJobConfig(filePath: string): Promise<JobConfig> {\n\tconst doc = await readConfigDocument(filePath);\n\treturn validateConfig(filePath, doc);\n}\n\n/**\n * Save a JobConfig to a YAML file using atomic writes.\n * Multiline systemPrompt values use YAML block literal style (|).\n */\nexport async function saveJobConfig(filePath: string, config: JobConfig): Promise<void> {\n\tconst doc = new Document(config);\n\n\t// For multiline systemPrompt, force YAML block literal style (|)\n\tif (config.systemPrompt?.includes(\"\\n\")) {\n\t\tconst node = doc.getIn([\"systemPrompt\"]);\n\t\tif (node && typeof node === \"object\" && \"type\" in node) {\n\t\t\t(node as { type: string }).type = \"BLOCK_LITERAL\";\n\t\t}\n\t}\n\n\tconst yamlContent = doc.toString({ indent: 2 });\n\tawait writeFileSafe(filePath, yamlContent);\n}\n\n/**\n * Update a field in a YAML Document by path, preserving comments.\n */\nexport function updateConfigField(doc: Document, path: (string | number)[], value: unknown): void {\n\tdoc.setIn(path, value);\n}\n\n/**\n * Write a YAML Document to a file using atomic writes, preserving comments.\n */\nexport async function writeConfigDocument(filePath: string, doc: Document): Promise<void> {\n\tconst yamlContent = doc.toString({ indent: 2 });\n\tawait writeFileSafe(filePath, yamlContent);\n}\n","import { z } from \"zod\";\n\nconst ModelSchema = z.union([\n\tz.enum([\"sonnet\", \"opus\", \"haiku\", \"opusplan\", \"default\"]),\n\tz.string().regex(/^claude-/),\n]);\n\nexport const PipelineConfigSchema = z.object({\n\tenabled: z.boolean().default(false),\n\tplanModel: ModelSchema.default(\"haiku\"),\n\timplementModel: ModelSchema.default(\"opus\"),\n\treviewModel: ModelSchema.default(\"sonnet\"),\n\tmaxReviewRounds: z.number().int().positive().default(1),\n});\n\nexport type PipelineConfig = z.infer<typeof PipelineConfigSchema>;\n\nexport const JobConfigSchema = z.object({\n\tid: z.string().min(1),\n\tname: z.string().min(1),\n\trepo: z.object({\n\t\tpath: z.string().min(1),\n\t\tbranch: z.string().default(\"main\"),\n\t\tremote: z.string().default(\"origin\"),\n\t}),\n\tschedule: z.object({\n\t\tcron: z.string().min(1),\n\t\ttimezone: z.string().default(\"UTC\"),\n\t}),\n\tfocus: z\n\t\t.array(z.enum([\"open-issues\", \"bug-discovery\", \"features\", \"documentation\"]))\n\t\t.default([\"open-issues\", \"bug-discovery\"]),\n\tsystemPrompt: z.string().optional(),\n\tguardrails: z\n\t\t.object({\n\t\t\tmaxTurns: z.number().int().positive().default(50),\n\t\t\tmaxBudgetUsd: z.number().positive().default(5.0),\n\t\t\tnoNewDependencies: z.boolean().default(false),\n\t\t\tnoArchitectureChanges: z.boolean().default(false),\n\t\t\tbugFixOnly: z.boolean().default(false),\n\t\t\trestrictToPaths: z.array(z.string()).optional(),\n\t\t})\n\t\t.default({\n\t\t\tmaxTurns: 50,\n\t\t\tmaxBudgetUsd: 5.0,\n\t\t\tnoNewDependencies: false,\n\t\t\tnoArchitectureChanges: false,\n\t\t\tbugFixOnly: false,\n\t\t}),\n\tnotifications: z\n\t\t.object({\n\t\t\tdiscord: z\n\t\t\t\t.object({\n\t\t\t\t\twebhookUrl: z.string().url(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tslack: z\n\t\t\t\t.object({\n\t\t\t\t\twebhookUrl: z.string().url(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\ttelegram: z\n\t\t\t\t.object({\n\t\t\t\t\tbotToken: z.string(),\n\t\t\t\t\tchatId: z.string(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.default({}),\n\tenabled: z.boolean().default(true),\n\tmodel: ModelSchema.optional(),\n\tbudget: z\n\t\t.object({\n\t\t\tdailyUsd: z.number().positive().optional(),\n\t\t\tweeklyUsd: z.number().positive().optional(),\n\t\t\tmonthlyUsd: z.number().positive().optional(),\n\t\t})\n\t\t.optional(),\n\tmaxFeedbackRounds: z.number().int().positive().default(3).optional(),\n\tpipeline: PipelineConfigSchema.optional(),\n});\n\nexport type JobConfig = z.infer<typeof JobConfigSchema>;\n\nexport interface ScheduleInfo {\n\tcron: string;\n\ttimezone: string;\n\thumanReadable: string;\n\tnextRuns: Date[];\n}\n"],"mappings":"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","names":["readFile","parseDocument","z","z","z","readFile","parseDocument","z"]}
1
+ {"version":3,"sources":["../src/core/job-manager.ts","../src/util/fs.ts","../src/core/config.ts","../src/core/types.ts"],"sourcesContent":["import { readdir, readFile, rm } from \"node:fs/promises\";\nimport { nanoid } from \"nanoid\";\nimport { parseDocument } from \"yaml\";\nimport { z } from \"zod\";\nimport { writeFileSafe } from \"../util/fs.js\";\nimport { paths } from \"../util/paths.js\";\nimport { loadJobConfig, saveJobConfig } from \"./config.js\";\nimport { type JobConfig, JobConfigSchema } from \"./types.js\";\n\n/**\n * Create a new job with a generated nanoid(12) identifier.\n * Writes the config to disk and returns the complete JobConfig.\n */\nexport async function createJob(input: Omit<JobConfig, \"id\">): Promise<JobConfig> {\n\tconst id = nanoid(12);\n\tconst config: JobConfig = { ...input, id };\n\tawait saveJobConfig(paths.jobConfig(id), config);\n\treturn config;\n}\n\n/**\n * Read and validate a job config by its ID.\n * Throws if the job doesn't exist (ENOENT) or config is invalid.\n */\nexport async function readJob(jobId: string): Promise<JobConfig> {\n\treturn loadJobConfig(paths.jobConfig(jobId));\n}\n\n/**\n * Update specified fields of a job config while preserving YAML comments.\n * Validates the result before writing. Rejects invalid updates.\n */\nexport async function updateJob(\n\tjobId: string,\n\tupdates: Partial<Omit<JobConfig, \"id\">>,\n): Promise<JobConfig> {\n\tconst configPath = paths.jobConfig(jobId);\n\tconst content = await readFile(configPath, \"utf-8\");\n\tconst doc = parseDocument(content);\n\n\t// Apply each update key to the Document, preserving comments\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tif (key === \"id\") continue; // Never update the id\n\t\tdoc.set(key, doc.createNode(value));\n\t}\n\n\t// Validate the modified document\n\tconst raw = doc.toJS();\n\tconst result = JobConfigSchema.safeParse(raw);\n\n\tif (!result.success) {\n\t\tthrow new Error(`Invalid config after update: ${z.prettifyError(result.error)}`);\n\t}\n\n\tawait writeFileSafe(configPath, doc.toString({ indent: 2 }));\n\treturn result.data;\n}\n\n/**\n * Delete a job and its entire directory.\n * Idempotent: does not throw if the job doesn't exist.\n */\nexport async function deleteJob(jobId: string): Promise<void> {\n\tawait rm(paths.jobDir(jobId), { recursive: true, force: true });\n}\n\n/**\n * List all valid job configs.\n * Skips invalid directories/configs. Returns empty array if no jobs directory exists.\n */\nexport async function listJobs(): Promise<JobConfig[]> {\n\tlet entries: import(\"node:fs\").Dirent<string>[];\n\ttry {\n\t\tentries = await readdir(paths.jobs, { withFileTypes: true, encoding: \"utf-8\" });\n\t} catch (error: unknown) {\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t\"code\" in error &&\n\t\t\t(error as NodeJS.ErrnoException).code === \"ENOENT\"\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tthrow error;\n\t}\n\n\tconst results: JobConfig[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.isDirectory()) continue;\n\t\ttry {\n\t\t\tconst config = await readJob(entry.name);\n\t\t\tresults.push(config);\n\t\t} catch {\n\t\t\t// Skip invalid directories/configs\n\t\t}\n\t}\n\n\treturn results;\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport writeFileAtomic from \"write-file-atomic\";\n\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait writeFileAtomic(filePath, content, \"utf-8\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport { Document, parseDocument } from \"yaml\";\nimport { z } from \"zod\";\nimport { ConfigParseError, ConfigValidationError } from \"../util/errors.js\";\nimport { writeFileSafe } from \"../util/fs.js\";\nimport { type JobConfig, JobConfigSchema } from \"./types.js\";\n\n/**\n * Read a YAML config file and return the parsed Document (preserves comments).\n * Throws ConfigParseError if the YAML syntax is invalid.\n */\nexport async function readConfigDocument(filePath: string): Promise<Document> {\n\tconst content = await readFile(filePath, \"utf-8\");\n\tconst doc = parseDocument(content);\n\n\tif (doc.errors.length > 0) {\n\t\tthrow new ConfigParseError(\n\t\t\tfilePath,\n\t\t\tdoc.errors.map((e) => ({ message: e.message })),\n\t\t);\n\t}\n\n\treturn doc;\n}\n\n/**\n * Validate a parsed YAML Document against the JobConfigSchema.\n * Returns the validated and typed JobConfig.\n * Throws ConfigValidationError if validation fails.\n */\nexport function validateConfig(filePath: string, doc: Document): JobConfig {\n\tconst raw = doc.toJS();\n\tconst result = JobConfigSchema.safeParse(raw);\n\n\tif (!result.success) {\n\t\tthrow new ConfigValidationError(filePath, z.prettifyError(result.error));\n\t}\n\n\treturn result.data;\n}\n\n/**\n * Load a job config from a YAML file, validating it against the schema.\n * Combines readConfigDocument + validateConfig.\n */\nexport async function loadJobConfig(filePath: string): Promise<JobConfig> {\n\tconst doc = await readConfigDocument(filePath);\n\treturn validateConfig(filePath, doc);\n}\n\n/**\n * Save a JobConfig to a YAML file using atomic writes.\n * Multiline systemPrompt values use YAML block literal style (|).\n */\nexport async function saveJobConfig(filePath: string, config: JobConfig): Promise<void> {\n\tconst doc = new Document(config);\n\n\t// For multiline systemPrompt, force YAML block literal style (|)\n\tif (config.systemPrompt?.includes(\"\\n\")) {\n\t\tconst node = doc.getIn([\"systemPrompt\"]);\n\t\tif (node && typeof node === \"object\" && \"type\" in node) {\n\t\t\t(node as { type: string }).type = \"BLOCK_LITERAL\";\n\t\t}\n\t}\n\n\tconst yamlContent = doc.toString({ indent: 2 });\n\tawait writeFileSafe(filePath, yamlContent);\n}\n\n/**\n * Update a field in a YAML Document by path, preserving comments.\n */\nexport function updateConfigField(doc: Document, path: (string | number)[], value: unknown): void {\n\tdoc.setIn(path, value);\n}\n\n/**\n * Write a YAML Document to a file using atomic writes, preserving comments.\n */\nexport async function writeConfigDocument(filePath: string, doc: Document): Promise<void> {\n\tconst yamlContent = doc.toString({ indent: 2 });\n\tawait writeFileSafe(filePath, yamlContent);\n}\n","import { z } from \"zod\";\n\nconst ModelSchema = z.union([\n\tz.enum([\"sonnet\", \"opus\", \"haiku\", \"opusplan\", \"default\"]),\n\tz.string().regex(/^claude-/),\n]);\n\nexport const PipelineConfigSchema = z.object({\n\tenabled: z.boolean().default(false),\n\tplanModel: ModelSchema.default(\"haiku\"),\n\timplementModel: ModelSchema.default(\"opus\"),\n\treviewModel: ModelSchema.default(\"sonnet\"),\n\tmaxReviewRounds: z.number().int().positive().default(1),\n});\n\nexport type PipelineConfig = z.infer<typeof PipelineConfigSchema>;\n\nexport const JobConfigSchema = z.object({\n\tid: z.string().min(1),\n\tname: z.string().min(1),\n\trepo: z.object({\n\t\tpath: z.string().min(1),\n\t\tbranch: z.string().default(\"main\"),\n\t\tremote: z.string().default(\"origin\"),\n\t}),\n\tschedule: z.object({\n\t\tcron: z.string().min(1),\n\t\ttimezone: z.string().default(\"UTC\"),\n\t}),\n\tfocus: z\n\t\t.array(z.enum([\"open-issues\", \"bug-discovery\", \"features\", \"documentation\"]))\n\t\t.default([\"open-issues\", \"bug-discovery\"]),\n\tsystemPrompt: z.string().optional(),\n\tguardrails: z\n\t\t.object({\n\t\t\tmaxTurns: z.number().int().nonnegative().default(50),\n\t\t\tmaxBudgetUsd: z.number().nonnegative().default(5.0),\n\t\t\tnoNewDependencies: z.boolean().default(false),\n\t\t\tnoArchitectureChanges: z.boolean().default(false),\n\t\t\tbugFixOnly: z.boolean().default(false),\n\t\t\trestrictToPaths: z.array(z.string()).optional(),\n\t\t})\n\t\t.default({\n\t\t\tmaxTurns: 50,\n\t\t\tmaxBudgetUsd: 5.0,\n\t\t\tnoNewDependencies: false,\n\t\t\tnoArchitectureChanges: false,\n\t\t\tbugFixOnly: false,\n\t\t}),\n\tnotifications: z\n\t\t.object({\n\t\t\tdiscord: z\n\t\t\t\t.object({\n\t\t\t\t\twebhookUrl: z.string().url(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tslack: z\n\t\t\t\t.object({\n\t\t\t\t\twebhookUrl: z.string().url(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\ttelegram: z\n\t\t\t\t.object({\n\t\t\t\t\tbotToken: z.string(),\n\t\t\t\t\tchatId: z.string(),\n\t\t\t\t\tonSuccess: z.boolean().default(true),\n\t\t\t\t\tonFailure: z.boolean().default(true),\n\t\t\t\t\tonNoChanges: z.boolean().default(false),\n\t\t\t\t\tonLocked: z.boolean().default(false),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.default({}),\n\tenabled: z.boolean().default(true),\n\tmodel: ModelSchema.optional(),\n\tbudget: z\n\t\t.object({\n\t\t\tdailyUsd: z.number().positive().optional(),\n\t\t\tweeklyUsd: z.number().positive().optional(),\n\t\t\tmonthlyUsd: z.number().positive().optional(),\n\t\t})\n\t\t.optional(),\n\tmaxFeedbackRounds: z.number().int().positive().default(3).optional(),\n\tpipeline: PipelineConfigSchema.optional(),\n});\n\nexport type JobConfig = z.infer<typeof JobConfigSchema>;\n\nexport interface ScheduleInfo {\n\tcron: string;\n\ttimezone: string;\n\thumanReadable: string;\n\tnextRuns: Date[];\n}\n"],"mappings":"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","names":["readFile","parseDocument","z","z","z","readFile","parseDocument","z"]}