@camox/cli 0.14.2 → 0.15.1

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.
@@ -9,10 +9,12 @@ function authHeaders(token) {
9
9
  "Content-Type": "application/json"
10
10
  };
11
11
  }
12
- function createRpcClient(token) {
12
+ function createRpcClient(token, apiUrl = CAMOX_API_URL, environmentName) {
13
+ const headers = { Authorization: `Bearer ${token}` };
14
+ if (environmentName) headers["x-environment-name"] = environmentName;
13
15
  return createORPCClient(new RPCLink({
14
- url: `${CAMOX_API_URL}/rpc`,
15
- headers: { Authorization: `Bearer ${token}` }
16
+ url: `${apiUrl}/rpc`,
17
+ headers
16
18
  }));
17
19
  }
18
20
  async function verifySession(token) {
@@ -62,5 +64,15 @@ async function createProject(token, name, slug, organizationId) {
62
64
  organizationId
63
65
  });
64
66
  }
67
+ async function getProjectBySlug(token, slug, apiUrl) {
68
+ return createRpcClient(token, apiUrl).projects.getBySlug({ slug });
69
+ }
70
+ async function callTool(params) {
71
+ return await createRpcClient(params.token, params.apiUrl, params.environmentName).agent.callTool({
72
+ projectId: params.projectId,
73
+ name: params.name,
74
+ arguments: params.args
75
+ });
76
+ }
65
77
  //#endregion
66
- export { setActiveOrganization as a, listOrganizations as i, createOrganization as n, verifySession as o, createProject as r, checkSlugAvailability as t };
78
+ export { getProjectBySlug as a, verifySession as c, createProject as i, checkSlugAvailability as n, listOrganizations as o, createOrganization as r, setActiveOrganization as s, callTool as t };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { c as verifySession } from "./api-Bgstxixw.mjs";
3
+ export { verifySession };
package/dist/index.mjs CHANGED
@@ -1,31 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { a as setActiveOrganization, i as listOrganizations, n as createOrganization, r as createProject, t as checkSlugAvailability } from "./api-QINint5w.mjs";
2
+ import { a as getProjectBySlug, i as createProject, n as checkSlugAvailability, o as listOrganizations, r as createOrganization, s as setActiveOrganization, t as callTool } from "./api-Bgstxixw.mjs";
3
3
  import { object, or } from "@optique/core/constructs";
4
4
  import { message } from "@optique/core/message";
5
5
  import { defineProgram } from "@optique/core/program";
6
- import { run } from "@optique/run";
6
+ import { runSync } from "@optique/run";
7
+ import { multiple, optional } from "@optique/core/modifiers";
8
+ import { command, constant, option } from "@optique/core/primitives";
9
+ import { integer, string } from "@optique/core/valueparser";
7
10
  import { execSync, spawn, spawnSync } from "node:child_process";
8
11
  import fs from "node:fs";
12
+ import http from "node:http";
13
+ import os from "node:os";
9
14
  import path from "node:path";
10
- import { fileURLToPath } from "node:url";
11
15
  import * as p from "@clack/prompts";
12
16
  import { log } from "@clack/prompts";
13
- import { command, constant } from "@optique/core/primitives";
17
+ import { ZodError, z } from "zod";
18
+ import { fileURLToPath } from "node:url";
14
19
  import slugify from "slugify";
15
- import http from "node:http";
16
- import os from "node:os";
17
- //#region \0rolldown/runtime.js
18
- var __defProp = Object.defineProperty;
19
- var __exportAll = (all, no_symbols) => {
20
- let target = {};
21
- for (var name in all) __defProp(target, name, {
22
- get: all[name],
23
- enumerable: true
24
- });
25
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
26
- return target;
27
- };
28
- //#endregion
29
20
  //#region src/lib/auth.ts
30
21
  const CAMOX_URL = process.env.CAMOX_URL || "https://camox.ai";
31
22
  const CAMOX_API_URL = process.env.CAMOX_API_URL || "https://api.camox.ai";
@@ -47,7 +38,15 @@ function writeAllTokens(tokens) {
47
38
  fs.writeFileSync(AUTH_FILE, JSON.stringify(tokens, null, 2), { mode: 384 });
48
39
  }
49
40
  function readAuthToken() {
50
- const entry = readAllTokens()[normalizeUrl(CAMOX_URL)];
41
+ return readAuthTokenForUrl(CAMOX_URL);
42
+ }
43
+ /**
44
+ * Look up a stored token by an explicit auth URL. Used by the tool dispatch
45
+ * path, which sources the URL from the vite plugin sidecar rather than env
46
+ * vars so the right credential is selected per project.
47
+ */
48
+ function readAuthTokenForUrl(authenticationUrl) {
49
+ const entry = readAllTokens()[normalizeUrl(authenticationUrl)];
51
50
  if (entry?.token && entry?.name) return entry;
52
51
  return null;
53
52
  }
@@ -174,7 +173,7 @@ async function authenticateUser() {
174
173
  async function getOrAuthenticate() {
175
174
  const stored = readAuthToken();
176
175
  if (stored) {
177
- const { verifySession } = await import("./api-CB7vjDU7.mjs");
176
+ const { verifySession } = await import("./api-DoFRj7vC.mjs");
178
177
  if (await verifySession(stored.token)) {
179
178
  p.log.info(`Authenticated as ${stored.name}`);
180
179
  return stored;
@@ -185,6 +184,306 @@ async function getOrAuthenticate() {
185
184
  return authenticateUser();
186
185
  }
187
186
  //#endregion
187
+ //#region src/lib/output.ts
188
+ function isJsonMode(mode) {
189
+ if (mode === "json") return true;
190
+ return !process.stdout.isTTY;
191
+ }
192
+ function printResult(value, mode) {
193
+ const indent = isJsonMode(mode) ? 0 : 2;
194
+ process.stdout.write(`${JSON.stringify(value, null, indent)}\n`);
195
+ }
196
+ function printError(err) {
197
+ process.stderr.write(`${JSON.stringify(err)}\n`);
198
+ }
199
+ /**
200
+ * Parse a JSON flag value, surfacing a structured CLI error if the input
201
+ * isn't valid JSON. Block `content` and `settings` arrive this way.
202
+ */
203
+ function parseJsonFlag(name, raw) {
204
+ try {
205
+ return JSON.parse(raw);
206
+ } catch (e) {
207
+ const message = e instanceof Error ? e.message : String(e);
208
+ throw Object.assign(/* @__PURE__ */ new Error(`Invalid JSON for ${name}: ${message}`), { __cliError: {
209
+ code: "INVALID_JSON",
210
+ message: `Invalid JSON for ${name}`,
211
+ details: message
212
+ } });
213
+ }
214
+ }
215
+ function asCliError(err) {
216
+ if (err && typeof err === "object" && "__cliError" in err) return err.__cliError;
217
+ if (err instanceof Error) return {
218
+ code: "INTERNAL_ERROR",
219
+ message: err.message
220
+ };
221
+ return {
222
+ code: "INTERNAL_ERROR",
223
+ message: String(err)
224
+ };
225
+ }
226
+ //#endregion
227
+ //#region src/lib/runtime.ts
228
+ /**
229
+ * Subset of the camox vite plugin's options that the CLI needs at dispatch
230
+ * time. Written by the plugin to `node_modules/.camox/runtime.json` on every
231
+ * `configResolved` (dev + build), so it always reflects what vite actually
232
+ * loaded — including `_internal.apiUrl` overrides.
233
+ *
234
+ * Schema is the source of truth; the TS type is derived from it via
235
+ * `z.infer` so the two never drift.
236
+ */
237
+ const runtimeSchema = z.object({
238
+ projectSlug: z.string().min(1),
239
+ apiUrl: z.string().url(),
240
+ authenticationUrl: z.string().url(),
241
+ environmentName: z.string().min(1)
242
+ });
243
+ const SIDECAR = path.join("node_modules", ".camox", "runtime.json");
244
+ var RuntimeNotFoundError = class extends Error {
245
+ cwd;
246
+ constructor(cwd) {
247
+ super(`No camox runtime found. Looked for "${SIDECAR}" walking up from ${cwd}. The camox vite plugin writes this file on dev/build — start your project's dev server (or run a build) once before invoking camox.`);
248
+ this.cwd = cwd;
249
+ this.name = "RuntimeNotFoundError";
250
+ }
251
+ };
252
+ var RuntimeMalformedError = class extends Error {
253
+ constructor(file, reason) {
254
+ super(`Camox runtime sidecar at ${file} is malformed (${reason}). Re-run your project's dev server to regenerate it.`);
255
+ this.name = "RuntimeMalformedError";
256
+ }
257
+ };
258
+ /**
259
+ * Walk up from cwd looking for the sidecar. Validates against `runtimeSchema`
260
+ * and throws `RuntimeNotFoundError` / `RuntimeMalformedError` with messages
261
+ * that tell the user how to fix it.
262
+ */
263
+ function loadRuntime(cwd = process.cwd()) {
264
+ let dir = cwd;
265
+ while (true) {
266
+ const candidate = path.join(dir, SIDECAR);
267
+ if (fs.existsSync(candidate)) {
268
+ let raw;
269
+ try {
270
+ raw = JSON.parse(fs.readFileSync(candidate, "utf-8"));
271
+ } catch (e) {
272
+ throw new RuntimeMalformedError(candidate, e instanceof Error ? e.message : String(e));
273
+ }
274
+ try {
275
+ return runtimeSchema.parse(raw);
276
+ } catch (e) {
277
+ if (e instanceof ZodError) throw new RuntimeMalformedError(candidate, e.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; "));
278
+ throw e;
279
+ }
280
+ }
281
+ const parent = path.dirname(dir);
282
+ if (parent === dir) throw new RuntimeNotFoundError(cwd);
283
+ dir = parent;
284
+ }
285
+ }
286
+ //#endregion
287
+ //#region src/lib/dispatch.ts
288
+ /**
289
+ * Strip undefined fields. Optique returns `undefined` for absent optional
290
+ * flags, but the tool's Zod input often distinguishes `key: undefined` from
291
+ * the key being absent. Send only the keys the user actually passed.
292
+ */
293
+ function compact(input) {
294
+ const out = {};
295
+ for (const [k, v] of Object.entries(input)) if (v !== void 0) out[k] = v;
296
+ return out;
297
+ }
298
+ function fail(err, code) {
299
+ printError(err);
300
+ process.exit(code);
301
+ }
302
+ async function resolveProjectId(token, slug, apiUrl) {
303
+ try {
304
+ return (await getProjectBySlug(token, slug, apiUrl)).id;
305
+ } catch (err) {
306
+ return fail({
307
+ code: "PROJECT_LOOKUP_FAILED",
308
+ message: `Could not load project "${slug}".`,
309
+ details: err instanceof Error ? err.message : String(err)
310
+ }, 2);
311
+ }
312
+ }
313
+ async function callRemote(params) {
314
+ try {
315
+ return await callTool(params);
316
+ } catch (err) {
317
+ return fail(asCliError(err), 1);
318
+ }
319
+ }
320
+ /**
321
+ * Resolve auth + project, call the registered tool via `agent.callTool`,
322
+ * and render the result. Exit codes: 0 on success, 1 on tool error, 2 on
323
+ * auth/project resolution failure.
324
+ *
325
+ * Project, apiUrl, and authenticationUrl all come from the vite plugin's
326
+ * `node_modules/.camox/runtime.json` sidecar — that's the single source of
327
+ * truth. `--project <slug>` and `CAMOX_PROJECT` may override the slug.
328
+ */
329
+ async function dispatch(opts) {
330
+ let runtime;
331
+ try {
332
+ runtime = loadRuntime();
333
+ } catch (err) {
334
+ if (err instanceof RuntimeNotFoundError || err instanceof RuntimeMalformedError) return fail({
335
+ code: "RUNTIME_NOT_FOUND",
336
+ message: err.message
337
+ }, 2);
338
+ throw err;
339
+ }
340
+ const slug = opts.projectFlag?.trim() || process.env.CAMOX_PROJECT?.trim() || runtime.projectSlug;
341
+ const token = readAuthTokenForUrl(runtime.authenticationUrl);
342
+ if (!token) return fail({
343
+ code: "NOT_AUTHENTICATED",
344
+ message: `No stored credentials for ${runtime.authenticationUrl}. Run \`camox login\` against this backend first.`
345
+ }, 2);
346
+ const environmentName = opts.production ? "production" : runtime.environmentName;
347
+ const projectId = await resolveProjectId(token.token, slug, runtime.apiUrl);
348
+ const response = await callRemote({
349
+ token: token.token,
350
+ apiUrl: runtime.apiUrl,
351
+ environmentName,
352
+ projectId,
353
+ name: opts.toolName,
354
+ args: compact(opts.args)
355
+ });
356
+ if (!response.ok) {
357
+ printError(response.error);
358
+ process.exit(1);
359
+ }
360
+ printResult(response.result, opts.outputMode);
361
+ process.exit(0);
362
+ }
363
+ //#endregion
364
+ //#region src/commands/blocks.ts
365
+ const projectFlag$2 = optional(option("--project", string({ metavar: "SLUG" })));
366
+ const jsonFlag$2 = option("--json");
367
+ const productionFlag$2 = option("--production");
368
+ const parser$6 = command("blocks", or(command("types", object({
369
+ command: constant("blocks.types"),
370
+ project: projectFlag$2,
371
+ production: productionFlag$2,
372
+ json: jsonFlag$2
373
+ })), command("describe", object({
374
+ command: constant("blocks.describe"),
375
+ type: multiple(option("--type", string({ metavar: "TYPE" })), { min: 1 }),
376
+ project: projectFlag$2,
377
+ production: productionFlag$2,
378
+ json: jsonFlag$2
379
+ })), command("create", object({
380
+ command: constant("blocks.create"),
381
+ pageId: option("--page-id", integer({ metavar: "ID" })),
382
+ type: option("--type", string({ metavar: "TYPE" })),
383
+ content: option("--content", string({ metavar: "JSON" })),
384
+ settings: optional(option("--settings", string({ metavar: "JSON" }))),
385
+ afterPosition: optional(option("--after-position", string({ metavar: "POS" }))),
386
+ project: projectFlag$2,
387
+ production: productionFlag$2,
388
+ json: jsonFlag$2
389
+ })), command("edit", object({
390
+ command: constant("blocks.edit"),
391
+ id: option("--id", integer({ metavar: "ID" })),
392
+ content: optional(option("--content", string({ metavar: "JSON" }))),
393
+ settings: optional(option("--settings", string({ metavar: "JSON" }))),
394
+ project: projectFlag$2,
395
+ production: productionFlag$2,
396
+ json: jsonFlag$2
397
+ })), command("move", object({
398
+ command: constant("blocks.move"),
399
+ id: option("--id", integer({ metavar: "ID" })),
400
+ afterPosition: optional(option("--after-position", string({ metavar: "POS" }))),
401
+ project: projectFlag$2,
402
+ production: productionFlag$2,
403
+ json: jsonFlag$2
404
+ })), command("delete", object({
405
+ command: constant("blocks.delete"),
406
+ id: option("--id", integer({ metavar: "ID" })),
407
+ project: projectFlag$2,
408
+ production: productionFlag$2,
409
+ json: jsonFlag$2
410
+ }))));
411
+ async function handler$6(args) {
412
+ const outputMode = args.json ? "json" : "auto";
413
+ const projectFlag = args.project;
414
+ const production = args.production;
415
+ try {
416
+ switch (args.command) {
417
+ case "blocks.types": return dispatch({
418
+ toolName: "listBlockTypes",
419
+ args: {},
420
+ projectFlag,
421
+ production,
422
+ outputMode
423
+ });
424
+ case "blocks.describe": return dispatch({
425
+ toolName: "describeBlockTypes",
426
+ args: { types: [...args.type] },
427
+ projectFlag,
428
+ production,
429
+ outputMode
430
+ });
431
+ case "blocks.create": {
432
+ const content = parseJsonFlag("--content", args.content);
433
+ const settings = args.settings !== void 0 ? parseJsonFlag("--settings", args.settings) : void 0;
434
+ return dispatch({
435
+ toolName: "createBlock",
436
+ args: {
437
+ pageId: args.pageId,
438
+ type: args.type,
439
+ content,
440
+ settings,
441
+ afterPosition: args.afterPosition
442
+ },
443
+ projectFlag,
444
+ production,
445
+ outputMode
446
+ });
447
+ }
448
+ case "blocks.edit": {
449
+ const content = args.content !== void 0 ? parseJsonFlag("--content", args.content) : void 0;
450
+ const settings = args.settings !== void 0 ? parseJsonFlag("--settings", args.settings) : void 0;
451
+ return dispatch({
452
+ toolName: "editBlock",
453
+ args: {
454
+ id: args.id,
455
+ content,
456
+ settings
457
+ },
458
+ projectFlag,
459
+ production,
460
+ outputMode
461
+ });
462
+ }
463
+ case "blocks.move": return dispatch({
464
+ toolName: "moveBlock",
465
+ args: {
466
+ id: args.id,
467
+ afterPosition: args.afterPosition
468
+ },
469
+ projectFlag,
470
+ production,
471
+ outputMode
472
+ });
473
+ case "blocks.delete": return dispatch({
474
+ toolName: "deleteBlock",
475
+ args: { id: args.id },
476
+ projectFlag,
477
+ production,
478
+ outputMode
479
+ });
480
+ }
481
+ } catch (err) {
482
+ printError(asCliError(err));
483
+ process.exit(1);
484
+ }
485
+ }
486
+ //#endregion
188
487
  //#region src/lib/utils.ts
189
488
  const pmCommands = {
190
489
  pnpm: {
@@ -220,13 +519,8 @@ function copyDir(src, dest, replacements) {
220
519
  }
221
520
  //#endregion
222
521
  //#region src/commands/init.ts
223
- var init_exports = /* @__PURE__ */ __exportAll({
224
- handler: () => handler$2,
225
- init: () => init,
226
- parser: () => parser$2
227
- });
228
- const parser$2 = command("init", object({ command: constant("init") }));
229
- const handler$2 = init;
522
+ const parser$5 = command("init", object({ command: constant("init") }));
523
+ const handler$5 = init;
230
524
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
231
525
  const ownPkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "package.json"), "utf-8"));
232
526
  function onCancel() {
@@ -434,14 +728,34 @@ src/routeTree.gen.ts
434
728
  });
435
729
  }
436
730
  //#endregion
731
+ //#region src/commands/layouts.ts
732
+ const projectFlag$1 = optional(option("--project", string({ metavar: "SLUG" })));
733
+ const jsonFlag$1 = option("--json");
734
+ const productionFlag$1 = option("--production");
735
+ const parser$4 = command("layouts", or(command("list", object({
736
+ command: constant("layouts.list"),
737
+ project: projectFlag$1,
738
+ production: productionFlag$1,
739
+ json: jsonFlag$1
740
+ }))));
741
+ async function handler$4(args) {
742
+ const outputMode = args.json ? "json" : "auto";
743
+ const projectFlag = args.project;
744
+ const production = args.production;
745
+ switch (args.command) {
746
+ case "layouts.list": return dispatch({
747
+ toolName: "listLayouts",
748
+ args: {},
749
+ projectFlag,
750
+ production,
751
+ outputMode
752
+ });
753
+ }
754
+ }
755
+ //#endregion
437
756
  //#region src/commands/login.ts
438
- var login_exports = /* @__PURE__ */ __exportAll({
439
- handler: () => handler$1,
440
- login: () => login,
441
- parser: () => parser$1
442
- });
443
- const parser$1 = command("login", object({ command: constant("login") }));
444
- const handler$1 = login;
757
+ const parser$3 = command("login", object({ command: constant("login") }));
758
+ const handler$3 = login;
445
759
  async function login() {
446
760
  p.intro("camox login");
447
761
  try {
@@ -455,13 +769,8 @@ async function login() {
455
769
  }
456
770
  //#endregion
457
771
  //#region src/commands/logout.ts
458
- var logout_exports = /* @__PURE__ */ __exportAll({
459
- handler: () => handler,
460
- logout: () => logout,
461
- parser: () => parser
462
- });
463
- const parser = command("logout", object({ command: constant("logout") }));
464
- const handler = logout;
772
+ const parser$2 = command("logout", object({ command: constant("logout") }));
773
+ const handler$2 = logout;
465
774
  function logout() {
466
775
  p.intro("camox logout");
467
776
  const token = readAuthToken();
@@ -473,17 +782,211 @@ function logout() {
473
782
  p.log.success(`Logged out from ${token.name}.`);
474
783
  }
475
784
  //#endregion
785
+ //#region src/commands/pages.ts
786
+ const projectFlag = optional(option("--project", string({ metavar: "SLUG" })));
787
+ const jsonFlag = option("--json");
788
+ const productionFlag = option("--production");
789
+ const parser$1 = command("pages", or(command("list", object({
790
+ command: constant("pages.list"),
791
+ project: projectFlag,
792
+ production: productionFlag,
793
+ json: jsonFlag
794
+ })), command("get", object({
795
+ command: constant("pages.get"),
796
+ id: optional(option("--id", integer({ metavar: "ID" }))),
797
+ path: optional(option("--path", string({ metavar: "PATH" }))),
798
+ project: projectFlag,
799
+ production: productionFlag,
800
+ json: jsonFlag
801
+ })), command("create", object({
802
+ command: constant("pages.create"),
803
+ pathSegment: option("--path-segment", string({ metavar: "SEGMENT" })),
804
+ layoutId: option("--layout-id", integer({ metavar: "ID" })),
805
+ parentPageId: optional(option("--parent-page-id", integer({ metavar: "ID" }))),
806
+ contentDescription: optional(option("--content-description", string({ metavar: "TEXT" }))),
807
+ project: projectFlag,
808
+ production: productionFlag,
809
+ json: jsonFlag
810
+ })), command("update", object({
811
+ command: constant("pages.update"),
812
+ id: option("--id", integer({ metavar: "ID" })),
813
+ pathSegment: optional(option("--path-segment", string({ metavar: "SEGMENT" }))),
814
+ parentPageId: optional(option("--parent-page-id", integer({ metavar: "ID" }))),
815
+ project: projectFlag,
816
+ production: productionFlag,
817
+ json: jsonFlag
818
+ })), command("set-layout", object({
819
+ command: constant("pages.set-layout"),
820
+ id: option("--id", integer({ metavar: "ID" })),
821
+ layoutId: option("--layout-id", integer({ metavar: "ID" })),
822
+ project: projectFlag,
823
+ production: productionFlag,
824
+ json: jsonFlag
825
+ })), command("delete", object({
826
+ command: constant("pages.delete"),
827
+ id: option("--id", integer({ metavar: "ID" })),
828
+ project: projectFlag,
829
+ production: productionFlag,
830
+ json: jsonFlag
831
+ }))));
832
+ async function handler$1(args) {
833
+ const outputMode = args.json ? "json" : "auto";
834
+ const projectFlag = args.project;
835
+ const production = args.production;
836
+ switch (args.command) {
837
+ case "pages.list": return dispatch({
838
+ toolName: "listPages",
839
+ args: {},
840
+ projectFlag,
841
+ production,
842
+ outputMode
843
+ });
844
+ case "pages.get":
845
+ if (args.id == null === (args.path == null)) {
846
+ printError({
847
+ code: "INVALID_ARGS",
848
+ message: "Pass exactly one of --id or --path."
849
+ });
850
+ process.exit(2);
851
+ }
852
+ return dispatch({
853
+ toolName: "getPage",
854
+ args: args.id != null ? { id: args.id } : { path: args.path },
855
+ projectFlag,
856
+ production,
857
+ outputMode
858
+ });
859
+ case "pages.create": return dispatch({
860
+ toolName: "createPage",
861
+ args: {
862
+ pathSegment: args.pathSegment,
863
+ layoutId: args.layoutId,
864
+ parentPageId: args.parentPageId,
865
+ contentDescription: args.contentDescription
866
+ },
867
+ projectFlag,
868
+ production,
869
+ outputMode
870
+ });
871
+ case "pages.update": return dispatch({
872
+ toolName: "updatePage",
873
+ args: {
874
+ id: args.id,
875
+ pathSegment: args.pathSegment,
876
+ parentPageId: args.parentPageId
877
+ },
878
+ projectFlag,
879
+ production,
880
+ outputMode
881
+ });
882
+ case "pages.set-layout": return dispatch({
883
+ toolName: "setPageLayout",
884
+ args: {
885
+ id: args.id,
886
+ layoutId: args.layoutId
887
+ },
888
+ projectFlag,
889
+ production,
890
+ outputMode
891
+ });
892
+ case "pages.delete": return dispatch({
893
+ toolName: "deletePage",
894
+ args: { id: args.id },
895
+ projectFlag,
896
+ production,
897
+ outputMode
898
+ });
899
+ }
900
+ }
901
+ //#endregion
902
+ //#region src/commands/status.ts
903
+ const parser = command("status", object({
904
+ command: constant("status"),
905
+ production: option("--production"),
906
+ json: option("--json")
907
+ }));
908
+ async function handler(args) {
909
+ let runtime;
910
+ try {
911
+ runtime = loadRuntime();
912
+ } catch (err) {
913
+ if (err instanceof RuntimeNotFoundError || err instanceof RuntimeMalformedError) {
914
+ printError({
915
+ code: "RUNTIME_NOT_FOUND",
916
+ message: err.message
917
+ });
918
+ process.exit(2);
919
+ }
920
+ throw err;
921
+ }
922
+ const environmentName = args.production ? "production" : runtime.environmentName;
923
+ const token = readAuthTokenForUrl(runtime.authenticationUrl);
924
+ const status = {
925
+ projectSlug: runtime.projectSlug,
926
+ environmentName,
927
+ apiUrl: runtime.apiUrl,
928
+ authenticationUrl: runtime.authenticationUrl,
929
+ authenticated: token !== null,
930
+ user: token ? {
931
+ name: token.name,
932
+ email: token.email
933
+ } : null
934
+ };
935
+ if (args.json || !process.stdout.isTTY) {
936
+ process.stdout.write(`${JSON.stringify(status, null, process.stdout.isTTY ? 2 : 0)}\n`);
937
+ process.exit(0);
938
+ }
939
+ const lines = [
940
+ `project: ${status.projectSlug}`,
941
+ `environment: ${status.environmentName}`,
942
+ `api: ${status.apiUrl}`,
943
+ `auth: ${status.authenticationUrl}`,
944
+ status.user ? `signed in: ${status.user.name} <${status.user.email}>` : `signed in: (no token for ${status.authenticationUrl} — run \`camox login\`)`
945
+ ];
946
+ process.stdout.write(`${lines.join("\n")}\n`);
947
+ process.exit(0);
948
+ }
949
+ //#endregion
476
950
  //#region src/index.ts
477
- await {
478
- init: init_exports,
479
- login: login_exports,
480
- logout: logout_exports
481
- }[run(defineProgram({
482
- parser: or(parser$2, parser$1, parser),
951
+ const result = runSync(defineProgram({
952
+ parser: or(parser$5, parser$3, parser$2, parser, parser$1, parser$6, parser$4),
483
953
  metadata: {
484
954
  name: "camox",
485
955
  brief: message`Camox CLI`
486
956
  }
487
- }), { help: "both" }).command].handler();
957
+ }), { help: "both" });
958
+ switch (result.command) {
959
+ case "init":
960
+ await handler$5();
961
+ break;
962
+ case "login":
963
+ await handler$3();
964
+ break;
965
+ case "logout":
966
+ await handler$2();
967
+ break;
968
+ case "status":
969
+ await handler(result);
970
+ break;
971
+ case "pages.list":
972
+ case "pages.get":
973
+ case "pages.create":
974
+ case "pages.update":
975
+ case "pages.set-layout":
976
+ case "pages.delete":
977
+ await handler$1(result);
978
+ break;
979
+ case "blocks.types":
980
+ case "blocks.describe":
981
+ case "blocks.create":
982
+ case "blocks.edit":
983
+ case "blocks.move":
984
+ case "blocks.delete":
985
+ await handler$6(result);
986
+ break;
987
+ case "layouts.list":
988
+ await handler$4(result);
989
+ break;
990
+ }
488
991
  //#endregion
489
992
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camox/cli",
3
- "version": "0.14.2",
3
+ "version": "0.15.1",
4
4
  "bin": {
5
5
  "camox": "./dist/index.mjs"
6
6
  },
@@ -19,14 +19,15 @@
19
19
  "@optique/run": "*",
20
20
  "@orpc/client": "^1.13.14",
21
21
  "@orpc/server": "^1.13.14",
22
- "slugify": "^1.6.9"
22
+ "slugify": "^1.6.9",
23
+ "zod": "^4.3.6"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/node": "^24.12.2",
26
27
  "@typescript/native-preview": "7.0.0-dev.20260412.1",
27
28
  "oxlint": "^0.15.0",
28
29
  "tsdown": "^0.21.8",
29
- "@camox/api-contract": "0.14.2"
30
+ "@camox/api-contract": "0.15.1"
30
31
  },
31
32
  "nx": {
32
33
  "tags": [
@@ -9,8 +9,7 @@
9
9
  "build": "vp build",
10
10
  "serve": "vp preview",
11
11
  "lint": "vp lint",
12
- "check": "vp check",
13
- "prepare": "vp config"
12
+ "check": "vp check"
14
13
  },
15
14
  "dependencies": {
16
15
  "@base-ui/react": "^1.4.0",
@@ -9,9 +9,6 @@ import { defineConfig, loadEnv } from "vite-plus";
9
9
  const env = loadEnv(process.env.NODE_ENV!, process.cwd(), "CAMOX_");
10
10
 
11
11
  export default defineConfig({
12
- staged: {
13
- "*": "vp check --fix"
14
- },
15
12
  resolve: { tsconfigPaths: true },
16
13
  plugins: [
17
14
  tailwindcss(),
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import { o as verifySession } from "./api-QINint5w.mjs";
3
- export { verifySession };
@@ -1 +0,0 @@
1
- vp staged