micro-models-agent 2.28.0 → 2.29.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.
- package/CHANGELOG.md +56 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,62 @@ All notable changes to Micro Models Agent (MMA) will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [2.29.0] - 2026-10-07
|
|
8
|
+
|
|
9
|
+
The plugin system stops being "an anonymous object in an array": a plugin is now a
|
|
10
|
+
registered entity with author, version, description, declared permissions and a
|
|
11
|
+
visible on/off switch. `mma web` gets a **Plugins** sidebar tab with live toggles
|
|
12
|
+
and a details popup; a plugin that fails to load is now visible instead of
|
|
13
|
+
silently missing.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Agent-written capability drafts** (`src/modules/plugins/drafts.ts`, `draft-host.ts`, `src/tools/define-capability.ts`): the `define_capability` tool writes a capability into `.mma/plugins/drafts/<name>.ts` and asks the user for permission with the full code shown. A draft is **inert until approved** - the catalog is not read at all without a marker (`.mma/plugins/.drafts-approved`, project-scoped and outside the catalog so the plugin scan never sees it). After approval the capability is registered live (`plugin__<name>__<name>` tool, `plugin:<name>` tag), and it reaches already-open `mma web` sessions. Declared `permissions` are required - an empty declaration would make the consent prompt a lie. `plugins.maxDrafts` (default 10) caps the drafts per project with LRU eviction; `mma plugins drafts [approve|revoke]` and a startup warning cover the pending state.
|
|
18
|
+
- **`[PLUGIN CAPABILITIES]` prompt block** (`src/modules/plugins/capabilities-block.ts`): lists the tools installed plugins contributed and states that `define_capability` exists. Omitted when the tool set is narrowed by an allowlist (onboarding), where the tool is unavailable anyway.
|
|
19
|
+
- **Plugin tools** (`src/modules/plugins/tools.ts`, `AgentPlugin.getToolDefinitions()`): a plugin can add its own tools to the harness. Definitions enter the registry under `plugin__<plugin>__<tool>` (same convention as `mcp__<server>__<tool>`), get a `plugin:<name>` tag and `alwaysOn: true` by default so `enable_tools` cannot hide them; the core fills `provides.tools`, which the sidebar popup, `mma plugins list` and `mma plugins show` already read. Toggling a plugin with tools resets the provider prompt cache - the details popup says so instead of hiding it.
|
|
20
|
+
- **Live plugin reload** (`src/modules/plugins/reload.ts`, `manager.ts`, `loader.ts`): edits to a plugin file are picked up without restarting the process - unload (`onUnload`), drop the `require` cache, read again. Available as `mma plugins reload`, `/plugins reload`, `POST /api/reload/plugins`, and a "reload plugins" button in Settings > Plugins. Skills reload the same way, so a skill written at runtime is loadable in the same turn.
|
|
21
|
+
- **`onUnload` hook** on `AgentPlugin`: release servers, timers and sockets when a plugin goes away. Without it a reload leaks - `examples/plugins/web-ui` starts an HTTP server in `onSessionStart`, and copies used to accumulate across `/reload`.
|
|
22
|
+
- **`PluginManager` owns its source catalogs** (`setSourceDirs`, set at bootstrap): CLI, REPL and the web all call `reload()` and none of them knows the paths. `/reload` unloads the old plugins and clears the cache before rebuilding bootstrap, so nothing outlives it.
|
|
23
|
+
- **`ToolRegistry.upsert` / `ToolRegistry.unregister`** (`src/tools/registry.ts`): for tool sets owned by an external source and changed at runtime. `register` still throws on a duplicate - a core duplicate is a startup bug.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Plugin reload never reached an already-running web session**: `reload` replaced the plugin in the main manager only, so a session runner kept the old instance - its hooks and its tools stayed on the pre-edit code until the process restarted. The main manager now broadcasts the new instance (and removals) to managers sharing its gate; a manager that adopted someone else's gate never broadcasts, so a runner's own execution plugin cannot leak into the main agent.
|
|
28
|
+
- **A cloned registry looked like a name collision**: `buildRunnerRegistry` copies definitions into a session registry, and the copy carried no ownership record, so the plugin's contribution was rejected as "name already taken by the harness" - the stale copy kept serving calls and reload could not update it. Ownership is now read from the `plugin:<name>` tag, which survives cloning; it also lets a disabled plugin's tools be cleaned out of a session registry.
|
|
29
|
+
- **A plugin tool without `success` looked failed**: `ToolResult.success` is required, and plugins are usually plain JS, so `{output}` produced an apparently failed tool card and no `success` in the log. The plugin handler result is normalized (missing `success` means success, non-string `output` is stringified), and a definition without `handler` is rejected at registration with a readable warning instead of failing at call time with `tool.handler is not a function`.
|
|
30
|
+
- **Light theme rendered every toggle as off**: `body.light .toggle` outranked `.toggle.on` on specificity, so enabled toggles showed the disabled colour app-wide (settings included).
|
|
31
|
+
- **Plugin code edits were ignored until a process restart**: `/reload` rebuilt bootstrap but nothing invalidated the `require` cache. Verified experimentally before fixing: cache invalidation works under Bun for `.ts` and `.js`, but under Node only for `.js` (Node caches transpiled `.ts` separately). Such files are counted in `ReloadReport.staleTs` and the UI/CLI say a restart is needed rather than reporting a reload that did not change anything.
|
|
32
|
+
- **A deleted plugin file left the plugin registered**: reloading a catalog now drops plugins whose file disappeared.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **Plugin metadata** (`src/modules/types.ts`, `src/modules/plugins/records.ts`): optional `description`, `author`, `homepage`, `permissions`, `provides` on `AgentPlugin`. All optional on purpose - missing metadata is a warning, never a load error, so the 8-line plugin and both `examples/plugins` keep working. Hard validation only on `name`.
|
|
37
|
+
- **`PluginRecord` read model** (`records.ts`): the single source for CLI, REPL and web. `PluginManager.getRecords()` (cached, invalidated on any change) plus `getFailures()` returning `PluginLoadFailure[]` - a plugin that throws on import was previously indistinguishable from a missing one.
|
|
38
|
+
- **Live enable/disable** (`config.plugins.disabled`, new `plugins.json` domain): `mma plugins enable|disable <name>`, `/plugins enable|disable <name>`, `POST /api/plugins/:name {enabled}`, and a toggle per row in the sidebar tab and the settings panel. No restart, no `reconfigure`. All paths write through `setConfigValue`, so they cannot drift.
|
|
39
|
+
- **Plugins sidebar tab** (`assets/js/sidebar/plugins.ts`, `Alt+6`): row list with glyph/name/version/author, a live toggle, one dim description line, and load failures as their own rows. Details open in the existing nested `#subOverlay` (same pattern as the LSP info dialog) - description, author, version, homepage, absolute path with copy, provided tools/hooks as chips, declared permissions with an explicit "declaration, not enforcement" note, and metadata warnings.
|
|
40
|
+
- **Plugin SDK exports** (`src/index.ts`): `AgentPlugin`, `HostBridge`, `HostBridgeSubmitOptions`, `TurnSummary`, `PluginRecord`, `PLUGIN_PERMISSIONS` are now exported from the package root; third-party plugins no longer have to duck-type the contract.
|
|
41
|
+
- **`mma plugins show <name>` / `/plugins show <name>`**: per-plugin details in the terminal, same content as the web popup.
|
|
42
|
+
- **CLI/REPL listing rewrite**: both share one formatter (`src/modules/plugins/format.ts`) and now show author, permissions, description and load failures.
|
|
43
|
+
- **`GET /api/plugins`** (`webui/settings/settings-api.ts`): returns `{plugins: PluginRecord[], failures, mcp}`. `enabled` is the real flag instead of a hardcoded `true`; every other field is additive.
|
|
44
|
+
- **`WebPluginManager`** (`webui/state.ts`): widened to `getRecords`/`getFailures`/`setEnabled`/`reload`; `PluginManager` satisfies it structurally. The redundant narrow `WebPluginInfo` view is gone.
|
|
45
|
+
- **`PluginLoader.loadFromDir`** returns `LoadReport {loaded, skipped, failed}` instead of `void` and stamps `plugin.path` on each plugin.
|
|
46
|
+
- **`subdialog.ts`** resolves its overlay nodes lazily instead of at import time; an import-time capture silently no-ops when the overlay is not in the DOM yet.
|
|
47
|
+
- **Sidebar tab icons**: `map`/`stethoscope`/`puzzle` were too dense to read at 17px and are replaced with `layout-grid`/`code`/`plug`.
|
|
48
|
+
- **`POST /api/reload/plugins`** is a separate action namespace, not `POST /api/plugins/reload` - `reload` is a legal plugin name, and exact-first matching would have made such a plugin impossible to toggle.
|
|
49
|
+
- **Internals**: `PluginManager` was over the 300-line rule at 316; hook dispatching moved to `src/modules/plugins/dispatch.ts`.
|
|
50
|
+
- **Plugin tool contribution and per-session registry clones** (`attachToolRegistry` / `detachToolRegistry` / `shareGateWith`): the manager owns the set of tool registries it feeds (main plus one per live web session), and per-session plugin managers share the **deny-list object** with the main one. Before this, a web toggle only affected the main agent - hooks and (now) tools of a disabled plugin kept running in session runners. The deny-list is mutated in place (replacing the object would leave runners on the old set), `getRecords()` is validated against the shared `gate.version`, and stopping a runner calls `dispose()` so the manager does not keep a dead registry and keep writing tools into it.
|
|
51
|
+
- **A plugin tool set is all-or-nothing**: a name already taken by the harness or another plugin, a malformed definition, a duplicate name after sanitization, or a `getToolDefinitions()` that throws rejects the plugin's **whole** contribution (logged as a warning, shown by `mma plugins show <name>` / `/plugins show`). A half-installed tool set is worse than none - the model would see one of three tools and could not tell why the others were missing. Hooks stay live.
|
|
52
|
+
|
|
53
|
+
### Removed
|
|
54
|
+
|
|
55
|
+
- **`sessionIsolation.isolatePlugins`**: declared in the config type, defaults and `/config` registry, but read nowhere in `src/`. Dead switch removed so the registry has one enable/disable mechanism. No behaviour change.
|
|
56
|
+
|
|
57
|
+
### Known limits (documented, not fixed)
|
|
58
|
+
|
|
59
|
+
- **Draft approval does not cross processes.** The approval is a marker file, the loaded code lives in process memory: `mma plugins drafts revoke` from a terminal unloads the drafts in *that* process, and a running `mma web` only notices on restart or `POST /api/reload/plugins` (same in the other direction). Inside one process (the `define_capability` tool, the Plugins tab) it is live. Verified in a live run.
|
|
60
|
+
- Disabling a plugin stops its hooks and tool contributions but does **not** undo the module import that already ran, and `permissions` is a declaration shown to the user rather than enforcement. Real isolation and code trust remain open work (see `docs/specs/2026-09-28-production-readiness-design.md`, P1).
|
|
61
|
+
- Approving a draft is still a decision, not a boundary: the code runs in the agent process with the harness's own reach (fs, network, `bash`). Real isolation and code trust remain open work (see `docs/specs/2026-09-28-production-readiness-design.md`, P1).
|
|
62
|
+
|
|
7
63
|
## [2.28.0] - 2026-10-07
|
|
8
64
|
|
|
9
65
|
Tool-produced images (browser screenshots, `attach_image`) are now visible in the
|