@ijfw/install 1.2.9 → 1.3.0
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/README.md +5 -3
- package/dist/ijfw.js +28 -28
- package/dist/install.js +1916 -85
- package/dist/uninstall.js +36 -11
- package/package.json +1 -1
- package/src/install.ps1 +51 -22
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @ijfw/install
|
|
2
2
|
|
|
3
3
|
One-command installer for [IJFW](https://gitlab.com/therealseandonahoe/ijfw) -- the AI
|
|
4
|
-
efficiency layer for Claude Code, Codex, Gemini, Cursor, Windsurf, Copilot.
|
|
4
|
+
efficiency layer for 14 AI coding agents: Claude Code, Codex, Gemini, Cursor, Windsurf, Copilot, Hermes, Wayland, OpenCode, Qwen Code, Cline, Kimi Code, OpenClaw, and Aider.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
@@ -39,8 +39,10 @@ Memory is preserved across re-runs by default.
|
|
|
39
39
|
|
|
40
40
|
## Preflight
|
|
41
41
|
|
|
42
|
-
Requires `node >=18
|
|
43
|
-
installer
|
|
42
|
+
Requires `node >=18` and `git` (used for the initial repo clone). The
|
|
43
|
+
installer is Node-native end to end -- no bash, no WSL, no Git for Windows
|
|
44
|
+
shell. On native Windows use the PowerShell installer (PS 5.1+), which
|
|
45
|
+
delegates to Node directly:
|
|
44
46
|
|
|
45
47
|
```powershell
|
|
46
48
|
iwr https://gitlab.com/therealseandonahoe/ijfw/-/raw/main/installer/src/install.ps1 -OutFile install.ps1
|
package/dist/ijfw.js
CHANGED
|
@@ -483,7 +483,7 @@ async function run5(ctx) {
|
|
|
483
483
|
const res = spawnSync5(
|
|
484
484
|
"npx",
|
|
485
485
|
["--yes", `publint@${ver}`, "--strict"],
|
|
486
|
-
{ encoding: "utf8", cwd: ctx.repoRoot + "/installer", timeout:
|
|
486
|
+
{ encoding: "utf8", cwd: ctx.repoRoot + "/installer", timeout: 9e4 }
|
|
487
487
|
);
|
|
488
488
|
const durationMs = Date.now() - t0;
|
|
489
489
|
const output = (res.stdout || "") + (res.stderr || "");
|
|
@@ -727,7 +727,7 @@ __export(pack_smoke_exports, {
|
|
|
727
727
|
severity: () => severity10
|
|
728
728
|
});
|
|
729
729
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
730
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, mkdirSync, writeFileSync as writeFileSync2, readdirSync as readdirSync3 } from "node:fs";
|
|
730
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, mkdirSync, writeFileSync as writeFileSync2, readdirSync as readdirSync3, existsSync } from "node:fs";
|
|
731
731
|
import { join as join6, resolve } from "node:path";
|
|
732
732
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
733
733
|
async function run10(ctx) {
|
|
@@ -803,13 +803,9 @@ async function run10(ctx) {
|
|
|
803
803
|
];
|
|
804
804
|
let binPath = null;
|
|
805
805
|
for (const c2 of binCandidates) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
binPath = c2;
|
|
810
|
-
break;
|
|
811
|
-
}
|
|
812
|
-
} catch {
|
|
806
|
+
if (existsSync(c2)) {
|
|
807
|
+
binPath = c2;
|
|
808
|
+
break;
|
|
813
809
|
}
|
|
814
810
|
}
|
|
815
811
|
if (!binPath) {
|
|
@@ -883,7 +879,7 @@ __export(upgrade_smoke_exports, {
|
|
|
883
879
|
severity: () => severity11
|
|
884
880
|
});
|
|
885
881
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
886
|
-
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync, existsSync } from "node:fs";
|
|
882
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync, existsSync as existsSync2 } from "node:fs";
|
|
887
883
|
import { join as join7, resolve as resolve2 } from "node:path";
|
|
888
884
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
889
885
|
async function run11(ctx) {
|
|
@@ -952,8 +948,7 @@ async function run11(ctx) {
|
|
|
952
948
|
];
|
|
953
949
|
let installerBin = null;
|
|
954
950
|
for (const c2 of binCandidates) {
|
|
955
|
-
|
|
956
|
-
if (check.status === 0) {
|
|
951
|
+
if (existsSync2(c2)) {
|
|
957
952
|
installerBin = c2;
|
|
958
953
|
break;
|
|
959
954
|
}
|
|
@@ -968,7 +963,7 @@ async function run11(ctx) {
|
|
|
968
963
|
};
|
|
969
964
|
}
|
|
970
965
|
const settingsPath = join7(claudeDir, "settings.json");
|
|
971
|
-
if (
|
|
966
|
+
if (existsSync2(settingsPath)) {
|
|
972
967
|
let settings;
|
|
973
968
|
try {
|
|
974
969
|
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
@@ -993,7 +988,7 @@ async function run11(ctx) {
|
|
|
993
988
|
}
|
|
994
989
|
}
|
|
995
990
|
const marketplaceSrc = join7(installerDir, "src", "marketplace.js");
|
|
996
|
-
if (
|
|
991
|
+
if (existsSync2(marketplaceSrc)) {
|
|
997
992
|
const src = readFileSync(marketplaceSrc, "utf8");
|
|
998
993
|
const registersCorrectKey = src.includes("'ijfw@ijfw'") || src.includes('"ijfw@ijfw"');
|
|
999
994
|
const registersWrongKey = /enabledPlugins\[['"]ijfw-core@ijfw['"]\]\s*=\s*true/.test(src);
|
|
@@ -1049,7 +1044,7 @@ var preflight_exports = {};
|
|
|
1049
1044
|
__export(preflight_exports, {
|
|
1050
1045
|
runPreflightCommand: () => runPreflightCommand
|
|
1051
1046
|
});
|
|
1052
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
1047
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "node:fs";
|
|
1053
1048
|
import { join as join8, dirname } from "node:path";
|
|
1054
1049
|
import { fileURLToPath } from "node:url";
|
|
1055
1050
|
function printHelp() {
|
|
@@ -1091,7 +1086,7 @@ function loadVersions(repoRoot2) {
|
|
|
1091
1086
|
join8(repoRoot2, ".ijfw", "preflight-versions.json")
|
|
1092
1087
|
];
|
|
1093
1088
|
for (const f of candidates) {
|
|
1094
|
-
if (
|
|
1089
|
+
if (existsSync3(f)) {
|
|
1095
1090
|
try {
|
|
1096
1091
|
return JSON.parse(readFileSync2(f, "utf8"));
|
|
1097
1092
|
} catch {
|
|
@@ -2419,14 +2414,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
2419
2414
|
// src/ijfw.js
|
|
2420
2415
|
import { dirname as dirname2, join as join9, resolve as resolve3, basename } from "node:path";
|
|
2421
2416
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2422
|
-
import { existsSync as
|
|
2417
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, copyFileSync, readdirSync as readdirSync4, rmSync as rmSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2423
2418
|
import { homedir, platform as platform2 } from "node:os";
|
|
2424
2419
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
2425
2420
|
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
2426
2421
|
function repoRoot() {
|
|
2427
2422
|
let dir = __dirname2;
|
|
2428
2423
|
for (let i = 0; i < 6; i++) {
|
|
2429
|
-
if (
|
|
2424
|
+
if (existsSync4(join9(dir, "package.json")) && existsSync4(join9(dir, ".git"))) return dir;
|
|
2430
2425
|
dir = resolve3(dir, "..");
|
|
2431
2426
|
}
|
|
2432
2427
|
return process.cwd();
|
|
@@ -2442,7 +2437,7 @@ COMMANDS
|
|
|
2442
2437
|
install Install IJFW into your AI coding agents
|
|
2443
2438
|
uninstall Remove IJFW from your AI coding agents
|
|
2444
2439
|
help Open the full IJFW guide (terminal, or --browser for rendered)
|
|
2445
|
-
preflight Run
|
|
2440
|
+
preflight Run 12-gate quality pipeline before publishing
|
|
2446
2441
|
dashboard Start / stop / check the local observability dashboard
|
|
2447
2442
|
design Manage the visual design companion
|
|
2448
2443
|
doctor Diagnose IJFW installation health
|
|
@@ -2453,19 +2448,21 @@ COMMANDS
|
|
|
2453
2448
|
}
|
|
2454
2449
|
function doctorCheck(cmd, args) {
|
|
2455
2450
|
const r = spawnSync12(cmd, args, { encoding: "utf8" });
|
|
2456
|
-
|
|
2451
|
+
if (r.status === 0) return r.stdout.split("\n")[0].trim();
|
|
2452
|
+
if (r.status === 127 || r.error && r.error.code === "ENOENT") return "not found";
|
|
2453
|
+
return `exit ${r.status} (may be transient)`;
|
|
2457
2454
|
}
|
|
2458
2455
|
function findCli() {
|
|
2459
2456
|
const candidates = [
|
|
2460
2457
|
join9(repoRoot(), "mcp-server", "src", "cross-orchestrator-cli.js"),
|
|
2461
2458
|
join9(homedir(), ".ijfw", "mcp-server", "src", "cross-orchestrator-cli.js")
|
|
2462
2459
|
];
|
|
2463
|
-
return candidates.find((p) =>
|
|
2460
|
+
return candidates.find((p) => existsSync4(p)) || null;
|
|
2464
2461
|
}
|
|
2465
2462
|
function delegateToCli(argTail) {
|
|
2466
2463
|
const cli = findCli();
|
|
2467
2464
|
if (!cli) return false;
|
|
2468
|
-
const r = spawnSync12(
|
|
2465
|
+
const r = spawnSync12(process.execPath, [cli, ...argTail], { stdio: "inherit" });
|
|
2469
2466
|
process.exit(r.status ?? 1);
|
|
2470
2467
|
}
|
|
2471
2468
|
async function main() {
|
|
@@ -2519,7 +2516,7 @@ async function main() {
|
|
|
2519
2516
|
const ijfwHome = join9(homedir(), ".ijfw");
|
|
2520
2517
|
const findInTree = (...rel) => {
|
|
2521
2518
|
const candidates = [join9(root, ...rel), join9(ijfwHome, ...rel)];
|
|
2522
|
-
return candidates.find((p) =>
|
|
2519
|
+
return candidates.find((p) => existsSync4(p)) || null;
|
|
2523
2520
|
};
|
|
2524
2521
|
if (dashSub === "start" || dashSub === "stop" || dashSub === "status") {
|
|
2525
2522
|
const dashBin = findInTree("mcp-server", "bin", "ijfw-dashboard");
|
|
@@ -2530,7 +2527,7 @@ async function main() {
|
|
|
2530
2527
|
const serverJs = findInTree("mcp-server", "src", "dashboard-server.js");
|
|
2531
2528
|
if (dashSub === "start" && serverJs) {
|
|
2532
2529
|
const { spawn } = await import("node:child_process");
|
|
2533
|
-
const child = spawn(process.execPath, [serverJs, "--daemon"], {
|
|
2530
|
+
const child = spawn(process.execPath, [serverJs, "start", "--daemon"], {
|
|
2534
2531
|
detached: true,
|
|
2535
2532
|
stdio: "ignore"
|
|
2536
2533
|
});
|
|
@@ -2567,7 +2564,7 @@ async function main() {
|
|
|
2567
2564
|
process.exit(1);
|
|
2568
2565
|
}
|
|
2569
2566
|
const abs = resolve3(filePath);
|
|
2570
|
-
if (!
|
|
2567
|
+
if (!existsSync4(abs)) {
|
|
2571
2568
|
console.error(`File not found: ${abs}`);
|
|
2572
2569
|
process.exit(1);
|
|
2573
2570
|
}
|
|
@@ -2593,7 +2590,7 @@ async function main() {
|
|
|
2593
2590
|
resolve3(__dirname2, "..", "docs", "GUIDE.md"),
|
|
2594
2591
|
join9(homedir(), ".ijfw", "docs", "GUIDE.md")
|
|
2595
2592
|
];
|
|
2596
|
-
const guidePath = candidates.find((p) =>
|
|
2593
|
+
const guidePath = candidates.find((p) => existsSync4(p));
|
|
2597
2594
|
if (!guidePath) {
|
|
2598
2595
|
console.error("[ijfw] Guide not found. Run `ijfw install` to fetch the full guide, or visit https://gitlab.com/therealseandonahoe/ijfw/-/blob/main/docs/GUIDE.md");
|
|
2599
2596
|
process.exit(1);
|
|
@@ -2603,7 +2600,7 @@ async function main() {
|
|
|
2603
2600
|
const assetsSrc = join9(dirname2(guidePath), "guide", "assets");
|
|
2604
2601
|
const outDir = join9(homedir(), ".ijfw", "guide");
|
|
2605
2602
|
mkdirSync3(join9(outDir, "assets"), { recursive: true });
|
|
2606
|
-
if (
|
|
2603
|
+
if (existsSync4(assetsSrc)) {
|
|
2607
2604
|
for (const f of readdirSync4(assetsSrc)) {
|
|
2608
2605
|
copyFileSync(join9(assetsSrc, f), join9(outDir, "assets", f));
|
|
2609
2606
|
}
|
|
@@ -2635,7 +2632,10 @@ async function main() {
|
|
|
2635
2632
|
}
|
|
2636
2633
|
const hasLess = spawnSync12("less", ["-V"], { stdio: "ignore" }).status === 0;
|
|
2637
2634
|
if (hasLess) {
|
|
2638
|
-
spawnSync12("less", ["-R", guidePath], { stdio: "inherit" });
|
|
2635
|
+
const lessRes = spawnSync12("less", ["-R", guidePath], { stdio: "inherit" });
|
|
2636
|
+
if (lessRes.status !== 0 && lessRes.status !== null) {
|
|
2637
|
+
process.stdout.write(readFileSync3(guidePath, "utf8"));
|
|
2638
|
+
}
|
|
2639
2639
|
} else {
|
|
2640
2640
|
process.stdout.write(readFileSync3(guidePath, "utf8"));
|
|
2641
2641
|
}
|