@insforge/cli 0.1.73 → 0.1.76
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/index.js +490 -67
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as
|
|
4
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
5
5
|
import { join as join17, dirname as dirname3 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -41,8 +41,8 @@ var LineReader = class {
|
|
|
41
41
|
this.output.write(prompt);
|
|
42
42
|
if (this.queue.length > 0) return this.queue.shift();
|
|
43
43
|
if (this.closed) return null;
|
|
44
|
-
return new Promise((
|
|
45
|
-
this.waiter =
|
|
44
|
+
return new Promise((resolve8) => {
|
|
45
|
+
this.waiter = resolve8;
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
close() {
|
|
@@ -424,8 +424,8 @@ function startCallbackServer() {
|
|
|
424
424
|
return new Promise((resolveServer) => {
|
|
425
425
|
let resolveResult;
|
|
426
426
|
let rejectResult;
|
|
427
|
-
const resultPromise = new Promise((
|
|
428
|
-
resolveResult =
|
|
427
|
+
const resultPromise = new Promise((resolve8, reject) => {
|
|
428
|
+
resolveResult = resolve8;
|
|
429
429
|
rejectResult = reject;
|
|
430
430
|
});
|
|
431
431
|
const server = createServer((req, res) => {
|
|
@@ -1158,7 +1158,7 @@ function registerProjectsCommands(projectsCmd2) {
|
|
|
1158
1158
|
}
|
|
1159
1159
|
outputTable(
|
|
1160
1160
|
["ID", "Name", "Region", "Status", "AppKey"],
|
|
1161
|
-
projects.map((
|
|
1161
|
+
projects.map((p3) => [p3.id, p3.name, p3.region, p3.status, p3.appkey])
|
|
1162
1162
|
);
|
|
1163
1163
|
}
|
|
1164
1164
|
} catch (err) {
|
|
@@ -1751,10 +1751,14 @@ ${missing.join("\n")}
|
|
|
1751
1751
|
`;
|
|
1752
1752
|
appendFileSync(gitignorePath, block);
|
|
1753
1753
|
}
|
|
1754
|
-
|
|
1754
|
+
var AGENT_FLAGS = "-a antigravity -a augment -a claude-code -a cline -a codex -a cursor -a gemini-cli -a github-copilot -a kilo -a qoder -a qwen-code -a roo -a trae -a windsurf";
|
|
1755
|
+
var PROVIDER_SKILLS = {
|
|
1756
|
+
"better-auth": { repo: "better-auth/skills", label: "Better Auth skills" }
|
|
1757
|
+
};
|
|
1758
|
+
async function installSkills(json, authProvider) {
|
|
1755
1759
|
try {
|
|
1756
1760
|
if (!json) clack9.log.info("Installing InsForge agent skills (global)...");
|
|
1757
|
-
await execAsync(
|
|
1761
|
+
await execAsync(`npx skills add insforge/agent-skills -g -y ${AGENT_FLAGS}`, {
|
|
1758
1762
|
cwd: process.cwd(),
|
|
1759
1763
|
timeout: SKILL_INSTALL_TIMEOUT_MS
|
|
1760
1764
|
});
|
|
@@ -1778,6 +1782,22 @@ async function installSkills(json) {
|
|
|
1778
1782
|
clack9.log.info("Run `npx skills add https://github.com/vercel-labs/skills --skill find-skills` once resolved.");
|
|
1779
1783
|
}
|
|
1780
1784
|
}
|
|
1785
|
+
const providerEntry = authProvider ? PROVIDER_SKILLS[authProvider] : void 0;
|
|
1786
|
+
if (providerEntry) {
|
|
1787
|
+
try {
|
|
1788
|
+
if (!json) clack9.log.info(`Installing ${providerEntry.label} (global)...`);
|
|
1789
|
+
await execAsync(`npx skills add ${providerEntry.repo} -g -y ${AGENT_FLAGS}`, {
|
|
1790
|
+
cwd: process.cwd(),
|
|
1791
|
+
timeout: SKILL_INSTALL_TIMEOUT_MS
|
|
1792
|
+
});
|
|
1793
|
+
if (!json) clack9.log.success(`${providerEntry.label} installed.`);
|
|
1794
|
+
} catch (err) {
|
|
1795
|
+
if (!json) {
|
|
1796
|
+
clack9.log.warn(`Could not install ${providerEntry.label}: ${describeExecError(err)}`);
|
|
1797
|
+
clack9.log.info(`Run \`npx skills add ${providerEntry.repo}\` once resolved to see the full output.`);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1781
1801
|
try {
|
|
1782
1802
|
updateGitignore();
|
|
1783
1803
|
} catch {
|
|
@@ -1868,18 +1888,34 @@ async function getJwtSecret() {
|
|
|
1868
1888
|
function spliceDatabasePassword(maskedUrl, password3) {
|
|
1869
1889
|
return maskedUrl.replace(/^(postgresql:\/\/[^:]+:)[^@]+(@)/, `$1${password3}$2`);
|
|
1870
1890
|
}
|
|
1891
|
+
function isMaskedDatabasePassword(value) {
|
|
1892
|
+
return /^\*+$/.test(value);
|
|
1893
|
+
}
|
|
1894
|
+
async function fetchDatabasePasswordOnce() {
|
|
1895
|
+
try {
|
|
1896
|
+
const res = await ossFetch("/api/metadata/database-password");
|
|
1897
|
+
const body = await res.json();
|
|
1898
|
+
const pw = body.databasePassword;
|
|
1899
|
+
if (typeof pw !== "string" || !pw || isMaskedDatabasePassword(pw)) return null;
|
|
1900
|
+
return pw;
|
|
1901
|
+
} catch {
|
|
1902
|
+
return null;
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1871
1905
|
async function getDatabaseConnectionString() {
|
|
1872
1906
|
try {
|
|
1873
|
-
const
|
|
1874
|
-
ossFetch("/api/metadata/database-connection-string"),
|
|
1875
|
-
ossFetch("/api/metadata/database-password")
|
|
1876
|
-
]);
|
|
1907
|
+
const urlRes = await ossFetch("/api/metadata/database-connection-string");
|
|
1877
1908
|
const urlBody = await urlRes.json();
|
|
1878
|
-
const pwBody = await pwRes.json();
|
|
1879
1909
|
const masked = urlBody.connectionURL;
|
|
1880
|
-
const password3 = pwBody.databasePassword;
|
|
1881
1910
|
if (typeof masked !== "string" || !masked) return null;
|
|
1882
|
-
|
|
1911
|
+
let password3 = await fetchDatabasePasswordOnce();
|
|
1912
|
+
const POLL_ATTEMPTS = 9;
|
|
1913
|
+
const POLL_DELAY_MS = 2e3;
|
|
1914
|
+
for (let attempt = 0; password3 === null && attempt < POLL_ATTEMPTS; attempt++) {
|
|
1915
|
+
await new Promise((r) => setTimeout(r, POLL_DELAY_MS));
|
|
1916
|
+
password3 = await fetchDatabasePasswordOnce();
|
|
1917
|
+
}
|
|
1918
|
+
if (password3 === null) return null;
|
|
1883
1919
|
return spliceDatabasePassword(masked, password3);
|
|
1884
1920
|
} catch {
|
|
1885
1921
|
return null;
|
|
@@ -1918,8 +1954,8 @@ ${err.nextActions}`;
|
|
|
1918
1954
|
// src/auth-providers/apply.ts
|
|
1919
1955
|
var execFileAsync = promisify2(execFile);
|
|
1920
1956
|
var VALID_AUTH_PROVIDERS = ["better-auth"];
|
|
1921
|
-
function pathExists(
|
|
1922
|
-
return fs.stat(
|
|
1957
|
+
function pathExists(p3) {
|
|
1958
|
+
return fs.stat(p3).then(() => true, () => false);
|
|
1923
1959
|
}
|
|
1924
1960
|
function deepMergeKeepBase(base, patch) {
|
|
1925
1961
|
const out = { ...base };
|
|
@@ -2310,11 +2346,11 @@ async function collectDeploymentFiles(sourceDir) {
|
|
|
2310
2346
|
return files;
|
|
2311
2347
|
}
|
|
2312
2348
|
async function createZipBuffer(sourceDir) {
|
|
2313
|
-
return new Promise((
|
|
2349
|
+
return new Promise((resolve8, reject) => {
|
|
2314
2350
|
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
2315
2351
|
const chunks = [];
|
|
2316
2352
|
archive.on("data", (chunk) => chunks.push(chunk));
|
|
2317
|
-
archive.on("end", () =>
|
|
2353
|
+
archive.on("end", () => resolve8(Buffer.concat(chunks)));
|
|
2318
2354
|
archive.on("error", (err) => reject(err));
|
|
2319
2355
|
archive.directory(sourceDir, false, (entry) => {
|
|
2320
2356
|
if (shouldExclude(entry.name)) return false;
|
|
@@ -2396,7 +2432,7 @@ async function pollDeployment(deploymentId, spinner10, syncBeforeRead) {
|
|
|
2396
2432
|
const startTime = Date.now();
|
|
2397
2433
|
let deployment = null;
|
|
2398
2434
|
while (Date.now() - startTime < POLL_TIMEOUT_MS3) {
|
|
2399
|
-
await new Promise((
|
|
2435
|
+
await new Promise((resolve8) => setTimeout(resolve8, POLL_INTERVAL_MS3));
|
|
2400
2436
|
try {
|
|
2401
2437
|
if (syncBeforeRead) {
|
|
2402
2438
|
await ossFetch(`/api/deployments/${deploymentId}/sync`, { method: "POST" });
|
|
@@ -2877,7 +2913,7 @@ function registerCreateCommand(program2) {
|
|
|
2877
2913
|
else clack12.log.warn(msg);
|
|
2878
2914
|
}
|
|
2879
2915
|
}
|
|
2880
|
-
await installSkills(json);
|
|
2916
|
+
await installSkills(json, opts.auth);
|
|
2881
2917
|
trackCommand("create", orgId);
|
|
2882
2918
|
await reportCliUsage("cli.create", true, 6);
|
|
2883
2919
|
const templateDownloaded = hasTemplate ? await fs4.stat(path4.join(process.cwd(), "package.json")).catch(() => null) : null;
|
|
@@ -2962,7 +2998,7 @@ function registerCreateCommand(program2) {
|
|
|
2962
2998
|
clack12.note(
|
|
2963
2999
|
`Open your coding agent (Claude Code, Codex, Cursor, etc.) and try:
|
|
2964
3000
|
|
|
2965
|
-
${prompts.map((
|
|
3001
|
+
${prompts.map((p3) => `\u2022 "${p3}"`).join("\n")}`,
|
|
2966
3002
|
"Start building"
|
|
2967
3003
|
);
|
|
2968
3004
|
}
|
|
@@ -3147,7 +3183,7 @@ async function runNpmSetupIfPresent() {
|
|
|
3147
3183
|
}
|
|
3148
3184
|
}
|
|
3149
3185
|
function registerProjectLinkCommand(program2) {
|
|
3150
|
-
program2.command("link").description("Link current directory to an InsForge project").option("--project-id <id>", "Project ID to link").option("--org-id <id>", "Organization ID").option("--template <template>", "Download a template after linking: react, nextjs, chatbot, crm, e-commerce, todo").option("--auth <provider>", "Wire a third-party auth provider into the chosen template (currently: better-auth)").option("--api-base-url <url>", "API Base URL for direct linking (OSS/Self-hosted)").option("--api-key <key>", "API Key for direct linking (OSS/Self-hosted)").action(async (opts, cmd) => {
|
|
3186
|
+
program2.command("link").description("Link current directory to an InsForge project (no args: installs agent skills only)").option("--project-id <id>", "Project ID to link").option("--org-id <id>", "Organization ID").option("--template <template>", "Download a template after linking: react, nextjs, chatbot, crm, e-commerce, todo").option("--auth <provider>", "Wire a third-party auth provider into the chosen template (currently: better-auth)").option("--api-base-url <url>", "API Base URL for direct linking (OSS/Self-hosted)").option("--api-key <key>", "API Key for direct linking (OSS/Self-hosted)").action(async (opts, cmd) => {
|
|
3151
3187
|
const { json, apiUrl } = getRootOpts(cmd);
|
|
3152
3188
|
const validTemplates = ["react", "nextjs", "chatbot", "crm", "e-commerce", "todo"];
|
|
3153
3189
|
if (opts.auth && !VALID_AUTH_PROVIDERS.includes(opts.auth)) {
|
|
@@ -3157,6 +3193,28 @@ function registerProjectLinkCommand(program2) {
|
|
|
3157
3193
|
if (opts.template && !validTemplates.includes(opts.template)) {
|
|
3158
3194
|
throw new CLIError(`Invalid template "${opts.template}". Valid options: ${validTemplates.join(", ")}`);
|
|
3159
3195
|
}
|
|
3196
|
+
const isSkillsOnly = opts.projectId === void 0 && opts.orgId === void 0 && opts.template === void 0 && opts.auth === void 0 && opts.apiBaseUrl === void 0 && opts.apiKey === void 0;
|
|
3197
|
+
if (isSkillsOnly) {
|
|
3198
|
+
try {
|
|
3199
|
+
await installSkills(json);
|
|
3200
|
+
trackCommand("link", "skills-only", { skills_only: true });
|
|
3201
|
+
await reportCliUsage("cli.link_skills_only", true, 1);
|
|
3202
|
+
if (json) {
|
|
3203
|
+
outputJson({ success: true, skills_only: true });
|
|
3204
|
+
} else {
|
|
3205
|
+
clack13.note(
|
|
3206
|
+
`Open your coding agent (Claude Code, Codex, Cursor, etc.) and ask it to build something. It will walk you through provisioning an InsForge project when needed.`,
|
|
3207
|
+
"What's next"
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
3210
|
+
return;
|
|
3211
|
+
} catch (err) {
|
|
3212
|
+
await reportCliUsage("cli.link_skills_only", false);
|
|
3213
|
+
await shutdownAnalytics();
|
|
3214
|
+
handleError(err, json);
|
|
3215
|
+
return;
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3160
3218
|
if (opts.apiBaseUrl || opts.apiKey) {
|
|
3161
3219
|
try {
|
|
3162
3220
|
if (!opts.apiBaseUrl || !opts.apiKey) {
|
|
@@ -3235,7 +3293,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
3235
3293
|
await runNpmSetupIfPresent();
|
|
3236
3294
|
}
|
|
3237
3295
|
}
|
|
3238
|
-
await installSkills(json);
|
|
3296
|
+
await installSkills(json, opts.auth);
|
|
3239
3297
|
trackCommand("link", "oss-org", { direct: true, template: template2 });
|
|
3240
3298
|
await reportCliUsage("cli.link_direct", true, 6, projectConfig2);
|
|
3241
3299
|
try {
|
|
@@ -3282,7 +3340,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
3282
3340
|
}
|
|
3283
3341
|
}
|
|
3284
3342
|
trackCommand("link", "oss-org", { direct: true });
|
|
3285
|
-
await installSkills(json);
|
|
3343
|
+
await installSkills(json, opts.auth);
|
|
3286
3344
|
await reportCliUsage("cli.link_direct", true, 6, projectConfig2);
|
|
3287
3345
|
try {
|
|
3288
3346
|
const urlMatch = opts.apiBaseUrl.match(/^https?:\/\/([^.]+)\.[^.]+\.insforge\.app/);
|
|
@@ -3337,9 +3395,9 @@ function registerProjectLinkCommand(program2) {
|
|
|
3337
3395
|
}
|
|
3338
3396
|
const selected = await select2({
|
|
3339
3397
|
message: "Select a project to link:",
|
|
3340
|
-
options: projects.map((
|
|
3341
|
-
value:
|
|
3342
|
-
label: `${
|
|
3398
|
+
options: projects.map((p3) => ({
|
|
3399
|
+
value: p3.id,
|
|
3400
|
+
label: `${p3.name} (${p3.region}, ${p3.status})`
|
|
3343
3401
|
}))
|
|
3344
3402
|
});
|
|
3345
3403
|
if (isCancel2(selected)) process.exit(0);
|
|
@@ -3432,7 +3490,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
3432
3490
|
await runNpmSetupIfPresent();
|
|
3433
3491
|
}
|
|
3434
3492
|
}
|
|
3435
|
-
await installSkills(json);
|
|
3493
|
+
await installSkills(json, opts.auth);
|
|
3436
3494
|
await reportCliUsage("cli.link", true, 6, projectConfig);
|
|
3437
3495
|
if (!json) {
|
|
3438
3496
|
const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
|
|
@@ -3465,7 +3523,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
3465
3523
|
else clack13.log.warn(msg);
|
|
3466
3524
|
}
|
|
3467
3525
|
}
|
|
3468
|
-
await installSkills(json);
|
|
3526
|
+
await installSkills(json, opts.auth);
|
|
3469
3527
|
await reportCliUsage("cli.link", true, 6, projectConfig);
|
|
3470
3528
|
if (!json) {
|
|
3471
3529
|
const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
|
|
@@ -3478,7 +3536,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
3478
3536
|
clack13.note(
|
|
3479
3537
|
`Open your coding agent (Claude Code, Codex, Cursor, etc.) and try:
|
|
3480
3538
|
|
|
3481
|
-
${prompts.map((
|
|
3539
|
+
${prompts.map((p3) => `\u2022 "${p3}"`).join("\n")}`,
|
|
3482
3540
|
"Start building"
|
|
3483
3541
|
);
|
|
3484
3542
|
}
|
|
@@ -3635,13 +3693,13 @@ function registerDbPoliciesCommand(dbCmd2) {
|
|
|
3635
3693
|
}
|
|
3636
3694
|
outputTable(
|
|
3637
3695
|
["Table", "Policy Name", "Command", "Roles", "Qual", "With Check"],
|
|
3638
|
-
policies.map((
|
|
3639
|
-
String(
|
|
3640
|
-
String(
|
|
3641
|
-
String(
|
|
3642
|
-
Array.isArray(
|
|
3643
|
-
String(
|
|
3644
|
-
String(
|
|
3696
|
+
policies.map((p3) => [
|
|
3697
|
+
String(p3.tableName ?? "-"),
|
|
3698
|
+
String(p3.policyName ?? "-"),
|
|
3699
|
+
String(p3.cmd ?? "-"),
|
|
3700
|
+
Array.isArray(p3.roles) ? p3.roles.join(", ") : String(p3.roles ?? "-"),
|
|
3701
|
+
String(p3.qual ?? "-"),
|
|
3702
|
+
String(p3.withCheck ?? "-")
|
|
3645
3703
|
])
|
|
3646
3704
|
);
|
|
3647
3705
|
}
|
|
@@ -4787,10 +4845,10 @@ function registerStorageDeleteBucketCommand(storageCmd2) {
|
|
|
4787
4845
|
try {
|
|
4788
4846
|
await requireAuth();
|
|
4789
4847
|
if (!yes && !json) {
|
|
4790
|
-
const
|
|
4848
|
+
const confirm8 = await confirm2({
|
|
4791
4849
|
message: `Delete bucket "${name}" and all its objects? This cannot be undone.`
|
|
4792
4850
|
});
|
|
4793
|
-
if (isCancel2(
|
|
4851
|
+
if (isCancel2(confirm8) || !confirm8) {
|
|
4794
4852
|
process.exit(0);
|
|
4795
4853
|
}
|
|
4796
4854
|
}
|
|
@@ -4937,12 +4995,12 @@ function registerListCommand(program2) {
|
|
|
4937
4995
|
id: org.id,
|
|
4938
4996
|
name: org.name,
|
|
4939
4997
|
type: org.type ?? null,
|
|
4940
|
-
projects: projects.map((
|
|
4941
|
-
id:
|
|
4942
|
-
name:
|
|
4943
|
-
region:
|
|
4944
|
-
status:
|
|
4945
|
-
appkey:
|
|
4998
|
+
projects: projects.map((p3) => ({
|
|
4999
|
+
id: p3.id,
|
|
5000
|
+
name: p3.name,
|
|
5001
|
+
region: p3.region,
|
|
5002
|
+
status: p3.status,
|
|
5003
|
+
appkey: p3.appkey
|
|
4946
5004
|
}))
|
|
4947
5005
|
}))
|
|
4948
5006
|
);
|
|
@@ -4954,13 +5012,13 @@ function registerListCommand(program2) {
|
|
|
4954
5012
|
rows.push([org.name, "-", "-", "-", "-"]);
|
|
4955
5013
|
} else {
|
|
4956
5014
|
for (let i = 0; i < projects.length; i++) {
|
|
4957
|
-
const
|
|
5015
|
+
const p3 = projects[i];
|
|
4958
5016
|
rows.push([
|
|
4959
5017
|
i === 0 ? org.name : "",
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
5018
|
+
p3.name,
|
|
5019
|
+
p3.region,
|
|
5020
|
+
p3.status,
|
|
5021
|
+
p3.appkey
|
|
4964
5022
|
]);
|
|
4965
5023
|
}
|
|
4966
5024
|
}
|
|
@@ -5341,10 +5399,10 @@ function registerSecretsDeleteCommand(secretsCmd2) {
|
|
|
5341
5399
|
try {
|
|
5342
5400
|
await requireAuth();
|
|
5343
5401
|
if (!yes && !json) {
|
|
5344
|
-
const
|
|
5402
|
+
const confirm8 = await confirm2({
|
|
5345
5403
|
message: `Delete secret "${key}"? This cannot be undone.`
|
|
5346
5404
|
});
|
|
5347
|
-
if (isCancel2(
|
|
5405
|
+
if (isCancel2(confirm8) || !confirm8) {
|
|
5348
5406
|
process.exit(0);
|
|
5349
5407
|
}
|
|
5350
5408
|
}
|
|
@@ -5532,10 +5590,10 @@ function registerSchedulesDeleteCommand(schedulesCmd2) {
|
|
|
5532
5590
|
try {
|
|
5533
5591
|
await requireAuth();
|
|
5534
5592
|
if (!yes && !json) {
|
|
5535
|
-
const
|
|
5593
|
+
const confirm8 = await confirm2({
|
|
5536
5594
|
message: `Delete schedule "${id}"? This cannot be undone.`
|
|
5537
5595
|
});
|
|
5538
|
-
if (isCancel2(
|
|
5596
|
+
if (isCancel2(confirm8) || !confirm8) {
|
|
5539
5597
|
process.exit(0);
|
|
5540
5598
|
}
|
|
5541
5599
|
}
|
|
@@ -5757,6 +5815,8 @@ function registerComputeUpdateCommand(computeCmd2) {
|
|
|
5757
5815
|
outputJson(service);
|
|
5758
5816
|
} else {
|
|
5759
5817
|
outputSuccess(`Service "${service.name}" updated [${service.status}]`);
|
|
5818
|
+
if (service.endpointUrl) console.log(` Endpoint: ${service.endpointUrl}`);
|
|
5819
|
+
if (service.port !== void 0) console.log(` Port: ${service.port} (container must listen on this port)`);
|
|
5760
5820
|
}
|
|
5761
5821
|
await reportCliUsage("cli.compute.update", true);
|
|
5762
5822
|
} catch (err) {
|
|
@@ -5957,7 +6017,7 @@ primary_region = "${opts.region}"
|
|
|
5957
6017
|
};
|
|
5958
6018
|
}
|
|
5959
6019
|
function flyctlBuildAndPush(opts) {
|
|
5960
|
-
return new Promise((
|
|
6020
|
+
return new Promise((resolve8, reject) => {
|
|
5961
6021
|
const cleanupStub = ensureFlyTomlStub({
|
|
5962
6022
|
dir: opts.dir,
|
|
5963
6023
|
appId: opts.appId,
|
|
@@ -6013,7 +6073,7 @@ function flyctlBuildAndPush(opts) {
|
|
|
6013
6073
|
)
|
|
6014
6074
|
);
|
|
6015
6075
|
}
|
|
6016
|
-
|
|
6076
|
+
resolve8({ imageRef: `registry.fly.io/${opts.appId}@${m[1]}` });
|
|
6017
6077
|
});
|
|
6018
6078
|
});
|
|
6019
6079
|
}
|
|
@@ -6112,6 +6172,7 @@ function registerComputeDeployCommand(computeCmd2) {
|
|
|
6112
6172
|
const verb = existing2 ? "updated" : "deployed";
|
|
6113
6173
|
outputSuccess(`Service "${service2.name}" ${verb} [${service2.status}]`);
|
|
6114
6174
|
if (service2.endpointUrl) console.log(` Endpoint: ${service2.endpointUrl}`);
|
|
6175
|
+
if (service2.port !== void 0) console.log(` Port: ${service2.port} (container must listen on this port)`);
|
|
6115
6176
|
}
|
|
6116
6177
|
await reportCliUsage("cli.compute.deploy", true);
|
|
6117
6178
|
return;
|
|
@@ -6207,6 +6268,7 @@ function registerComputeDeployCommand(computeCmd2) {
|
|
|
6207
6268
|
const verb = existing ? "updated" : "deployed";
|
|
6208
6269
|
outputSuccess(`Service "${service.name}" ${verb} [${service.status}]`);
|
|
6209
6270
|
if (service.endpointUrl) console.log(` Endpoint: ${service.endpointUrl}`);
|
|
6271
|
+
if (service.port !== void 0) console.log(` Port: ${service.port} (container must listen on this port)`);
|
|
6210
6272
|
console.log(` Image: ${imageRef} (built remotely; no local image to clean up)`);
|
|
6211
6273
|
}
|
|
6212
6274
|
await reportCliUsage("cli.compute.deploy", true);
|
|
@@ -6896,7 +6958,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
6896
6958
|
const s = !json ? clack15.spinner() : null;
|
|
6897
6959
|
s?.start("Collecting diagnostic data...");
|
|
6898
6960
|
const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
|
|
6899
|
-
const cliVersion = "0.1.
|
|
6961
|
+
const cliVersion = "0.1.76";
|
|
6900
6962
|
s?.stop("Data collected");
|
|
6901
6963
|
if (!json) {
|
|
6902
6964
|
console.log(`
|
|
@@ -7530,10 +7592,10 @@ function registerPaymentsConfigCommand(paymentsCmd2) {
|
|
|
7530
7592
|
throw new CLIError("Use --yes with --json to remove a Stripe key non-interactively.");
|
|
7531
7593
|
}
|
|
7532
7594
|
if (!yes) {
|
|
7533
|
-
const
|
|
7595
|
+
const confirm8 = await confirm2({
|
|
7534
7596
|
message: `Remove Stripe ${environment} key? Payment sync and mutations for this environment will stop.`
|
|
7535
7597
|
});
|
|
7536
|
-
if (isCancel2(
|
|
7598
|
+
if (isCancel2(confirm8) || !confirm8) process.exit(0);
|
|
7537
7599
|
}
|
|
7538
7600
|
const data = await removeStripeSecretKey(environment);
|
|
7539
7601
|
if (json) {
|
|
@@ -8056,10 +8118,10 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
|
|
|
8056
8118
|
);
|
|
8057
8119
|
}
|
|
8058
8120
|
if (!yes) {
|
|
8059
|
-
const
|
|
8121
|
+
const confirm8 = await confirm2({
|
|
8060
8122
|
message: `Delete Stripe ${environment} product "${productId}"?`
|
|
8061
8123
|
});
|
|
8062
|
-
if (isCancel2(
|
|
8124
|
+
if (isCancel2(confirm8) || !confirm8) process.exit(0);
|
|
8063
8125
|
}
|
|
8064
8126
|
const data = await deletePaymentProduct(environment, productId);
|
|
8065
8127
|
if (json) {
|
|
@@ -8410,14 +8472,14 @@ async function startPosthogCliFlow(projectId, jwt, apiUrl) {
|
|
|
8410
8472
|
throw new CLIError("PostHog cli-start returned an unexpected response shape.");
|
|
8411
8473
|
}
|
|
8412
8474
|
function sleep(ms, signal) {
|
|
8413
|
-
return new Promise((
|
|
8475
|
+
return new Promise((resolve8, reject) => {
|
|
8414
8476
|
if (signal?.aborted) {
|
|
8415
8477
|
reject(new CLIError("Connection wait cancelled."));
|
|
8416
8478
|
return;
|
|
8417
8479
|
}
|
|
8418
8480
|
const timer = setTimeout(() => {
|
|
8419
8481
|
signal?.removeEventListener("abort", onAbort);
|
|
8420
|
-
|
|
8482
|
+
resolve8();
|
|
8421
8483
|
}, ms);
|
|
8422
8484
|
const onAbort = () => {
|
|
8423
8485
|
clearTimeout(timer);
|
|
@@ -8985,13 +9047,373 @@ function frameworkLabel(framework) {
|
|
|
8985
9047
|
return "Astro";
|
|
8986
9048
|
}
|
|
8987
9049
|
}
|
|
8988
|
-
function relative3(
|
|
8989
|
-
return
|
|
9050
|
+
function relative3(p3) {
|
|
9051
|
+
return p3.replace(process.cwd() + "/", "");
|
|
9052
|
+
}
|
|
9053
|
+
|
|
9054
|
+
// src/commands/config/export.ts
|
|
9055
|
+
import { writeFileSync as writeFileSync9, existsSync as existsSync14 } from "fs";
|
|
9056
|
+
import { resolve as resolve5 } from "path";
|
|
9057
|
+
import * as p from "@clack/prompts";
|
|
9058
|
+
import pc4 from "picocolors";
|
|
9059
|
+
|
|
9060
|
+
// src/lib/config-toml.ts
|
|
9061
|
+
import * as smolToml from "smol-toml";
|
|
9062
|
+
|
|
9063
|
+
// src/lib/config-schema.ts
|
|
9064
|
+
var ConfigValidationError = class extends Error {
|
|
9065
|
+
constructor(path6, message) {
|
|
9066
|
+
super(`config.${path6}: ${message}`);
|
|
9067
|
+
this.path = path6;
|
|
9068
|
+
this.name = "ConfigValidationError";
|
|
9069
|
+
}
|
|
9070
|
+
};
|
|
9071
|
+
function validateConfig(input) {
|
|
9072
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
9073
|
+
throw new ConfigValidationError("", "must be an object");
|
|
9074
|
+
}
|
|
9075
|
+
const obj = input;
|
|
9076
|
+
const out = {};
|
|
9077
|
+
if ("project_id" in obj) {
|
|
9078
|
+
if (typeof obj.project_id !== "string") {
|
|
9079
|
+
throw new ConfigValidationError("project_id", "must be a string");
|
|
9080
|
+
}
|
|
9081
|
+
out.project_id = obj.project_id;
|
|
9082
|
+
}
|
|
9083
|
+
if ("auth" in obj) out.auth = validateAuth(obj.auth);
|
|
9084
|
+
return out;
|
|
9085
|
+
}
|
|
9086
|
+
function validateAuth(input) {
|
|
9087
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
9088
|
+
throw new ConfigValidationError("auth", "must be an object");
|
|
9089
|
+
}
|
|
9090
|
+
const obj = input;
|
|
9091
|
+
const out = {};
|
|
9092
|
+
if ("allowed_redirect_urls" in obj) {
|
|
9093
|
+
const v = obj.allowed_redirect_urls;
|
|
9094
|
+
if (!Array.isArray(v) || !v.every((u) => typeof u === "string")) {
|
|
9095
|
+
throw new ConfigValidationError(
|
|
9096
|
+
"auth.allowed_redirect_urls",
|
|
9097
|
+
"must be an array of strings"
|
|
9098
|
+
);
|
|
9099
|
+
}
|
|
9100
|
+
out.allowed_redirect_urls = v;
|
|
9101
|
+
}
|
|
9102
|
+
return out;
|
|
9103
|
+
}
|
|
9104
|
+
|
|
9105
|
+
// src/lib/config-toml.ts
|
|
9106
|
+
function parseConfigToml(input) {
|
|
9107
|
+
let parsed;
|
|
9108
|
+
try {
|
|
9109
|
+
parsed = smolToml.parse(input);
|
|
9110
|
+
} catch (err) {
|
|
9111
|
+
throw new Error(`TOML parse error: ${err.message}`, { cause: err });
|
|
9112
|
+
}
|
|
9113
|
+
return validateConfig(parsed);
|
|
9114
|
+
}
|
|
9115
|
+
function stringifyConfigToml(config) {
|
|
9116
|
+
const lines = [];
|
|
9117
|
+
if (config.project_id !== void 0) {
|
|
9118
|
+
lines.push(`project_id = ${JSON.stringify(config.project_id)}`);
|
|
9119
|
+
lines.push("");
|
|
9120
|
+
}
|
|
9121
|
+
if (config.auth) {
|
|
9122
|
+
lines.push("[auth]");
|
|
9123
|
+
if (config.auth.allowed_redirect_urls !== void 0) {
|
|
9124
|
+
const urls = config.auth.allowed_redirect_urls.map((u) => JSON.stringify(u)).join(", ");
|
|
9125
|
+
lines.push(`allowed_redirect_urls = [${urls}]`);
|
|
9126
|
+
}
|
|
9127
|
+
lines.push("");
|
|
9128
|
+
}
|
|
9129
|
+
return lines.join("\n").replace(/\n+$/, "\n");
|
|
9130
|
+
}
|
|
9131
|
+
|
|
9132
|
+
// src/commands/config/export.ts
|
|
9133
|
+
function registerConfigExportCommand(cfg) {
|
|
9134
|
+
cfg.command("export").description("Pull live project config and write insforge.toml").option("--out <path>", "output path", "insforge.toml").option("--force", "overwrite without confirmation").action(async (opts, cmd) => {
|
|
9135
|
+
const { json } = getRootOpts(cmd);
|
|
9136
|
+
try {
|
|
9137
|
+
await requireAuth();
|
|
9138
|
+
const target = resolve5(process.cwd(), opts.out);
|
|
9139
|
+
if (existsSync14(target) && !opts.force) {
|
|
9140
|
+
if (json) {
|
|
9141
|
+
throw new CLIError(
|
|
9142
|
+
`${opts.out} exists. Re-run with --force to overwrite.`,
|
|
9143
|
+
1,
|
|
9144
|
+
"OUTPUT_EXISTS"
|
|
9145
|
+
);
|
|
9146
|
+
}
|
|
9147
|
+
const ok = await p.confirm({
|
|
9148
|
+
message: `${opts.out} exists. Overwrite?`,
|
|
9149
|
+
initialValue: false
|
|
9150
|
+
});
|
|
9151
|
+
if (!ok || p.isCancel(ok)) {
|
|
9152
|
+
console.log("Aborted.");
|
|
9153
|
+
return;
|
|
9154
|
+
}
|
|
9155
|
+
}
|
|
9156
|
+
const res = await ossFetch("/api/metadata");
|
|
9157
|
+
const raw = await res.json();
|
|
9158
|
+
const config = {};
|
|
9159
|
+
const skipped = [];
|
|
9160
|
+
const authSlice = raw?.auth;
|
|
9161
|
+
if (authSlice && typeof authSlice === "object" && "allowedRedirectUrls" in authSlice) {
|
|
9162
|
+
config.auth = {
|
|
9163
|
+
allowed_redirect_urls: authSlice.allowedRedirectUrls ?? []
|
|
9164
|
+
};
|
|
9165
|
+
} else {
|
|
9166
|
+
skipped.push("auth.allowed_redirect_urls");
|
|
9167
|
+
}
|
|
9168
|
+
const toml = stringifyConfigToml(config);
|
|
9169
|
+
writeFileSync9(target, toml, "utf8");
|
|
9170
|
+
if (json) {
|
|
9171
|
+
console.log(JSON.stringify({ written: target, config, skipped }, null, 2));
|
|
9172
|
+
} else {
|
|
9173
|
+
console.log(`${pc4.green("\u2713")} Wrote ${target}`);
|
|
9174
|
+
if (skipped.length) {
|
|
9175
|
+
console.warn(
|
|
9176
|
+
pc4.yellow(
|
|
9177
|
+
`\u26A0 Skipped ${skipped.length} section(s) not supported by this backend:`
|
|
9178
|
+
) + "\n" + skipped.map((k) => ` - ${k}`).join("\n")
|
|
9179
|
+
);
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9182
|
+
await reportCliUsage("cli.config.export", true);
|
|
9183
|
+
} catch (err) {
|
|
9184
|
+
await reportCliUsage("cli.config.export", false);
|
|
9185
|
+
handleError(err, json);
|
|
9186
|
+
}
|
|
9187
|
+
});
|
|
9188
|
+
}
|
|
9189
|
+
|
|
9190
|
+
// src/commands/config/plan.ts
|
|
9191
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
9192
|
+
import { resolve as resolve6 } from "path";
|
|
9193
|
+
import pc5 from "picocolors";
|
|
9194
|
+
|
|
9195
|
+
// src/lib/config-diff.ts
|
|
9196
|
+
function diffConfig({ live, file }) {
|
|
9197
|
+
const changes = [];
|
|
9198
|
+
const fileAuth = file.auth;
|
|
9199
|
+
const liveAuth = live.auth ?? {};
|
|
9200
|
+
if (fileAuth && "allowed_redirect_urls" in fileAuth) {
|
|
9201
|
+
const fromV = normalizeUrlList(liveAuth.allowed_redirect_urls);
|
|
9202
|
+
const toV = normalizeUrlList(fileAuth.allowed_redirect_urls);
|
|
9203
|
+
if (!arrayEquals(fromV, toV)) {
|
|
9204
|
+
changes.push({
|
|
9205
|
+
section: "auth",
|
|
9206
|
+
op: "modify",
|
|
9207
|
+
key: "allowed_redirect_urls",
|
|
9208
|
+
from: fromV,
|
|
9209
|
+
to: toV
|
|
9210
|
+
});
|
|
9211
|
+
}
|
|
9212
|
+
}
|
|
9213
|
+
return { changes, summary: summarize(changes) };
|
|
9214
|
+
}
|
|
9215
|
+
function summarize(changes) {
|
|
9216
|
+
const s = { add: 0, modify: 0, remove: 0, kept: 0 };
|
|
9217
|
+
for (const c of changes) {
|
|
9218
|
+
if (c.op === "modify") s.modify++;
|
|
9219
|
+
}
|
|
9220
|
+
return s;
|
|
9221
|
+
}
|
|
9222
|
+
function normalizeUrlList(input) {
|
|
9223
|
+
return Array.from(new Set(input ?? [])).sort();
|
|
9224
|
+
}
|
|
9225
|
+
function arrayEquals(a, b) {
|
|
9226
|
+
if (a.length !== b.length) return false;
|
|
9227
|
+
return a.every((v, i) => v === b[i]);
|
|
9228
|
+
}
|
|
9229
|
+
|
|
9230
|
+
// src/lib/config-format.ts
|
|
9231
|
+
function formatPlan(result) {
|
|
9232
|
+
if (result.changes.length === 0) {
|
|
9233
|
+
return "No changes. Live state matches insforge.toml.";
|
|
9234
|
+
}
|
|
9235
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
9236
|
+
for (const c of result.changes) {
|
|
9237
|
+
const arr = bySection.get(c.section) ?? [];
|
|
9238
|
+
arr.push(c);
|
|
9239
|
+
bySection.set(c.section, arr);
|
|
9240
|
+
}
|
|
9241
|
+
const lines = [];
|
|
9242
|
+
for (const [section, changes] of bySection) {
|
|
9243
|
+
lines.push(` ${section}:`);
|
|
9244
|
+
for (const c of changes) {
|
|
9245
|
+
lines.push(` ${formatChange(c)}`);
|
|
9246
|
+
}
|
|
9247
|
+
lines.push("");
|
|
9248
|
+
}
|
|
9249
|
+
const s = result.summary;
|
|
9250
|
+
lines.push(
|
|
9251
|
+
`${s.add} add, ${s.modify} modify, ${s.remove} remove, ${s.kept} untracked kept.`
|
|
9252
|
+
);
|
|
9253
|
+
return lines.join("\n");
|
|
9254
|
+
}
|
|
9255
|
+
function formatChange(c) {
|
|
9256
|
+
return `~ ${c.key}: ${JSON.stringify(c.from)} \u2192 ${JSON.stringify(c.to)}`;
|
|
9257
|
+
}
|
|
9258
|
+
|
|
9259
|
+
// src/lib/config-capabilities.ts
|
|
9260
|
+
function metadataSupports(raw, change) {
|
|
9261
|
+
if (change.section === "auth" && change.key === "allowed_redirect_urls") {
|
|
9262
|
+
return raw?.auth !== void 0 && raw.auth !== null && typeof raw.auth === "object" && "allowedRedirectUrls" in raw.auth;
|
|
9263
|
+
}
|
|
9264
|
+
return false;
|
|
9265
|
+
}
|
|
9266
|
+
function changePath(change) {
|
|
9267
|
+
return `${change.section}.${change.key}`;
|
|
9268
|
+
}
|
|
9269
|
+
|
|
9270
|
+
// src/commands/config/plan.ts
|
|
9271
|
+
function registerConfigPlanCommand(cfg) {
|
|
9272
|
+
cfg.command("plan").description("Show diff between insforge.toml and live project state").option("--file <path>", "path to insforge.toml", "insforge.toml").action(async (opts, cmd) => {
|
|
9273
|
+
const { json } = getRootOpts(cmd);
|
|
9274
|
+
try {
|
|
9275
|
+
await requireAuth();
|
|
9276
|
+
const tomlPath = resolve6(process.cwd(), opts.file);
|
|
9277
|
+
const tomlSource = readFileSync11(tomlPath, "utf8");
|
|
9278
|
+
const file = parseConfigToml(tomlSource);
|
|
9279
|
+
const res = await ossFetch("/api/metadata");
|
|
9280
|
+
const raw = await res.json();
|
|
9281
|
+
const live = {
|
|
9282
|
+
auth: { allowed_redirect_urls: raw.auth?.allowedRedirectUrls ?? [] }
|
|
9283
|
+
};
|
|
9284
|
+
const result = diffConfig({ live, file });
|
|
9285
|
+
const skipped = result.changes.filter((c) => !metadataSupports(raw, c)).map((c) => changePath(c));
|
|
9286
|
+
if (json) {
|
|
9287
|
+
console.log(JSON.stringify({ ...result, skipped }, null, 2));
|
|
9288
|
+
} else {
|
|
9289
|
+
console.log(`Plan for insforge.toml (file: ${opts.file}):
|
|
9290
|
+
`);
|
|
9291
|
+
console.log(formatPlan(result));
|
|
9292
|
+
if (skipped.length) {
|
|
9293
|
+
console.warn(
|
|
9294
|
+
"\n" + pc5.yellow(`\u26A0 Apply will skip ${skipped.length} section(s) \u2014 backend doesn't support them yet:`) + "\n" + skipped.map((k) => ` - ${k}`).join("\n")
|
|
9295
|
+
);
|
|
9296
|
+
}
|
|
9297
|
+
}
|
|
9298
|
+
await reportCliUsage("cli.config.plan", true);
|
|
9299
|
+
} catch (err) {
|
|
9300
|
+
await reportCliUsage("cli.config.plan", false);
|
|
9301
|
+
handleError(err, json);
|
|
9302
|
+
}
|
|
9303
|
+
});
|
|
9304
|
+
}
|
|
9305
|
+
|
|
9306
|
+
// src/commands/config/apply.ts
|
|
9307
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
9308
|
+
import { resolve as resolve7 } from "path";
|
|
9309
|
+
import * as p2 from "@clack/prompts";
|
|
9310
|
+
import pc6 from "picocolors";
|
|
9311
|
+
function registerConfigApplyCommand(cfg) {
|
|
9312
|
+
cfg.command("apply").description("Apply insforge.toml to the live project").option("--file <path>", "path to insforge.toml", "insforge.toml").option("--dry-run", "show plan, do not apply").option("--auto-approve", "skip confirmation prompt").action(async (opts, cmd) => {
|
|
9313
|
+
const { json, yes } = getRootOpts(cmd);
|
|
9314
|
+
try {
|
|
9315
|
+
await requireAuth();
|
|
9316
|
+
const tomlPath = resolve7(process.cwd(), opts.file);
|
|
9317
|
+
const tomlSource = readFileSync12(tomlPath, "utf8");
|
|
9318
|
+
const file = parseConfigToml(tomlSource);
|
|
9319
|
+
const res = await ossFetch("/api/metadata");
|
|
9320
|
+
const raw = await res.json();
|
|
9321
|
+
const live = {
|
|
9322
|
+
auth: { allowed_redirect_urls: raw.auth?.allowedRedirectUrls ?? [] }
|
|
9323
|
+
};
|
|
9324
|
+
const result = diffConfig({ live, file });
|
|
9325
|
+
const approved = opts.autoApprove || yes;
|
|
9326
|
+
if (!json) {
|
|
9327
|
+
console.log(formatPlan(result));
|
|
9328
|
+
}
|
|
9329
|
+
if (result.changes.length === 0 || opts.dryRun) {
|
|
9330
|
+
if (json) {
|
|
9331
|
+
console.log(
|
|
9332
|
+
JSON.stringify({ plan: result, applied: false, dryRun: !!opts.dryRun }, null, 2)
|
|
9333
|
+
);
|
|
9334
|
+
}
|
|
9335
|
+
await reportCliUsage("cli.config.apply", true);
|
|
9336
|
+
return;
|
|
9337
|
+
}
|
|
9338
|
+
if (!approved) {
|
|
9339
|
+
if (json) {
|
|
9340
|
+
throw new CLIError(
|
|
9341
|
+
"Refusing to apply in --json mode without --auto-approve or --yes.",
|
|
9342
|
+
1,
|
|
9343
|
+
"CONFIRMATION_REQUIRED"
|
|
9344
|
+
);
|
|
9345
|
+
}
|
|
9346
|
+
const ok = await p2.confirm({
|
|
9347
|
+
message: "Apply these changes?",
|
|
9348
|
+
initialValue: false
|
|
9349
|
+
});
|
|
9350
|
+
if (!ok || p2.isCancel(ok)) {
|
|
9351
|
+
console.log("Aborted.");
|
|
9352
|
+
await reportCliUsage("cli.config.apply", true);
|
|
9353
|
+
return;
|
|
9354
|
+
}
|
|
9355
|
+
}
|
|
9356
|
+
const applied = [];
|
|
9357
|
+
const skipped = [];
|
|
9358
|
+
for (const change of result.changes) {
|
|
9359
|
+
const path6 = changePath(change);
|
|
9360
|
+
if (!metadataSupports(raw, change)) {
|
|
9361
|
+
skipped.push({
|
|
9362
|
+
key: path6,
|
|
9363
|
+
reason: `your backend doesn't expose ${path6} \u2014 upgrade the project to apply this section`
|
|
9364
|
+
});
|
|
9365
|
+
continue;
|
|
9366
|
+
}
|
|
9367
|
+
await applyChange(change);
|
|
9368
|
+
applied.push(change);
|
|
9369
|
+
}
|
|
9370
|
+
if (json) {
|
|
9371
|
+
console.log(
|
|
9372
|
+
JSON.stringify({ plan: result, applied, skipped }, null, 2)
|
|
9373
|
+
);
|
|
9374
|
+
} else {
|
|
9375
|
+
if (skipped.length) {
|
|
9376
|
+
console.warn(
|
|
9377
|
+
pc6.yellow(`\u26A0 Skipped ${skipped.length} section(s):`) + "\n" + skipped.map((s) => ` - ${s.key}: ${s.reason}`).join("\n")
|
|
9378
|
+
);
|
|
9379
|
+
}
|
|
9380
|
+
if (applied.length) {
|
|
9381
|
+
console.log(
|
|
9382
|
+
`${pc6.green("\u2713")} Applied ${applied.length} of ${result.changes.length} change(s).`
|
|
9383
|
+
);
|
|
9384
|
+
} else {
|
|
9385
|
+
console.log("Nothing applied.");
|
|
9386
|
+
}
|
|
9387
|
+
}
|
|
9388
|
+
await reportCliUsage("cli.config.apply", true);
|
|
9389
|
+
} catch (err) {
|
|
9390
|
+
await reportCliUsage("cli.config.apply", false);
|
|
9391
|
+
handleError(err, json);
|
|
9392
|
+
}
|
|
9393
|
+
});
|
|
9394
|
+
}
|
|
9395
|
+
async function applyChange(change) {
|
|
9396
|
+
if (change.section === "auth" && change.key === "allowed_redirect_urls") {
|
|
9397
|
+
await ossFetch("/api/auth/config", {
|
|
9398
|
+
method: "PUT",
|
|
9399
|
+
body: JSON.stringify({ allowedRedirectUrls: change.to })
|
|
9400
|
+
});
|
|
9401
|
+
return;
|
|
9402
|
+
}
|
|
9403
|
+
throw new Error(`Unsupported change type: ${change.section}.${change.key}`);
|
|
9404
|
+
}
|
|
9405
|
+
|
|
9406
|
+
// src/commands/config/index.ts
|
|
9407
|
+
function registerConfigCommand(program2) {
|
|
9408
|
+
const cfg = program2.command("config").description("Manage insforge.toml (declarative project configuration)");
|
|
9409
|
+
registerConfigExportCommand(cfg);
|
|
9410
|
+
registerConfigPlanCommand(cfg);
|
|
9411
|
+
registerConfigApplyCommand(cfg);
|
|
8990
9412
|
}
|
|
8991
9413
|
|
|
8992
9414
|
// src/index.ts
|
|
8993
9415
|
var __dirname = dirname3(fileURLToPath(import.meta.url));
|
|
8994
|
-
var pkg = JSON.parse(
|
|
9416
|
+
var pkg = JSON.parse(readFileSync13(join17(__dirname, "../package.json"), "utf-8"));
|
|
8995
9417
|
var INSFORGE_LOGO = `
|
|
8996
9418
|
\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
8997
9419
|
\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
|
|
@@ -9082,6 +9504,7 @@ registerSchedulesCreateCommand(schedulesCmd);
|
|
|
9082
9504
|
registerSchedulesUpdateCommand(schedulesCmd);
|
|
9083
9505
|
registerSchedulesDeleteCommand(schedulesCmd);
|
|
9084
9506
|
registerSchedulesLogsCommand(schedulesCmd);
|
|
9507
|
+
registerConfigCommand(program);
|
|
9085
9508
|
if (process.argv.length <= 2 && process.stdout.isTTY) {
|
|
9086
9509
|
await showInteractiveMenu();
|
|
9087
9510
|
} else {
|