fimo 0.2.5 → 0.3.0-experimental.1782982991158
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.
|
@@ -3,9 +3,10 @@ name: fimo-cli
|
|
|
3
3
|
description: >-
|
|
4
4
|
The `fimo` CLI scaffolds and manages Fimo projects from the command line.
|
|
5
5
|
Load when the user wants to create a new Fimo project, build content
|
|
6
|
-
(schemas, entries, forms, media, labels/locales), deploy a site,
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
(schemas, entries, forms, media, labels/locales), deploy a site, manage
|
|
7
|
+
custom domains, check site traffic/analytics, invite collaborators, inspect
|
|
8
|
+
AI credits, log in or switch organizations, or set up Fimo for their AI
|
|
9
|
+
tool. Most "do X with Fimo" tasks go through this skill.
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Fimo CLI
|
package/dist/cli/bundle.json
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -19612,6 +19612,15 @@ function throwUnauthorized(cfg, status) {
|
|
|
19612
19612
|
}
|
|
19613
19613
|
throw new UnauthorizedError(cfg.apiUrl, status);
|
|
19614
19614
|
}
|
|
19615
|
+
async function throwPermissionDenied(cfg, response) {
|
|
19616
|
+
let required2 = [];
|
|
19617
|
+
try {
|
|
19618
|
+
const body = await response.json();
|
|
19619
|
+
required2 = Array.isArray(body.required) ? body.required : body.required ? [body.required] : [];
|
|
19620
|
+
} catch {
|
|
19621
|
+
}
|
|
19622
|
+
throw new PermissionDeniedError(cfg.apiUrl, required2);
|
|
19623
|
+
}
|
|
19615
19624
|
async function fimoFetch(url2, init) {
|
|
19616
19625
|
const headers = new Headers(init.headers);
|
|
19617
19626
|
if (!headers.has(CLI_VERSION_HEADER)) {
|
|
@@ -19626,7 +19635,7 @@ async function fimoFetch(url2, init) {
|
|
|
19626
19635
|
}
|
|
19627
19636
|
return response;
|
|
19628
19637
|
}
|
|
19629
|
-
var ApiRequestError, UnauthorizedError, CLI_VERSION_HEADER, CLI_LATEST_HEADER, FIMO_ENV_HEADER, FimoApiClient;
|
|
19638
|
+
var ApiRequestError, UnauthorizedError, PermissionDeniedError, CLI_VERSION_HEADER, CLI_LATEST_HEADER, FIMO_ENV_HEADER, FimoApiClient;
|
|
19630
19639
|
var init_api = __esm({
|
|
19631
19640
|
"src/cli/api.ts"() {
|
|
19632
19641
|
init_auth();
|
|
@@ -19667,7 +19676,27 @@ var init_api = __esm({
|
|
|
19667
19676
|
this.status = status;
|
|
19668
19677
|
}
|
|
19669
19678
|
};
|
|
19679
|
+
PermissionDeniedError = class extends Error {
|
|
19680
|
+
static {
|
|
19681
|
+
__name(this, "PermissionDeniedError");
|
|
19682
|
+
}
|
|
19683
|
+
// 403: the session is VALID but the principal's role lacks a permission.
|
|
19684
|
+
// Distinct from UnauthorizedError (401, stale/invalid token) so the CLI
|
|
19685
|
+
// never tells a correctly-authenticated caller to `fimo login` — that
|
|
19686
|
+
// false diagnosis gets repeated verbatim by agent callers.
|
|
19687
|
+
apiUrl;
|
|
19688
|
+
/** Permission(s) the server reported missing — the 403 body's `required`. */
|
|
19689
|
+
required;
|
|
19690
|
+
constructor(apiUrl, required2 = [], message) {
|
|
19691
|
+
const detail = required2.length ? ` Missing permission: ${required2.join(", ")}.` : "";
|
|
19692
|
+
super(message ?? `You don't have permission to do this on ${apiUrl}.${detail}`);
|
|
19693
|
+
this.name = "PermissionDeniedError";
|
|
19694
|
+
this.apiUrl = apiUrl;
|
|
19695
|
+
this.required = required2;
|
|
19696
|
+
}
|
|
19697
|
+
};
|
|
19670
19698
|
__name(throwUnauthorized, "throwUnauthorized");
|
|
19699
|
+
__name(throwPermissionDenied, "throwPermissionDenied");
|
|
19671
19700
|
CLI_VERSION_HEADER = "X-Fimo-CLI-Version";
|
|
19672
19701
|
CLI_LATEST_HEADER = "X-Fimo-CLI-Latest";
|
|
19673
19702
|
FIMO_ENV_HEADER = "X-Fimo-Env";
|
|
@@ -19732,9 +19761,12 @@ var init_api = __esm({
|
|
|
19732
19761
|
headers.set(FIMO_ENV_HEADER, this.env);
|
|
19733
19762
|
}
|
|
19734
19763
|
const response = await fimoFetch(`${this.cfg.apiUrl}${path46}`, { ...init, headers });
|
|
19735
|
-
if (response.status === 401
|
|
19764
|
+
if (response.status === 401) {
|
|
19736
19765
|
throwUnauthorized(this.cfg, response.status);
|
|
19737
19766
|
}
|
|
19767
|
+
if (response.status === 403 && !opts.allow403) {
|
|
19768
|
+
await throwPermissionDenied(this.cfg, response);
|
|
19769
|
+
}
|
|
19738
19770
|
if (!response.ok) {
|
|
19739
19771
|
const error45 = await this.formatError(response);
|
|
19740
19772
|
throw new ApiRequestError(init.method ?? "GET", path46, response.status, error45);
|
|
@@ -19752,9 +19784,12 @@ var init_api = __esm({
|
|
|
19752
19784
|
headers.set(FIMO_ENV_HEADER, this.env);
|
|
19753
19785
|
}
|
|
19754
19786
|
const response = await fimoFetch(`${this.cfg.apiUrl}${path46}`, { ...init, headers });
|
|
19755
|
-
if (response.status === 401
|
|
19787
|
+
if (response.status === 401) {
|
|
19756
19788
|
throwUnauthorized(this.cfg, response.status);
|
|
19757
19789
|
}
|
|
19790
|
+
if (response.status === 403) {
|
|
19791
|
+
await throwPermissionDenied(this.cfg, response);
|
|
19792
|
+
}
|
|
19758
19793
|
if (!response.ok) {
|
|
19759
19794
|
const error45 = await this.formatError(response);
|
|
19760
19795
|
throw new Error(`API ${init.method ?? "GET"} ${path46} failed: ${response.status} ${error45}`);
|
|
@@ -41596,7 +41631,7 @@ var init_color = __esm({
|
|
|
41596
41631
|
|
|
41597
41632
|
// src/cli/utils/auth-errors.ts
|
|
41598
41633
|
function isCliAuthError(err) {
|
|
41599
|
-
return err instanceof NotAuthenticatedError || err instanceof UnauthorizedError;
|
|
41634
|
+
return err instanceof NotAuthenticatedError || err instanceof UnauthorizedError || err instanceof PermissionDeniedError;
|
|
41600
41635
|
}
|
|
41601
41636
|
function rethrowCliAuthError(err, beforeThrow) {
|
|
41602
41637
|
if (isCliAuthError(err)) {
|
|
@@ -41610,6 +41645,16 @@ function retryCommand(args = process.argv.slice(2)) {
|
|
|
41610
41645
|
function formatCliAuthError(err, opts = {}) {
|
|
41611
41646
|
const p2 = opts.palette ?? palette;
|
|
41612
41647
|
const command = retryCommand(opts.args);
|
|
41648
|
+
if (err instanceof PermissionDeniedError) {
|
|
41649
|
+
return [
|
|
41650
|
+
`${p2.red("\u2717")} You don't have permission to run this command.`,
|
|
41651
|
+
"",
|
|
41652
|
+
err.required.length ? ` Missing permission: ${p2.bold(err.required.join(", "))}` : " Your role on this project does not allow this action.",
|
|
41653
|
+
" Ask a project admin for access, or use an account with a higher role.",
|
|
41654
|
+
"",
|
|
41655
|
+
p2.dim(` Backend: ${err.apiUrl}`)
|
|
41656
|
+
].join("\n");
|
|
41657
|
+
}
|
|
41613
41658
|
const expired = err instanceof UnauthorizedError;
|
|
41614
41659
|
const intro = expired ? "Your Fimo session is expired or invalid." : "You're not signed in to Fimo.";
|
|
41615
41660
|
const loginVerb = expired ? "refresh your session" : "sign in";
|
|
@@ -42736,7 +42781,9 @@ var init_integration_dto = __esm({
|
|
|
42736
42781
|
BindProjectChannelRequestSchema = external_exports.object({
|
|
42737
42782
|
ref: external_exports.string().min(1),
|
|
42738
42783
|
connectionAlias: external_exports.string().min(1).optional(),
|
|
42739
|
-
agentName: external_exports.string().min(1).max(160).nullable().optional()
|
|
42784
|
+
agentName: external_exports.string().min(1).max(160).nullable().optional(),
|
|
42785
|
+
/** Take over a channel already bound to another project in the same org (org owner/admin only). */
|
|
42786
|
+
force: external_exports.boolean().optional()
|
|
42740
42787
|
});
|
|
42741
42788
|
ProjectChannelBindingDTOSchema = external_exports.object({
|
|
42742
42789
|
id: external_exports.uuid(),
|
|
@@ -45322,6 +45369,16 @@ var init_git = __esm({
|
|
|
45322
45369
|
});
|
|
45323
45370
|
|
|
45324
45371
|
// src/cli/utils/project-context.ts
|
|
45372
|
+
function projectSettingsFromEnv() {
|
|
45373
|
+
const projectId = process.env.FIMO_PROJECT_ID?.trim();
|
|
45374
|
+
if (!projectId) return null;
|
|
45375
|
+
return {
|
|
45376
|
+
projectId,
|
|
45377
|
+
organizationId: process.env.FIMO_ORGANIZATION_ID?.trim() ?? "",
|
|
45378
|
+
name: process.env.FIMO_PROJECT_NAME?.trim() ?? projectId,
|
|
45379
|
+
apiUrl: process.env.FIMO_API_URL?.trim() ?? loadConfig().apiUrl
|
|
45380
|
+
};
|
|
45381
|
+
}
|
|
45325
45382
|
async function resolveEnvFromGit(cwd) {
|
|
45326
45383
|
if (!await isGitRepo(cwd)) return null;
|
|
45327
45384
|
try {
|
|
@@ -45343,7 +45400,11 @@ async function getProjectContext(opts = {}) {
|
|
|
45343
45400
|
try {
|
|
45344
45401
|
settings = loadProjectSettings(cwd);
|
|
45345
45402
|
} catch {
|
|
45346
|
-
|
|
45403
|
+
const fromEnv = projectSettingsFromEnv();
|
|
45404
|
+
if (!fromEnv) {
|
|
45405
|
+
throw new NotInProjectError();
|
|
45406
|
+
}
|
|
45407
|
+
settings = fromEnv;
|
|
45347
45408
|
}
|
|
45348
45409
|
let env2;
|
|
45349
45410
|
let source;
|
|
@@ -45447,6 +45508,7 @@ var init_project_context = __esm({
|
|
|
45447
45508
|
this.name = "NotInProjectError";
|
|
45448
45509
|
}
|
|
45449
45510
|
};
|
|
45511
|
+
__name(projectSettingsFromEnv, "projectSettingsFromEnv");
|
|
45450
45512
|
InvalidEnvOverrideError = class extends Error {
|
|
45451
45513
|
static {
|
|
45452
45514
|
__name(this, "InvalidEnvOverrideError");
|
|
@@ -100149,7 +100211,7 @@ Examples:
|
|
|
100149
100211
|
Run \`fimo channels <command> --help\` for command-specific help.
|
|
100150
100212
|
`
|
|
100151
100213
|
);
|
|
100152
|
-
channels.command("bind <ref>").description("Bind a provider channel to this project").option("--project <id>", "Project id (defaults to .fimo.settings.json projectId)").option("-C, --cwd <dir>", "Project directory").option("--connection <alias>", "Connection alias when a project has more than one provider connection").option("--agent <name>", "Agent name reserved for this channel binding").action((ref, opts) => bindCommand(ref, opts));
|
|
100214
|
+
channels.command("bind <ref>").description("Bind a provider channel to this project").option("--project <id>", "Project id (defaults to .fimo.settings.json projectId)").option("-C, --cwd <dir>", "Project directory").option("--connection <alias>", "Connection alias when a project has more than one provider connection").option("--agent <name>", "Agent name reserved for this channel binding").option("--force", "Take over a channel already bound to another project in your org (org owner/admin only)").action((ref, opts) => bindCommand(ref, opts));
|
|
100153
100215
|
}
|
|
100154
100216
|
__name(registerChannelsCommands, "registerChannelsCommands");
|
|
100155
100217
|
async function bindCommand(ref, opts) {
|
|
@@ -100158,7 +100220,8 @@ async function bindCommand(ref, opts) {
|
|
|
100158
100220
|
const binding = await api.bindProjectChannel(projectId, {
|
|
100159
100221
|
ref,
|
|
100160
100222
|
connectionAlias: opts.connection,
|
|
100161
|
-
agentName: opts.agent
|
|
100223
|
+
agentName: opts.agent,
|
|
100224
|
+
force: opts.force
|
|
100162
100225
|
});
|
|
100163
100226
|
ui.ok({
|
|
100164
100227
|
command: "channels bind",
|
|
@@ -109194,13 +109257,22 @@ program.parseAsync(process.argv).catch((err) => {
|
|
|
109194
109257
|
const command = process.argv[2] ?? "fimo";
|
|
109195
109258
|
if (isCliAuthError(err)) {
|
|
109196
109259
|
if (currentMode().format === "json") {
|
|
109197
|
-
|
|
109198
|
-
|
|
109199
|
-
|
|
109200
|
-
|
|
109201
|
-
|
|
109202
|
-
|
|
109203
|
-
|
|
109260
|
+
if (err instanceof PermissionDeniedError) {
|
|
109261
|
+
ui.error({
|
|
109262
|
+
command,
|
|
109263
|
+
code: "PERMISSION_DENIED",
|
|
109264
|
+
message: err.message,
|
|
109265
|
+
hint: err.required.length ? `Your role lacks \`${err.required.join(", ")}\` on this project \u2014 ask a project admin for access.` : "Your role does not allow this action on this project \u2014 ask a project admin for access."
|
|
109266
|
+
});
|
|
109267
|
+
} else {
|
|
109268
|
+
const isExpired = err instanceof UnauthorizedError;
|
|
109269
|
+
ui.error({
|
|
109270
|
+
command,
|
|
109271
|
+
code: isExpired ? "SESSION_EXPIRED" : "NOT_AUTHENTICATED",
|
|
109272
|
+
message: err.message,
|
|
109273
|
+
hint: isExpired ? "Run `fimo login` to refresh." : "Run `fimo login` to sign in."
|
|
109274
|
+
});
|
|
109275
|
+
}
|
|
109204
109276
|
} else {
|
|
109205
109277
|
renderCliAuthError(err);
|
|
109206
109278
|
}
|
package/package.json
CHANGED
package/release.json
CHANGED