@lovelybunch/api 1.0.75-alpha.13 → 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.
- package/dist/lib/mail/mail-runner.d.ts +30 -0
- package/dist/lib/mail/mail-runner.js +108 -3
- package/dist/lib/storage/file-storage.js +2 -7
- package/dist/routes/api/v1/mail/index.js +4 -1
- package/dist/routes/api/v1/mail/route.d.ts +42 -0
- package/dist/routes/api/v1/mail/route.js +78 -0
- package/dist/routes/api/v1/slack/route.d.ts +6 -6
- package/dist/routes/api/v1/tasks/[id]/route.d.ts +2 -236
- package/dist/routes/api/v1/tasks/route.d.ts +2 -236
- package/dist/routes/api/v1/tasks/route.js +2 -8
- package/package.json +4 -4
- package/static/assets/{ActivityPage-BwJ7fLWq.js → ActivityPage-Ch44od-j.js} +1 -1
- package/static/assets/{ApiKeysSettingsPage-mKPYHrbG.js → ApiKeysSettingsPage-DuT2DLgr.js} +2 -2
- package/static/assets/{ArchitectureEditPage-CnF2W_T8.js → ArchitectureEditPage-DvJkcnEG.js} +1 -1
- package/static/assets/{ArchitecturePage-BaGE12Uz.js → ArchitecturePage-DqSclgRT.js} +1 -1
- package/static/assets/{AuthSettingsPage-B1_TL7WY.js → AuthSettingsPage-yM2zFEcv.js} +2 -2
- package/static/assets/{CallbackPage-Byf97nZK.js → CallbackPage-Bytr8RS8.js} +1 -1
- package/static/assets/{CodePage-C0hGkcdC.js → CodePage-BlGPi7uk.js} +1 -1
- package/static/assets/{CollapsibleSection-BTQLspUE.js → CollapsibleSection-irzuq21b.js} +1 -1
- package/static/assets/{DashboardPage-YArLaSEp.js → DashboardPage-DdA0uFZr.js} +1 -1
- package/static/assets/{GitPage-6DGf2Yb2.js → GitPage-Cl_rMV7q.js} +1 -1
- package/static/assets/{GitSettingsPage-BPFC022b.js → GitSettingsPage-B6bQRTLV.js} +1 -1
- package/static/assets/{IdentityPage-BdLn29tv.js → IdentityPage-CTsJJ_nR.js} +1 -1
- package/static/assets/{ImplementationStepsEditor-nSp4uTSC.js → ImplementationStepsEditor-D1q30m-M.js} +2 -2
- package/static/assets/{IntegrationsSettingsPage-C-Xqzlyi.js → IntegrationsSettingsPage-au7RbHgk.js} +1 -1
- package/static/assets/{JobDetailPage-DlFsVN9_.js → JobDetailPage-CDRH2EOg.js} +1 -1
- package/static/assets/KnowledgeDetailPage-DpvktyWP.js +1 -0
- package/static/assets/{KnowledgeEditPage-Dx68IG0a.js → KnowledgeEditPage-bHrMagf9.js} +1 -1
- package/static/assets/KnowledgePage-CHu-yTF2.js +3 -0
- package/static/assets/{LoginPage-Cea--t3a.js → LoginPage-Dxep5Whg.js} +1 -1
- package/static/assets/MailInboxPage-3enQ9yud.js +1 -0
- package/static/assets/MailProcessingModal-BN-hk7rN.js +6 -0
- package/static/assets/MailReadPage-Dg6oDlFh.js +1 -0
- package/static/assets/{MailSentPage-DveMCrm1.js → MailSentPage-Dig5IXdR.js} +1 -1
- package/static/assets/McpSettingsPage-CNwqGqLg.js +1 -0
- package/static/assets/{NewKnowledgePage-D_u_1sQi.js → NewKnowledgePage-Czxn4P1j.js} +1 -1
- package/static/assets/{NewSkillPage-DqibSZhY.js → NewSkillPage-CqaO2xNS.js} +1 -1
- package/static/assets/{NewTaskPage-DWbH-3Vk.js → NewTaskPage-CYITUYtu.js} +2 -2
- package/static/assets/NotFoundPage-BEQ3ZHqV.js +6 -0
- package/static/assets/{NotificationsSettingsPage-CL0ph697.js → NotificationsSettingsPage-HuOKal9l.js} +1 -1
- package/static/assets/{ProjectEditPage-BbN-CUvi.js → ProjectEditPage-CeHWqhRX.js} +1 -1
- package/static/assets/{ProjectPage-sepCO80y.js → ProjectPage-YTFg8Fkd.js} +1 -1
- package/static/assets/{PromptsSettingsPage-Cif2VMDl.js → PromptsSettingsPage-DPTo5b4l.js} +1 -1
- package/static/assets/{ResourceDetailPage-xHcmXDDt.js → ResourceDetailPage-CA_ZCk6v.js} +1 -1
- package/static/assets/{ResourcesPage-CJC07ag1.js → ResourcesPage-6kcr9x0O.js} +1 -1
- package/static/assets/RoleEditPage-CULuINfL.js +13 -0
- package/static/assets/{RolePage-qxwbXbGA.js → RolePage-BhJl9l-G.js} +1 -1
- package/static/assets/{RulesSettingsPage-BtrNsENs.js → RulesSettingsPage-CYhp9PHk.js} +3 -3
- package/static/assets/SchedulePage-vUZaPVX6.js +4 -0
- package/static/assets/{SkillDetailPage-DO67DAR3.js → SkillDetailPage-BT1Gp3Hh.js} +1 -1
- package/static/assets/{SkillEditPage-QvIWlVgE.js → SkillEditPage-CV2BMeF_.js} +1 -1
- package/static/assets/{SkillsPage-BLJFdLWk.js → SkillsPage-fT1CoBCE.js} +2 -2
- package/static/assets/{SkillsSettingsPage-BKArD_RN.js → SkillsSettingsPage-TiwaPPcd.js} +1 -1
- package/static/assets/{SourceInput-DRz0yu8C.js → SourceInput-B790vfwY.js} +1 -1
- package/static/assets/{TagInput-BJbcCU-Z.js → TagInput-Btfjq6aa.js} +1 -1
- package/static/assets/TaskDetailPage-BMGupUYM.js +16 -0
- package/static/assets/{TaskEditPage-BigoTtEt.js → TaskEditPage-CQz9UIZL.js} +1 -1
- package/static/assets/TasksPage-NbDKSkOe.js +17 -0
- package/static/assets/{TerminalPage-CmcMWc-0.js → TerminalPage-CQLCoRdq.js} +1 -1
- package/static/assets/{TerminalSessionPage-BD85W3Y8.js → TerminalSessionPage-doL1BiJi.js} +1 -1
- package/static/assets/{UserPreferencesPage-Cir8iHV7.js → UserPreferencesPage-D2CiwL2m.js} +1 -1
- package/static/assets/UserSettingsPage-iSTGwM80.js +1 -0
- package/static/assets/{UtilitiesPage-eit9YbF2.js → UtilitiesPage-B-ZW4kdp.js} +1 -1
- package/static/assets/{alert-y_ZN3v8G.js → alert-15F3-9XX.js} +1 -1
- package/static/assets/{arrow-down-CDO_FBBg.js → arrow-down-BrqEvvfv.js} +1 -1
- package/static/assets/{arrow-left-DSdiSF-4.js → arrow-left-CaqvCoIB.js} +1 -1
- package/static/assets/{arrow-up-DD3J0gOT.js → arrow-up-DNzaGmlT.js} +1 -1
- package/static/assets/arrow-up-down-DCe7-ihF.js +6 -0
- package/static/assets/{badge-DEdGwxT7.js → badge-BnmevczT.js} +1 -1
- package/static/assets/{browser-modal-DmW_vKAc.js → browser-modal-ChaWEpHZ.js} +1 -1
- package/static/assets/{card-D2IL9dFO.js → card-NkV5eOu8.js} +1 -1
- package/static/assets/{chevron-left-C6c6KPNR.js → chevron-left-Blz556B2.js} +1 -1
- package/static/assets/{chevron-up-85UlHYRP.js → chevron-up-rbFu97ce.js} +1 -1
- package/static/assets/{chevrons-up-BRQ6LS9m.js → chevrons-up-BQMlE7rT.js} +1 -1
- package/static/assets/{circle-alert-DS3JTzTX.js → circle-alert-B_3aezfy.js} +1 -1
- package/static/assets/{circle-check-BYnFgi54.js → circle-check-Di9E8LZ0.js} +1 -1
- package/static/assets/{circle-check-big-CY4XVZX5.js → circle-check-big-DeInZUEL.js} +1 -1
- package/static/assets/{circle-play-DZRonULa.js → circle-play-_KPAQa5u.js} +1 -1
- package/static/assets/{circle-x-y-VLhhlk.js → circle-x-Dqvz_3qq.js} +1 -1
- package/static/assets/{clipboard-BgAFTdDB.js → clipboard-CbMUHSIJ.js} +1 -1
- package/static/assets/{clock-BSV-PWC8.js → clock-DYK-k9QO.js} +1 -1
- package/static/assets/{download-BAwvn93i.js → download-DvfDST0e.js} +1 -1
- package/static/assets/{external-link-CUVrRJUy.js → external-link-4402xHJm.js} +1 -1
- package/static/assets/{eye-B0ROJhbz.js → eye-C96SnuaK.js} +1 -1
- package/static/assets/{folder-git-2-sZcm0AKa.js → folder-git-2-DM9e4LLF.js} +1 -1
- package/static/assets/index-DIPJXXxG.css +2 -0
- package/static/assets/{index-Dg1fqsBK.js → index-SVcL57hQ.js} +98 -98
- package/static/assets/{info-DaYx3WZu.js → info-C4HFkLJI.js} +1 -1
- package/static/assets/label-MGLxVQcy.js +1 -0
- package/static/assets/{markdown-editor-BjPIrCIB.js → markdown-editor-8DjKwEtI.js} +1 -1
- package/static/assets/{message-square-C4zc7NY1.js → message-square-C3VNiI6M.js} +1 -1
- package/static/assets/{paperclip-DjxwDxFr.js → paperclip-o6t1e21X.js} +1 -1
- package/static/assets/{pause-CnhJnDBC.js → pause-pAcTJVOC.js} +1 -1
- package/static/assets/{play-CqmnqjTk.js → play-Dn69nfRB.js} +1 -1
- package/static/assets/{radio-group-DYfSGjrJ.js → radio-group-C_JhFin5.js} +1 -1
- package/static/assets/{refresh-cw-Bph91vei.js → refresh-cw-oOjEruv4.js} +1 -1
- package/static/assets/{search-pTEzH58w.js → search-Ck3r4Ru-.js} +1 -1
- package/static/assets/{select-B2bDLBT8.js → select-DY8bp_yH.js} +1 -1
- package/static/assets/{switch-CUtIrWkC.js → switch-CyhPMHQO.js} +1 -1
- package/static/assets/{tabs-NT4Nw7xd.js → tabs-Cjt4N6XC.js} +1 -1
- package/static/assets/{tag-BGmTkjx-.js → tag-CajsrbmJ.js} +1 -1
- package/static/assets/{terminal-preview-BwYbZ-N2.js → terminal-preview-DkoSzVhy.js} +1 -1
- package/static/assets/{use-terminal-D_zORiG8.js → use-terminal-CJMIUQKK.js} +1 -1
- package/static/assets/{video-CdNAQkyo.js → video-Db8h41sP.js} +1 -1
- package/static/assets/{zap-BRkfEy3x.js → zap-BQyXK_jX.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/KnowledgeDetailPage-CSdmwigy.js +0 -1
- package/static/assets/KnowledgePage-BJqb3hbW.js +0 -8
- package/static/assets/MailInboxPage-CsJtIvkf.js +0 -1
- package/static/assets/MailReadPage-DMLvEBZ6.js +0 -1
- package/static/assets/McpSettingsPage-D5YFsGWq.js +0 -1
- package/static/assets/RoleEditPage-C_k6HckV.js +0 -13
- package/static/assets/SchedulePage-vjKLtnVK.js +0 -4
- package/static/assets/TaskDetailPage-Dcerr70C.js +0 -1
- package/static/assets/TasksPage-BfNWUfKe.js +0 -17
- package/static/assets/UserSettingsPage-B_nleEc5.js +0 -1
- package/static/assets/index-CkH7-cOr.css +0 -2
- package/static/assets/label-xXCWeKDL.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|