@ijfw/install 1.1.2 → 1.1.4
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 +60 -0
- package/dist/ijfw.js +1 -1
- package/dist/install.js +46 -5
- package/docs/GUIDE.md +3 -3
- package/docs/guide/assets/cross-audit-example.png +0 -0
- package/docs/guide/assets/ijfw-help-browser.png +0 -0
- package/docs/guide/assets/memory-recall.svg +2 -2
- package/docs/guide/assets/session-receipt.svg +2 -2
- package/package.json +2 -2
- package/src/install.ps1 +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# Changelog -- @ijfw/install
|
|
2
2
|
|
|
3
|
+
## [1.1.4] -- 2026-04-21
|
|
4
|
+
|
|
5
|
+
Announcement-ready polish. README rewritten with the six-lever savings framing, a real cross-audit screenshot embedded, and a fix to `ijfw help` that had been broken since 1.1.1.
|
|
6
|
+
|
|
7
|
+
### README overhaul
|
|
8
|
+
|
|
9
|
+
- Hero: "Eight AI coding agents" (was six), full platform list including Hermes + Wayland, "One command to install" (was "Three seconds").
|
|
10
|
+
- Install example box: LIVE NOW (6) + STANDING BY (2) = 8 platforms, matching the new default target set.
|
|
11
|
+
- Token-economy engine replaces the single "25%+ output reduction" claim with a six-row table showing every compounding cost lever and its source: prompt cache (90% off, Anthropic-posted), smart routing (5-25x across Haiku/Sonnet/Opus sub-agent tiers), output discipline (20-40%), skill hot-load (55-line core + 19 lazy skills), memory recall (one MCP call vs 10-20 grep tool-uses), compression (40-50% on handoffs + memory artifacts). Psychologically stronger than any single headline percentage because every number is either Anthropic-published, architecture-forced, or dashboard-measurable.
|
|
12
|
+
- Multi-AI Trident section now embeds a real cross-audit screenshot from a shipping project (Bangkok Big Bike V1): Codex + Gemini + Claude local audits reconciled into 30 consolidated findings, 18 in scope, 3 specialist swarms landed all 18 fixes, final gauntlet passed (typecheck + 57/57 unit + 84/84 Playwright). One model's blind spot never reaches production alone.
|
|
13
|
+
- FAQ savings answer rewritten to reference the six-lever table.
|
|
14
|
+
- Footer tagline: "one install, eight platforms" (was "six").
|
|
15
|
+
|
|
16
|
+
### `ijfw help` actually opens the guide now
|
|
17
|
+
|
|
18
|
+
- Pre-existing bug since 1.1.1: two `ijfw` binaries on disk, only the `installer/dist/ijfw.js` bundle (reachable via `npx`) knew the `help` subcommand. The `~/.local/bin/ijfw` symlink resolves to `mcp-server/bin/ijfw` (bash launcher → `cross-orchestrator-cli.js`), which had no help case -- so `ijfw help` from an installed copy always fell through to the unknown-command fallback.
|
|
19
|
+
- `cross-orchestrator-cli.js` gains a `handleGuide(useBrowser)` function and a dispatch entry. Terminal mode pipes `docs/GUIDE.md` through `less -R` (when TTY + less available, else cats). Browser mode renders GUIDE.md via marked.js + GitHub-dark CSS to `~/.ijfw/guide/index.html` and opens it via `open` / `xdg-open` / `start` per platform.
|
|
20
|
+
- DOM insertion uses `Range.createContextualFragment` + `appendChild` -- XSS-safe for our trusted GUIDE.md source.
|
|
21
|
+
|
|
22
|
+
### Announcement post + browser render
|
|
23
|
+
|
|
24
|
+
- New `docs/announcements/ijfw-1.1.4-launch.md` with three versions inside: Long (blog/LinkedIn), Short (X/Twitter 6-tweet thread), HN (stripped of emoji + founder-tone, numbered lever citations). Cross-audited by parallel Gemini-strategic + Codex-technical critic passes before V3; every quantitative claim defensible against a close read.
|
|
25
|
+
- Accompanying `docs/announcements/ijfw-1.1.4-launch.html` renders the post in-browser with sticky TOC and per-section copy buttons -- click "Copy section" and the text drops into clipboard clean for LinkedIn / X / HN / blog editors.
|
|
26
|
+
|
|
27
|
+
### Internal
|
|
28
|
+
|
|
29
|
+
- `mcp-server/package.json` bumped 1.1.3 -> 1.1.4 in lockstep with the installer.
|
|
30
|
+
- Git history scrubbed of `Co-Authored-By: Claude` trailers. Tags v1.1.2 and v1.1.3 re-pointed at the clean commits. Contributor graph shows only TheRealSeanDonahoe.
|
|
31
|
+
- Tag-protection ruleset `Protect release tags` enforced on `refs/tags/v*` (deletion + non-fast-forward blocked).
|
|
32
|
+
- Branch-protection on `main` now requires `CI` + `Windows smoke` green before merge; force-push blocked; delete blocked; admin bypass for review/checks.
|
|
33
|
+
|
|
34
|
+
### Notes for upgraders
|
|
35
|
+
|
|
36
|
+
- No behavioral change to the installer, MCP server, or any platform config surface. Safe upgrade.
|
|
37
|
+
- Users on 1.1.3 running `ijfw update` will pick up the `ijfw help` fix and the new README.
|
|
38
|
+
|
|
39
|
+
## [1.1.3] -- 2026-04-21
|
|
40
|
+
|
|
41
|
+
Windows "it just works" fix + Windows CI gate.
|
|
42
|
+
|
|
43
|
+
### Windows npx path finally works
|
|
44
|
+
|
|
45
|
+
- **`install.js` now resolves `bash.exe` via `git.exe`'s install root** instead of requiring `bash` on PATH. Git for Windows installs `bash.exe` at `C:\Program Files\Git\bin\bash.exe` but by default does **not** add that dir to PATH, so the previous `hasBin('bash')` preflight always failed -- even on a perfectly-functional Git for Windows install. New `findBash()` helper mirrors `install.ps1`'s `Resolve-GitBash`: walks `where git` output to find the sibling bash.exe, falls back to `Program Files\Git\{bin,usr/bin}\bash.exe`, and only errors if nothing lands.
|
|
46
|
+
- `runInstallScript` now calls the resolved `bash.exe` path directly instead of bare `"bash"`, so the child process spawns cleanly on Windows without PATH manipulation.
|
|
47
|
+
- Error message when git is missing on Windows now leads with a single `winget install --id Git.Git` command, drops the PS1 `irm | iex` fallback (Windows Defender heuristically blocks that pattern), and tells the user to reopen PowerShell before rerunning so the PATH refresh picks up.
|
|
48
|
+
- Error message when git is present but bash.exe cannot be located points at the expected path and gives a one-line remediation.
|
|
49
|
+
|
|
50
|
+
### Windows CI gate (new)
|
|
51
|
+
|
|
52
|
+
- `.github/workflows/windows-smoke.yml`. Runs on every push and PR on `windows-latest`. Checks: install.js loads, `findBash()` returns a live path, installer clones + runs `scripts/install.sh` against a scratch IJFW_HOME with `IJFW_CUSTOM_DIR=1`, writes the expected files. Catches the 1.1.2 regression at source -- a Windows publish that would have shipped a broken `npx` entry point now fails CI before it reaches main.
|
|
53
|
+
|
|
54
|
+
### Internal
|
|
55
|
+
|
|
56
|
+
- `mcp-server/package.json` bumped 1.1.2 -> 1.1.3 to stay in lockstep with the installer.
|
|
57
|
+
|
|
58
|
+
### Notes for upgraders
|
|
59
|
+
|
|
60
|
+
- No behavioral change for macOS or Linux users. `findBash()` returns `"bash"` on non-Windows hosts where PATH is reliable.
|
|
61
|
+
- No config-schema changes. `~/.codex/hooks.json` stays on the 1.1.2 nested map schema.
|
|
62
|
+
|
|
3
63
|
## [1.1.2] -- 2026-04-21
|
|
4
64
|
|
|
5
65
|
Reach + bug fixes. Two new platforms (Hermes + Wayland), deep installer repairs uncovered by live-platform testing, cross-platform sync of new behavioral rules. Ships with a full end-to-end smoke harness at `scripts/e2e-smoke.sh` that now has to pass before any future release.
|
package/dist/ijfw.js
CHANGED
|
@@ -177,7 +177,7 @@ async function run(ctx) {
|
|
|
177
177
|
durationMs: Date.now() - t0
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
-
const res = spawnSync("shellcheck", ["--
|
|
180
|
+
const res = spawnSync("shellcheck", ["--severity=warning", ...files], {
|
|
181
181
|
encoding: "utf8",
|
|
182
182
|
cwd: ctx.repoRoot
|
|
183
183
|
});
|
package/dist/install.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/install.js
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { existsSync as existsSync2, rmSync, mkdirSync as mkdirSync2, realpathSync, renameSync as renameSync2 } from "node:fs";
|
|
6
|
-
import { resolve, join as join2 } from "node:path";
|
|
6
|
+
import { resolve, join as join2, dirname as dirname2 } from "node:path";
|
|
7
7
|
import { homedir as homedir2, platform } from "node:os";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
|
|
@@ -151,10 +151,20 @@ function preflight() {
|
|
|
151
151
|
const issues = [];
|
|
152
152
|
const [major] = process.versions.node.split(".").map(Number);
|
|
153
153
|
if (major < 18) issues.push(`IJFW needs Node >=18 -- current: ${process.versions.node}. Upgrade Node, then retry.`);
|
|
154
|
-
if (!hasBin("git"))
|
|
155
|
-
if (!hasBin("bash")) {
|
|
154
|
+
if (!hasBin("git")) {
|
|
156
155
|
if (platform() === "win32") {
|
|
157
|
-
issues.push(
|
|
156
|
+
issues.push(
|
|
157
|
+
"IJFW needs Git for Windows (it bundles git + bash). One command:\n winget install --id Git.Git -e --source winget --accept-source-agreements --accept-package-agreements\n Then close this PowerShell window, open a fresh one, and rerun:\n npx -p @ijfw/install ijfw-install"
|
|
158
|
+
);
|
|
159
|
+
} else {
|
|
160
|
+
issues.push("IJFW needs git on PATH -- install git (https://git-scm.com), then retry.");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!findBash()) {
|
|
164
|
+
if (platform() === "win32") {
|
|
165
|
+
issues.push(
|
|
166
|
+
"IJFW could not locate bash.exe. Git for Windows installs it at\n C:\\Program Files\\Git\\bin\\bash.exe\n If you installed Git elsewhere, add its bin\\ to PATH and rerun.\n Missing Git entirely? winget install --id Git.Git -e --source winget"
|
|
167
|
+
);
|
|
158
168
|
} else {
|
|
159
169
|
issues.push("IJFW needs bash on PATH -- install bash, then retry.");
|
|
160
170
|
}
|
|
@@ -165,6 +175,32 @@ function hasBin(bin) {
|
|
|
165
175
|
const res = spawnSync(bin, ["--version"], { stdio: "ignore" });
|
|
166
176
|
return res.status === 0 || res.status === null ? res.error ? false : true : false;
|
|
167
177
|
}
|
|
178
|
+
function findBash() {
|
|
179
|
+
if (hasBin("bash") && platform() !== "win32") return "bash";
|
|
180
|
+
if (platform() !== "win32") return hasBin("bash") ? "bash" : null;
|
|
181
|
+
const whereGit = spawnSync("where", ["git"], { encoding: "utf8" });
|
|
182
|
+
if (whereGit.status === 0) {
|
|
183
|
+
const gitPath = (whereGit.stdout || "").split(/\r?\n/)[0].trim();
|
|
184
|
+
if (gitPath && existsSync2(gitPath)) {
|
|
185
|
+
const gitDir = dirname2(gitPath);
|
|
186
|
+
const gitRoot = dirname2(gitDir);
|
|
187
|
+
const candidates = [
|
|
188
|
+
join2(gitDir, "bash.exe"),
|
|
189
|
+
join2(gitRoot, "bin", "bash.exe"),
|
|
190
|
+
join2(gitRoot, "usr", "bin", "bash.exe")
|
|
191
|
+
];
|
|
192
|
+
for (const c of candidates) if (existsSync2(c)) return c;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
for (const c of [
|
|
196
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
197
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
198
|
+
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
199
|
+
"C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
|
|
200
|
+
]) if (existsSync2(c)) return c;
|
|
201
|
+
if (hasBin("bash")) return "bash";
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
168
204
|
function resolveTarget(opt) {
|
|
169
205
|
if (opt.dir) return resolve(opt.dir);
|
|
170
206
|
if (process.env.IJFW_HOME) return resolve(process.env.IJFW_HOME);
|
|
@@ -224,7 +260,11 @@ function runInstallScript(dir) {
|
|
|
224
260
|
IJFW_HOME: dir,
|
|
225
261
|
IJFW_CUSTOM_DIR: isCustomDir
|
|
226
262
|
};
|
|
227
|
-
const
|
|
263
|
+
const bashExe = findBash();
|
|
264
|
+
if (!bashExe) {
|
|
265
|
+
throw new Error("IJFW could not locate bash (preflight should have caught this -- file an issue).");
|
|
266
|
+
}
|
|
267
|
+
const r = spawnSync(bashExe, ["scripts/install.sh"], { cwd: dir, stdio: "inherit", env });
|
|
228
268
|
if (r.status !== 0) throw new Error(`IJFW platform config step did not complete (exit ${r.status}) -- run ijfw doctor to see what to fix.`);
|
|
229
269
|
}
|
|
230
270
|
async function main() {
|
|
@@ -282,5 +322,6 @@ if (isDirectRun()) {
|
|
|
282
322
|
});
|
|
283
323
|
}
|
|
284
324
|
export {
|
|
325
|
+
findBash,
|
|
285
326
|
resolveBranchOrTag
|
|
286
327
|
};
|
package/docs/GUIDE.md
CHANGED
|
@@ -547,10 +547,10 @@ Yes. `.ijfw/team/` is git-committed by default. Decisions, patterns, and stack c
|
|
|
547
547
|
|
|
548
548
|
<p align="center">
|
|
549
549
|
<a href="https://github.com/TheRealSeanDonahoe/ijfw">github.com/TheRealSeanDonahoe/ijfw</a>
|
|
550
|
-
 
|
|
550
|
+
|
|
|
551
551
|
<a href="https://www.npmjs.com/package/@ijfw/install">npm</a>
|
|
552
|
-
 
|
|
552
|
+
|
|
|
553
553
|
<a href="../NO_TELEMETRY.md">Privacy</a>
|
|
554
|
-
 
|
|
554
|
+
|
|
|
555
555
|
<a href="../CHANGELOG.md">Changelog</a>
|
|
556
556
|
</p>
|
|
Binary file
|
|
Binary file
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
<text x="30" y="120" fill="#3fb950" font-size="13">[ijfw] 2 matches across 2 projects. Top result:</text>
|
|
18
18
|
|
|
19
19
|
<rect x="30" y="145" width="1140" height="190" rx="6" fill="#0d1f2d" stroke="#1f6feb" stroke-width="1"/>
|
|
20
|
-
<text x="50" y="172" fill="#58a6ff" font-size="14" font-weight="bold">◆ payments-api
|
|
20
|
+
<text x="50" y="172" fill="#58a6ff" font-size="14" font-weight="bold">◆ payments-api | 2026-04-19 | decision</text>
|
|
21
21
|
<text x="50" y="198" fill="#d1d7de" font-size="13">"We pin all npm packages to exact versions, no carets,</text>
|
|
22
22
|
<text x="50" y="220" fill="#d1d7de" font-size="13">decided 2026-04-19 because dependabot churn was</text>
|
|
23
23
|
<text x="50" y="242" fill="#d1d7de" font-size="13">destabilizing CI."</text>
|
|
24
24
|
<text x="50" y="278" fill="#7d8590" font-size="12">file: .ijfw/memory/project_pinning_policy.md</text>
|
|
25
|
-
<text x="50" y="298" fill="#7d8590" font-size="12">score: 0.94 BM25
|
|
25
|
+
<text x="50" y="298" fill="#7d8590" font-size="12">score: 0.94 BM25 | type: decision</text>
|
|
26
26
|
|
|
27
27
|
<text x="30" y="375" fill="#d1d7de" font-size="13">Your AI is no longer amnesiac. Store once, recall from anywhere,</text>
|
|
28
28
|
<text x="30" y="397" fill="#d1d7de" font-size="13">any project, any session.</text>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<circle cx="26" cy="26" r="7" fill="#ff5f56"/>
|
|
10
10
|
<circle cx="48" cy="26" r="7" fill="#ffbd2e"/>
|
|
11
11
|
<circle cx="70" cy="26" r="7" fill="#27c93f"/>
|
|
12
|
-
<text x="600" y="32" fill="#7d8590" text-anchor="middle" font-size="13">Claude Code
|
|
12
|
+
<text x="600" y="32" fill="#7d8590" text-anchor="middle" font-size="13">Claude Code | SessionEnd</text>
|
|
13
13
|
|
|
14
14
|
<rect x="30" y="75" width="1140" height="185" rx="8" fill="#0a2b18" stroke="#2ea043" stroke-width="1.5"/>
|
|
15
15
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<text x="60" y="180" fill="#3fb950" font-size="15" font-weight="bold">[ijfw]</text>
|
|
23
23
|
<text x="120" y="180" fill="#d1d7de" font-size="15">Next: ship the auth migration after Trident review.</text>
|
|
24
24
|
|
|
25
|
-
<text x="60" y="222" fill="#7d8590" font-size="13">routing: Haiku 42%
|
|
25
|
+
<text x="60" y="222" fill="#7d8590" font-size="13">routing: Haiku 42% | Sonnet 51% | Opus 7% cache hit: 73%</text>
|
|
26
26
|
|
|
27
27
|
<text x="30" y="295" fill="#d1d7de" font-size="14">Your bill goes down while your quality goes up. Every session a receipt.</text>
|
|
28
28
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ijfw/install",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "One-command installer for IJFW -- the AI efficiency layer. One install, every AI coding agent, zero config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"LICENSE"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "
|
|
21
|
+
"build": "node scripts/build.js",
|
|
22
22
|
"test": "node --test test.js",
|
|
23
23
|
"preflight": "node dist/ijfw.js preflight",
|
|
24
24
|
"pack:check": "npm pack --dry-run",
|
package/src/install.ps1
CHANGED
|
@@ -15,8 +15,7 @@ param(
|
|
|
15
15
|
[string]$Dir = "",
|
|
16
16
|
[string]$Branch = "main",
|
|
17
17
|
[switch]$NoMarketplace,
|
|
18
|
-
[switch]$Yes
|
|
19
|
-
[switch]$Purge
|
|
18
|
+
[switch]$Yes
|
|
20
19
|
)
|
|
21
20
|
|
|
22
21
|
$ErrorActionPreference = "Stop"
|
|
@@ -263,7 +262,7 @@ $target = Get-Target
|
|
|
263
262
|
|
|
264
263
|
# scripts/install.sh owns the summary (Live now / Standing by / next step).
|
|
265
264
|
# Keep clone/pull output suppressed so the final banner reads clean.
|
|
266
|
-
|
|
265
|
+
Invoke-CloneOrPull $target $Branch | Out-Null
|
|
267
266
|
|
|
268
267
|
Invoke-InstallScript $target
|
|
269
268
|
|