@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 +15 -15
- package/dist/config-migration/profile-files.d.ts +4 -0
- package/dist/config-migration/profile-files.js +22 -0
- package/dist/install/capability-preflight-error.js +5 -1
- package/dist/install/codex.d.ts +1 -0
- package/dist/install/host-capabilities.d.ts +2 -0
- package/dist/install/host-capabilities.js +13 -1
- package/dist/install/index.js +3 -1
- package/dist/install/strict-config-probe.d.ts +2 -0
- package/dist/install/strict-config-probe.js +34 -5
- package/dist/install/uninstall.d.ts +2 -0
- package/dist/install/uninstall.js +34 -0
- package/marketplace/plugins/litcodex/.codex-plugin/plugin.json +1 -1
- package/marketplace/plugins/litcodex/components/auto-update/package.json +1 -1
- package/marketplace/plugins/litcodex/components/comment-checker/package.json +1 -1
- package/marketplace/plugins/litcodex/components/git-bash/package.json +1 -1
- package/marketplace/plugins/litcodex/components/lit-loop/package.json +1 -1
- package/marketplace/plugins/litcodex/components/lsp/package.json +1 -1
- package/marketplace/plugins/litcodex/components/rules/package.json +1 -1
- package/marketplace/plugins/litcodex/components/start-work-continuation/package.json +1 -1
- package/marketplace/plugins/litcodex/components/telemetry/package.json +1 -1
- package/marketplace/plugins/litcodex/components/wikify-knowledge/package.json +1 -1
- package/node_modules/@litcodex/lit-loop/package.json +1 -1
- package/package.json +2 -2
- package/readme-assets/badge-version.svg +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.
|
|
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.
|
|
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.
|
|
36
|
-
<a href="https://github.com/wjgoarxiv/litcodex/blob/main/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litcodex@1.0.
|
|
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.
|
|
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> <a href="#install">Install</a> <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> <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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
119
|
-
`npm exec --yes --package @litfamily/litcodex@1.0.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
}
|
package/dist/install/codex.d.ts
CHANGED
|
@@ -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 {
|
|
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) {
|
package/dist/install/index.js
CHANGED
|
@@ -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);
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
60
|
+
function inspectConfigLoad(value) {
|
|
46
61
|
if (!isRecord(value) || !isRecord(value["checks"]) || !isRecord(value["checks"]["config.load"]))
|
|
47
62
|
return null;
|
|
48
|
-
const
|
|
49
|
-
|
|
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/lit-loop",
|
|
3
|
-
"version": "1.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/lit-loop",
|
|
3
|
-
"version": "1.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.
|
|
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.
|
|
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.
|
|
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>
|