@ijfw/install 1.4.0 → 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/install.js +41 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,36 @@ iwr https://gitlab.com/therealseandonahoe/ijfw/-/raw/main/installer/src/install.
|
|
|
49
49
|
.\install.ps1 -Dir $env:USERPROFILE\.ijfw
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Extension CLI
|
|
53
|
+
|
|
54
|
+
IJFW ships a full extension system for installing and sandboxing third-party skills.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Publisher key management
|
|
58
|
+
ijfw extension keygen <author> # Generate an Ed25519 publisher keypair
|
|
59
|
+
ijfw extension trust <keyId> <publicKey> # Add a publisher to your trusted store
|
|
60
|
+
ijfw extension trust-registry [<url>] # Pull + apply the hosted publisher registry
|
|
61
|
+
ijfw extension untrust <keyId> # Remove a publisher from your trusted store
|
|
62
|
+
ijfw extension trusted # List all trusted publishers
|
|
63
|
+
|
|
64
|
+
# Extension lifecycle
|
|
65
|
+
ijfw extension add <source> [flags] # Install an extension (npm name, local path, or https git URL)
|
|
66
|
+
--allow-unsigned # Accept extensions with no signature
|
|
67
|
+
--accept-untrusted # Accept extensions signed by an untrusted publisher (prompts on TTY)
|
|
68
|
+
--activate # Auto-activate after install
|
|
69
|
+
ijfw extension activate <name> # Activate an installed extension (enforces declared permissions)
|
|
70
|
+
ijfw extension deactivate # Deactivate the current extension
|
|
71
|
+
|
|
72
|
+
# Admin / registry maintainer (rare)
|
|
73
|
+
ijfw extension rotate-keys <oldKeyId> <newKeyId> # Produce a signed rotation token
|
|
74
|
+
ijfw extension keygen-meta <author> # Generate the registry meta-keypair
|
|
75
|
+
ijfw extension sign-registry <path> # Sign a registry JSON file in place
|
|
76
|
+
ijfw extension verify-registry <path> # Verify a registry JSON signature
|
|
77
|
+
ijfw extension registry-status # Show registry cache age + signature status
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The rotation flow and registry maintainer docs live in `docs/REGISTRY-MAINTAINER.md`.
|
|
81
|
+
|
|
52
82
|
## Build (contributors)
|
|
53
83
|
|
|
54
84
|
```bash
|
package/dist/install.js
CHANGED
|
@@ -502,6 +502,31 @@ function clineMerge(serverJs, home, ts) {
|
|
|
502
502
|
writeAtomic(dst, JSON.stringify(doc, null, 2), { mode: 384 });
|
|
503
503
|
return dst;
|
|
504
504
|
}
|
|
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
|
+
}
|
|
505
530
|
var IS_WIN, EXTENSION_PLATFORM_SKILL_DIRS;
|
|
506
531
|
var init_install_helpers = __esm({
|
|
507
532
|
"src/install-helpers.js"() {
|
|
@@ -772,6 +797,12 @@ async function installCodex(ctx) {
|
|
|
772
797
|
for (const f of listFiles(hookScriptsDir, ".sh")) {
|
|
773
798
|
installHook(f.path, join4(hooksBase, f.name), ctx.ts);
|
|
774
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
|
+
}
|
|
775
806
|
const codexCtx = join4(ctx.home, ".codex", "IJFW.md");
|
|
776
807
|
copyIfAbsent(join4(ctx.repoRoot, "codex", ".codex", "IJFW.md"), codexCtx);
|
|
777
808
|
const userSkills = join4(ctx.home, ".codex", "skills");
|
|
@@ -852,6 +883,12 @@ async function installGemini(ctx) {
|
|
|
852
883
|
for (const f of listFiles(hookScriptsDir, ".sh")) {
|
|
853
884
|
installHook(f.path, join4(extDst, "hooks", f.name), ctx.ts);
|
|
854
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
|
+
}
|
|
855
892
|
const skillsSrc = join4(extSrc, "skills");
|
|
856
893
|
for (const sd of listSubdirs(skillsSrc)) {
|
|
857
894
|
copyDirIfAbsent(sd.path, join4(extDst, "skills", sd.name));
|
|
@@ -914,7 +951,8 @@ async function installWayland(ctx) {
|
|
|
914
951
|
}
|
|
915
952
|
}
|
|
916
953
|
}
|
|
917
|
-
|
|
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");
|
|
918
956
|
return { status: "ok" };
|
|
919
957
|
}
|
|
920
958
|
async function installHermes(ctx) {
|
|
@@ -965,7 +1003,8 @@ async function installHermes(ctx) {
|
|
|
965
1003
|
}
|
|
966
1004
|
}
|
|
967
1005
|
mergeYamlPluginsEnabled(dst, "ijfw");
|
|
968
|
-
|
|
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");
|
|
969
1008
|
return { status: "ok" };
|
|
970
1009
|
}
|
|
971
1010
|
async function installCursor(ctx) {
|