@litfamily/litcodex 1.0.0 → 1.0.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 CHANGED
@@ -1,6 +1,6 @@
1
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/cover.webp" width="100%" alt="LitCodex v5 armory cover" /></p>
1
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/cover.webp" width="100%" alt="LitCodex v5 armory cover" /></p>
2
2
 
3
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/ascii-readme.svg" width="480" alt="LIT ASCII B mark" /></p>
3
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/ascii-readme.svg" width="480" alt="LIT ASCII B mark" /></p>
4
4
 
5
5
  <details>
6
6
  <summary>Copy ASCII logo</summary>
@@ -32,12 +32,12 @@ LIT · codex
32
32
  </details>
33
33
 
34
34
  <p align="center">
35
- <a href="#install"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/badge-version.svg" alt="1.0.0" /></a>
36
- <a href="https://github.com/wjgoarxiv/litcodex/blob/main/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/badge-license.svg" alt="MIT license" /></a>
35
+ <a href="#install"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/badge-version.svg" alt="1.0.1" /></a>
36
+ <a href="https://github.com/wjgoarxiv/litcodex/blob/main/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/badge-license.svg" alt="MIT license" /></a>
37
37
  </p>
38
38
 
39
39
  <p align="center">
40
- <a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/usage.md"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/lucide-book-open.svg" width="16" alt="" /> Docs</a> &nbsp; <a href="#install">Install</a> &nbsp; <a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/lucide-play.svg" width="16" alt="" /> Ignition</a> &nbsp; <a href="https://github.com/wjgoarxiv/litcodex/blob/main/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/lucide-shield-check.svg" width="16" alt="" /> MIT</a>
40
+ <a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/usage.md"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/lucide-book-open.svg" width="16" alt="" /> Docs</a> &nbsp; <a href="#install">Install</a> &nbsp; <a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/lucide-play.svg" width="16" alt="" /> Ignition</a> &nbsp; <a href="https://github.com/wjgoarxiv/litcodex/blob/main/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/lucide-shield-check.svg" width="16" alt="" /> MIT</a>
41
41
  </p>
42
42
 
43
43
  # @litfamily/litcodex
@@ -79,7 +79,7 @@ Append `lit` to a prompt to activate the Codex CLI hook. It routes the request i
79
79
 
80
80
  The hook is an entry signal; it does not prove that a model result or visual check completed.
81
81
 
82
- <p align="center"><a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/ignition-poster.png" width="720" alt="Ignition motion poster" /></a></p>
82
+ <p align="center"><a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/ignition-poster.png" width="720" alt="Ignition motion poster" /></a></p>
83
83
 
84
84
  Select the poster for the optional film; this README keeps motion opt-in.
85
85
 
@@ -93,7 +93,7 @@ Host limit: Codex CLI owns hook and agent execution, while authentication, model
93
93
  and any visual check remain host capabilities. A route mark or static editorial image is not completion
94
94
  evidence.
95
95
 
96
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/litcodex-ignition-1600.webp" width="49%" alt="LitCodex ignition editorial cue" /> <img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/litcodex-continuity-1600.webp" width="49%" alt="LitCodex continuity editorial cue" /></p>
96
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/litcodex-ignition-1600.webp" width="49%" alt="LitCodex ignition editorial cue" /> <img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/litcodex-continuity-1600.webp" width="49%" alt="LitCodex continuity editorial cue" /></p>
97
97
 
98
98
  ## What is LitCodex
99
99
 
@@ -103,20 +103,20 @@ only after every success criterion passes. The npm package is self-contained and
103
103
 
104
104
  ## Install
105
105
 
106
- > Install `@litfamily/litcodex@1.0.0` with the scoped command below. See [migration guidance](https://github.com/wjgoarxiv/litcodex/blob/main/docs/npm-migration.md).
106
+ > Install `@litfamily/litcodex@1.0.1` with the scoped command below. See [migration guidance](https://github.com/wjgoarxiv/litcodex/blob/main/docs/npm-migration.md).
107
107
 
108
108
  With **Node.js 22+** and **Codex CLI** installed, run:
109
109
 
110
110
  ```sh
111
- npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex install
111
+ npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex install
112
112
  ```
113
113
 
114
114
  The installer registers the plugin, hooks, and agents, then updates managed keys in `~/.codex/config.toml`.
115
115
  It asks for the lead model, helper model, and output style. Codex authentication and model access are required
116
116
  when you run model work; installation itself does not require GitHub credentials.
117
117
 
118
- Preview changes with `npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex --dry-run install`. For unattended setup, use
119
- `npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex install --yes`. An explicit `--style <id>` still applies.
118
+ Preview changes with `npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex --dry-run install`. For unattended setup, use
119
+ `npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex install --yes`. An explicit `--style <id>` still applies.
120
120
 
121
121
  For a persistent command:
122
122
 
@@ -125,7 +125,7 @@ npm install -g @litfamily/litcodex
125
125
  litcodex install
126
126
  ```
127
127
 
128
- > Without a global install, use `npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex <command>`, such as `npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex doctor`.
128
+ > Without a global install, use `npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex <command>`, such as `npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex doctor`.
129
129
 
130
130
  For an isolated trial apart from existing settings, follow the [isolated trial guide](https://github.com/wjgoarxiv/litcodex/blob/main/docs/npm-migration.md#isolated-local-trial).
131
131
  Changing only `CODEX_HOME` can still discover settings in your existing home.
@@ -226,7 +226,7 @@ See [state and recovery](https://github.com/wjgoarxiv/litcodex/blob/main/docs/us
226
226
  ## Verify it worked
227
227
 
228
228
  ```sh
229
- npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex doctor
229
+ npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex doctor
230
230
  ```
231
231
 
232
232
  `litcodex doctor` checks registration, hooks, config, and host capabilities. `litcodex loop doctor` checks
@@ -259,7 +259,7 @@ project loop state. A successful installation check does not prove authenticated
259
259
  ## Uninstall
260
260
 
261
261
  ```sh
262
- npm exec --yes --package @litfamily/litcodex@1.0.0 -- litcodex uninstall
262
+ npm exec --yes --package @litfamily/litcodex@1.0.1 -- litcodex uninstall
263
263
  ```
264
264
 
265
265
  `litcodex uninstall` removes the plugin and LitCodex-managed config while preserving unrelated settings.
@@ -284,7 +284,7 @@ Tests, fixtures, test helpers, and Vitest configuration remain tracked repositor
284
284
 
285
285
  Select the poster to watch the 10-second film.
286
286
 
287
- <p align="center"><a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.0/readme-assets/ignition-poster.png" width="720" alt="Ignition motion graphic poster" /></a></p>
287
+ <p align="center"><a href="https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-film.mp4"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.1/readme-assets/ignition-poster.png" width="720" alt="Ignition motion graphic poster" /></a></p>
288
288
 
289
289
  [Animated GIF](https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/ignition-readme.gif) · [Media and icon credits](https://github.com/wjgoarxiv/litcodex/blob/main/docs/assets/readme/README.md)
290
290
 
@@ -9,3 +9,7 @@ export declare function ensureGpt56ProfileFiles(args: {
9
9
  readonly reconfigure: boolean;
10
10
  readonly modelContexts?: Gpt56ModelContexts;
11
11
  }): Promise<ProfileFileResult>;
12
+ /** The per-model profile file names LitCodex may write directly under `codexHome`. */
13
+ export declare const GPT56_PROFILE_FILE_NAMES: readonly string[];
14
+ /** True when `content` is exactly what LitCodex would have written for `name` (bare, or with the limits it still recognizes as its own). Used by uninstall to remove only files it authored. */
15
+ export declare function isManagedGpt56ProfileContent(name: string, content: string): boolean;
@@ -56,6 +56,28 @@ function profileContent() {
56
56
  "gpt56-luna-max.config.toml": renderProfile(GPT56_MODELS.luna, "max"),
57
57
  };
58
58
  }
59
+ /** The per-model profile file names LitCodex may write directly under `codexHome`. */
60
+ export const GPT56_PROFILE_FILE_NAMES = Object.keys(profileContent());
61
+ /** True when `content` is exactly what LitCodex would have written for `name` (bare, or with the limits it still recognizes as its own). Used by uninstall to remove only files it authored. */
62
+ export function isManagedGpt56ProfileContent(name, content) {
63
+ const desired = profileContent()[name];
64
+ if (desired === undefined)
65
+ return false;
66
+ if (content === desired)
67
+ return true;
68
+ switch (name) {
69
+ case "gpt56-sol-high.config.toml":
70
+ return isExactGeneratedExplicitSolProfile(content);
71
+ case "gpt56-terra-high.config.toml":
72
+ return isExactGeneratedTerraProfile(content);
73
+ case "gpt56-luna-max.config.toml":
74
+ return isExactGeneratedLunaProfile(content);
75
+ case "gpt6-astra-xhigh.config.toml":
76
+ return isExactGeneratedAstraProfile(content);
77
+ default:
78
+ return false;
79
+ }
80
+ }
59
81
  function renderProfile(model, effort) {
60
82
  return `model = ${JSON.stringify(model)}\nmodel_reasoning_effort = ${JSON.stringify(effort)}\n`;
61
83
  }
@@ -27,7 +27,11 @@ export function capabilityPreflightError(capabilities, codexBin) {
27
27
  // When that also fails, the existing Codex configuration on this machine is what
28
28
  // the resolved binary cannot load, and LitCodex's managed settings are innocent.
29
29
  if (reason === "host-config-incompatible") {
30
- return new InstallError("LITCODEX_INSTALL_HOST_CONFIG_INCOMPATIBLE", `The existing Codex configuration on this machine could not be loaded by the Codex that ran, with or without LitCodex settings; no install mutation was attempted.${resolved} This usually means that Codex is older than the one that last wrote the configuration.`, { capabilities });
30
+ const detail = capabilities.concurrency.detail;
31
+ const explanation = detail === undefined
32
+ ? " This usually means that Codex is older than the one that last wrote the configuration."
33
+ : ` Codex reported: ${detail}.`;
34
+ return new InstallError("LITCODEX_INSTALL_HOST_CONFIG_INCOMPATIBLE", `The existing Codex configuration on this machine could not be loaded by the Codex that ran, with or without LitCodex settings; no install mutation was attempted.${resolved}${explanation}`, { capabilities });
31
35
  }
32
36
  return new InstallError("LITCODEX_INSTALL_CONFIG_WRITE_FAILED", `Codex strict config rejected LitCodex managed settings; no install mutation was attempted.${resolved}`, { capabilities });
33
37
  }
@@ -10,6 +10,7 @@ export interface SpawnOptions {
10
10
  readonly stdio: "inherit" | "pipe";
11
11
  readonly timeout?: number;
12
12
  readonly env?: NodeJS.ProcessEnv;
13
+ readonly cwd?: string;
13
14
  readonly shell?: false;
14
15
  readonly windowsVerbatimArguments?: boolean;
15
16
  }
@@ -7,6 +7,8 @@ export interface CapabilityReport {
7
7
  readonly reason: string;
8
8
  readonly observedSource: string;
9
9
  readonly limit?: number;
10
+ /** Extra diagnostic text observed from Codex itself: a startup warning on acceptance, or the doctor-reported failure detail on host-config-incompatible rejection. */
11
+ readonly detail?: string;
10
12
  }
11
13
  export interface HostCapabilities {
12
14
  readonly concurrency: CapabilityReport;
@@ -64,6 +64,10 @@ export function probeHostCapabilities(codexBin, spawn, selection = {}) {
64
64
  hostConfigRejected: baselineProbe?.kind === "rejected",
65
65
  timedOut: isTimeout(versionResult) || rootProbe.kind === "timeout",
66
66
  versionSupport,
67
+ ...(rootProbe.kind === "accepted" && rootProbe.warning !== undefined ? { rootWarning: rootProbe.warning } : {}),
68
+ ...(baselineProbe?.kind === "rejected" && baselineProbe.detail !== undefined
69
+ ? { hostConfigDetail: baselineProbe.detail }
70
+ : {}),
67
71
  });
68
72
  return {
69
73
  concurrency,
@@ -99,14 +103,21 @@ function concurrencyReport(args) {
99
103
  }
100
104
  if (!args.rootAccepted) {
101
105
  const reason = args.hostConfigRejected === true ? "host-config-incompatible" : "strict-config-rejected";
102
- return { status: "unavailable", reason, observedSource };
106
+ return {
107
+ status: "unavailable",
108
+ reason,
109
+ observedSource,
110
+ ...(args.hostConfigDetail === undefined ? {} : { detail: args.hostConfigDetail }),
111
+ };
103
112
  }
113
+ const detail = args.rootWarning === undefined ? {} : { detail: args.rootWarning };
104
114
  if (args.versionSupport.kind === "newer-stable") {
105
115
  return {
106
116
  status: "advisory",
107
117
  limit: HARD_CONCURRENCY_LIMIT,
108
118
  reason: "strict config accepted on a newer stable Codex; configured concurrency is usable but runtime enforcement is not yet source-verified",
109
119
  observedSource,
120
+ ...detail,
110
121
  };
111
122
  }
112
123
  return {
@@ -114,6 +125,7 @@ function concurrencyReport(args) {
114
125
  limit: HARD_CONCURRENCY_LIMIT,
115
126
  reason: "strict-config accepted the reserved collaboration schema, max_concurrent_threads_per_session=20, and agents.max_depth=1",
116
127
  observedSource,
128
+ ...detail,
117
129
  };
118
130
  }
119
131
  function autoCompactionReport(args) {
@@ -5,7 +5,7 @@
5
5
  // argv into typed `InstallOptions`, and return an integer exit code. `--dry-run` returns BEFORE any
6
6
  // spawn or fs write (renders the plan only). Unknown/bad flags exit 1.
7
7
  import { spawnSync } from "node:child_process";
8
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
9
9
  import { createRequire } from "node:module";
10
10
  import { join } from "node:path";
11
11
  import readline from "node:readline/promises";
@@ -40,6 +40,7 @@ const realSpawn = (cmd, args, opts) => {
40
40
  shell: invocation.shell,
41
41
  windowsVerbatimArguments: invocation.windowsVerbatimArguments || opts.windowsVerbatimArguments === true,
42
42
  ...(opts.env === undefined ? {} : { env: opts.env }),
43
+ ...(opts.cwd === undefined ? {} : { cwd: opts.cwd }),
43
44
  });
44
45
  const out = {
45
46
  status: res.status,
@@ -384,6 +385,7 @@ export function runUninstallCli(args, io = defaultIo()) {
384
385
  existsSync,
385
386
  readdirSync: (path) => readdirSync(path),
386
387
  rmSync,
388
+ rmdirSync: (path) => rmdirSync(path),
387
389
  readFileSync: (path, enc) => readFileSync(path, enc),
388
390
  writeFileSync: (path, data) => {
389
391
  writeFileSync(path, data);
@@ -1,8 +1,10 @@
1
1
  import { type SpawnLike } from "./codex.js";
2
2
  export type StrictConfigProbe = {
3
3
  readonly kind: "accepted";
4
+ readonly warning?: string;
4
5
  } | {
5
6
  readonly kind: "rejected";
7
+ readonly detail?: string;
6
8
  } | {
7
9
  readonly kind: "timeout";
8
10
  };
@@ -13,7 +13,12 @@ export function probeStrictConfig(args) {
13
13
  if (existsSync(sourceConfig)) {
14
14
  writeFileSync(join(probeHome, "config.toml"), readFileSync(sourceConfig), { mode: 0o600 });
15
15
  }
16
- return runProbe({ ...args, env: { ...args.env, CODEX_HOME: probeHome } });
16
+ // cwd matters here: Codex resolves per-project trust/overlay state from the *caller's*
17
+ // cwd, not from CODEX_HOME. Inheriting the real caller cwd let an unrelated trusted
18
+ // project entry in the copied config.toml (e.g. `[projects."$HOME"]`) change how that
19
+ // same config parses, turning a healthy host into a false refusal. Pointing cwd at the
20
+ // disposable probe home keeps the result a function of the config content alone.
21
+ return runProbe({ ...args, env: { ...args.env, CODEX_HOME: probeHome }, cwd: probeHome });
17
22
  }
18
23
  finally {
19
24
  rmSync(probeHome, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
@@ -24,6 +29,7 @@ function runProbe(args) {
24
29
  stdio: "pipe",
25
30
  timeout: STRICT_CONFIG_PROBE_TIMEOUT_MS,
26
31
  ...(args.env === undefined ? {} : { env: args.env }),
32
+ ...(args.cwd === undefined ? {} : { cwd: args.cwd }),
27
33
  });
28
34
  if (isTimeout(result))
29
35
  return { kind: "timeout" };
@@ -31,7 +37,16 @@ function runProbe(args) {
31
37
  return { kind: "rejected" };
32
38
  try {
33
39
  const parsed = JSON.parse(result.stdout ?? "");
34
- return configLoadStatus(parsed) === "ok" ? { kind: "accepted" } : { kind: "rejected" };
40
+ const load = inspectConfigLoad(parsed);
41
+ if (load === null)
42
+ return { kind: "rejected" };
43
+ // A "warning" config.load status still parsed config.toml successfully — Codex is
44
+ // reporting something advisory (e.g. an ignored project-local key), not a load
45
+ // failure. Only a genuinely unparsable/failed load is a real rejection.
46
+ if (load.status === "ok" || (load.status === "warning" && load.parseOk)) {
47
+ return load.warning === undefined ? { kind: "accepted" } : { kind: "accepted", warning: load.warning };
48
+ }
49
+ return load.detail === undefined ? { kind: "rejected" } : { kind: "rejected", detail: load.detail };
35
50
  }
36
51
  catch (error) {
37
52
  if (error instanceof SyntaxError)
@@ -42,11 +57,25 @@ function runProbe(args) {
42
57
  function isTimeout(result) {
43
58
  return result.error instanceof Error && "code" in result.error && result.error.code === "ETIMEDOUT";
44
59
  }
45
- function configLoadStatus(value) {
60
+ function inspectConfigLoad(value) {
46
61
  if (!isRecord(value) || !isRecord(value["checks"]) || !isRecord(value["checks"]["config.load"]))
47
62
  return null;
48
- const status = value["checks"]["config.load"]["status"];
49
- return typeof status === "string" ? status : null;
63
+ const check = value["checks"]["config.load"];
64
+ const status = check["status"];
65
+ if (typeof status !== "string")
66
+ return null;
67
+ const details = isRecord(check["details"]) ? check["details"] : {};
68
+ const parseOk = details["config.toml parse"] === "ok";
69
+ const warning = typeof details["startup warning"] === "string" ? details["startup warning"] : undefined;
70
+ const notes = Array.isArray(check["notes"]) ? check["notes"].filter((note) => typeof note === "string") : [];
71
+ const summary = typeof check["summary"] === "string" ? check["summary"] : undefined;
72
+ const detailParts = [summary, ...notes].filter((part) => part !== undefined && part.length > 0);
73
+ return {
74
+ status,
75
+ parseOk,
76
+ ...(warning === undefined ? {} : { warning }),
77
+ ...(detailParts.length === 0 ? {} : { detail: detailParts.join(": ") }),
78
+ };
50
79
  }
51
80
  function isRecord(value) {
52
81
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -6,6 +6,8 @@ export interface UninstallFs {
6
6
  recursive?: boolean;
7
7
  force?: boolean;
8
8
  }): void;
9
+ /** Removes an empty directory only; must throw (not silently recurse) if the directory is non-empty. */
10
+ rmdirSync?(path: string): void;
9
11
  lstatSync?(path: string): {
10
12
  isSymbolicLink(): boolean;
11
13
  isDirectory(): boolean;
@@ -3,6 +3,7 @@ import { lstatSync as nativeLstatSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { removeSubagentDefaults } from "../config-migration/multi-agent-v2-guard.js";
5
5
  import { ensureNativeDefaultAgentConfig } from "../config-migration/native-default-route.js";
6
+ import { GPT56_PROFILE_FILE_NAMES, isManagedGpt56ProfileContent } from "../config-migration/profile-files.js";
6
7
  import { NATIVE_DEFAULT_AGENT_FILE } from "./agent-routing.js";
7
8
  import { prepareAgentSources } from "./agents-install.js";
8
9
  import { isSafeManagedMarketplaceRoot, LITCODEX_MARKETPLACE, LITCODEX_PLUGIN_REF, managedMarketplaceRoot, } from "./marketplace.js";
@@ -25,6 +26,7 @@ export function runUninstall(deps) {
25
26
  }
26
27
  removeManagedAgents(deps);
27
28
  removeManagedSubagentDefaults(deps);
29
+ removeManagedProfileFiles(deps);
28
30
  return { ok: pluginOk && marketplaceOk, codexHome: deps.codexHome };
29
31
  }
30
32
  function isSafeUninstallPaths(deps) {
@@ -102,6 +104,38 @@ function removeManagedAgents(deps) {
102
104
  catch {
103
105
  // Best-effort agent cleanup must not hide the authoritative Codex removal result.
104
106
  }
107
+ removeIfEmptyDirectory(deps, agentsDir);
108
+ }
109
+ /** Best-effort per-model profile removal: only files whose content matches what LitCodex generates. */
110
+ function removeManagedProfileFiles(deps) {
111
+ if (!isDirectoryNonSymlink(deps, deps.codexHome) || deps.fs.readFileSync === undefined)
112
+ return;
113
+ for (const name of GPT56_PROFILE_FILE_NAMES) {
114
+ const path = join(deps.codexHome, name);
115
+ if (!isRegularNonSymlink(deps, path))
116
+ continue;
117
+ try {
118
+ const content = deps.fs.readFileSync(path, "utf8");
119
+ if (isManagedGpt56ProfileContent(name, content))
120
+ deps.fs.rmSync(path);
121
+ }
122
+ catch {
123
+ // Preserve unreadable or unremovable profiles while checking the rest.
124
+ }
125
+ }
126
+ }
127
+ /** Non-recursive: only removes a managed directory that install created and that is now empty. */
128
+ function removeIfEmptyDirectory(deps, path) {
129
+ if (deps.fs.rmdirSync === undefined || !isDirectoryNonSymlink(deps, path))
130
+ return;
131
+ try {
132
+ if (deps.fs.readdirSync(path).length > 0)
133
+ return;
134
+ deps.fs.rmdirSync(path);
135
+ }
136
+ catch {
137
+ // A non-empty or otherwise unremovable directory is left in place.
138
+ }
105
139
  }
106
140
  const MANAGED_DEFAULT_HEADER = [
107
141
  'name = "default"',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litcodex",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Codex plugin: the lit-loop activation, durable loop runtime, and local review-gated knowledge.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/auto-update",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex foreground update barrier for the SessionStart and management lifecycles.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/comment-checker",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Comment-Checker hook: flags low-value / AI-slop comments introduced by edits.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/git-bash",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Git-Bash hook: reminds Windows sessions to prefer the git_bash MCP before the built-in shell.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lit-loop",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Lit-Loop runtime: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lsp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex LSP hook (inert placeholder): post-edit diagnostics + cache reset, no-op until an LSP daemon is provided.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/rules",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex rules: injects project rule files (AGENTS.md etc.) into model context through lifecycle hooks.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/start-work-continuation",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Start-Work continuation hook: resumes in-flight start-work state on root Stop.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/telemetry",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex telemetry: a deliberately inert, local-only SessionStart hook (NO network, NO data collection).",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/wikify-knowledge",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Local review-gated knowledge records for the LitCodex Wikify surface.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lit-loop",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "LitCodex Lit-Loop runtime: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
5
5
  "type": "module",
6
6
  "private": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litfamily/litcodex",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Codex loop harness installer. Run `npm exec --package @litfamily/litcodex -- litcodex install` to set up the LitCodex Codex platform: the bare `lit` hook and the durable lit-loop runtime.",
5
5
  "keywords": [
6
6
  "codex",
@@ -43,7 +43,7 @@
43
43
  "readme-assets"
44
44
  ],
45
45
  "dependencies": {
46
- "@litcodex/lit-loop": "1.0.0"
46
+ "@litcodex/lit-loop": "1.0.1"
47
47
  },
48
48
  "bundledDependencies": [
49
49
  "@litcodex/lit-loop"
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.0"><title>release: 1.0.0</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.0</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.1"><title>release: 1.0.1</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.1</text></g></svg>