@lovelybunch/api 1.0.75-alpha.12 → 1.0.75-alpha.14

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 (119) hide show
  1. package/dist/lib/mail/mail-runner.d.ts +30 -0
  2. package/dist/lib/mail/mail-runner.js +108 -3
  3. package/dist/lib/storage/file-storage.js +2 -7
  4. package/dist/routes/api/v1/mail/index.js +4 -1
  5. package/dist/routes/api/v1/mail/route.d.ts +42 -0
  6. package/dist/routes/api/v1/mail/route.js +78 -0
  7. package/dist/routes/api/v1/slack/route.d.ts +6 -6
  8. package/dist/routes/api/v1/tasks/[id]/route.d.ts +2 -236
  9. package/dist/routes/api/v1/tasks/route.d.ts +2 -236
  10. package/dist/routes/api/v1/tasks/route.js +2 -8
  11. package/dist/server-with-static.js +2 -0
  12. package/package.json +4 -4
  13. package/static/assets/{ActivityPage-nSSbSFAB.js → ActivityPage-Ch44od-j.js} +1 -1
  14. package/static/assets/{ApiKeysSettingsPage-xrhhroQ_.js → ApiKeysSettingsPage-DuT2DLgr.js} +2 -2
  15. package/static/assets/{ArchitectureEditPage-CHFEQNgk.js → ArchitectureEditPage-DvJkcnEG.js} +1 -1
  16. package/static/assets/{ArchitecturePage-EudLa-GY.js → ArchitecturePage-DqSclgRT.js} +1 -1
  17. package/static/assets/{AuthSettingsPage-C3YTYgj_.js → AuthSettingsPage-yM2zFEcv.js} +2 -2
  18. package/static/assets/{CallbackPage-VI4m1EWU.js → CallbackPage-Bytr8RS8.js} +1 -1
  19. package/static/assets/{CodePage-CcH6EB2S.js → CodePage-BlGPi7uk.js} +1 -1
  20. package/static/assets/{CollapsibleSection-4LvowJQN.js → CollapsibleSection-irzuq21b.js} +1 -1
  21. package/static/assets/{DashboardPage-Dj2GNTQg.js → DashboardPage-DdA0uFZr.js} +1 -1
  22. package/static/assets/{GitPage-E9px87JY.js → GitPage-Cl_rMV7q.js} +1 -1
  23. package/static/assets/{GitSettingsPage-BepF5Dpg.js → GitSettingsPage-B6bQRTLV.js} +1 -1
  24. package/static/assets/{IdentityPage-Ccarv5Tz.js → IdentityPage-CTsJJ_nR.js} +1 -1
  25. package/static/assets/{ImplementationStepsEditor-BPeqMfAd.js → ImplementationStepsEditor-D1q30m-M.js} +2 -2
  26. package/static/assets/{IntegrationsSettingsPage-Dp3FRWNn.js → IntegrationsSettingsPage-au7RbHgk.js} +1 -1
  27. package/static/assets/{JobDetailPage-DOJKC2Oq.js → JobDetailPage-CDRH2EOg.js} +1 -1
  28. package/static/assets/KnowledgeDetailPage-DpvktyWP.js +1 -0
  29. package/static/assets/{KnowledgeEditPage-D7gBI6r-.js → KnowledgeEditPage-bHrMagf9.js} +1 -1
  30. package/static/assets/KnowledgePage-CHu-yTF2.js +3 -0
  31. package/static/assets/{LoginPage-nYfkZp1m.js → LoginPage-Dxep5Whg.js} +1 -1
  32. package/static/assets/MailInboxPage-3enQ9yud.js +1 -0
  33. package/static/assets/MailProcessingModal-BN-hk7rN.js +6 -0
  34. package/static/assets/MailReadPage-Dg6oDlFh.js +1 -0
  35. package/static/assets/{MailSentPage-BqtUkhvw.js → MailSentPage-Dig5IXdR.js} +1 -1
  36. package/static/assets/McpSettingsPage-CNwqGqLg.js +1 -0
  37. package/static/assets/{NewKnowledgePage-BsiP9u8K.js → NewKnowledgePage-Czxn4P1j.js} +1 -1
  38. package/static/assets/{NewSkillPage-BuwLNwdi.js → NewSkillPage-CqaO2xNS.js} +1 -1
  39. package/static/assets/{NewTaskPage-DVh5Xv1O.js → NewTaskPage-CYITUYtu.js} +2 -2
  40. package/static/assets/NotFoundPage-BEQ3ZHqV.js +6 -0
  41. package/static/assets/{NotificationsSettingsPage-BbDASNoh.js → NotificationsSettingsPage-HuOKal9l.js} +1 -1
  42. package/static/assets/{ProjectEditPage-DdCvF5RR.js → ProjectEditPage-CeHWqhRX.js} +1 -1
  43. package/static/assets/{ProjectPage-2ujqpmN5.js → ProjectPage-YTFg8Fkd.js} +1 -1
  44. package/static/assets/{PromptsSettingsPage-xmsIGnw7.js → PromptsSettingsPage-DPTo5b4l.js} +1 -1
  45. package/static/assets/{ResourceDetailPage--4tTrZYy.js → ResourceDetailPage-CA_ZCk6v.js} +1 -1
  46. package/static/assets/{ResourcesPage-Nrgt2hCS.js → ResourcesPage-6kcr9x0O.js} +1 -1
  47. package/static/assets/RoleEditPage-CULuINfL.js +13 -0
  48. package/static/assets/{RolePage-hS7J_Bhy.js → RolePage-BhJl9l-G.js} +1 -1
  49. package/static/assets/{RulesSettingsPage-D4K8SBOu.js → RulesSettingsPage-CYhp9PHk.js} +3 -3
  50. package/static/assets/SchedulePage-vUZaPVX6.js +4 -0
  51. package/static/assets/{SkillDetailPage-DXtASGaY.js → SkillDetailPage-BT1Gp3Hh.js} +1 -1
  52. package/static/assets/{SkillEditPage-D75sp5rI.js → SkillEditPage-CV2BMeF_.js} +1 -1
  53. package/static/assets/{SkillsPage-CsutZlkM.js → SkillsPage-fT1CoBCE.js} +2 -2
  54. package/static/assets/{SkillsSettingsPage-B8z_IMlS.js → SkillsSettingsPage-TiwaPPcd.js} +1 -1
  55. package/static/assets/{SourceInput-DkQR44OP.js → SourceInput-B790vfwY.js} +1 -1
  56. package/static/assets/{TagInput-BkkvY_kU.js → TagInput-Btfjq6aa.js} +1 -1
  57. package/static/assets/TaskDetailPage-BMGupUYM.js +16 -0
  58. package/static/assets/{TaskEditPage-CnKiBPvU.js → TaskEditPage-CQz9UIZL.js} +1 -1
  59. package/static/assets/TasksPage-NbDKSkOe.js +17 -0
  60. package/static/assets/{TerminalPage-DIXOrK6a.js → TerminalPage-CQLCoRdq.js} +1 -1
  61. package/static/assets/{TerminalSessionPage-Bu0_HyWE.js → TerminalSessionPage-doL1BiJi.js} +1 -1
  62. package/static/assets/{UserPreferencesPage-_ZVEA1Ec.js → UserPreferencesPage-D2CiwL2m.js} +1 -1
  63. package/static/assets/UserSettingsPage-iSTGwM80.js +1 -0
  64. package/static/assets/{UtilitiesPage-D4Ae45jX.js → UtilitiesPage-B-ZW4kdp.js} +1 -1
  65. package/static/assets/{alert-oIIrVTSO.js → alert-15F3-9XX.js} +1 -1
  66. package/static/assets/{arrow-down-Bzd7RaRH.js → arrow-down-BrqEvvfv.js} +1 -1
  67. package/static/assets/{arrow-left-BjR0fDgf.js → arrow-left-CaqvCoIB.js} +1 -1
  68. package/static/assets/{arrow-up-C7p7WCEm.js → arrow-up-DNzaGmlT.js} +1 -1
  69. package/static/assets/arrow-up-down-DCe7-ihF.js +6 -0
  70. package/static/assets/{badge-C2DkFMMB.js → badge-BnmevczT.js} +1 -1
  71. package/static/assets/{browser-modal-C6te-uYZ.js → browser-modal-ChaWEpHZ.js} +1 -1
  72. package/static/assets/{card-WnET8BI8.js → card-NkV5eOu8.js} +1 -1
  73. package/static/assets/{chevron-left-BIRokVSR.js → chevron-left-Blz556B2.js} +1 -1
  74. package/static/assets/{chevron-up-Cn_oyEAo.js → chevron-up-rbFu97ce.js} +1 -1
  75. package/static/assets/{chevrons-up-CupaYlEL.js → chevrons-up-BQMlE7rT.js} +1 -1
  76. package/static/assets/{circle-alert-aIhIWzZ9.js → circle-alert-B_3aezfy.js} +1 -1
  77. package/static/assets/{circle-check-Cji8oWtr.js → circle-check-Di9E8LZ0.js} +1 -1
  78. package/static/assets/{circle-check-big-CfzDBM2L.js → circle-check-big-DeInZUEL.js} +1 -1
  79. package/static/assets/{circle-play-BAAWTmz3.js → circle-play-_KPAQa5u.js} +1 -1
  80. package/static/assets/{circle-x-DUrreDIn.js → circle-x-Dqvz_3qq.js} +1 -1
  81. package/static/assets/{clipboard-BM4PIYFM.js → clipboard-CbMUHSIJ.js} +1 -1
  82. package/static/assets/{clock-PqCucnPP.js → clock-DYK-k9QO.js} +1 -1
  83. package/static/assets/{download-BfRAPZa0.js → download-DvfDST0e.js} +1 -1
  84. package/static/assets/{external-link-BHVp3obJ.js → external-link-4402xHJm.js} +1 -1
  85. package/static/assets/{eye-DSRHxLqT.js → eye-C96SnuaK.js} +1 -1
  86. package/static/assets/{folder-git-2-C2qrNCQi.js → folder-git-2-DM9e4LLF.js} +1 -1
  87. package/static/assets/index-DIPJXXxG.css +2 -0
  88. package/static/assets/{index-Cv-tURje.js → index-SVcL57hQ.js} +98 -98
  89. package/static/assets/{info-yTHl9iJb.js → info-C4HFkLJI.js} +1 -1
  90. package/static/assets/label-MGLxVQcy.js +1 -0
  91. package/static/assets/{markdown-editor-CKaviYH9.js → markdown-editor-8DjKwEtI.js} +1 -1
  92. package/static/assets/{message-square-D-mJ-M1p.js → message-square-C3VNiI6M.js} +1 -1
  93. package/static/assets/{paperclip-BSIzwgES.js → paperclip-o6t1e21X.js} +1 -1
  94. package/static/assets/{pause-DJ-9PRz9.js → pause-pAcTJVOC.js} +1 -1
  95. package/static/assets/{play-WwrfRXB7.js → play-Dn69nfRB.js} +1 -1
  96. package/static/assets/{radio-group-Cahzon6Q.js → radio-group-C_JhFin5.js} +1 -1
  97. package/static/assets/{refresh-cw-DNc78_Y9.js → refresh-cw-oOjEruv4.js} +1 -1
  98. package/static/assets/{search-k0E_myGY.js → search-Ck3r4Ru-.js} +1 -1
  99. package/static/assets/{select-DXmoGuE-.js → select-DY8bp_yH.js} +1 -1
  100. package/static/assets/{switch-D_BwNkIO.js → switch-CyhPMHQO.js} +1 -1
  101. package/static/assets/{tabs-Bc7iwFOR.js → tabs-Cjt4N6XC.js} +1 -1
  102. package/static/assets/{tag-C0GUie9u.js → tag-CajsrbmJ.js} +1 -1
  103. package/static/assets/{terminal-preview-COHnoVSQ.js → terminal-preview-DkoSzVhy.js} +1 -1
  104. package/static/assets/{use-terminal-Cnylz5l4.js → use-terminal-CJMIUQKK.js} +1 -1
  105. package/static/assets/{video-BC93G8Yl.js → video-Db8h41sP.js} +1 -1
  106. package/static/assets/{zap-Bf22dXda.js → zap-BQyXK_jX.js} +1 -1
  107. package/static/index.html +2 -2
  108. package/static/assets/KnowledgeDetailPage-BT0czLqw.js +0 -1
  109. package/static/assets/KnowledgePage-CcfftMdn.js +0 -8
  110. package/static/assets/MailInboxPage-DvD2sH0g.js +0 -1
  111. package/static/assets/MailReadPage-CZ9stBHd.js +0 -1
  112. package/static/assets/McpSettingsPage-CrNaaXtj.js +0 -1
  113. package/static/assets/RoleEditPage-D8XSVw9S.js +0 -13
  114. package/static/assets/SchedulePage-BiJmkZ3Q.js +0 -4
  115. package/static/assets/TaskDetailPage-Bh3Cb6ce.js +0 -1
  116. package/static/assets/TasksPage-3UvOASrt.js +0 -17
  117. package/static/assets/UserSettingsPage-hOWbcJ8X.js +0 -1
  118. package/static/assets/index-CkH7-cOr.css +0 -2
  119. package/static/assets/label-DjRbZW_E.js +0 -1
@@ -5,14 +5,44 @@ interface MailRunResult {
5
5
  error?: string;
6
6
  cliCommand: string;
7
7
  }
8
+ export interface ActiveMailProcess {
9
+ mailId: string;
10
+ pid: number;
11
+ agent: string;
12
+ startedAt: string;
13
+ logPath: string;
14
+ }
8
15
  export declare class MailRunner {
9
16
  private projectRootPromise;
17
+ private activeProcesses;
10
18
  constructor();
11
19
  private ensureCliAvailable;
12
20
  private ensureLogPath;
13
21
  private loadSystemPrompt;
14
22
  private loadConfigModel;
15
23
  private buildInstruction;
24
+ /**
25
+ * Get the status of an active mail processing job.
26
+ * Returns null if no active process exists for this mailId.
27
+ */
28
+ getActiveProcess(mailId: string): ActiveMailProcess | null;
29
+ /**
30
+ * Get all active mail processing jobs.
31
+ */
32
+ getActiveProcesses(): ActiveMailProcess[];
33
+ /**
34
+ * Read the latest log file for a mail processing job.
35
+ * Returns the tail of the log (up to maxBytes).
36
+ */
37
+ readLog(mailId: string, maxBytes?: number): Promise<{
38
+ log: string;
39
+ logPath: string;
40
+ } | null>;
41
+ /**
42
+ * Stop an active mail processing job.
43
+ * Sends SIGTERM, then SIGKILL after 5s.
44
+ */
45
+ stop(mailId: string): Promise<boolean>;
16
46
  run(mailId: string, mailFilePath: string): Promise<MailRunResult>;
17
47
  }
18
48
  export declare function getMailRunner(): MailRunner;
@@ -74,6 +74,7 @@ function getMaxRuntime() {
74
74
  }
75
75
  export class MailRunner {
76
76
  projectRootPromise;
77
+ activeProcesses = new Map();
77
78
  constructor() {
78
79
  this.projectRootPromise = getProjectRoot();
79
80
  }
@@ -122,6 +123,97 @@ export class MailRunner {
122
123
  .replace(/\{\{mailId\}\}/g, mailId);
123
124
  return instruction;
124
125
  }
126
+ /**
127
+ * Get the status of an active mail processing job.
128
+ * Returns null if no active process exists for this mailId.
129
+ */
130
+ getActiveProcess(mailId) {
131
+ const tracked = this.activeProcesses.get(mailId);
132
+ if (!tracked || !tracked.child.pid)
133
+ return null;
134
+ return {
135
+ mailId,
136
+ pid: tracked.child.pid,
137
+ agent: tracked.agent,
138
+ startedAt: tracked.startedAt,
139
+ logPath: tracked.logPath,
140
+ };
141
+ }
142
+ /**
143
+ * Get all active mail processing jobs.
144
+ */
145
+ getActiveProcesses() {
146
+ const result = [];
147
+ for (const [mailId, tracked] of this.activeProcesses) {
148
+ if (tracked.child.pid) {
149
+ result.push({
150
+ mailId,
151
+ pid: tracked.child.pid,
152
+ agent: tracked.agent,
153
+ startedAt: tracked.startedAt,
154
+ logPath: tracked.logPath,
155
+ });
156
+ }
157
+ }
158
+ return result;
159
+ }
160
+ /**
161
+ * Read the latest log file for a mail processing job.
162
+ * Returns the tail of the log (up to maxBytes).
163
+ */
164
+ async readLog(mailId, maxBytes = 8192) {
165
+ const projectRoot = await this.projectRootPromise;
166
+ const logsDir = path.join(projectRoot, '.nut', 'mail', 'logs', mailId);
167
+ let files;
168
+ try {
169
+ files = await fs.readdir(logsDir);
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ const logFiles = files.filter(f => f.endsWith('.log')).sort();
175
+ if (logFiles.length === 0)
176
+ return null;
177
+ const latestLog = path.join(logsDir, logFiles[logFiles.length - 1]);
178
+ try {
179
+ const stat = await fs.stat(latestLog);
180
+ const start = Math.max(0, stat.size - maxBytes);
181
+ const fh = await fs.open(latestLog, 'r');
182
+ try {
183
+ const buf = Buffer.alloc(Math.min(stat.size, maxBytes));
184
+ await fh.read(buf, 0, buf.length, start);
185
+ let log = buf.toString('utf-8');
186
+ if (start > 0) {
187
+ log = '...' + log.slice(log.indexOf('\n') + 1);
188
+ }
189
+ return { log, logPath: path.relative(projectRoot, latestLog) };
190
+ }
191
+ finally {
192
+ await fh.close();
193
+ }
194
+ }
195
+ catch {
196
+ return null;
197
+ }
198
+ }
199
+ /**
200
+ * Stop an active mail processing job.
201
+ * Sends SIGTERM, then SIGKILL after 5s.
202
+ */
203
+ async stop(mailId) {
204
+ const tracked = this.activeProcesses.get(mailId);
205
+ if (!tracked)
206
+ return false;
207
+ console.log(`[mail] Stopping processing for ${mailId} (PID: ${tracked.child.pid})`);
208
+ tracked.child.kill('SIGTERM');
209
+ setTimeout(() => {
210
+ try {
211
+ tracked.child.kill('SIGKILL');
212
+ }
213
+ catch { /* already dead */ }
214
+ }, 5000);
215
+ return true;
216
+ }
125
217
  async run(mailId, mailFilePath) {
126
218
  const model = await this.loadConfigModel();
127
219
  const agent = resolveAgent(model);
@@ -132,7 +224,8 @@ export class MailRunner {
132
224
  const logPath = await this.ensureLogPath(mailId);
133
225
  const logStream = createWriteStream(logPath, { flags: 'a' });
134
226
  const summaryChunks = [];
135
- logStream.write(`[${new Date().toISOString()}] Starting mail processing for ${mailId} using ${agent} CLI\n`);
227
+ const startedAt = new Date().toISOString();
228
+ logStream.write(`[${startedAt}] Starting mail processing for ${mailId} using ${agent} CLI\n`);
136
229
  logStream.write(`Mail file: ${mailFilePath}\n`);
137
230
  logStream.write(`Command: ${shellCommand}\n`);
138
231
  return new Promise((resolve) => {
@@ -172,6 +265,14 @@ export class MailRunner {
172
265
  child.kill('SIGTERM');
173
266
  setTimeout(() => child.kill('SIGKILL'), 10_000);
174
267
  }, maxRuntime);
268
+ // Track the active process
269
+ this.activeProcesses.set(mailId, {
270
+ child,
271
+ agent: CLI_AGENT_LABEL[agent],
272
+ startedAt,
273
+ logPath: path.relative(projectRoot, logPath),
274
+ abortTimeout,
275
+ });
175
276
  child.stdout?.on('data', (chunk) => {
176
277
  const text = chunk.toString();
177
278
  logStream.write(text);
@@ -182,11 +283,15 @@ export class MailRunner {
182
283
  logStream.write(text);
183
284
  summaryChunks.push(text);
184
285
  });
286
+ const cleanup = () => {
287
+ this.activeProcesses.delete(mailId);
288
+ clearTimeout(abortTimeout);
289
+ };
185
290
  child.on('error', (error) => {
186
291
  const message = `Failed to start CLI command: ${error.message}`;
187
292
  logStream.write(`${message}\n`);
188
293
  logStream.end();
189
- clearTimeout(abortTimeout);
294
+ cleanup();
190
295
  setMailProcessing(mailId, false).catch(err => console.warn('[mail] failed to clear processing:', err));
191
296
  resolve({
192
297
  status: 'failed',
@@ -200,7 +305,7 @@ export class MailRunner {
200
305
  const status = code === 0 ? 'succeeded' : 'failed';
201
306
  logStream.write(`\n[${new Date().toISOString()}] Mail processing for ${mailId} completed with exit code ${code}\n`);
202
307
  logStream.end();
203
- clearTimeout(abortTimeout);
308
+ cleanup();
204
309
  setMailProcessing(mailId, false).catch(err => console.warn('[mail] failed to clear processing:', err));
205
310
  const summary = summaryChunks.join('');
206
311
  resolve({
@@ -77,6 +77,7 @@ export class FileStorageAdapter {
77
77
  updatedAt: updatedAt.toISOString(),
78
78
  status: task.status,
79
79
  priority: task.metadata.priority || 'medium',
80
+ ...(task.metadata.readiness != null && { readiness: task.metadata.readiness }),
80
81
  // Author information
81
82
  author: {
82
83
  id: task.author.id,
@@ -258,21 +259,15 @@ export class FileStorageAdapter {
258
259
  error: step.error,
259
260
  executedAt: step.executedAt ? new Date(step.executedAt) : undefined
260
261
  })),
261
- evidence: data.evidence || [],
262
- policies: data.policies || [],
263
- featureFlags: data.featureFlags || [],
264
- experiments: data.experiments || [],
265
- telemetryContracts: data.telemetryContracts || [],
266
- releasePlan: data.releasePlan || { strategy: 'immediate' },
267
262
  status: data.status || 'draft',
268
263
  comments: normalizedComments,
269
264
  metadata: {
270
265
  createdAt: new Date(data.createdAt || Date.now()),
271
266
  updatedAt: new Date(data.updatedAt || Date.now()),
272
267
  reviewers: data.reviewers || [],
273
- aiInteractions: data.aiInteractions || [],
274
268
  tags: data.tags || [],
275
269
  priority: data.priority || 'medium',
270
+ ...(data.readiness != null && { readiness: data.readiness }),
276
271
  },
277
272
  content // Store the markdown content
278
273
  };
@@ -1,10 +1,13 @@
1
1
  import { Hono } from 'hono';
2
- import { listMailHandler, getMailHandler, setMailStatusHandler, setMailActionHandler, replyMailHandler, sendMailHandler, deleteMailHandler, inboundWebhookHandler, } from './route.js';
2
+ import { listMailHandler, getMailHandler, setMailStatusHandler, setMailActionHandler, replyMailHandler, sendMailHandler, deleteMailHandler, inboundWebhookHandler, getMailProcessingHandler, stopMailProcessingHandler, } from './route.js';
3
3
  const mailRoutes = new Hono();
4
4
  // Resend inbound webhook
5
5
  mailRoutes.post('/inbound', inboundWebhookHandler);
6
6
  // Send email (coming soon)
7
7
  mailRoutes.post('/send', sendMailHandler);
8
+ // Processing status and control
9
+ mailRoutes.get('/:id/processing', getMailProcessingHandler);
10
+ mailRoutes.post('/:id/processing/stop', stopMailProcessingHandler);
8
11
  // Set email status (read/unread)
9
12
  mailRoutes.put('/:id/status', setMailStatusHandler);
10
13
  // Set agent action summary
@@ -31,6 +31,7 @@ export declare function listMailHandler(c: Context): Promise<(Response & import(
31
31
  folder: MailFolder;
32
32
  action?: string;
33
33
  processing?: boolean;
34
+ processingStartedAt?: string;
34
35
  }[];
35
36
  };
36
37
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
@@ -71,6 +72,7 @@ export declare function getMailHandler(c: Context): Promise<(Response & import("
71
72
  folder: MailFolder;
72
73
  action?: string;
73
74
  processing?: boolean;
75
+ processingStartedAt?: string;
74
76
  };
75
77
  };
76
78
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
@@ -108,6 +110,7 @@ export declare function setMailStatusHandler(c: Context): Promise<(Response & im
108
110
  folder: MailFolder;
109
111
  action?: string;
110
112
  processing?: boolean;
113
+ processingStartedAt?: string;
111
114
  };
112
115
  };
113
116
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
@@ -145,6 +148,7 @@ export declare function replyMailHandler(c: Context): Promise<(Response & import
145
148
  folder: MailFolder;
146
149
  action?: string;
147
150
  processing?: boolean;
151
+ processingStartedAt?: string;
148
152
  };
149
153
  };
150
154
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
@@ -207,12 +211,49 @@ export declare function setMailActionHandler(c: Context): Promise<(Response & im
207
211
  folder: MailFolder;
208
212
  action?: string;
209
213
  processing?: boolean;
214
+ processingStartedAt?: string;
210
215
  };
211
216
  };
212
217
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
213
218
  success: false;
214
219
  error: any;
215
220
  }, 404 | 500, "json">)>;
221
+ /**
222
+ * GET /api/v1/mail/:id/processing
223
+ * Get processing status and log tail for an email
224
+ */
225
+ export declare function getMailProcessingHandler(c: Context): Promise<(Response & import("hono").TypedResponse<{
226
+ success: false;
227
+ error: string;
228
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
229
+ success: true;
230
+ data: {
231
+ mailId: string;
232
+ processing: boolean;
233
+ processingStartedAt: string;
234
+ active: {
235
+ pid: number;
236
+ agent: string;
237
+ startedAt: string;
238
+ };
239
+ log: string;
240
+ logPath: string;
241
+ };
242
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
243
+ success: false;
244
+ error: any;
245
+ }, 500, "json">)>;
246
+ /**
247
+ * POST /api/v1/mail/:id/processing/stop
248
+ * Stop an active mail processing job
249
+ */
250
+ export declare function stopMailProcessingHandler(c: Context): Promise<(Response & import("hono").TypedResponse<{
251
+ success: true;
252
+ message: string;
253
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
254
+ success: false;
255
+ error: any;
256
+ }, 500, "json">)>;
216
257
  /**
217
258
  * POST /api/v1/mail/inbound
218
259
  * Receive email via Resend webhook
@@ -244,6 +285,7 @@ export declare function inboundWebhookHandler(c: Context): Promise<(Response & i
244
285
  folder: MailFolder;
245
286
  action?: string;
246
287
  processing?: boolean;
288
+ processingStartedAt?: string;
247
289
  };
248
290
  };
249
291
  }, 201, "json">) | (Response & import("hono").TypedResponse<{
@@ -197,6 +197,84 @@ export async function setMailActionHandler(c) {
197
197
  }, status);
198
198
  }
199
199
  }
200
+ /**
201
+ * GET /api/v1/mail/:id/processing
202
+ * Get processing status and log tail for an email
203
+ */
204
+ export async function getMailProcessingHandler(c) {
205
+ try {
206
+ const id = c.req.param('id');
207
+ const runner = getMailRunner();
208
+ const mail = await getMail(id);
209
+ if (!mail) {
210
+ return c.json({
211
+ success: false,
212
+ error: `Email "${id}" not found`,
213
+ }, 404);
214
+ }
215
+ const active = runner.getActiveProcess(id);
216
+ const logData = await runner.readLog(id);
217
+ return c.json({
218
+ success: true,
219
+ data: {
220
+ mailId: id,
221
+ processing: mail.processing || false,
222
+ processingStartedAt: mail.processingStartedAt || null,
223
+ active: active ? {
224
+ pid: active.pid,
225
+ agent: active.agent,
226
+ startedAt: active.startedAt,
227
+ } : null,
228
+ log: logData?.log || null,
229
+ logPath: logData?.logPath || null,
230
+ },
231
+ });
232
+ }
233
+ catch (error) {
234
+ console.error('[mail] getProcessing error:', error);
235
+ return c.json({
236
+ success: false,
237
+ error: error.message || 'Failed to get processing status',
238
+ }, 500);
239
+ }
240
+ }
241
+ /**
242
+ * POST /api/v1/mail/:id/processing/stop
243
+ * Stop an active mail processing job
244
+ */
245
+ export async function stopMailProcessingHandler(c) {
246
+ try {
247
+ const id = c.req.param('id');
248
+ const runner = getMailRunner();
249
+ const active = runner.getActiveProcess(id);
250
+ if (!active) {
251
+ // No active process — clear the processing flag if still set
252
+ await setMailProcessing(id, false);
253
+ return c.json({
254
+ success: true,
255
+ message: `No active process found for "${id}". Processing flag cleared.`,
256
+ });
257
+ }
258
+ const stopped = await runner.stop(id);
259
+ if (!stopped) {
260
+ return c.json({
261
+ success: false,
262
+ error: `Failed to stop processing for "${id}"`,
263
+ }, 500);
264
+ }
265
+ return c.json({
266
+ success: true,
267
+ message: `Processing for "${id}" has been stopped (PID: ${active.pid}).`,
268
+ });
269
+ }
270
+ catch (error) {
271
+ console.error('[mail] stopProcessing error:', error);
272
+ return c.json({
273
+ success: false,
274
+ error: error.message || 'Failed to stop processing',
275
+ }, 500);
276
+ }
277
+ }
200
278
  /**
201
279
  * POST /api/v1/mail/inbound
202
280
  * Receive email via Resend webhook
@@ -7,9 +7,6 @@ export declare function getConfig(c: Context): Promise<(Response & import("hono"
7
7
  success: true;
8
8
  data: {
9
9
  enabled: boolean;
10
- channelId: string;
11
- channelName: string;
12
- siteUrl: string;
13
10
  notifications: {
14
11
  proposals: {
15
12
  created: boolean;
@@ -24,6 +21,9 @@ export declare function getConfig(c: Context): Promise<(Response & import("hono"
24
21
  merge: boolean;
25
22
  };
26
23
  };
24
+ channelId: string;
25
+ channelName: string;
26
+ siteUrl: string;
27
27
  hasBotToken: boolean;
28
28
  hasSigningSecret: boolean;
29
29
  };
@@ -39,9 +39,6 @@ export declare function updateConfig(c: Context): Promise<(Response & import("ho
39
39
  success: true;
40
40
  data: {
41
41
  enabled: boolean;
42
- channelId: string;
43
- channelName: string;
44
- siteUrl: string;
45
42
  notifications: {
46
43
  proposals: {
47
44
  created: boolean;
@@ -56,6 +53,9 @@ export declare function updateConfig(c: Context): Promise<(Response & import("ho
56
53
  merge: boolean;
57
54
  };
58
55
  };
56
+ channelId: string;
57
+ channelName: string;
58
+ siteUrl: string;
59
59
  hasBotToken: boolean;
60
60
  hasSigningSecret: boolean;
61
61
  };