@voltro/cli 0.34.0 → 0.35.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 (137) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/dist/apiBuild-B8aoJvuw.js +2 -0
  3. package/dist/{apiBuild-DZF_f0_I.js → apiBuild-DYD_ONLD.js} +2 -2
  4. package/dist/{appGraph-gQ_6GkQQ.js → appGraph-KGDPTuTy.js} +1 -1
  5. package/dist/appGraph-zuMGKVYX.js +2 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/{build-CE7Ca9gm.js → build-CD8K4XOr.js} +7 -7
  8. package/dist/{checkCommand-Dv8r9tGO.js → checkCommand-Ct9xkTrS.js} +8 -7
  9. package/dist/{checkCommand-YZDmkAGd.js → checkCommand-DKpDLlqu.js} +1 -1
  10. package/dist/{clusterCmd-CNXKlcvD.js → clusterCmd-D5wsCmA_.js} +1 -1
  11. package/dist/{codegenCommand-DC6w2tNZ.js → codegenCommand-C4YoQIc2.js} +3 -3
  12. package/dist/{codemodRunner-DRRqXR74.js → codemodRunner-BnFq3Fgu.js} +175 -34
  13. package/dist/{commands-gutsz-Ac.js → commands-BE8E7zF3.js} +37 -29
  14. package/dist/{dashboardCommand-3YG8p-UA.js → dashboardCommand-D7SgZGaN.js} +3 -3
  15. package/dist/{dataCommand-qL0r7fPO.js → dataCommand-BhYwDgg-.js} +56 -54
  16. package/dist/dbCommand-DS4b97Is.js +2 -0
  17. package/dist/{dbCommand-B6X0FZbq.js → dbCommand-O8HA63s2.js} +6 -6
  18. package/dist/{dev-CerMd0mW.js → dev-C7sFZq3m.js} +2696 -2188
  19. package/dist/{dev-CoG-ZPx8.js → dev-D2BikO7a.js} +1 -1
  20. package/dist/doctorCommand-CM4Ch9C7.js +2 -0
  21. package/dist/{doctorCommand-CnDXQxfa.js → doctorCommand-DnimF5IM.js} +76 -73
  22. package/dist/{dormancyCommand-Dszo57d6.js → dormancyCommand-QewYug_s.js} +1 -1
  23. package/dist/{embeddingsCommand-C0sKVRo1.js → embeddingsCommand-BfiLS_QI.js} +1 -1
  24. package/dist/{envCommand-DPgdV1Bq.js → envCommand-CCGPRQY1.js} +2 -2
  25. package/dist/{evolveCommand-DHpkgjgH.js → evolveCommand-CHsLCtDf.js} +2 -2
  26. package/dist/frameworkTableAssembly-YyVe32Cb.js +2 -0
  27. package/dist/frameworkTableAssembly-oMPBKqlE.js +511 -0
  28. package/dist/{generateCommand-oibemh97.js → generateCommand-DbgcUpGw.js} +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/{infoCommand-BJw9nLUR.js → infoCommand-DwOgK1t6.js} +1 -1
  31. package/dist/{inspect-CBqFtAKA.js → inspect-CjTYzAs_.js} +32 -2
  32. package/dist/inspect-P4pxoMaV.js +2 -0
  33. package/dist/{inspectCmd-Bppy-GGw.js → inspectCmd-EHFZ9yYu.js} +1 -1
  34. package/dist/{inspectFetch-Cm8_wVvp.js → inspectFetch-EMuhTG_9.js} +1 -1
  35. package/dist/{logsCmd-CCca3KRZ.js → logsCmd-D36xK7Zu.js} +1 -1
  36. package/dist/manifestBuild-COkJoyAr.js +2 -0
  37. package/dist/{manifestBuild-sxpwdKY1.js → manifestBuild-hpPLaGxV.js} +1 -1
  38. package/dist/{migrate-CBwOt_iV.js → migrate-BV7I-ZHZ.js} +3 -3
  39. package/dist/probeCommand-CZfaaUOZ.js +122 -0
  40. package/dist/{runtimeTrace-CRxalXTs.js → runtimeTrace-CH3eUiMw.js} +1 -1
  41. package/dist/scheduleCmd-DQRu6BZC.js +149 -0
  42. package/dist/{sdkgen-CYJscZC7.js → sdkgen-BLkvGRfX.js} +1 -1
  43. package/dist/{seedRunner-TFHHiToI.js → seedRunner-ZmLSqNe2.js} +74 -70
  44. package/dist/serveCommand-CbDHU6l-.js +2 -0
  45. package/dist/serveCommand-iwlUBNS1.js +1766 -0
  46. package/dist/serveEntry.js +1 -1
  47. package/dist/{start-B-9Nsp-S.js → start-BgN62boB.js} +1 -1
  48. package/dist/{start-9LiUOfES.js → start-T4VesWiM.js} +2 -2
  49. package/dist/startEntry.js +1 -1
  50. package/dist/{tracesCmd-CkEZQrtt.js → tracesCmd-DStmCJPi.js} +1 -1
  51. package/dist/updateCommand-BlMZhWgO.js +2 -0
  52. package/dist/{updateCommand-Bkptutss.js → updateCommand-x0pI_x-B.js} +1 -1
  53. package/dist/webDev-BcykISYQ2.js +2 -0
  54. package/dist/{webDev-CBYvPqQr.js → webDev-Dybxew86.js} +14 -2
  55. package/dist/{webhooksCommand-CID96Rga.js → webhooksCommand-DlAgS2Iw.js} +1 -1
  56. package/dist/{workflowsCmd-D1VTmLMY.js → workflowsCmd-BGF-mRZ5.js} +1 -1
  57. package/package.json +47 -17
  58. package/templates/AGENTS.md +1 -1
  59. package/templates/agent-docs/_index.md +1 -1
  60. package/templates/agent-docs/_manifest.json +1 -1
  61. package/templates/agent-docs/authentication.md +55 -7
  62. package/templates/agent-docs/cli.md +59 -0
  63. package/templates/agent-docs/data.md +59 -2
  64. package/templates/agent-docs/database/migrations.md +50 -1
  65. package/templates/agent-docs/deployment.md +214 -21
  66. package/templates/agent-docs/introduction.md +1 -1
  67. package/templates/agent-docs/multi-tenancy.md +93 -22
  68. package/templates/agent-docs/plugins/ai-flows.md +86 -0
  69. package/templates/agent-docs/plugins/billing.md +1 -1
  70. package/templates/agent-docs/plugins/clickhouse.md +31 -0
  71. package/templates/agent-docs/plugins/search.md +6 -3
  72. package/templates/agent-docs/plugins/storage.md +11 -0
  73. package/templates/agent-docs/plugins.md +3 -1
  74. package/templates/agent-docs/scheduling.md +17 -0
  75. package/templates/agent-docs/security.md +2 -2
  76. package/templates/agent-docs/whats-new.md +95 -1729
  77. package/templates/agent-docs/workflows.md +101 -0
  78. package/templates/apps/api-ai/package.json +7 -7
  79. package/templates/apps/api-auth/package.json +8 -8
  80. package/templates/apps/api-backend/package.json +7 -7
  81. package/templates/apps/api-backend-deactivation/package.json +7 -7
  82. package/templates/apps/api-backend-mail/package.json +8 -8
  83. package/templates/apps/api-backend-mariadb/package.json +9 -9
  84. package/templates/apps/api-backend-sqlite/package.json +8 -8
  85. package/templates/apps/api-backend-storage/package.json +8 -8
  86. package/templates/apps/api-cms/package.json +10 -10
  87. package/templates/apps/api-collab/package.json +8 -8
  88. package/templates/apps/api-data-advanced/package.json +8 -8
  89. package/templates/apps/api-durable/package.json +8 -8
  90. package/templates/apps/api-feature-flags/package.json +9 -9
  91. package/templates/apps/api-governance/package.json +8 -8
  92. package/templates/apps/api-kv/package.json +8 -8
  93. package/templates/apps/api-moderation/package.json +8 -8
  94. package/templates/apps/api-observability/package.json +8 -8
  95. package/templates/apps/api-ratelimit/package.json +8 -8
  96. package/templates/apps/api-rbac/package.json +8 -8
  97. package/templates/apps/api-rest/package.json +7 -7
  98. package/templates/apps/api-saas/package.json +11 -11
  99. package/templates/apps/api-saas-starter/package.json +10 -10
  100. package/templates/apps/api-search/package.json +8 -8
  101. package/templates/apps/api-status/package.json +8 -8
  102. package/templates/apps/api-versioning/package.json +8 -8
  103. package/templates/apps/api-webhooks/package.json +9 -9
  104. package/templates/apps/changelog/package.json +6 -6
  105. package/templates/apps/edge-functions/package.json +2 -2
  106. package/templates/apps/frontend-admin/package.json +8 -8
  107. package/templates/apps/frontend-app/package.json +9 -9
  108. package/templates/apps/frontend-auth/package.json +8 -8
  109. package/templates/apps/frontend-blank/package.json +7 -7
  110. package/templates/apps/frontend-cms/package.json +9 -9
  111. package/templates/apps/frontend-collab/package.json +10 -10
  112. package/templates/apps/frontend-contact/package.json +7 -7
  113. package/templates/apps/frontend-dashboard/package.json +7 -7
  114. package/templates/apps/frontend-docs/package.json +7 -7
  115. package/templates/apps/frontend-i18n/package.json +6 -6
  116. package/templates/apps/frontend-landing/package.json +7 -7
  117. package/templates/apps/frontend-portal/package.json +8 -8
  118. package/templates/apps/frontend-saas/package.json +8 -8
  119. package/templates/apps/frontend-spa/package.json +7 -7
  120. package/templates/apps/frontend-ssr/package.json +7 -7
  121. package/templates/apps/frontend-ssr-api/package.json +8 -8
  122. package/templates/apps/frontend-static-blog/package.json +6 -6
  123. package/templates/apps/frontend-status/package.json +8 -8
  124. package/templates/apps/mobile-app/package.json +3 -3
  125. package/dist/apiBuild-BICVGnEC.js +0 -2
  126. package/dist/appGraph-CvQCte0z.js +0 -2
  127. package/dist/dbCommand-CpdKLeQq.js +0 -2
  128. package/dist/doctorCommand-BvqGBwNG.js +0 -2
  129. package/dist/frameworkTableAssembly-BGHmck-x.js +0 -2
  130. package/dist/frameworkTableAssembly-DkkP6BgC.js +0 -674
  131. package/dist/inspect-C_T_WGvl.js +0 -2
  132. package/dist/manifestBuild-ChsKAhmn.js +0 -2
  133. package/dist/scheduleCmd--jksTrf6.js +0 -69
  134. package/dist/serveCommand-B_isw7q4.js +0 -1647
  135. package/dist/serveCommand-DOvbgRnQ.js +0 -2
  136. package/dist/updateCommand-us1_hdIC.js +0 -2
  137. package/dist/webDev-Cg-fFiyd2.js +0 -2
@@ -4937,7 +4937,136 @@ var x = (e, t, n) => {
4937
4937
  return Mr.test(t) || Ar.test(t) && jr.test(t);
4938
4938
  }),
4939
4939
  note: "@voltro/plugin-presence no longer declares a table. Four things moved.\n\n1. A roster member is now { key, meta } — there is NO `lastSeen`.\n\n It was the OWNING replica's clock, so on more than one replica \"active 3\n minutes ago\" rendered from it was wrong by the skew between two pods, with\n nothing to say so. It was also the only field a plain heartbeat changed,\n which is what made the roster push on every beat instead of on every change.\n\n // before\n members.map((m) => `${m.key} — ${ago(m.lastSeen)}`)\n // after: put anything time-shaped you need into meta\n usePresence(channel, { meta: { joinedAt: Date.now() } })\n members.map((m) => `${m.key} — ${ago(m.meta?.joinedAt)}`)\n\n2. `PresenceTracker.track()` and `.untrack()` return { delta, changed }.\n\n // before\n bus.announce(tracker.track({ channel, tenantId, key }))\n // after — announce ALWAYS (a peer's sweep needs the liveness signal),\n // push only on a change\n const write = tracker.track({ channel, tenantId, key })\n bus.announce(write.delta)\n if (write.changed) publishReactivity(store, presenceRoster)\n\n Do not blind-append `.delta` and move on: dropping `changed` restores the\n per-heartbeat push this release removed, and nothing will report it.\n\n `attachPresenceBus` also takes an optional `onRosterChanged` now — call it\n if you drive the bus yourself, or a peer's join and a peer's death will\n update your tracker and push nobody.\n\n3. These exports are DELETED, with no replacement:\n\n presenceTable, PresenceStore, PresenceEntry,\n memoryPresenceStore, isOnline, filterOnline, staleKeys\n\n They were the table era's read model — an abstraction over rows plus the\n staleness filter a row needed because it outlived the client that wrote it.\n Presence has neither. Reading the roster is `presence.list` / `usePresence`;\n the staleness sweep is the plugin's own and needs nothing from you.\n\n4. If your `source:` names '_voltro_presence' as a string, point it at the\n channel object instead:\n\n import { presenceRoster } from '@voltro/plugin-presence'\n defineQuery({ name: 'room.summary', source: presenceRoster, ... })\n\n And to push it yourself:\n\n import { publishReactivity } from '@voltro/protocol'\n publishReactivity(ctx.store, presenceRoster)\n\nTHE TABLE IS NOT DROPPED FOR YOU. The declarative differ never plans a drop for\na framework table no app declares — deliberately, so a live `_voltro_*` table is\nnever destroyed by an app that simply does not know about it. So an existing\n`_voltro_presence` stays, empty, until you remove it:\n\n DROP TABLE IF EXISTS _voltro_presence;\n\nIt holds no data anyone can use: nothing has written a row to it since presence\nmoved into memory."
4940
- }), Pr = /\brouteHttp\s*\(/, q = [
4940
+ }), Pr = (e) => {
4941
+ let t = e.getArguments()[0];
4942
+ if (t === void 0 || !t.isKind(b.ObjectLiteralExpression)) return /* @__PURE__ */ new Set();
4943
+ let n = /* @__PURE__ */ new Set();
4944
+ for (let e of t.getProperties()) {
4945
+ let t = (e.asKind(b.PropertyAssignment) ?? e.asKind(b.ShorthandPropertyAssignment))?.getName?.();
4946
+ t !== void 0 && n.add(t);
4947
+ }
4948
+ return n;
4949
+ }, Fr = (e, t) => /defineEvent\s*\(/.test(e) ? t.some((e) => {
4950
+ if (e.getExpression().getText() !== "defineEvent") return !1;
4951
+ let t = Pr(e);
4952
+ return !t.has("guards") && !t.has("openAccess");
4953
+ }) : !1, Ir = C({
4954
+ version: "0.35.0",
4955
+ id: "0.35.0/01_event-access-decision",
4956
+ title: "Every declared event decides who may listen (`guards:` or `openAccess:`)",
4957
+ kind: "manual",
4958
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Fr(e.getFullText(), e.getDescendantsOfKind(b.CallExpression))),
4959
+ note: (/* @__PURE__ */ "YOUR APP WILL NOT BOOT UNTIL EVERY DECLARED EVENT DECIDES WHO MAY LISTEN.(This closes the sibling of 0.34.0's procedure gate: `defineEvent`'s `guards:`(was optional and enforcement skipped an empty list, so an event with no(decision was silently subscribable by ANY authenticated session that could(open the socket.((WHAT TO DO, IN THIS ORDER:((1) LIST THEM. `voltro doctor` prints every undecided event with its tag and( file — the same set, from the same function, that the boot refuses on.( `voltro doctor --json` carries it as `accessDecisions.undecided` for CI.((2) DECIDE EACH ONE. There are exactly two answers and they are not the same( claim:(( guards: [{ scope: 'display:read' }] a subscriber must hold a scope( openAccess: 'public scoreboard' anyone may listen — and why(( `openAccess` takes a REASON, not a boolean. It is what a reviewer reads( later, and it is what makes \"we decided this is open\" distinguishable( from \"nobody looked\".((3) DO NOT RUBBER-STAMP. Reaching for a scope every caller already holds( satisfies the gate, reads as protection, and enforces nothing. If the( event is open, say `openAccess`. If it should not be open, this gate just( found a real hole — an event often carries exactly the data its table( guards behind a scoped query.((IF YOU NEED TO SHIP FIRST. The same field that covers procedures covers(events, in `app.config.ts`:(( export default { security: { defaultDeny: false } }((That restores the old default-allow for the WHOLE app, in one place a(reviewer can see. There is no env var for it, on purpose. `voltro doctor`(keeps listing the undecided events while it is off, marked advisory.((NOT AFFECTED: apps already running `security: { defaultDeny: false }`, and(events your PLUGINS declare — the gate reads your app's own discovered(`*.event.ts` files only.".split("(")).join("\n")
4960
+ }), Lr = /\brouteHttp\s*\(/, Rr = C({
4961
+ version: "0.34.0",
4962
+ id: "0.34.0/26_route-http-is-async",
4963
+ title: "`routeHttp` returns a Promise",
4964
+ kind: "manual",
4965
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Lr.test(e.getFullText())),
4966
+ note: "`routeHttp` (@voltro/mcp) is async now:\n\n routeHttp(options): HttpOutcome // before\n routeHttp(options): Promise<HttpOutcome> // after\n\nAwait it, and make the enclosing function async if it is not already:\n\n // before\n const outcome = routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\n // after\n const outcome = await routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\nWhy it moved: `tools/list` now folds in the app's agent tools and `tools/call`\nexecutes one, so two of the methods reach the app. The rest still resolve without\ntouching anything, and the function is still pure in the sense that matters — it\nbinds no socket, and a test supplies a `live` double.\n\nIf you use the shipped `serveHttp` transport there is nothing to do; it already\nawaits."
4967
+ }), zr = /@voltro\/plugin-(billing|governance|storage)/, Br = /* @__PURE__ */ RegExp("\\b(billing\\.(startCheckout|portalUrl|previewChange|changePlan|changeSeats|invoices|reportUsage)|governance\\.(export|erase)|storage\\.(mintUploadUrl|ingestUrl|listRefs))\\b"), Vr = /\bdefinePluginRoute\s*\(|\broutes\s*:\s*\[/, Hr = C({
4968
+ version: "0.35.0",
4969
+ id: "0.35.0/02_plugin-procedures-carry-access-decisions",
4970
+ title: "First-party plugin procedures carry access decisions; twelve now require a scope",
4971
+ kind: "manual",
4972
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
4973
+ let t = e.getFullText();
4974
+ return zr.test(t) || Br.test(t) || Vr.test(t) && /VoltroPlugin|definePlugin/.test(t);
4975
+ }),
4976
+ note: [
4977
+ "Every first-party plugin rpc route now declares an access decision, and the",
4978
+ "dispatch spine enforces `security.defaultDeny` PER REQUEST as defense in",
4979
+ "depth behind the boot gate. Twelve routes that any authenticated session",
4980
+ "could previously call now require a SCOPE — a caller without it gets a",
4981
+ "typed ScopeError:",
4982
+ "",
4983
+ " billing.startCheckout billing:manage",
4984
+ " billing.portalUrl billing:manage",
4985
+ " billing.previewChange billing:manage",
4986
+ " billing.changePlan billing:manage",
4987
+ " billing.changeSeats billing:manage",
4988
+ " billing.invoices billing:manage (a guarded READ: invoice",
4989
+ " amounts + hosted-invoice links are billing-",
4990
+ " admin material, not member-banner material)",
4991
+ " billing.reportUsage billing:report (an unguarded usage report",
4992
+ " let any session inflate its tenant's counters",
4993
+ " until a quota locked the tenant out)",
4994
+ " governance.export admin:full (already enforced in-handler;",
4995
+ " governance.erase admin:full the descriptor now declares it,",
4996
+ " so clients + doctor can see it — behaviour is",
4997
+ " unchanged for these two)",
4998
+ " storage.mintUploadUrl storage:manage (raw bring-your-own-key PUT;",
4999
+ " bypasses upload limits + virus scan)",
5000
+ " storage.ingestUrl storage:manage (the server fetches a caller-",
5001
+ " supplied URL — an SSRF surface)",
5002
+ " storage.listRefs storage:browse (tenant-WIDE media-library",
5003
+ " index, private objects' metadata included)",
5004
+ "",
5005
+ "WHAT TO DO:",
5006
+ "",
5007
+ "1) Decide WHO in your app holds each capability, then grant the scope there",
5008
+ " — an rbac role (`rbacPlugin({ roles: { billingAdmin: { scopes:",
5009
+ " ['billing:manage'] } } })`), your auth strategy's `resolveScopes`, or an",
5010
+ " api key's scope set. `admin:full` passes every guard, as always.",
5011
+ "",
5012
+ "2) If a surface in your UI calls one of these for EVERY member (for example",
5013
+ " a pricing page calling billing.previewChange), move it behind the role",
5014
+ " that owns it or grant the scope deliberately — do NOT hand the scope to",
5015
+ " everyone just to make the error go away. That is the rubber-stamp shape",
5016
+ " this change removes; the open-by-design reads your members need",
5017
+ " (billing.subscription, billing.entitlementStatus, the whole",
5018
+ " notifications/presence/flags surface) stayed open, each with its reason",
5019
+ " in `openAccess`.",
5020
+ "",
5021
+ "3) If YOU author a plugin with `routes:`: give every route `guards:` or",
5022
+ " `openAccess: '<why>'`. Under `security.defaultDeny` (the default) the",
5023
+ " dispatch spine now refuses an undecided plugin route per-request with a",
5024
+ " typed ScopeError naming the tag — the same rule your app procedures",
5025
+ " already meet at boot. Spreading a browser-safe descriptor that carries",
5026
+ " the decision (`{ ...listDescriptor, execute }`) is enough.",
5027
+ "",
5028
+ "ESCAPE HATCH (whole app, reviewable, no env var): `app.config.ts` →",
5029
+ "`security: { defaultDeny: false }` restores default-allow for undecided",
5030
+ "descriptors everywhere. The twelve scoped routes above still require their",
5031
+ "scopes — a declared guard is enforced regardless of defaultDeny.",
5032
+ "",
5033
+ "NOT AFFECTED: notifications.* (13 routes), presence.* (3), flags.* (2),",
5034
+ "governance.consent / hasConsent, billing.subscription / entitlementStatus,",
5035
+ "and the storage upload/share flow (13 routes) — all now declare",
5036
+ "`openAccess` with the reason each is safe (self-scoped rows, signed",
5037
+ "subject-bound tickets, per-object grants), and behave exactly as before."
5038
+ ].join("\n")
5039
+ }), Ur = /AnalyticsMirrorImpl/, Wr = C({
5040
+ version: "0.35.0",
5041
+ id: "0.35.0/03_analytics-mirror-max-version",
5042
+ title: "Custom analytics mirror sinks answer `maxVersion` (fleet-scope seed read)",
5043
+ kind: "manual",
5044
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Ur.test(e.getFullText())),
5045
+ note: [
5046
+ "The analytics CDC-mirror now derives its version from the CHANGE under",
5047
+ "`changeScope: 'fleet'` (postgres CDC, mysql binlog): warehouse baseline +",
5048
+ "per-key stream ordinal, so N replicas stamp IDENTICAL versions for one",
5049
+ "change and the duplicate writes dedupe in the warehouse for free.",
5050
+ "",
5051
+ "Your custom `AnalyticsMirrorImpl` must answer the baseline read:",
5052
+ "",
5053
+ " maxVersion: ({ table, primaryKeyValue }) =>",
5054
+ " // the HIGHEST version you have persisted for that key,",
5055
+ " // tombstones included — or null if the key was never written.",
5056
+ "",
5057
+ "Two rules, both load-bearing:",
5058
+ "",
5059
+ " * TOMBSTONES ANSWER TOO. If your `remove` deletes the row physically,",
5060
+ " a re-created key would seed below the delete and never reappear.",
5061
+ " Keep deletes as tombstones (the shipped sinks all do).",
5062
+ " * `null` means \"never written\", and only that. Answering 0 for an",
5063
+ " unknown key is fine (baseline 0 is the null path); answering null",
5064
+ " for a KNOWN key restarts its numbering and the version guard then",
5065
+ " silently rejects every later write until the count catches up.",
5066
+ "",
5067
+ "The read is issued at most once per key per process, off the commit path."
5068
+ ].join("\n")
5069
+ }), Gr = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), q = [
4941
5070
  ge,
4942
5071
  _e,
4943
5072
  ye,
@@ -5032,13 +5161,25 @@ var x = (e, t, n) => {
5032
5161
  Dr,
5033
5162
  kr,
5034
5163
  Nr,
5164
+ Rr,
5165
+ Ir,
5166
+ Hr,
5167
+ Wr,
5168
+ C({
5169
+ version: "0.35.0",
5170
+ id: "0.35.0/04_flow-run-step-skipped",
5171
+ title: "A flow run step can now be 'skipped' — handle it where you render a run timeline",
5172
+ kind: "manual",
5173
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Gr(e.getFullText())),
5174
+ note: (/* @__PURE__ */ "A FLOW RUN STEP CAN NOW BE 'skipped'.((`when:` on a flow step gates it on a prior value, and a step whose condition(is false is SKIPPED rather than run. That is a sixth member of(`RunStepStatus`, so an exhaustive switch over it no longer compiles, and a(lookup keyed by status now has a hole.((WHAT TO DO:((1) FIND IT. Anywhere you render or branch on a run step status — a timeline( component, a status badge map, a progress calculation.((2) DECIDE WHAT A SKIPPED STEP LOOKS LIKE. It is NOT a failure and NOT a( success: it did not run, on purpose, and it produced no output. The( step carries `skipReason` — the rendered condition, e.g.( `{{mode}} equals \"full\"` — so the timeline can say WHY.((3) DO NOT DEFAULT IT TO INVISIBLE. Dropping the row compiles and reads fine( in review, and it reproduces exactly the problem `skipReason` exists to( prevent: a step that vanished is indistinguishable from a step nobody( declared, which is the first thing a user reports as a bug.((A PROGRESS COUNT probably needs a second look too: `succeeded / total` now(under-reports a completed run that skipped a step. Counting(`succeeded + skipped` against the total is usually what was meant.((If your app does not render a flow timeline, there is nothing to do — this(note fires on any file that names the status type or its literals.".split("(")).join("\n")
5175
+ }),
5035
5176
  C({
5036
- version: "0.34.0",
5037
- id: "0.34.0/26_route-http-is-async",
5038
- title: "`routeHttp` returns a Promise",
5177
+ version: "0.35.0",
5178
+ id: "0.35.0/05_declared-schema-drops-runtime-flags",
5179
+ title: "The declared schema no longer reads `CDC` / `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`",
5039
5180
  kind: "manual",
5040
- appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Pr.test(e.getFullText())),
5041
- note: "`routeHttp` (@voltro/mcp) is async now:\n\n routeHttp(options): HttpOutcome // before\n routeHttp(options): Promise<HttpOutcome> // after\n\nAwait it, and make the enclosing function async if it is not already:\n\n // before\n const outcome = routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\n // after\n const outcome = await routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\nWhy it moved: `tools/list` now folds in the app's agent tools and `tools/call`\nexecutes one, so two of the methods reach the app. The rest still resolve without\ntouching anything, and the function is still pure in the sense that matters it\nbinds no socket, and a test supplies a `live` double.\n\nIf you use the shipped `serveHttp` transport there is nothing to do; it already\nawaits."
5181
+ appliesTo: () => !0,
5182
+ note: (/* @__PURE__ */ "The set of framework tables your app DECLARES is hashed into the schema(fingerprint. A pre-deploy `voltro db apply` records that hash; every serving(container recomputes it and refuses to boot if it differs. Until this release(three RUNTIME flags fed into that set:(( CDC=0 removed `_voltro_cdc_offsets`( VOLTRO_UNDO=on added `_voltro_undo_log`( VOLTRO_TRACING_PERSIST=all added `_voltro_traces`((All three read as pure runtime knobs, so they tend to live on the PODS and(not on the pre-upgrade migrate Job — which is a green migrate followed by(every pod in CrashLoopBackOff. This was reported against a Helm deployment(where `CDC: \"0\"` was in all three overlays' pod blocks and none of their(jobs; it had been latent for months and would have fired on the next deploy.((WHAT YOU MUST DO — only if you set one of these to turn a table ON in(production:(( * `VOLTRO_UNDO=on` in production → add to app.config.ts:( export default { schema: { undo: true }, … }( * `VOLTRO_TRACING_PERSIST` keeping trace history in production → add:( export default { schema: { traces: true }, }(( Without the declaration, `voltro serve` now REFUSES to boot and names the( field. That refusal is the point: before, the same configuration either( wrote to a table nobody created or produced a fingerprint the migrate job( could not reproduce.(( Turning capture OFF still needs no declaration and never will — a declared( table nobody writes to is harmless. Only turning it ON is a schema claim.((WHAT HAPPENS WITHOUT ANY ACTION:(( * On mariadb or mssql you will see ONE additive `create-table` in your next( plan: `_voltro_cdc_offsets` is now declared by the DIALECT rather than by( `CDC`, so it exists whether or not that process drives CDC. It is an( offsets table a handful of rows — and the alternative was leaving a( runtime flag able to split your fleet.( * On postgres/sqlite nothing changes: those dialects have no offsets table.((AND ONE THING WORTH DOING ANYWAY: if you are upgrading a deployment that has(a separate migrate job, diff that job's `env:` against your pods' once. The(framework can now guarantee its OWN tables do not depend on a runtime flag;(it cannot make the same guarantee for a plugin's `extendSchema.tables`, which(is app code and may read anything. A `prod-mismatch` refusal now prints which(tables this process decided and from which input, so the comparison is quick.".split("(")).join("\n")
5042
5183
  })
5043
5184
  ], J = /* @__PURE__ */ new Set([
5044
5185
  "node_modules",
@@ -5052,12 +5193,12 @@ var x = (e, t, n) => {
5052
5193
  ".turbo",
5053
5194
  ".cache",
5054
5195
  ".output"
5055
- ]), Fr = () => [...[...J].map((e) => `**/${e}/**`), "**/.voltro-*/**"], Y = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, X = /\.(?:tsx?|jsx?|mjs|cjs)$/, Ir = (e) => m(e).replace(X, ""), Lr = (e) => {
5196
+ ]), Kr = () => [...[...J].map((e) => `**/${e}/**`), "**/.voltro-*/**"], Y = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, X = /\.(?:tsx?|jsx?|mjs|cjs)$/, qr = (e) => m(e).replace(X, ""), Jr = (e) => {
5056
5197
  let t = e.split("/").filter((e) => e.length > 0).pop();
5057
5198
  if (t === void 0 || t === "." || t === "..") return;
5058
5199
  let n = t.replace(X, "");
5059
5200
  return n.length > 0 ? n : void 0;
5060
- }, Rr = (e) => {
5201
+ }, Yr = (e) => {
5061
5202
  let t = /* @__PURE__ */ new Map();
5062
5203
  for (let n of e) {
5063
5204
  let e;
@@ -5068,55 +5209,55 @@ var x = (e, t, n) => {
5068
5209
  }
5069
5210
  Y.lastIndex = 0;
5070
5211
  for (let r = Y.exec(e); r !== null; r = Y.exec(e)) {
5071
- let e = Lr(r[1] ?? r[2] ?? "");
5212
+ let e = Jr(r[1] ?? r[2] ?? "");
5072
5213
  if (e === void 0) continue;
5073
5214
  let i = t.get(e);
5074
5215
  i === void 0 ? t.set(e, /* @__PURE__ */ new Set([n])) : i.add(n);
5075
5216
  }
5076
5217
  }
5077
5218
  return t;
5078
- }, zr = (e, t) => {
5219
+ }, Xr = (e, t) => {
5079
5220
  let n = new Set(e);
5080
- for (let r of e) for (let e of [Ir(r), m(h(r))]) {
5221
+ for (let r of e) for (let e of [qr(r), m(h(r))]) {
5081
5222
  let r = t.get(e);
5082
5223
  if (r !== void 0) for (let e of r) n.add(e);
5083
5224
  }
5084
5225
  return n;
5085
- }, Z = [
5226
+ }, Zr = [
5086
5227
  "**/*.ts",
5087
5228
  "**/*.tsx",
5088
5229
  "!**/node_modules/**",
5089
5230
  "!**/dist/**",
5090
5231
  "!**/.framework/**",
5091
5232
  "!**/*.d.ts"
5092
- ], Q = (e, t, n = Hr) => {
5233
+ ], Z = (e, t, n = ei) => {
5093
5234
  let r = /* @__PURE__ */ new Set();
5094
- for (let e of t) for (let t of e.scope ?? Z) r.add(t);
5235
+ for (let e of t) for (let t of e.scope ?? Zr) r.add(t);
5095
5236
  let i = n(e);
5096
5237
  if (i !== void 0) {
5097
- let t = [...r].filter((e) => !e.startsWith("!")).map((e) => Vr(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => Vr(e.slice(1))), a = [...J], o = [];
5238
+ let t = [...r].filter((e) => !e.startsWith("!")).map((e) => $r(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => $r(e.slice(1))), a = [...J], o = [];
5098
5239
  for (let r of i) {
5099
5240
  if (a.some((e) => r === e || r.startsWith(`${e}/`) || r.includes(`/${e}/`)) || !t.some((e) => e(r)) || n.some((e) => e(r))) continue;
5100
5241
  let i = g(e, r);
5101
5242
  v(i) && o.push(i);
5102
5243
  }
5103
- return Br(o.length, e), o;
5244
+ return Qr(o.length, e), o;
5104
5245
  }
5105
5246
  let a = oe([...r], {
5106
5247
  cwd: e,
5107
5248
  absolute: !0,
5108
5249
  expandDirectories: !1,
5109
5250
  followSymbolicLinks: !1,
5110
- ignore: [...Fr()]
5251
+ ignore: [...Kr()]
5111
5252
  });
5112
- return Br(a.length, e), a;
5113
- }, Br = (e, t) => {
5114
- let n = Ur();
5253
+ return Qr(a.length, e), a;
5254
+ }, Qr = (e, t) => {
5255
+ let n = ti();
5115
5256
  if (!(e <= n)) throw Error(`voltro update: the codemod scan matched ${e} files under ${t}, past the ${n} ceiling.\n Every matched file is parsed into one ts-morph project, so the heap needed grows with\n this number — past the ceiling it runs out of memory, and V8 aborts without naming a\n limit, which is why this stops here instead. Three ways out, in order:\n • put non-source directories in .gitignore (inside a git repo the scan then never\n sees them at all — a build cache, a data dump, a virtualenv),\n • run \`voltro update\` from the app directory rather than the workspace root, or\n • take one codemod at a time: \`voltro update --dry-run\` lists the ids, then\n \`voltro update --codemods-only --only <id>\` runs a single one.\n If every one of those files really is source this pass must rewrite, raise the ceiling\n with VOLTRO_CODEMOD_MAX_FILES and give node room: NODE_OPTIONS=--max-old-space-size=8192.`);
5116
- }, Vr = (e) => {
5257
+ }, $r = (e) => {
5117
5258
  let t = e.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "\0").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\u0000/g, "(?:.*/)?").replace(/\\\{([^}]*)\\\}/g, (e, t) => `(?:${t.split(",").join("|")})`);
5118
5259
  return (e) => RegExp(`^${t}$`).test(e);
5119
- }, Hr = (e) => {
5260
+ }, ei = (e) => {
5120
5261
  try {
5121
5262
  let t = re("git", [
5122
5263
  "ls-files",
@@ -5137,17 +5278,17 @@ var x = (e, t, n) => {
5137
5278
  } catch {
5138
5279
  return;
5139
5280
  }
5140
- }, Ur = () => {
5281
+ }, ti = () => {
5141
5282
  let e = Number(process.env.VOLTRO_CODEMOD_MAX_FILES);
5142
5283
  return Number.isInteger(e) && e > 0 ? e : 2e4;
5143
- }, $ = (e, t) => {
5284
+ }, Q = (e, t) => {
5144
5285
  let n = e.split(".").map(Number), r = t.split(".").map(Number);
5145
5286
  for (let e = 0; e < 3; e++) {
5146
5287
  let t = (n[e] ?? 0) - (r[e] ?? 0);
5147
5288
  if (t !== 0) return t;
5148
5289
  }
5149
5290
  return 0;
5150
- }, Wr = (e, t, n = q) => n.filter((n) => $(e, n.version) < 0 && $(n.version, t) <= 0).slice().sort(he), Gr = (e, t, n = () => {}) => {
5291
+ }, ni = (e, t, n = q) => n.filter((n) => Q(e, n.version) < 0 && Q(n.version, t) <= 0).slice().sort(he), $ = (e, t, n = () => {}) => {
5151
5292
  let r = [], i = [], a = [];
5152
5293
  for (let o of t) {
5153
5294
  if (!(!o.appliesTo || o.appliesTo({ project: e }))) {
@@ -5193,8 +5334,8 @@ var x = (e, t, n) => {
5193
5334
  manual: i,
5194
5335
  skipped: a
5195
5336
  };
5196
- }, Kr = async (e) => {
5197
- let t = e.log ?? (() => {}), n = Wr(e.from, e.to, e.codemods ?? q), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
5337
+ }, ri = async (e) => {
5338
+ let t = e.log ?? (() => {}), n = ni(e.from, e.to, e.codemods ?? q), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
5198
5339
  let t = n.filter((t) => e.only.includes(t.id)), r = e.only.filter((e) => !n.some((t) => t.id === e));
5199
5340
  if (r.length > 0) throw Error(`voltro update --only: no codemod in ${e.from} → ${e.to} has id ${r.map((e) => `"${e}"`).join(", ")}.\n Available for this jump:\n${n.map((e) => ` ${e.id}`).join("\n")}`);
5200
5341
  return t;
@@ -5213,15 +5354,15 @@ var x = (e, t, n) => {
5213
5354
  baseUrl: i.baseUrl,
5214
5355
  paths: i.paths
5215
5356
  } }
5216
- }), o, s = Q(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ? Rr(Q(e.root, [{
5357
+ }), o, s = Z(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ? Yr(Z(e.root, [{
5217
5358
  ...c[0],
5218
- scope: Z
5359
+ scope: Zr
5219
5360
  }])) : void 0;
5220
5361
  for (let n of r) {
5221
5362
  if (c.includes(n)) {
5222
- let r = a(), i = Q(e.root, [n]);
5223
- for (let e of zr(i, p)) v(e) && r.addSourceFileAtPath(e);
5224
- let s = Gr(r, [n], t);
5363
+ let r = a(), i = Z(e.root, [n]);
5364
+ for (let e of Xr(i, p)) v(e) && r.addSourceFileAtPath(e);
5365
+ let s = $(r, [n], t);
5225
5366
  e.dryRun || await r.save(), l.push(...s.applied), u.push(...s.manual), d.push(...s.skipped), o = void 0;
5226
5367
  continue;
5227
5368
  }
@@ -5230,7 +5371,7 @@ var x = (e, t, n) => {
5230
5371
  for (let t of s) v(t) && e.addSourceFileAtPath(t);
5231
5372
  return e;
5232
5373
  })();
5233
- let r = Gr(o, [n], t);
5374
+ let r = $(o, [n], t);
5234
5375
  e.dryRun || await o.save(), l.push(...r.applied), u.push(...r.manual), d.push(...r.skipped);
5235
5376
  }
5236
5377
  return {
@@ -5240,4 +5381,4 @@ var x = (e, t, n) => {
5240
5381
  };
5241
5382
  };
5242
5383
  //#endregion
5243
- export { C as i, Kr as n, J as r, $ as t };
5384
+ export { C as i, ri as n, J as r, Q as t };
@@ -90,7 +90,7 @@ var a = () => {
90
90
  name: "dev",
91
91
  summary: "Start the local development server (auto-discovers routes / mutations).",
92
92
  status: "wired",
93
- run: (e) => import("./dev-CoG-ZPx8.js").then((t) => t.runDev(e)),
93
+ run: (e) => import("./dev-D2BikO7a.js").then((t) => t.runDev(e)),
94
94
  help: {
95
95
  usage: "[app]",
96
96
  examples: [["voltro dev", "boot the app in the current directory"], ["voltro dev apps/acme/api", "boot a specific app"]],
@@ -108,7 +108,7 @@ var a = () => {
108
108
  name: "dashboard",
109
109
  summary: "Serve the DevTools dashboard standalone (from @voltro/dashboard). Targets via VOLTRO_DASHBOARD_APPS; --port to override.",
110
110
  status: "wired",
111
- run: (e) => import("./dashboardCommand-3YG8p-UA.js").then((t) => t.runDashboardCommand(e)),
111
+ run: (e) => import("./dashboardCommand-D7SgZGaN.js").then((t) => t.runDashboardCommand(e)),
112
112
  help: {
113
113
  usage: "[--port <n>]",
114
114
  flags: [["--port <n>", "port to serve the dashboard on"]],
@@ -120,7 +120,7 @@ var a = () => {
120
120
  name: "check",
121
121
  summary: "Verify the app graph (blast-radius checks) against a running api; LLM-shaped --json diagnostics. Flags: --json, --process <p>, --diff removeTable:<name>.",
122
122
  status: "wired",
123
- run: (e) => import("./checkCommand-YZDmkAGd.js").then((t) => t.runCheckCommand(e)),
123
+ run: (e) => import("./checkCommand-DKpDLlqu.js").then((t) => t.runCheckCommand(e)),
124
124
  help: {
125
125
  usage: "[--json] [--offline] [--process <name>] [--diff removeTable:<name>]",
126
126
  flags: [
@@ -154,7 +154,7 @@ var a = () => {
154
154
  name: "webhooks",
155
155
  summary: "Outbound-webhook artefacts. `consumer` generates the ZERO-DEPENDENCY Standard-Webhooks verification package a subscriber installs, from this app's own declared events; `events` lists the events a subscriber can register for. Usage: voltro webhooks <consumer|events> [path] [--out <dir>] [--name <pkg>] [--json].",
156
156
  status: "wired",
157
- run: (e) => import("./webhooksCommand-CID96Rga.js").then((t) => t.runWebhooksCommand(e)),
157
+ run: (e) => import("./webhooksCommand-DlAgS2Iw.js").then((t) => t.runWebhooksCommand(e)),
158
158
  help: {
159
159
  usage: "<consumer|events> [path] [--out <dir>] [--name <pkg>] [--json]",
160
160
  flags: [
@@ -170,7 +170,7 @@ var a = () => {
170
170
  name: "evolve",
171
171
  summary: "Schema-evolution copilot: propose an observed-graph-driven codemod + a branch-verified backfill for a schema change (rename/retype/split/drop a column, rename a table). Dry-run by default; --write applies. Usage: voltro evolve rename-column <table>.<col> --to <newName> [--write] [--json].",
172
172
  status: "wired",
173
- run: (e) => import("./evolveCommand-DHpkgjgH.js").then((t) => t.runEvolveCommand(e)),
173
+ run: (e) => import("./evolveCommand-CHsLCtDf.js").then((t) => t.runEvolveCommand(e)),
174
174
  help: {
175
175
  usage: "<rename-column|rename-table|retype-column|split-column|drop-column> <target> [--to <new>] [--write]",
176
176
  flags: [
@@ -187,7 +187,7 @@ var a = () => {
187
187
  name: "codegen",
188
188
  summary: "Emit rpcGroup.generated.ts from discovered route / mutation descriptors.",
189
189
  status: "wired",
190
- run: (e) => import("./codegenCommand-DC6w2tNZ.js").then((t) => t.runCodegenCommand(e)),
190
+ run: (e) => import("./codegenCommand-C4YoQIc2.js").then((t) => t.runCodegenCommand(e)),
191
191
  help: {
192
192
  usage: "[app]",
193
193
  examples: [["voltro codegen", "regenerate rpcGroup.generated.ts for the app in the cwd"]],
@@ -198,7 +198,7 @@ var a = () => {
198
198
  name: "migrate",
199
199
  summary: "Apply the declared schema to the database (alias of `db apply` — diffs declared vs live and emits the ALTERs). `--create-only` for the bootstrap-only CREATE TABLE IF NOT EXISTS path.",
200
200
  status: "wired",
201
- run: (e) => import("./migrate-CBwOt_iV.js").then((t) => t.runMigrateCommand(e)),
201
+ run: (e) => import("./migrate-BV7I-ZHZ.js").then((t) => t.runMigrateCommand(e)),
202
202
  help: {
203
203
  usage: "[app] [--create-only]",
204
204
  flags: [["--create-only", "only CREATE TABLE IF NOT EXISTS — never ALTER (bootstrap)"]],
@@ -258,7 +258,7 @@ var a = () => {
258
258
  name: "info",
259
259
  summary: "Report versions (CLI, node, every installed @voltro/* — flags lockstep skew), package manager, and dialect. --json for CI. Exits 1 on version skew.",
260
260
  status: "wired",
261
- run: (e) => import("./infoCommand-BJw9nLUR.js").then((t) => t.runInfoCommand(e)),
261
+ run: (e) => import("./infoCommand-DwOgK1t6.js").then((t) => t.runInfoCommand(e)),
262
262
  help: {
263
263
  usage: "[--json]",
264
264
  flags: [["--json", "machine-readable report"]],
@@ -279,7 +279,7 @@ var a = () => {
279
279
  name: "env",
280
280
  summary: "Inspect/sync the typed-env manifest. Subcommands: check (default), sync (.env.example), types (env.generated.d.ts for CI tsc), turbo.",
281
281
  status: "wired",
282
- run: (e) => import("./envCommand-DPgdV1Bq.js").then((t) => t.runEnvCommand(e)),
282
+ run: (e) => import("./envCommand-CCGPRQY1.js").then((t) => t.runEnvCommand(e)),
283
283
  help: {
284
284
  usage: "[check|sync|types|turbo] [--force]",
285
285
  flags: [["--force", "overwrite the generated file instead of refusing on a conflict"]],
@@ -308,12 +308,12 @@ var a = () => {
308
308
  run: async (e) => {
309
309
  let t = e.find((e) => !e.startsWith("-")) ?? process.cwd();
310
310
  if (e.includes("--preflight")) {
311
- let { runServePreflight: e } = await import("./doctorCommand-BvqGBwNG.js");
311
+ let { runServePreflight: e } = await import("./doctorCommand-CM4Ch9C7.js");
312
312
  return e(n(t), !0);
313
313
  }
314
- let { tryRunWebServe: r } = await import("./webDev-Cg-fFiyd2.js"), i = await r(n(t));
314
+ let { tryRunWebServe: r } = await import("./webDev-BcykISYQ2.js"), i = await r(n(t));
315
315
  if (!i.ran) {
316
- let { runServeDispatch: t } = await import("./serveCommand-DOvbgRnQ.js");
316
+ let { runServeDispatch: t } = await import("./serveCommand-CbDHU6l-.js");
317
317
  return t(e);
318
318
  }
319
319
  return i.exitCode;
@@ -341,13 +341,13 @@ var a = () => {
341
341
  handlesHelp: !0,
342
342
  summary: "Preflight an app for production: the precompiled serve bundle, hand-rolled primitives (naming the shipped one), @voltro/* version skew, executors with no access check, `.serverOnly()` leaks, and junction-FK gaps.",
343
343
  status: "wired",
344
- run: (e) => import("./doctorCommand-BvqGBwNG.js").then((t) => t.runDoctorCommand(e))
344
+ run: (e) => import("./doctorCommand-CM4Ch9C7.js").then((t) => t.runDoctorCommand(e))
345
345
  },
346
346
  {
347
347
  name: "build",
348
348
  summary: "Production build for a web app (vite build + per-page SSG pre-render).",
349
349
  status: "wired",
350
- run: (e) => import("./build-CE7Ca9gm.js").then((t) => t.runBuildCommand(e)),
350
+ run: (e) => import("./build-CD8K4XOr.js").then((t) => t.runBuildCommand(e)),
351
351
  help: {
352
352
  usage: "[app] [--target <t>]",
353
353
  flags: [["--target <t>", "build target"]],
@@ -363,14 +363,14 @@ var a = () => {
363
363
  name: "prune-runtime",
364
364
  summary: "Trim a deployed web tree’s node_modules to the reachable runtime set (standalone image slimming).",
365
365
  status: "wired",
366
- run: (e) => import("./runtimeTrace-CRxalXTs.js").then((t) => t.runPruneRuntimeCommand(e)),
366
+ run: (e) => import("./runtimeTrace-CH3eUiMw.js").then((t) => t.runPruneRuntimeCommand(e)),
367
367
  hidden: !0
368
368
  },
369
369
  {
370
370
  name: "generate",
371
371
  summary: "AI app-builder (round-2/06): generate app graph + files from a prompt, gated by `voltro check`. Dry-run by default; --write applies. Usage: voltro generate \"<prompt>\" [--write].",
372
372
  status: "wired",
373
- run: (e) => import("./generateCommand-oibemh97.js").then((t) => t.runGenerateCommand(e)),
373
+ run: (e) => import("./generateCommand-DbgcUpGw.js").then((t) => t.runGenerateCommand(e)),
374
374
  help: {
375
375
  usage: "\"<prompt>\" [--write]",
376
376
  flags: [["--write", "write the generated files (dry-run is the default)"]],
@@ -381,7 +381,7 @@ var a = () => {
381
381
  name: "dormancy",
382
382
  summary: "Single-node scale-to-zero: front the API with a wake-orchestrator that stops the app when idle and brings it back on a request or a due wakeup (cron/workflow). Needs a SQL store. Flags: --port, --app-port, --idle-grace-ms, --tick-ms.",
383
383
  status: "wired",
384
- run: (e) => import("./dormancyCommand-Dszo57d6.js").then((t) => t.runDormancyCommand(e)),
384
+ run: (e) => import("./dormancyCommand-QewYug_s.js").then((t) => t.runDormancyCommand(e)),
385
385
  help: {
386
386
  usage: "[app] [--port <n>] [--app-port <n>] [--idle-grace-ms <n>] [--tick-ms <n>]",
387
387
  flags: [
@@ -398,7 +398,7 @@ var a = () => {
398
398
  name: "start",
399
399
  summary: "Production runtime: serves dist + SSR-on-demand for ssr/isr pages.",
400
400
  status: "wired",
401
- run: (e) => import("./start-B-9Nsp-S.js").then((t) => t.runStartCommand(e)),
401
+ run: (e) => import("./start-BgN62boB.js").then((t) => t.runStartCommand(e)),
402
402
  help: {
403
403
  usage: "[app]",
404
404
  examples: [["voltro start", "serve a built web app (dist + SSR-on-demand)"]],
@@ -452,7 +452,7 @@ var a = () => {
452
452
  name: "db",
453
453
  summary: "Database subcommands. Declarative flow: plan, apply, branch, plans, drift [--accept], squash, restore-snapshot. File migrations: generate [name], migrate, rollback, status, files, rollback-file. Also: seed, gc-snapshots.",
454
454
  status: "wired",
455
- run: (e) => import("./dbCommand-CpdKLeQq.js").then((t) => t.runDbCommand(e)),
455
+ run: (e) => import("./dbCommand-DS4b97Is.js").then((t) => t.runDbCommand(e)),
456
456
  help: {
457
457
  usage: "<plan|apply|branch|plans|drift|squash|restore-snapshot|generate|migrate|rollback|status|files|rollback-file|seed|gc-snapshots>",
458
458
  examples: [
@@ -468,7 +468,7 @@ var a = () => {
468
468
  name: "data",
469
469
  summary: "Export/import + backup/restore of app data. Logical (rows + optional assets): export <dir> [--tenant <id>|--tables a,b] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot]; import <dir> [--assets] [--no-verify]. Native (rows ONLY — no blobs): backup <dir> / restore <dir> (pg_dump/mariadb-dump/…). Resumable; typed-NDJSON; content-addressed assets on the logical path.",
470
470
  status: "wired",
471
- run: (e) => import("./dataCommand-qL0r7fPO.js").then((t) => t.runDataCommand(e)),
471
+ run: (e) => import("./dataCommand-BhYwDgg-.js").then((t) => t.runDataCommand(e)),
472
472
  help: {
473
473
  usage: "<export|import|backup|restore> <dir> [options]",
474
474
  flags: [
@@ -523,20 +523,20 @@ var a = () => {
523
523
  handlesHelp: !0,
524
524
  summary: "Upgrade the app to the latest framework: bump every @voltro/* dependency (across ALL workspace members, install once at the workspace root), then run the codemods shipped with the target version. Flags: --to <version>, --from <version>, --codemods-only, --dry-run, --force, --exact, --help. After: run `voltro db apply`.",
525
525
  status: "wired",
526
- run: (e) => import("./updateCommand-us1_hdIC.js").then((t) => t.runUpdateCommand(e))
526
+ run: (e) => import("./updateCommand-BlMZhWgO.js").then((t) => t.runUpdateCommand(e))
527
527
  },
528
528
  {
529
529
  name: "_apply-codemods",
530
530
  summary: "Internal: apply shipped codemods for a framework version jump (re-exec target of `voltro update`).",
531
531
  status: "wired",
532
532
  hidden: !0,
533
- run: (e) => import("./updateCommand-us1_hdIC.js").then((t) => t.runApplyCodemods(e))
533
+ run: (e) => import("./updateCommand-BlMZhWgO.js").then((t) => t.runApplyCodemods(e))
534
534
  },
535
535
  {
536
536
  name: "embeddings",
537
537
  summary: "Embeddings tooling. Subcommand: backfill <table> --text <field> --vector <field> [--model <m>] [--model-field <f>] [--batch <n>] [--dry-run] — (re)embed rows the vectorEmbedding() mixin missed.",
538
538
  status: "wired",
539
- run: (e) => import("./embeddingsCommand-C0sKVRo1.js").then((t) => t.runEmbeddingsCommand(e)),
539
+ run: (e) => import("./embeddingsCommand-BfiLS_QI.js").then((t) => t.runEmbeddingsCommand(e)),
540
540
  help: {
541
541
  usage: "backfill <table> --text <field> --vector <field> [--model <m>] [--batch <n>] [--dry-run]",
542
542
  flags: [
@@ -577,12 +577,19 @@ var a = () => {
577
577
  notes: ["A file whose first lines carry the `voltro:agents-md:keep` marker is never overwritten."]
578
578
  }
579
579
  },
580
+ {
581
+ name: "probe",
582
+ summary: "Ask a RUNNING app whether its declared access is enforced. `access` calls every guarded procedure with NO credentials and reports any that answer (--process, --url, --strict, --format).",
583
+ status: "wired",
584
+ handlesHelp: !0,
585
+ run: (e) => import("./probeCommand-CZfaaUOZ.js").then((t) => t.runProbeCommand(e))
586
+ },
580
587
  {
581
588
  name: "schedule",
582
589
  summary: "Operate on registered schedules. `run <name>` fires one on demand (--process, --trigger manual|external, --url).",
583
590
  status: "wired",
584
591
  handlesHelp: !0,
585
- run: (e) => import("./scheduleCmd--jksTrf6.js").then((t) => t.runScheduleCommand(e))
592
+ run: (e) => import("./scheduleCmd-DQRu6BZC.js").then((t) => t.runScheduleCommand(e))
586
593
  },
587
594
  {
588
595
  name: "schedule-manifest",
@@ -604,35 +611,35 @@ var a = () => {
604
611
  handlesHelp: !0,
605
612
  summary: "Tail recent log records from every running voltro process. --tail N --since 30s --level error --filter PAT --format json|pretty|text.",
606
613
  status: "wired",
607
- run: (e) => import("./logsCmd-CCca3KRZ.js").then((t) => t.runLogsCommand(e))
614
+ run: (e) => import("./logsCmd-D36xK7Zu.js").then((t) => t.runLogsCommand(e))
608
615
  },
609
616
  {
610
617
  name: "traces",
611
618
  handlesHelp: !0,
612
619
  summary: "Distributed traces from every running api. --tail N --errors --since 30s --process NAME --format json|pretty. Use --id <traceId> for the waterfall of one trace.",
613
620
  status: "wired",
614
- run: (e) => import("./tracesCmd-CkEZQrtt.js").then((t) => t.runTracesCommand(e))
621
+ run: (e) => import("./tracesCmd-DStmCJPi.js").then((t) => t.runTracesCommand(e))
615
622
  },
616
623
  {
617
624
  name: "inspect",
618
625
  handlesHelp: !0,
619
626
  summary: "Query the live /_voltro/inspect/* surface. Subcommands: app, routes, rpc, metrics, cache, schedules, aggregates, invoke. --process NAME --format json|pretty. `schedules --failing` reports only broken crons and exits 1 if any (usable as a post-deploy gate).",
620
627
  status: "wired",
621
- run: (e) => import("./inspectCmd-Bppy-GGw.js").then((t) => t.runInspectCommand(e))
628
+ run: (e) => import("./inspectCmd-EHFZ9yYu.js").then((t) => t.runInspectCommand(e))
622
629
  },
623
630
  {
624
631
  name: "workflows",
625
632
  handlesHelp: !0,
626
633
  summary: "Inspect + operate workflow runs. Subcommands: list, show <runId>, start <name>, retry|cancel|suspend|resume <runId>, signal|update <runId> --name, children <parentExecutionId>, flow (declarative flow-control queue + ledger), pause|unpause <workflowName>.",
627
634
  status: "wired",
628
- run: (e) => import("./workflowsCmd-D1VTmLMY.js").then((t) => t.runWorkflowsCommand(e))
635
+ run: (e) => import("./workflowsCmd-BGF-mRZ5.js").then((t) => t.runWorkflowsCommand(e))
629
636
  },
630
637
  {
631
638
  name: "cluster",
632
639
  handlesHelp: !0,
633
640
  summary: "Clustering snapshot of every running api. Subcommand: status — per-instance replicaId, runner address, dialect, CDC flavor, coordination, server_id, + a flag for SQL runners stuck on localhost. --process NAME --format json|pretty.",
634
641
  status: "wired",
635
- run: (e) => import("./clusterCmd-CNXKlcvD.js").then((t) => t.runClusterCommand(e))
642
+ run: (e) => import("./clusterCmd-D5wsCmA_.js").then((t) => t.runClusterCommand(e))
636
643
  },
637
644
  {
638
645
  name: "login",
@@ -719,6 +726,7 @@ var a = () => {
719
726
  "workflows",
720
727
  "cluster",
721
728
  "check",
729
+ "probe",
722
730
  "eval",
723
731
  "doctor",
724
732
  "capabilities"
@@ -1,6 +1,6 @@
1
- import { d as e } from "./dev-CerMd0mW.js";
2
- import { P as t, j as n } from "./webDev-CBYvPqQr.js";
3
- import { t as r } from "./start-9LiUOfES.js";
1
+ import { d as e } from "./dev-C7sFZq3m.js";
2
+ import { P as t, j as n } from "./webDev-Dybxew86.js";
3
+ import { t as r } from "./start-T4VesWiM.js";
4
4
  import { join as i } from "node:path";
5
5
  import { existsSync as a } from "node:fs";
6
6
  import { createLogger as o } from "@voltro/logger";