@ijfw/install 1.5.3 → 1.5.5
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/CHANGELOG.md +21 -0
- package/README.md +33 -65
- package/dist/hub-index-snippet.json +49 -0
- package/dist/ijfw.js +103 -23
- package/dist/install.js +201 -33
- package/docs/GUIDE.md +2 -2
- package/docs/guide/assets/ferrox-hero.png +0 -0
- package/package.json +16 -5
- package/scripts/hub-extension/aion-extension.json.tmpl +156 -0
- package/scripts/hub-extension/assets/ijfw-logo.svg +4 -0
- package/scripts/hub-extension/install.js.tmpl +46 -0
- package/scripts/hub-extension/uninstall.js.tmpl +42 -0
- package/scripts/pack-hub-extension.js +561 -0
- package/src/install.ps1 +30 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.4] -- 2026-05-26
|
|
4
|
+
|
|
5
|
+
**Wayland Hub Extension pack pipeline.** Adds `pack-hub-extension` -- a new CLI subcommand that produces the three distributable artifacts Wayland's prebuild sync script needs to bundle IJFW as a native Hub Extension without committing binaries to the Wayland repo.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `ijfw pack-hub-extension [--output <dir>]` produces three artifacts in one shot:
|
|
10
|
+
- `ijfw-<version>.zip` -- the installable Hub Extension bundle (manifest + lifecycle hooks + assets)
|
|
11
|
+
- `ijfw-<version>.sha512` -- SHA-512 SRI checksum for Wayland's integrity verifier
|
|
12
|
+
- `hub-index-snippet.json` -- drop-in entry for Wayland's Hub Index, ready to merge at build time
|
|
13
|
+
- `--output <dir>` flag lets callers stage artifacts anywhere (defaults to `dist/`); the flag is forwarded verbatim to `scripts/pack-hub-extension.js`.
|
|
14
|
+
- `scripts/pack-hub-extension.js` + `scripts/hub-extension/**` now ship inside the npm tarball, so Wayland's prebuild script can invoke the packer directly via `npx -y @ijfw/install@<version> pack-hub-extension --output <stage-dir>` with no local clone required.
|
|
15
|
+
- Hub Extension bundle includes `scripts/install.js` (runs `npx -y @ijfw/install@latest` non-interactively) and `scripts/uninstall.js` with split timeouts -- 100s for install, 30s for uninstall -- so Wayland's sandboxed fork never hangs the boot sequence.
|
|
16
|
+
- Manifest template (`aion-extension.json.tmpl`) declares all 15 `acpAdapters` so Wayland's existing verifier checks every supported CLI on PATH post-install. If any are missing, install fails with a clear error rather than silently succeeding.
|
|
17
|
+
- Wayland integration: their `scripts/sync-hub-extensions.ts` prebuild step invokes `pack-hub-extension` at every build so each Wayland release snapshots the latest published IJFW without storing binaries in the repo.
|
|
18
|
+
|
|
19
|
+
### Internal
|
|
20
|
+
|
|
21
|
+
- `@ijfw/memory-server@1.5.4` republishes alongside with no functional changes vs 1.5.3 -- preserves the version-lockstep invariant between the two packages.
|
|
22
|
+
- Test coverage: `installer/test/test-pack-hub-extension.js` verifies artifact production, SHA-512 stability across runs on identical content, and manifest shape conformance.
|
|
23
|
+
|
|
3
24
|
## [1.3.2] -- 2026-05-15
|
|
4
25
|
|
|
5
26
|
**Project-agnostic swarm orchestration + live visual workflow + richer Codex native surface.** Adds first-class Team Assembly, blackboard coordination, swarm task lifecycle, conservative git worktrees, recovery checkpoints, Superpowers-style live design previews, and Claude-parity Codex command aliases.
|
package/README.md
CHANGED
|
@@ -1,92 +1,60 @@
|
|
|
1
|
-
# @ijfw/install
|
|
1
|
+
# @ijfw/install — One-command installer for IJFW
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
> Ferrox Labs · Local-first infrastructure for AI coding agents
|
|
4
|
+
|
|
5
|
+
IJFW is Ferrox Labs' shared development infrastructure for AI-driven teams — shared memory across projects, smart model routing, cross-AI adversarial audits (Trident: Claude + Codex + Gemini in parallel), and a disciplined think-build-ship workflow. v1.5.5 closed 60 audit findings in a single milestone. This package wires it onto every AI coding agent on your machine.
|
|
6
|
+
|
|
7
|
+
Full docs: [github.com/FerroxLabs/ijfw](https://github.com/FerroxLabs/ijfw)
|
|
8
|
+
|
|
9
|
+
## Table of contents
|
|
10
|
+
|
|
11
|
+
- [Install](#install)
|
|
12
|
+
- [What it does](#what-it-does)
|
|
13
|
+
- [Options](#options)
|
|
14
|
+
- [Uninstall](#uninstall)
|
|
15
|
+
- [Links](#links)
|
|
5
16
|
|
|
6
17
|
## Install
|
|
7
18
|
|
|
8
19
|
```bash
|
|
9
20
|
npm install -g @ijfw/install
|
|
10
|
-
ijfw
|
|
21
|
+
ijfw install
|
|
11
22
|
```
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
If no AI agents are detected, install Claude Code or Codex first, then re-run.
|
|
25
|
+
|
|
26
|
+
## What it does
|
|
14
27
|
|
|
15
|
-
|
|
28
|
+
- Installs the IJFW source tree at `~/.ijfw/`
|
|
29
|
+
- Wires the MCP server into 14 platforms via their config files
|
|
30
|
+
- Adds Aider as a rules-only tier — 15 agents supported total
|
|
31
|
+
- Sets up shared memory at `~/.ijfw/memory/` (plain markdown hot, SQLite FTS5 warm, optional vectors cold)
|
|
32
|
+
- Runs an 8-gate preflight before declaring done
|
|
33
|
+
|
|
34
|
+
## Options
|
|
16
35
|
|
|
17
36
|
| Flag | Default | Notes |
|
|
18
37
|
|------|---------|-------|
|
|
19
38
|
| `--dir <path>` | `$IJFW_HOME` or `~/.ijfw` | Install location |
|
|
20
39
|
| `--branch <name>` | latest released tag | Git branch or tag |
|
|
21
|
-
| `--no-marketplace` |
|
|
22
|
-
| `--yes` |
|
|
40
|
+
| `--no-marketplace` | enabled | Skip settings.json edits |
|
|
41
|
+
| `--yes` | interactive | Non-interactive run |
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
## Uninstall
|
|
25
44
|
|
|
26
45
|
```bash
|
|
27
46
|
ijfw uninstall # preserves ~/.ijfw/memory/
|
|
28
47
|
ijfw uninstall --purge # removes memory too
|
|
29
48
|
```
|
|
30
49
|
|
|
31
|
-
If `ijfw`
|
|
32
|
-
package already), invoke the bin directly:
|
|
50
|
+
If `ijfw` is no longer on your PATH, invoke the bin directly:
|
|
33
51
|
|
|
34
52
|
```bash
|
|
35
53
|
npx -p @ijfw/install ijfw-uninstall
|
|
36
54
|
```
|
|
37
55
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## Preflight
|
|
41
|
-
|
|
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:
|
|
46
|
-
|
|
47
|
-
```powershell
|
|
48
|
-
iwr https://gitlab.com/therealseandonahoe/ijfw/-/raw/main/installer/src/install.ps1 -OutFile install.ps1
|
|
49
|
-
.\install.ps1 -Dir $env:USERPROFILE\.ijfw
|
|
50
|
-
```
|
|
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
|
-
|
|
82
|
-
## Build (contributors)
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
cd installer
|
|
86
|
-
npm install
|
|
87
|
-
npm run build # outputs dist/install.js + dist/uninstall.js
|
|
88
|
-
npm test
|
|
89
|
-
npm run pack:check
|
|
90
|
-
```
|
|
56
|
+
## Links
|
|
91
57
|
|
|
92
|
-
|
|
58
|
+
- Source, issues, and docs: [github.com/FerroxLabs/ijfw](https://github.com/FerroxLabs/ijfw)
|
|
59
|
+
- npm package: [@ijfw/install](https://www.npmjs.com/package/@ijfw/install)
|
|
60
|
+
- License: MIT
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ijfw",
|
|
3
|
+
"displayName": "IJFW — AI Efficiency Layer",
|
|
4
|
+
"version": "1.5.5",
|
|
5
|
+
"description": "One install, every AI coding agent, zero config. Unifies 15 CLIs under a shared MCP memory layer so context follows you across Claude, Codex, Gemini, Cursor, Windsurf, and 10 more.",
|
|
6
|
+
"author": "Sean Donahoe",
|
|
7
|
+
"icon": "assets/ijfw-logo.svg",
|
|
8
|
+
"dist": {
|
|
9
|
+
"tarball": "extensions/ijfw-1.5.5.zip",
|
|
10
|
+
"integrity": "sha512-vm3ot0+GhXYy0/HcStB/xmFjZhSXWG7jzSLuIPe43/Dla8qhyR9gsCwBI/8+RsUJqMXiPgc0GuxrgwW2f5DDWA==",
|
|
11
|
+
"unpackedSize": 3312
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"wayland": ">=0.6.0"
|
|
15
|
+
},
|
|
16
|
+
"hubs": [
|
|
17
|
+
"acpAdapters",
|
|
18
|
+
"mcpServers"
|
|
19
|
+
],
|
|
20
|
+
"contributes": {
|
|
21
|
+
"acpAdapters": [
|
|
22
|
+
"claude",
|
|
23
|
+
"codex",
|
|
24
|
+
"gemini",
|
|
25
|
+
"cursor",
|
|
26
|
+
"windsurf",
|
|
27
|
+
"copilot",
|
|
28
|
+
"hermes",
|
|
29
|
+
"wayland",
|
|
30
|
+
"aider",
|
|
31
|
+
"opencode",
|
|
32
|
+
"qwencode",
|
|
33
|
+
"cline",
|
|
34
|
+
"kimicode",
|
|
35
|
+
"openclaw",
|
|
36
|
+
"antigravity"
|
|
37
|
+
],
|
|
38
|
+
"mcpServers": [
|
|
39
|
+
"ijfw-memory"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"tags": [
|
|
43
|
+
"ai",
|
|
44
|
+
"coding",
|
|
45
|
+
"mcp",
|
|
46
|
+
"memory",
|
|
47
|
+
"multi-agent"
|
|
48
|
+
]
|
|
49
|
+
}
|
package/dist/ijfw.js
CHANGED
|
@@ -2110,7 +2110,7 @@ __export(upgrade_smoke_exports, {
|
|
|
2110
2110
|
severity: () => severity11
|
|
2111
2111
|
});
|
|
2112
2112
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
2113
|
-
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync4, existsSync as existsSync4 } from "node:fs";
|
|
2113
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync4, existsSync as existsSync4, cpSync } from "node:fs";
|
|
2114
2114
|
import { join as join10, resolve as resolve2 } from "node:path";
|
|
2115
2115
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
2116
2116
|
async function run11(ctx) {
|
|
@@ -2199,30 +2199,94 @@ async function run11(ctx) {
|
|
|
2199
2199
|
durationMs: Date.now() - t0
|
|
2200
2200
|
};
|
|
2201
2201
|
}
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
return {
|
|
2209
|
-
name: "upgrade-smoke",
|
|
2210
|
-
status: "FAIL",
|
|
2211
|
-
message: "upgrade-smoke: settings.json is not valid JSON",
|
|
2212
|
-
details: [e.message],
|
|
2213
|
-
durationMs: Date.now() - t0
|
|
2214
|
-
};
|
|
2202
|
+
const targetIjfwHome = join10(fakeHome, ".ijfw");
|
|
2203
|
+
mkdirSync4(targetIjfwHome, { recursive: true });
|
|
2204
|
+
for (const sub of ["claude", "mcp-server"]) {
|
|
2205
|
+
const src = join10(ctx.repoRoot, sub);
|
|
2206
|
+
if (existsSync4(src)) {
|
|
2207
|
+
cpSync(src, join10(targetIjfwHome, sub), { recursive: true });
|
|
2215
2208
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2209
|
+
}
|
|
2210
|
+
const installerPkgSrc = join10(ctx.repoRoot, "installer", "package.json");
|
|
2211
|
+
if (existsSync4(installerPkgSrc)) {
|
|
2212
|
+
mkdirSync4(join10(targetIjfwHome, "installer"), { recursive: true });
|
|
2213
|
+
cpSync(installerPkgSrc, join10(targetIjfwHome, "installer", "package.json"));
|
|
2214
|
+
}
|
|
2215
|
+
const runInstaller = spawnSync11(installerBin, ["--yes"], {
|
|
2216
|
+
encoding: "utf8",
|
|
2217
|
+
cwd: installDir,
|
|
2218
|
+
timeout: 12e4,
|
|
2219
|
+
env: {
|
|
2220
|
+
...cleanEnv,
|
|
2221
|
+
HOME: fakeHome,
|
|
2222
|
+
USERPROFILE: fakeHome,
|
|
2223
|
+
IJFW_HOME: targetIjfwHome,
|
|
2224
|
+
// Hermetic: install.js refuses any network attempt under this flag
|
|
2225
|
+
// (TR-001). The gate's contract is "the installer either completes
|
|
2226
|
+
// without network or fails clearly". The marketplace merge step
|
|
2227
|
+
// (which is what we actually want to verify) does NOT need network.
|
|
2228
|
+
CI: "1",
|
|
2229
|
+
IJFW_SKIP_NETWORK: "1"
|
|
2230
|
+
},
|
|
2231
|
+
shell: process.platform === "win32"
|
|
2232
|
+
});
|
|
2233
|
+
if (runInstaller.status !== 0 || runInstaller.signal) {
|
|
2234
|
+
const stderrLines = (runInstaller.stderr || "").split("\n").filter(Boolean);
|
|
2235
|
+
const lastStderrLine = stderrLines.length > 0 ? stderrLines[stderrLines.length - 1].slice(0, 200) : "(no stderr)";
|
|
2236
|
+
let cat;
|
|
2237
|
+
if (runInstaller.signal) {
|
|
2238
|
+
cat = `killed by ${runInstaller.signal}`;
|
|
2239
|
+
} else if (runInstaller.status === 137 || runInstaller.status === 124) {
|
|
2240
|
+
cat = `timed out (exit ${runInstaller.status})`;
|
|
2241
|
+
} else if (runInstaller.status === null) {
|
|
2242
|
+
cat = "timed out (status null)";
|
|
2243
|
+
} else {
|
|
2244
|
+
cat = `exited ${runInstaller.status}`;
|
|
2225
2245
|
}
|
|
2246
|
+
return {
|
|
2247
|
+
name: "upgrade-smoke",
|
|
2248
|
+
status: "FAIL",
|
|
2249
|
+
message: `upgrade-smoke: installer ${cat}. Last stderr line: ${lastStderrLine}`,
|
|
2250
|
+
details: ((runInstaller.stdout || "") + (runInstaller.stderr || "")).split("\n").filter(Boolean).slice(0, 15),
|
|
2251
|
+
durationMs: Date.now() - t0
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
const settingsPath = join10(claudeDir, "settings.json");
|
|
2255
|
+
if (!existsSync4(settingsPath)) {
|
|
2256
|
+
return {
|
|
2257
|
+
name: "upgrade-smoke",
|
|
2258
|
+
status: "FAIL",
|
|
2259
|
+
message: "upgrade-smoke: installer did not write ~/.claude/settings.json",
|
|
2260
|
+
details: [
|
|
2261
|
+
`expected: ${settingsPath}`,
|
|
2262
|
+
"The installer ran (exit 0) but the marketplace merge never produced settings.json.",
|
|
2263
|
+
"This is the false-pass shape TR-001 retired \u2014 the gate must observe the write.",
|
|
2264
|
+
...((runInstaller.stdout || "") + (runInstaller.stderr || "")).split("\n").filter(Boolean).slice(0, 8)
|
|
2265
|
+
],
|
|
2266
|
+
durationMs: Date.now() - t0
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
let settings;
|
|
2270
|
+
try {
|
|
2271
|
+
settings = JSON.parse(readFileSync4(settingsPath, "utf8"));
|
|
2272
|
+
} catch (e) {
|
|
2273
|
+
return {
|
|
2274
|
+
name: "upgrade-smoke",
|
|
2275
|
+
status: "FAIL",
|
|
2276
|
+
message: "upgrade-smoke: settings.json is not valid JSON",
|
|
2277
|
+
details: [e.message],
|
|
2278
|
+
durationMs: Date.now() - t0
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
const hasWrongKey = JSON.stringify(settings).includes("ijfw-core");
|
|
2282
|
+
if (hasWrongKey) {
|
|
2283
|
+
return {
|
|
2284
|
+
name: "upgrade-smoke",
|
|
2285
|
+
status: "FAIL",
|
|
2286
|
+
message: 'upgrade-smoke: settings.json still uses deprecated "ijfw-core" key',
|
|
2287
|
+
details: [`Found "ijfw-core" in: ${settingsPath}`],
|
|
2288
|
+
durationMs: Date.now() - t0
|
|
2289
|
+
};
|
|
2226
2290
|
}
|
|
2227
2291
|
const marketplaceSrc = join10(installerDir, "src", "marketplace.js");
|
|
2228
2292
|
if (existsSync4(marketplaceSrc)) {
|
|
@@ -3782,6 +3846,16 @@ var COMMAND_REGISTRY = Object.freeze([
|
|
|
3782
3846
|
helpGroup: "EXPLORE"
|
|
3783
3847
|
},
|
|
3784
3848
|
// ---------- TIER 2: COORDINATION (shown in `ijfw commands`) ----------
|
|
3849
|
+
{
|
|
3850
|
+
name: "pack-hub-extension",
|
|
3851
|
+
tier: "coordination",
|
|
3852
|
+
owner: "installer-direct",
|
|
3853
|
+
description: "Pack the Wayland Hub Extension (zip + SHA-512 + manifest snippet). Used by Wayland's prebuild sync.",
|
|
3854
|
+
aliases: [],
|
|
3855
|
+
since: "1.5.4",
|
|
3856
|
+
status: "active",
|
|
3857
|
+
helpGroup: "BUILD"
|
|
3858
|
+
},
|
|
3785
3859
|
{
|
|
3786
3860
|
name: "status",
|
|
3787
3861
|
tier: "coordination",
|
|
@@ -4246,6 +4320,12 @@ async function main() {
|
|
|
4246
4320
|
process.exit(r.status ?? 1);
|
|
4247
4321
|
break;
|
|
4248
4322
|
}
|
|
4323
|
+
case "pack-hub-extension": {
|
|
4324
|
+
const packScript = resolve4(__dirname2, "..", "scripts", "pack-hub-extension.js");
|
|
4325
|
+
const r = spawnSync12("node", [packScript, ...argv.slice(3)], { stdio: "inherit" });
|
|
4326
|
+
process.exit(r.status ?? 1);
|
|
4327
|
+
break;
|
|
4328
|
+
}
|
|
4249
4329
|
case "uninstall": {
|
|
4250
4330
|
const uninstallBin = resolve4(__dirname2, "..", "dist", "uninstall.js");
|
|
4251
4331
|
const r = spawnSync12("node", [uninstallBin, ...argv.slice(3)], { stdio: "inherit" });
|