@mercury-fw/cli 0.56.0 → 0.57.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 CHANGED
@@ -1,5 +1,36 @@
1
1
  # @mercury-fw/cli
2
2
 
3
+ ## 0.57.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 377ce2a: `mfw create` gives the app a place for plugins of its own: `plugins/<name>`, each a package, as a workspace of the app (`"workspaces": ["plugins/*"]` in `package.json`), listed in `dependencies` as `workspace:*` and declared in `mercury.config.ts`. A `bunfig.toml` keeps Bun's hoisted `node_modules`: with a workspaces key Bun would switch to its isolated linker, whose `node_modules` is made of links. The Dockerfile copies `bunfig.toml` with `package.json`, then `plugins/` before `bun install`, so a plugin's postinstall finds its own scripts, and puts on PATH the binaries a plugin's postinstall writes to its `bin/`, as it does for the framework's packages. `.dockerignore` leaves out every `node_modules`, a plugin's own included, and the binaries a plugin's postinstall wrote on the host, which `.gitignore` keeps out of the repository too. `package.json` gets a `test` script (`bun test`), which runs the plugins' tests too.
8
+
9
+ An existing app keeps working as it is. To give it the same place:
10
+
11
+ 1. In `package.json`, add `"workspaces": ["plugins/*"]` and `"test": "bun test"` under `scripts`.
12
+ 2. Add a `bunfig.toml` next to it:
13
+
14
+ ```toml
15
+ [install]
16
+ linker = "hoisted"
17
+ ```
18
+
19
+ 3. In the `Dockerfile`, change `COPY --chown=mercury:mercury package.json bun.lock* ./` to `COPY --chown=mercury:mercury package.json bun.lock* bunfig.toml ./`, add `COPY --chown=mercury:mercury plugin[s] ./plugins/` right after `COPY --chown=mercury:mercury .pack[s] ./.packs/`, and replace the line `RUN find /app/node_modules -path '*/@mercury-fw/*/bin/*' -type f -exec ln -sf {} /usr/local/bin/ \;` with:
20
+
21
+ ```dockerfile
22
+ RUN mkdir -p /app/plugins \
23
+ && find /app/node_modules/@mercury-fw /app/plugins -mindepth 3 -maxdepth 3 -path '*/bin/*' -type f -exec ln -sf {} /usr/local/bin/ \;
24
+ ```
25
+
26
+ 4. In `.dockerignore`, change `node_modules` to `**/node_modules` and add `plugins/*/bin`.
27
+ 5. In `.gitignore`, add `plugins/*/bin`.
28
+
29
+ ### Patch Changes
30
+
31
+ - @mercury-fw/core@0.57.0
32
+ - @mercury-fw/utils@0.57.0
33
+
3
34
  ## 0.56.0
4
35
 
5
36
  ### Patch Changes
package/README.md CHANGED
@@ -51,7 +51,7 @@ Writes a new Mercury app into `<folder>`, which has to be missing or empty; the
51
51
  - which channels and which tool plugins to include (none is fine: the REPL always works);
52
52
  - the git remote for `origin`, which you can leave empty (most of the time it doesn't exist yet when you scaffold).
53
53
 
54
- It writes the `mercury.config.ts` for that selection, the persona, a `locales/` folder with an `en.json` for the texts people see (empty, or the starting formatter rules' own texts: `app.jira.no-issues` with Jira), the service and REPL entrypoints, a Dockerfile, a compose file with Qdrant, and an env example listing every variable the chosen pieces read. A plugin that hands over lists comes wrapped in the formatter with a starting rule, yours to change.
54
+ It writes the `mercury.config.ts` for that selection, the persona, a `locales/` folder with an `en.json` for the texts people see (empty, or the starting formatter rules' own texts: `app.jira.no-issues` with Jira), the service and REPL entrypoints, a Dockerfile, a compose file with Qdrant, and an env example listing every variable the chosen pieces read. Its `package.json` declares `plugins/*` as workspaces, the place for the app's own plugins (each a package in `plugins/<name>`, which the image copies before installing), and a `test` script (`bun test`, the plugins' tests included); `bunfig.toml` keeps Bun's hoisted `node_modules`, which the workspaces would otherwise turn into links. A plugin that hands over lists comes wrapped in the formatter with a starting rule, yours to change.
55
55
 
56
56
  Then it runs `bun install` in the app and creates a git repository on `main` with a first commit (`bun.lock` included), adding `origin` when you gave one; nothing is pushed. Each step is best effort and never undoes the ones before it: an install that fails still leaves the app committed, without the lockfile, and the closing message says what to run. The repository is skipped when the folder is already inside one (an app created in a monorepo belongs to it). Whether git can commit is git's call: when it refuses (no identity, a hook) or isn't installed, the message reports why and lists the commands to finish by hand. `bun install` prints its own output as it runs.
57
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mercury-fw/cli",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,8 +41,8 @@
41
41
  "comment:shape": "The Mercury CLI (`mfw`). `mfw create <dir>` writes a new Mercury app from the template. The framework packages move in lockstep with it, so a new app gets them at the CLI's own version; plugins and channels at the registry's latest. The plugin and channel packages are devDependencies only for the catalog test. `main(argv)` is exported for create-mercury-agent.",
42
42
  "dependencies": {
43
43
  "@clack/prompts": "^1.8.1",
44
- "@mercury-fw/core": "0.56.0",
45
- "@mercury-fw/utils": "0.56.0",
44
+ "@mercury-fw/core": "0.57.0",
45
+ "@mercury-fw/utils": "0.57.0",
46
46
  "commander": "^15.0.0"
47
47
  },
48
48
  "devDependencies": {
@@ -51,11 +51,11 @@
51
51
  "@mercury-fw/channel-google-chat": "0.10.0",
52
52
  "@mercury-fw/channel-http": "0.12.0",
53
53
  "@mercury-fw/directory-static": "0.1.1",
54
- "@mercury-fw/formatter": "0.56.0",
54
+ "@mercury-fw/formatter": "0.57.0",
55
55
  "@mercury-fw/plugin-atlassian-admin": "0.5.0",
56
56
  "@mercury-fw/plugin-bitbucket": "0.6.0",
57
57
  "@mercury-fw/plugin-jira": "0.8.0",
58
- "@mercury-fw/plugin-web-search": "0.3.0",
58
+ "@mercury-fw/plugin-web-search": "0.4.0",
59
59
  "@mercury-fw/plugin-zitadel": "0.5.0",
60
60
  "@mercury-fw/typescript-config": "*",
61
61
  "@mercury-fw/web-search-searxng": "0.1.0",
package/src/render.ts CHANGED
@@ -13,6 +13,7 @@ import { CATALOG, type CatalogEntry, type EnvVar } from "./catalog.ts";
13
13
  import indexTs from "../template/src/index.ts.tpl" with { type: "text" };
14
14
  import replTs from "../template/src/repl.ts.tpl" with { type: "text" };
15
15
  import tsconfigJson from "../template/tsconfig.json.tpl" with { type: "text" };
16
+ import bunfigToml from "../template/bunfig.toml.tpl" with { type: "text" };
16
17
  import gitignore from "../template/gitignore.tpl" with { type: "text" };
17
18
  import dockerignore from "../template/dockerignore.tpl" with { type: "text" };
18
19
  import dockerfile from "../template/Dockerfile.tpl" with { type: "text" };
@@ -85,6 +86,7 @@ export function renderApp(input: RenderInput): Map<string, string> {
85
86
  [".gitignore", gitignore],
86
87
  ["Dockerfile", dockerfile],
87
88
  ["README.md", renderReadme(input.name, channels, auth, tools, directory)],
89
+ ["bunfig.toml", bunfigToml],
88
90
  ["docker-compose.yml", renderCompose(input.name, channels.some((c) => c.id === "http"), services)],
89
91
  ["locales/en.json", renderEnglish(tools)],
90
92
  ["mercury.config.ts", renderConfig(assistantName, input.role, channels, auth, tools, directory)],
@@ -308,7 +310,9 @@ function renderPackageJson(
308
310
  version: "0.1.0",
309
311
  type: "module",
310
312
  private: true,
311
- scripts: { start: "bun src/index.ts", repl: "bun src/repl.ts", typecheck: "tsc --noEmit" },
313
+ // The app's own plugins, each a package of its own under plugins/.
314
+ workspaces: ["plugins/*"],
315
+ scripts: { start: "bun src/index.ts", repl: "bun src/repl.ts", typecheck: "tsc --noEmit", test: "bun test" },
312
316
  dependencies,
313
317
  // The CLI in the app itself, at the framework's version: a global `mfw`
314
318
  // hands the app's commands over to it.
@@ -418,6 +422,8 @@ ${directory ? `- Directory: ${directory.id}\n` : ""}
418
422
  - \`mercury.config.ts\`: what the app is made of (tool plugins, channels, how their lists read) and the assistant's persona: its name, who it is and how it answers. Edit them freely.
419
423
  - \`locales/\`: the texts people see, one file per language the assistant speaks. \`en.json\` overrides the English ones; add \`it.json\` (and \`it\` to \`i18n.locales\` in the config) for Italian, \`i18n.defaultLocale\` for the language people get when they haven't picked one, \`i18n.timeZone\` (an IANA name such as \`Europe/Rome\`) for the time zone of whoever saved none and whose app says none. The app's own texts (a formatter rule's) are \`app.\` keys, written in English in \`en.json\` and translated in every other file. Mercury logs at startup the keys a file is missing.
420
424
  - \`src/index.ts\`: the service (channels, crons). \`src/repl.ts\`: an interactive terminal for trying things out.
425
+ - \`plugins/\`: the app's own plugins, when it has any: each one a package in a folder of its own (\`plugins/<name>\`, a workspace), listed in \`dependencies\` as \`workspace:*\` and declared in \`mercury.config.ts\`. \`bun run test\` runs their tests.
426
+ - \`bunfig.toml\`: keeps Bun's hoisted \`node_modules\`, which the workspaces would otherwise turn into links the image's PATH step doesn't follow. Keep it.
421
427
  - \`.env.example\`: every variable the app reads. Copy it to \`.env\` and fill it in.
422
428
 
423
429
  ## Running it
@@ -13,12 +13,17 @@ WORKDIR /app
13
13
 
14
14
  # Each tool plugin downloads its pinned CLI in its postinstall (allowed by
15
15
  # package.json's trustedDependencies); the binaries go on PATH. .packs/ holds
16
- # local tarballs when the app installs them (mfw local-packages), and is
17
- # skipped when it isn't there.
18
- COPY --chown=mercury:mercury package.json bun.lock* ./
16
+ # local tarballs when the app installs them (mfw local-packages), plugins/ the
17
+ # app's own plugins (workspaces, whose postinstall needs their whole folder),
18
+ # and each is skipped when it isn't there. bunfig.toml keeps Bun's hoisted
19
+ # node_modules, which the workspaces would otherwise turn into symlinks.
20
+ COPY --chown=mercury:mercury package.json bun.lock* bunfig.toml ./
19
21
  COPY --chown=mercury:mercury .pack[s] ./.packs/
22
+ COPY --chown=mercury:mercury plugin[s] ./plugins/
20
23
  RUN bun install --production && chown -R mercury:mercury node_modules
21
- RUN find /app/node_modules -path '*/@mercury-fw/*/bin/*' -type f -exec ln -sf {} /usr/local/bin/ \;
24
+ # plugins/ made when the app has none, or find fails on it.
25
+ RUN mkdir -p /app/plugins \
26
+ && find /app/node_modules/@mercury-fw /app/plugins -mindepth 3 -maxdepth 3 -path '*/bin/*' -type f -exec ln -sf {} /usr/local/bin/ \;
22
27
 
23
28
  COPY --chown=mercury:mercury mercury.config.ts ./
24
29
  COPY --chown=mercury:mercury locales ./locales
@@ -0,0 +1,2 @@
1
+ [install]
2
+ linker = "hoisted"
@@ -1,6 +1,7 @@
1
- node_modules
1
+ **/node_modules
2
2
  .git
3
3
  .env
4
4
  .env.*
5
5
  !.env.example
6
6
  *.log
7
+ plugins/*/bin
@@ -6,3 +6,4 @@ node_modules
6
6
  .DS_Store
7
7
  .packs/
8
8
  e2e/results/
9
+ plugins/*/bin