@ijfw/install 1.3.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.1] -- 2026-05-12
4
+
5
+ **Codex hook cleanup + release cadence hardening.** Tightens IJFW's Codex integration for Codex 0.130+, reduces the default dependency footprint, and moves more release drift into automated gates before it reaches users.
6
+
7
+ - Codex `SessionStart` now emits `additionalContext` inside `hookSpecificOutput` with `hookEventName: "SessionStart"`, matching Codex's strict hook response shape. This closes the `SessionStart hook (failed): hook returned invalid session start JSON output` error.
8
+ - Codex `PostToolUse` is now stdout-silent. IJFW still records local observations and failure signals, but it no longer re-injects cleaned tool output as `systemMessage`, which Codex renders as visible hook warning spam.
9
+ - Codex hook Node shims now pass user/tool text after `--`, so tool output beginning with `---` is treated as data instead of a Node CLI option. This closes the `node: bad option: ---` failure.
10
+ - Codex `UserPromptSubmit` and `PreToolUse` advisory output now use the same `hookSpecificOutput.additionalContext` shape when they do emit context.
11
+ - Codex `Stop` now stays stdout-silent on routine session saves. Normal receipts are written locally; only actionable compression notices can surface by default. This closes the `Stop hook (completed) warning: [ijfw] Session #... saved` noise.
12
+ - Codex bundle tests now cover strict `SessionStart` JSON and silent `PostToolUse` behavior for both routine output and failure-looking output.
13
+ - The shipped MCP server no longer installs `@xenova/transformers` by default. Cold semantic vectors are explicit opt-in and `IJFW_VECTORS` now defaults to `off`, keeping the production install smaller and quieter under package audits.
14
+ - The preflight audit gate now runs against both `installer` and `mcp-server`, so server-side dependency drift is covered by the same release gate as the installer.
15
+ - `ijfw preflight` now routes through the canonical 11-gate preflight entrypoint from both installer and MCP CLI paths instead of falling back to `scripts/check-all.sh`.
16
+ - Platform capability drift is now gated by `platform-capabilities.json` plus `scripts/check-platform-drift.js`, covering skill counts, hook-event counts, and marketplace/plugin manifest claims.
17
+ - Update-check changelog URLs now point at GitLab releases, matching the canonical repository.
18
+ - D2 graph-write lock timeout handling now throws the intended `EBUSY_GRAPH_WRITE` error instead of tripping an undeclared variable path under collision.
19
+
20
+ Files: `codex/.codex/hooks/session-start.sh`, `codex/.codex/hooks/post-tool-use.sh`, `codex/.codex/hooks/pre-prompt.sh`, `codex/.codex/hooks/pre-tool-use.sh`, `codex/.codex/hooks/session-end.sh`, `scripts/observation/test-envelope-invariant-codex.sh`, `mcp-server/test-codex-bundle.js`, `mcp-server/src/vectors.js`, `mcp-server/package.json`, `installer/src/preflight/gates/audit-ci.js`, `installer/src/preflight.js`, `mcp-server/src/cross-orchestrator-cli.js`, `mcp-server/src/compute/graph-lock.js`, `platform-capabilities.json`, `scripts/check-platform-drift.js`.
21
+
3
22
  ## [1.2.6] -- 2026-05-01
4
23
 
5
24
  **Token sandbox + parallel workflow dispatch + DeepSeek frontier upgrade.** A new `ijfw_run` MCP tool keeps large command output out of your context window entirely -- builds, test suites, grep runs, and log tails are sandboxed to disk and summarized in a few lines instead of flooding thousands of tokens. The `ijfw-workflow` execution engine gains a formal Wave Table that makes parallel agent dispatch deterministic rather than inferred. DeepSeek moves to `deepseek-v4-pro` -- the actual frontier model -- so the Trident gets Frontier AI checking Frontier AI.
package/dist/ijfw.js CHANGED
@@ -582,27 +582,35 @@ async function run7(ctx) {
582
582
  const t0 = Date.now();
583
583
  const ver = ctx.versions["audit-ci"] || "latest";
584
584
  const configPath = join4(ctx.repoRoot, ".audit-ci.jsonc");
585
- const res = spawnSync7(
586
- "npx",
587
- ["--yes", `audit-ci@${ver}`, "--config", configPath],
588
- {
589
- encoding: "utf8",
590
- cwd: join4(ctx.repoRoot, "installer"),
591
- timeout: 6e4
592
- }
593
- );
585
+ const packageDirs = ["installer", "mcp-server"];
586
+ const runs = packageDirs.map((dir) => {
587
+ const res = spawnSync7(
588
+ "npx",
589
+ ["--yes", `audit-ci@${ver}`, "--config", configPath],
590
+ {
591
+ encoding: "utf8",
592
+ cwd: join4(ctx.repoRoot, dir),
593
+ timeout: 6e4
594
+ }
595
+ );
596
+ return { dir, status: res.status, output: (res.stdout || "") + (res.stderr || "") };
597
+ });
594
598
  const durationMs = Date.now() - t0;
595
- const output = (res.stdout || "") + (res.stderr || "");
596
- const lines = output.split("\n").filter(Boolean);
597
- if (res.status === 0) {
599
+ const failed = runs.filter((r) => r.status !== 0);
600
+ if (failed.length === 0) {
598
601
  return {
599
602
  name: "audit-ci",
600
603
  status: "PASS",
601
- message: "audit-ci: no high/critical vulnerabilities",
602
- details: [],
604
+ message: "audit-ci: no high/critical vulnerabilities in installer or mcp-server",
605
+ details: runs.map((r) => `${r.dir}: pass`),
603
606
  durationMs
604
607
  };
605
608
  }
609
+ const lines = [];
610
+ for (const r of failed) {
611
+ lines.push(`${r.dir}: audit failed`);
612
+ lines.push(...r.output.split("\n").filter(Boolean).slice(0, 10));
613
+ }
606
614
  return {
607
615
  name: "audit-ci",
608
616
  status: "FAIL",
@@ -1045,7 +1053,7 @@ __export(preflight_exports, {
1045
1053
  runPreflightCommand: () => runPreflightCommand
1046
1054
  });
1047
1055
  import { readFileSync as readFileSync2, existsSync as existsSync3 } from "node:fs";
1048
- import { join as join8, dirname } from "node:path";
1056
+ import { join as join8, dirname, resolve as resolve3 } from "node:path";
1049
1057
  import { fileURLToPath } from "node:url";
1050
1058
  function printHelp() {
1051
1059
  console.log(`
@@ -1144,11 +1152,24 @@ async function runPreflightCommand(argv, repoRoot2) {
1144
1152
  const report = await runPreflight(gates, ctx);
1145
1153
  process.exit(report.outcome === "pass" ? 0 : 1);
1146
1154
  }
1155
+ function defaultRepoRoot() {
1156
+ let dir = __dirname;
1157
+ for (let i = 0; i < 8; i++) {
1158
+ if (existsSync3(join8(dir, "package.json")) && existsSync3(join8(dir, "mcp-server"))) return dir;
1159
+ const next = resolve3(dir, "..");
1160
+ if (next === dir) break;
1161
+ dir = next;
1162
+ }
1163
+ return process.cwd();
1164
+ }
1147
1165
  var __dirname;
1148
1166
  var init_preflight = __esm({
1149
- "src/preflight.js"() {
1167
+ async "src/preflight.js"() {
1150
1168
  init_runner();
1151
1169
  __dirname = dirname(fileURLToPath(import.meta.url));
1170
+ if (process.argv[1] && resolve3(process.argv[1]) === fileURLToPath(import.meta.url)) {
1171
+ await runPreflightCommand(process.argv, defaultRepoRoot());
1172
+ }
1152
1173
  }
1153
1174
  });
1154
1175
 
@@ -2412,7 +2433,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
2412
2433
  });
2413
2434
 
2414
2435
  // src/ijfw.js
2415
- import { dirname as dirname2, join as join9, resolve as resolve3, basename } from "node:path";
2436
+ import { dirname as dirname2, join as join9, resolve as resolve4, basename } from "node:path";
2416
2437
  import { fileURLToPath as fileURLToPath2 } from "node:url";
2417
2438
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, copyFileSync, readdirSync as readdirSync4, rmSync as rmSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
2418
2439
  import { homedir, platform as platform2 } from "node:os";
@@ -2422,7 +2443,7 @@ function repoRoot() {
2422
2443
  let dir = __dirname2;
2423
2444
  for (let i = 0; i < 6; i++) {
2424
2445
  if (existsSync4(join9(dir, "package.json")) && existsSync4(join9(dir, ".git"))) return dir;
2425
- dir = resolve3(dir, "..");
2446
+ dir = resolve4(dir, "..");
2426
2447
  }
2427
2448
  return process.cwd();
2428
2449
  }
@@ -2437,7 +2458,7 @@ COMMANDS
2437
2458
  install Install IJFW into your AI coding agents
2438
2459
  uninstall Remove IJFW from your AI coding agents
2439
2460
  help Open the full IJFW guide (terminal, or --browser for rendered)
2440
- preflight Run 12-gate quality pipeline before publishing
2461
+ preflight Run 11-gate quality pipeline before publishing
2441
2462
  dashboard Start / stop / check the local observability dashboard
2442
2463
  design Manage the visual design companion
2443
2464
  doctor Diagnose IJFW installation health
@@ -2494,19 +2515,19 @@ async function main() {
2494
2515
  }
2495
2516
  switch (sub) {
2496
2517
  case "install": {
2497
- const installBin = resolve3(__dirname2, "..", "dist", "install.js");
2518
+ const installBin = resolve4(__dirname2, "..", "dist", "install.js");
2498
2519
  const r = spawnSync12("node", [installBin, ...argv.slice(3)], { stdio: "inherit" });
2499
2520
  process.exit(r.status ?? 1);
2500
2521
  break;
2501
2522
  }
2502
2523
  case "uninstall": {
2503
- const uninstallBin = resolve3(__dirname2, "..", "dist", "uninstall.js");
2524
+ const uninstallBin = resolve4(__dirname2, "..", "dist", "uninstall.js");
2504
2525
  const r = spawnSync12("node", [uninstallBin, ...argv.slice(3)], { stdio: "inherit" });
2505
2526
  process.exit(r.status ?? 1);
2506
2527
  break;
2507
2528
  }
2508
2529
  case "preflight": {
2509
- const { runPreflightCommand: runPreflightCommand2 } = await Promise.resolve().then(() => (init_preflight(), preflight_exports));
2530
+ const { runPreflightCommand: runPreflightCommand2 } = await init_preflight().then(() => preflight_exports);
2510
2531
  await runPreflightCommand2([argv[0], argv[1], ...argv.slice(3)], repoRoot());
2511
2532
  break;
2512
2533
  }
@@ -2563,7 +2584,7 @@ async function main() {
2563
2584
  console.error("Usage: ijfw design push <file.html>");
2564
2585
  process.exit(1);
2565
2586
  }
2566
- const abs = resolve3(filePath);
2587
+ const abs = resolve4(filePath);
2567
2588
  if (!existsSync4(abs)) {
2568
2589
  console.error(`File not found: ${abs}`);
2569
2590
  process.exit(1);
@@ -2587,7 +2608,7 @@ async function main() {
2587
2608
  const wantsBrowser = argv.slice(3).includes("--browser");
2588
2609
  const candidates = [
2589
2610
  join9(repoRoot(), "docs", "GUIDE.md"),
2590
- resolve3(__dirname2, "..", "docs", "GUIDE.md"),
2611
+ resolve4(__dirname2, "..", "docs", "GUIDE.md"),
2591
2612
  join9(homedir(), ".ijfw", "docs", "GUIDE.md")
2592
2613
  ];
2593
2614
  const guidePath = candidates.find((p) => existsSync4(p));
package/dist/install.js CHANGED
@@ -767,7 +767,7 @@ async function installCodex(ctx) {
767
767
  copyDirIfAbsent(sd.path, join4(projSkills, sd.name));
768
768
  }
769
769
  }
770
- ctx.log.ok("Installed Codex bundle: MCP + hooks + 15 skills + context");
770
+ ctx.log.ok("Installed Codex bundle: MCP + hooks + 19 skills + context");
771
771
  return { status: "ok" };
772
772
  }
773
773
  async function installGemini(ctx) {
@@ -832,7 +832,7 @@ async function installGemini(ctx) {
832
832
  for (const f of listFiles(agentSrc, ".md")) {
833
833
  copyIfAbsent(f.path, join4(extDst, "agents", f.name));
834
834
  }
835
- ctx.log.ok("Installed Gemini bundle: MCP + extension + 15 skills + 11 hooks + policy");
835
+ ctx.log.ok("Installed Gemini bundle: MCP + extension + 19 skills + 11 hooks + policy");
836
836
  return { status: "ok" };
837
837
  }
838
838
  async function installWayland(ctx) {
@@ -2048,14 +2048,12 @@ function cloneOrPull(dir, branch) {
2048
2048
  else if (remoteSignal) console.warn(` git exited on signal ${remoteSignal}`);
2049
2049
  else if (remoteStatus !== 0 && remoteStderr) console.warn(` git remote get-url: ${remoteStderr.slice(0, 120).trim()}`);
2050
2050
  if (remoteStatus === 0) {
2051
- const STALE_ORIGINS = [
2052
- "https://github.com/seandonahoe/ijfw.git",
2053
- "https://github.com/seandonahoe/ijfw",
2054
- "https://github.com/seandonahoe/ijfw/",
2055
- "https://github.com/seandonahoe/ijfw.git/"
2051
+ const STALE_PATTERNS = [
2052
+ /^https:\/\/github\.com\/seandonahoe\/ijfw(\.git)?\/?$/i,
2053
+ /^https:\/\/github\.com\/therealseandonahoe\/ijfw(\.git)?\/?$/i
2056
2054
  ];
2057
2055
  const currentOrigin = (stdout || "").trim();
2058
- if (STALE_ORIGINS.includes(currentOrigin)) {
2056
+ if (STALE_PATTERNS.some((re) => re.test(currentOrigin))) {
2059
2057
  const setUrl = spawnSync2("git", ["-C", dir, "remote", "set-url", "origin", DEFAULT_REPO], { stdio: "inherit" });
2060
2058
  if (setUrl.status !== 0) {
2061
2059
  console.warn(` [!] origin migration failed -- could not repoint ${currentOrigin} to ${DEFAULT_REPO}`);
package/docs/GUIDE.md CHANGED
@@ -172,7 +172,7 @@ Run `/team setup` in Claude Code, or `ijfw team` from the shell, to see your cur
172
172
  |------|-------|--------------|
173
173
  | Hot | Plain markdown in `.ijfw/memory/` | Always on. Instant reads. Git friendly. |
174
174
  | Warm | BM25 ranked search | Always on. Scales to around 10,000 entries per project. |
175
- | Cold | Optional semantic vectors | Only if you install `@xenova/transformers`. Off by default. |
175
+ | Cold | Optional semantic vectors | Off by default. Requires a user-installed embedding provider. |
176
176
 
177
177
  Every session also ends with an optional "dream cycle". Run `/consolidate` or "run a dream cycle" to have IJFW sweep the day's memory: promote observed patterns into your knowledge base, prune stale entries, reconcile contradictions, optionally lift winners into global memory so every future project benefits. Memory that grows sharper over time instead of heavier.
178
178
 
@@ -359,9 +359,9 @@ IJFW configures six AI coding agents with native affordances on each, plus a uni
359
359
 
360
360
  | Platform | What ships |
361
361
  |----------|------------|
362
- | Claude Code | Native plugin via marketplace, MCP auto-registered, 9 hooks, 20 on-demand skills, 21 slash commands |
363
- | Codex CLI | Native plugin (`.codex-plugin/plugin.json`), 20 skills, 9 hooks, MCP registered, marketplace-ready |
364
- | Gemini CLI | Native extension (`gemini-extension.json`), 20 skills, 11 hook events, 21 TOML slash commands, policy engine, BeforeModel injection, checkpointing |
362
+ | Claude Code | Native plugin via marketplace, MCP auto-registered, 6 hook events / 12 scripts, 22 on-demand skills, 22 slash commands |
363
+ | Codex CLI | Native plugin (`.codex-plugin/plugin.json`), 19 skills, 5 hook events, MCP registered, marketplace-ready |
364
+ | Gemini CLI | Native extension (`gemini-extension.json`), 19 skills, 11 hook events, 19 TOML slash commands, policy engine, BeforeModel injection, checkpointing |
365
365
  | Cursor | `.cursor/mcp.json` plus `.cursor/rules/ijfw.mdc`. Dashboard view-only. |
366
366
  | Windsurf | `~/.codeium/windsurf/mcp_config.json` plus `.windsurfrules`. Dashboard view-only. |
367
367
  | Copilot (VS Code) | `.vscode/mcp.json` plus `.github/copilot-instructions.md`. Dashboard view-only. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ijfw/install",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
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": {
@@ -55,7 +55,6 @@
55
55
  "url": "git+https://gitlab.com/therealseandonahoe/ijfw.git"
56
56
  },
57
57
  "publishConfig": {
58
- "access": "public",
59
- "provenance": true
58
+ "access": "public"
60
59
  }
61
60
  }