esp-modkit 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +35 -0
- data/LICENSE +21 -0
- data/README.md +117 -0
- data/docs/architecture.md +125 -0
- data/docs/authoring-guide.md +206 -0
- data/docs/getting-started.md +183 -0
- data/docs/reference/api/active-project.md +22 -0
- data/docs/reference/api/agent.md +24 -0
- data/docs/reference/api/docs-generator.md +20 -0
- data/docs/reference/api/http-server.md +46 -0
- data/docs/reference/api/index.md +38 -0
- data/docs/reference/api/introspection.md +17 -0
- data/docs/reference/api/mcp-installer.md +26 -0
- data/docs/reference/api/mcp-server.md +27 -0
- data/docs/reference/api/mw-builder.md +14 -0
- data/docs/reference/api/mw-data-files.md +20 -0
- data/docs/reference/api/mw-dialogue-dsl.md +58 -0
- data/docs/reference/api/mw-i18n.md +20 -0
- data/docs/reference/api/mw-linter.md +18 -0
- data/docs/reference/api/mw-loader.md +26 -0
- data/docs/reference/api/mw-openmw-config.md +15 -0
- data/docs/reference/api/mw-operations.md +24 -0
- data/docs/reference/api/mw-preflight.md +17 -0
- data/docs/reference/api/mw-reference-index.md +21 -0
- data/docs/reference/api/mw-scaffolder.md +13 -0
- data/docs/reference/api/mw-script-blob.md +31 -0
- data/docs/reference/api/mw-script-extractor.md +17 -0
- data/docs/reference/api/operations.md +25 -0
- data/docs/reference/api/plugins.md +24 -0
- data/docs/reference/api/preferences.md +13 -0
- data/docs/reference/api/project-marker.md +23 -0
- data/docs/reference/api/providers.md +22 -0
- data/docs/reference/api/recents.md +17 -0
- data/docs/reference/api/ui.md +21 -0
- data/docs/reference/api/vcs.md +17 -0
- data/docs/reference/api/watcher.md +11 -0
- data/docs/reference/commands.md +271 -0
- data/docs/walkthrough.md +193 -0
- data/exe/esp +10 -0
- data/lib/esp/active_project.rb +71 -0
- data/lib/esp/agent.rb +104 -0
- data/lib/esp/cli/docs.rb +44 -0
- data/lib/esp/cli/i18n.rb +67 -0
- data/lib/esp/cli/mcp.rb +52 -0
- data/lib/esp/cli/plugins.rb +42 -0
- data/lib/esp/cli/refs.rb +137 -0
- data/lib/esp/cli/support.rb +87 -0
- data/lib/esp/cli.rb +317 -0
- data/lib/esp/docs_generator.rb +148 -0
- data/lib/esp/http_server.rb +232 -0
- data/lib/esp/introspection.rb +151 -0
- data/lib/esp/mcp_installer.rb +122 -0
- data/lib/esp/mcp_server.rb +465 -0
- data/lib/esp/mw/builder.rb +71 -0
- data/lib/esp/mw/data_files.rb +67 -0
- data/lib/esp/mw/dialogue_dsl.rb +209 -0
- data/lib/esp/mw/i18n.rb +113 -0
- data/lib/esp/mw/linter.rb +103 -0
- data/lib/esp/mw/loader.rb +130 -0
- data/lib/esp/mw/openmw_config.rb +138 -0
- data/lib/esp/mw/operations.rb +374 -0
- data/lib/esp/mw/preflight.rb +161 -0
- data/lib/esp/mw/reference_index.rb +182 -0
- data/lib/esp/mw/scaffolder.rb +197 -0
- data/lib/esp/mw/script_blob.rb +87 -0
- data/lib/esp/mw/script_extractor.rb +85 -0
- data/lib/esp/mw/tes3conv.rb +38 -0
- data/lib/esp/operations.rb +285 -0
- data/lib/esp/plugins.rb +75 -0
- data/lib/esp/preferences.rb +63 -0
- data/lib/esp/project_marker.rb +99 -0
- data/lib/esp/providers/anthropic.rb +74 -0
- data/lib/esp/providers/ollama.rb +102 -0
- data/lib/esp/providers/openai.rb +91 -0
- data/lib/esp/providers.rb +76 -0
- data/lib/esp/recents.rb +74 -0
- data/lib/esp/ui.rb +144 -0
- data/lib/esp/vcs.rb +112 -0
- data/lib/esp/version.rb +11 -0
- data/lib/esp/watcher.rb +55 -0
- data/lib/esp.rb +85 -0
- data/locales/en.yml +164 -0
- data/locales/fr.yml +10 -0
- metadata +241 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Mw::Scaffolder
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/mw/scaffolder.rb`
|
|
6
|
+
|
|
7
|
+
Scaffolds a fresh mod folder under `mods/<Mod>/`. One TES3 Header
|
|
8
|
+
record (pre-filled with sensible defaults), one README, and that's
|
|
9
|
+
it — no script / i18n / design subdirectories until the author
|
|
10
|
+
actually wants them. Picks the source format from `--format`;
|
|
11
|
+
subprocess formats get a `#!` line and exec bit.
|
|
12
|
+
|
|
13
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Mw::ScriptBlob
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/mw/script_blob.rb`
|
|
6
|
+
|
|
7
|
+
Synthesizes the ZSTD-framed blobs that tes3conv expects for a Script
|
|
8
|
+
record's SCVR (variable list) and SCDT (bytecode) subrecords.
|
|
9
|
+
|
|
10
|
+
Vanilla blobs use ZSTD frames whose blocks may be raw (small/empty
|
|
11
|
+
scripts) or compressed-with-LZ77 matches (large scripts). tes3conv
|
|
12
|
+
accepts either, so we always emit raw blocks — simpler, smaller code,
|
|
13
|
+
and only marginally larger output. Decoding always goes through
|
|
14
|
+
libzstd via zstd-ruby so we can extract names from any vanilla blob.
|
|
15
|
+
|
|
16
|
+
Raw frame layout:
|
|
17
|
+
4 bytes ZSTD magic (28 b5 2f fd)
|
|
18
|
+
1 byte Frame Header Descriptor (0x00)
|
|
19
|
+
1 byte Window Descriptor (0x58)
|
|
20
|
+
3 bytes Block header ((size << 3) | type<<1 | last_block)
|
|
21
|
+
N bytes Raw payload
|
|
22
|
+
|
|
23
|
+
Payload layout (both SCVR and SCDT placeholder):
|
|
24
|
+
4 bytes LE uint32 — byte length of names section (0 if none)
|
|
25
|
+
N bytes Null-terminated variable names, concatenated
|
|
26
|
+
|
|
27
|
+
Empty vars and the bytecode placeholder both use a 4-byte zero payload
|
|
28
|
+
(length prefix = 0). A truly zero-byte payload is rejected by tes3conv
|
|
29
|
+
for SCDT and isn't what vanilla emits anywhere.
|
|
30
|
+
|
|
31
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Mw::ScriptExtractor
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/mw/script_extractor.rb`
|
|
6
|
+
|
|
7
|
+
Inverse of preflight's text_source resolution. Given a JSON-format mod
|
|
8
|
+
source whose Script records carry inline `text`, hoist each script
|
|
9
|
+
body out to `scripts/<id>.mwscript` and replace the inline fields
|
|
10
|
+
(`text`, `bytecode`, `variables`, `header`) with a single
|
|
11
|
+
`text_source` pointer. Preflight regenerates everything on build, so
|
|
12
|
+
the resulting source round-trips losslessly through `esp build`.
|
|
13
|
+
|
|
14
|
+
Skips records that already have `text_source` set — re-running is a
|
|
15
|
+
no-op. .rb sources are out of scope; their author owns the layout.
|
|
16
|
+
|
|
17
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Operations
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/operations.rb`
|
|
6
|
+
|
|
7
|
+
Transport-agnostic service layer — the engine-agnostic shell half. One
|
|
8
|
+
method per operation, each taking a string-keyed params hash and
|
|
9
|
+
returning a plain Ruby hash. The HTTP API (`esp serve`) and the MCP
|
|
10
|
+
server (`esp mcp serve`) are thin shells over these methods plus the
|
|
11
|
+
active plugin's ops, so both frontends emit byte-identical payloads.
|
|
12
|
+
|
|
13
|
+
What's here vs. in the plugin (Esp::Mw::Operations): the ops that have
|
|
14
|
+
no Morrowind-specific concept — version/health/commands, the LLM
|
|
15
|
+
provider seam, project/workspace/preferences state, recents, the
|
|
16
|
+
git-diff review surface (the document under review is opaque to the
|
|
17
|
+
shell). The plugin owns build/lint/unpack/scaffold/i18n/refs/dialogue
|
|
18
|
+
and anything that decodes records.
|
|
19
|
+
|
|
20
|
+
Errors that are the caller's fault (missing field, no index, validation)
|
|
21
|
+
raise InputError; frontends map that to a 400 / tool-error. Lower
|
|
22
|
+
layers raise their own typed errors which both frontends also treat as
|
|
23
|
+
caller errors via the ERROR_CODES table below.
|
|
24
|
+
|
|
25
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Plugins
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/plugins.rb`
|
|
6
|
+
|
|
7
|
+
The game-plugin registry. Each plugin (Esp::Mw today; future Esp::Ob,
|
|
8
|
+
Esp::Sr) registers itself here at load time with a short `id` (the value
|
|
9
|
+
that lands in a project's `.espresso/project.json` `game:` field) and the
|
|
10
|
+
modules the frontends need to reach into — its Operations façade today.
|
|
11
|
+
|
|
12
|
+
The shell composes its routes/tools against this registry, so the only
|
|
13
|
+
thing tying the shell to a specific game is the project the user opens.
|
|
14
|
+
Add a plugin: drop `lib/esp/<id>/`, call `Esp::Plugins.register` from its
|
|
15
|
+
entry file, and add it to the load manifest.
|
|
16
|
+
|
|
17
|
+
Lookups are by id string; `default_id` names the plugin used when no
|
|
18
|
+
project is open (today: the first registered, which is `mw` because the
|
|
19
|
+
load manifest loads it first). Slice 2 wires Esp::Operations.dispatch
|
|
20
|
+
through `Esp::Plugins.active_for(input)` so an op like `build` reaches
|
|
21
|
+
the plugin matching the active project's `game:` field rather than
|
|
22
|
+
always Esp::Mw::Operations.
|
|
23
|
+
|
|
24
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Preferences
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/preferences.rb`
|
|
6
|
+
|
|
7
|
+
Per-user preferences persisted as JSON alongside the recents file at
|
|
8
|
+
ESP_DATA_DIR/preferences.json. Today: just `mods_home` (the directory the
|
|
9
|
+
Open Project picker starts in / New Project scaffolds into). More keys to
|
|
10
|
+
come; the merge-with-defaults read keeps backward compatibility as the
|
|
11
|
+
schema grows. Same single-writer / mutex story as Recents.
|
|
12
|
+
|
|
13
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::ProjectMarker
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/project_marker.rb`
|
|
6
|
+
|
|
7
|
+
Reads, writes, and discovers the `.esp/project.json` marker that
|
|
8
|
+
identifies a directory as an esp project. Used by:
|
|
9
|
+
|
|
10
|
+
- `esp init` and `Esp::Operations.projects_new` to write the marker.
|
|
11
|
+
- `Esp::Operations.open_project` to read the marker's `game:` field so
|
|
12
|
+
the plugin registry knows which Operations module owns this project.
|
|
13
|
+
- The CLI cwd walk-up so `esp build` works from anywhere inside a
|
|
14
|
+
project tree without `--root`.
|
|
15
|
+
|
|
16
|
+
Marker filename rename (step 23.5 slice 3): the canonical location is
|
|
17
|
+
now `.esp/project.json`. Projects scaffolded by an earlier ESPresso
|
|
18
|
+
release wrote `.espresso/project.json`; readers accept both, writers
|
|
19
|
+
only emit the new name. The back-compat lookup goes away when the
|
|
20
|
+
release that drops it ships (no auto-migration — we don't silently
|
|
21
|
+
rewrite a user's project files).
|
|
22
|
+
|
|
23
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Providers
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/providers.rb`
|
|
6
|
+
|
|
7
|
+
The LLM-provider seam behind Esp::Agent. Each provider translates the
|
|
8
|
+
agent's neutral transcript to its API's native wire shape and normalizes
|
|
9
|
+
the response back to a Completion. Providers self-register here, so adding
|
|
10
|
+
one is a new file under providers/ plus a require in the load manifest.
|
|
11
|
+
|
|
12
|
+
Provider contract:
|
|
13
|
+
#complete(system:, tools:, messages:) -> Completion(text:, tool_calls:, raw:)
|
|
14
|
+
system — String system prompt
|
|
15
|
+
tools — Array<{name:, description:, input_schema:}> (JSON-Schema)
|
|
16
|
+
messages — the neutral transcript (see Esp::Agent)
|
|
17
|
+
raw — the provider-native assistant *message* for this turn, stored
|
|
18
|
+
on the assistant entry and replayed verbatim next call so
|
|
19
|
+
provider-side state (Anthropic thinking signatures, OpenAI
|
|
20
|
+
tool_calls) survives multi-turn tool use.
|
|
21
|
+
|
|
22
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Recents
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/recents.rb`
|
|
6
|
+
|
|
7
|
+
Per-user "recently opened projects" list, persisted as JSON in the data
|
|
8
|
+
directory the Tauri shell injects via ESP_DATA_DIR (macOS:
|
|
9
|
+
~/Library/Application Support/com.coreyellis.espresso/). Falls back to
|
|
10
|
+
~/.config/esp/ for CLI / unit-test use. The MW_DATA_DIR env var still
|
|
11
|
+
works as a one-release deprecation alias so existing dev shells keep
|
|
12
|
+
finding the same on-disk state; remove after step 24 ships.
|
|
13
|
+
Single-writer per process — the mutex serialises threaded WEBrick
|
|
14
|
+
handlers; cross-process collisions are accepted in v1 (one ESPresso ↔
|
|
15
|
+
one backend).
|
|
16
|
+
|
|
17
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Ui
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/ui.rb`
|
|
6
|
+
|
|
7
|
+
Internal i18n for the *tool's own* user-facing strings — CLI output and
|
|
8
|
+
error messages. Distinct from Esp::Mw::I18n, which localizes mod *content*;
|
|
9
|
+
this localizes mw itself so the distributed tool can ship in other
|
|
10
|
+
languages.
|
|
11
|
+
|
|
12
|
+
Catalogues live at locales/<locale>.yml, resolved relative to this file
|
|
13
|
+
(they ship with the tool, independent of Esp::ROOT — which points at the
|
|
14
|
+
user's mod project). Lookup is dot-pathed with %{named} interpolation,
|
|
15
|
+
falling back to en, then to the key itself.
|
|
16
|
+
|
|
17
|
+
Active locale: ESP_UI_LOCALE (with MW_UI_LOCALE honoured as a one-release
|
|
18
|
+
deprecation alias), then LANG/LC_ALL (stripped to the language subtag,
|
|
19
|
+
e.g. "fr_FR.UTF-8" -> "fr"), then en. Tests pin it to en.
|
|
20
|
+
|
|
21
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Vcs
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/vcs.rb`
|
|
6
|
+
|
|
7
|
+
A thin wrapper over the `git` CLI, scoped to a working-tree `root`. Backs
|
|
8
|
+
the diff-review loop (step 20): list working-tree changes, show one file's
|
|
9
|
+
diff, stage approved files, discard rejected ones. We shell out rather than
|
|
10
|
+
bind libgit2 (nothing extra to ship) — the project is already a git repo.
|
|
11
|
+
|
|
12
|
+
Every method takes an explicit `root` so it operates on the *user's* mod
|
|
13
|
+
project, never the toolchain repo, and so it's testable against a scratch
|
|
14
|
+
repo. Git failures raise GitError; the Operations layer maps that to a
|
|
15
|
+
caller-facing error.
|
|
16
|
+
|
|
17
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Esp::Watcher
|
|
4
|
+
|
|
5
|
+
**Source:** `lib/esp/watcher.rb`
|
|
6
|
+
|
|
7
|
+
File-watch-driven rebuild. Watches a mod's source directory (and
|
|
8
|
+
its scripts/, i18n/, etc. subtrees) and re-invokes Esp::Mw::Builder on
|
|
9
|
+
any matching change. Blocks until SIGINT.
|
|
10
|
+
|
|
11
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<!-- esp:auto — regenerated by `esp docs build`; edits here are overwritten -->
|
|
2
|
+
|
|
3
|
+
# Command reference
|
|
4
|
+
|
|
5
|
+
Every command accepts `--json` for structured output to stdout.
|
|
6
|
+
Errors print as `{"error": "..."}` to stderr with a non-zero exit.
|
|
7
|
+
|
|
8
|
+
## Top-level commands
|
|
9
|
+
|
|
10
|
+
### `esp version`
|
|
11
|
+
|
|
12
|
+
Print esp version
|
|
13
|
+
|
|
14
|
+
Usage: `esp version`
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
- `--json` — Output structured JSON instead of human text
|
|
18
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
19
|
+
|
|
20
|
+
### `esp doctor`
|
|
21
|
+
|
|
22
|
+
Check install prerequisites (Ruby, tes3conv, references index)
|
|
23
|
+
|
|
24
|
+
Usage: `esp doctor`
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
- `--json` — Output structured JSON instead of human text
|
|
28
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
29
|
+
|
|
30
|
+
### `esp init`
|
|
31
|
+
|
|
32
|
+
Bootstrap an esp project here (or in NAME subdir) — writes .esp/project.json + git init
|
|
33
|
+
|
|
34
|
+
Usage: `esp init [NAME]`
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
- `--game STRING` — Game plugin (default: mw; pass --game ob etc. once those plugins exist)
|
|
38
|
+
- `--force` — Re-initialise even if .esp/project.json already exists
|
|
39
|
+
- `--json` — Output structured JSON instead of human text
|
|
40
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
41
|
+
|
|
42
|
+
### `esp setup`
|
|
43
|
+
|
|
44
|
+
Configure git diff driver + tracked pre-commit hooks
|
|
45
|
+
|
|
46
|
+
Usage: `esp setup`
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
- `--json` — Output structured JSON instead of human text
|
|
50
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
51
|
+
|
|
52
|
+
### `esp new`
|
|
53
|
+
|
|
54
|
+
Scaffold a new mod folder under mods/<MOD>/
|
|
55
|
+
|
|
56
|
+
Usage: `esp new MOD`
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
- `--format STRING` — Source format: json | rb | py | js | mjs | ts
|
|
60
|
+
- `--author STRING` — Author name (default: git config user.name)
|
|
61
|
+
- `--description STRING` — Plugin description
|
|
62
|
+
- `--force` — Overwrite an existing mod folder
|
|
63
|
+
- `--json` — Output structured JSON instead of human text
|
|
64
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
65
|
+
|
|
66
|
+
### `esp unpack`
|
|
67
|
+
|
|
68
|
+
Import a plugin (a path, or an installed plugin NAME) to mods/<name>/
|
|
69
|
+
|
|
70
|
+
Usage: `esp unpack PLUGIN [NAME]`
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
- `--config STRING` — openmw.cfg to resolve a bare plugin NAME against
|
|
74
|
+
- `--json` — Output structured JSON instead of human text
|
|
75
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
76
|
+
|
|
77
|
+
### `esp build`
|
|
78
|
+
|
|
79
|
+
Build mods/<MOD>/<MOD>.{json,rb,py,js,mjs,ts} -> dist/<MOD>[.locale].esp
|
|
80
|
+
|
|
81
|
+
Usage: `esp build [MOD]`
|
|
82
|
+
|
|
83
|
+
Options:
|
|
84
|
+
- `--all` — Build every mod in mods/
|
|
85
|
+
- `--install` — After building, register the mod(s) with openmw.cfg
|
|
86
|
+
- `--config STRING` — openmw.cfg to register with (implies --install target)
|
|
87
|
+
- `--locale STRING` — Build with this locale (suffixes the output: dist/<MOD>.<locale>.esp)
|
|
88
|
+
- `--json` — Output structured JSON instead of human text
|
|
89
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
90
|
+
|
|
91
|
+
### `esp install`
|
|
92
|
+
|
|
93
|
+
Register dist/<MOD>.esp with OpenMW's openmw.cfg (and/or copy to Data Files)
|
|
94
|
+
|
|
95
|
+
Usage: `esp install MOD`
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
- `--copy_to STRING` — Also copy the built .esp into PATH (original-engine users: Morrowind/Data Files/)
|
|
99
|
+
- `--to_data_files` — Also copy to the auto-detected Morrowind Data Files dir (MORROWIND_DATA env override)
|
|
100
|
+
- `--register_openmw` — Register with openmw.cfg (default: true; --no-register-openmw skips)
|
|
101
|
+
- `--json` — Output structured JSON instead of human text
|
|
102
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
103
|
+
|
|
104
|
+
### `esp lint`
|
|
105
|
+
|
|
106
|
+
Find dangling refs and missing-master issues using the reference index
|
|
107
|
+
|
|
108
|
+
Usage: `esp lint MOD`
|
|
109
|
+
|
|
110
|
+
Options:
|
|
111
|
+
- `--json` — Output structured JSON instead of human text
|
|
112
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
113
|
+
|
|
114
|
+
### `esp watch`
|
|
115
|
+
|
|
116
|
+
Rebuild MOD on any change under mods/<MOD>/. Blocks until Ctrl-C.
|
|
117
|
+
|
|
118
|
+
Usage: `esp watch MOD`
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
- `--locale STRING` — Build with this locale on each change
|
|
122
|
+
- `--json` — Output structured JSON instead of human text
|
|
123
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
124
|
+
|
|
125
|
+
### `esp serve`
|
|
126
|
+
|
|
127
|
+
Start the HTTP API on localhost (mirrors the CLI; same payload shapes)
|
|
128
|
+
|
|
129
|
+
Usage: `esp serve`
|
|
130
|
+
|
|
131
|
+
Options:
|
|
132
|
+
- `--port NUMERIC` — TCP port to bind on localhost
|
|
133
|
+
- `--json` — Output structured JSON instead of human text
|
|
134
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
135
|
+
|
|
136
|
+
### `esp extract-scripts`
|
|
137
|
+
|
|
138
|
+
Move every Script record's inline text into mods/<MOD>/scripts/<id>.mwscript
|
|
139
|
+
|
|
140
|
+
Usage: `esp extract-scripts MOD`
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
- `--json` — Output structured JSON instead of human text
|
|
144
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
145
|
+
|
|
146
|
+
## `esp plugins` subcommand group
|
|
147
|
+
|
|
148
|
+
Inspect installed OpenMW plugins
|
|
149
|
+
|
|
150
|
+
### `esp plugins list`
|
|
151
|
+
|
|
152
|
+
List plugins installed in OpenMW (active flag + load order)
|
|
153
|
+
|
|
154
|
+
Usage: `esp list`
|
|
155
|
+
|
|
156
|
+
Options:
|
|
157
|
+
- `--config STRING` — Path to openmw.cfg (default: per-OS user config)
|
|
158
|
+
- `--json` — Output structured JSON instead of human text
|
|
159
|
+
|
|
160
|
+
## `esp refs` subcommand group
|
|
161
|
+
|
|
162
|
+
Manage vanilla ESM references
|
|
163
|
+
|
|
164
|
+
### `esp refs unpack`
|
|
165
|
+
|
|
166
|
+
Convert vanilla ESMs to JSON under the per-user references directory
|
|
167
|
+
|
|
168
|
+
Usage: `esp unpack`
|
|
169
|
+
|
|
170
|
+
Options:
|
|
171
|
+
- `--data STRING` — Data Files directory (default: $MORROWIND_DATA or the detected install)
|
|
172
|
+
- `--json` — Output structured JSON instead of human text
|
|
173
|
+
- `--references_dir STRING` — Override the references directory (default: $ESP_REFERENCES_DIR or $ESP_DATA_DIR/references)
|
|
174
|
+
|
|
175
|
+
### `esp refs index`
|
|
176
|
+
|
|
177
|
+
Build/refresh the SQLite index over the per-user references directory
|
|
178
|
+
|
|
179
|
+
Usage: `esp index`
|
|
180
|
+
|
|
181
|
+
Options:
|
|
182
|
+
- `--json` — Output structured JSON instead of human text
|
|
183
|
+
- `--references_dir STRING` — Override the references directory (default: $ESP_REFERENCES_DIR or $ESP_DATA_DIR/references)
|
|
184
|
+
|
|
185
|
+
### `esp refs find`
|
|
186
|
+
|
|
187
|
+
Find vanilla records — substring match on id + name by default
|
|
188
|
+
|
|
189
|
+
Usage: `esp find [QUERY]`
|
|
190
|
+
|
|
191
|
+
Options:
|
|
192
|
+
- `--type STRING` — Filter by record type (e.g. Npc, Cell, Script)
|
|
193
|
+
- `--like STRING` — SQL LIKE pattern on id (e.g. 'Fargoth%')
|
|
194
|
+
- `--exact` — Match QUERY as an exact id instead of a substring
|
|
195
|
+
- `--show` — Print full JSON of each match
|
|
196
|
+
- `--limit NUMERIC` — Max rows to print
|
|
197
|
+
- `--json` — Output structured JSON instead of human text
|
|
198
|
+
- `--references_dir STRING` — Override the references directory (default: $ESP_REFERENCES_DIR or $ESP_DATA_DIR/references)
|
|
199
|
+
|
|
200
|
+
## `esp i18n` subcommand group
|
|
201
|
+
|
|
202
|
+
Translation catalogue tools
|
|
203
|
+
|
|
204
|
+
### `esp i18n check`
|
|
205
|
+
|
|
206
|
+
Report missing/orphan i18n keys per locale (vs. en)
|
|
207
|
+
|
|
208
|
+
Usage: `esp check MOD`
|
|
209
|
+
|
|
210
|
+
Options:
|
|
211
|
+
- `--json` — Output structured JSON instead of human text
|
|
212
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
213
|
+
|
|
214
|
+
### `esp i18n audit`
|
|
215
|
+
|
|
216
|
+
Audit tool-UI locales: undefined/unused/orphan keys + missing translations
|
|
217
|
+
|
|
218
|
+
Usage: `esp audit`
|
|
219
|
+
|
|
220
|
+
Options:
|
|
221
|
+
- `--json` — Output structured JSON instead of human text
|
|
222
|
+
- `--root STRING` — Project root (defaults to the active project or the toolchain repo)
|
|
223
|
+
|
|
224
|
+
## `esp docs` subcommand group
|
|
225
|
+
|
|
226
|
+
Generate / introspect reference documentation
|
|
227
|
+
|
|
228
|
+
### `esp docs build`
|
|
229
|
+
|
|
230
|
+
Regenerate docs/reference/ from the CLI tree and module headers
|
|
231
|
+
|
|
232
|
+
Usage: `esp build`
|
|
233
|
+
|
|
234
|
+
Options:
|
|
235
|
+
- `--out STRING` — Output directory (relative to repo root)
|
|
236
|
+
- `--json` — Output structured JSON instead of human text
|
|
237
|
+
|
|
238
|
+
### `esp docs introspect`
|
|
239
|
+
|
|
240
|
+
Dump the CLI command tree + module surface as JSON (always JSON)
|
|
241
|
+
|
|
242
|
+
Usage: `esp introspect`
|
|
243
|
+
|
|
244
|
+
Options:
|
|
245
|
+
- `--json` — Output structured JSON instead of human text
|
|
246
|
+
|
|
247
|
+
## `esp mcp` subcommand group
|
|
248
|
+
|
|
249
|
+
Model Context Protocol server for AI tools
|
|
250
|
+
|
|
251
|
+
### `esp mcp serve`
|
|
252
|
+
|
|
253
|
+
Run the MCP server over stdio (JSON-RPC 2.0) for AI clients
|
|
254
|
+
|
|
255
|
+
Usage: `esp serve`
|
|
256
|
+
|
|
257
|
+
Options:
|
|
258
|
+
- `--json` — Output structured JSON instead of human text
|
|
259
|
+
|
|
260
|
+
### `esp mcp install`
|
|
261
|
+
|
|
262
|
+
Register `esp mcp serve` with an AI client (Claude Code / Desktop)
|
|
263
|
+
|
|
264
|
+
Usage: `esp install`
|
|
265
|
+
|
|
266
|
+
Options:
|
|
267
|
+
- `--client STRING` — Which MCP client to configure
|
|
268
|
+
- `--name STRING` — Name to register the server under in mcpServers
|
|
269
|
+
- `--json` — Output structured JSON instead of human text
|
|
270
|
+
|
|
271
|
+
<!-- /esp:auto — write durable docs below this line; they survive rebuilds -->
|