@amsterdamdatalabs/enact-extensions 0.1.56 → 0.1.58
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 +37 -27
- package/dist/internal/file-ops.d.ts.map +1 -1
- package/dist/internal/file-ops.js +5 -1
- package/dist/internal/file-ops.js.map +1 -1
- package/extensions/enact-repo/.agents/plugin.json +1 -1
- package/extensions/enact-repo/README.md +22 -11
- package/package.json +1 -1
- package/scripts/enact-extensions.mjs +26 -18
- package/scripts/lib/run-repo-doctor.mjs +51 -47
- package/scripts/lib/run-repo-install.mjs +311 -899
package/README.md
CHANGED
|
@@ -58,11 +58,11 @@ node scripts/enact-extensions.mjs sync extensions/plugin-dev
|
|
|
58
58
|
node scripts/enact-extensions.mjs list
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
`install` / `uninstall` / `doctor`
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
`install` / `uninstall` / `doctor` accept any bundle resolvable by bare name or
|
|
62
|
+
explicit plugin path, and only in repo-local `--repo <path>` form.
|
|
63
|
+
[`bundled-extensions.json`](bundled-extensions.json) names the default bundle set;
|
|
64
|
+
it is not an install or doctor allow-list. An unknown or unresolvable bundle fails
|
|
65
|
+
clearly before anything is touched.
|
|
66
66
|
|
|
67
67
|
### Repo-local install (`--repo`)
|
|
68
68
|
|
|
@@ -71,41 +71,50 @@ Install a bundle **into a git repository** as committed, relative files, followi
|
|
|
71
71
|
```bash
|
|
72
72
|
enact-extensions install enact-repo --repo <path> [--host claude,codex,cursor,kimi,opencode] [--force]
|
|
73
73
|
enact-extensions install enact-repo --repo <path> --dry-run # preview; writes nothing
|
|
74
|
-
enact-extensions uninstall enact-repo --repo <path> [--purge]
|
|
74
|
+
enact-extensions uninstall enact-repo --repo <path> [--purge]
|
|
75
75
|
enact-extensions uninstall enact-repo --repo <path> --dry-run [--purge] # preview; writes nothing
|
|
76
76
|
enact-extensions doctor enact-repo --repo <path> [--json] # read-only health check
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
`<path>` must be the git repository root (not a subdirectory, not `$HOME`)
|
|
79
|
+
`<path>` must be the git repository root (not a subdirectory, not `$HOME`) and must
|
|
80
|
+
already contain a regular, non-symlink root `enact-config.toml`. Install is
|
|
81
|
+
reconciliation, never enrollment: an unmarked repository is refused before any
|
|
82
|
+
file is read or written. `--host` defaults to every repo host the bundle targets.
|
|
80
83
|
|
|
81
|
-
`--dry-run` prints exactly what would be
|
|
84
|
+
`--dry-run` prints exactly what would be deleted or rebuilt — one line per file,
|
|
85
|
+
naming the action and reason — and exits with the same success/failure a real run
|
|
86
|
+
would, without touching the filesystem. `install --force` is an explicit,
|
|
87
|
+
announced request for the same authoritative repair performed by a normal install;
|
|
88
|
+
it never enables a merge, preservation, or restore path.
|
|
82
89
|
|
|
83
90
|
`doctor enact-repo --repo <path>` is read-only. It reports the installed and current
|
|
84
91
|
bundle versions, lock integrity and drift, and each host's lock-owned native paths.
|
|
85
92
|
It also reports Codex and Kimi trust notes, Cursor MCP approval, Kimi's global-hook
|
|
86
|
-
status, required global binaries, the root `enact-config.toml`
|
|
87
|
-
an optional `enact-hook doctor --repo` result, and
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
status, required global binaries, the root `enact-config.toml` marker and whether its
|
|
94
|
+
`[extensions]` roster is present, an optional `enact-hook doctor --repo` result, and
|
|
95
|
+
the per-repo hook logs. A pre-existing regular marker without `[extensions]` is valid
|
|
96
|
+
for doctor; install adds this extension's roster declaration. Doctor never writes; it
|
|
97
|
+
exits non-zero only for a hard requirement such as a missing install, lock-integrity
|
|
98
|
+
failure, missing required binary, or missing/invalid root marker.
|
|
99
|
+
|
|
100
|
+
| Host | Canonical files rebuilt in the repo |
|
|
93
101
|
| --- | --- |
|
|
94
|
-
| Claude Code | `.claude/agents/*.md`, `.claude/skills/<skill>/`, root `.mcp.json`, and
|
|
102
|
+
| Claude Code | `.claude/agents/*.md`, `.claude/skills/<skill>/`, root `.mcp.json`, and `.claude/settings.json`. Trust the folder before loading the project configuration. |
|
|
95
103
|
| Codex | `.codex/agents/*.toml`, `.agents/skills/<skill>/`, `.codex/config.toml` MCP tables, and `.codex/hooks.json`. Trust the exact project path and review hooks with `/hooks`. |
|
|
96
104
|
| Cursor | `.cursor/agents/*.md`, `.cursor/skills/<skill>/`, `.cursor/mcp.json`, and `.cursor/hooks.json`. |
|
|
97
105
|
| Kimi Code | `.kimi-code/agents/*.md`, `.kimi-code/skills/<skill>/`, and `.kimi-code/mcp.json`. Kimi hooks remain global-only and are installed by `enact-vps`, never by this repo-local command. |
|
|
98
|
-
| OpenCode | `.opencode/agents/*.md`, `.opencode/skills/<skill>/`, and root `opencode.json
|
|
106
|
+
| OpenCode | `.opencode/agents/*.md`, `.opencode/skills/<skill>/`, and root `opencode.json`. The repo-local installer also removes the retired `.opencode/plugins` root. |
|
|
99
107
|
|
|
100
108
|
Skills are installed at each host's native project discovery path: `.agents/skills/` for
|
|
101
109
|
Codex and `.claude/skills/`, `.cursor/skills/`, `.kimi-code/skills/`, or
|
|
102
|
-
`.opencode/skills/` for the other hosts.
|
|
103
|
-
|
|
110
|
+
`.opencode/skills/` for the other hosts. These paths are components of authoritative
|
|
111
|
+
roots, so stale, foreign, or drifted entries are deleted and regenerated from the
|
|
112
|
+
bundle on every reconciliation.
|
|
104
113
|
|
|
105
|
-
`lean-ctx` config: regardless of `--host`, the bundle's baseline `lean-ctx/config.toml` and `lean-ctx/layout.toml` are installed as
|
|
114
|
+
`lean-ctx` config: regardless of `--host`, the bundle's baseline `lean-ctx/config.toml` and `lean-ctx/layout.toml` are installed as canonical whole files at `.agents/lean-ctx/config/lean-ctx/` — every host's `.mcp.json`/hooks equivalent runs `enact-hook lean-ctx ...`, which resolves its config from this repo-local path. Drift is repaired by replacing the owned file; uninstall does not restore prior content.
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
`[extensions.<name>]` declaration for the installed bundle. The shared file's tables
|
|
116
|
+
Install text-surgeries only the pre-existing root `enact-config.toml`'s `[extensions]`
|
|
117
|
+
scope and the bare `[extensions.<name>]` declaration for the installed bundle. The shared file's tables
|
|
109
118
|
have one owner: `version`/`[hooks]`/`[rules]`/`[repo]` are `enact-hook`,
|
|
110
119
|
`[extensions]` is enact-extensions, and `[controls]` is enact-repo-controls. The
|
|
111
120
|
installer edits only its own block, removes the legacy marker-only `[skills]` block,
|
|
@@ -113,12 +122,13 @@ and never writes `[hooks]`. It also manages the baseline `lean-ctx` config,
|
|
|
113
122
|
`.agents/.gitignore` runtime entries, and `.agents/enact-repo.lock.json`. Commit all
|
|
114
123
|
of it except what `.gitignore` excludes.
|
|
115
124
|
|
|
116
|
-
The lock records every managed file (sha256),
|
|
125
|
+
The lock records every canonical managed file (sha256), the owned roots, and the
|
|
126
|
+
plugin version, all as relative paths. Its reconciliation contract is:
|
|
117
127
|
|
|
118
|
-
- **Re-runs are idempotent.** An unchanged bundle produces
|
|
119
|
-
- **
|
|
120
|
-
- **
|
|
121
|
-
- **Uninstall removes
|
|
128
|
+
- **Re-runs are idempotent.** An unchanged bundle produces byte-identical owned files.
|
|
129
|
+
- **Roots are rebuilt, never merged.** `.agents`, `.claude`, `.codex`, `.cursor`, `.kimi-code`, and `.opencode` are Enact-owned roots. Reconciliation deletes their contents and writes only the canonical projection; it also deletes retired `.claude-plugin`, `.codex-plugin`, `.cursor-plugin`, `.kimi-plugin`, and `.opencode/plugins` roots.
|
|
130
|
+
- **Runtime boundaries are explicit.** `.agents/hooks/` and `.agents/lean-ctx/{data,cache,state,bin}/` remain outside Enact ownership; their writers retain them through install and both uninstall modes.
|
|
131
|
+
- **Uninstall removes the authoritative deployment.** It removes Enact-owned native roots and the extension declaration, without restoring foreign or prior files. `enact-config.toml` remains a pre-existing central marker; `--purge` additionally cuts an `[extensions]` block this installer appended, using text-level surgery only.
|
|
122
132
|
|
|
123
133
|
Install the CLI itself globally (the CLI binary only — no plugins, no host config):
|
|
124
134
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../src/internal/file-ops.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,4EAA4E;IAC5E,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACvE,iDAAiD;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C,4EAA4E;IAC5E,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,kDAAkD;IAClD,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjD,gDAAgD;IAChD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2CAA2C;IAC3C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,iDAAiD;IACjD,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtD;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../src/internal/file-ops.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,4EAA4E;IAC5E,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACvE,iDAAiD;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C,4EAA4E;IAC5E,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,kDAAkD;IAClD,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjD,gDAAgD;IAChD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2CAA2C;IAC3C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,iDAAiD;IACjD,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtD;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAmFzF"}
|
|
@@ -39,8 +39,12 @@ export function makeFileOps(repo, dryRun, actions) {
|
|
|
39
39
|
if (!existsSync(path))
|
|
40
40
|
return false;
|
|
41
41
|
actions.push({ file: rel, action: "remove-dir", reason: reason ?? "directory" });
|
|
42
|
+
// macOS may create .DS_Store while Finder or a launched host observes a
|
|
43
|
+
// root being rebuilt. Retry Node's documented transient recursive-delete
|
|
44
|
+
// errors (including ENOTEMPTY) rather than leaving an owned root half
|
|
45
|
+
// removed.
|
|
42
46
|
if (!dryRun)
|
|
43
|
-
rmSync(path, { recursive: true, force: true });
|
|
47
|
+
rmSync(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
44
48
|
return true;
|
|
45
49
|
},
|
|
46
50
|
rmdirIfEmpty(rel) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-ops.js","sourceRoot":"","sources":["../../src/internal/file-ops.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"file-ops.js","sourceRoot":"","sources":["../../src/internal/file-ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enact-repo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Baseline agent setup for any repository: the full Enact skill catalog plus guard, briefing, and code-review-graph hooks and MCP tooling, installed at repo scope.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "amsterdamdatalabs"
|
|
@@ -69,8 +69,9 @@ host, with no `--host` appended.
|
|
|
69
69
|
|
|
70
70
|
## Repo-local install
|
|
71
71
|
|
|
72
|
-
Install into
|
|
73
|
-
top-level README, "Repo-local install").
|
|
72
|
+
Install into an already centrally managed repository with `enact-extensions install enact-repo --repo <repo-root>`
|
|
73
|
+
(see the top-level README, "Repo-local install"). Root `enact-config.toml` must already exist;
|
|
74
|
+
install is reconciliation, not enrollment. The command writes direct native project files only:
|
|
74
75
|
`.claude/agents` and `.claude/skills`; `.codex/agents` and `.agents/skills`;
|
|
75
76
|
`.cursor/agents` and `.cursor/skills`; `.kimi-code/agents` and `.kimi-code/skills`; and
|
|
76
77
|
`.opencode/agents` and `.opencode/skills`. It also writes each host's
|
|
@@ -78,18 +79,28 @@ native MCP and hook configuration where supported. It never writes a plugin root
|
|
|
78
79
|
or plugin registration.
|
|
79
80
|
Kimi hooks are global-only and are installed by `enact-vps`, not by this bundle. OpenCode's
|
|
80
81
|
process-level hook carrier is separate from this repo-local installer; OpenCode bundles always
|
|
81
|
-
install their native local files and remove
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
`[
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
install their native local files and remove legacy plugin roots. The installer rebuilds the owned
|
|
83
|
+
roots `.agents`, `.claude`, `.codex`, `.cursor`, `.kimi-code`, and `.opencode` from the canonical
|
|
84
|
+
bundle on every run: stale, foreign, and drifted content is deleted, never merged, adopted, or
|
|
85
|
+
restored. It removes the retired `.claude-plugin`, `.codex-plugin`, `.cursor-plugin`,
|
|
86
|
+
`.kimi-plugin`, and `.opencode/plugins` roots. It modifies only `[extensions]` in the pre-existing
|
|
87
|
+
marker through text-level surgery, removes the legacy marker-only `[skills]` block, and never
|
|
88
|
+
writes `[hooks]`. The baseline `lean-ctx/config.toml` and `lean-ctx/layout.toml` live at
|
|
89
|
+
`.agents/lean-ctx/config/lean-ctx/`. The explicit unmanaged runtime boundaries are
|
|
90
|
+
`.agents/hooks/` and `.agents/lean-ctx/{data,cache,state,bin}/`; they are written by their own
|
|
91
|
+
runtimes and ignored via `.agents/.gitignore` (`/lean-ctx/data/`,
|
|
90
92
|
`/lean-ctx/cache/`, `/lean-ctx/state/`, `/lean-ctx/bin/` — the `config/` dir itself stays
|
|
91
93
|
committed).
|
|
92
94
|
|
|
95
|
+
## Commands
|
|
96
|
+
|
|
97
|
+
The authoritative bundle currently declares no `commands/` source. A 2026-09-18 audit of
|
|
98
|
+
`test-repo-only-for-global-tools-m5` found native agent profiles but no native command artifact.
|
|
99
|
+
The installer therefore does not invent a command projection. Documented future repo-local command
|
|
100
|
+
paths are `.claude/commands/` (frontmatter Markdown), `.cursor/commands/` (plain Markdown), and
|
|
101
|
+
`.opencode/commands/` (frontmatter Markdown); Codex has no documented project-local command path.
|
|
102
|
+
Command projection remains pending a canonical Enact command source.
|
|
103
|
+
|
|
93
104
|
## Canonical install path
|
|
94
105
|
|
|
95
106
|
The canonical install entrypoint is `extensions/enact-repo/.agents/plugin.json`. `enact-extensions
|
package/package.json
CHANGED
|
@@ -37,17 +37,16 @@ Usage:
|
|
|
37
37
|
enact-extensions sync [path|name] Sync host manifests from .agents/plugin.json (default: cwd)
|
|
38
38
|
enact-extensions sync [path|name] --name <id> Create .agents/plugin.json then sync (new plugin)
|
|
39
39
|
enact-extensions install <name> --repo <path> [--host claude,codex,cursor,kimi,opencode] [--force]
|
|
40
|
-
|
|
41
|
-
(
|
|
42
|
-
enact-extensions install <name> --repo <path> --dry-run Print exactly what install would write
|
|
40
|
+
Rebuild Enact-owned native roots in an already marked git repo
|
|
41
|
+
(state in .agents/<name>.lock.json)
|
|
42
|
+
enact-extensions install <name> --repo <path> --dry-run Print exactly what install would delete/write, per
|
|
43
43
|
file (action + reason), and exit with the same success/failure
|
|
44
44
|
the real run would have. Touches nothing.
|
|
45
|
-
enact-extensions uninstall <name> --repo <path> [--purge]
|
|
46
|
-
Remove
|
|
47
|
-
|
|
48
|
-
file itself if install created it and only version = 1 remains)
|
|
45
|
+
enact-extensions uninstall <name> --repo <path> [--purge]
|
|
46
|
+
Remove the authoritative native roots and this extension declaration
|
|
47
|
+
(--purge also cuts a table this extension appended)
|
|
49
48
|
enact-extensions uninstall <name> --repo <path> --dry-run [--purge]
|
|
50
|
-
Print exactly what uninstall would remove
|
|
49
|
+
Print exactly what uninstall would remove, per file
|
|
51
50
|
(action + reason), and exit with the same success/failure the
|
|
52
51
|
real run would have. Touches nothing.
|
|
53
52
|
enact-extensions doctor enact-repo --repo <path> [--json]
|
|
@@ -72,15 +71,15 @@ Options:
|
|
|
72
71
|
--stdout (index only) Alias for --out -.
|
|
73
72
|
--json (list/doctor) Emit JSON to stdout instead of human output.
|
|
74
73
|
--name <id> (sync only) Plugin name for a new .agents/plugin.json.
|
|
75
|
-
--repo <path> (install/uninstall/doctor) Target
|
|
76
|
-
|
|
74
|
+
--repo <path> (install/uninstall/doctor) Target an already marked git repository root at <path>.
|
|
75
|
+
Root enact-config.toml is required; never writes under $HOME or absolute paths.
|
|
77
76
|
--host <list> (install --repo) Hosts to install for: claude,codex,cursor,kimi,opencode
|
|
78
77
|
(default: every repo host the bundle targets).
|
|
79
78
|
--dry-run (install/uninstall --repo) Print exactly what would change, per file, and
|
|
80
79
|
exit with the same success/failure the real run would have. Writes nothing.
|
|
81
|
-
--force (install
|
|
82
|
-
|
|
83
|
-
--purge (uninstall --repo) Also
|
|
80
|
+
--force (install --repo) Explicitly request the authoritative repair. It deletes and
|
|
81
|
+
rebuilds the same owned roots as every install; it never preserves or restores foreign content.
|
|
82
|
+
--purge (uninstall --repo) Also cut an [extensions] block this extension appended.
|
|
84
83
|
|
|
85
84
|
Name resolution (bare plugin names):
|
|
86
85
|
When a bare name (no "/" in it) is given, it is resolved in this order:
|
|
@@ -99,7 +98,7 @@ Examples:
|
|
|
99
98
|
enact-extensions install enact-repo --repo ~/code/my-service --host claude,cursor
|
|
100
99
|
enact-extensions install enact-repo --repo . --dry-run Preview the plan; writes nothing
|
|
101
100
|
enact-extensions uninstall enact-repo --repo . --purge
|
|
102
|
-
enact-extensions uninstall enact-repo --repo . --dry-run Preview what would be removed
|
|
101
|
+
enact-extensions uninstall enact-repo --repo . --dry-run Preview what would be removed
|
|
103
102
|
enact-extensions doctor enact-repo --repo . Read-only health check
|
|
104
103
|
enact-extensions doctor enact-repo --repo . --json
|
|
105
104
|
`;
|
|
@@ -154,12 +153,12 @@ function parseArgs(argv) {
|
|
|
154
153
|
options.repo = argv[++i];
|
|
155
154
|
} else if (arg === "--host" && argv[i + 1]) {
|
|
156
155
|
options.host = argv[++i];
|
|
157
|
-
} else if (arg === "--force") {
|
|
158
|
-
options.force = true;
|
|
159
156
|
} else if (arg === "--purge") {
|
|
160
157
|
options.purge = true;
|
|
161
158
|
} else if (arg === "--dry-run") {
|
|
162
159
|
options.dryRun = true;
|
|
160
|
+
} else if (arg === "--force") {
|
|
161
|
+
options.force = true;
|
|
163
162
|
} else if (arg === "--json") {
|
|
164
163
|
options.json = true;
|
|
165
164
|
} else if (arg === "-h" || arg === "--help") {
|
|
@@ -205,7 +204,10 @@ try {
|
|
|
205
204
|
!["install", "uninstall"].includes(command) &&
|
|
206
205
|
(options.force || options.purge || options.host || options.dryRun)
|
|
207
206
|
) {
|
|
208
|
-
fail("--host/--
|
|
207
|
+
fail("--host/--purge/--dry-run/--force only apply to install|uninstall <name> --repo <path>");
|
|
208
|
+
}
|
|
209
|
+
if (options.force && command !== "install") {
|
|
210
|
+
fail("--force applies only to install <name> --repo <path>");
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
function printRepoDoctorReport(report) {
|
|
@@ -530,7 +532,12 @@ try {
|
|
|
530
532
|
}
|
|
531
533
|
const result =
|
|
532
534
|
command === "install"
|
|
533
|
-
? runRepoInstall(pluginRoot, {
|
|
535
|
+
? runRepoInstall(pluginRoot, {
|
|
536
|
+
repo: options.repo,
|
|
537
|
+
host: options.host,
|
|
538
|
+
force: options.force,
|
|
539
|
+
dryRun,
|
|
540
|
+
})
|
|
534
541
|
: runRepoUninstall(repoPluginName, { repo: options.repo, purge: options.purge, force: options.force, dryRun });
|
|
535
542
|
if (dryRun) {
|
|
536
543
|
if (result.actions.length === 0) {
|
|
@@ -539,6 +546,7 @@ try {
|
|
|
539
546
|
for (const a of result.actions) {
|
|
540
547
|
console.log(`[dry-run] would ${a.action}: ${a.file} — ${a.reason}`);
|
|
541
548
|
}
|
|
549
|
+
console.log(`would change ${result.actions.length} file(s)`);
|
|
542
550
|
}
|
|
543
551
|
}
|
|
544
552
|
exit(0);
|
|
@@ -10,10 +10,9 @@
|
|
|
10
10
|
* - plugin version vs bundle version (outdated?), plus per-file content
|
|
11
11
|
* drift against what the CURRENT
|
|
12
12
|
* bundle would generate
|
|
13
|
-
* - lock integrity (every managed file
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* or missing)
|
|
13
|
+
* - lock integrity (every canonical managed file
|
|
14
|
+
* present + hash match; no foreign
|
|
15
|
+
* content inside owned roots)
|
|
17
16
|
* - per-host status: direct native files recorded in the lock (never a
|
|
18
17
|
* plugin root or marketplace), codex (files present; read-only
|
|
19
18
|
* ~/.codex/config.toml projects."<repo>".trust_level; hooks-review-
|
|
@@ -48,21 +47,21 @@
|
|
|
48
47
|
|
|
49
48
|
import { spawnSync } from "node:child_process";
|
|
50
49
|
import { createHash } from "node:crypto";
|
|
51
|
-
import { existsSync, lstatSync, readFileSync, readlinkSync } from "node:fs";
|
|
50
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, readlinkSync } from "node:fs";
|
|
52
51
|
import { homedir } from "node:os";
|
|
53
52
|
import { basename, join } from "node:path";
|
|
54
53
|
import * as TOML from "@iarna/toml";
|
|
55
|
-
import {
|
|
54
|
+
import { findBlock } from "../../dist/index.js";
|
|
56
55
|
import {
|
|
57
56
|
abs,
|
|
58
57
|
buildPlan,
|
|
59
58
|
CONFIG_PATH,
|
|
60
59
|
fileSha,
|
|
61
60
|
HOOK_LOG_FILES,
|
|
61
|
+
inspectExtensionsScope,
|
|
62
62
|
lockRel,
|
|
63
63
|
REPO_HOSTS,
|
|
64
64
|
readBundle,
|
|
65
|
-
readJsonStrict,
|
|
66
65
|
readLock,
|
|
67
66
|
resolveRepoRoot,
|
|
68
67
|
sha256,
|
|
@@ -299,8 +298,8 @@ function runHookDoctor(repo, enactHook) {
|
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
// ---------------------------------------------------------------------------
|
|
302
|
-
// lock integrity — every managed file present + hash match
|
|
303
|
-
//
|
|
301
|
+
// lock integrity — every canonical managed file present + hash match, plus
|
|
302
|
+
// no foreign content inside an owned root.
|
|
304
303
|
// ---------------------------------------------------------------------------
|
|
305
304
|
function checkLockIntegrity(repo, name, lock) {
|
|
306
305
|
const missingFiles = [];
|
|
@@ -309,24 +308,6 @@ function checkLockIntegrity(repo, name, lock) {
|
|
|
309
308
|
if (!existsSync(abs(repo, rel))) missingFiles.push(rel);
|
|
310
309
|
else if (fileSha(repo, rel) !== want) driftedFiles.push(rel);
|
|
311
310
|
}
|
|
312
|
-
const jsonIssues = [];
|
|
313
|
-
for (const [rel, record] of Object.entries(lock.merged)) {
|
|
314
|
-
const path = abs(repo, rel);
|
|
315
|
-
if (!existsSync(path)) {
|
|
316
|
-
jsonIssues.push(`${rel} (file missing)`);
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
let doc;
|
|
320
|
-
try {
|
|
321
|
-
doc = readJsonStrict(path, rel);
|
|
322
|
-
} catch (err) {
|
|
323
|
-
jsonIssues.push(`${rel} (${err instanceof Error ? err.message : String(err)})`);
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
for (const entry of record.entries) {
|
|
327
|
-
if (!entryPresent(doc, entry)) jsonIssues.push(`${rel} (${entry.path.join(".")})`);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
311
|
const tomlIssues = [];
|
|
331
312
|
for (const [rel, record] of Object.entries(lock.toml)) {
|
|
332
313
|
const path = abs(repo, rel);
|
|
@@ -358,13 +339,41 @@ function checkLockIntegrity(repo, name, lock) {
|
|
|
358
339
|
}
|
|
359
340
|
if (!existsSync(path)) symlinkIssues.push(`${rel} (dangling -> ${target})`);
|
|
360
341
|
}
|
|
342
|
+
const rootIssues = [];
|
|
343
|
+
for (const root of lock.ownedRoots ?? []) {
|
|
344
|
+
const expectedFiles = new Set(
|
|
345
|
+
[...Object.keys(lock.files ?? {}), lockRel(name)].filter((rel) => rel.startsWith(`${root}/`)),
|
|
346
|
+
);
|
|
347
|
+
const expectedDirs = new Set([root]);
|
|
348
|
+
for (const rel of expectedFiles) {
|
|
349
|
+
const parts = rel.split("/");
|
|
350
|
+
for (let i = 1; i < parts.length; i++) expectedDirs.add(parts.slice(0, i).join("/"));
|
|
351
|
+
}
|
|
352
|
+
const boundaries = new Set((lock.unmanagedBoundaries ?? []).filter((rel) => rel.startsWith(`${root}/`)));
|
|
353
|
+
const visit = (rel) => {
|
|
354
|
+
if ([...boundaries].some((boundary) => rel === boundary || rel.startsWith(`${boundary}/`))) return;
|
|
355
|
+
const path = abs(repo, rel);
|
|
356
|
+
const state = lstatSync(path, { throwIfNoEntry: false });
|
|
357
|
+
if (!state) return;
|
|
358
|
+
if (!state.isDirectory() || state.isSymbolicLink()) {
|
|
359
|
+
if (!expectedFiles.has(rel)) rootIssues.push(`${rel} (foreign file)`);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!expectedDirs.has(rel)) {
|
|
363
|
+
rootIssues.push(`${rel} (foreign directory)`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
for (const entry of readdirSync(path, { withFileTypes: true })) visit(`${rel}/${entry.name}`);
|
|
367
|
+
};
|
|
368
|
+
if (existsSync(abs(repo, root))) visit(root);
|
|
369
|
+
}
|
|
361
370
|
const valid =
|
|
362
371
|
missingFiles.length === 0 &&
|
|
363
372
|
driftedFiles.length === 0 &&
|
|
364
|
-
jsonIssues.length === 0 &&
|
|
365
373
|
tomlIssues.length === 0 &&
|
|
366
|
-
symlinkIssues.length === 0
|
|
367
|
-
|
|
374
|
+
symlinkIssues.length === 0 &&
|
|
375
|
+
rootIssues.length === 0;
|
|
376
|
+
return { valid, missingFiles, driftedFiles, tomlIssues, symlinkIssues, rootIssues };
|
|
368
377
|
}
|
|
369
378
|
|
|
370
379
|
// ---------------------------------------------------------------------------
|
|
@@ -478,9 +487,9 @@ function checkMarker(repo) {
|
|
|
478
487
|
note: "missing -- enact-hook only acts in repos containing this file; re-run install",
|
|
479
488
|
};
|
|
480
489
|
}
|
|
481
|
-
let
|
|
490
|
+
let extensions;
|
|
482
491
|
try {
|
|
483
|
-
|
|
492
|
+
extensions = inspectExtensionsScope(readFileSync(path, "utf8"), "checking central-management marker");
|
|
484
493
|
} catch (err) {
|
|
485
494
|
return {
|
|
486
495
|
...base,
|
|
@@ -488,25 +497,20 @@ function checkMarker(repo) {
|
|
|
488
497
|
parses: false,
|
|
489
498
|
extensionsPresent: false,
|
|
490
499
|
valid: false,
|
|
491
|
-
note:
|
|
500
|
+
note: err instanceof Error ? err.message : String(err),
|
|
492
501
|
};
|
|
493
502
|
}
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
const extensionsPresent =
|
|
497
|
-
const declared = extensionsPresent
|
|
498
|
-
? Object.entries(doc.extensions)
|
|
499
|
-
.filter(([, v]) => v && typeof v === "object" && !Array.isArray(v))
|
|
500
|
-
.map(([k]) => k)
|
|
501
|
-
: [];
|
|
503
|
+
// The root file is the central-management marker. `[extensions]` is our
|
|
504
|
+
// optional roster, inspected only through its own textual scope.
|
|
505
|
+
const extensionsPresent = extensions.present;
|
|
502
506
|
return {
|
|
503
507
|
...base,
|
|
504
508
|
present: true,
|
|
505
509
|
parses: true,
|
|
506
510
|
extensionsPresent,
|
|
507
|
-
declared,
|
|
508
|
-
valid:
|
|
509
|
-
note: extensionsPresent ? undefined : "present
|
|
511
|
+
declared: extensions.declarations,
|
|
512
|
+
valid: true,
|
|
513
|
+
note: extensionsPresent ? undefined : "present; [extensions] roster will be added by install",
|
|
510
514
|
};
|
|
511
515
|
}
|
|
512
516
|
|
|
@@ -582,9 +586,9 @@ export function runRepoDoctor(pluginRoot, options = {}) {
|
|
|
582
586
|
if (!lockIntegrity.valid) {
|
|
583
587
|
problems.push(
|
|
584
588
|
`lock integrity: ${lockIntegrity.missingFiles.length} missing + ${lockIntegrity.driftedFiles.length} drifted managed file(s), ` +
|
|
585
|
-
`${lockIntegrity.
|
|
586
|
-
`${lockIntegrity.symlinkIssues.length} symlink issue(s) -- ` +
|
|
587
|
-
`re-run
|
|
589
|
+
`${lockIntegrity.tomlIssues.length} toml + ` +
|
|
590
|
+
`${lockIntegrity.symlinkIssues.length} symlink + ${lockIntegrity.rootIssues.length} owned-root issue(s) -- ` +
|
|
591
|
+
`re-run install to repair or uninstall to remove`,
|
|
588
592
|
);
|
|
589
593
|
}
|
|
590
594
|
|