loopable-cli 0.2.1 → 0.3.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 (134) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/_connectorId-CDCuSgpN.js +1 -0
  3. package/.output/public/assets/_loopId-DOnIsVTW.js +1 -0
  4. package/.output/public/assets/_taskId-BO5MZnlZ.js +1 -0
  5. package/.output/public/assets/agents-CBozi7oi.js +1 -0
  6. package/.output/public/assets/alert-Bn_wjgTX.js +1 -0
  7. package/.output/public/assets/button-K3ypIhAZ.js +1 -0
  8. package/.output/public/assets/card-DiVnaTIE.js +1 -0
  9. package/.output/public/assets/chevron-right-BrctLtFK.js +1 -0
  10. package/.output/public/assets/connection-status-DKWelvLO.js +1 -0
  11. package/.output/public/assets/connector-icon-CEbdE71G.js +1 -0
  12. package/.output/public/assets/connectors-JyX3IzJj.js +1 -0
  13. package/.output/public/assets/gaps-PjmcbaWo.js +1 -0
  14. package/.output/public/assets/inbox-CujRR0Cz.js +1 -0
  15. package/.output/public/assets/index-C9SQ_Baq.js +16 -0
  16. package/.output/public/assets/loop-form-Dw3cuTzw.js +1 -0
  17. package/.output/public/assets/loops-DcEfZa2_.js +1 -0
  18. package/.output/public/assets/manifests-yJpevyye.js +1 -0
  19. package/.output/public/assets/new-CwsnNuRW.js +1 -0
  20. package/.output/public/assets/page-bvnfRMum.js +1 -0
  21. package/.output/public/assets/play-yHLs4DjK.js +1 -0
  22. package/.output/public/assets/plus-Ber25lrU.js +1 -0
  23. package/.output/public/assets/preload-helper-BoU_7EQC.js +3 -0
  24. package/.output/public/assets/{refresh-cw-C3xBnKfy.js → refresh-cw-BzSY7M8I.js} +1 -1
  25. package/.output/public/assets/rotate-ccw-DLv9EfCX.js +1 -0
  26. package/.output/public/assets/runners-DzX-RU3i.js +2 -0
  27. package/.output/public/assets/select-C9grIFwG.js +1 -0
  28. package/.output/public/assets/setting-fields-DUc3npgh.js +3 -0
  29. package/.output/public/assets/styles-B9B98zLk.css +2 -0
  30. package/.output/public/assets/switch-DwABVI6d.js +1 -0
  31. package/.output/public/assets/task-list-Ddk8-qt7.js +1 -0
  32. package/.output/public/assets/textarea-Ds-gIYUQ.js +1 -0
  33. package/.output/public/assets/time-goBWd-5J.js +1 -0
  34. package/.output/public/assets/use-live-tasks-DZNNuECy.js +1 -0
  35. package/.output/public/assets/useCompositeListItem-P4Nmmn7j.js +1 -0
  36. package/.output/public/assets/usePositioner-B7i9Ejzh.js +1 -0
  37. package/.output/server/_chunks/ssr-renderer.mjs +1 -1
  38. package/.output/server/{_connectorId-C9yydJrC.mjs → _connectorId-COuQN02a.mjs} +198 -188
  39. package/.output/server/_libs/@base-ui/react+[...].mjs +1410 -804
  40. package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
  41. package/.output/server/_libs/lucide-react.mjs +93 -84
  42. package/.output/server/_libs/next-themes.mjs +1 -1
  43. package/.output/server/_libs/sonner.mjs +1 -1
  44. package/.output/server/_loopId-CZh6_Yhr.mjs +310 -0
  45. package/.output/server/_ssr/{agents-DG643yoJ.mjs → agents-B_qo1gpL.mjs} +195 -6
  46. package/.output/server/_ssr/{agents-C7B6RJ6-.mjs → agents-Bz10gz_m.mjs} +8 -8
  47. package/.output/server/_ssr/agents-CjbOUp3Z.mjs +206 -0
  48. package/.output/server/_ssr/{alert-DQvzE7bu.mjs → alert-C2WBWfzo.mjs} +2 -2
  49. package/.output/server/_ssr/card-r1cV-PCN.mjs +36 -0
  50. package/.output/server/_ssr/{client-BtVRVhQ2.mjs → client-Dk3SD8Il.mjs} +5 -1
  51. package/.output/server/_ssr/connection-status-BogAL-Fj.mjs +32 -0
  52. package/.output/server/_ssr/{connections-Df-aDpfJ.mjs → connections-Cqvb6Gw2.mjs} +372 -325
  53. package/.output/server/_ssr/connector-icon-DrhVbhs6.mjs +190 -0
  54. package/.output/server/_ssr/connectors-BfS5tQKr.mjs +81 -0
  55. package/.output/server/_ssr/{connectors-e0mf2pMs.mjs → connectors-DJI-rzPU.mjs} +10 -10
  56. package/.output/server/_ssr/{createServerRpc-DPDrnFdH.mjs → createServerRpc-DDrp2nLT.mjs} +2 -2
  57. package/.output/server/_ssr/{gaps-Cz76ZicM.mjs → gaps-CcvHiLcj.mjs} +15 -7
  58. package/.output/server/_ssr/inbox-D1ef761v.mjs +178 -0
  59. package/.output/server/_ssr/loop-form-DWwOR05R.mjs +346 -0
  60. package/.output/server/_ssr/{loops-D8WuK7Ke.mjs → loops-6WhUe_lc.mjs} +37 -27
  61. package/.output/server/_ssr/loops-DHPjzG-t.mjs +217 -0
  62. package/.output/server/_ssr/new-ChKBdcXJ.mjs +245 -0
  63. package/.output/server/_ssr/page-DZVxKvdn.mjs +120 -0
  64. package/.output/server/_ssr/{router-54IDWTVz.mjs → router-DdwREiOf.mjs} +162 -489
  65. package/.output/server/_ssr/runners-CK9Cx9fS.mjs +217 -0
  66. package/.output/server/_ssr/runners-CrznFPHt.mjs +140 -0
  67. package/.output/server/_ssr/{runners-Cj6z9Mqh.mjs → runners-W-pgo5yo.mjs} +5 -5
  68. package/.output/server/_ssr/{secrets-CRnpwGBh.mjs → secrets-CV5scFlt.mjs} +2 -2
  69. package/.output/server/_ssr/select-BtndHhHb.mjs +76 -0
  70. package/.output/server/_ssr/{setting-fields-DzBlslan.mjs → setting-fields-LNgywAW7.mjs} +25 -20
  71. package/.output/server/_ssr/ssr.mjs +43 -42
  72. package/.output/server/_ssr/{start-Vq3Oan3v.mjs → start-C_j-e4vF.mjs} +9 -4
  73. package/.output/server/_ssr/{switch-1pnd_bPJ.mjs → switch-odxNO_S4.mjs} +3 -3
  74. package/.output/server/_ssr/task-list-Dnmq_WeE.mjs +150 -0
  75. package/.output/server/_ssr/{tasks-Qtml5TlK.mjs → tasks-D-kXLgVP.mjs} +13 -13
  76. package/.output/server/_ssr/{tasks-BDqznm57.mjs → tasks-D7aUvA33.mjs} +44 -17
  77. package/.output/server/_ssr/{textarea-CHJTKtsJ.mjs → textarea-D2c_vTIC.mjs} +2 -2
  78. package/.output/server/_ssr/time-Cy8TZP0Z.mjs +13 -0
  79. package/.output/server/_ssr/use-live-tasks-BzhTkEOL.mjs +40 -0
  80. package/.output/server/_tanstack-start-manifest_v-2HUdn-2E.mjs +166 -0
  81. package/.output/server/_taskId-D3KkNJW1.mjs +263 -0
  82. package/.output/server/index.mjs +199 -164
  83. package/README.md +36 -6
  84. package/dist/cli.mjs +161 -8
  85. package/dist/dispatcher.mjs +671 -285
  86. package/dist/runner.mjs +333 -46
  87. package/drizzle/0025_prompt_tasks_done.sql +2 -0
  88. package/drizzle/0026_guidance_into_prompt.sql +3 -0
  89. package/drizzle/0027_relative_folders.sql +5 -0
  90. package/drizzle/0028_runner_version.sql +5 -0
  91. package/drizzle/meta/_journal.json +29 -1
  92. package/package.json +4 -2
  93. package/.output/public/assets/_connectorId-CkygNLny.js +0 -1
  94. package/.output/public/assets/_loopId-Cshlc5Ja.js +0 -1
  95. package/.output/public/assets/_taskId-BKDIJ_Fg.js +0 -1
  96. package/.output/public/assets/alert-BT2EVMJP.js +0 -1
  97. package/.output/public/assets/arrow-left-CWUZt6k2.js +0 -1
  98. package/.output/public/assets/arrow-right-dy_oOg_c.js +0 -1
  99. package/.output/public/assets/connection-status-DCqqmY_6.js +0 -1
  100. package/.output/public/assets/connector-icon-BUoK6Cru.js +0 -1
  101. package/.output/public/assets/connectors-CeLBtEtg.js +0 -1
  102. package/.output/public/assets/external-link-DC11orFA.js +0 -1
  103. package/.output/public/assets/gaps-BtFoD7mF.js +0 -1
  104. package/.output/public/assets/inbox-BYNjkNDJ.js +0 -1
  105. package/.output/public/assets/index-0yP3Jn_G.js +0 -18
  106. package/.output/public/assets/loader-B4Epchm_.js +0 -1
  107. package/.output/public/assets/loop-form-DnSJNc1k.js +0 -1
  108. package/.output/public/assets/loops-1CvbqO6m.js +0 -1
  109. package/.output/public/assets/new-m5NlqYQT.js +0 -1
  110. package/.output/public/assets/play-DD4xQgvi.js +0 -1
  111. package/.output/public/assets/preload-helper-CfdAYKD7.js +0 -3
  112. package/.output/public/assets/rolldown-runtime-CbXtAM7H.js +0 -1
  113. package/.output/public/assets/runners-D8QVl-Y6.js +0 -1
  114. package/.output/public/assets/select-Cppu-hti.js +0 -1
  115. package/.output/public/assets/setting-fields-bJ_gTG7Q.js +0 -3
  116. package/.output/public/assets/styles-ClTGaXU0.css +0 -2
  117. package/.output/public/assets/switch-hRIbNGOj.js +0 -1
  118. package/.output/public/assets/task-list-BAxjcVgr.js +0 -1
  119. package/.output/public/assets/textarea-Fyuzi6Vp.js +0 -1
  120. package/.output/public/assets/trash-2-BXZzBsoV.js +0 -1
  121. package/.output/public/assets/useValueChanged-VVyq4hb9.js +0 -1
  122. package/.output/server/_loopId-B0VG-eBC.mjs +0 -301
  123. package/.output/server/_ssr/connection-status-BZr3Y-IC.mjs +0 -31
  124. package/.output/server/_ssr/connector-icon-WvxwZ5TF.mjs +0 -56
  125. package/.output/server/_ssr/connectors-BU0IiRge.mjs +0 -107
  126. package/.output/server/_ssr/inbox-CAUBa1I3.mjs +0 -114
  127. package/.output/server/_ssr/loop-form-FqSaXiHl.mjs +0 -413
  128. package/.output/server/_ssr/loops-Dqoebe8q.mjs +0 -222
  129. package/.output/server/_ssr/new-bBsVaWD6.mjs +0 -169
  130. package/.output/server/_ssr/runners-D2UAdLyj.mjs +0 -106
  131. package/.output/server/_ssr/runners-DGWaVvWi.mjs +0 -116
  132. package/.output/server/_ssr/task-list-_qgBS9LU.mjs +0 -187
  133. package/.output/server/_tanstack-start-manifest_v-CvheE7ZF.mjs +0 -131
  134. package/.output/server/_taskId-V4QLBO2N.mjs +0 -256
package/dist/cli.mjs CHANGED
@@ -2189,6 +2189,130 @@ var init_drizzle_orm = __esm({
2189
2189
  }
2190
2190
  });
2191
2191
 
2192
+ // package.json
2193
+ var package_default;
2194
+ var init_package = __esm({
2195
+ "package.json"() {
2196
+ package_default = {
2197
+ name: "loopable-cli",
2198
+ version: "0.2.1",
2199
+ description: "CLI to run Loopable: App, Dispatcher, and Runner.",
2200
+ license: "MIT",
2201
+ type: "module",
2202
+ bin: {
2203
+ loopable: "./dist/cli.mjs"
2204
+ },
2205
+ files: [
2206
+ ".output",
2207
+ "dist",
2208
+ "drizzle"
2209
+ ],
2210
+ engines: {
2211
+ node: ">=22"
2212
+ },
2213
+ packageManager: "pnpm@11.22.0",
2214
+ repository: {
2215
+ type: "git",
2216
+ url: "git+https://github.com/imsobear/loopable.git"
2217
+ },
2218
+ bugs: {
2219
+ url: "https://github.com/imsobear/loopable/issues"
2220
+ },
2221
+ homepage: "https://github.com/imsobear/loopable#readme",
2222
+ publishConfig: {
2223
+ access: "public"
2224
+ },
2225
+ imports: {
2226
+ "#/*": "./src/*"
2227
+ },
2228
+ scripts: {
2229
+ dev: "node --experimental-strip-types scripts/dev.ts",
2230
+ start: "node dist/cli.mjs start",
2231
+ dispatcher: "LOOPABLE_DEV=1 node --experimental-strip-types src/cli.ts dispatcher",
2232
+ runner: "LOOPABLE_DEV=1 node --experimental-strip-types src/cli.ts runner",
2233
+ "generate-routes": "tsr generate",
2234
+ build: "vite build && node scripts/build-cli.mjs",
2235
+ preview: "vite preview",
2236
+ test: "vitest run",
2237
+ "test:watch": "vitest",
2238
+ "db:generate": "drizzle-kit generate",
2239
+ "db:studio": "LOOPABLE_DEV=1 drizzle-kit studio",
2240
+ typecheck: "tsc --noEmit",
2241
+ release: "node scripts/release.mjs",
2242
+ deploy: "LOOPABLE_CF=1 vite build && wrangler deploy",
2243
+ "site:dev": "pnpm --filter loopable-site dev",
2244
+ "site:build": "pnpm --filter loopable-site build",
2245
+ "site:deploy": "pnpm --filter loopable-site deploy",
2246
+ prepublishOnly: "pnpm typecheck && pnpm test && pnpm build"
2247
+ },
2248
+ dependencies: {
2249
+ "@libsql/client": "^0.18.0"
2250
+ },
2251
+ devDependencies: {
2252
+ "@base-ui/react": "^1.7.0",
2253
+ "@cloudflare/containers": "^0.3.7",
2254
+ "@cloudflare/vite-plugin": "^1.54.10",
2255
+ "@fontsource-variable/geist": "^5.3.0",
2256
+ "@tailwindcss/vite": "4.1.18",
2257
+ "@tanstack/devtools-vite": "0.8.5",
2258
+ "@tanstack/react-devtools": "0.10.12",
2259
+ "@tanstack/react-router": "1.170.32",
2260
+ "@tanstack/react-router-devtools": "1.167.1",
2261
+ "@tanstack/react-start": "1.168.49",
2262
+ "@tanstack/router-cli": "1.167.33",
2263
+ "@types/node": "^22.10.2",
2264
+ "@types/qrcode": "^1.5.6",
2265
+ "@types/react": "^19.2.0",
2266
+ "@types/react-dom": "^19.2.0",
2267
+ "@vitejs/plugin-react": "^6.0.1",
2268
+ "class-variance-authority": "^0.7.1",
2269
+ clsx: "^2.1.1",
2270
+ "drizzle-kit": "^0.31.10",
2271
+ "drizzle-orm": "^0.45.2",
2272
+ esbuild: "^0.28.2",
2273
+ "lucide-react": "^1.39.0",
2274
+ "next-themes": "^0.4.6",
2275
+ nitro: "3.0.260610-beta",
2276
+ qrcode: "^1.5.4",
2277
+ react: "19.2.0",
2278
+ "react-dom": "19.2.0",
2279
+ shadcn: "^4.19.1",
2280
+ sonner: "^2.0.8",
2281
+ "tailwind-merge": "^3.6.0",
2282
+ tailwindcss: "4.1.18",
2283
+ "tw-animate-css": "^1.4.0",
2284
+ typescript: "^6.0.2",
2285
+ vite: "^8.0.0",
2286
+ vitest: "^4.1.11",
2287
+ wrangler: "^4.132.0"
2288
+ }
2289
+ };
2290
+ }
2291
+ });
2292
+
2293
+ // src/lib/version.ts
2294
+ function olderThan(a, b) {
2295
+ if (!a) return true;
2296
+ const pa = a.split(".").map((part) => Number.parseInt(part, 10));
2297
+ const pb = b.split(".").map((part) => Number.parseInt(part, 10));
2298
+ for (let i = 0; i < 3; i++) {
2299
+ const x = pa[i] ?? 0;
2300
+ const y = pb[i] ?? 0;
2301
+ if (Number.isNaN(x)) return true;
2302
+ if (x !== y) return x < y;
2303
+ }
2304
+ return false;
2305
+ }
2306
+ var VERSION, RUNNER_PROTOCOL, LEGACY_RUNNER_PROTOCOL;
2307
+ var init_version2 = __esm({
2308
+ "src/lib/version.ts"() {
2309
+ init_package();
2310
+ VERSION = package_default.version;
2311
+ RUNNER_PROTOCOL = 2;
2312
+ LEGACY_RUNNER_PROTOCOL = 1;
2313
+ }
2314
+ });
2315
+
2192
2316
  // node_modules/.pnpm/drizzle-orm@0.45.2_@libsql+client@0.18.0_@types+better-sqlite3@9.6.0_better-sqlite3@13.0.3/node_modules/drizzle-orm/selection-proxy.js
2193
2317
  var SelectionProxyHandler;
2194
2318
  var init_selection_proxy = __esm({
@@ -6705,6 +6829,10 @@ var init_schema = __esm({
6705
6829
  status: text("status").$type().notNull().default("offline"),
6706
6830
  inventory: text("inventory", { mode: "json" }).$type().notNull().default([]),
6707
6831
  lastSeenAt: integer("last_seen_at", { mode: "timestamp_ms" }),
6832
+ /** The runner's loopable-cli version. Null for runners before 0.3. */
6833
+ version: text("version"),
6834
+ /** What jobs it understands; see RUNNER_PROTOCOL. Null means the first. */
6835
+ protocol: integer("protocol"),
6708
6836
  createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(sql`(unixepoch() * 1000)`)
6709
6837
  });
6710
6838
  }
@@ -6912,11 +7040,21 @@ __export(runners_exports, {
6912
7040
  listRunners: () => listRunners,
6913
7041
  onlineRunnerCount: () => onlineRunnerCount,
6914
7042
  pickRunner: () => pickRunner,
7043
+ protocolOf: () => protocolOf,
6915
7044
  rotateJoinToken: () => rotateJoinToken,
6916
7045
  runnerIdForToken: () => runnerIdForToken
6917
7046
  });
6918
7047
  import { randomBytes, randomUUID } from "node:crypto";
6919
7048
  import { hostname as osHostname } from "node:os";
7049
+ function protocolOf(row) {
7050
+ return row.protocol ?? LEGACY_RUNNER_PROTOCOL;
7051
+ }
7052
+ function buildFields(build) {
7053
+ return {
7054
+ version: typeof build.version === "string" && build.version ? build.version : null,
7055
+ protocol: typeof build.protocol === "number" ? build.protocol : null
7056
+ };
7057
+ }
6920
7058
  function isRunnerOnline(row, now = Date.now()) {
6921
7059
  if (row.status !== "online") return false;
6922
7060
  if (!row.lastSeenAt) return false;
@@ -6930,7 +7068,10 @@ function toView(row, now = Date.now()) {
6930
7068
  hostname: row.hostname,
6931
7069
  status: online ? "online" : "offline",
6932
7070
  inventory: row.inventory,
6933
- lastSeenAt: row.lastSeenAt?.toISOString() ?? null
7071
+ lastSeenAt: row.lastSeenAt?.toISOString() ?? null,
7072
+ version: row.version,
7073
+ protocol: protocolOf(row),
7074
+ outdated: protocolOf(row) < RUNNER_PROTOCOL || olderThan(row.version, VERSION)
6934
7075
  };
6935
7076
  }
6936
7077
  async function listRunners() {
@@ -6960,11 +7101,13 @@ async function busyRunnerIds() {
6960
7101
  )
6961
7102
  );
6962
7103
  }
6963
- async function availableAgentIds(requiresHost = false) {
7104
+ async function availableAgentIds(requiresHost = false, minProtocol = 0) {
6964
7105
  const local = osHostname();
6965
7106
  return [
6966
7107
  ...new Set(
6967
- (await listRunners()).filter((row) => row.status === "online" && (!requiresHost || row.hostname === local)).flatMap(
7108
+ (await listRunners()).filter(
7109
+ (row) => row.status === "online" && (!requiresHost || row.hostname === local) && row.protocol >= minProtocol
7110
+ ).flatMap(
6968
7111
  (row) => row.inventory.filter((entry) => entry.installed && entry.signedIn).map((entry) => entry.agentId)
6969
7112
  )
6970
7113
  )
@@ -6973,9 +7116,11 @@ async function availableAgentIds(requiresHost = false) {
6973
7116
  async function pickRunner(input) {
6974
7117
  const now = Date.now();
6975
7118
  const local = osHostname();
6976
- let candidates = (await db().select().from(runners).all()).filter(
7119
+ const minProtocol = input.minProtocol ?? 0;
7120
+ const capable = (await db().select().from(runners).all()).filter(
6977
7121
  (row) => isRunnerOnline(row, now) && runnerCanRun(row, input.agentId)
6978
7122
  );
7123
+ let candidates = capable.filter((row) => protocolOf(row) >= minProtocol);
6979
7124
  if (input.requiresHost) {
6980
7125
  candidates = candidates.filter((row) => row.hostname === local);
6981
7126
  }
@@ -6986,6 +7131,11 @@ async function pickRunner(input) {
6986
7131
  if (input.requiresHost) {
6987
7132
  throw new Error("This job needs a runner on the same host as Loopable.");
6988
7133
  }
7134
+ if (capable.length > 0) {
7135
+ throw new Error(
7136
+ "Every runner with this agent is too old for this job. Upgrade them with npm install -g loopable-cli."
7137
+ );
7138
+ }
6989
7139
  throw new Error("No runner is online that can run this agent.");
6990
7140
  }
6991
7141
  async function getJoinToken() {
@@ -7000,10 +7150,10 @@ async function rotateJoinToken() {
7000
7150
  await secretStore().set(joinTokenKey(), token);
7001
7151
  return token;
7002
7152
  }
7003
- async function heartbeatRunner(runnerId, inventory) {
7153
+ async function heartbeatRunner(runnerId, inventory, build = {}) {
7004
7154
  const row = await getRunner(runnerId);
7005
7155
  if (!row) throw new Error("Unknown runner.");
7006
- await db().update(runners).set({ status: "online", inventory, lastSeenAt: /* @__PURE__ */ new Date() }).where(eq(runners.id, runnerId)).run();
7156
+ await db().update(runners).set({ status: "online", inventory, lastSeenAt: /* @__PURE__ */ new Date(), ...buildFields(build) }).where(eq(runners.id, runnerId)).run();
7007
7157
  return toView(await getRunner(runnerId));
7008
7158
  }
7009
7159
  async function joinRunner(input) {
@@ -7022,7 +7172,8 @@ async function joinRunner(input) {
7022
7172
  status: "online",
7023
7173
  inventory: input.inventory,
7024
7174
  lastSeenAt: now,
7025
- hostname: input.hostname
7175
+ hostname: input.hostname,
7176
+ ...buildFields(input)
7026
7177
  }).where(eq(runners.id, id)).run();
7027
7178
  } else {
7028
7179
  await db().insert(runners).values({
@@ -7031,7 +7182,8 @@ async function joinRunner(input) {
7031
7182
  hostname: input.hostname,
7032
7183
  status: "online",
7033
7184
  inventory: input.inventory,
7034
- lastSeenAt: now
7185
+ lastSeenAt: now,
7186
+ ...buildFields(input)
7035
7187
  }).run();
7036
7188
  }
7037
7189
  const token = randomBytes(24).toString("base64url");
@@ -7062,6 +7214,7 @@ var init_runners = __esm({
7062
7214
  "src/server/runners.ts"() {
7063
7215
  "use strict";
7064
7216
  init_drizzle_orm();
7217
+ init_version2();
7065
7218
  init_client();
7066
7219
  init_schema();
7067
7220
  init_secrets();