@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.
- package/dist/{api-QINint5w.mjs → api-Bgstxixw.mjs} +16 -4
- package/dist/api-DoFRj7vC.mjs +3 -0
- package/dist/index.mjs +551 -48
- package/package.json +4 -3
- package/template/package.json +1 -2
- package/template/vite.config.ts +0 -3
- package/dist/api-CB7vjDU7.mjs +0 -3
- package/template/.vite-hooks/pre-commit +0 -1
|
@@ -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: `${
|
|
15
|
-
headers
|
|
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 {
|
|
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
224
|
-
|
|
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
|
-
|
|
439
|
-
|
|
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
|
-
|
|
459
|
-
|
|
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
|
-
|
|
478
|
-
|
|
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" })
|
|
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.
|
|
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.
|
|
30
|
+
"@camox/api-contract": "0.15.1"
|
|
30
31
|
},
|
|
31
32
|
"nx": {
|
|
32
33
|
"tags": [
|
package/template/package.json
CHANGED
package/template/vite.config.ts
CHANGED
|
@@ -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(),
|
package/dist/api-CB7vjDU7.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
vp staged
|