@voltro/cli 0.11.4 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/dist/{apiBuild-DHHuiwXF.js → apiBuild-B6_ehbem.js} +9 -8
  3. package/dist/apiBuild-Bzpb383i.js +2 -0
  4. package/dist/appModuleLoader-C9r9mxZt.js +19 -0
  5. package/dist/bin.js +21 -10
  6. package/dist/cliArgs-qdZSElM3.js +28 -0
  7. package/dist/{commands-BwbMqR-1.js → commands-DYOuGlEC.js} +2903 -2647
  8. package/dist/dbCommand-ADD4mrTI.js +2 -0
  9. package/dist/dbCommand-DIOJQwsq.js +876 -0
  10. package/dist/{dev-Cvojvb_J.js → dev-Fb9BmavX.js} +1697 -2411
  11. package/dist/dev-xdijqojc.js +3 -0
  12. package/dist/frameworkTableAssembly-CYlrafoK.js +600 -0
  13. package/dist/frameworkTableAssembly-XvKO7wQt.js +2 -0
  14. package/dist/index.d.ts +19 -0
  15. package/dist/index.js +3 -3
  16. package/dist/inspect-DcZ04OME.js +2 -0
  17. package/dist/inspect-Dwx0_tUj.js +921 -0
  18. package/dist/inspectMetrics-DOiiII34.js +3408 -0
  19. package/dist/manifestBuild-D1MzJAiQ.js +2 -0
  20. package/dist/manifestBuild-P9yuCY2d.js +39 -0
  21. package/dist/seedRunner-D6eu-u5U.js +229 -0
  22. package/dist/serveCommand-CqYxzBZR.js +1113 -0
  23. package/dist/serveEntry.js +4 -4
  24. package/dist/{start-DyJE6w1R.js → start-CjG_0xhR.js} +346 -343
  25. package/dist/startEntry.js +2 -2
  26. package/dist/startup.js +1 -1
  27. package/dist/{startupRunner-DhlX9nqd.js → startupRunner-DPGFchOa.js} +19 -33
  28. package/package.json +17 -17
  29. package/templates/AGENTS.md +1 -0
  30. package/templates/agent-docs/_index.md +1 -0
  31. package/templates/agent-docs/authentication.md +36 -0
  32. package/templates/agent-docs/cli.md +254 -14
  33. package/templates/agent-docs/configuration.md +48 -0
  34. package/templates/agent-docs/data.md +39 -0
  35. package/templates/agent-docs/database/migrations.md +32 -0
  36. package/templates/agent-docs/database/transactions.md +31 -0
  37. package/templates/agent-docs/scheduling.md +35 -1
  38. package/templates/agent-docs/security.md +48 -0
  39. package/templates/agent-docs/templates/apibackends.md +90 -17
  40. package/templates/agent-docs/testing.md +24 -0
  41. package/templates/agent-docs/whats-new.md +81 -0
  42. package/templates/apps/api-ai/package.json +7 -7
  43. package/templates/apps/api-auth/package.json +8 -8
  44. package/templates/apps/api-backend/package.json +7 -7
  45. package/templates/apps/api-backend-deactivation/package.json +7 -7
  46. package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +1 -1
  47. package/templates/apps/api-backend-mail/package.json +8 -8
  48. package/templates/apps/api-backend-mariadb/package.json +9 -9
  49. package/templates/apps/api-backend-storage/package.json +8 -8
  50. package/templates/apps/api-data-advanced/package.json +8 -8
  51. package/templates/apps/api-data-advanced/tests/queries.test.ts +6 -1
  52. package/templates/apps/api-durable/package.json +8 -8
  53. package/templates/apps/api-feature-flags/package.json +9 -9
  54. package/templates/apps/api-governance/app.config.ts +0 -1
  55. package/templates/apps/api-governance/package.json +8 -8
  56. package/templates/apps/api-kv/package.json +8 -8
  57. package/templates/apps/api-kv/tests/sync.test.ts +2 -2
  58. package/templates/apps/api-moderation/package.json +8 -8
  59. package/templates/apps/api-observability/package.json +8 -8
  60. package/templates/apps/api-ratelimit/package.json +8 -8
  61. package/templates/apps/api-rbac/README.md +53 -14
  62. package/templates/apps/api-rbac/app.config.ts +24 -26
  63. package/templates/apps/api-rbac/authz.ts +76 -0
  64. package/templates/apps/api-rbac/database/schema.ts +23 -6
  65. package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +7 -5
  66. package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +15 -8
  67. package/templates/apps/api-rbac/mutations/notes.delete.mutation.server.ts +54 -0
  68. package/templates/apps/api-rbac/mutations/notes.delete.mutation.ts +43 -0
  69. package/templates/apps/api-rbac/mutations/teams.rename.mutation.server.ts +19 -0
  70. package/templates/apps/api-rbac/mutations/teams.rename.mutation.ts +37 -0
  71. package/templates/apps/api-rbac/package.json +8 -8
  72. package/templates/apps/api-rbac/queries/notes.list.query.server.ts +12 -0
  73. package/templates/apps/api-rbac/queries/notes.list.query.ts +26 -0
  74. package/templates/apps/api-rbac/template.json +2 -2
  75. package/templates/apps/api-rbac/tests/authz.test.ts +233 -0
  76. package/templates/apps/api-rest/package.json +7 -7
  77. package/templates/apps/api-saas/package.json +11 -11
  78. package/templates/apps/api-search/package.json +8 -8
  79. package/templates/apps/api-versioning/package.json +8 -8
  80. package/templates/apps/api-webhooks/package.json +9 -8
  81. package/templates/apps/changelog/package.json +6 -6
  82. package/templates/apps/edge-functions/package.json +2 -2
  83. package/templates/apps/frontend-admin/package.json +8 -8
  84. package/templates/apps/frontend-app/package.json +8 -8
  85. package/templates/apps/frontend-blank/package.json +7 -7
  86. package/templates/apps/frontend-contact/package.json +7 -7
  87. package/templates/apps/frontend-dashboard/package.json +7 -7
  88. package/templates/apps/frontend-docs/package.json +7 -7
  89. package/templates/apps/frontend-i18n/package.json +6 -6
  90. package/templates/apps/frontend-landing/package.json +7 -7
  91. package/templates/apps/frontend-spa/package.json +7 -7
  92. package/templates/apps/frontend-ssr/package.json +7 -7
  93. package/templates/apps/frontend-ssr-api/package.json +8 -8
  94. package/templates/apps/frontend-static-blog/package.json +6 -6
  95. package/dist/apiBuild-D9MtlD02.js +0 -2
  96. package/dist/dev-BsBsIv93.js +0 -2
  97. package/dist/inspectMetrics-D4EJ8LTi.js +0 -4255
  98. package/dist/serveCommand-ARqSs73o.js +0 -1117
  99. package/templates/apps/api-rbac/tests/notes.create.test.ts +0 -80
@@ -0,0 +1,3 @@
1
+ import "./seedRunner-D6eu-u5U.js";
2
+ import { c as e, f as t, s as n } from "./dev-Fb9BmavX.js";
3
+ export { n as loadApiConfig, e as loadDiscovered, t as walk };
@@ -0,0 +1,600 @@
1
+ import { n as e } from "./appModuleLoader-C9r9mxZt.js";
2
+ import { basename as t, join as n } from "node:path";
3
+ import { pathToFileURL as r } from "node:url";
4
+ import { Effect as i } from "effect";
5
+ import { promises as a } from "node:fs";
6
+ import { _voltroConnectionGrantsTable as o, _voltroConnectionsTable as s, _voltroScheduleClaimsTable as c, _voltroScheduleRunsTable as l, _voltroTracesTable as u, _voltroUndoLogTable as d, _voltroWakeupsTable as ee, _voltroWorkflowEventDeliveriesTable as f, _voltroWorkflowEventsTable as te, outboxAttemptsTable as ne, outboxTable as re, undoCaptureEnabled as ie } from "@voltro/runtime";
7
+ import { SqlClient as p } from "@effect/sql";
8
+ import { _voltroWorkflowRunEventsTable as ae, _voltroWorkflowRunStepsTable as oe, _voltroWorkflowRunsTable as se, _voltroWorkflowStartContextsTable as m } from "@voltro/workflow";
9
+ import { agentMessagesTable as ce, agentThreadsTable as le, aiBudgetTable as ue, aiUsageTable as de, isAgentDescriptor as fe, isAgentExecutor as pe, resolveToolModuleHandlers as me } from "@voltro/ai";
10
+ import { _voltroApiKeysTable as he, _voltroCdcOffsetsTable as ge, _voltroIdempotencyTable as _e, _voltroKvTable as ve, _voltroMigrationPlansTable as ye, _voltroMigrationsTable as be, _voltroMssqlCdcOffsetsTable as h, _voltroSeedsTable as g, lt as _ } from "@voltro/database";
11
+ import { _voltroWebhookDeliveriesTable as v, _voltroWebhookTargetsTable as y } from "@voltro/plugin-webhooks/mixin";
12
+ import { _voltroStorageBlobsTable as b, _voltroStorageGrantsTable as x, _voltroStorageRefsTable as S, _voltroStorageUsageTable as C } from "@voltro/plugin-storage";
13
+ import { defineAction as w, defineMutation as T, defineQuery as E } from "@voltro/protocol";
14
+ //#region src/frameworkTables.ts
15
+ var D = [
16
+ {
17
+ table: be,
18
+ when: "always"
19
+ },
20
+ {
21
+ table: g,
22
+ when: "always"
23
+ },
24
+ {
25
+ table: ye,
26
+ when: "always"
27
+ },
28
+ {
29
+ table: se,
30
+ when: "workflows"
31
+ },
32
+ {
33
+ table: oe,
34
+ when: "workflows"
35
+ },
36
+ {
37
+ table: ae,
38
+ when: "workflows"
39
+ },
40
+ {
41
+ table: m,
42
+ when: "workflows"
43
+ },
44
+ {
45
+ table: te,
46
+ when: "workflows"
47
+ },
48
+ {
49
+ table: f,
50
+ when: "workflows"
51
+ },
52
+ {
53
+ table: l,
54
+ when: "schedules"
55
+ },
56
+ {
57
+ table: c,
58
+ when: "schedules"
59
+ },
60
+ {
61
+ table: y,
62
+ when: "webhooks"
63
+ },
64
+ {
65
+ table: v,
66
+ when: "webhooks"
67
+ },
68
+ {
69
+ table: u,
70
+ when: "traces"
71
+ },
72
+ {
73
+ table: d,
74
+ when: "undo"
75
+ },
76
+ {
77
+ table: re,
78
+ when: "outbox"
79
+ },
80
+ {
81
+ table: ne,
82
+ when: "outbox"
83
+ },
84
+ {
85
+ table: s,
86
+ when: "connections"
87
+ },
88
+ {
89
+ table: o,
90
+ when: "connections"
91
+ },
92
+ {
93
+ table: ee,
94
+ when: "always"
95
+ },
96
+ {
97
+ table: S,
98
+ when: "always"
99
+ },
100
+ {
101
+ table: x,
102
+ when: "always"
103
+ },
104
+ {
105
+ table: b,
106
+ when: "always"
107
+ },
108
+ {
109
+ table: C,
110
+ when: "always"
111
+ },
112
+ {
113
+ table: _e,
114
+ when: "always"
115
+ },
116
+ {
117
+ table: he,
118
+ when: "always"
119
+ },
120
+ {
121
+ table: ve,
122
+ when: "always"
123
+ }
124
+ ], O = (e) => {
125
+ let t = D.filter((t) => t.when === "always" || t.when === "workflows" && e.workflows || t.when === "schedules" && e.schedules || t.when === "webhooks" && e.webhooks || t.when === "traces" && e.traces || t.when === "undo" && e.undo === !0 || t.when === "outbox" && e.outbox === !0 || t.when === "connections" && e.connections === !0).map((e) => e.table);
126
+ return e.cdc === !0 && t.push(e.cdcDialect === "mssql" ? h : ge), t;
127
+ }, k = (e) => {
128
+ let t = e.startsWith("@") ? e.replace(/^@[^/]+\//, "") : e;
129
+ return (t.startsWith("plugin-") ? t.slice(7) : t).replace(/-([a-zA-Z0-9])/g, (e, t) => t.toUpperCase());
130
+ }, A = (e) => {
131
+ let t = e.startsWith("@") ? e.replace(/^@[^/]+\//, "") : e;
132
+ return (t.startsWith("plugin-") ? t.slice(7) : t).replace(/#/g, "--").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
133
+ }, j = (e, t) => t.name.includes(".") ? t.name : `${k(e.name)}.${t.name}`, M = (e, t, n) => {
134
+ switch (e) {
135
+ case "query": return E({
136
+ name: t,
137
+ input: n.input,
138
+ output: n.output,
139
+ ...n.error === void 0 ? {} : { error: n.error },
140
+ ...n.source === void 0 ? {} : { source: n.source }
141
+ });
142
+ case "mutation": return T({
143
+ name: t,
144
+ input: n.input,
145
+ output: n.output,
146
+ ...n.error === void 0 ? {} : { error: n.error }
147
+ });
148
+ case "action": return w({
149
+ name: t,
150
+ input: n.input,
151
+ output: n.output,
152
+ ...n.error === void 0 ? {} : { error: n.error }
153
+ });
154
+ }
155
+ }, N = (e) => (t, n) => i.suspend(() => {
156
+ let r = { request: {
157
+ subject: n.request.subject,
158
+ traceId: n.request.traceId
159
+ } };
160
+ return e.execute(t, r);
161
+ }), xe = (e) => {
162
+ let t = [];
163
+ for (let n of e) {
164
+ let e = n.routes ?? [];
165
+ for (let r of e) {
166
+ let e = j(n, r), i = M(r.kind, e, r);
167
+ t.push({
168
+ kind: r.kind,
169
+ file: `plugin:${n.name}`,
170
+ descriptor: i,
171
+ executor: N(r),
172
+ plugin: {
173
+ name: n.name,
174
+ version: n.version
175
+ }
176
+ });
177
+ }
178
+ }
179
+ return t;
180
+ }, Se = (e, t) => {
181
+ let n = /* @__PURE__ */ new Map();
182
+ for (let e of t) n.set(e, "user-route");
183
+ for (let t of e) {
184
+ let e = t.descriptor.name, r = n.get(e);
185
+ if (r !== void 0) throw Error(`plugin route tag collision: "${e}" declared by plugin "${t.plugin.name}" but already claimed by ${r === "user-route" ? "a user-authored route" : `plugin "${r}"`}`);
186
+ n.set(e, t.plugin.name);
187
+ }
188
+ }, P = "_voltro_plugin_migrations", Ce = () => i.gen(function* () {
189
+ yield* (yield* p.SqlClient).unsafe(`
190
+ CREATE TABLE IF NOT EXISTS ${P} (
191
+ id TEXT PRIMARY KEY,
192
+ plugin_name TEXT NOT NULL,
193
+ migration_id TEXT NOT NULL,
194
+ description TEXT,
195
+ applied_at TEXT NOT NULL
196
+ );
197
+ `).pipe(i.orDie);
198
+ }), we = (e, t) => `${k(e)}__${t}`, Te = () => i.gen(function* () {
199
+ let e = yield* p.SqlClient, t = yield* e`SELECT id FROM ${e(P)}`.pipe(i.orDie);
200
+ return new Set(t.map((e) => e.id));
201
+ }), Ee = (e) => i.gen(function* () {
202
+ let t = yield* p.SqlClient, n = (/* @__PURE__ */ new Date()).toISOString();
203
+ yield* t`
204
+ INSERT INTO ${t(P)} (id, plugin_name, migration_id, description, applied_at)
205
+ VALUES (${e.key}, ${e.pluginName}, ${e.migration.id}, ${e.migration.description ?? null}, ${n})
206
+ `.pipe(i.orDie);
207
+ }), De = (e) => i.gen(function* () {
208
+ let t = e.flatMap((e) => (e.extendSchema?.migrations ?? []).map((t) => ({
209
+ plugin: e,
210
+ migration: t
211
+ })));
212
+ if (t.length === 0) return [];
213
+ yield* Ce();
214
+ let n = yield* Te(), r = [];
215
+ for (let { plugin: e, migration: a } of t) {
216
+ let t = we(e.name, a.id), o = Date.now();
217
+ if (n.has(t)) {
218
+ r.push({
219
+ pluginName: e.name,
220
+ migrationId: a.id,
221
+ status: "skipped",
222
+ durationMs: 0
223
+ });
224
+ continue;
225
+ }
226
+ let s = yield* p.SqlClient;
227
+ try {
228
+ yield* a.up(s).pipe(i.mapError((e) => e)), yield* Ee({
229
+ key: t,
230
+ pluginName: e.name,
231
+ migration: a
232
+ }), r.push({
233
+ pluginName: e.name,
234
+ migrationId: a.id,
235
+ status: "applied",
236
+ durationMs: Date.now() - o
237
+ });
238
+ } catch (t) {
239
+ return r.push({
240
+ pluginName: e.name,
241
+ migrationId: a.id,
242
+ status: "failed",
243
+ durationMs: Date.now() - o,
244
+ error: t
245
+ }), yield* i.fail(/* @__PURE__ */ Error(`Plugin migration failed: ${e.name} ${a.id} — ${t instanceof Error ? t.message : String(t)}`));
246
+ }
247
+ }
248
+ return r;
249
+ }), Oe = (e) => e.filter((e) => e.extendSchema && (e.extendSchema.tables?.length ?? 0) + (e.extendSchema.migrations?.length ?? 0) > 0).map((e) => ({
250
+ pluginName: e.name,
251
+ pluginAlias: k(e.name),
252
+ tables: e.extendSchema.tables?.length ?? 0,
253
+ migrations: e.extendSchema.migrations?.length ?? 0
254
+ })), ke = (e) => e.flatMap((e) => e.extendSchema?.tables ?? []), F = /(?<!\.server)\.agent\.tsx?$/, Ae = /\.agent\.server\.tsx?$/, I = /\.tool\.tsx?$/, L = async (t, n) => {
255
+ let r = 0;
256
+ for (let i of t) if (I.test(i)) try {
257
+ let t = await e(i);
258
+ r += me(t);
259
+ } catch (e) {
260
+ n.warn("tool: failed to import — handler not wired", { file: i }, e);
261
+ }
262
+ return r;
263
+ }, je = (e) => e.replace(/\.agent\.(tsx?)$/, ".agent.server.$1"), Me = async (t, n) => {
264
+ let r = [], i = /* @__PURE__ */ new Set();
265
+ for (let a of t) {
266
+ if (!F.test(a)) continue;
267
+ let t;
268
+ try {
269
+ t = await e(a);
270
+ } catch (e) {
271
+ n.warn("agent: failed to import descriptor", { file: a }, e);
272
+ continue;
273
+ }
274
+ let o = Object.values(t).find(fe);
275
+ if (o === void 0) {
276
+ n.warn("agent: no defineAgent() descriptor export found", { file: a });
277
+ continue;
278
+ }
279
+ if (i.has(o.name)) {
280
+ n.warn("agent: duplicate name — skipping", {
281
+ file: a,
282
+ name: o.name
283
+ });
284
+ continue;
285
+ }
286
+ let s = je(a), c;
287
+ try {
288
+ c = await e(s);
289
+ } catch (e) {
290
+ n.warn("agent: no executor — expected a `*.agent.server.tsx` default-exporting defineAgentExecutor()", {
291
+ descriptor: a,
292
+ expected: s,
293
+ name: o.name
294
+ }, e);
295
+ continue;
296
+ }
297
+ let l = c.default;
298
+ if (!pe(l)) {
299
+ n.warn("agent: executor file must default-export defineAgentExecutor(descriptor, {...})", {
300
+ file: s,
301
+ name: o.name
302
+ });
303
+ continue;
304
+ }
305
+ i.add(o.name), r.push({
306
+ file: a,
307
+ serverFile: s,
308
+ descriptor: o,
309
+ executor: l
310
+ });
311
+ }
312
+ return { agents: r };
313
+ }, R = /\.connection\.tsx?$/, Ne = (e) => e.replace(R, ""), Pe = async (n, r) => {
314
+ let i = [], a = /* @__PURE__ */ new Map();
315
+ for (let t of n) {
316
+ let n;
317
+ try {
318
+ n = await e(t);
319
+ } catch (e) {
320
+ r.warn("connections: failed to import", { file: t }, e);
321
+ continue;
322
+ }
323
+ let o = n.default;
324
+ if (o === void 0 || typeof o != "object" || !o) {
325
+ r.warn("connections: missing or non-object default export — expected `defineConnection({...})`", { file: t });
326
+ continue;
327
+ }
328
+ let s = o;
329
+ if (typeof s.id != "string" || s.id.length === 0) {
330
+ r.warn("connections: invalid `id` field", { file: t });
331
+ continue;
332
+ }
333
+ if (s.kind !== "oauth2" && s.kind !== "pat") {
334
+ r.warn("connections: `kind` must be \"oauth2\" or \"pat\"", {
335
+ file: t,
336
+ kind: String(s.kind)
337
+ });
338
+ continue;
339
+ }
340
+ let c = a.get(s.id);
341
+ if (c !== void 0) {
342
+ r.error("connections: DUPLICATE id — only the first is registered", {
343
+ id: s.id,
344
+ registered: c,
345
+ ignored: t
346
+ });
347
+ continue;
348
+ }
349
+ a.set(s.id, t), i.push({
350
+ file: t,
351
+ definition: s
352
+ });
353
+ }
354
+ return i.length > 0 && r.info("discovered connections", {
355
+ connections: i.map((e) => `${e.definition.id} (${e.definition.kind})`),
356
+ files: i.map((e) => Ne(t(e.file)))
357
+ }), i;
358
+ }, z = (e) => typeof e.attributes["framework.kind"] == "string" && e.attributes["framework.kind"].startsWith("subscription."), B = (e) => {
359
+ if (e.name.includes("_voltro_traces")) return !0;
360
+ for (let t in e.attributes) {
361
+ let n = e.attributes[t];
362
+ if (typeof n == "string" && n.includes("_voltro_traces")) return !0;
363
+ }
364
+ return !1;
365
+ }, Fe = (e) => typeof e.attributes["framework.kind"] == "string" && e.attributes["framework.kind"].startsWith("subscription"), Ie = 1e3, Le = 500, Re = 50, V = class {
366
+ capacity;
367
+ buffer = [];
368
+ constructor(e = Ie) {
369
+ this.capacity = e;
370
+ }
371
+ append(e) {
372
+ this.buffer.push(e), this.buffer.length > this.capacity && this.buffer.shift();
373
+ }
374
+ query(e = {}) {
375
+ let t = e.since ?? 0, n = e.until ?? Date.now(), r = Math.min(e.max ?? Le, this.capacity), i = e.traceId, a = e.minDurationMs, o = e.status, s = e.name?.toLowerCase(), c = [];
376
+ for (let e = this.buffer.length - 1; e >= 0 && c.length < r; e--) {
377
+ let r = this.buffer[e];
378
+ r.startMs < t || r.startMs > n || i !== void 0 && r.traceId !== i || a !== void 0 && r.durationMs < a || o !== void 0 && r.status !== o || s !== void 0 && !r.name.toLowerCase().includes(s) || c.push(r);
379
+ }
380
+ return c.reverse();
381
+ }
382
+ queryGrouped(e = {}) {
383
+ let t = e.since ?? 0, n = e.maxTraces ?? Re, r = e.onlyErrors ?? !1, i = /* @__PURE__ */ new Map();
384
+ for (let e of this.buffer) {
385
+ if (e.startMs < t) continue;
386
+ let n = i.get(e.traceId);
387
+ n ? n.push(e) : i.set(e.traceId, [e]);
388
+ }
389
+ let a = [];
390
+ for (let [e, t] of i) {
391
+ t.sort((e, t) => e.startMs - t.startMs);
392
+ let n = t.some((e) => e.status === "error");
393
+ if (r && !n) continue;
394
+ let i = t[0].startMs, o = t.reduce((e, t) => t.endMs > e ? t.endMs : e, i), s = t.filter(z), c = s.length > 0 || t.some(Fe), l = s.reduce((e, t) => e === void 0 || t.startMs > e.startMs ? t : e, void 0);
395
+ a.push({
396
+ traceId: e,
397
+ rootName: t[0].name,
398
+ startMs: i,
399
+ durationMs: o - i,
400
+ spanCount: t.length,
401
+ hasError: n,
402
+ kind: c ? "subscription" : "request",
403
+ ...l === void 0 ? {} : { lastDeliveryMs: l.durationMs },
404
+ ...s.length > 0 ? { deliveryCount: s.length } : {},
405
+ spans: t
406
+ });
407
+ }
408
+ return a.sort((e, t) => t.startMs - e.startMs), a.slice(0, n);
409
+ }
410
+ size() {
411
+ return this.buffer.length;
412
+ }
413
+ capacityHint() {
414
+ return this.capacity;
415
+ }
416
+ clear() {
417
+ this.buffer = [];
418
+ }
419
+ }, H = null, ze = () => (H === null && (H = new V()), H), Be = /* @__PURE__ */ new Set([
420
+ "off",
421
+ "errors",
422
+ "interesting",
423
+ "all"
424
+ ]), U = (e, t, n, r) => {
425
+ let i = Number(e);
426
+ return Number.isFinite(i) ? Math.min(r, Math.max(n, i)) : t;
427
+ }, Ve = (e) => e !== void 0 && [
428
+ "1",
429
+ "true",
430
+ "yes",
431
+ "on"
432
+ ].includes(e.toLowerCase()), He = (e) => {
433
+ let t = Number(e);
434
+ return Number.isFinite(t) && t > 0 ? t : 24;
435
+ }, W = (e = process.env) => {
436
+ let t = (e.VOLTRO_TRACING_BUFFER ?? "").toLowerCase() === "off", n = U(e.VOLTRO_TRACING_SAMPLE, 1, 0, 1), r = (e.VOLTRO_TRACING_PERSIST ?? "").toLowerCase(), i = e.NODE_ENV === "production" ? "off" : "interesting";
437
+ return {
438
+ mode: Be.has(r) ? r : n <= 0 ? "off" : i,
439
+ sampleRate: n,
440
+ slowMs: U(e.VOLTRO_TRACING_SLOW_MS, 500, 0, 2 ** 53 - 1),
441
+ ttlHours: He(e.VOLTRO_TRACING_TTL_HOURS),
442
+ persistDelivery: Ve(e.VOLTRO_TRACING_PERSIST_DELIVERY),
443
+ bufferDisabled: t
444
+ };
445
+ }, G = (e = process.env) => {
446
+ let t = W(e);
447
+ return !t.bufferDisabled && t.mode !== "off";
448
+ }, Ue = (e, t) => {
449
+ if (t >= 1) return !0;
450
+ if (t <= 0) return !1;
451
+ let n = 2166136261;
452
+ for (let t = 0; t < e.length; t++) n ^= e.charCodeAt(t), n = Math.imul(n, 16777619);
453
+ return (n >>> 0) % 1e3 < t * 1e3;
454
+ }, We = (e, t) => {
455
+ if (t.mode === "off" || B(e) || z(e) && !t.persistDelivery) return !1;
456
+ let n = e.status === "error";
457
+ if (t.mode === "errors") return n;
458
+ if (n) return !0;
459
+ if (!Ue(e.traceId, t.sampleRate)) return !1;
460
+ if (t.mode === "all") return !0;
461
+ let r = e.parentSpanId === null || e.parentSpanId === void 0 || e.parentSpanId === "", i = typeof e.durationMs == "number" && e.durationMs >= t.slowMs;
462
+ return r || i;
463
+ }, Ge = (e) => {
464
+ if (e.bufferDisabled) return "durable traces: OFF (VOLTRO_TRACING_BUFFER=off)";
465
+ if (e.mode === "off") return "durable traces: OFF — _voltro_traces not created (prod default; set VOLTRO_TRACING_PERSIST=interesting to enable, or use OTLP)";
466
+ let t = e.mode === "interesting" ? ` (errors + slow≥${e.slowMs}ms + roots)` : e.mode === "errors" ? " (errors only)" : "";
467
+ return `durable traces: mode=${e.mode}${t}` + (e.sampleRate < 1 ? ` · sample=${e.sampleRate}` : "") + (e.persistDelivery ? " · +delivery" : "") + ` · ttl=${e.ttlHours}h`;
468
+ }, Ke = (e = 30 * 6e4) => {
469
+ let t = /* @__PURE__ */ new Map();
470
+ return (n, r) => {
471
+ let i = t.get(n);
472
+ return i !== void 0 && r - i < e ? !1 : (t.set(n, r), !0);
473
+ };
474
+ }, qe = (e) => {
475
+ let { store: t, log: n } = e, r = e.policy ?? W();
476
+ n.info(Ge(r));
477
+ let i = Ke(), a = [], o = () => {};
478
+ if (r.mode !== "off") {
479
+ let e = [], s = 0;
480
+ o = (t) => {
481
+ We(t, r) && (e.length >= 5e3 && (e.shift(), s += 1, i("flush-drop", Date.now()) && (n.warn(`trace flush queue saturated — dropping durable spans (${s}+ since last warning). Durable inflow exceeds write throughput; reduce it with VOLTRO_TRACING_PERSIST=errors|interesting or VOLTRO_TRACING_SAMPLE<1.`), s = 0)), e.push(t));
482
+ };
483
+ let c = async () => {
484
+ if (e.length === 0) return;
485
+ let n = e.splice(0, 200);
486
+ for (let e of n) try {
487
+ await t.insert("_voltro_traces", {
488
+ id: `${e.traceId}:${e.spanId}`,
489
+ traceId: e.traceId,
490
+ spanId: e.spanId,
491
+ parentSpanId: e.parentSpanId,
492
+ name: e.name,
493
+ kind: e.kind,
494
+ status: e.status,
495
+ statusMessage: e.statusMessage ?? null,
496
+ startedAt: new Date(e.startMs),
497
+ endedAt: new Date(e.endMs),
498
+ durationMs: Math.round(e.durationMs),
499
+ attributes: e.attributes,
500
+ events: e.events ?? null
501
+ });
502
+ } catch {}
503
+ }, l = setInterval(() => {
504
+ c();
505
+ }, 1e3);
506
+ l.unref?.(), a.push(l);
507
+ }
508
+ let s = r.ttlHours, c = 2e4, l = t.raw?.bind(t), u = async () => {
509
+ try {
510
+ let e = /* @__PURE__ */ new Date(Date.now() - s * 36e5), r = 0;
511
+ if (l) for (;;) {
512
+ let t = await l({
513
+ _tag: "RawSqlFragment",
514
+ strings: ["DELETE FROM \"_voltro_traces\" WHERE \"id\" IN (SELECT \"id\" FROM \"_voltro_traces\" WHERE \"startedAt\" < ", ` LIMIT ${c}) RETURNING "id"`],
515
+ values: [e]
516
+ });
517
+ if (r += t.length, t.length < c) break;
518
+ }
519
+ else for (;;) {
520
+ let n = await t.query({
521
+ table: "_voltro_traces",
522
+ order: [],
523
+ predicate: _("startedAt", e),
524
+ projection: ["id"],
525
+ skip: void 0,
526
+ take: c
527
+ });
528
+ if (n.length === 0) break;
529
+ for (let e of n) try {
530
+ await t.delete("_voltro_traces", e.id);
531
+ } catch {}
532
+ if (r += n.length, n.length < c) break;
533
+ }
534
+ r >= c && i("gc-volume", Date.now()) && n.warn(`trace GC pruned ${r} spans past the ${s}h TTL in one pass — high durable-trace volume. If _voltro_traces stays large, cut the inflow (VOLTRO_TRACING_PERSIST=errors|interesting, VOLTRO_TRACING_SAMPLE<1) or shorten VOLTRO_TRACING_TTL_HOURS.`);
535
+ } catch (e) {
536
+ i("gc-error", Date.now()) && n.warn(`trace GC pass failed — _voltro_traces may grow until this clears: ${e instanceof Error ? e.message : String(e)}`);
537
+ }
538
+ }, d = setInterval(() => {
539
+ u();
540
+ }, 5 * 6e4);
541
+ return d.unref?.(), a.push(d), {
542
+ persistTraceSpan: (e) => o(e),
543
+ stop: () => {
544
+ for (let e of a) clearInterval(e);
545
+ }
546
+ };
547
+ }, Je = /\.(query|mutation|action|stream)\.ts$/, Ye = /\.(query|mutation|action|stream)\.server\.ts$/, K = /\.workflow\.tsx$/, q = /\.workflow\.server\.tsx$/, J = /\.workflow\.tsx?$/, Y = /\.trigger\.tsx?$/, X = /\.cron\.tsx?$/, Z = /\.webhook\.tsx?$/, Q = /\.outbox\.tsx?$/, Xe = /\.subscribe\.tsx?$/, Ze = /\.reaction\.tsx?$/, Qe = /\.aggregate\.tsx?$/, $e = /\.startup\.tsx?$/, et = /\.seed\.ts$/, tt = /\.relations\.ts$/, nt = /\.entity\.ts$|\.schema\.ts$|^schema\.ts$/, rt = (e) => J.test(e) && !K.test(e) && !q.test(e), it = async (e) => {
548
+ let t = !1, r = !1, i = !1, o = !1, s = !1, c = !1, l = async (e) => {
549
+ let u = await a.readdir(e, { withFileTypes: !0 }).catch(() => []);
550
+ for (let a of u) if (a.isDirectory()) {
551
+ if (a.name === "node_modules" || a.name === "dist" || a.name === ".framework" || a.name.startsWith(".")) continue;
552
+ await l(n(e, a.name));
553
+ } else {
554
+ let e = a.name;
555
+ (J.test(e) || Y.test(e)) && (t = !0), X.test(e) && (r = !0), Z.test(e) && (i = !0), F.test(e) && (o = !0), Q.test(e) && (s = !0), R.test(e) && (c = !0);
556
+ }
557
+ };
558
+ return await l(e), {
559
+ workflows: t,
560
+ schedules: r,
561
+ webhooks: i,
562
+ agents: o,
563
+ outbox: s,
564
+ connections: c
565
+ };
566
+ }, at = async (e) => {
567
+ try {
568
+ return (await import(r(n(e, "app.config.ts")).href)).default?.plugins ?? [];
569
+ } catch {
570
+ return [];
571
+ }
572
+ }, $ = (e) => {
573
+ let t = /* @__PURE__ */ new Map(), n = (e) => {
574
+ e?.tableName && !t.has(e.tableName) && t.set(e.tableName, e);
575
+ };
576
+ for (let t of O({
577
+ workflows: e.mix.workflows,
578
+ schedules: e.mix.schedules,
579
+ webhooks: e.mix.webhooks,
580
+ traces: G(),
581
+ cdc: e.cdc,
582
+ ...e.cdcDialect ? { cdcDialect: e.cdcDialect } : {},
583
+ undo: ie(),
584
+ outbox: e.mix.outbox,
585
+ connections: e.mix.connections
586
+ })) n(t);
587
+ e.mix.agents && (n(le), n(ce), n(de), n(ue));
588
+ for (let t of ke(e.plugins)) n(t);
589
+ return [...t.values()];
590
+ }, ot = async (e) => {
591
+ let t = await it(e.root), n = await at(e.root), r = (process.env.DB_DIALECT ?? "postgres").toLowerCase(), i = r === "mariadb" ? "mariadb" : r === "mssql" ? "mssql" : void 0;
592
+ return $({
593
+ mix: t,
594
+ plugins: n,
595
+ cdc: e.cdc ?? (i !== void 0 && (process.env.CDC ?? "1") !== "0"),
596
+ ...i ? { cdcDialect: i } : {}
597
+ });
598
+ };
599
+ //#endregion
600
+ export { Me as A, ze as C, F as D, Pe as E, xe as F, k as I, A as L, De as M, Oe as N, Ae as O, Se as P, O as R, V as S, R as T, J as _, Q as a, qe as b, Ze as c, et as d, $e as f, K as g, Z as h, X as i, L as j, I as k, tt as l, Y as m, $ as n, Je as o, Xe as p, Qe as r, Ye as s, ot as t, nt as u, q as v, B as w, G as x, rt as y };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./frameworkTableAssembly-CYlrafoK.js";
2
+ export { e as assembleFrameworkTables };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,20 @@
1
1
  export declare const CLI_NAME: "framework";
2
2
 
3
+ /**
4
+ * `voltro help` grouped by the job each command does, in the order a user meets
5
+ * them (scaffold → develop → data → build/run → deploy → observe → maintain).
6
+ *
7
+ * A FLAT list of 45 commands in registry order is unusable: most summaries run
8
+ * past 100 chars, so every line wraps and the whole thing reads as a paragraph
9
+ * wall. Here each line is one short lead sentence; the full summary is a
10
+ * `voltro <command> --help` away.
11
+ *
12
+ * Kept as one table rather than a `group` field on all 45 specs so the ordering
13
+ * is readable in one place. `commands.test.ts` asserts every visible command
14
+ * appears in exactly one group, so this can't drift when a command is added.
15
+ */
16
+ export declare const COMMAND_GROUPS: ReadonlyArray<readonly [string, ReadonlyArray<string>]>;
17
+
3
18
  export declare const COMMANDS: ReadonlyArray<CommandSpec>;
4
19
 
5
20
  export declare type CommandSpec = {
@@ -24,6 +39,10 @@ export declare const listTemplates: () => Promise<ReadonlyArray<TemplateInfo>>;
24
39
 
25
40
  export declare const printUsage: () => void;
26
41
 
42
+ /** Command names close enough to a typo to suggest. Also matches on prefix /
43
+ * substring, so `voltro work` suggests `workflows`. Exported for the test. */
44
+ export declare const suggestCommands: (input: string, limit?: number) => ReadonlyArray<string>;
45
+
27
46
  export declare interface TemplateInfo extends TemplateManifest {
28
47
  /** Absolute path to the template source directory. */
29
48
  readonly path: string;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as e, n as t, r as n, t as r } from "./commands-BwbMqR-1.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./commands-DYOuGlEC.js";
2
2
  //#region src/index.ts
3
- var i = "framework";
3
+ var o = "framework";
4
4
  //#endregion
5
- export { i as CLI_NAME, r as COMMANDS, t as dispatch, e as listTemplates, n as printUsage };
5
+ export { o as CLI_NAME, a as COMMANDS, n as COMMAND_GROUPS, i as dispatch, r as listTemplates, t as printUsage, e as suggestCommands };
@@ -0,0 +1,2 @@
1
+ import { r as e } from "./inspect-Dwx0_tUj.js";
2
+ export { e as buildCapabilityManifest };