@cjvana/claude-auto 0.1.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 (159) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +435 -0
  4. package/dist/check-repo-6C4QI2M2.js +33 -0
  5. package/dist/check-repo-6C4QI2M2.js.map +1 -0
  6. package/dist/check-repo-SXWFIVO5.js +8 -0
  7. package/dist/check-repo-SXWFIVO5.js.map +1 -0
  8. package/dist/chunk-24PS2XSV.js +203 -0
  9. package/dist/chunk-24PS2XSV.js.map +1 -0
  10. package/dist/chunk-2D5E23XA.js +129 -0
  11. package/dist/chunk-2D5E23XA.js.map +1 -0
  12. package/dist/chunk-3NEANSUS.js +26 -0
  13. package/dist/chunk-3NEANSUS.js.map +1 -0
  14. package/dist/chunk-4I5UIASZ.js +71 -0
  15. package/dist/chunk-4I5UIASZ.js.map +1 -0
  16. package/dist/chunk-5LGOK52J.js +38 -0
  17. package/dist/chunk-5LGOK52J.js.map +1 -0
  18. package/dist/chunk-6RYMWH5M.js +35 -0
  19. package/dist/chunk-6RYMWH5M.js.map +1 -0
  20. package/dist/chunk-A6XWZPLY.js +56 -0
  21. package/dist/chunk-A6XWZPLY.js.map +1 -0
  22. package/dist/chunk-AWLSYOVF.js +61 -0
  23. package/dist/chunk-AWLSYOVF.js.map +1 -0
  24. package/dist/chunk-BY5YEOVG.js +75 -0
  25. package/dist/chunk-BY5YEOVG.js.map +1 -0
  26. package/dist/chunk-D4MBOIYQ.js +46 -0
  27. package/dist/chunk-D4MBOIYQ.js.map +1 -0
  28. package/dist/chunk-DVZC42TL.js +33 -0
  29. package/dist/chunk-DVZC42TL.js.map +1 -0
  30. package/dist/chunk-E3XVLTT4.js +13 -0
  31. package/dist/chunk-E3XVLTT4.js.map +1 -0
  32. package/dist/chunk-GLW7T4QE.js +116 -0
  33. package/dist/chunk-GLW7T4QE.js.map +1 -0
  34. package/dist/chunk-H2MUDYMW.js +23 -0
  35. package/dist/chunk-H2MUDYMW.js.map +1 -0
  36. package/dist/chunk-HF7PGQI3.js +69 -0
  37. package/dist/chunk-HF7PGQI3.js.map +1 -0
  38. package/dist/chunk-LBH6SLHH.js +543 -0
  39. package/dist/chunk-LBH6SLHH.js.map +1 -0
  40. package/dist/chunk-M53MPY3U.js +115 -0
  41. package/dist/chunk-M53MPY3U.js.map +1 -0
  42. package/dist/chunk-MI7OZ5XD.js +146 -0
  43. package/dist/chunk-MI7OZ5XD.js.map +1 -0
  44. package/dist/chunk-NB46PEG2.js +177 -0
  45. package/dist/chunk-NB46PEG2.js.map +1 -0
  46. package/dist/chunk-ORBF5IW3.js +60 -0
  47. package/dist/chunk-ORBF5IW3.js.map +1 -0
  48. package/dist/chunk-PFU5YLRH.js +131 -0
  49. package/dist/chunk-PFU5YLRH.js.map +1 -0
  50. package/dist/chunk-QLRCFKLU.js +34 -0
  51. package/dist/chunk-QLRCFKLU.js.map +1 -0
  52. package/dist/chunk-QQTIJN3S.js +167 -0
  53. package/dist/chunk-QQTIJN3S.js.map +1 -0
  54. package/dist/chunk-QRYCNVLT.js +72 -0
  55. package/dist/chunk-QRYCNVLT.js.map +1 -0
  56. package/dist/chunk-S6E67XMR.js +52 -0
  57. package/dist/chunk-S6E67XMR.js.map +1 -0
  58. package/dist/chunk-S6W4SURF.js +33 -0
  59. package/dist/chunk-S6W4SURF.js.map +1 -0
  60. package/dist/chunk-SMZYA6CY.js +121 -0
  61. package/dist/chunk-SMZYA6CY.js.map +1 -0
  62. package/dist/chunk-SNOA575X.js +12 -0
  63. package/dist/chunk-SNOA575X.js.map +1 -0
  64. package/dist/chunk-SZRIZBWI.js +44 -0
  65. package/dist/chunk-SZRIZBWI.js.map +1 -0
  66. package/dist/chunk-TAGHPCFT.js +47 -0
  67. package/dist/chunk-TAGHPCFT.js.map +1 -0
  68. package/dist/chunk-TGKCHHXT.js +34 -0
  69. package/dist/chunk-TGKCHHXT.js.map +1 -0
  70. package/dist/chunk-TORYFKPK.js +39 -0
  71. package/dist/chunk-TORYFKPK.js.map +1 -0
  72. package/dist/chunk-U35GRLBD.js +143 -0
  73. package/dist/chunk-U35GRLBD.js.map +1 -0
  74. package/dist/chunk-W2HBRERV.js +57 -0
  75. package/dist/chunk-W2HBRERV.js.map +1 -0
  76. package/dist/chunk-WYU476R2.js +119 -0
  77. package/dist/chunk-WYU476R2.js.map +1 -0
  78. package/dist/chunk-YMO45Z6G.js +69 -0
  79. package/dist/chunk-YMO45Z6G.js.map +1 -0
  80. package/dist/claude-auto-run.js +1717 -0
  81. package/dist/claude-auto-run.js.map +1 -0
  82. package/dist/claude-auto.js +186 -0
  83. package/dist/claude-auto.js.map +1 -0
  84. package/dist/cost-QGM3D4QW.js +72 -0
  85. package/dist/cost-QGM3D4QW.js.map +1 -0
  86. package/dist/cost-QKN3U7AG.js +11 -0
  87. package/dist/cost-QKN3U7AG.js.map +1 -0
  88. package/dist/create-T3BDDS6G.js +14 -0
  89. package/dist/create-T3BDDS6G.js.map +1 -0
  90. package/dist/create-U5WYKTD4.js +118 -0
  91. package/dist/create-U5WYKTD4.js.map +1 -0
  92. package/dist/crontab-CDMC2FDT.js +118 -0
  93. package/dist/crontab-CDMC2FDT.js.map +1 -0
  94. package/dist/crontab-MAJ52FOK.js +118 -0
  95. package/dist/crontab-MAJ52FOK.js.map +1 -0
  96. package/dist/crontab-PNEWANLW.js +12 -0
  97. package/dist/crontab-PNEWANLW.js.map +1 -0
  98. package/dist/edit-77E3ZQHM.js +134 -0
  99. package/dist/edit-77E3ZQHM.js.map +1 -0
  100. package/dist/edit-RVPRAAQ2.js +13 -0
  101. package/dist/edit-RVPRAAQ2.js.map +1 -0
  102. package/dist/index.d.ts +1137 -0
  103. package/dist/index.js +2049 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/launchd-7F27BIZB.js +166 -0
  106. package/dist/launchd-7F27BIZB.js.map +1 -0
  107. package/dist/launchd-HNZIWLNC.js +166 -0
  108. package/dist/launchd-HNZIWLNC.js.map +1 -0
  109. package/dist/launchd-LZGDP7BM.js +12 -0
  110. package/dist/launchd-LZGDP7BM.js.map +1 -0
  111. package/dist/list-OIGERGYJ.js +15 -0
  112. package/dist/list-OIGERGYJ.js.map +1 -0
  113. package/dist/list-T35RSQVU.js +73 -0
  114. package/dist/list-T35RSQVU.js.map +1 -0
  115. package/dist/logs-D5FNSCXE.js +12 -0
  116. package/dist/logs-D5FNSCXE.js.map +1 -0
  117. package/dist/logs-YVSFXBSB.js +40 -0
  118. package/dist/logs-YVSFXBSB.js.map +1 -0
  119. package/dist/pause-2YOLFMAR.js +12 -0
  120. package/dist/pause-2YOLFMAR.js.map +1 -0
  121. package/dist/pause-JB42JGTB.js +45 -0
  122. package/dist/pause-JB42JGTB.js.map +1 -0
  123. package/dist/pause-OJNUYBCJ.js +47 -0
  124. package/dist/pause-OJNUYBCJ.js.map +1 -0
  125. package/dist/remove-RXYKFYBI.js +12 -0
  126. package/dist/remove-RXYKFYBI.js.map +1 -0
  127. package/dist/remove-UASXZCOR.js +59 -0
  128. package/dist/remove-UASXZCOR.js.map +1 -0
  129. package/dist/report-CHAJH2SA.js +150 -0
  130. package/dist/report-CHAJH2SA.js.map +1 -0
  131. package/dist/report-IYGK5HTC.js +14 -0
  132. package/dist/report-IYGK5HTC.js.map +1 -0
  133. package/dist/resume-3ATNZP6D.js +13 -0
  134. package/dist/resume-3ATNZP6D.js.map +1 -0
  135. package/dist/resume-6WVGU6XW.js +48 -0
  136. package/dist/resume-6WVGU6XW.js.map +1 -0
  137. package/dist/resume-JVTR7OEX.js +50 -0
  138. package/dist/resume-JVTR7OEX.js.map +1 -0
  139. package/dist/schtasks-2EQAD3ES.js +11 -0
  140. package/dist/schtasks-2EQAD3ES.js.map +1 -0
  141. package/dist/schtasks-4V2IFD3A.js +142 -0
  142. package/dist/schtasks-4V2IFD3A.js.map +1 -0
  143. package/dist/schtasks-JGEPEKQS.js +142 -0
  144. package/dist/schtasks-JGEPEKQS.js.map +1 -0
  145. package/dist/tui-2DUPCX3Q.js +15 -0
  146. package/dist/tui-2DUPCX3Q.js.map +1 -0
  147. package/dist/tui-6LOGPILA.js +547 -0
  148. package/dist/tui-6LOGPILA.js.map +1 -0
  149. package/package.json +81 -0
  150. package/scripts/postinstall.mjs +65 -0
  151. package/scripts/preuninstall.mjs +33 -0
  152. package/skills/edit/SKILL.md +25 -0
  153. package/skills/list/SKILL.md +26 -0
  154. package/skills/logs/SKILL.md +33 -0
  155. package/skills/pause/SKILL.md +21 -0
  156. package/skills/remove/SKILL.md +22 -0
  157. package/skills/resume/SKILL.md +21 -0
  158. package/skills/setup/SKILL.md +195 -0
  159. package/skills/status/SKILL.md +27 -0
@@ -0,0 +1,1137 @@
1
+ import { Document } from 'yaml';
2
+ import { z } from 'zod';
3
+ import Database from 'better-sqlite3';
4
+
5
+ type CliCommand = "create" | "check-repo" | "list" | "logs" | "report" | "pause" | "resume" | "remove" | "edit" | "cost" | "dashboard" | "help";
6
+ interface ParsedCommand {
7
+ command: CliCommand;
8
+ args: Record<string, string | number | boolean | undefined>;
9
+ }
10
+ type CommandHandler = (args: ParsedCommand["args"]) => Promise<void>;
11
+ declare const COMMANDS: Record<string, string>;
12
+
13
+ /**
14
+ * Check if a path is a valid git repository.
15
+ * Outputs JSON for the setup wizard to consume.
16
+ */
17
+ declare function checkRepoCommand(args: ParsedCommand["args"]): Promise<void>;
18
+
19
+ /**
20
+ * CLI command handler for `claude-auto cost`.
21
+ *
22
+ * Without a jobId: displays per-job cost summary table.
23
+ * With a jobId: displays per-day cost breakdown for that job.
24
+ * With --json flag: outputs JSON array instead of formatted table.
25
+ *
26
+ * @param args - Parsed CLI arguments (jobId?: string, json?: boolean)
27
+ */
28
+ declare function costCommand(args: Record<string, string | number | boolean | undefined>): Promise<void>;
29
+
30
+ /**
31
+ * Create a new autonomous cron job. Validates all inputs, optionally clones the repo,
32
+ * creates the job config, and registers with the system scheduler.
33
+ */
34
+ declare function createCommand(args: ParsedCommand["args"]): Promise<void>;
35
+
36
+ /**
37
+ * Edit a job's configuration fields. Re-validates and re-registers with scheduler
38
+ * if schedule or timezone changes. Supports multiple flags in one invocation.
39
+ */
40
+ declare function editCommand(args: ParsedCommand["args"]): Promise<void>;
41
+
42
+ /**
43
+ * List all configured jobs with enriched status info:
44
+ * ID, Name, Status, Repo, Schedule, Last Run, Next Run.
45
+ *
46
+ * Satisfies JOB-01 (list with status/schedule/last run/next run)
47
+ * and JOB-05 (multiple jobs visible as separate entries).
48
+ */
49
+ declare function listCommand(args: ParsedCommand["args"]): Promise<void>;
50
+
51
+ /**
52
+ * Show recent run history for a specific job.
53
+ * Displays a table of: Run ID, Status, Started, Duration, PR URL, Error.
54
+ */
55
+ declare function logsCommand(args: ParsedCommand["args"]): Promise<void>;
56
+
57
+ /**
58
+ * Pause a running job: sets enabled=false and unregisters from scheduler.
59
+ * Idempotent: pausing an already-paused job prints a message and exits cleanly.
60
+ */
61
+ declare function pauseCommand(args: ParsedCommand["args"]): Promise<void>;
62
+
63
+ /**
64
+ * Remove a job: unregisters from scheduler and deletes job directory.
65
+ * With --keep-logs: archives run logs before deleting.
66
+ */
67
+ declare function removeCommand(args: ParsedCommand["args"]): Promise<void>;
68
+
69
+ /**
70
+ * Show aggregate run summary for a single job or across all jobs.
71
+ * Satisfies REPT-02 (aggregate run summary reports).
72
+ */
73
+ declare function reportCommand(args: ParsedCommand["args"]): Promise<void>;
74
+
75
+ /**
76
+ * Resume a paused job: sets enabled=true and re-registers with scheduler.
77
+ * Idempotent: resuming an already-active job prints a message and exits cleanly.
78
+ */
79
+ declare function resumeCommand(args: ParsedCommand["args"]): Promise<void>;
80
+
81
+ /**
82
+ * Convert milliseconds to human-readable duration.
83
+ * Omits zero-value leading parts. For hours+, shows "Xh Ym" (omits seconds).
84
+ * For minutes+, shows "Xm Ys". For <1m, shows "Xs".
85
+ */
86
+ declare function formatDuration(ms: number): string;
87
+ /**
88
+ * Format a date as a relative time string: "just now", "5 minutes ago", "2 hours ago", etc.
89
+ * Pure math, no library dependencies.
90
+ */
91
+ declare function formatRelativeTime(date: Date): string;
92
+ /**
93
+ * Format data as an aligned text table.
94
+ * Returns an empty string when there are no rows.
95
+ */
96
+ declare function formatTable(headers: string[], rows: string[][]): string;
97
+ /**
98
+ * Returns a text badge for a status string: "active" -> "[active]".
99
+ */
100
+ declare function statusBadge(status: string): string;
101
+
102
+ /**
103
+ * Parse CLI argv (process.argv.slice(2)) into a structured command.
104
+ * Extracts the subcommand from argv[0], then parses remaining args.
105
+ */
106
+ declare function parseCommand(argv: string[]): ParsedCommand;
107
+ /**
108
+ * Main CLI entry point. Parses argv and dispatches to the appropriate command handler.
109
+ */
110
+ declare function runCli(argv: string[]): Promise<void>;
111
+
112
+ declare const JobConfigSchema: z.ZodObject<{
113
+ id: z.ZodString;
114
+ name: z.ZodString;
115
+ repo: z.ZodObject<{
116
+ path: z.ZodString;
117
+ branch: z.ZodDefault<z.ZodString>;
118
+ remote: z.ZodDefault<z.ZodString>;
119
+ }, z.core.$strip>;
120
+ schedule: z.ZodObject<{
121
+ cron: z.ZodString;
122
+ timezone: z.ZodDefault<z.ZodString>;
123
+ }, z.core.$strip>;
124
+ focus: z.ZodDefault<z.ZodArray<z.ZodEnum<{
125
+ "open-issues": "open-issues";
126
+ "bug-discovery": "bug-discovery";
127
+ features: "features";
128
+ documentation: "documentation";
129
+ }>>>;
130
+ systemPrompt: z.ZodOptional<z.ZodString>;
131
+ guardrails: z.ZodDefault<z.ZodObject<{
132
+ maxTurns: z.ZodDefault<z.ZodNumber>;
133
+ maxBudgetUsd: z.ZodDefault<z.ZodNumber>;
134
+ noNewDependencies: z.ZodDefault<z.ZodBoolean>;
135
+ noArchitectureChanges: z.ZodDefault<z.ZodBoolean>;
136
+ bugFixOnly: z.ZodDefault<z.ZodBoolean>;
137
+ restrictToPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
138
+ }, z.core.$strip>>;
139
+ notifications: z.ZodDefault<z.ZodObject<{
140
+ discord: z.ZodOptional<z.ZodObject<{
141
+ webhookUrl: z.ZodString;
142
+ onSuccess: z.ZodDefault<z.ZodBoolean>;
143
+ onFailure: z.ZodDefault<z.ZodBoolean>;
144
+ onNoChanges: z.ZodDefault<z.ZodBoolean>;
145
+ onLocked: z.ZodDefault<z.ZodBoolean>;
146
+ }, z.core.$strip>>;
147
+ slack: z.ZodOptional<z.ZodObject<{
148
+ webhookUrl: z.ZodString;
149
+ onSuccess: z.ZodDefault<z.ZodBoolean>;
150
+ onFailure: z.ZodDefault<z.ZodBoolean>;
151
+ onNoChanges: z.ZodDefault<z.ZodBoolean>;
152
+ onLocked: z.ZodDefault<z.ZodBoolean>;
153
+ }, z.core.$strip>>;
154
+ telegram: z.ZodOptional<z.ZodObject<{
155
+ botToken: z.ZodString;
156
+ chatId: z.ZodString;
157
+ onSuccess: z.ZodDefault<z.ZodBoolean>;
158
+ onFailure: z.ZodDefault<z.ZodBoolean>;
159
+ onNoChanges: z.ZodDefault<z.ZodBoolean>;
160
+ onLocked: z.ZodDefault<z.ZodBoolean>;
161
+ }, z.core.$strip>>;
162
+ }, z.core.$strip>>;
163
+ enabled: z.ZodDefault<z.ZodBoolean>;
164
+ model: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
165
+ default: "default";
166
+ sonnet: "sonnet";
167
+ opus: "opus";
168
+ haiku: "haiku";
169
+ opusplan: "opusplan";
170
+ }>, z.ZodString]>>;
171
+ budget: z.ZodOptional<z.ZodObject<{
172
+ dailyUsd: z.ZodOptional<z.ZodNumber>;
173
+ weeklyUsd: z.ZodOptional<z.ZodNumber>;
174
+ monthlyUsd: z.ZodOptional<z.ZodNumber>;
175
+ }, z.core.$strip>>;
176
+ maxFeedbackRounds: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
177
+ pipeline: z.ZodOptional<z.ZodObject<{
178
+ enabled: z.ZodDefault<z.ZodBoolean>;
179
+ planModel: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
180
+ default: "default";
181
+ sonnet: "sonnet";
182
+ opus: "opus";
183
+ haiku: "haiku";
184
+ opusplan: "opusplan";
185
+ }>, z.ZodString]>>;
186
+ implementModel: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
187
+ default: "default";
188
+ sonnet: "sonnet";
189
+ opus: "opus";
190
+ haiku: "haiku";
191
+ opusplan: "opusplan";
192
+ }>, z.ZodString]>>;
193
+ reviewModel: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
194
+ default: "default";
195
+ sonnet: "sonnet";
196
+ opus: "opus";
197
+ haiku: "haiku";
198
+ opusplan: "opusplan";
199
+ }>, z.ZodString]>>;
200
+ maxReviewRounds: z.ZodDefault<z.ZodNumber>;
201
+ }, z.core.$strip>>;
202
+ }, z.core.$strip>;
203
+ type JobConfig = z.infer<typeof JobConfigSchema>;
204
+ interface ScheduleInfo {
205
+ cron: string;
206
+ timezone: string;
207
+ humanReadable: string;
208
+ nextRuns: Date[];
209
+ }
210
+
211
+ /**
212
+ * Read a YAML config file and return the parsed Document (preserves comments).
213
+ * Throws ConfigParseError if the YAML syntax is invalid.
214
+ */
215
+ declare function readConfigDocument(filePath: string): Promise<Document>;
216
+ /**
217
+ * Validate a parsed YAML Document against the JobConfigSchema.
218
+ * Returns the validated and typed JobConfig.
219
+ * Throws ConfigValidationError if validation fails.
220
+ */
221
+ declare function validateConfig(filePath: string, doc: Document): JobConfig;
222
+ /**
223
+ * Load a job config from a YAML file, validating it against the schema.
224
+ * Combines readConfigDocument + validateConfig.
225
+ */
226
+ declare function loadJobConfig(filePath: string): Promise<JobConfig>;
227
+ /**
228
+ * Save a JobConfig to a YAML file using atomic writes.
229
+ * Multiline systemPrompt values use YAML block literal style (|).
230
+ */
231
+ declare function saveJobConfig(filePath: string, config: JobConfig): Promise<void>;
232
+ /**
233
+ * Update a field in a YAML Document by path, preserving comments.
234
+ */
235
+ declare function updateConfigField(doc: Document, path: (string | number)[], value: unknown): void;
236
+ /**
237
+ * Write a YAML Document to a file using atomic writes, preserving comments.
238
+ */
239
+ declare function writeConfigDocument(filePath: string, doc: Document): Promise<void>;
240
+
241
+ /**
242
+ * Get or create the SQLite database singleton.
243
+ * On first call, opens the database, sets pragmas (WAL mode, synchronous=normal,
244
+ * foreign_keys=ON), and runs schema migrations.
245
+ *
246
+ * @param dbPath - Optional path override for testing (e.g., ":memory:")
247
+ * @returns The singleton Database instance
248
+ */
249
+ declare function getDatabase(dbPath?: string): Database.Database;
250
+ /**
251
+ * Close the database connection and reset the singleton.
252
+ * Safe to call multiple times. After calling, the next getDatabase()
253
+ * call will open a fresh connection.
254
+ */
255
+ declare function closeDatabase(): void;
256
+
257
+ /**
258
+ * Create a new job with a generated nanoid(12) identifier.
259
+ * Writes the config to disk and returns the complete JobConfig.
260
+ */
261
+ declare function createJob(input: Omit<JobConfig, "id">): Promise<JobConfig>;
262
+ /**
263
+ * Read and validate a job config by its ID.
264
+ * Throws if the job doesn't exist (ENOENT) or config is invalid.
265
+ */
266
+ declare function readJob(jobId: string): Promise<JobConfig>;
267
+ /**
268
+ * Update specified fields of a job config while preserving YAML comments.
269
+ * Validates the result before writing. Rejects invalid updates.
270
+ */
271
+ declare function updateJob(jobId: string, updates: Partial<Omit<JobConfig, "id">>): Promise<JobConfig>;
272
+ /**
273
+ * Delete a job and its entire directory.
274
+ * Idempotent: does not throw if the job doesn't exist.
275
+ */
276
+ declare function deleteJob(jobId: string): Promise<void>;
277
+ /**
278
+ * List all valid job configs.
279
+ * Skips invalid directories/configs. Returns empty array if no jobs directory exists.
280
+ */
281
+ declare function listJobs(): Promise<JobConfig[]>;
282
+
283
+ /**
284
+ * Validate a cron expression. Throws CronValidationError if invalid.
285
+ * Only accepts standard 5-field cron expressions.
286
+ */
287
+ declare function validateCronExpression(cronExpr: string): void;
288
+ /**
289
+ * Get a human-readable description of a cron expression.
290
+ * Example: "0 *​/6 * * *" -> "Every 6 hours"
291
+ */
292
+ declare function describeSchedule(cronExpr: string): string;
293
+ /**
294
+ * Compute the next N run times for a cron expression in the given IANA timezone.
295
+ */
296
+ declare function getNextRuns(cronExpr: string, timezone: string, count?: number): Date[];
297
+ /**
298
+ * Validate a cron expression and return complete schedule info
299
+ * including human-readable description and next run times.
300
+ */
301
+ declare function validateAndDescribeSchedule(cronExpr: string, timezone: string): ScheduleInfo;
302
+
303
+ interface SpawnOptions {
304
+ cwd: string;
305
+ prompt: string;
306
+ maxTurns: number;
307
+ maxBudgetUsd: number;
308
+ allowedTools: string[];
309
+ appendSystemPrompt?: string;
310
+ model?: string;
311
+ env?: Record<string, string>;
312
+ }
313
+ interface SpawnResult {
314
+ success: boolean;
315
+ result: string;
316
+ summary: string;
317
+ sessionId: string;
318
+ costUsd: number;
319
+ numTurns: number;
320
+ durationMs: number;
321
+ isError: boolean;
322
+ subtype: string;
323
+ errors?: string[];
324
+ }
325
+ type RunStatus = "success" | "no-changes" | "error" | "locked" | "git-error" | "paused" | "budget-exceeded" | "needs-human-review" | "merge-conflict";
326
+ interface RunResult {
327
+ status: RunStatus;
328
+ jobId: string;
329
+ runId: string;
330
+ startedAt: string;
331
+ completedAt: string;
332
+ durationMs: number;
333
+ prUrl?: string;
334
+ summary?: string;
335
+ costUsd?: number;
336
+ numTurns?: number;
337
+ sessionId?: string;
338
+ error?: string;
339
+ branchName?: string;
340
+ issueNumber?: number;
341
+ model?: string;
342
+ feedbackRound?: number;
343
+ prNumber?: number;
344
+ pipelineStages?: Array<{
345
+ stage: string;
346
+ costUsd: number;
347
+ durationMs: number;
348
+ numTurns: number;
349
+ }>;
350
+ }
351
+ interface RunLogEntry extends RunResult {
352
+ }
353
+ interface ReviewThread {
354
+ id: string;
355
+ isResolved: boolean;
356
+ comments: Array<{
357
+ body: string;
358
+ author: {
359
+ login: string;
360
+ };
361
+ }>;
362
+ }
363
+ interface PRFeedbackContext {
364
+ number: number;
365
+ title: string;
366
+ headRefName: string;
367
+ url: string;
368
+ reviewDecision: string;
369
+ unresolvedThreads: ReviewThread[];
370
+ currentRound: number;
371
+ }
372
+ interface PipelineStageResult {
373
+ stage: "plan" | "implement" | "review" | "fix";
374
+ spawnResult: SpawnResult;
375
+ }
376
+ interface PipelineResult {
377
+ stages: PipelineStageResult[];
378
+ reviewVerdict: "pass" | "fail" | "skipped";
379
+ totalCostUsd: number;
380
+ totalDurationMs: number;
381
+ summary: string;
382
+ }
383
+ interface RebaseResult {
384
+ diverged: boolean;
385
+ rebased: boolean;
386
+ conflicts: string[];
387
+ }
388
+
389
+ /**
390
+ * Send notifications to all configured providers for a completed run.
391
+ *
392
+ * Best-effort: failures are logged as warnings but never thrown.
393
+ * All providers are called in parallel via Promise.allSettled.
394
+ */
395
+ declare function sendNotifications(config: JobConfig, result: RunResult): Promise<void>;
396
+
397
+ type NotificationEvent = "success" | "no-changes" | "error" | "locked" | "git-error" | "budget-exceeded" | "merge-conflict" | "needs-human-review";
398
+ interface NotificationPayload {
399
+ event: NotificationEvent;
400
+ jobId: string;
401
+ jobName: string;
402
+ runId: string;
403
+ repoPath: string;
404
+ branch: string;
405
+ startedAt: string;
406
+ completedAt: string;
407
+ durationMs: number;
408
+ prUrl?: string;
409
+ summary?: string;
410
+ costUsd?: number;
411
+ numTurns?: number;
412
+ error?: string;
413
+ branchName?: string;
414
+ }
415
+ interface EventTriggers {
416
+ onSuccess?: boolean;
417
+ onFailure?: boolean;
418
+ onNoChanges?: boolean;
419
+ onLocked?: boolean;
420
+ }
421
+ /**
422
+ * Determines whether a notification should be sent for a given run status
423
+ * and provider trigger configuration.
424
+ *
425
+ * Defaults:
426
+ * - onSuccess: true (backward compat -- always notify on PR created)
427
+ * - onFailure: true (always notify on errors)
428
+ * - onNoChanges: false (avoid noise)
429
+ * - onLocked: false (avoid noise)
430
+ */
431
+ declare function shouldNotify(status: RunStatus, triggers: EventTriggers): boolean;
432
+ /**
433
+ * Build a NotificationPayload from job config and run result.
434
+ * Maps RunResult + JobConfig into the shape formatters consume.
435
+ */
436
+ declare function buildPayload(config: JobConfig, result: RunResult): NotificationPayload;
437
+
438
+ /**
439
+ * Format a notification payload for Discord webhook API.
440
+ * Returns a JSON-serializable object with Discord embeds.
441
+ */
442
+ declare function formatDiscord(payload: NotificationPayload): object;
443
+ /**
444
+ * Format a notification payload for Slack incoming webhook API.
445
+ * Returns a JSON-serializable object with Slack blocks.
446
+ */
447
+ declare function formatSlack(payload: NotificationPayload): object;
448
+ /**
449
+ * Format a notification payload for Telegram Bot API (sendMessage).
450
+ * Returns a JSON-serializable object with chat_id, text, and parse_mode.
451
+ */
452
+ declare function formatTelegram(payload: NotificationPayload, chatId: string): object;
453
+
454
+ /**
455
+ * Extract a GitHub issue number from text.
456
+ * Looks for patterns like: #42, fixes #7, closes #123, resolves #99
457
+ * Returns the first matched issue number, or undefined if none found.
458
+ */
459
+ declare function extractIssueNumber(text: string): number | undefined;
460
+ interface PostIssueCommentOptions {
461
+ repoPath: string;
462
+ issueNumber: number;
463
+ status: RunStatus;
464
+ prUrl?: string;
465
+ summary?: string;
466
+ error?: string;
467
+ jobName: string;
468
+ }
469
+ /**
470
+ * Post a comment on a GitHub issue about the run result.
471
+ *
472
+ * Best-effort: failures are logged as warnings but never thrown.
473
+ * Skips posting for "locked" status (no value in commenting on skipped runs).
474
+ */
475
+ declare function postIssueComment(options: PostIssueCommentOptions): Promise<void>;
476
+
477
+ interface RegisteredJob {
478
+ jobId: string;
479
+ schedule: string;
480
+ command: string;
481
+ }
482
+ interface Scheduler {
483
+ register(job: JobConfig, env?: Record<string, string>): Promise<void>;
484
+ unregister(jobId: string): Promise<void>;
485
+ isRegistered(jobId: string): Promise<boolean>;
486
+ list(): Promise<RegisteredJob[]>;
487
+ }
488
+ /**
489
+ * Factory function that returns the correct Scheduler implementation
490
+ * for the current platform: CrontabScheduler on Linux, LaunchdScheduler on macOS,
491
+ * SchtasksScheduler on Windows.
492
+ */
493
+ declare function createScheduler(): Promise<Scheduler>;
494
+
495
+ /**
496
+ * CrontabScheduler implements the Scheduler interface for Linux systems.
497
+ * Uses comment-tagged crontab entries for identification and CRUD.
498
+ */
499
+ declare class CrontabScheduler implements Scheduler {
500
+ register(job: JobConfig, _env?: Record<string, string>): Promise<void>;
501
+ unregister(jobId: string): Promise<void>;
502
+ isRegistered(jobId: string): Promise<boolean>;
503
+ list(): Promise<RegisteredJob[]>;
504
+ }
505
+
506
+ type Platform = "linux" | "darwin" | "win32";
507
+ /**
508
+ * Detect the current platform. Returns "linux", "darwin", or "win32".
509
+ * Throws SchedulerError for unsupported platforms.
510
+ */
511
+ declare function detectPlatform(): Platform;
512
+
513
+ interface CalendarInterval {
514
+ Month?: number;
515
+ Day?: number;
516
+ Weekday?: number;
517
+ Hour?: number;
518
+ Minute?: number;
519
+ }
520
+ /**
521
+ * Convert a 5-field cron expression to launchd scheduling config.
522
+ *
523
+ * For high-frequency "every N minutes" patterns, returns { startInterval: seconds }.
524
+ * For specific times, returns { calendarIntervals: CalendarInterval[] }.
525
+ *
526
+ * Throws if the expression would produce more than 50 calendar intervals.
527
+ */
528
+ declare function cronToCalendarIntervals(cronExpr: string): {
529
+ calendarIntervals?: CalendarInterval[];
530
+ startInterval?: number;
531
+ };
532
+ /**
533
+ * LaunchdScheduler implements the Scheduler interface for macOS.
534
+ * Uses plist files in ~/Library/LaunchAgents/ and modern launchctl bootstrap/bootout.
535
+ */
536
+ declare class LaunchdScheduler implements Scheduler {
537
+ register(job: JobConfig, env?: Record<string, string>): Promise<void>;
538
+ unregister(jobId: string): Promise<void>;
539
+ isRegistered(jobId: string): Promise<boolean>;
540
+ list(): Promise<RegisteredJob[]>;
541
+ }
542
+
543
+ interface SchtasksSchedule {
544
+ args: string[];
545
+ description: string;
546
+ }
547
+ /**
548
+ * Translate a 5-field cron expression into schtasks /SC schedule parameters.
549
+ *
550
+ * Supports:
551
+ * - Every N minutes (e.g., *\/30 * * * *)
552
+ * - Every N hours at minute M (e.g., 0 *\/6 * * *)
553
+ * - Daily at specific time (e.g., 0 9 * * *)
554
+ * - Specific days of week (e.g., 0 9 * * 1-5)
555
+ * - Monthly on a single day (e.g., 0 9 15 * *)
556
+ *
557
+ * Throws SchedulerError for patterns that cannot be represented as a single
558
+ * Windows Task Scheduler entry.
559
+ */
560
+ declare function cronToSchtasks(cronExpr: string): SchtasksSchedule;
561
+ /**
562
+ * SchtasksScheduler implements the Scheduler interface for Windows systems.
563
+ * Uses `schtasks.exe` to create, query, and delete tasks in Windows Task Scheduler.
564
+ *
565
+ * Task name format: `claude-auto-{jobId}`
566
+ */
567
+ declare class SchtasksScheduler implements Scheduler {
568
+ register(job: JobConfig, _env?: Record<string, string>): Promise<void>;
569
+ unregister(jobId: string): Promise<void>;
570
+ isRegistered(jobId: string): Promise<boolean>;
571
+ list(): Promise<RegisteredJob[]>;
572
+ }
573
+
574
+ /**
575
+ * Structured context from a prior run, containing only verifiable facts
576
+ * (issue numbers, PR URLs, branch names) -- never raw narrative summaries.
577
+ */
578
+ interface RunContext {
579
+ id: string;
580
+ status: string;
581
+ pr_url: string | null;
582
+ branch_name: string | null;
583
+ issue_number: number | null;
584
+ summary: string | null;
585
+ started_at: string;
586
+ }
587
+ /**
588
+ * Persist a run log entry to the SQLite database.
589
+ * Maps RunLogEntry camelCase fields to snake_case columns.
590
+ *
591
+ * @param entry - The run log entry to save
592
+ */
593
+ declare function saveRunContext(entry: RunLogEntry): void;
594
+ /**
595
+ * Load recent run context for a job from SQLite.
596
+ * Only returns runs with status "success" or "no-changes" (not errors, locked, etc.)
597
+ * to avoid injecting failure context into Claude's prompt.
598
+ *
599
+ * @param jobId - The job identifier
600
+ * @param limit - Maximum number of recent runs to return (default: 5)
601
+ * @returns Array of RunContext sorted by started_at descending
602
+ */
603
+ declare function loadRunContext(jobId: string, limit?: number): RunContext[];
604
+ /**
605
+ * Format run context as a structured "Previous Work" prompt section.
606
+ * Only includes verifiable facts (issue numbers, PR URLs, branch names)
607
+ * to avoid hallucination amplification from raw narrative summaries.
608
+ *
609
+ * @param context - Array of RunContext from loadRunContext
610
+ * @returns Formatted string for prompt injection, or empty string if no context
611
+ */
612
+ declare function formatContextWindow(context: RunContext[]): string;
613
+
614
+ /**
615
+ * Budget configuration with optional caps per time period.
616
+ * When a cap is set, cumulative cost within that period is checked
617
+ * before spawning a new run.
618
+ */
619
+ interface BudgetConfig {
620
+ dailyUsd?: number;
621
+ weeklyUsd?: number;
622
+ monthlyUsd?: number;
623
+ }
624
+ /**
625
+ * Per-job cost summary row returned by getCostSummary() when no jobId is specified.
626
+ */
627
+ interface CostSummaryRow {
628
+ job_id: string;
629
+ runs: number;
630
+ total_cost: number;
631
+ avg_cost: number;
632
+ total_turns: number;
633
+ }
634
+ /**
635
+ * Per-day cost breakdown row returned by getCostSummary(jobId).
636
+ */
637
+ interface DailyCostRow {
638
+ day: string;
639
+ runs: number;
640
+ total_cost: number;
641
+ total_turns: number;
642
+ }
643
+ /**
644
+ * Check whether cumulative cost for a job exceeds any configured budget cap.
645
+ *
646
+ * Queries the runs table for cost accrued within each budget period (daily, weekly, monthly),
647
+ * excluding non-spending statuses (locked, paused, budget-exceeded).
648
+ *
649
+ * @param jobId - The job identifier to check
650
+ * @param budget - Budget configuration with optional period caps
651
+ * @param dbPath - Optional database path override for testing
652
+ * @returns true if any budget cap is met or exceeded, false otherwise
653
+ */
654
+ declare function checkBudget(jobId: string, budget: BudgetConfig, dbPath?: string): boolean;
655
+ /**
656
+ * Get cost summary data from the runs table.
657
+ *
658
+ * When jobId is provided, returns per-day cost breakdown for that job (last 30 days).
659
+ * When no jobId is provided, returns per-job aggregate cost totals across all jobs.
660
+ *
661
+ * @param jobId - Optional job identifier for per-day breakdown
662
+ * @param dbPath - Optional database path override for testing
663
+ * @returns Array of CostSummaryRow (no jobId) or DailyCostRow (with jobId)
664
+ */
665
+ declare function getCostSummary(jobId?: string, dbPath?: string): CostSummaryRow[] | DailyCostRow[];
666
+
667
+ /**
668
+ * Pull latest changes from remote branch.
669
+ * Runs: git fetch, git checkout, git pull --ff-only (in order).
670
+ */
671
+ declare function pullLatest(repoPath: string, branch: string, remote: string): Promise<void>;
672
+ /**
673
+ * Create a new branch for this run.
674
+ * Branch name format: claude-auto/{jobId}/{ISO-timestamp}
675
+ */
676
+ declare function createBranch(repoPath: string, jobId: string): Promise<string>;
677
+ /**
678
+ * Check if the working tree has uncommitted changes.
679
+ */
680
+ declare function hasChanges(repoPath: string): Promise<boolean>;
681
+ /**
682
+ * Push branch to origin with upstream tracking.
683
+ * Safety: only uses -u flag, no destructive push flags.
684
+ */
685
+ declare function pushBranch(repoPath: string, branchName: string): Promise<void>;
686
+ /**
687
+ * Checkout an existing branch (e.g., a PR branch) and reset to match remote.
688
+ * Used for PR feedback iteration -- safely switches to the existing PR branch.
689
+ *
690
+ * Steps:
691
+ * 1. Fetch the latest state of the branch from origin
692
+ * 2. Checkout the branch (may already exist locally or be created from remote tracking)
693
+ * 3. Hard reset to match origin exactly (safe because claude-auto never has local-only state)
694
+ */
695
+ declare function checkoutExistingBranch(repoPath: string, branchName: string): Promise<void>;
696
+ /**
697
+ * Create a pull request via GitHub CLI.
698
+ * Returns the PR URL.
699
+ */
700
+ declare function createPR(repoPath: string, branchName: string, baseBranch: string, title: string, body: string): Promise<string>;
701
+ /**
702
+ * Check if the target branch has diverged from the current branch.
703
+ * Fetches the remote base branch first, then uses git merge-base --is-ancestor
704
+ * to determine if the remote base is still an ancestor of HEAD.
705
+ *
706
+ * @returns true if diverged (remote base has commits not in current branch), false otherwise
707
+ */
708
+ declare function checkDivergence(repoPath: string, baseBranch: string, remote: string): Promise<boolean>;
709
+ /**
710
+ * Attempt to rebase the current branch onto the remote base branch.
711
+ * First checks for divergence; if not diverged, returns early.
712
+ * If diverged, attempts rebase. On conflict, aborts cleanly and returns conflict list.
713
+ */
714
+ declare function attemptRebase(repoPath: string, baseBranch: string, remote: string): Promise<RebaseResult>;
715
+ /**
716
+ * Get the diff between the base branch and HEAD.
717
+ * Best-effort: returns empty string on error.
718
+ */
719
+ declare function getDiffFromBase(repoPath: string, baseBranch: string): Promise<string>;
720
+
721
+ /**
722
+ * A scored and filtered GitHub issue ready for presentation to Claude.
723
+ * Body is truncated to 1000 chars to reduce token usage.
724
+ */
725
+ interface ScoredIssue {
726
+ number: number;
727
+ title: string;
728
+ body: string;
729
+ labels: string[];
730
+ score: number;
731
+ skipReason?: string;
732
+ }
733
+ /**
734
+ * Triage GitHub issues for a repository by scoring and filtering them
735
+ * before presenting to Claude. This reduces token usage and improves
736
+ * work selection quality.
737
+ *
738
+ * Scoring rubric:
739
+ * - Base score: 50
740
+ * - Label boosts: good first issue (+30), bug (+20), enhancement (+10), documentation (+5)
741
+ * - Body quality: < 20 chars (-30), > 100 chars (+10), > 500 chars (+5 additional)
742
+ *
743
+ * Skip reasons:
744
+ * - already-attempted: issue was worked on in a previous run
745
+ * - assigned: issue has assignees
746
+ * - negative-label: issue has wontfix or duplicate label
747
+ * - requires-human: issue has question or discussion label
748
+ *
749
+ * @param repoPath - Path to the repository (used as cwd for gh CLI)
750
+ * @param previousIssues - Issue numbers already attempted in prior runs
751
+ * @returns Scored issues sorted by score descending, with skipped issues excluded
752
+ */
753
+ declare function triageIssues(repoPath: string, previousIssues: number[]): Promise<ScoredIssue[]>;
754
+
755
+ /** Stale lock threshold: 45 minutes in milliseconds */
756
+ declare const STALE_THRESHOLD: number;
757
+ /**
758
+ * Acquire a file-based lock for a job.
759
+ * Returns a release function on success, or null if the lock is already held.
760
+ * Uses proper-lockfile for cross-process safety with stale detection.
761
+ */
762
+ declare function acquireLock(jobId: string): Promise<(() => Promise<void>) | null>;
763
+
764
+ /**
765
+ * Write a run log entry as a JSON file for a specific job run.
766
+ * Creates the runs directory if it doesn't exist (via writeFileSafe).
767
+ *
768
+ * @param jobId - The job identifier
769
+ * @param entry - The run log entry to write
770
+ */
771
+ declare function writeRunLog(jobId: string, entry: RunLogEntry): Promise<void>;
772
+ /**
773
+ * Read and parse a specific run log entry.
774
+ *
775
+ * @param jobId - The job identifier
776
+ * @param runId - The run identifier
777
+ * @returns Parsed RunLogEntry
778
+ * @throws When the log file doesn't exist (ENOENT)
779
+ */
780
+ declare function readRunLog(jobId: string, runId: string): Promise<RunLogEntry>;
781
+ /**
782
+ * List all run logs for a job, sorted by startedAt descending (newest first).
783
+ * Returns an empty array when the runs directory doesn't exist.
784
+ * Skips files that fail to parse (logs warning but doesn't throw).
785
+ *
786
+ * @param jobId - The job identifier
787
+ * @returns Array of RunLogEntry sorted by startedAt descending
788
+ */
789
+ declare function listRunLogs(jobId: string): Promise<RunLogEntry[]>;
790
+
791
+ /**
792
+ * Execute a full autonomous run cycle for a job.
793
+ *
794
+ * Sequence: lock -> config -> enabled check -> budget check -> pullLatest ->
795
+ * check PR feedback (priority) -> if feedback: iterate on PR -> else: triage issues ->
796
+ * create branch -> spawn Claude -> check changes -> push/PR -> log -> unlock
797
+ *
798
+ * @param jobId - The job identifier to run
799
+ * @returns RunResult with status indicating outcome
800
+ */
801
+ declare function executeRun(jobId: string): Promise<RunResult>;
802
+
803
+ /**
804
+ * Run the multi-stage pipeline: plan -> implement -> review -> optional fix.
805
+ *
806
+ * Each stage spawns a separate Claude instance via spawnClaude with its
807
+ * configured model, budget slice, and prompt. The review stage verdict
808
+ * determines whether a fix stage runs.
809
+ *
810
+ * When maxReviewRounds > 1, the review+fix cycle repeats up to N times.
811
+ * On the last round, if review fails, the fix stage still runs once but
812
+ * no re-review occurs.
813
+ *
814
+ * @param config - Job configuration with pipeline settings
815
+ * @param repoPath - Path to the repository
816
+ * @param branchName - Current work branch name
817
+ * @param runContext - Prior run context for duplicate avoidance
818
+ * @param triaged - Pre-scored issues from triage
819
+ * @returns PipelineResult with all stage results aggregated
820
+ */
821
+ declare function runPipeline(config: JobConfig, repoPath: string, _branchName: string, runContext: RunContext[], triaged: ScoredIssue[]): Promise<PipelineResult>;
822
+
823
+ /**
824
+ * Build a read-only tool set for plan and review stages.
825
+ * Excludes Edit, Write, and git mutation tools (add, commit).
826
+ * Includes read-only tools: file reading, search, git inspection, issue viewing, test running.
827
+ *
828
+ * @param _config - Job configuration (reserved for future guardrail-based filtering)
829
+ * @returns Array of allowed tool strings for read-only stages
830
+ */
831
+ declare function buildReadOnlyTools(_config: JobConfig): string[];
832
+ /**
833
+ * Build the work prompt for the PLAN stage of the pipeline.
834
+ * Instructs Claude to research the codebase and produce a concrete,
835
+ * actionable implementation plan without making any changes.
836
+ *
837
+ * @param config - Job configuration with focus areas
838
+ * @param triaged - Pre-scored issues from triage (may be empty)
839
+ * @param context - Prior run context for duplicate avoidance
840
+ * @returns Multi-section plan prompt string
841
+ */
842
+ declare function buildPlanPrompt(config: JobConfig, triaged: ScoredIssue[], context: RunContext[]): string;
843
+ /**
844
+ * Build the system prompt for the PLAN stage.
845
+ *
846
+ * @param config - Job configuration with optional systemPrompt
847
+ * @returns System prompt string for the planning stage
848
+ */
849
+ declare function buildPlanSystemPrompt(config: JobConfig): string;
850
+ /**
851
+ * Build the work prompt for the IMPLEMENT stage of the pipeline.
852
+ * Includes the plan output, focus areas, guardrails, git safety rules,
853
+ * and completion instructions.
854
+ *
855
+ * @param config - Job configuration with guardrails and focus areas
856
+ * @param planResult - SpawnResult from the plan stage
857
+ * @param context - Prior run context for duplicate avoidance
858
+ * @returns Multi-section implement prompt string
859
+ */
860
+ declare function buildImplementPrompt(config: JobConfig, planResult: SpawnResult, context: RunContext[]): string;
861
+ /**
862
+ * Build the system prompt for the IMPLEMENT stage.
863
+ *
864
+ * @param config - Job configuration with optional systemPrompt
865
+ * @returns System prompt string for the implementation stage
866
+ */
867
+ declare function buildImplementSystemPrompt(config: JobConfig): string;
868
+ /**
869
+ * Build the work prompt for the REVIEW stage of the pipeline.
870
+ * Includes the original plan, the implementation diff, and verdict instructions.
871
+ *
872
+ * @param config - Job configuration
873
+ * @param planText - The plan stage output text
874
+ * @param diffOutput - Git diff of implementation changes
875
+ * @returns Multi-section review prompt string
876
+ */
877
+ declare function buildReviewPrompt(_config: JobConfig, planText: string, diffOutput: string): string;
878
+ /**
879
+ * Build the system prompt for the REVIEW stage.
880
+ *
881
+ * @param config - Job configuration with optional systemPrompt
882
+ * @returns System prompt string for the review stage
883
+ */
884
+ declare function buildReviewSystemPrompt(config: JobConfig): string;
885
+ /**
886
+ * Build the work prompt for the FIX stage of the pipeline.
887
+ * Includes the review feedback and git safety rules.
888
+ *
889
+ * @param config - Job configuration
890
+ * @param reviewText - The review stage output text with issues to fix
891
+ * @returns Multi-section fix prompt string
892
+ */
893
+ declare function buildFixPrompt(_config: JobConfig, reviewText: string): string;
894
+ /**
895
+ * Build the system prompt for the FIX stage.
896
+ *
897
+ * @param config - Job configuration with optional systemPrompt
898
+ * @returns System prompt string for the fix stage
899
+ */
900
+ declare function buildFixSystemPrompt(config: JobConfig): string;
901
+ /**
902
+ * Parse the review stage output to determine the verdict.
903
+ * Searches for "VERDICT: PASS" or "VERDICT: FAIL" markers.
904
+ * If both exist, FAIL takes priority (safer).
905
+ * Defaults to "fail" when no verdict marker is found (safer to run fix stage unnecessarily).
906
+ *
907
+ * @param reviewResult - SpawnResult from the review stage
908
+ * @returns "pass" or "fail"
909
+ */
910
+ declare function parseReviewVerdict(reviewResult: SpawnResult): "pass" | "fail";
911
+
912
+ /**
913
+ * Internal interface for PR data from `gh pr list --json`.
914
+ * Not exported -- external consumers use PRFeedbackContext.
915
+ */
916
+ interface PRWithFeedback {
917
+ number: number;
918
+ title: string;
919
+ headRefName: string;
920
+ reviewDecision: string;
921
+ url: string;
922
+ }
923
+ /**
924
+ * List open PRs authored by the current user that match this job's branch prefix.
925
+ * Uses `gh pr list` with JSON output for structured data.
926
+ *
927
+ * @param repoPath - Path to the git repository
928
+ * @param jobId - Job identifier used to filter branches by prefix
929
+ * @returns Array of PRs matching the claude-auto/{jobId}/ branch prefix
930
+ */
931
+ declare function listOpenPRsWithFeedback(repoPath: string, jobId: string): Promise<PRWithFeedback[]>;
932
+ /**
933
+ * Get the owner and name of the repository from `gh repo view`.
934
+ *
935
+ * @param repoPath - Path to the git repository
936
+ * @returns Object with owner (login) and name of the repository
937
+ */
938
+ declare function getRepoOwnerName(repoPath: string): Promise<{
939
+ owner: string;
940
+ name: string;
941
+ }>;
942
+ /**
943
+ * Fetch unresolved review threads for a PR using the GitHub GraphQL API.
944
+ * This is necessary because the REST API does not expose the `isResolved` field.
945
+ *
946
+ * Filters out:
947
+ * - Resolved threads (isResolved: true)
948
+ * - Threads where ALL comments are from bot authors (login ending with "[bot]")
949
+ *
950
+ * @param repoPath - Path to the git repository
951
+ * @param prNumber - PR number to query
952
+ * @returns Array of unresolved ReviewThread objects with human comments
953
+ */
954
+ declare function getUnresolvedThreads(repoPath: string, prNumber: number): Promise<ReviewThread[]>;
955
+ /**
956
+ * Post a comment on a PR using `gh pr comment`.
957
+ * Best-effort: failures are logged as warnings but never thrown.
958
+ *
959
+ * @param repoPath - Path to the git repository
960
+ * @param prNumber - PR number to comment on
961
+ * @param body - Comment body text
962
+ */
963
+ declare function postPRComment(repoPath: string, prNumber: number, body: string): Promise<void>;
964
+ /**
965
+ * Get the current feedback round count for a PR from the SQLite database.
966
+ * Counts the number of prior runs with a matching pr_number and non-null feedback_round.
967
+ *
968
+ * @param jobId - Job identifier
969
+ * @param prNumber - PR number
970
+ * @returns Number of prior feedback rounds (0 if none)
971
+ */
972
+ declare function getFeedbackRound(jobId: string, prNumber: number): number;
973
+ /**
974
+ * Check for open PRs with actionable feedback that should be iterated on.
975
+ *
976
+ * Orchestration flow:
977
+ * 1. List open PRs for this job
978
+ * 2. Filter to PRs with CHANGES_REQUESTED review decision
979
+ * 3. For each candidate, fetch unresolved review threads
980
+ * 4. Check feedback round count against max rounds
981
+ * 5. Return PRFeedbackContext if actionable, null otherwise
982
+ *
983
+ * @param repoPath - Path to the git repository
984
+ * @param jobId - Job identifier
985
+ * @param maxRounds - Maximum number of feedback rounds allowed
986
+ * @returns PRFeedbackContext if there's actionable feedback, null otherwise
987
+ */
988
+ declare function checkPendingPRFeedback(repoPath: string, jobId: string, maxRounds: number): Promise<PRFeedbackContext | null>;
989
+
990
+ /**
991
+ * Build the system prompt for Claude, including research instructions
992
+ * and an optional user-provided system prompt.
993
+ *
994
+ * @param config - Job configuration with optional systemPrompt
995
+ * @returns Combined system prompt string
996
+ */
997
+ declare function buildSystemPrompt(config: JobConfig): string;
998
+ /**
999
+ * Build the work prompt for Claude, containing priority chain, focus areas,
1000
+ * conditional guardrails, git safety rules, documentation requirements,
1001
+ * completion instructions, and optionally a "Previous Work" context section.
1002
+ *
1003
+ * @param config - Job configuration with guardrails and focus areas
1004
+ * @param context - Optional array of prior run context for duplicate avoidance
1005
+ * @returns Multi-section work prompt string
1006
+ */
1007
+ declare function buildWorkPrompt(config: JobConfig, context?: RunContext[]): string;
1008
+ /**
1009
+ * Build a prompt for Claude to address PR review feedback.
1010
+ *
1011
+ * The prompt includes:
1012
+ * 1. Task framing with round/iteration info
1013
+ * 2. Sanitized review comments in XML tags (truncated to 2000 chars each)
1014
+ * 3. Git safety rules
1015
+ * 4. Completion instructions
1016
+ * 5. Previous work context (if provided)
1017
+ *
1018
+ * @param config - Job configuration
1019
+ * @param feedback - PR feedback context with unresolved review threads
1020
+ * @param context - Optional array of prior run context
1021
+ * @returns Multi-section feedback prompt string
1022
+ */
1023
+ declare function buildFeedbackPrompt(config: JobConfig, feedback: PRFeedbackContext, context?: RunContext[]): string;
1024
+ /**
1025
+ * Build a work prompt enhanced with pre-triaged issue candidates.
1026
+ *
1027
+ * When triaged issues are provided, replaces the generic "check gh issue list"
1028
+ * section with a ranked list of pre-scored candidates. Falls back to the
1029
+ * standard buildWorkPrompt when no triaged issues are available.
1030
+ *
1031
+ * @param config - Job configuration
1032
+ * @param triaged - Array of scored issues from triage (may be empty)
1033
+ * @param context - Optional array of prior run context
1034
+ * @returns Multi-section work prompt string
1035
+ */
1036
+ declare function buildTriagedWorkPrompt(config: JobConfig, triaged: ScoredIssue[], context?: RunContext[]): string;
1037
+
1038
+ /**
1039
+ * Build the list of allowed tools for Claude based on job config guardrails.
1040
+ * Always includes core tools (Read, Edit, Write, Glob, Grep), git tools,
1041
+ * GitHub CLI tools, and npm test/lint/typecheck tools. Conditionally includes
1042
+ * npm install/add when noNewDependencies is false (default).
1043
+ */
1044
+ declare function buildAllowedTools(config: JobConfig): string[];
1045
+ /**
1046
+ * Spawn Claude Code CLI in headless mode with JSON output parsing.
1047
+ * Invokes `claude -p` with --output-format json, --max-turns, --max-budget-usd,
1048
+ * --dangerously-skip-permissions, and optional --append-system-prompt and --allowedTools.
1049
+ *
1050
+ * @param options - Spawn configuration including cwd, prompt, limits, and tools
1051
+ * @returns SpawnResult with parsed JSON output fields
1052
+ * @throws SpawnError when process exits non-zero and JSON parsing fails
1053
+ */
1054
+ declare function spawnClaude(options: SpawnOptions): Promise<SpawnResult>;
1055
+
1056
+ /**
1057
+ * Launch the interactive TUI dashboard.
1058
+ * Renders the App component via ink and blocks until the user quits.
1059
+ */
1060
+ declare function launchDashboard(): Promise<void>;
1061
+
1062
+ declare class ConfigParseError extends Error {
1063
+ readonly filePath: string;
1064
+ readonly parseErrors: Array<{
1065
+ message: string;
1066
+ }>;
1067
+ name: "ConfigParseError";
1068
+ constructor(filePath: string, parseErrors: Array<{
1069
+ message: string;
1070
+ }>);
1071
+ }
1072
+ declare class ConfigValidationError extends Error {
1073
+ readonly filePath: string;
1074
+ readonly validationMessage: string;
1075
+ name: "ConfigValidationError";
1076
+ constructor(filePath: string, validationMessage: string);
1077
+ }
1078
+ declare class SchedulerError extends Error {
1079
+ readonly platform: string;
1080
+ readonly cause?: Error | undefined;
1081
+ name: "SchedulerError";
1082
+ constructor(platform: string, message: string, cause?: Error | undefined);
1083
+ }
1084
+ declare class CronValidationError extends Error {
1085
+ readonly expression: string;
1086
+ name: "CronValidationError";
1087
+ constructor(expression: string, message: string);
1088
+ }
1089
+ declare class GitOpsError extends Error {
1090
+ readonly operation: string;
1091
+ readonly repoPath: string;
1092
+ readonly cause?: Error | undefined;
1093
+ name: "GitOpsError";
1094
+ constructor(operation: string, repoPath: string, message: string, cause?: Error | undefined);
1095
+ }
1096
+ declare class LockError extends Error {
1097
+ readonly jobId: string;
1098
+ name: "LockError";
1099
+ constructor(jobId: string, message: string);
1100
+ }
1101
+ declare class SpawnError extends Error {
1102
+ readonly exitCode?: number | undefined;
1103
+ name: "SpawnError";
1104
+ constructor(message: string, exitCode?: number | undefined);
1105
+ }
1106
+
1107
+ interface ExecResult {
1108
+ stdout: string;
1109
+ stderr: string;
1110
+ }
1111
+ /**
1112
+ * Execute a command and return stdout/stderr.
1113
+ * Throws if the command exits with non-zero status.
1114
+ */
1115
+ declare function execCommand(command: string, args: string[], options?: {
1116
+ stdin?: string;
1117
+ cwd?: string;
1118
+ }): Promise<ExecResult>;
1119
+
1120
+ declare function writeFileSafe(filePath: string, content: string): Promise<void>;
1121
+
1122
+ declare const paths: {
1123
+ readonly base: string;
1124
+ readonly jobs: string;
1125
+ readonly jobDir: (jobId: string) => string;
1126
+ readonly jobConfig: (jobId: string) => string;
1127
+ readonly logs: string;
1128
+ readonly jobLogs: (jobId: string) => string;
1129
+ readonly jobLog: (jobId: string, runId: string) => string;
1130
+ readonly jobLock: (jobId: string) => string;
1131
+ readonly plistDir: string;
1132
+ readonly plistPath: (jobId: string) => string;
1133
+ readonly crontabLock: string;
1134
+ readonly database: string;
1135
+ };
1136
+
1137
+ export { type BudgetConfig, COMMANDS, type CalendarInterval, type CliCommand, type CommandHandler, ConfigParseError, ConfigValidationError, type CostSummaryRow, CronValidationError, CrontabScheduler, type DailyCostRow, type EventTriggers, GitOpsError, type JobConfig, JobConfigSchema, LaunchdScheduler, LockError, type NotificationEvent, type NotificationPayload, type PRFeedbackContext, type ParsedCommand, type PipelineResult, type PipelineStageResult, type Platform, type RebaseResult, type RegisteredJob, type ReviewThread, type RunContext, type RunLogEntry, type RunResult, type RunStatus, STALE_THRESHOLD, type ScheduleInfo, type Scheduler, SchedulerError, SchtasksScheduler, type ScoredIssue, SpawnError, type SpawnOptions, type SpawnResult, acquireLock, attemptRebase, buildAllowedTools, buildFeedbackPrompt, buildFixPrompt, buildFixSystemPrompt, buildImplementPrompt, buildImplementSystemPrompt, buildPayload, buildPlanPrompt, buildPlanSystemPrompt, buildReadOnlyTools, buildReviewPrompt, buildReviewSystemPrompt, buildSystemPrompt, buildTriagedWorkPrompt, buildWorkPrompt, checkBudget, checkDivergence, checkPendingPRFeedback, checkRepoCommand, checkoutExistingBranch, closeDatabase, costCommand, createBranch, createCommand, createJob, createPR, createScheduler, cronToCalendarIntervals, cronToSchtasks, deleteJob, describeSchedule, detectPlatform, editCommand, execCommand, executeRun, extractIssueNumber, formatContextWindow, formatDiscord, formatDuration, formatRelativeTime, formatSlack, formatTable, formatTelegram, getCostSummary, getDatabase, getDiffFromBase, getFeedbackRound, getNextRuns, getRepoOwnerName, getUnresolvedThreads, hasChanges, launchDashboard, listCommand, listJobs, listOpenPRsWithFeedback, listRunLogs, loadJobConfig, loadRunContext, logsCommand, parseCommand, parseReviewVerdict, paths, pauseCommand, postIssueComment, postPRComment, pullLatest, pushBranch, readConfigDocument, readJob, readRunLog, removeCommand, reportCommand, resumeCommand, runCli, runPipeline, saveJobConfig, saveRunContext, sendNotifications, shouldNotify, spawnClaude, statusBadge, triageIssues, updateConfigField, updateJob, validateAndDescribeSchedule, validateConfig, validateCronExpression, writeConfigDocument, writeFileSafe, writeRunLog };