@beignet/cli 0.0.44 → 0.0.46
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/CHANGELOG.md +25 -0
- package/README.md +78 -16
- package/dist/choices.d.ts +5 -1
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +12 -0
- package/dist/choices.js.map +1 -1
- package/dist/db.d.ts +4 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +12 -6
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +598 -62
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +4 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +356 -5
- package/dist/mcp.js.map +1 -1
- package/dist/operational-lifecycle.d.ts +12 -0
- package/dist/operational-lifecycle.d.ts.map +1 -0
- package/dist/operational-lifecycle.js +39 -0
- package/dist/operational-lifecycle.js.map +1 -0
- package/dist/operational-path.d.ts +3 -0
- package/dist/operational-path.d.ts.map +1 -0
- package/dist/operational-path.js +26 -0
- package/dist/operational-path.js.map +1 -0
- package/dist/operational-process.d.ts +78 -0
- package/dist/operational-process.d.ts.map +1 -0
- package/dist/operational-process.js +228 -0
- package/dist/operational-process.js.map +1 -0
- package/dist/operational-runner.d.ts +2 -0
- package/dist/operational-runner.d.ts.map +1 -0
- package/dist/operational-runner.js +168 -0
- package/dist/operational-runner.js.map +1 -0
- package/dist/outbox.d.ts +14 -6
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +140 -124
- package/dist/outbox.js.map +1 -1
- package/dist/schedule.d.ts +2 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +79 -81
- package/dist/schedule.js.map +1 -1
- package/dist/task.d.ts +2 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +57 -61
- package/dist/task.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +32 -8
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +9 -2
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shadcn.d.ts.map +1 -1
- package/dist/templates/shadcn.js +3 -1
- package/dist/templates/shadcn.js.map +1 -1
- package/dist/templates/shared.js +1 -1
- package/package.json +2 -2
- package/skills/app-structure/SKILL.md +26 -7
- package/src/choices.ts +22 -0
- package/src/db.ts +12 -6
- package/src/index.ts +19 -16
- package/src/inspect.ts +844 -67
- package/src/lib.ts +27 -1
- package/src/mcp.ts +459 -4
- package/src/operational-lifecycle.ts +56 -0
- package/src/operational-path.ts +35 -0
- package/src/operational-process.ts +454 -0
- package/src/operational-runner.ts +221 -0
- package/src/outbox.ts +154 -128
- package/src/schedule.ts +84 -89
- package/src/task.ts +58 -62
- package/src/templates/agents.ts +32 -8
- package/src/templates/server.ts +9 -2
- package/src/templates/shadcn.ts +3 -1
- package/src/templates/shared.ts +1 -1
package/src/outbox.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { ErrorReporterPort } from "@beignet/core/error-reporting";
|
|
4
4
|
import type {
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
flushOperationalErrorReporter,
|
|
17
17
|
reportOperationalFailure,
|
|
18
18
|
} from "./operational-error-reporting.js";
|
|
19
|
+
import { runWithOperationalCleanup } from "./operational-lifecycle.js";
|
|
20
|
+
import { resolveAppOperationalModulePath } from "./operational-path.js";
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Options for running one bounded outbox drain pass.
|
|
@@ -126,10 +128,19 @@ export type RunOutboxRequeueResult = {
|
|
|
126
128
|
durationMs: number;
|
|
127
129
|
};
|
|
128
130
|
|
|
129
|
-
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
/** Result returned by `beignet outbox purge`. */
|
|
132
|
+
export type RunOutboxPurgeResult = {
|
|
133
|
+
schemaVersion: 1;
|
|
134
|
+
cwd: string;
|
|
135
|
+
modulePath: string;
|
|
136
|
+
dryRun: boolean;
|
|
137
|
+
matched: number;
|
|
138
|
+
deleted: number;
|
|
139
|
+
durationMs: number;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/** Result returned by `beignet outbox prune`. */
|
|
143
|
+
export type RunOutboxPruneResult = {
|
|
133
144
|
schemaVersion: 1;
|
|
134
145
|
cwd: string;
|
|
135
146
|
modulePath: string;
|
|
@@ -222,115 +233,122 @@ export async function runOutboxDrain(
|
|
|
222
233
|
: undefined;
|
|
223
234
|
const ctx = assertOutboxDrainContext(rawContext, modulePath);
|
|
224
235
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
236
|
+
return runWithOperationalCleanup({
|
|
237
|
+
operation: "Outbox drain",
|
|
238
|
+
cleanupLabel: "stopOutboxDrainContext",
|
|
239
|
+
run: async () => {
|
|
240
|
+
try {
|
|
241
|
+
// Loaded lazily so CLI commands that never touch the app runtime, such
|
|
242
|
+
// as `beignet lint`, work without a built @beignet/core.
|
|
243
|
+
const { drainOutbox } = await import("@beignet/core/outbox");
|
|
244
|
+
const result = await drainOutbox({
|
|
245
|
+
outbox: ctx.ports.outbox,
|
|
246
|
+
registry,
|
|
247
|
+
eventBus: ctx.ports.eventBus,
|
|
248
|
+
jobs: ctx.ports.jobs,
|
|
249
|
+
batchSize,
|
|
250
|
+
instrumentation: ctx.ports.instrumentation ?? ctx.ports.devtools,
|
|
251
|
+
instrumentationContext: {
|
|
252
|
+
requestId: ctx.requestId,
|
|
253
|
+
traceId: ctx.traceId,
|
|
254
|
+
},
|
|
255
|
+
onError(error, message) {
|
|
256
|
+
ctx.ports.logger?.error("Outbox delivery failed", {
|
|
257
|
+
error,
|
|
258
|
+
outboxMessageId: message.id,
|
|
259
|
+
kind: message.kind,
|
|
260
|
+
name: message.name,
|
|
261
|
+
attempts: message.attempts,
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
onDeadLetter(error, message) {
|
|
265
|
+
return reportOperationalFailure({
|
|
266
|
+
ctx,
|
|
267
|
+
error,
|
|
268
|
+
reportOptions: {
|
|
269
|
+
level: "error",
|
|
270
|
+
mechanism: "beignet.outbox.cli",
|
|
271
|
+
handled: false,
|
|
272
|
+
tags: {
|
|
273
|
+
"beignet.kind": "outbox",
|
|
274
|
+
"beignet.outbox.kind": message.kind,
|
|
275
|
+
"beignet.outbox.name": message.name,
|
|
276
|
+
"beignet.outbox.outcome": "deadLettered",
|
|
277
|
+
},
|
|
278
|
+
contexts: {
|
|
279
|
+
outbox: {
|
|
280
|
+
messageId: message.id,
|
|
281
|
+
kind: message.kind,
|
|
282
|
+
name: message.name,
|
|
283
|
+
attempts: message.attempts,
|
|
284
|
+
maxAttempts: message.maxAttempts,
|
|
285
|
+
outcome: "deadLettered",
|
|
286
|
+
},
|
|
287
|
+
},
|
|
271
288
|
},
|
|
272
|
-
}
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
onSettlementError(settlementError, message) {
|
|
292
|
+
return reportOperationalFailure({
|
|
293
|
+
ctx,
|
|
294
|
+
error: settlementError,
|
|
295
|
+
reportOptions: {
|
|
296
|
+
level: "error",
|
|
297
|
+
mechanism: "beignet.outbox.cli",
|
|
298
|
+
handled: false,
|
|
299
|
+
tags: {
|
|
300
|
+
"beignet.kind": "outbox",
|
|
301
|
+
"beignet.outbox.kind": message.kind,
|
|
302
|
+
"beignet.outbox.name": message.name,
|
|
303
|
+
"beignet.outbox.outcome": "settlementFailed",
|
|
304
|
+
},
|
|
305
|
+
contexts: {
|
|
306
|
+
outbox: {
|
|
307
|
+
messageId: message.id,
|
|
308
|
+
kind: message.kind,
|
|
309
|
+
name: message.name,
|
|
310
|
+
attempts: message.attempts,
|
|
311
|
+
maxAttempts: message.maxAttempts,
|
|
312
|
+
outcome: "settlementFailed",
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
});
|
|
273
317
|
},
|
|
274
318
|
});
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
319
|
+
|
|
320
|
+
await recordOutboxDrain(ctx, result);
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
schemaVersion: 1,
|
|
324
|
+
cwd,
|
|
325
|
+
modulePath,
|
|
326
|
+
result,
|
|
327
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
328
|
+
};
|
|
329
|
+
} catch (error) {
|
|
330
|
+
await reportOperationalFailure({
|
|
278
331
|
ctx,
|
|
279
|
-
error
|
|
332
|
+
error,
|
|
280
333
|
reportOptions: {
|
|
281
334
|
level: "error",
|
|
282
335
|
mechanism: "beignet.outbox.cli",
|
|
283
336
|
handled: false,
|
|
284
337
|
tags: {
|
|
285
338
|
"beignet.kind": "outbox",
|
|
286
|
-
"beignet.outbox.
|
|
287
|
-
"beignet.outbox.name": message.name,
|
|
288
|
-
"beignet.outbox.outcome": "settlementFailed",
|
|
289
|
-
},
|
|
290
|
-
contexts: {
|
|
291
|
-
outbox: {
|
|
292
|
-
messageId: message.id,
|
|
293
|
-
kind: message.kind,
|
|
294
|
-
name: message.name,
|
|
295
|
-
attempts: message.attempts,
|
|
296
|
-
maxAttempts: message.maxAttempts,
|
|
297
|
-
outcome: "settlementFailed",
|
|
298
|
-
},
|
|
339
|
+
"beignet.outbox.outcome": "drainFailed",
|
|
299
340
|
},
|
|
341
|
+
contexts: { outbox: { outcome: "drainFailed" } },
|
|
300
342
|
},
|
|
301
343
|
});
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
modulePath,
|
|
311
|
-
result,
|
|
312
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
313
|
-
};
|
|
314
|
-
} catch (error) {
|
|
315
|
-
await reportOperationalFailure({
|
|
316
|
-
ctx,
|
|
317
|
-
error,
|
|
318
|
-
reportOptions: {
|
|
319
|
-
level: "error",
|
|
320
|
-
mechanism: "beignet.outbox.cli",
|
|
321
|
-
handled: false,
|
|
322
|
-
tags: {
|
|
323
|
-
"beignet.kind": "outbox",
|
|
324
|
-
"beignet.outbox.outcome": "drainFailed",
|
|
325
|
-
},
|
|
326
|
-
contexts: { outbox: { outcome: "drainFailed" } },
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
throw error;
|
|
330
|
-
} finally {
|
|
331
|
-
await flushOperationalErrorReporter(ctx);
|
|
332
|
-
await outboxModule.stopOutboxDrainContext?.(ctx, contextArgs);
|
|
333
|
-
}
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
cleanup: async () => {
|
|
348
|
+
await flushOperationalErrorReporter(ctx);
|
|
349
|
+
await outboxModule.stopOutboxDrainContext?.(ctx, contextArgs);
|
|
350
|
+
},
|
|
351
|
+
});
|
|
334
352
|
}
|
|
335
353
|
|
|
336
354
|
/**
|
|
@@ -403,7 +421,7 @@ export async function runOutboxRequeue(
|
|
|
403
421
|
*/
|
|
404
422
|
export async function runOutboxPurge(
|
|
405
423
|
options: RunOutboxPurgeOptions = {},
|
|
406
|
-
): Promise<
|
|
424
|
+
): Promise<RunOutboxPurgeResult> {
|
|
407
425
|
if (!options.before && !options.all) {
|
|
408
426
|
throw new Error(
|
|
409
427
|
"Pass --before <date> to purge old dead-lettered messages, or pass --all to purge every dead-lettered message.",
|
|
@@ -437,7 +455,7 @@ export async function runOutboxPurge(
|
|
|
437
455
|
*/
|
|
438
456
|
export async function runOutboxPrune(
|
|
439
457
|
options: RunOutboxPruneOptions,
|
|
440
|
-
): Promise<
|
|
458
|
+
): Promise<RunOutboxPruneResult> {
|
|
441
459
|
return withOutboxAdminContext(options, "prune", async ({ admin, base }) => {
|
|
442
460
|
const query = {
|
|
443
461
|
status: "delivered" as const,
|
|
@@ -482,30 +500,37 @@ async function withOutboxAdminContext<T extends object>(
|
|
|
482
500
|
? await outboxModule.createOutboxAdminContext(contextArgs)
|
|
483
501
|
: await createFallbackOutboxAdminContext(outboxModule);
|
|
484
502
|
const ctx = assertOutboxAdminContext(rawContext, modulePath);
|
|
485
|
-
const admin = resolveOutboxAdminPort(ctx, modulePath);
|
|
486
503
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
if (outboxModule.stopOutboxAdminContext) {
|
|
502
|
-
await outboxModule.stopOutboxAdminContext(ctx, contextArgs);
|
|
503
|
-
} else {
|
|
504
|
-
await outboxModule.stopOutboxDrainContext?.(ctx, {
|
|
505
|
-
registry: maybeOutboxRegistry(outboxModule.outboxRegistry),
|
|
504
|
+
return runWithOperationalCleanup({
|
|
505
|
+
operation: `Outbox ${operation}`,
|
|
506
|
+
cleanupLabel: outboxModule.stopOutboxAdminContext
|
|
507
|
+
? "stopOutboxAdminContext"
|
|
508
|
+
: "stopOutboxDrainContext",
|
|
509
|
+
run: async () => {
|
|
510
|
+
const admin = resolveOutboxAdminPort(ctx, modulePath);
|
|
511
|
+
const result = await run({
|
|
512
|
+
admin,
|
|
513
|
+
base: {
|
|
514
|
+
schemaVersion: 1,
|
|
515
|
+
cwd,
|
|
516
|
+
modulePath,
|
|
517
|
+
},
|
|
506
518
|
});
|
|
507
|
-
|
|
508
|
-
|
|
519
|
+
return {
|
|
520
|
+
...result,
|
|
521
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
522
|
+
};
|
|
523
|
+
},
|
|
524
|
+
cleanup: async () => {
|
|
525
|
+
if (outboxModule.stopOutboxAdminContext) {
|
|
526
|
+
await outboxModule.stopOutboxAdminContext(ctx, contextArgs);
|
|
527
|
+
} else {
|
|
528
|
+
await outboxModule.stopOutboxDrainContext?.(ctx, {
|
|
529
|
+
registry: maybeOutboxRegistry(outboxModule.outboxRegistry),
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
});
|
|
509
534
|
}
|
|
510
535
|
|
|
511
536
|
async function createFallbackOutboxAdminContext(
|
|
@@ -521,10 +546,11 @@ async function loadOutboxModule(
|
|
|
521
546
|
cwd: string,
|
|
522
547
|
modulePath: string,
|
|
523
548
|
): Promise<OutboxModule> {
|
|
524
|
-
|
|
549
|
+
let absolutePath: string;
|
|
525
550
|
try {
|
|
526
|
-
await
|
|
527
|
-
} catch {
|
|
551
|
+
absolutePath = await resolveAppOperationalModulePath(cwd, modulePath);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
528
554
|
throw new Error(
|
|
529
555
|
`Could not find app outbox registry at ${modulePath}. Create server/outbox.ts or configure paths.outbox in beignet.config.ts.`,
|
|
530
556
|
);
|
package/src/schedule.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { ErrorReporterPort } from "@beignet/core/error-reporting";
|
|
4
4
|
import type { ProviderInstrumentationPort } from "@beignet/core/providers";
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
flushOperationalErrorReporter,
|
|
14
14
|
reportOperationalFailure,
|
|
15
15
|
} from "./operational-error-reporting.js";
|
|
16
|
+
import { runWithOperationalCleanup } from "./operational-lifecycle.js";
|
|
17
|
+
import { resolveAppOperationalModulePath } from "./operational-path.js";
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Options for running one app-owned schedule.
|
|
@@ -21,7 +23,8 @@ export type RunAppScheduleOptions = {
|
|
|
21
23
|
name: string;
|
|
22
24
|
cwd?: string;
|
|
23
25
|
modulePath?: string;
|
|
24
|
-
payload
|
|
26
|
+
/** Pre-parsed payload validated by the registered schedule schema. */
|
|
27
|
+
payload?: unknown;
|
|
25
28
|
id?: string;
|
|
26
29
|
attempt?: number;
|
|
27
30
|
scheduledAt?: string;
|
|
@@ -106,91 +109,97 @@ export async function runAppSchedule(
|
|
|
106
109
|
: {};
|
|
107
110
|
const scheduleContext = toScheduleContext(ctx);
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
},
|
|
128
|
-
onHookError({ error, hook }) {
|
|
129
|
-
scheduleContext.ports?.logger?.warn?.(
|
|
130
|
-
"Schedule lifecycle hook failed",
|
|
131
|
-
{
|
|
112
|
+
return runWithOperationalCleanup({
|
|
113
|
+
operation: `Schedule "${schedule.name}"`,
|
|
114
|
+
cleanupLabel: "stopScheduleContext",
|
|
115
|
+
run: async () => {
|
|
116
|
+
// Loaded lazily so CLI commands that never touch the app runtime, such as
|
|
117
|
+
// `beignet lint`, work without a built @beignet/core.
|
|
118
|
+
const { createInlineScheduleRunner } = await import(
|
|
119
|
+
"@beignet/core/schedules"
|
|
120
|
+
);
|
|
121
|
+
const runner = createInlineScheduleRunner<unknown>({
|
|
122
|
+
ctx,
|
|
123
|
+
instrumentation: scheduleContext.ports,
|
|
124
|
+
instrumentationContext: {
|
|
125
|
+
requestId: scheduleContext.requestId,
|
|
126
|
+
traceId: scheduleContext.traceId,
|
|
127
|
+
},
|
|
128
|
+
onError({ error }) {
|
|
129
|
+
scheduleContext.ports?.logger?.error("Schedule failed", {
|
|
132
130
|
error,
|
|
133
|
-
hook,
|
|
134
131
|
scheduleName: schedule.name,
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
ctx: scheduleContext,
|
|
145
|
-
error,
|
|
146
|
-
reportOptions: {
|
|
147
|
-
level: "error",
|
|
148
|
-
mechanism: "beignet.schedule.cli",
|
|
149
|
-
handled: false,
|
|
150
|
-
tags: {
|
|
151
|
-
"beignet.kind": "schedule",
|
|
152
|
-
"beignet.schedule": schedule.name,
|
|
153
|
-
},
|
|
154
|
-
contexts: {
|
|
155
|
-
schedule: {
|
|
156
|
-
name: schedule.name,
|
|
157
|
-
source: runOptions.source ?? "beignet-cli",
|
|
158
|
-
attempt: runOptions.attempt ?? null,
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
onHookError({ error, hook }) {
|
|
135
|
+
scheduleContext.ports?.logger?.warn?.(
|
|
136
|
+
"Schedule lifecycle hook failed",
|
|
137
|
+
{
|
|
138
|
+
error,
|
|
139
|
+
hook,
|
|
140
|
+
scheduleName: schedule.name,
|
|
159
141
|
},
|
|
160
|
-
|
|
142
|
+
);
|
|
161
143
|
},
|
|
162
144
|
});
|
|
163
|
-
throw error;
|
|
164
|
-
}
|
|
165
145
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
146
|
+
try {
|
|
147
|
+
await runner.run(schedule, runOptions);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
await reportOperationalFailure({
|
|
150
|
+
ctx: scheduleContext,
|
|
151
|
+
error,
|
|
152
|
+
reportOptions: {
|
|
153
|
+
level: "error",
|
|
154
|
+
mechanism: "beignet.schedule.cli",
|
|
155
|
+
handled: false,
|
|
156
|
+
tags: {
|
|
157
|
+
"beignet.kind": "schedule",
|
|
158
|
+
"beignet.schedule": schedule.name,
|
|
159
|
+
},
|
|
160
|
+
contexts: {
|
|
161
|
+
schedule: {
|
|
162
|
+
name: schedule.name,
|
|
163
|
+
source: runOptions.source ?? "beignet-cli",
|
|
164
|
+
attempt: runOptions.attempt ?? null,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
schemaVersion: 1,
|
|
174
|
+
name: schedule.name,
|
|
175
|
+
cwd,
|
|
176
|
+
modulePath,
|
|
177
|
+
run: {
|
|
178
|
+
id: runOptions.id,
|
|
179
|
+
attempt: runOptions.attempt,
|
|
180
|
+
scheduledAt: stringifyDateInput(runOptions.scheduledAt),
|
|
181
|
+
triggeredAt: stringifyDateInput(runOptions.triggeredAt),
|
|
182
|
+
source: runOptions.source ?? "beignet-cli",
|
|
183
|
+
},
|
|
184
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
cleanup: async () => {
|
|
188
|
+
await flushOperationalErrorReporter(scheduleContext);
|
|
189
|
+
await scheduleModule.stopScheduleContext?.(ctx, contextArgs);
|
|
190
|
+
},
|
|
191
|
+
});
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
async function loadScheduleModule(
|
|
187
195
|
cwd: string,
|
|
188
196
|
modulePath: string,
|
|
189
197
|
): Promise<ScheduleModule> {
|
|
190
|
-
|
|
198
|
+
let absolutePath: string;
|
|
191
199
|
try {
|
|
192
|
-
await
|
|
193
|
-
} catch {
|
|
200
|
+
absolutePath = await resolveAppOperationalModulePath(cwd, modulePath);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
194
203
|
throw new Error(
|
|
195
204
|
`Could not find app schedule registry at ${modulePath}. Create server/schedules.ts or configure paths.schedules in beignet.config.ts.`,
|
|
196
205
|
);
|
|
@@ -213,7 +222,7 @@ function buildScheduleRunOptions(
|
|
|
213
222
|
};
|
|
214
223
|
|
|
215
224
|
if (options.payload !== undefined) {
|
|
216
|
-
runOptions.payload =
|
|
225
|
+
runOptions.payload = options.payload;
|
|
217
226
|
}
|
|
218
227
|
if (options.id !== undefined) runOptions.id = options.id;
|
|
219
228
|
if (options.attempt !== undefined) runOptions.attempt = options.attempt;
|
|
@@ -223,20 +232,6 @@ function buildScheduleRunOptions(
|
|
|
223
232
|
return runOptions;
|
|
224
233
|
}
|
|
225
234
|
|
|
226
|
-
function parseSchedulePayloadFlag(
|
|
227
|
-
input: NonNullable<RunAppScheduleOptions["payload"]>,
|
|
228
|
-
): unknown {
|
|
229
|
-
if (typeof input !== "string") return input;
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
return JSON.parse(input) as unknown;
|
|
233
|
-
} catch (error) {
|
|
234
|
-
throw new Error(
|
|
235
|
-
`Invalid --payload JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
235
|
function findSchedule(
|
|
241
236
|
schedules: readonly unknown[] | undefined,
|
|
242
237
|
name: string,
|