@mercury-fw/core 0.31.0 → 0.31.1

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,16 @@
1
1
  # @mercury-fw/core
2
2
 
3
+ ## 0.31.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7926aa2: - Wiki grep ignores case, for the agent, the nightly review, `mfw vault grep` and the HTTP `/wiki/grep` route.
8
+ - The agent's `write_file` and the nightly review's `write_curated` take a path starting with `curated/`, as listing, reading and grepping give it, instead of writing under `curated/curated/`.
9
+ - @mercury-fw/plugin-types@0.31.1
10
+ - @mercury-fw/channel-types@0.31.1
11
+ - @mercury-fw/cli-engine@0.31.1
12
+ - @mercury-fw/confirm-engine@0.31.1
13
+
3
14
  ## 0.31.0
4
15
 
5
16
  ### Patch Changes
@@ -1,3 +1,6 @@
1
+ /** `path` relative to curated/: a vault-relative one (`curated/x.md`, as
2
+ * listing, reading and grepping give it) loses its leading `curated/`. */
3
+ export declare function relativeToCurated(path: string): string;
1
4
  /** Writes a curated doc at `curated/<relativePath>` (e.g. "standards/jira-fields.md"). */
2
5
  export declare function writeCuratedNote(vaultPath: string, relativePath: string, fields: {
3
6
  author?: string;
@@ -19,7 +19,8 @@ export type WikiGrepMatch = {
19
19
  line: number;
20
20
  text: string;
21
21
  };
22
- /** Searches every file under `roots` for `pattern` (a regular expression), line by line. */
22
+ /** Searches every file under `roots` for `pattern` (a regular expression,
23
+ * case-insensitive: a note's wording isn't the question's), line by line. */
23
24
  export declare function grepWikiInRoots(vaultPath: string, roots: string[], pattern: string): Promise<WikiGrepMatch[]>;
24
25
  /** Searches every file visible to `userId` for `pattern` (a regular expression), line by line. */
25
26
  export declare function grepWiki(vaultPath: string, userId: string, pattern: string): Promise<WikiGrepMatch[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mercury-fw/core",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,10 +31,10 @@
31
31
  "test": "bun test"
32
32
  },
33
33
  "dependencies": {
34
- "@mercury-fw/channel-types": "0.31.0",
35
- "@mercury-fw/cli-engine": "0.31.0",
36
- "@mercury-fw/confirm-engine": "0.31.0",
37
- "@mercury-fw/plugin-types": "0.31.0",
34
+ "@mercury-fw/channel-types": "0.31.1",
35
+ "@mercury-fw/cli-engine": "0.31.1",
36
+ "@mercury-fw/confirm-engine": "0.31.1",
37
+ "@mercury-fw/plugin-types": "0.31.1",
38
38
  "@qdrant/js-client-rest": "^1.19.0",
39
39
  "ai": "^7.0.126",
40
40
  "ai-sdk-ollama": "^4.4.0",
@@ -31,7 +31,8 @@ export async function readWikiVaultFile(vaultPath: string, relativePath: string)
31
31
  }
32
32
 
33
33
  export async function grepWikiVault(vaultPath: string, pattern: string): Promise<WikiGrepMatch[]> {
34
- const regex = new RegExp(pattern);
34
+ // Case-insensitive, like every other wiki grep.
35
+ const regex = new RegExp(pattern, "i");
35
36
  const files = await listWikiVault(vaultPath);
36
37
  const matches: WikiGrepMatch[] = [];
37
38
  for (const file of files) {
@@ -19,7 +19,7 @@ import type { ExecutableTool } from "@mercury-fw/plugin-types";
19
19
  import { tool } from "ai";
20
20
  import { z } from "zod";
21
21
  import { listWikiFilesInRoots, readWikiFileInRoots, grepWikiInRoots, selfReviewRoots, readIndexFile } from "./wiki-read.ts";
22
- import { writeCuratedNote, writeIndexFile, deleteRawEntry, deleteCuratedEntry } from "./wiki-note.ts";
22
+ import { writeCuratedNote, writeIndexFile, deleteRawEntry, deleteCuratedEntry, relativeToCurated } from "./wiki-note.ts";
23
23
  import { normalizeIndexKey, upsertIndexEntry, removeIndexEntry } from "./index-entry.ts";
24
24
 
25
25
  export type SelfReviewToolsDeps = { vaultPath: string };
@@ -76,11 +76,12 @@ export function createSelfReviewTools(
76
76
  });
77
77
 
78
78
  const write_curated = tool({
79
- description: 'Create or overwrite a curated doc. "path" is relative to curated/, e.g. "standards/jira-fields.md".',
79
+ description:
80
+ 'Create or overwrite a curated doc. "path" is relative to curated/, e.g. "standards/jira-fields.md"; the path list_files and grep give ("curated/standards/jira-fields.md") works too.',
80
81
  inputSchema: z.object({ path: z.string().min(1), content: z.string() }),
81
82
  execute: async ({ path, content }) => {
82
83
  try {
83
- await writeCuratedNote(vaultPath, path, {}, content);
84
+ await writeCuratedNote(vaultPath, relativeToCurated(path), {}, content);
84
85
  return { ok: true as const };
85
86
  } catch (err) {
86
87
  return { ok: false as const, error: String(err) };
@@ -127,7 +127,7 @@ async function main(): Promise<void> {
127
127
  case "grep": {
128
128
  const pattern = args[0];
129
129
  if (!pattern) usage();
130
- const regex = new RegExp(pattern);
130
+ const regex = new RegExp(pattern, "i");
131
131
  const glob = new Bun.Glob("**/*.md");
132
132
  for await (const file of glob.scan({ cwd: vaultPath })) {
133
133
  const content = await Bun.file(`${vaultPath}/${file}`).text();
@@ -201,6 +201,12 @@ async function deleteVaultFile(vaultPath: string, fullPath: string, commitMessag
201
201
  });
202
202
  }
203
203
 
204
+ /** `path` relative to curated/: a vault-relative one (`curated/x.md`, as
205
+ * listing, reading and grepping give it) loses its leading `curated/`. */
206
+ export function relativeToCurated(path: string): string {
207
+ return path.replace(/^curated\//, "");
208
+ }
209
+
204
210
  /** Writes a curated doc at `curated/<relativePath>` (e.g. "standards/jira-fields.md"). */
205
211
  export async function writeCuratedNote(
206
212
  vaultPath: string,
@@ -88,9 +88,10 @@ export async function readWikiFile(vaultPath: string, userId: string, relativePa
88
88
 
89
89
  export type WikiGrepMatch = { path: string; line: number; text: string };
90
90
 
91
- /** Searches every file under `roots` for `pattern` (a regular expression), line by line. */
91
+ /** Searches every file under `roots` for `pattern` (a regular expression,
92
+ * case-insensitive: a note's wording isn't the question's), line by line. */
92
93
  export async function grepWikiInRoots(vaultPath: string, roots: string[], pattern: string): Promise<WikiGrepMatch[]> {
93
- const regex = new RegExp(pattern);
94
+ const regex = new RegExp(pattern, "i");
94
95
  const files = await listWikiFilesInRoots(vaultPath, roots);
95
96
  const matches: WikiGrepMatch[] = [];
96
97
 
@@ -15,7 +15,7 @@ import type { ExecutableTool } from "@mercury-fw/plugin-types";
15
15
  import { tool } from "ai";
16
16
  import { z } from "zod";
17
17
  import { listWikiFiles, readWikiFile, grepWiki, readWikiFileInRoots } from "./wiki-read.ts";
18
- import { writeCuratedNote } from "./wiki-note.ts";
18
+ import { writeCuratedNote, relativeToCurated } from "./wiki-note.ts";
19
19
 
20
20
  export type WikiToolsDeps = { vaultPath: string; userId: string };
21
21
 
@@ -55,12 +55,13 @@ export function createWikiTools(
55
55
  const write_file = tool({
56
56
  description:
57
57
  'Write or update a curated wiki document (team knowledge — conventions, standards, decisions). "path" ' +
58
- 'is relative to curated/, e.g. "standards/jira-fields.md". This can only write under curated/ — your ' +
58
+ 'is relative to curated/, e.g. "standards/jira-fields.md"; the path grep and read_file give ' +
59
+ '("curated/standards/jira-fields.md") works too. This can only write under curated/ — your ' +
59
60
  "own semantic notes are managed automatically by the memory consolidation process, not through this tool.",
60
61
  inputSchema: z.object({ path: z.string().min(1), content: z.string() }),
61
62
  execute: async ({ path, content }) => {
62
63
  try {
63
- await writeCuratedNote(vaultPath, path, { last_updated: new Date().toISOString().slice(0, 10) }, content);
64
+ await writeCuratedNote(vaultPath, relativeToCurated(path), { last_updated: new Date().toISOString().slice(0, 10) }, content);
64
65
  return { ok: true as const };
65
66
  } catch (err) {
66
67
  return { ok: false as const, error: String(err) };
@@ -70,7 +71,7 @@ export function createWikiTools(
70
71
 
71
72
  const grep = tool({
72
73
  description:
73
- "Search wiki documents (curated/ plus your own inferred/ notes) for a regular expression pattern. " +
74
+ "Search wiki documents (curated/ plus your own inferred/ notes) for a regular expression pattern, ignoring case. " +
74
75
  "Returns matching lines with their file path and line number.",
75
76
  inputSchema: z.object({ pattern: z.string().min(1) }),
76
77
  execute: async ({ pattern }) => {