@mercury-fw/cli 0.70.0 → 0.72.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,26 @@
1
1
  # @mercury-fw/cli
2
2
 
3
+ ## 0.72.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 468cb12: - `mfw create`: new apps declare `traces: { sink: jsonlTraces(), level: "meta" }` and depend on `@mercury-fw/trace-jsonl`
8
+ - **Migration:** to record traces, `bun add @mercury-fw/trace-jsonl` at the framework's version, add `import { jsonlTraces } from "@mercury-fw/trace-jsonl";` and `traces: { sink: jsonlTraces(), level: "meta" },` to `mercury.config.ts`, then in `src/index.ts` pass `tracer: app.tracer` to `loadChannels` and `await app.tracer.flush();` before `process.exit(0)` in `shutdown`
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [468cb12]
13
+ - @mercury-fw/core@0.72.0
14
+ - @mercury-fw/utils@0.72.0
15
+
16
+ ## 0.71.0
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [2b08f7e]
21
+ - @mercury-fw/core@0.71.0
22
+ - @mercury-fw/utils@0.71.0
23
+
3
24
  ## 0.70.0
4
25
 
5
26
  ### Patch Changes
package/README.md CHANGED
@@ -53,7 +53,7 @@ Writes a new Mercury app into `<folder>`, which has to be missing or empty; the
53
53
  - which channels and which tool plugins to include (none is fine: the REPL always works);
54
54
  - the git remote for `origin`, which you can leave empty (most of the time it doesn't exist yet when you scaffold).
55
55
 
56
- 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); the workspaces make Bun install with its isolated linker, and the Dockerfile's PATH step follows the links it makes. A plugin that hands over lists comes wrapped in the formatter with a starting rule, yours to change.
56
+ It writes the `mercury.config.ts` for that selection, the persona, the traces (`@mercury-fw/trace-jsonl`, at level `meta`, in `.mercury/traces/` on the vault's volume), 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); the workspaces make Bun install with its isolated linker, and the Dockerfile's PATH step follows the links it makes. A plugin that hands over lists comes wrapped in the formatter with a starting rule, yours to change.
57
57
 
58
58
  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.
59
59
 
@@ -13,6 +13,8 @@ export type RenderInput = {
13
13
  directory?: string;
14
14
  versions: Record<string, string>;
15
15
  };
16
+ /** The trace sink every new app declares, writing the traces to files on the vault's volume. */
17
+ export declare const TRACE_SINK_PACKAGE = "@mercury-fw/trace-jsonl";
16
18
  /** Builds every file of the new app. Throws on an invalid app name, an empty
17
19
  * assistant name or role, an id the catalog doesn't have, or a package with no
18
20
  * version in `input.versions`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mercury-fw/cli",
3
- "version": "0.70.0",
3
+ "version": "0.72.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.70.0",
45
- "@mercury-fw/utils": "0.70.0",
44
+ "@mercury-fw/core": "0.72.0",
45
+ "@mercury-fw/utils": "0.72.0",
46
46
  "commander": "^15.0.0"
47
47
  },
48
48
  "devDependencies": {
@@ -51,7 +51,7 @@
51
51
  "@mercury-fw/channel-google-chat": "0.12.0",
52
52
  "@mercury-fw/channel-http": "0.16.0",
53
53
  "@mercury-fw/directory-static": "0.1.2",
54
- "@mercury-fw/formatter": "0.70.0",
54
+ "@mercury-fw/formatter": "0.72.0",
55
55
  "@mercury-fw/plugin-atlassian-admin": "0.5.1",
56
56
  "@mercury-fw/plugin-bitbucket": "0.6.1",
57
57
  "@mercury-fw/plugin-confluence": "0.1.0",
package/src/render.ts CHANGED
@@ -83,12 +83,24 @@ const CONFIG_HEADER = `/**
83
83
  * provider when a channel needs one, how the lists its plugins hand over read,
84
84
  * the assistant's persona and the languages it speaks (\`i18n\`: a file per
85
85
  * language in \`locales/\`, \`en.json\` overriding the English texts) and its version
86
- * (\`version\`, its \`package.json\`'s, shown on the HTTP channel's \`/version\`). The entrypoints
86
+ * (\`version\`, its \`package.json\`'s, shown on the HTTP channel's \`/version\`) and where
87
+ * the traces of what it does go (\`traces\`). The entrypoints
87
88
  * (\`src/index.ts\`, \`src/repl.ts\`) hand this config to \`composeMercury\`.
88
89
  *
89
90
  * Every tool plugin and channel declared here is active.
90
91
  */`;
91
92
 
93
+ /** The trace sink every new app declares, writing the traces to files on the vault's volume. */
94
+ export const TRACE_SINK_PACKAGE = "@mercury-fw/trace-jsonl";
95
+
96
+ /** The config's `traces` entry, with what it records and where. */
97
+ const TRACES_SECTION = [
98
+ " // What the agent does, as events in .mercury/traces/ on the vault's volume:",
99
+ " // a file per day, the last 7 days with activity kept. \"meta\" records names,",
100
+ " // outcomes and times; \"args\" also what the tools were given. Remove to record nothing.",
101
+ ' traces: { sink: jsonlTraces(), level: "meta" },',
102
+ ].join("\n");
103
+
92
104
  /** Builds every file of the new app. Throws on an invalid app name, an empty
93
105
  * assistant name or role, an id the catalog doesn't have, or a package with no
94
106
  * version in `input.versions`. */
@@ -254,6 +266,7 @@ function renderConfig(
254
266
  for (const c of [...channels, ...(auth ? [auth] : []), ...(directory ? [directory] : [])]) {
255
267
  imports.push(`import { ${c.exportName} } from "${c.package}";`);
256
268
  }
269
+ imports.push(`import { jsonlTraces } from "${TRACE_SINK_PACKAGE}";`);
257
270
 
258
271
  const helpers = withRules.map((t) => `${t.formatter?.helpers}\n\n`).join("");
259
272
 
@@ -278,6 +291,7 @@ function renderConfig(
278
291
  ...(directory ? [` directory: ${directory.exportName},`] : []),
279
292
  MODEL_SECTION,
280
293
  " i18n: { locales: { en } },",
294
+ TRACES_SECTION,
281
295
  VERSION_COMMENT,
282
296
  " version: pkg.version,",
283
297
  "});",
@@ -318,7 +332,7 @@ function renderPackageJson(
318
332
  directory: CatalogEntry | undefined,
319
333
  ): string {
320
334
  const chosen = [...channels, ...(auth ? [auth] : []), ...tools, ...(directory ? [directory] : [])];
321
- const packages = [...new Set(["@mercury-fw/core", ...chosen.flatMap(entryPackages)])];
335
+ const packages = [...new Set(["@mercury-fw/core", TRACE_SINK_PACKAGE, ...chosen.flatMap(entryPackages)])];
322
336
  if (tools.some((t) => t.formatter)) {
323
337
  packages.push("@mercury-fw/formatter");
324
338
  }
package/src/versions.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import pkg from "../package.json";
8
8
 
9
9
  /** The framework packages a new app can depend on: always at the CLI's version. */
10
- export const FRAMEWORK_PACKAGES = ["@mercury-fw/cli", "@mercury-fw/core", "@mercury-fw/formatter"];
10
+ export const FRAMEWORK_PACKAGES = ["@mercury-fw/cli", "@mercury-fw/core", "@mercury-fw/formatter", "@mercury-fw/trace-jsonl"];
11
11
 
12
12
  /** The registry asked when `MFW_REGISTRY` doesn't name another. */
13
13
  export const DEFAULT_REGISTRY = "https://registry.npmjs.org";
@@ -12,7 +12,7 @@ import mercuryConfig from "../mercury.config.ts";
12
12
 
13
13
  const app = await composeMercury(mercuryConfig);
14
14
 
15
- const loadedChannels: LoadedChannel[] = loadChannels(app.channels, { runtime: app.channelRuntime });
15
+ const loadedChannels: LoadedChannel[] = loadChannels(app.channels, { runtime: app.channelRuntime, tracer: app.tracer });
16
16
  for (const { name, provider } of loadedChannels) {
17
17
  await provider.start(app.handleTurn);
18
18
  console.error(`[channel] ${name} started`);
@@ -34,6 +34,8 @@ async function shutdown(signal: string): Promise<void> {
34
34
  await provider.stop?.();
35
35
  console.error(`[shutdown] channel ${name} stopped`);
36
36
  }
37
+ // The last events written before the signal, stored before exiting.
38
+ await app.tracer.flush();
37
39
  process.exit(0);
38
40
  }
39
41
  process.on("SIGINT", () => void shutdown("SIGINT"));