@beignet/cli 0.0.3 → 0.0.4
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 +205 -0
- package/README.md +379 -61
- package/dist/ansi.d.ts +10 -0
- package/dist/ansi.d.ts.map +1 -0
- package/dist/ansi.js +20 -0
- package/dist/ansi.js.map +1 -0
- package/dist/choices.d.ts +72 -0
- package/dist/choices.d.ts.map +1 -0
- package/dist/choices.js +88 -0
- package/dist/choices.js.map +1 -0
- package/dist/completion.d.ts +47 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +123 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/create-prompts.d.ts +42 -0
- package/dist/create-prompts.d.ts.map +1 -0
- package/dist/create-prompts.js +136 -0
- package/dist/create-prompts.js.map +1 -0
- package/dist/create.d.ts +4 -1
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +16 -26
- package/dist/create.js.map +1 -1
- package/dist/db.d.ts +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +37 -2
- package/dist/db.js.map +1 -1
- package/dist/github-annotations.d.ts +18 -0
- package/dist/github-annotations.d.ts.map +1 -0
- package/dist/github-annotations.js +22 -0
- package/dist/github-annotations.js.map +1 -0
- package/dist/index.d.ts +1 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +657 -588
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +21 -2
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +1938 -131
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +20 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +17 -0
- package/dist/lib.js.map +1 -0
- package/dist/lint.d.ts +10 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +340 -33
- package/dist/lint.js.map +1 -1
- package/dist/make.d.ts +20 -3
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +1756 -394
- package/dist/make.js.map +1 -1
- package/dist/outbox.d.ts +24 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +138 -0
- package/dist/outbox.js.map +1 -0
- package/dist/schedule.d.ts +36 -0
- package/dist/schedule.d.ts.map +1 -0
- package/dist/schedule.js +155 -0
- package/dist/schedule.js.map +1 -0
- package/dist/task.d.ts +26 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +106 -0
- package/dist/task.js.map +1 -0
- package/dist/templates.d.ts +3 -32
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +1002 -527
- package/dist/templates.js.map +1 -1
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +18 -0
- package/dist/version.js.map +1 -0
- package/package.json +9 -8
- package/src/ansi.ts +30 -0
- package/src/choices.ts +137 -0
- package/src/completion.ts +169 -0
- package/src/config.ts +16 -0
- package/src/create-prompts.ts +182 -0
- package/src/create.ts +24 -31
- package/src/db.ts +60 -4
- package/src/github-annotations.ts +37 -0
- package/src/index.ts +1067 -803
- package/src/inspect.ts +2859 -115
- package/src/lib.ts +45 -0
- package/src/lint.ts +493 -39
- package/src/make.ts +2181 -405
- package/src/outbox.ts +249 -0
- package/src/schedule.ts +272 -0
- package/src/task.ts +169 -0
- package/src/templates.ts +1073 -567
- package/src/version.ts +20 -0
- package/dist/create-bin.d.ts +0 -3
- package/dist/create-bin.d.ts.map +0 -1
- package/dist/create-bin.js +0 -9
- package/dist/create-bin.js.map +0 -1
- package/src/create-bin.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { buildApplication, buildCommand, buildRouteMap, run, text_en, } from "@stricli/core";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export { applyDoctorFixes, createProject, formatDoctor, formatLint, formatRoutes, inspectApp, lintApp, makeAdapter, makeContract, makeEvent, makeFactory, makeFeature, makeFeatureAddonChoices, makeJob, makeListener, makeNotification, makePolicy, makePort, makeResource, makeSchedule, makeSeed, makeTest, makeUpload, makeUseCase, runDatabaseCommand, };
|
|
12
|
-
const templateChoices = ["next"];
|
|
13
|
-
const packageManagerChoices = [
|
|
14
|
-
"bun",
|
|
15
|
-
"npm",
|
|
16
|
-
"pnpm",
|
|
17
|
-
"yarn",
|
|
4
|
+
import { buildApplication, buildCommand, buildRouteMap, proposeCompletions, run, text_en, } from "@stricli/core";
|
|
5
|
+
import { completionShellChoices, featureChoices, integrationChoices, makeFeatureAddonChoices, packageManagerChoices, presetChoices, templateChoices, } from "./choices.js";
|
|
6
|
+
import { getCliVersion } from "./version.js";
|
|
7
|
+
const outputFormatChoices = [
|
|
8
|
+
"human",
|
|
9
|
+
"json",
|
|
10
|
+
"github",
|
|
18
11
|
];
|
|
19
12
|
const parseString = (input) => input;
|
|
13
|
+
const parsePositiveInteger = (input) => {
|
|
14
|
+
const value = Number(input);
|
|
15
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
16
|
+
throw new Error("Expected a positive integer.");
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
20
|
const forceFlag = {
|
|
21
21
|
kind: "boolean",
|
|
22
22
|
optional: true,
|
|
@@ -41,18 +41,61 @@ const parsedStringFlag = (brief) => ({
|
|
|
41
41
|
optional: true,
|
|
42
42
|
brief,
|
|
43
43
|
});
|
|
44
|
+
const cwdFlag = parsedStringFlag("App directory to inspect. Defaults to the current working directory.");
|
|
45
|
+
const formatFlag = {
|
|
46
|
+
kind: "enum",
|
|
47
|
+
values: outputFormatChoices,
|
|
48
|
+
optional: true,
|
|
49
|
+
brief: "Output format. Defaults to human, or github when GITHUB_ACTIONS=true.",
|
|
50
|
+
};
|
|
44
51
|
const makeFlagParameters = {
|
|
45
52
|
force: forceFlag,
|
|
46
53
|
dryRun: dryRunFlag,
|
|
47
54
|
json: jsonFlag,
|
|
48
55
|
};
|
|
49
|
-
const
|
|
56
|
+
const routesFlagParameters = {
|
|
57
|
+
json: jsonFlag,
|
|
58
|
+
cwd: cwdFlag,
|
|
59
|
+
};
|
|
60
|
+
const lintFlagParameters = {
|
|
50
61
|
json: jsonFlag,
|
|
62
|
+
cwd: cwdFlag,
|
|
63
|
+
format: formatFlag,
|
|
51
64
|
};
|
|
52
65
|
const dbFlagParameters = {
|
|
53
66
|
json: jsonFlag,
|
|
54
67
|
dryRun: dryRunFlag,
|
|
55
68
|
};
|
|
69
|
+
const taskRunFlagParameters = {
|
|
70
|
+
json: jsonFlag,
|
|
71
|
+
input: parsedStringFlag("JSON input passed to the task schema."),
|
|
72
|
+
module: parsedStringFlag("Task registry module. Defaults to server/tasks.ts."),
|
|
73
|
+
};
|
|
74
|
+
const outboxDrainFlagParameters = {
|
|
75
|
+
json: jsonFlag,
|
|
76
|
+
module: parsedStringFlag("Outbox registry module. Defaults to server/outbox.ts."),
|
|
77
|
+
batchSize: {
|
|
78
|
+
kind: "parsed",
|
|
79
|
+
parse: parsePositiveInteger,
|
|
80
|
+
optional: true,
|
|
81
|
+
brief: "Maximum messages to claim in one drain pass.",
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
const scheduleRunFlagParameters = {
|
|
85
|
+
json: jsonFlag,
|
|
86
|
+
module: parsedStringFlag("Schedule registry module. Defaults to server/schedules.ts."),
|
|
87
|
+
payload: parsedStringFlag("JSON payload passed to the schedule schema."),
|
|
88
|
+
id: parsedStringFlag("Provider or app schedule run ID."),
|
|
89
|
+
attempt: {
|
|
90
|
+
kind: "parsed",
|
|
91
|
+
parse: parsePositiveInteger,
|
|
92
|
+
optional: true,
|
|
93
|
+
brief: "One-based provider attempt number.",
|
|
94
|
+
},
|
|
95
|
+
scheduledAt: parsedStringFlag("Provider scheduled timestamp."),
|
|
96
|
+
triggeredAt: parsedStringFlag("Schedule trigger timestamp."),
|
|
97
|
+
source: parsedStringFlag("Provider or app source label."),
|
|
98
|
+
};
|
|
56
99
|
const namePositional = {
|
|
57
100
|
kind: "tuple",
|
|
58
101
|
parameters: [
|
|
@@ -63,12 +106,29 @@ const namePositional = {
|
|
|
63
106
|
},
|
|
64
107
|
],
|
|
65
108
|
};
|
|
109
|
+
function resolveOutputFormat(flags) {
|
|
110
|
+
if (flags.json) {
|
|
111
|
+
if (flags.format && flags.format !== "json") {
|
|
112
|
+
throw new Error(`--json conflicts with --format ${flags.format}. Pass one of them.`);
|
|
113
|
+
}
|
|
114
|
+
return "json";
|
|
115
|
+
}
|
|
116
|
+
if (flags.format)
|
|
117
|
+
return flags.format;
|
|
118
|
+
return process.env.GITHUB_ACTIONS === "true" ? "github" : "human";
|
|
119
|
+
}
|
|
120
|
+
function useColor() {
|
|
121
|
+
return process.stdout.isTTY === true && !process.env.NO_COLOR;
|
|
122
|
+
}
|
|
66
123
|
const createCommand = buildCommand({
|
|
67
124
|
docs: {
|
|
68
125
|
brief: "Create a new Beignet app.",
|
|
69
126
|
fullDescription: `Available features: ${featureChoices.join(", ")}
|
|
70
127
|
|
|
71
|
-
Available integrations: ${integrationChoices.join(", ")}
|
|
128
|
+
Available integrations: ${integrationChoices.join(", ")}
|
|
129
|
+
|
|
130
|
+
Running create on an interactive terminal without selection flags opens a
|
|
131
|
+
prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
72
132
|
},
|
|
73
133
|
parameters: {
|
|
74
134
|
flags: {
|
|
@@ -81,8 +141,8 @@ Available integrations: ${integrationChoices.join(", ")}`,
|
|
|
81
141
|
preset: {
|
|
82
142
|
kind: "enum",
|
|
83
143
|
values: presetChoices,
|
|
84
|
-
|
|
85
|
-
brief: "Starter preset to generate.",
|
|
144
|
+
optional: true,
|
|
145
|
+
brief: "Starter preset to generate. Defaults to standard.",
|
|
86
146
|
},
|
|
87
147
|
packageManager: {
|
|
88
148
|
kind: "enum",
|
|
@@ -90,35 +150,29 @@ Available integrations: ${integrationChoices.join(", ")}`,
|
|
|
90
150
|
optional: true,
|
|
91
151
|
brief: "Package manager to use in next-step commands.",
|
|
92
152
|
},
|
|
93
|
-
feature: {
|
|
94
|
-
kind: "enum",
|
|
95
|
-
values: featureChoices,
|
|
96
|
-
optional: true,
|
|
97
|
-
variadic: true,
|
|
98
|
-
brief: "Add a starter feature. Repeatable.",
|
|
99
|
-
},
|
|
100
153
|
features: {
|
|
101
154
|
kind: "enum",
|
|
102
155
|
values: featureChoices,
|
|
103
156
|
optional: true,
|
|
104
157
|
variadic: ",",
|
|
105
|
-
brief: "Add comma-separated
|
|
106
|
-
},
|
|
107
|
-
integration: {
|
|
108
|
-
kind: "enum",
|
|
109
|
-
values: integrationChoices,
|
|
110
|
-
optional: true,
|
|
111
|
-
variadic: true,
|
|
112
|
-
brief: "Add a first-party integration. Repeatable.",
|
|
158
|
+
brief: "Add starter features as a comma-separated list.",
|
|
113
159
|
},
|
|
114
160
|
integrations: {
|
|
115
161
|
kind: "enum",
|
|
116
162
|
values: integrationChoices,
|
|
117
163
|
optional: true,
|
|
118
164
|
variadic: ",",
|
|
119
|
-
brief: "Add
|
|
165
|
+
brief: "Add first-party integrations as a comma-separated list.",
|
|
166
|
+
},
|
|
167
|
+
yes: {
|
|
168
|
+
kind: "boolean",
|
|
169
|
+
optional: true,
|
|
170
|
+
withNegated: false,
|
|
171
|
+
brief: "Skip interactive prompts and use the defaults.",
|
|
120
172
|
},
|
|
121
173
|
force: forceFlag,
|
|
174
|
+
dryRun: dryRunFlag,
|
|
175
|
+
json: jsonFlag,
|
|
122
176
|
},
|
|
123
177
|
positional: {
|
|
124
178
|
kind: "tuple",
|
|
@@ -127,28 +181,53 @@ Available integrations: ${integrationChoices.join(", ")}`,
|
|
|
127
181
|
parse: parseString,
|
|
128
182
|
placeholder: "directory",
|
|
129
183
|
brief: "Project directory to create.",
|
|
184
|
+
optional: true,
|
|
130
185
|
},
|
|
131
186
|
],
|
|
132
187
|
},
|
|
133
188
|
},
|
|
134
|
-
async
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
189
|
+
loader: async () => {
|
|
190
|
+
const { createProject } = await import("./create.js");
|
|
191
|
+
const { promptCreateSelections, shouldPromptInteractively } = await import("./create-prompts.js");
|
|
192
|
+
return async function runCreate(flags, directory) {
|
|
193
|
+
let selections = {
|
|
194
|
+
directory,
|
|
195
|
+
preset: flags.preset,
|
|
196
|
+
features: flags.features,
|
|
197
|
+
integrations: flags.integrations,
|
|
198
|
+
packageManager: flags.packageManager,
|
|
199
|
+
};
|
|
200
|
+
const interactive = shouldPromptInteractively({ ...selections, yes: flags.yes }, {
|
|
201
|
+
stdin: process.stdin.isTTY === true,
|
|
202
|
+
stdout: process.stdout.isTTY === true,
|
|
203
|
+
});
|
|
204
|
+
if (interactive) {
|
|
205
|
+
const answers = await promptCreateSelections(selections);
|
|
206
|
+
if (answers === undefined) {
|
|
207
|
+
this.process.stderr.write("Cancelled.\n");
|
|
208
|
+
this.process.exitCode = 2;
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
selections = answers;
|
|
212
|
+
}
|
|
213
|
+
if (selections.directory === undefined) {
|
|
214
|
+
throw new Error("Project directory is required. Pass beignet create <directory>, or run beignet create in an interactive terminal.");
|
|
215
|
+
}
|
|
216
|
+
const integrations = uniqueValues([...(selections.integrations ?? [])]);
|
|
217
|
+
const result = await createProject({
|
|
218
|
+
name: selections.directory,
|
|
219
|
+
template: flags.template,
|
|
220
|
+
preset: selections.preset ?? "standard",
|
|
221
|
+
features: uniqueValues([...(selections.features ?? [])]),
|
|
222
|
+
packageManager: selections.packageManager,
|
|
223
|
+
integrations,
|
|
224
|
+
force: Boolean(flags.force),
|
|
225
|
+
dryRun: Boolean(flags.dryRun),
|
|
226
|
+
});
|
|
227
|
+
writeOutput(this, flags.json
|
|
228
|
+
? JSON.stringify(result, null, 2)
|
|
229
|
+
: nextSteps(result, { integrations }));
|
|
230
|
+
};
|
|
152
231
|
},
|
|
153
232
|
});
|
|
154
233
|
const routesCommand = buildCommand({
|
|
@@ -156,11 +235,14 @@ const routesCommand = buildCommand({
|
|
|
156
235
|
brief: "Inspect registered Beignet routes.",
|
|
157
236
|
},
|
|
158
237
|
parameters: {
|
|
159
|
-
flags:
|
|
238
|
+
flags: routesFlagParameters,
|
|
160
239
|
},
|
|
161
|
-
async
|
|
162
|
-
const
|
|
163
|
-
|
|
240
|
+
loader: async () => {
|
|
241
|
+
const { formatRoutes, inspectApp } = await import("./inspect.js");
|
|
242
|
+
return async function runRoutes(flags) {
|
|
243
|
+
const result = await inspectApp({ cwd: flags.cwd });
|
|
244
|
+
writeOutput(this, flags.json ? JSON.stringify(result, null, 2) : formatRoutes(result));
|
|
245
|
+
};
|
|
164
246
|
},
|
|
165
247
|
});
|
|
166
248
|
const doctorCommand = buildCommand({
|
|
@@ -182,19 +264,35 @@ const doctorCommand = buildCommand({
|
|
|
182
264
|
withNegated: false,
|
|
183
265
|
brief: "Apply low-risk fixes before reporting.",
|
|
184
266
|
},
|
|
267
|
+
cwd: cwdFlag,
|
|
268
|
+
format: formatFlag,
|
|
185
269
|
},
|
|
186
270
|
},
|
|
187
|
-
async
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
271
|
+
loader: async () => {
|
|
272
|
+
const { applyDoctorFixes, formatDoctor, formatDoctorGithub, inspectApp } = await import("./inspect.js");
|
|
273
|
+
return async function runDoctor(flags) {
|
|
274
|
+
const format = resolveOutputFormat(flags);
|
|
275
|
+
const fixes = flags.fix
|
|
276
|
+
? await applyDoctorFixes({
|
|
277
|
+
cwd: flags.cwd,
|
|
278
|
+
strict: Boolean(flags.strict),
|
|
279
|
+
})
|
|
280
|
+
: [];
|
|
281
|
+
const result = await inspectApp({
|
|
282
|
+
cwd: flags.cwd,
|
|
283
|
+
strict: Boolean(flags.strict),
|
|
284
|
+
});
|
|
285
|
+
result.fixes = fixes;
|
|
286
|
+
writeOutput(this, format === "json"
|
|
287
|
+
? JSON.stringify(result, null, 2)
|
|
288
|
+
: format === "github"
|
|
289
|
+
? formatDoctorGithub(result)
|
|
290
|
+
: formatDoctor(result, { color: useColor() }));
|
|
291
|
+
if (result.diagnostics.some((diagnostic) => diagnostic.severity === "error" ||
|
|
292
|
+
(flags.strict && diagnostic.severity === "warning"))) {
|
|
293
|
+
this.process.exitCode = 1;
|
|
294
|
+
}
|
|
295
|
+
};
|
|
198
296
|
},
|
|
199
297
|
});
|
|
200
298
|
const lintCommand = buildCommand({
|
|
@@ -202,14 +300,22 @@ const lintCommand = buildCommand({
|
|
|
202
300
|
brief: "Check Beignet dependency direction conventions.",
|
|
203
301
|
},
|
|
204
302
|
parameters: {
|
|
205
|
-
flags:
|
|
206
|
-
},
|
|
207
|
-
async
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
303
|
+
flags: lintFlagParameters,
|
|
304
|
+
},
|
|
305
|
+
loader: async () => {
|
|
306
|
+
const { formatLint, formatLintGithub, lintApp } = await import("./lint.js");
|
|
307
|
+
return async function runLint(flags) {
|
|
308
|
+
const format = resolveOutputFormat(flags);
|
|
309
|
+
const result = await lintApp({ cwd: flags.cwd });
|
|
310
|
+
writeOutput(this, format === "json"
|
|
311
|
+
? JSON.stringify(result, null, 2)
|
|
312
|
+
: format === "github"
|
|
313
|
+
? formatLintGithub(result)
|
|
314
|
+
: formatLint(result, { color: useColor() }));
|
|
315
|
+
if (result.diagnostics.length > 0) {
|
|
316
|
+
this.process.exitCode = 1;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
213
319
|
},
|
|
214
320
|
});
|
|
215
321
|
function databaseCommand(command) {
|
|
@@ -220,18 +326,21 @@ function databaseCommand(command) {
|
|
|
220
326
|
parameters: {
|
|
221
327
|
flags: dbFlagParameters,
|
|
222
328
|
},
|
|
223
|
-
async
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
329
|
+
loader: async () => {
|
|
330
|
+
const { runDatabaseCommand } = await import("./db.js");
|
|
331
|
+
return async function runDb(flags) {
|
|
332
|
+
const result = await runDatabaseCommand({
|
|
333
|
+
command,
|
|
334
|
+
captureOutput: Boolean(flags.json),
|
|
335
|
+
dryRun: Boolean(flags.dryRun),
|
|
336
|
+
});
|
|
337
|
+
writeOutput(this, flags.json
|
|
338
|
+
? JSON.stringify(result, null, 2)
|
|
339
|
+
: databaseCommandNextSteps(result));
|
|
340
|
+
if (result.exitCode !== 0) {
|
|
341
|
+
this.process.exitCode = result.exitCode;
|
|
342
|
+
}
|
|
343
|
+
};
|
|
235
344
|
},
|
|
236
345
|
});
|
|
237
346
|
}
|
|
@@ -246,330 +355,325 @@ const dbRoutes = buildRouteMap({
|
|
|
246
355
|
seed: databaseCommand("seed"),
|
|
247
356
|
},
|
|
248
357
|
});
|
|
249
|
-
const
|
|
250
|
-
docs: {
|
|
251
|
-
brief: "Generate a feature resource.",
|
|
252
|
-
},
|
|
253
|
-
parameters: {
|
|
254
|
-
flags: makeFlagParameters,
|
|
255
|
-
positional: namePositional,
|
|
256
|
-
},
|
|
257
|
-
async func(flags, name) {
|
|
258
|
-
const result = await makeResource({
|
|
259
|
-
name,
|
|
260
|
-
force: Boolean(flags.force),
|
|
261
|
-
dryRun: Boolean(flags.dryRun),
|
|
262
|
-
});
|
|
263
|
-
writeOutput(this, flags.json
|
|
264
|
-
? JSON.stringify(result, null, 2)
|
|
265
|
-
: makeResourceNextSteps(result));
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
const makeFeatureCommand = buildCommand({
|
|
358
|
+
const taskRunCommand = buildCommand({
|
|
269
359
|
docs: {
|
|
270
|
-
brief: "
|
|
360
|
+
brief: "Run an app-owned operational task.",
|
|
271
361
|
},
|
|
272
362
|
parameters: {
|
|
273
|
-
flags:
|
|
274
|
-
...makeFlagParameters,
|
|
275
|
-
with: {
|
|
276
|
-
kind: "enum",
|
|
277
|
-
values: makeFeatureAddonChoices,
|
|
278
|
-
optional: true,
|
|
279
|
-
variadic: ",",
|
|
280
|
-
brief: "Add feature-owned artifacts. Supports policy, event/events, job/jobs, and upload/uploads.",
|
|
281
|
-
},
|
|
282
|
-
},
|
|
363
|
+
flags: taskRunFlagParameters,
|
|
283
364
|
positional: namePositional,
|
|
284
365
|
},
|
|
285
|
-
async
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
366
|
+
loader: async () => {
|
|
367
|
+
const { runAppTask } = await import("./task.js");
|
|
368
|
+
return async function runTask(flags, name) {
|
|
369
|
+
const result = await runAppTask({
|
|
370
|
+
name,
|
|
371
|
+
input: flags.input,
|
|
372
|
+
modulePath: flags.module,
|
|
373
|
+
});
|
|
374
|
+
writeOutput(this, flags.json
|
|
375
|
+
? JSON.stringify(result, null, 2)
|
|
376
|
+
: appTaskRunNextSteps(result));
|
|
377
|
+
};
|
|
295
378
|
},
|
|
296
379
|
});
|
|
297
|
-
const
|
|
380
|
+
const taskRoutes = buildRouteMap({
|
|
298
381
|
docs: {
|
|
299
|
-
brief: "
|
|
300
|
-
},
|
|
301
|
-
parameters: {
|
|
302
|
-
flags: makeFlagParameters,
|
|
303
|
-
positional: namePositional,
|
|
382
|
+
brief: "Run Beignet app operational tasks.",
|
|
304
383
|
},
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
name,
|
|
308
|
-
force: Boolean(flags.force),
|
|
309
|
-
dryRun: Boolean(flags.dryRun),
|
|
310
|
-
});
|
|
311
|
-
writeOutput(this, flags.json
|
|
312
|
-
? JSON.stringify(result, null, 2)
|
|
313
|
-
: makeContractNextSteps(result));
|
|
384
|
+
routes: {
|
|
385
|
+
run: taskRunCommand,
|
|
314
386
|
},
|
|
315
387
|
});
|
|
316
|
-
const
|
|
388
|
+
const outboxDrainCommand = buildCommand({
|
|
317
389
|
docs: {
|
|
318
|
-
brief: "
|
|
390
|
+
brief: "Run one app-owned outbox drain pass.",
|
|
319
391
|
},
|
|
320
392
|
parameters: {
|
|
321
|
-
flags:
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
393
|
+
flags: outboxDrainFlagParameters,
|
|
394
|
+
},
|
|
395
|
+
loader: async () => {
|
|
396
|
+
const { runOutboxDrain } = await import("./outbox.js");
|
|
397
|
+
return async function runDrain(flags) {
|
|
398
|
+
const result = await runOutboxDrain({
|
|
399
|
+
modulePath: flags.module,
|
|
400
|
+
batchSize: flags.batchSize,
|
|
401
|
+
});
|
|
402
|
+
writeOutput(this, flags.json
|
|
403
|
+
? JSON.stringify(result, null, 2)
|
|
404
|
+
: outboxDrainNextSteps(result));
|
|
405
|
+
};
|
|
333
406
|
},
|
|
334
407
|
});
|
|
335
|
-
const
|
|
408
|
+
const outboxRoutes = buildRouteMap({
|
|
336
409
|
docs: {
|
|
337
|
-
brief: "
|
|
410
|
+
brief: "Run Beignet outbox operations.",
|
|
338
411
|
},
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
positional: namePositional,
|
|
342
|
-
},
|
|
343
|
-
async func(flags, name) {
|
|
344
|
-
const result = await makeTest({
|
|
345
|
-
name,
|
|
346
|
-
force: Boolean(flags.force),
|
|
347
|
-
dryRun: Boolean(flags.dryRun),
|
|
348
|
-
});
|
|
349
|
-
writeOutput(this, flags.json ? JSON.stringify(result, null, 2) : makeTestNextSteps(result));
|
|
412
|
+
routes: {
|
|
413
|
+
drain: outboxDrainCommand,
|
|
350
414
|
},
|
|
351
415
|
});
|
|
352
|
-
const
|
|
416
|
+
const scheduleRunCommand = buildCommand({
|
|
353
417
|
docs: {
|
|
354
|
-
brief: "
|
|
418
|
+
brief: "Run an app-owned schedule.",
|
|
355
419
|
},
|
|
356
420
|
parameters: {
|
|
357
|
-
flags:
|
|
421
|
+
flags: scheduleRunFlagParameters,
|
|
358
422
|
positional: namePositional,
|
|
359
423
|
},
|
|
360
|
-
async
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
424
|
+
loader: async () => {
|
|
425
|
+
const { runAppSchedule } = await import("./schedule.js");
|
|
426
|
+
return async function runSchedule(flags, name) {
|
|
427
|
+
const result = await runAppSchedule({
|
|
428
|
+
name,
|
|
429
|
+
modulePath: flags.module,
|
|
430
|
+
payload: flags.payload,
|
|
431
|
+
id: flags.id,
|
|
432
|
+
attempt: flags.attempt,
|
|
433
|
+
scheduledAt: flags.scheduledAt,
|
|
434
|
+
triggeredAt: flags.triggeredAt,
|
|
435
|
+
source: flags.source,
|
|
436
|
+
});
|
|
437
|
+
writeOutput(this, flags.json
|
|
438
|
+
? JSON.stringify(result, null, 2)
|
|
439
|
+
: scheduleRunNextSteps(result));
|
|
440
|
+
};
|
|
367
441
|
},
|
|
368
442
|
});
|
|
369
|
-
const
|
|
443
|
+
const scheduleRoutes = buildRouteMap({
|
|
370
444
|
docs: {
|
|
371
|
-
brief: "
|
|
372
|
-
},
|
|
373
|
-
parameters: {
|
|
374
|
-
flags: makeFlagParameters,
|
|
375
|
-
positional: namePositional,
|
|
445
|
+
brief: "Run Beignet schedule operations.",
|
|
376
446
|
},
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
name,
|
|
380
|
-
force: Boolean(flags.force),
|
|
381
|
-
dryRun: Boolean(flags.dryRun),
|
|
382
|
-
});
|
|
383
|
-
writeOutput(this, flags.json
|
|
384
|
-
? JSON.stringify(result, null, 2)
|
|
385
|
-
: makeAdapterNextSteps(result));
|
|
447
|
+
routes: {
|
|
448
|
+
run: scheduleRunCommand,
|
|
386
449
|
},
|
|
387
450
|
});
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
positional: namePositional,
|
|
395
|
-
},
|
|
396
|
-
async func(flags, name) {
|
|
397
|
-
const result = await makePolicy({
|
|
398
|
-
name,
|
|
399
|
-
force: Boolean(flags.force),
|
|
400
|
-
dryRun: Boolean(flags.dryRun),
|
|
401
|
-
});
|
|
402
|
-
writeOutput(this, flags.json
|
|
403
|
-
? JSON.stringify(result, null, 2)
|
|
404
|
-
: makePolicyNextSteps(result));
|
|
451
|
+
const completionShellFlagParameters = {
|
|
452
|
+
shell: {
|
|
453
|
+
kind: "enum",
|
|
454
|
+
values: completionShellChoices,
|
|
455
|
+
optional: true,
|
|
456
|
+
brief: "Shell to manage completions for. Defaults to $SHELL.",
|
|
405
457
|
},
|
|
406
|
-
|
|
407
|
-
|
|
458
|
+
json: jsonFlag,
|
|
459
|
+
};
|
|
460
|
+
const completionInstallCommand = buildCommand({
|
|
408
461
|
docs: {
|
|
409
|
-
brief: "
|
|
462
|
+
brief: "Install beignet shell completions for bash or zsh.",
|
|
410
463
|
},
|
|
411
464
|
parameters: {
|
|
412
|
-
flags:
|
|
413
|
-
positional: namePositional,
|
|
465
|
+
flags: completionShellFlagParameters,
|
|
414
466
|
},
|
|
415
|
-
async
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
467
|
+
loader: async () => {
|
|
468
|
+
const { installCompletions } = await import("./completion.js");
|
|
469
|
+
return async function runInstall(flags) {
|
|
470
|
+
const result = await installCompletions({ shell: flags.shell });
|
|
471
|
+
writeOutput(this, flags.json
|
|
472
|
+
? JSON.stringify(result, null, 2)
|
|
473
|
+
: `${result.status === "updated" ? "Updated" : "Installed"} ${result.shell} completions in ${result.file}
|
|
474
|
+
|
|
475
|
+
Restart your shell or source the file to activate them.`);
|
|
476
|
+
};
|
|
422
477
|
},
|
|
423
478
|
});
|
|
424
|
-
const
|
|
479
|
+
const completionUninstallCommand = buildCommand({
|
|
425
480
|
docs: {
|
|
426
|
-
brief: "
|
|
481
|
+
brief: "Remove beignet shell completions for bash or zsh.",
|
|
427
482
|
},
|
|
428
483
|
parameters: {
|
|
429
|
-
flags:
|
|
430
|
-
positional: namePositional,
|
|
484
|
+
flags: completionShellFlagParameters,
|
|
431
485
|
},
|
|
432
|
-
async
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
486
|
+
loader: async () => {
|
|
487
|
+
const { uninstallCompletions } = await import("./completion.js");
|
|
488
|
+
return async function runUninstall(flags) {
|
|
489
|
+
const result = await uninstallCompletions({ shell: flags.shell });
|
|
490
|
+
writeOutput(this, flags.json
|
|
491
|
+
? JSON.stringify(result, null, 2)
|
|
492
|
+
: result.status === "removed"
|
|
493
|
+
? `Removed ${result.shell} completions from ${result.file}`
|
|
494
|
+
: `No beignet completions found in ${result.file}`);
|
|
495
|
+
};
|
|
439
496
|
},
|
|
440
497
|
});
|
|
441
|
-
const
|
|
498
|
+
const completionRoutes = buildRouteMap({
|
|
442
499
|
docs: {
|
|
443
|
-
brief: "
|
|
444
|
-
},
|
|
445
|
-
parameters: {
|
|
446
|
-
flags: makeFlagParameters,
|
|
447
|
-
positional: namePositional,
|
|
500
|
+
brief: "Manage beignet shell completions.",
|
|
448
501
|
},
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
force: Boolean(flags.force),
|
|
453
|
-
dryRun: Boolean(flags.dryRun),
|
|
454
|
-
});
|
|
455
|
-
writeOutput(this, flags.json
|
|
456
|
-
? JSON.stringify(result, null, 2)
|
|
457
|
-
: makeFactoryNextSteps(result));
|
|
502
|
+
routes: {
|
|
503
|
+
install: completionInstallCommand,
|
|
504
|
+
uninstall: completionUninstallCommand,
|
|
458
505
|
},
|
|
459
506
|
});
|
|
460
|
-
const
|
|
507
|
+
const makeResourceCommand = buildCommand({
|
|
461
508
|
docs: {
|
|
462
|
-
brief: "Generate a
|
|
509
|
+
brief: "Generate a CRUD-shaped resource slice.",
|
|
463
510
|
},
|
|
464
511
|
parameters: {
|
|
465
|
-
flags:
|
|
512
|
+
flags: {
|
|
513
|
+
...makeFlagParameters,
|
|
514
|
+
auth: {
|
|
515
|
+
kind: "boolean",
|
|
516
|
+
optional: true,
|
|
517
|
+
withNegated: false,
|
|
518
|
+
brief: "Generate policy metadata and use-case authorization checks for mutating routes.",
|
|
519
|
+
},
|
|
520
|
+
tenant: {
|
|
521
|
+
kind: "boolean",
|
|
522
|
+
optional: true,
|
|
523
|
+
withNegated: false,
|
|
524
|
+
brief: "Generate tenant-scoped schemas, repository methods, and use-case checks.",
|
|
525
|
+
},
|
|
526
|
+
events: {
|
|
527
|
+
kind: "boolean",
|
|
528
|
+
optional: true,
|
|
529
|
+
withNegated: false,
|
|
530
|
+
brief: "Generate domain event definitions and publish resource events.",
|
|
531
|
+
},
|
|
532
|
+
softDelete: {
|
|
533
|
+
kind: "boolean",
|
|
534
|
+
optional: true,
|
|
535
|
+
withNegated: false,
|
|
536
|
+
brief: "Generate soft-delete persistence that archives rows with deletedAt.",
|
|
537
|
+
},
|
|
538
|
+
},
|
|
466
539
|
positional: namePositional,
|
|
467
540
|
},
|
|
468
|
-
async
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
541
|
+
loader: async () => {
|
|
542
|
+
const { makeResource } = await import("./make.js");
|
|
543
|
+
return async function runMakeResource(flags, name) {
|
|
544
|
+
const result = await makeResource({
|
|
545
|
+
name,
|
|
546
|
+
force: Boolean(flags.force),
|
|
547
|
+
dryRun: Boolean(flags.dryRun),
|
|
548
|
+
auth: Boolean(flags.auth),
|
|
549
|
+
tenant: Boolean(flags.tenant),
|
|
550
|
+
events: Boolean(flags.events),
|
|
551
|
+
softDelete: Boolean(flags.softDelete),
|
|
552
|
+
});
|
|
553
|
+
writeOutput(this, flags.json
|
|
554
|
+
? JSON.stringify(result, null, 2)
|
|
555
|
+
: makeResourceNextSteps(result));
|
|
556
|
+
};
|
|
475
557
|
},
|
|
476
558
|
});
|
|
477
|
-
const
|
|
559
|
+
const makeFeatureCommand = buildCommand({
|
|
478
560
|
docs: {
|
|
479
|
-
brief: "Generate a feature
|
|
561
|
+
brief: "Generate a contract-first feature slice.",
|
|
480
562
|
},
|
|
481
563
|
parameters: {
|
|
482
|
-
flags:
|
|
564
|
+
flags: {
|
|
565
|
+
...makeFlagParameters,
|
|
566
|
+
with: {
|
|
567
|
+
kind: "enum",
|
|
568
|
+
values: makeFeatureAddonChoices,
|
|
569
|
+
optional: true,
|
|
570
|
+
variadic: ",",
|
|
571
|
+
brief: "Add feature-owned artifacts. Supports policy, task/tasks, event/events, job/jobs, notification/notifications, ui, and upload/uploads.",
|
|
572
|
+
},
|
|
573
|
+
},
|
|
483
574
|
positional: namePositional,
|
|
484
575
|
},
|
|
485
|
-
async
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
576
|
+
loader: async () => {
|
|
577
|
+
const { makeFeature } = await import("./make.js");
|
|
578
|
+
return async function runMakeFeature(flags, name) {
|
|
579
|
+
const result = await makeFeature({
|
|
580
|
+
name,
|
|
581
|
+
with: flags.with,
|
|
582
|
+
force: Boolean(flags.force),
|
|
583
|
+
dryRun: Boolean(flags.dryRun),
|
|
584
|
+
});
|
|
585
|
+
writeOutput(this, flags.json
|
|
586
|
+
? JSON.stringify(result, null, 2)
|
|
587
|
+
: makeFeatureNextSteps(result));
|
|
588
|
+
};
|
|
494
589
|
},
|
|
495
590
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
591
|
+
function simpleMakeCommand(generator, brief, formatNextSteps) {
|
|
592
|
+
return buildCommand({
|
|
593
|
+
docs: {
|
|
594
|
+
brief,
|
|
595
|
+
},
|
|
596
|
+
parameters: {
|
|
597
|
+
flags: makeFlagParameters,
|
|
598
|
+
positional: namePositional,
|
|
599
|
+
},
|
|
600
|
+
loader: async () => {
|
|
601
|
+
const generators = await import("./make.js");
|
|
602
|
+
return async function runMake(flags, name) {
|
|
603
|
+
const result = await generators[generator]({
|
|
604
|
+
name,
|
|
605
|
+
force: Boolean(flags.force),
|
|
606
|
+
dryRun: Boolean(flags.dryRun),
|
|
607
|
+
});
|
|
608
|
+
writeOutput(this, flags.json
|
|
609
|
+
? JSON.stringify(result, null, 2)
|
|
610
|
+
: formatNextSteps(result));
|
|
611
|
+
};
|
|
612
|
+
},
|
|
613
|
+
});
|
|
614
|
+
}
|
|
500
615
|
const makeListenerCommand = buildCommand({
|
|
501
616
|
docs: {
|
|
502
617
|
brief: "Generate a feature event listener.",
|
|
503
618
|
},
|
|
504
619
|
parameters: {
|
|
505
|
-
flags:
|
|
620
|
+
flags: {
|
|
621
|
+
...makeFlagParameters,
|
|
622
|
+
event: parsedStringFlag("Event to listen to, for example posts/published."),
|
|
623
|
+
},
|
|
506
624
|
positional: namePositional,
|
|
507
625
|
},
|
|
508
|
-
async
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
626
|
+
loader: async () => {
|
|
627
|
+
const { makeListener } = await import("./make.js");
|
|
628
|
+
return async function runMakeListener(flags, name) {
|
|
629
|
+
if (!flags.event) {
|
|
630
|
+
throw new Error("beignet make listener requires --event feature/name, for example --event posts/published.");
|
|
631
|
+
}
|
|
632
|
+
const result = await makeListener({
|
|
633
|
+
name,
|
|
634
|
+
event: flags.event,
|
|
635
|
+
force: Boolean(flags.force),
|
|
636
|
+
dryRun: Boolean(flags.dryRun),
|
|
637
|
+
});
|
|
638
|
+
writeOutput(this, flags.json
|
|
639
|
+
? JSON.stringify(result, null, 2)
|
|
640
|
+
: makeListenerNextSteps(result));
|
|
641
|
+
};
|
|
521
642
|
},
|
|
522
643
|
});
|
|
523
|
-
const makeScheduleFlagParameters = {
|
|
524
|
-
...makeFlagParameters,
|
|
525
|
-
cron: parsedStringFlag("Cron expression. Defaults to 0 9 * * *."),
|
|
526
|
-
timezone: parsedStringFlag("IANA timezone, for example America/Chicago."),
|
|
527
|
-
route: {
|
|
528
|
-
kind: "boolean",
|
|
529
|
-
optional: true,
|
|
530
|
-
withNegated: false,
|
|
531
|
-
brief: "Generate a Next.js cron route for this schedule.",
|
|
532
|
-
},
|
|
533
|
-
};
|
|
534
644
|
const makeScheduleCommand = buildCommand({
|
|
535
645
|
docs: {
|
|
536
646
|
brief: "Generate a feature schedule.",
|
|
537
647
|
},
|
|
538
648
|
parameters: {
|
|
539
|
-
flags:
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
});
|
|
551
|
-
writeOutput(this, flags.json
|
|
552
|
-
? JSON.stringify(result, null, 2)
|
|
553
|
-
: makeScheduleNextSteps(result));
|
|
554
|
-
},
|
|
555
|
-
});
|
|
556
|
-
const makeUploadCommand = buildCommand({
|
|
557
|
-
docs: {
|
|
558
|
-
brief: "Generate a feature upload.",
|
|
559
|
-
},
|
|
560
|
-
parameters: {
|
|
561
|
-
flags: makeFlagParameters,
|
|
649
|
+
flags: {
|
|
650
|
+
...makeFlagParameters,
|
|
651
|
+
cron: parsedStringFlag("Cron expression. Defaults to 0 9 * * *."),
|
|
652
|
+
timezone: parsedStringFlag("IANA timezone, for example America/Chicago."),
|
|
653
|
+
route: {
|
|
654
|
+
kind: "boolean",
|
|
655
|
+
optional: true,
|
|
656
|
+
withNegated: false,
|
|
657
|
+
brief: "Generate a Next.js cron route for this schedule.",
|
|
658
|
+
},
|
|
659
|
+
},
|
|
562
660
|
positional: namePositional,
|
|
563
661
|
},
|
|
564
|
-
async
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
662
|
+
loader: async () => {
|
|
663
|
+
const { makeSchedule } = await import("./make.js");
|
|
664
|
+
return async function runMakeSchedule(flags, name) {
|
|
665
|
+
const result = await makeSchedule({
|
|
666
|
+
name,
|
|
667
|
+
cron: flags.cron,
|
|
668
|
+
timezone: flags.timezone,
|
|
669
|
+
route: Boolean(flags.route),
|
|
670
|
+
force: Boolean(flags.force),
|
|
671
|
+
dryRun: Boolean(flags.dryRun),
|
|
672
|
+
});
|
|
673
|
+
writeOutput(this, flags.json
|
|
674
|
+
? JSON.stringify(result, null, 2)
|
|
675
|
+
: makeScheduleNextSteps(result));
|
|
676
|
+
};
|
|
573
677
|
},
|
|
574
678
|
});
|
|
575
679
|
const makeRoutes = buildRouteMap({
|
|
@@ -577,22 +681,23 @@ const makeRoutes = buildRouteMap({
|
|
|
577
681
|
brief: "Generate Beignet app files.",
|
|
578
682
|
},
|
|
579
683
|
routes: {
|
|
580
|
-
adapter:
|
|
581
|
-
contract:
|
|
582
|
-
event:
|
|
583
|
-
factory:
|
|
684
|
+
adapter: simpleMakeCommand("makeAdapter", "Generate a port adapter.", makeAdapterNextSteps),
|
|
685
|
+
contract: simpleMakeCommand("makeContract", "Generate a contract group.", makeContractNextSteps),
|
|
686
|
+
event: simpleMakeCommand("makeEvent", "Generate a feature event.", makeEventNextSteps),
|
|
687
|
+
factory: simpleMakeCommand("makeFactory", "Generate a feature test data factory.", makeFactoryNextSteps),
|
|
584
688
|
feature: makeFeatureCommand,
|
|
585
|
-
job:
|
|
586
|
-
notification:
|
|
689
|
+
job: simpleMakeCommand("makeJob", "Generate a feature job.", makeJobNextSteps),
|
|
690
|
+
notification: simpleMakeCommand("makeNotification", "Generate a feature notification.", makeNotificationNextSteps),
|
|
587
691
|
listener: makeListenerCommand,
|
|
588
|
-
policy:
|
|
589
|
-
port:
|
|
692
|
+
policy: simpleMakeCommand("makePolicy", "Generate an authorization policy.", makePolicyNextSteps),
|
|
693
|
+
port: simpleMakeCommand("makePort", "Generate an application port.", makePortNextSteps),
|
|
590
694
|
resource: makeResourceCommand,
|
|
591
695
|
schedule: makeScheduleCommand,
|
|
592
|
-
seed:
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
696
|
+
seed: simpleMakeCommand("makeSeed", "Generate a feature seed.", makeSeedNextSteps),
|
|
697
|
+
task: simpleMakeCommand("makeTask", "Generate a feature operational task.", makeTaskNextSteps),
|
|
698
|
+
test: simpleMakeCommand("makeTest", "Generate a use case test.", makeTestNextSteps),
|
|
699
|
+
upload: simpleMakeCommand("makeUpload", "Generate a feature upload.", makeUploadNextSteps),
|
|
700
|
+
useCase: simpleMakeCommand("makeUseCase", "Generate a use case.", makeUseCaseNextSteps),
|
|
596
701
|
},
|
|
597
702
|
});
|
|
598
703
|
const rootRoutes = buildRouteMap({
|
|
@@ -600,19 +705,26 @@ const rootRoutes = buildRouteMap({
|
|
|
600
705
|
brief: "Beignet CLI",
|
|
601
706
|
fullDescription: `Create apps, generate framework files, inspect routes, and check Beignet conventions.
|
|
602
707
|
|
|
603
|
-
create
|
|
708
|
+
Run npm create beignet@latest (or bun create beignet) to scaffold a new app.`,
|
|
604
709
|
},
|
|
605
710
|
routes: {
|
|
711
|
+
completion: completionRoutes,
|
|
606
712
|
create: createCommand,
|
|
607
713
|
db: dbRoutes,
|
|
608
714
|
doctor: doctorCommand,
|
|
609
715
|
lint: lintCommand,
|
|
610
716
|
make: makeRoutes,
|
|
717
|
+
outbox: outboxRoutes,
|
|
611
718
|
routes: routesCommand,
|
|
719
|
+
schedule: scheduleRoutes,
|
|
720
|
+
task: taskRoutes,
|
|
612
721
|
},
|
|
613
722
|
});
|
|
614
723
|
const cli = buildApplication(rootRoutes, {
|
|
615
724
|
name: "beignet",
|
|
725
|
+
versionInfo: {
|
|
726
|
+
currentVersion: getCliVersion(),
|
|
727
|
+
},
|
|
616
728
|
scanner: {
|
|
617
729
|
caseStyle: "allow-kebab-for-camel",
|
|
618
730
|
},
|
|
@@ -626,7 +738,7 @@ const cli = buildApplication(rootRoutes, {
|
|
|
626
738
|
commandErrorResult: (error) => error.message,
|
|
627
739
|
},
|
|
628
740
|
},
|
|
629
|
-
determineExitCode: () =>
|
|
741
|
+
determineExitCode: () => 2,
|
|
630
742
|
});
|
|
631
743
|
function uniqueValues(values) {
|
|
632
744
|
return [...new Set(values)];
|
|
@@ -637,9 +749,45 @@ function writeOutput(context, output) {
|
|
|
637
749
|
function formatCliException(error) {
|
|
638
750
|
return error instanceof Error ? error.message : String(error);
|
|
639
751
|
}
|
|
752
|
+
function appTaskRunNextSteps(result) {
|
|
753
|
+
const output = result.output === undefined
|
|
754
|
+
? "undefined"
|
|
755
|
+
: JSON.stringify(result.output, null, 2);
|
|
756
|
+
return `Ran task ${result.name} in ${result.durationMs}ms
|
|
757
|
+
|
|
758
|
+
Output:
|
|
759
|
+
${output}`;
|
|
760
|
+
}
|
|
761
|
+
function outboxDrainNextSteps(result) {
|
|
762
|
+
return `Drained outbox in ${result.durationMs}ms
|
|
763
|
+
|
|
764
|
+
Result:
|
|
765
|
+
claimed: ${result.result.claimed}
|
|
766
|
+
delivered: ${result.result.delivered}
|
|
767
|
+
retried: ${result.result.retried}
|
|
768
|
+
deadLettered: ${result.result.deadLettered}`;
|
|
769
|
+
}
|
|
770
|
+
function scheduleRunNextSteps(result) {
|
|
771
|
+
return `Ran schedule ${result.name} in ${result.durationMs}ms
|
|
772
|
+
|
|
773
|
+
Run:
|
|
774
|
+
source: ${result.run.source}
|
|
775
|
+
id: ${result.run.id ?? "none"}
|
|
776
|
+
attempt: ${result.run.attempt ?? "none"}
|
|
777
|
+
scheduledAt: ${result.run.scheduledAt ?? "none"}
|
|
778
|
+
triggeredAt: ${result.run.triggeredAt ?? "none"}`;
|
|
779
|
+
}
|
|
640
780
|
function nextSteps(result, options = {}) {
|
|
781
|
+
if (result.dryRun) {
|
|
782
|
+
const plannedFiles = result.files.map((file) => ` ${file}`).join("\n");
|
|
783
|
+
return `Would create ${result.name} at ${result.targetDir}
|
|
784
|
+
|
|
785
|
+
Planned files:
|
|
786
|
+
${plannedFiles}`;
|
|
787
|
+
}
|
|
641
788
|
const pm = result.packageManager;
|
|
642
789
|
const run = pm === "npm" ? "npm run" : `${pm} run`;
|
|
790
|
+
const cli = packageRunnerFromPackageManager(pm);
|
|
643
791
|
const envFileStep = result.files.includes(".env.example")
|
|
644
792
|
? " cp .env.example .env.local\n"
|
|
645
793
|
: "";
|
|
@@ -647,35 +795,83 @@ function nextSteps(result, options = {}) {
|
|
|
647
795
|
const envStep = envRequiredIntegrations.length > 0
|
|
648
796
|
? " Fill .env.local for selected provider integrations before starting the app.\n"
|
|
649
797
|
: "";
|
|
798
|
+
const hasDatabase = result.files.some((file) => file.startsWith("infra/db/"));
|
|
799
|
+
const databaseStep = hasDatabase
|
|
800
|
+
? `
|
|
801
|
+
Prepare the database:
|
|
802
|
+
${cli} db generate
|
|
803
|
+
${cli} db migrate
|
|
804
|
+
`
|
|
805
|
+
: "";
|
|
806
|
+
const featureDatabaseSteps = hasDatabase
|
|
807
|
+
? `
|
|
808
|
+
${cli} db generate
|
|
809
|
+
${cli} db migrate`
|
|
810
|
+
: "";
|
|
650
811
|
return `Created ${result.name} at ${result.targetDir}
|
|
651
812
|
|
|
652
813
|
Next steps:
|
|
653
814
|
cd ${result.targetDir}
|
|
654
815
|
${pm} install
|
|
655
|
-
${envFileStep}${envStep}
|
|
656
|
-
|
|
816
|
+
${envFileStep}${envStep}${databaseStep}
|
|
817
|
+
Start the app:
|
|
818
|
+
${run} dev
|
|
819
|
+
|
|
820
|
+
Inspect the app:
|
|
821
|
+
${cli} routes
|
|
822
|
+
${cli} lint
|
|
823
|
+
${cli} doctor
|
|
824
|
+
|
|
825
|
+
Generate a feature:
|
|
826
|
+
${cli} make feature projects${featureDatabaseSteps}
|
|
827
|
+
${run} test
|
|
828
|
+
${run} typecheck
|
|
829
|
+
${cli} lint
|
|
830
|
+
${cli} doctor`;
|
|
831
|
+
}
|
|
832
|
+
function packageRunnerFromPackageManager(pm) {
|
|
833
|
+
switch (pm) {
|
|
834
|
+
case "npm":
|
|
835
|
+
return "npm run beignet --";
|
|
836
|
+
case "pnpm":
|
|
837
|
+
return "pnpm beignet";
|
|
838
|
+
case "yarn":
|
|
839
|
+
return "yarn beignet";
|
|
840
|
+
default:
|
|
841
|
+
return "bun beignet";
|
|
842
|
+
}
|
|
657
843
|
}
|
|
658
844
|
function isEnvRequiredProviderIntegration(integration) {
|
|
659
845
|
return (integration === "inngest" ||
|
|
660
846
|
integration === "resend" ||
|
|
661
847
|
integration === "upstash-rate-limit");
|
|
662
848
|
}
|
|
663
|
-
function
|
|
664
|
-
|
|
665
|
-
.
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
.map((file) => ` ${file}`)
|
|
669
|
-
|
|
670
|
-
|
|
849
|
+
function changedFileLines(result) {
|
|
850
|
+
return {
|
|
851
|
+
changedFiles: [...result.createdFiles, ...result.updatedFiles]
|
|
852
|
+
.map((file) => ` ${file}`)
|
|
853
|
+
.join("\n"),
|
|
854
|
+
skippedFiles: result.skippedFiles.map((file) => ` ${file}`).join("\n"),
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
function makeNextSteps(result, noun, steps) {
|
|
858
|
+
const { changedFiles, skippedFiles } = changedFileLines(result);
|
|
859
|
+
return `${result.dryRun ? "Would create" : "Created"} ${result.name} ${noun} in ${result.targetDir}
|
|
671
860
|
|
|
672
861
|
Changed files:
|
|
673
862
|
${changedFiles || " none"}
|
|
674
863
|
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
675
864
|
|
|
676
865
|
Next steps:
|
|
677
|
-
|
|
678
|
-
|
|
866
|
+
${steps.map((step) => ` ${step}`).join("\n")}`;
|
|
867
|
+
}
|
|
868
|
+
function makeResourceNextSteps(result) {
|
|
869
|
+
return makeNextSteps(result, "resource", [
|
|
870
|
+
"Use make resource when the feature maps cleanly to a REST resource with repository-backed persistence.",
|
|
871
|
+
"Review the generated schemas and repository fields.",
|
|
872
|
+
"If this app uses Drizzle, run beignet db generate and beignet db migrate so the new schema is ready.",
|
|
873
|
+
"Run your app's test and typecheck commands, then beignet lint and beignet doctor.",
|
|
874
|
+
]);
|
|
679
875
|
}
|
|
680
876
|
function databaseCommandNextSteps(result) {
|
|
681
877
|
const command = [result.runner, ...result.args].join(" ");
|
|
@@ -686,272 +882,145 @@ Command:
|
|
|
686
882
|
${command}`;
|
|
687
883
|
}
|
|
688
884
|
function makeFeatureNextSteps(result) {
|
|
689
|
-
|
|
690
|
-
.
|
|
691
|
-
.
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} feature slice in ${result.targetDir}
|
|
696
|
-
|
|
697
|
-
Changed files:
|
|
698
|
-
${changedFiles || " none"}
|
|
699
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
700
|
-
|
|
701
|
-
Next steps:
|
|
702
|
-
Treat the generated name field as a placeholder and shape the contracts, use cases, and repository around the feature's real workflow.
|
|
703
|
-
Run your app's typecheck, test, beignet lint, and beignet doctor commands.`;
|
|
885
|
+
return makeNextSteps(result, "feature slice", [
|
|
886
|
+
"Use make feature for product capabilities and workflows. Use make resource when the concept is mostly CRUD-shaped.",
|
|
887
|
+
"Treat the generated name field as a placeholder and shape the contracts, use cases, and repository around the feature's real workflow.",
|
|
888
|
+
"If this app uses Drizzle, run beignet db generate and beignet db migrate so the new schema is ready.",
|
|
889
|
+
"Run your app's test and typecheck commands, then beignet lint and beignet doctor.",
|
|
890
|
+
]);
|
|
704
891
|
}
|
|
705
892
|
function makeContractNextSteps(result) {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
.
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
return
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
717
|
-
|
|
718
|
-
Next steps:
|
|
719
|
-
Add route handlers for the generated contracts.
|
|
720
|
-
Register the exported contract list with OpenAPI if this app publishes docs.`;
|
|
893
|
+
return makeNextSteps(result, "contract", [
|
|
894
|
+
"Add route handlers for the generated contracts.",
|
|
895
|
+
"Register the exported contract list with OpenAPI if this app publishes docs.",
|
|
896
|
+
]);
|
|
897
|
+
}
|
|
898
|
+
function makeTaskNextSteps(result) {
|
|
899
|
+
return makeNextSteps(result, "task", [
|
|
900
|
+
"Replace the starter input schema and handler with the operational workflow.",
|
|
901
|
+
"Keep business rules in use cases and call them from the task handler.",
|
|
902
|
+
]);
|
|
721
903
|
}
|
|
722
904
|
function makeUseCaseNextSteps(result) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
.
|
|
726
|
-
|
|
727
|
-
.map((file) => ` ${file}`)
|
|
728
|
-
.join("\n");
|
|
729
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} use case in ${result.targetDir}
|
|
730
|
-
|
|
731
|
-
Changed files:
|
|
732
|
-
${changedFiles || " none"}
|
|
733
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
734
|
-
|
|
735
|
-
Next steps:
|
|
736
|
-
Replace the starter input and output schemas with domain-specific shapes.
|
|
737
|
-
Add a focused use case test before wiring it to an HTTP route.`;
|
|
905
|
+
return makeNextSteps(result, "use case", [
|
|
906
|
+
"Replace the starter input and output schemas with domain-specific shapes.",
|
|
907
|
+
"Add a focused use case test before wiring it to an HTTP route.",
|
|
908
|
+
]);
|
|
738
909
|
}
|
|
739
910
|
function makeTestNextSteps(result) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
.
|
|
743
|
-
|
|
744
|
-
.map((file) => ` ${file}`)
|
|
745
|
-
.join("\n");
|
|
746
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} test in ${result.targetDir}
|
|
747
|
-
|
|
748
|
-
Changed files:
|
|
749
|
-
${changedFiles || " none"}
|
|
750
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
751
|
-
|
|
752
|
-
Next steps:
|
|
753
|
-
Replace the starter input, context, and assertion with behavior-specific coverage.
|
|
754
|
-
Run your app's test command.`;
|
|
911
|
+
return makeNextSteps(result, "test", [
|
|
912
|
+
"Replace the starter input, context, and assertion with behavior-specific coverage.",
|
|
913
|
+
"Run your app's test command.",
|
|
914
|
+
]);
|
|
755
915
|
}
|
|
756
916
|
function makePortNextSteps(result) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
.
|
|
760
|
-
|
|
761
|
-
.map((file) => ` ${file}`)
|
|
762
|
-
.join("\n");
|
|
763
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} port in ${result.targetDir}
|
|
764
|
-
|
|
765
|
-
Changed files:
|
|
766
|
-
${changedFiles || " none"}
|
|
767
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
768
|
-
|
|
769
|
-
Next steps:
|
|
770
|
-
Replace the starter execute method with domain-specific operations.
|
|
771
|
-
Replace the generated infrastructure stub with a real port adapter.`;
|
|
917
|
+
return makeNextSteps(result, "port", [
|
|
918
|
+
"Replace the starter execute method with domain-specific operations.",
|
|
919
|
+
"Replace the generated infrastructure stub with a real port adapter.",
|
|
920
|
+
]);
|
|
772
921
|
}
|
|
773
922
|
function makePolicyNextSteps(result) {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
.
|
|
777
|
-
|
|
778
|
-
.map((file) => ` ${file}`)
|
|
779
|
-
.join("\n");
|
|
780
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} policy in ${result.targetDir}
|
|
781
|
-
|
|
782
|
-
Changed files:
|
|
783
|
-
${changedFiles || " none"}
|
|
784
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
785
|
-
|
|
786
|
-
Next steps:
|
|
787
|
-
Replace the starter abilities with domain-specific authorization rules.
|
|
788
|
-
Register the policy with createGate(...) and bind it in request context.`;
|
|
923
|
+
return makeNextSteps(result, "policy", [
|
|
924
|
+
"Replace the starter abilities with domain-specific authorization rules.",
|
|
925
|
+
"Register the policy with createGate(...) and bind it in request context.",
|
|
926
|
+
]);
|
|
789
927
|
}
|
|
790
928
|
function makeAdapterNextSteps(result) {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
.
|
|
794
|
-
|
|
795
|
-
.map((file) => ` ${file}`)
|
|
796
|
-
.join("\n");
|
|
797
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} port adapter in ${result.targetDir}
|
|
798
|
-
|
|
799
|
-
Changed files:
|
|
800
|
-
${changedFiles || " none"}
|
|
801
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
802
|
-
|
|
803
|
-
Next steps:
|
|
804
|
-
Replace the generated throwing implementation with real infrastructure code.
|
|
805
|
-
Keep the adapter behind the port interface so use cases stay infrastructure-agnostic.`;
|
|
929
|
+
return makeNextSteps(result, "port adapter", [
|
|
930
|
+
"Replace the generated throwing implementation with real infrastructure code.",
|
|
931
|
+
"Keep the adapter behind the port interface so use cases stay infrastructure-agnostic.",
|
|
932
|
+
]);
|
|
806
933
|
}
|
|
807
934
|
function makeEventNextSteps(result) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
.
|
|
811
|
-
|
|
812
|
-
.map((file) => ` ${file}`)
|
|
813
|
-
.join("\n");
|
|
814
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} event in ${result.targetDir}
|
|
815
|
-
|
|
816
|
-
Changed files:
|
|
817
|
-
${changedFiles || " none"}
|
|
818
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
819
|
-
|
|
820
|
-
Next steps:
|
|
821
|
-
Replace the starter payload schema with the domain fact shape.
|
|
822
|
-
Emit the event from a use case with .emits(...) and events.record(...).`;
|
|
935
|
+
return makeNextSteps(result, "event", [
|
|
936
|
+
"Replace the starter payload schema with the domain fact shape.",
|
|
937
|
+
"Emit the event from a use case with .emits(...) and events.record(...).",
|
|
938
|
+
]);
|
|
823
939
|
}
|
|
824
940
|
function makeJobNextSteps(result) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
.
|
|
828
|
-
|
|
829
|
-
.map((file) => ` ${file}`)
|
|
830
|
-
.join("\n");
|
|
831
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} job in ${result.targetDir}
|
|
832
|
-
|
|
833
|
-
Changed files:
|
|
834
|
-
${changedFiles || " none"}
|
|
835
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
836
|
-
|
|
837
|
-
Next steps:
|
|
838
|
-
Replace the starter payload and handler with the real background work.
|
|
839
|
-
Dispatch the job through ctx.ports.jobs from a use case, listener, or schedule.`;
|
|
941
|
+
return makeNextSteps(result, "job", [
|
|
942
|
+
"Replace the starter payload and handler with the real background work.",
|
|
943
|
+
"Dispatch the job through ctx.ports.jobs from a use case, listener, or schedule.",
|
|
944
|
+
]);
|
|
840
945
|
}
|
|
841
946
|
function makeFactoryNextSteps(result) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
.
|
|
845
|
-
|
|
846
|
-
.map((file) => ` ${file}`)
|
|
847
|
-
.join("\n");
|
|
848
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} factory in ${result.targetDir}
|
|
849
|
-
|
|
850
|
-
Changed files:
|
|
851
|
-
${changedFiles || " none"}
|
|
852
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
853
|
-
|
|
854
|
-
Next steps:
|
|
855
|
-
Replace the starter defaults with realistic test data for this feature.
|
|
856
|
-
Persist through app-owned repository ports so tests avoid raw database clients.`;
|
|
947
|
+
return makeNextSteps(result, "factory", [
|
|
948
|
+
"Replace the starter defaults with realistic test data for this feature.",
|
|
949
|
+
"Persist through app-owned repository ports so tests avoid raw database clients.",
|
|
950
|
+
]);
|
|
857
951
|
}
|
|
858
952
|
function makeSeedNextSteps(result) {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
.
|
|
862
|
-
|
|
863
|
-
.map((file) => ` ${file}`)
|
|
864
|
-
.join("\n");
|
|
865
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} seed in ${result.targetDir}
|
|
866
|
-
|
|
867
|
-
Changed files:
|
|
868
|
-
${changedFiles || " none"}
|
|
869
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
870
|
-
|
|
871
|
-
Next steps:
|
|
872
|
-
Replace the starter record with idempotent local or demo data.
|
|
873
|
-
Import the feature seed from your app-owned database seed entrypoint and run it with runSeeds(...).`;
|
|
953
|
+
return makeNextSteps(result, "seed", [
|
|
954
|
+
"Replace the starter record with idempotent local or demo data.",
|
|
955
|
+
"Import the feature seed from your app-owned database seed entrypoint and run it with runSeeds(...).",
|
|
956
|
+
]);
|
|
874
957
|
}
|
|
875
958
|
function makeNotificationNextSteps(result) {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
.
|
|
879
|
-
|
|
880
|
-
.map((file) => ` ${file}`)
|
|
881
|
-
.join("\n");
|
|
882
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} notification in ${result.targetDir}
|
|
883
|
-
|
|
884
|
-
Changed files:
|
|
885
|
-
${changedFiles || " none"}
|
|
886
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
887
|
-
|
|
888
|
-
Next steps:
|
|
889
|
-
Replace the starter payload and channels with the real user-facing message.
|
|
890
|
-
Send the notification through ctx.ports.notifications so delivery can run inline in tests and through jobs in production.`;
|
|
959
|
+
return makeNextSteps(result, "notification", [
|
|
960
|
+
"Replace the starter payload and channels with the real user-facing message.",
|
|
961
|
+
"Send the notification through ctx.ports.notifications so delivery can run inline in tests and through jobs in production.",
|
|
962
|
+
]);
|
|
891
963
|
}
|
|
892
964
|
function makeListenerNextSteps(result) {
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
.
|
|
896
|
-
|
|
897
|
-
.map((file) => ` ${file}`)
|
|
898
|
-
.join("\n");
|
|
899
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} listener in ${result.targetDir}
|
|
900
|
-
|
|
901
|
-
Changed files:
|
|
902
|
-
${changedFiles || " none"}
|
|
903
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
904
|
-
|
|
905
|
-
Next steps:
|
|
906
|
-
Replace the starter handler with the event reaction.
|
|
907
|
-
Register the listener collection from infrastructure startup.`;
|
|
965
|
+
return makeNextSteps(result, "listener", [
|
|
966
|
+
"Replace the starter handler with the event reaction.",
|
|
967
|
+
"Register the listener collection from infrastructure startup.",
|
|
968
|
+
]);
|
|
908
969
|
}
|
|
909
970
|
function makeScheduleNextSteps(result) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
.
|
|
913
|
-
|
|
914
|
-
.map((file) => ` ${file}`)
|
|
915
|
-
.join("\n");
|
|
916
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} schedule in ${result.targetDir}
|
|
917
|
-
|
|
918
|
-
Changed files:
|
|
919
|
-
${changedFiles || " none"}
|
|
920
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
921
|
-
|
|
922
|
-
Next steps:
|
|
923
|
-
Replace the starter payload and handler with the scheduled workflow.
|
|
924
|
-
Trigger it from a cron route, worker, or provider adapter.`;
|
|
971
|
+
return makeNextSteps(result, "schedule", [
|
|
972
|
+
"Replace the starter payload and handler with the scheduled workflow.",
|
|
973
|
+
"Trigger it from a cron route, worker, or provider adapter.",
|
|
974
|
+
]);
|
|
925
975
|
}
|
|
926
976
|
function makeUploadNextSteps(result) {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
.
|
|
930
|
-
|
|
931
|
-
.map((file) => ` ${file}`)
|
|
932
|
-
.join("\n");
|
|
933
|
-
return `${result.dryRun ? "Would create" : "Created"} ${result.name} upload in ${result.targetDir}
|
|
934
|
-
|
|
935
|
-
Changed files:
|
|
936
|
-
${changedFiles || " none"}
|
|
937
|
-
${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
938
|
-
|
|
939
|
-
Next steps:
|
|
940
|
-
Replace the starter metadata, constraints, key, authorization, and onComplete behavior.
|
|
941
|
-
Register the upload in createUploadRouter(...) and expose it with createUploadRoute(...).`;
|
|
977
|
+
return makeNextSteps(result, "upload", [
|
|
978
|
+
"Replace the starter metadata, constraints, key, authorization, and onComplete behavior.",
|
|
979
|
+
"Register the upload in createUploadRouter(...) and expose it with createUploadRoute(...).",
|
|
980
|
+
]);
|
|
942
981
|
}
|
|
943
982
|
export async function main(inputs = process.argv.slice(2), context = { process }) {
|
|
944
983
|
if (inputs.length === 0) {
|
|
945
984
|
await run(cli, ["--help"], context);
|
|
946
|
-
context.process.exitCode =
|
|
985
|
+
context.process.exitCode = 2;
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
// Shell completion scripts call `beignet completion propose <words...>`.
|
|
989
|
+
// Handle it before stricli parses the inputs: the trailing words are a
|
|
990
|
+
// partial command line, not flags for this CLI.
|
|
991
|
+
if (inputs[0] === "completion" && inputs[1] === "propose") {
|
|
992
|
+
await writeCompletionProposals(inputs.slice(2), context);
|
|
947
993
|
return;
|
|
948
994
|
}
|
|
949
995
|
await run(cli, inputs, context);
|
|
950
996
|
normalizeExitCode(context.process);
|
|
951
997
|
}
|
|
998
|
+
async function writeCompletionProposals(inputs, context) {
|
|
999
|
+
try {
|
|
1000
|
+
const proposals = await proposeCompletions(cli, inputs.length === 0 ? [""] : inputs, context);
|
|
1001
|
+
for (const proposal of proposals) {
|
|
1002
|
+
context.process.stdout.write(`${proposal.completion}\n`);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
catch {
|
|
1006
|
+
// Completion failures must never break the shell; propose nothing.
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
// Stricli reports usage and internal failures as negative ExitCode values
|
|
1010
|
+
// (-5..-1). Node keeps the negative value on process.exitCode while Bun wraps
|
|
1011
|
+
// it to 251..255 on assignment, so both forms map to the usage exit code.
|
|
1012
|
+
const stricliErrorExitCodes = new Set([
|
|
1013
|
+
-5, -4, -3, -2, -1, 251, 252, 253, 254, 255,
|
|
1014
|
+
]);
|
|
952
1015
|
function normalizeExitCode(proc) {
|
|
953
|
-
if (typeof proc.exitCode
|
|
954
|
-
|
|
1016
|
+
if (typeof proc.exitCode !== "number") {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
if (stricliErrorExitCodes.has(proc.exitCode)) {
|
|
1020
|
+
proc.exitCode = 2;
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
if (proc.exitCode > 127) {
|
|
955
1024
|
proc.exitCode = 1;
|
|
956
1025
|
}
|
|
957
1026
|
}
|
|
@@ -970,7 +1039,7 @@ function isCliEntrypoint() {
|
|
|
970
1039
|
if (isCliEntrypoint()) {
|
|
971
1040
|
main().catch((error) => {
|
|
972
1041
|
console.error(error instanceof Error ? error.message : String(error));
|
|
973
|
-
process.exitCode =
|
|
1042
|
+
process.exitCode = 2;
|
|
974
1043
|
});
|
|
975
1044
|
}
|
|
976
1045
|
//# sourceMappingURL=index.js.map
|