@ijfw/install 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/ijfw.js +1124 -105
- package/dist/install.js +66 -11
- package/package.json +1 -1
package/dist/install.js
CHANGED
|
@@ -19,11 +19,15 @@ import {
|
|
|
19
19
|
chmodSync,
|
|
20
20
|
mkdirSync as mkdirSync2,
|
|
21
21
|
realpathSync,
|
|
22
|
-
statSync
|
|
22
|
+
statSync,
|
|
23
|
+
lstatSync,
|
|
24
|
+
openSync,
|
|
25
|
+
closeSync,
|
|
26
|
+
constants as fsConstants
|
|
23
27
|
} from "node:fs";
|
|
24
|
-
import { dirname as dirname3, basename, join as join3, normalize, delimiter } from "node:path";
|
|
28
|
+
import { dirname as dirname3, basename, join as join3, normalize, delimiter, resolve as resolve3, sep } from "node:path";
|
|
25
29
|
import { homedir as homedir2 } from "node:os";
|
|
26
|
-
import { createHash } from "node:crypto";
|
|
30
|
+
import { createHash, randomBytes as randomBytes2 } from "node:crypto";
|
|
27
31
|
function printOk(msg) {
|
|
28
32
|
process.stdout.write(` [ok] ${msg}
|
|
29
33
|
`);
|
|
@@ -60,7 +64,7 @@ function nativePath(p) {
|
|
|
60
64
|
function writeAtomic(path3, contents, opts = {}) {
|
|
61
65
|
const mode = opts.mode ?? 384;
|
|
62
66
|
mkdirSync2(dirname3(path3), { recursive: true });
|
|
63
|
-
const tmp = `${path3}.tmp.${process.pid}`;
|
|
67
|
+
const tmp = `${path3}.tmp.${process.pid}.${randomBytes2(4).toString("hex")}`;
|
|
64
68
|
writeFileSync2(tmp, contents, { mode });
|
|
65
69
|
renameSync2(tmp, path3);
|
|
66
70
|
try {
|
|
@@ -498,10 +502,47 @@ function clineMerge(serverJs, home, ts) {
|
|
|
498
502
|
writeAtomic(dst, JSON.stringify(doc, null, 2), { mode: 384 });
|
|
499
503
|
return dst;
|
|
500
504
|
}
|
|
501
|
-
|
|
505
|
+
function mergeYamlHook(dst, scriptPath, ts) {
|
|
506
|
+
mkdirSync2(dirname3(dst), { recursive: true });
|
|
507
|
+
if (ts) backup(dst, ts);
|
|
508
|
+
let text = "";
|
|
509
|
+
try {
|
|
510
|
+
text = existsSync3(dst) ? readFileSync2(dst, "utf8") : "";
|
|
511
|
+
} catch {
|
|
512
|
+
text = "";
|
|
513
|
+
}
|
|
514
|
+
const BEGIN = "# IJFW-HOOK-BEGIN pre_tool_use";
|
|
515
|
+
const END = "# IJFW-HOOK-END pre_tool_use";
|
|
516
|
+
text = stripSentinelBlock(text, BEGIN, END);
|
|
517
|
+
if (text && !text.endsWith("\n")) text += "\n";
|
|
518
|
+
const escaped = String(scriptPath).replace(/"/g, '\\"');
|
|
519
|
+
let block = `${BEGIN}
|
|
520
|
+
`;
|
|
521
|
+
block += "hooks:\n";
|
|
522
|
+
block += " pre_tool_use:\n";
|
|
523
|
+
block += ` - script: "${escaped}"
|
|
524
|
+
`;
|
|
525
|
+
block += " interpreter: python3\n";
|
|
526
|
+
block += `${END}
|
|
527
|
+
`;
|
|
528
|
+
writeAtomic(dst, text + block, { mode: 384 });
|
|
529
|
+
}
|
|
530
|
+
var IS_WIN, EXTENSION_PLATFORM_SKILL_DIRS;
|
|
502
531
|
var init_install_helpers = __esm({
|
|
503
532
|
"src/install-helpers.js"() {
|
|
504
533
|
IS_WIN = process.platform === "win32";
|
|
534
|
+
EXTENSION_PLATFORM_SKILL_DIRS = Object.freeze([
|
|
535
|
+
{ id: "claude", rel: "claude/skills" },
|
|
536
|
+
{ id: "codex", rel: "codex/skills" },
|
|
537
|
+
{ id: "gemini", rel: "gemini/extensions/ijfw/skills" },
|
|
538
|
+
{ id: "cursor", rel: "cursor/skills" },
|
|
539
|
+
{ id: "windsurf", rel: "windsurf/skills" },
|
|
540
|
+
{ id: "copilot", rel: "copilot/skills" },
|
|
541
|
+
{ id: "hermes", rel: "hermes/skills" },
|
|
542
|
+
{ id: "wayland", rel: "wayland/skills" },
|
|
543
|
+
{ id: "shared", rel: "shared/skills" },
|
|
544
|
+
{ id: "universal", rel: "universal/skills" }
|
|
545
|
+
]);
|
|
505
546
|
}
|
|
506
547
|
});
|
|
507
548
|
|
|
@@ -756,6 +797,12 @@ async function installCodex(ctx) {
|
|
|
756
797
|
for (const f of listFiles(hookScriptsDir, ".sh")) {
|
|
757
798
|
installHook(f.path, join4(hooksBase, f.name), ctx.ts);
|
|
758
799
|
}
|
|
800
|
+
const codexScriptsSrc = join4(ctx.repoRoot, "codex", ".codex", "scripts");
|
|
801
|
+
const codexScriptsDst = join4(hooksBase, "scripts");
|
|
802
|
+
ensureDir(codexScriptsDst);
|
|
803
|
+
for (const f of listFiles(codexScriptsSrc, ".sh")) {
|
|
804
|
+
installHook(f.path, join4(codexScriptsDst, f.name), ctx.ts);
|
|
805
|
+
}
|
|
759
806
|
const codexCtx = join4(ctx.home, ".codex", "IJFW.md");
|
|
760
807
|
copyIfAbsent(join4(ctx.repoRoot, "codex", ".codex", "IJFW.md"), codexCtx);
|
|
761
808
|
const userSkills = join4(ctx.home, ".codex", "skills");
|
|
@@ -836,6 +883,12 @@ async function installGemini(ctx) {
|
|
|
836
883
|
for (const f of listFiles(hookScriptsDir, ".sh")) {
|
|
837
884
|
installHook(f.path, join4(extDst, "hooks", f.name), ctx.ts);
|
|
838
885
|
}
|
|
886
|
+
const geminiHookScriptsSrc = join4(extSrc, "hooks", "scripts");
|
|
887
|
+
const geminiHookScriptsDst = join4(extDst, "hooks", "scripts");
|
|
888
|
+
ensureDir(geminiHookScriptsDst);
|
|
889
|
+
for (const f of listFiles(geminiHookScriptsSrc, ".sh")) {
|
|
890
|
+
installHook(f.path, join4(geminiHookScriptsDst, f.name), ctx.ts);
|
|
891
|
+
}
|
|
839
892
|
const skillsSrc = join4(extSrc, "skills");
|
|
840
893
|
for (const sd of listSubdirs(skillsSrc)) {
|
|
841
894
|
copyDirIfAbsent(sd.path, join4(extDst, "skills", sd.name));
|
|
@@ -898,7 +951,8 @@ async function installWayland(ctx) {
|
|
|
898
951
|
}
|
|
899
952
|
}
|
|
900
953
|
}
|
|
901
|
-
|
|
954
|
+
mergeYamlHook(dst, "plugins/ijfw/hooks/pre_tool_use_extension_check.py", ctx.ts);
|
|
955
|
+
ctx.log.ok("Installed Wayland bundle: MCP + WAYLAND.md + skills + plugin + tier-2 hook");
|
|
902
956
|
return { status: "ok" };
|
|
903
957
|
}
|
|
904
958
|
async function installHermes(ctx) {
|
|
@@ -949,7 +1003,8 @@ async function installHermes(ctx) {
|
|
|
949
1003
|
}
|
|
950
1004
|
}
|
|
951
1005
|
mergeYamlPluginsEnabled(dst, "ijfw");
|
|
952
|
-
|
|
1006
|
+
mergeYamlHook(dst, "plugins/ijfw/hooks/pre_tool_use_extension_check.py", ctx.ts);
|
|
1007
|
+
ctx.log.ok("Installed Hermes bundle: MCP + HERMES.md + skills + plugin + tier-2 hook");
|
|
953
1008
|
return { status: "ok" };
|
|
954
1009
|
}
|
|
955
1010
|
async function installCursor(ctx) {
|
|
@@ -1781,7 +1836,7 @@ var init_install_flow = __esm({
|
|
|
1781
1836
|
// src/install.js
|
|
1782
1837
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
1783
1838
|
import { existsSync as existsSync5, rmSync, mkdirSync as mkdirSync4, realpathSync as realpathSync2, renameSync as renameSync3 } from "node:fs";
|
|
1784
|
-
import { resolve as
|
|
1839
|
+
import { resolve as resolve4, join as join5, dirname as dirname5 } from "node:path";
|
|
1785
1840
|
import { homedir as homedir3, platform as platform2 } from "node:os";
|
|
1786
1841
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1787
1842
|
|
|
@@ -2042,8 +2097,8 @@ function findBash() {
|
|
|
2042
2097
|
return null;
|
|
2043
2098
|
}
|
|
2044
2099
|
function resolveTarget(opt) {
|
|
2045
|
-
if (opt.dir) return
|
|
2046
|
-
if (process.env.IJFW_HOME) return
|
|
2100
|
+
if (opt.dir) return resolve4(opt.dir);
|
|
2101
|
+
if (process.env.IJFW_HOME) return resolve4(process.env.IJFW_HOME);
|
|
2047
2102
|
return join5(homedir3(), ".ijfw");
|
|
2048
2103
|
}
|
|
2049
2104
|
function runCheck(cmd, args, opts) {
|
|
@@ -2107,7 +2162,7 @@ function cloneOrPull(dir, branch) {
|
|
|
2107
2162
|
}
|
|
2108
2163
|
async function runInstallScript(dir) {
|
|
2109
2164
|
const canonicalDir = join5(homedir3(), ".ijfw");
|
|
2110
|
-
const isCustomDir =
|
|
2165
|
+
const isCustomDir = resolve4(dir) !== canonicalDir;
|
|
2111
2166
|
const { runInstall: runInstall2 } = await Promise.resolve().then(() => (init_install_flow(), install_flow_exports));
|
|
2112
2167
|
await runInstall2({
|
|
2113
2168
|
targets: void 0,
|