@insforge/cli 0.1.53-dev.1 → 0.1.54
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 +34 -409
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { join as
|
|
4
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
5
|
+
import { join as join10, dirname } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import * as clack11 from "@clack/prompts";
|
|
@@ -1050,8 +1050,8 @@ ${missing.join("\n")}
|
|
|
1050
1050
|
}
|
|
1051
1051
|
async function installSkills(json) {
|
|
1052
1052
|
try {
|
|
1053
|
-
if (!json) clack5.log.info("Installing InsForge agent skills...");
|
|
1054
|
-
await execAsync("npx skills add insforge/agent-skills -y -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", {
|
|
1053
|
+
if (!json) clack5.log.info("Installing InsForge agent skills (global)...");
|
|
1054
|
+
await execAsync("npx skills add insforge/agent-skills -g -y -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", {
|
|
1055
1055
|
cwd: process.cwd(),
|
|
1056
1056
|
timeout: SKILL_INSTALL_TIMEOUT_MS
|
|
1057
1057
|
});
|
|
@@ -1063,8 +1063,8 @@ async function installSkills(json) {
|
|
|
1063
1063
|
}
|
|
1064
1064
|
}
|
|
1065
1065
|
try {
|
|
1066
|
-
if (!json) clack5.log.info("Installing find-skills...");
|
|
1067
|
-
await execAsync("npx skills add https://github.com/vercel-labs/skills --skill find-skills -y", {
|
|
1066
|
+
if (!json) clack5.log.info("Installing find-skills (global)...");
|
|
1067
|
+
await execAsync("npx skills add https://github.com/vercel-labs/skills --skill find-skills -g -y", {
|
|
1068
1068
|
cwd: process.cwd(),
|
|
1069
1069
|
timeout: SKILL_INSTALL_TIMEOUT_MS
|
|
1070
1070
|
});
|
|
@@ -1123,7 +1123,7 @@ async function reportCliUsage(toolName, success, maxRetries = 1, explicitConfig)
|
|
|
1123
1123
|
|
|
1124
1124
|
// src/lib/analytics.ts
|
|
1125
1125
|
import { PostHog } from "posthog-node";
|
|
1126
|
-
var POSTHOG_API_KEY = "";
|
|
1126
|
+
var POSTHOG_API_KEY = "phc_ueV1ii62wdBTkH7E70ugyeqHIHu8dFDdjs0qq3TZhJz";
|
|
1127
1127
|
var POSTHOG_HOST = process.env.POSTHOG_HOST || "https://us.i.posthog.com";
|
|
1128
1128
|
var client = null;
|
|
1129
1129
|
function getClient() {
|
|
@@ -2230,7 +2230,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
2230
2230
|
if (err instanceof CLIError && (err.exitCode === 5 || err.exitCode === 4 || err.message.includes("not found"))) {
|
|
2231
2231
|
const identity = creds.user?.email ?? creds.user?.name ?? "unknown user";
|
|
2232
2232
|
throw new CLIError(
|
|
2233
|
-
`
|
|
2233
|
+
`No access to project ${projectId} as ${identity}. Double-check the project ID, or run \`npx @insforge/cli logout\` to switch accounts.`,
|
|
2234
2234
|
5,
|
|
2235
2235
|
"PERMISSION_DENIED"
|
|
2236
2236
|
);
|
|
@@ -2671,380 +2671,6 @@ function registerDbImportCommand(dbCmd2) {
|
|
|
2671
2671
|
});
|
|
2672
2672
|
}
|
|
2673
2673
|
|
|
2674
|
-
// src/commands/db/migrations.ts
|
|
2675
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2676
|
-
import { join as join8 } from "path";
|
|
2677
|
-
|
|
2678
|
-
// src/lib/migrations.ts
|
|
2679
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
2680
|
-
import { join as join7 } from "path";
|
|
2681
|
-
var MIGRATION_FILENAME_REGEX = /^(\d{14})_([a-z0-9-]+)\.sql$/;
|
|
2682
|
-
function parseMigrationFilename(filename) {
|
|
2683
|
-
const match = MIGRATION_FILENAME_REGEX.exec(filename);
|
|
2684
|
-
if (!match) {
|
|
2685
|
-
return null;
|
|
2686
|
-
}
|
|
2687
|
-
return {
|
|
2688
|
-
filename,
|
|
2689
|
-
version: match[1],
|
|
2690
|
-
name: match[2]
|
|
2691
|
-
};
|
|
2692
|
-
}
|
|
2693
|
-
function compareMigrationVersions(left, right) {
|
|
2694
|
-
return left.localeCompare(right);
|
|
2695
|
-
}
|
|
2696
|
-
function formatMigrationVersion(date) {
|
|
2697
|
-
const year = String(date.getUTCFullYear());
|
|
2698
|
-
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
2699
|
-
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
2700
|
-
const hour = String(date.getUTCHours()).padStart(2, "0");
|
|
2701
|
-
const minute = String(date.getUTCMinutes()).padStart(2, "0");
|
|
2702
|
-
const second = String(date.getUTCSeconds()).padStart(2, "0");
|
|
2703
|
-
return `${year}${month}${day}${hour}${minute}${second}`;
|
|
2704
|
-
}
|
|
2705
|
-
function incrementMigrationVersion(version) {
|
|
2706
|
-
const year = Number(version.slice(0, 4));
|
|
2707
|
-
const month = Number(version.slice(4, 6)) - 1;
|
|
2708
|
-
const day = Number(version.slice(6, 8));
|
|
2709
|
-
const hour = Number(version.slice(8, 10));
|
|
2710
|
-
const minute = Number(version.slice(10, 12));
|
|
2711
|
-
const second = Number(version.slice(12, 14));
|
|
2712
|
-
const nextTimestamp = Date.UTC(year, month, day, hour, minute, second + 1);
|
|
2713
|
-
return formatMigrationVersion(new Date(nextTimestamp));
|
|
2714
|
-
}
|
|
2715
|
-
function getMigrationsDir(cwd = process.cwd()) {
|
|
2716
|
-
return join7(cwd, ".insforge", "migrations");
|
|
2717
|
-
}
|
|
2718
|
-
function ensureMigrationsDir(cwd = process.cwd()) {
|
|
2719
|
-
const migrationsDir = getMigrationsDir(cwd);
|
|
2720
|
-
if (!existsSync3(migrationsDir)) {
|
|
2721
|
-
mkdirSync2(migrationsDir, { recursive: true });
|
|
2722
|
-
}
|
|
2723
|
-
return migrationsDir;
|
|
2724
|
-
}
|
|
2725
|
-
function listLocalMigrationFilenames(cwd = process.cwd()) {
|
|
2726
|
-
const migrationsDir = getMigrationsDir(cwd);
|
|
2727
|
-
if (!existsSync3(migrationsDir)) {
|
|
2728
|
-
return [];
|
|
2729
|
-
}
|
|
2730
|
-
return readdirSync(migrationsDir).sort((left, right) => left.localeCompare(right));
|
|
2731
|
-
}
|
|
2732
|
-
function parseStrictLocalMigrations(filenames) {
|
|
2733
|
-
const migrations = filenames.map((filename) => {
|
|
2734
|
-
const parsedMigration = parseMigrationFilename(filename);
|
|
2735
|
-
if (!parsedMigration) {
|
|
2736
|
-
throw new CLIError(
|
|
2737
|
-
`Invalid migration filename: ${filename}. Expected <migration_version>_<migration-name>.sql.`
|
|
2738
|
-
);
|
|
2739
|
-
}
|
|
2740
|
-
return parsedMigration;
|
|
2741
|
-
});
|
|
2742
|
-
assertNoDuplicateMigrationVersions(migrations);
|
|
2743
|
-
return migrations.sort((left, right) => compareMigrationVersions(left.version, right.version));
|
|
2744
|
-
}
|
|
2745
|
-
function assertNoDuplicateMigrationVersions(migrations) {
|
|
2746
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2747
|
-
for (const migration of migrations) {
|
|
2748
|
-
if (seen.has(migration.version)) {
|
|
2749
|
-
throw new CLIError(`Duplicate local migration version found: ${migration.version}`);
|
|
2750
|
-
}
|
|
2751
|
-
seen.add(migration.version);
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
function getNextLocalMigrationVersion(migrations, latestRemoteVersion, now = /* @__PURE__ */ new Date()) {
|
|
2755
|
-
const orderedMigrations = [...migrations].sort(
|
|
2756
|
-
(left, right) => compareMigrationVersions(left.version, right.version)
|
|
2757
|
-
);
|
|
2758
|
-
assertNoDuplicateMigrationVersions(orderedMigrations);
|
|
2759
|
-
const latestKnownVersion = orderedMigrations.reduce(
|
|
2760
|
-
(latestVersion, migration) => {
|
|
2761
|
-
if (!latestVersion || compareMigrationVersions(migration.version, latestVersion) > 0) {
|
|
2762
|
-
return migration.version;
|
|
2763
|
-
}
|
|
2764
|
-
return latestVersion;
|
|
2765
|
-
},
|
|
2766
|
-
latestRemoteVersion
|
|
2767
|
-
);
|
|
2768
|
-
const currentVersion = formatMigrationVersion(now);
|
|
2769
|
-
if (!latestKnownVersion || compareMigrationVersions(currentVersion, latestKnownVersion) > 0) {
|
|
2770
|
-
return currentVersion;
|
|
2771
|
-
}
|
|
2772
|
-
return incrementMigrationVersion(latestKnownVersion);
|
|
2773
|
-
}
|
|
2774
|
-
function formatMigrationSql(statements) {
|
|
2775
|
-
return statements.map((statement) => statement.trim().replace(/;\s*$/u, "")).filter(Boolean).join(";\n\n").concat(statements.length > 0 ? ";\n" : "");
|
|
2776
|
-
}
|
|
2777
|
-
function findLocalMigrationByVersion(version, filenames) {
|
|
2778
|
-
const matches = filenames.map((filename) => parseMigrationFilename(filename)).filter(
|
|
2779
|
-
(migration) => migration !== null && migration.version === version
|
|
2780
|
-
);
|
|
2781
|
-
if (matches.length === 0) {
|
|
2782
|
-
throw new CLIError(`Local migration for version ${version} not found.`);
|
|
2783
|
-
}
|
|
2784
|
-
if (matches.length > 1) {
|
|
2785
|
-
throw new CLIError(
|
|
2786
|
-
`Multiple local migration files found for version ${version}.`
|
|
2787
|
-
);
|
|
2788
|
-
}
|
|
2789
|
-
return matches[0];
|
|
2790
|
-
}
|
|
2791
|
-
function resolveMigrationTarget(target, filenames) {
|
|
2792
|
-
if (/^\d{14}$/u.test(target)) {
|
|
2793
|
-
return findLocalMigrationByVersion(target, filenames);
|
|
2794
|
-
}
|
|
2795
|
-
const parsedTarget = parseMigrationFilename(target);
|
|
2796
|
-
if (!parsedTarget) {
|
|
2797
|
-
throw new CLIError(
|
|
2798
|
-
"Migration file names must match <migration_version>_<migration-name>.sql."
|
|
2799
|
-
);
|
|
2800
|
-
}
|
|
2801
|
-
if (!filenames.includes(target)) {
|
|
2802
|
-
throw new CLIError(`Local migration file not found: ${target}`);
|
|
2803
|
-
}
|
|
2804
|
-
return findLocalMigrationByVersion(parsedTarget.version, filenames);
|
|
2805
|
-
}
|
|
2806
|
-
|
|
2807
|
-
// src/commands/db/migrations.ts
|
|
2808
|
-
function getLatestRemoteVersion(migrations) {
|
|
2809
|
-
return migrations.reduce(
|
|
2810
|
-
(latestVersion, migration) => !latestVersion || compareMigrationVersions(migration.version, latestVersion) > 0 ? migration.version : latestVersion,
|
|
2811
|
-
null
|
|
2812
|
-
);
|
|
2813
|
-
}
|
|
2814
|
-
function buildMigrationFilename(version, name) {
|
|
2815
|
-
return `${version}_${name}.sql`;
|
|
2816
|
-
}
|
|
2817
|
-
function formatCreatedAt(createdAt) {
|
|
2818
|
-
const date = new Date(createdAt);
|
|
2819
|
-
return Number.isNaN(date.getTime()) ? createdAt : date.toLocaleString();
|
|
2820
|
-
}
|
|
2821
|
-
async function fetchRemoteMigrations() {
|
|
2822
|
-
const res = await ossFetch("/api/database/migrations");
|
|
2823
|
-
const raw = await res.json();
|
|
2824
|
-
return Array.isArray(raw.migrations) ? raw.migrations : [];
|
|
2825
|
-
}
|
|
2826
|
-
function assertValidMigrationName(name) {
|
|
2827
|
-
if (!/^[a-z0-9-]+$/u.test(name)) {
|
|
2828
|
-
throw new CLIError("Migration name must use lowercase letters, numbers, and hyphens only.");
|
|
2829
|
-
}
|
|
2830
|
-
}
|
|
2831
|
-
async function applyMigration(targetMigration, sql) {
|
|
2832
|
-
const body = {
|
|
2833
|
-
version: targetMigration.version,
|
|
2834
|
-
name: targetMigration.name,
|
|
2835
|
-
sql
|
|
2836
|
-
};
|
|
2837
|
-
const res = await ossFetch("/api/database/migrations", {
|
|
2838
|
-
method: "POST",
|
|
2839
|
-
body: JSON.stringify(body)
|
|
2840
|
-
});
|
|
2841
|
-
const createdMigration = await res.json();
|
|
2842
|
-
if (createdMigration.version !== targetMigration.version) {
|
|
2843
|
-
throw new CLIError(
|
|
2844
|
-
`Applied migration version mismatch. Expected ${targetMigration.version}, received ${createdMigration.version}.`
|
|
2845
|
-
);
|
|
2846
|
-
}
|
|
2847
|
-
return createdMigration;
|
|
2848
|
-
}
|
|
2849
|
-
function registerDbMigrationsCommand(dbCmd2) {
|
|
2850
|
-
const migrationsCmd = dbCmd2.command("migrations").description("Manage database migration files");
|
|
2851
|
-
migrationsCmd.command("list").description("List applied remote database migrations").action(async (_opts, cmd) => {
|
|
2852
|
-
const { json } = getRootOpts(cmd);
|
|
2853
|
-
try {
|
|
2854
|
-
await requireAuth();
|
|
2855
|
-
const migrations = await fetchRemoteMigrations();
|
|
2856
|
-
if (json) {
|
|
2857
|
-
outputJson({ migrations });
|
|
2858
|
-
} else if (migrations.length === 0) {
|
|
2859
|
-
console.log("No database migrations found.");
|
|
2860
|
-
} else {
|
|
2861
|
-
outputTable(
|
|
2862
|
-
["Version", "Name", "Created At"],
|
|
2863
|
-
migrations.map((migration) => [
|
|
2864
|
-
migration.version,
|
|
2865
|
-
migration.name,
|
|
2866
|
-
formatCreatedAt(migration.createdAt)
|
|
2867
|
-
])
|
|
2868
|
-
);
|
|
2869
|
-
}
|
|
2870
|
-
await reportCliUsage("cli.db.migrations.list", true);
|
|
2871
|
-
} catch (err) {
|
|
2872
|
-
await reportCliUsage("cli.db.migrations.list", false);
|
|
2873
|
-
handleError(err, json);
|
|
2874
|
-
}
|
|
2875
|
-
});
|
|
2876
|
-
migrationsCmd.command("fetch").description("Fetch applied remote migrations into .insforge/migrations/").action(async (_opts, cmd) => {
|
|
2877
|
-
const { json } = getRootOpts(cmd);
|
|
2878
|
-
try {
|
|
2879
|
-
await requireAuth();
|
|
2880
|
-
const migrations = await fetchRemoteMigrations();
|
|
2881
|
-
const migrationsDir = ensureMigrationsDir();
|
|
2882
|
-
const createdFiles = [];
|
|
2883
|
-
const skippedFiles = [];
|
|
2884
|
-
for (const migration of [...migrations].sort(
|
|
2885
|
-
(left, right) => compareMigrationVersions(left.version, right.version)
|
|
2886
|
-
)) {
|
|
2887
|
-
const filename = buildMigrationFilename(
|
|
2888
|
-
migration.version,
|
|
2889
|
-
migration.name
|
|
2890
|
-
);
|
|
2891
|
-
const filePath = join8(migrationsDir, filename);
|
|
2892
|
-
if (existsSync4(filePath)) {
|
|
2893
|
-
skippedFiles.push(filename);
|
|
2894
|
-
continue;
|
|
2895
|
-
}
|
|
2896
|
-
writeFileSync3(filePath, formatMigrationSql(migration.statements));
|
|
2897
|
-
createdFiles.push(filename);
|
|
2898
|
-
}
|
|
2899
|
-
if (json) {
|
|
2900
|
-
outputJson({
|
|
2901
|
-
directory: migrationsDir,
|
|
2902
|
-
totalRemoteMigrations: migrations.length,
|
|
2903
|
-
createdFiles,
|
|
2904
|
-
skippedFiles
|
|
2905
|
-
});
|
|
2906
|
-
} else {
|
|
2907
|
-
outputSuccess(
|
|
2908
|
-
`Fetched ${migrations.length} remote migration(s) into ${migrationsDir}.`
|
|
2909
|
-
);
|
|
2910
|
-
console.log(`Created: ${createdFiles.length}`);
|
|
2911
|
-
console.log(`Skipped: ${skippedFiles.length}`);
|
|
2912
|
-
}
|
|
2913
|
-
await reportCliUsage("cli.db.migrations.fetch", true);
|
|
2914
|
-
} catch (err) {
|
|
2915
|
-
await reportCliUsage("cli.db.migrations.fetch", false);
|
|
2916
|
-
handleError(err, json);
|
|
2917
|
-
}
|
|
2918
|
-
});
|
|
2919
|
-
migrationsCmd.command("new <migration-name>").description("Create a new local migration file").action(async (migrationName, _opts, cmd) => {
|
|
2920
|
-
const { json } = getRootOpts(cmd);
|
|
2921
|
-
try {
|
|
2922
|
-
await requireAuth();
|
|
2923
|
-
assertValidMigrationName(migrationName);
|
|
2924
|
-
const migrations = await fetchRemoteMigrations();
|
|
2925
|
-
const latestRemoteVersion = getLatestRemoteVersion(migrations);
|
|
2926
|
-
const localMigrations = parseStrictLocalMigrations(listLocalMigrationFilenames());
|
|
2927
|
-
const nextVersion = getNextLocalMigrationVersion(
|
|
2928
|
-
localMigrations,
|
|
2929
|
-
latestRemoteVersion
|
|
2930
|
-
);
|
|
2931
|
-
const filename = buildMigrationFilename(nextVersion, migrationName);
|
|
2932
|
-
const migrationsDir = ensureMigrationsDir();
|
|
2933
|
-
const filePath = join8(migrationsDir, filename);
|
|
2934
|
-
if (existsSync4(filePath)) {
|
|
2935
|
-
throw new CLIError(`Migration file already exists: ${filename}`);
|
|
2936
|
-
}
|
|
2937
|
-
writeFileSync3(filePath, "");
|
|
2938
|
-
if (json) {
|
|
2939
|
-
outputJson({ filename, path: filePath, version: nextVersion });
|
|
2940
|
-
} else {
|
|
2941
|
-
outputSuccess(`Created migration file ${filename}`);
|
|
2942
|
-
}
|
|
2943
|
-
await reportCliUsage("cli.db.migrations.new", true);
|
|
2944
|
-
} catch (err) {
|
|
2945
|
-
await reportCliUsage("cli.db.migrations.new", false);
|
|
2946
|
-
handleError(err, json);
|
|
2947
|
-
}
|
|
2948
|
-
});
|
|
2949
|
-
migrationsCmd.command("up [target]").description("Apply one or more local migration files").option("--all", "Apply all pending local migration files").option("--to <version-or-filename>", "Apply pending local migrations up to a version or file").action(async (target, options, cmd) => {
|
|
2950
|
-
const { json } = getRootOpts(cmd);
|
|
2951
|
-
try {
|
|
2952
|
-
await requireAuth();
|
|
2953
|
-
const migrations = await fetchRemoteMigrations();
|
|
2954
|
-
const latestRemoteVersion = getLatestRemoteVersion(migrations);
|
|
2955
|
-
const filenames = listLocalMigrationFilenames();
|
|
2956
|
-
const requestedModes = [Boolean(target), Boolean(options.all), Boolean(options.to)].filter(Boolean);
|
|
2957
|
-
if (requestedModes.length !== 1) {
|
|
2958
|
-
throw new CLIError(
|
|
2959
|
-
"Use exactly one apply mode: `up <target>`, `up --to <version-or-filename>`, or `up --all`."
|
|
2960
|
-
);
|
|
2961
|
-
}
|
|
2962
|
-
const applySingleTarget = async (targetMigrationFilenameOrVersion) => {
|
|
2963
|
-
const targetMigration = resolveMigrationTarget(targetMigrationFilenameOrVersion, filenames);
|
|
2964
|
-
const validLocalMigrations = filenames.map((filename) => parseMigrationFilename(filename)).filter((migration) => migration !== null).sort((left, right) => compareMigrationVersions(left.version, right.version));
|
|
2965
|
-
if (latestRemoteVersion && compareMigrationVersions(targetMigration.version, latestRemoteVersion) <= 0) {
|
|
2966
|
-
throw new CLIError(
|
|
2967
|
-
`Migration ${targetMigration.filename} is already applied remotely.`
|
|
2968
|
-
);
|
|
2969
|
-
}
|
|
2970
|
-
const earlierPendingMigration = validLocalMigrations.find(
|
|
2971
|
-
(migration) => migration.version !== targetMigration.version && (!latestRemoteVersion || compareMigrationVersions(migration.version, latestRemoteVersion) > 0) && compareMigrationVersions(migration.version, targetMigration.version) < 0
|
|
2972
|
-
);
|
|
2973
|
-
if (earlierPendingMigration) {
|
|
2974
|
-
throw new CLIError(
|
|
2975
|
-
`Migration ${targetMigration.filename} is not the next pending local migration. Apply ${earlierPendingMigration.filename} first.`
|
|
2976
|
-
);
|
|
2977
|
-
}
|
|
2978
|
-
const filePath = join8(getMigrationsDir(), targetMigration.filename);
|
|
2979
|
-
if (!existsSync4(filePath)) {
|
|
2980
|
-
throw new CLIError(`Local migration file not found: ${targetMigration.filename}`);
|
|
2981
|
-
}
|
|
2982
|
-
const sql = readFileSync4(filePath, "utf-8");
|
|
2983
|
-
if (!sql.trim()) {
|
|
2984
|
-
throw new CLIError(`Migration file is empty: ${targetMigration.filename}`);
|
|
2985
|
-
}
|
|
2986
|
-
return applyMigration(targetMigration, sql);
|
|
2987
|
-
};
|
|
2988
|
-
let appliedMigrations = [];
|
|
2989
|
-
if (target) {
|
|
2990
|
-
appliedMigrations = [await applySingleTarget(target)];
|
|
2991
|
-
} else {
|
|
2992
|
-
const localMigrations = parseStrictLocalMigrations(filenames);
|
|
2993
|
-
const pendingMigrations = localMigrations.filter(
|
|
2994
|
-
(migration) => !latestRemoteVersion || compareMigrationVersions(migration.version, latestRemoteVersion) > 0
|
|
2995
|
-
);
|
|
2996
|
-
if (pendingMigrations.length === 0) {
|
|
2997
|
-
if (json) {
|
|
2998
|
-
outputJson({ appliedMigrations: [] });
|
|
2999
|
-
} else {
|
|
3000
|
-
outputSuccess("No pending local migrations to apply.");
|
|
3001
|
-
}
|
|
3002
|
-
await reportCliUsage("cli.db.migrations.up", true);
|
|
3003
|
-
return;
|
|
3004
|
-
}
|
|
3005
|
-
let migrationsToApply = pendingMigrations;
|
|
3006
|
-
if (options.to) {
|
|
3007
|
-
const targetVersion = /^\d{14}$/u.test(options.to) ? options.to : resolveMigrationTarget(options.to, filenames).version;
|
|
3008
|
-
if (latestRemoteVersion && compareMigrationVersions(targetVersion, latestRemoteVersion) <= 0) {
|
|
3009
|
-
throw new CLIError(`Migration ${options.to} is already applied remotely.`);
|
|
3010
|
-
}
|
|
3011
|
-
migrationsToApply = pendingMigrations.filter(
|
|
3012
|
-
(migration) => compareMigrationVersions(migration.version, targetVersion) <= 0
|
|
3013
|
-
);
|
|
3014
|
-
if (migrationsToApply.length === 0 || migrationsToApply[migrationsToApply.length - 1]?.version !== targetVersion) {
|
|
3015
|
-
throw new CLIError(
|
|
3016
|
-
`Pending local migration not found for target ${options.to}.`
|
|
3017
|
-
);
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
for (const migration of migrationsToApply) {
|
|
3021
|
-
const filePath = join8(getMigrationsDir(), migration.filename);
|
|
3022
|
-
if (!existsSync4(filePath)) {
|
|
3023
|
-
throw new CLIError(`Local migration file not found: ${migration.filename}`);
|
|
3024
|
-
}
|
|
3025
|
-
const sql = readFileSync4(filePath, "utf-8");
|
|
3026
|
-
if (!sql.trim()) {
|
|
3027
|
-
throw new CLIError(`Migration file is empty: ${migration.filename}`);
|
|
3028
|
-
}
|
|
3029
|
-
appliedMigrations.push(await applyMigration(migration, sql));
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
if (json) {
|
|
3033
|
-
outputJson({ appliedMigrations });
|
|
3034
|
-
} else {
|
|
3035
|
-
outputSuccess(`Applied ${appliedMigrations.length} migration file(s).`);
|
|
3036
|
-
for (const migration of appliedMigrations) {
|
|
3037
|
-
console.log(`- ${buildMigrationFilename(migration.version, migration.name)}`);
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
await reportCliUsage("cli.db.migrations.up", true);
|
|
3041
|
-
} catch (err) {
|
|
3042
|
-
await reportCliUsage("cli.db.migrations.up", false);
|
|
3043
|
-
handleError(err, json);
|
|
3044
|
-
}
|
|
3045
|
-
});
|
|
3046
|
-
}
|
|
3047
|
-
|
|
3048
2674
|
// src/commands/records/list.ts
|
|
3049
2675
|
function registerRecordsCommands(recordsCmd2) {
|
|
3050
2676
|
recordsCmd2.command("list <table>").description("List records from a table").option("--select <columns>", "Columns to select (comma-separated)").option("--filter <filter>", 'Filter expression (e.g. "name=eq.John")').option("--order <order>", 'Order by (e.g. "created_at.desc")').option("--limit <n>", "Limit number of records", parseInt).option("--offset <n>", "Offset for pagination", parseInt).action(async (table, opts, cmd) => {
|
|
@@ -3228,21 +2854,21 @@ function registerFunctionsCommands(functionsCmd2) {
|
|
|
3228
2854
|
}
|
|
3229
2855
|
|
|
3230
2856
|
// src/commands/functions/deploy.ts
|
|
3231
|
-
import { readFileSync as
|
|
3232
|
-
import { join as
|
|
2857
|
+
import { readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
|
|
2858
|
+
import { join as join7 } from "path";
|
|
3233
2859
|
function registerFunctionsDeployCommand(functionsCmd2) {
|
|
3234
2860
|
functionsCmd2.command("deploy <slug>").description("Deploy an edge function (create or update)").option("--file <path>", "Path to the function source file").option("--name <name>", "Function display name").option("--description <desc>", "Function description").action(async (slug, opts, cmd) => {
|
|
3235
2861
|
const { json } = getRootOpts(cmd);
|
|
3236
2862
|
try {
|
|
3237
2863
|
await requireAuth();
|
|
3238
|
-
const filePath = opts.file ??
|
|
3239
|
-
if (!
|
|
2864
|
+
const filePath = opts.file ?? join7(process.cwd(), "insforge", "functions", slug, "index.ts");
|
|
2865
|
+
if (!existsSync3(filePath)) {
|
|
3240
2866
|
throw new CLIError(
|
|
3241
2867
|
`Source file not found: ${filePath}
|
|
3242
|
-
Specify --file <path> or create ${
|
|
2868
|
+
Specify --file <path> or create ${join7("insforge", "functions", slug, "index.ts")}`
|
|
3243
2869
|
);
|
|
3244
2870
|
}
|
|
3245
|
-
const code =
|
|
2871
|
+
const code = readFileSync4(filePath, "utf-8");
|
|
3246
2872
|
const name = opts.name ?? slug;
|
|
3247
2873
|
const description = opts.description ?? "";
|
|
3248
2874
|
let exists = false;
|
|
@@ -3429,7 +3055,7 @@ function registerStorageBucketsCommand(storageCmd2) {
|
|
|
3429
3055
|
}
|
|
3430
3056
|
|
|
3431
3057
|
// src/commands/storage/upload.ts
|
|
3432
|
-
import { readFileSync as
|
|
3058
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
|
|
3433
3059
|
import { basename as basename5 } from "path";
|
|
3434
3060
|
function registerStorageUploadCommand(storageCmd2) {
|
|
3435
3061
|
storageCmd2.command("upload <file>").description("Upload a file to a storage bucket").requiredOption("--bucket <name>", "Target bucket name").option("--key <objectKey>", "Object key (defaults to filename)").action(async (file, opts, cmd) => {
|
|
@@ -3438,10 +3064,10 @@ function registerStorageUploadCommand(storageCmd2) {
|
|
|
3438
3064
|
await requireAuth();
|
|
3439
3065
|
const config = getProjectConfig();
|
|
3440
3066
|
if (!config) throw new ProjectNotLinkedError();
|
|
3441
|
-
if (!
|
|
3067
|
+
if (!existsSync4(file)) {
|
|
3442
3068
|
throw new CLIError(`File not found: ${file}`);
|
|
3443
3069
|
}
|
|
3444
|
-
const fileContent =
|
|
3070
|
+
const fileContent = readFileSync5(file);
|
|
3445
3071
|
const objectKey = opts.key ?? basename5(file);
|
|
3446
3072
|
const bucketName = opts.bucket;
|
|
3447
3073
|
const formData = new FormData();
|
|
@@ -3472,8 +3098,8 @@ function registerStorageUploadCommand(storageCmd2) {
|
|
|
3472
3098
|
}
|
|
3473
3099
|
|
|
3474
3100
|
// src/commands/storage/download.ts
|
|
3475
|
-
import { writeFileSync as
|
|
3476
|
-
import { join as
|
|
3101
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
3102
|
+
import { join as join8, basename as basename6 } from "path";
|
|
3477
3103
|
function registerStorageDownloadCommand(storageCmd2) {
|
|
3478
3104
|
storageCmd2.command("download <objectKey>").description("Download a file from a storage bucket").requiredOption("--bucket <name>", "Source bucket name").option("--output <path>", "Output file path (defaults to current directory)").action(async (objectKey, opts, cmd) => {
|
|
3479
3105
|
const { json } = getRootOpts(cmd);
|
|
@@ -3493,8 +3119,8 @@ function registerStorageDownloadCommand(storageCmd2) {
|
|
|
3493
3119
|
throw new CLIError(err.error ?? `Download failed: ${res.status}`);
|
|
3494
3120
|
}
|
|
3495
3121
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
3496
|
-
const outputPath = opts.output ??
|
|
3497
|
-
|
|
3122
|
+
const outputPath = opts.output ?? join8(process.cwd(), basename6(objectKey));
|
|
3123
|
+
writeFileSync3(outputPath, buffer);
|
|
3498
3124
|
if (json) {
|
|
3499
3125
|
outputJson({ success: true, path: outputPath, size: buffer.length });
|
|
3500
3126
|
} else {
|
|
@@ -4600,13 +4226,13 @@ function registerComputeLogsCommand(computeCmd2) {
|
|
|
4600
4226
|
}
|
|
4601
4227
|
|
|
4602
4228
|
// src/commands/compute/deploy.ts
|
|
4603
|
-
import { existsSync as
|
|
4604
|
-
import { join as
|
|
4229
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, renameSync } from "fs";
|
|
4230
|
+
import { join as join9 } from "path";
|
|
4605
4231
|
import { execSync, spawn } from "child_process";
|
|
4606
4232
|
function parseFlyToml(dir) {
|
|
4607
|
-
const tomlPath =
|
|
4608
|
-
if (!
|
|
4609
|
-
const content =
|
|
4233
|
+
const tomlPath = join9(dir, "fly.toml");
|
|
4234
|
+
if (!existsSync5(tomlPath)) return {};
|
|
4235
|
+
const content = readFileSync6(tomlPath, "utf-8");
|
|
4610
4236
|
const config = {};
|
|
4611
4237
|
const portMatch = content.match(/internal_port\s*=\s*(\d+)/);
|
|
4612
4238
|
if (portMatch) config.internalPort = Number(portMatch[1]);
|
|
@@ -4676,8 +4302,8 @@ function registerComputeDeployCommand(computeCmd2) {
|
|
|
4676
4302
|
checkFlyctl();
|
|
4677
4303
|
const flyToken = getFlyToken();
|
|
4678
4304
|
const dir = directory ?? process.cwd();
|
|
4679
|
-
const dockerfilePath =
|
|
4680
|
-
if (!
|
|
4305
|
+
const dockerfilePath = join9(dir, "Dockerfile");
|
|
4306
|
+
if (!existsSync5(dockerfilePath)) {
|
|
4681
4307
|
throw new CLIError(`No Dockerfile found in ${dir}`);
|
|
4682
4308
|
}
|
|
4683
4309
|
const flyTomlDefaults = parseFlyToml(dir);
|
|
@@ -4722,15 +4348,15 @@ function registerComputeDeployCommand(computeCmd2) {
|
|
|
4722
4348
|
serviceId = service.id;
|
|
4723
4349
|
flyAppId = service.flyAppId;
|
|
4724
4350
|
}
|
|
4725
|
-
const existingTomlPath =
|
|
4726
|
-
const backupTomlPath =
|
|
4351
|
+
const existingTomlPath = join9(dir, "fly.toml");
|
|
4352
|
+
const backupTomlPath = join9(dir, "fly.toml.insforge-backup");
|
|
4727
4353
|
let hadExistingToml = false;
|
|
4728
|
-
if (
|
|
4354
|
+
if (existsSync5(existingTomlPath)) {
|
|
4729
4355
|
hadExistingToml = true;
|
|
4730
4356
|
renameSync(existingTomlPath, backupTomlPath);
|
|
4731
4357
|
}
|
|
4732
4358
|
const tomlContent = generateFlyToml(flyAppId, { port, memory, cpu, region });
|
|
4733
|
-
|
|
4359
|
+
writeFileSync4(existingTomlPath, tomlContent);
|
|
4734
4360
|
try {
|
|
4735
4361
|
if (!json) outputInfo("Building and deploying (this may take a few minutes)...");
|
|
4736
4362
|
await new Promise((resolve4, reject) => {
|
|
@@ -5455,7 +5081,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
5455
5081
|
const s = !json ? clack10.spinner() : null;
|
|
5456
5082
|
s?.start("Collecting diagnostic data...");
|
|
5457
5083
|
const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
|
|
5458
|
-
const cliVersion = "0.1.
|
|
5084
|
+
const cliVersion = "0.1.54";
|
|
5459
5085
|
s?.stop("Data collected");
|
|
5460
5086
|
if (!json) {
|
|
5461
5087
|
console.log(`
|
|
@@ -5684,7 +5310,7 @@ function formatBytesCompact(bytes) {
|
|
|
5684
5310
|
|
|
5685
5311
|
// src/index.ts
|
|
5686
5312
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5687
|
-
var pkg = JSON.parse(
|
|
5313
|
+
var pkg = JSON.parse(readFileSync7(join10(__dirname, "../package.json"), "utf-8"));
|
|
5688
5314
|
var INSFORGE_LOGO = `
|
|
5689
5315
|
\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
|
|
5690
5316
|
\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
|
|
@@ -5718,7 +5344,6 @@ registerDbTriggersCommand(dbCmd);
|
|
|
5718
5344
|
registerDbRpcCommand(dbCmd);
|
|
5719
5345
|
registerDbExportCommand(dbCmd);
|
|
5720
5346
|
registerDbImportCommand(dbCmd);
|
|
5721
|
-
registerDbMigrationsCommand(dbCmd);
|
|
5722
5347
|
var recordsCmd = program.command("records", { hidden: true }).description("CRUD operations on table records");
|
|
5723
5348
|
registerRecordsCommands(recordsCmd);
|
|
5724
5349
|
registerRecordsCreateCommand(recordsCmd);
|