mcp-memory-bucket 0.5.0 → 0.5.3
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/dist/client/assets/{index-DSHtiYCt.js → index-CqgDoHFV.js} +484 -215
- package/dist/client/index.html +1 -1
- package/dist/src/memory/repository.js +1 -1
- package/dist/src/memory/tools.js +9 -6
- package/dist/src/shared/relocate-tool.js +2 -1
- package/dist/src/shared/status.js +23 -0
- package/dist/src/skills/tools.js +7 -6
- package/package.json +1 -1
package/dist/client/index.html
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
:root[data-theme='dark'] { color-scheme: dark; }
|
|
28
28
|
body { font-family: system-ui, sans-serif; margin: 0; background: var(--bg); color: var(--fg); }
|
|
29
29
|
</style>
|
|
30
|
-
<script type="module" crossorigin src="/assets/index-
|
|
30
|
+
<script type="module" crossorigin src="/assets/index-CqgDoHFV.js"></script>
|
|
31
31
|
</head>
|
|
32
32
|
<body>
|
|
33
33
|
<mem-bucket-app></mem-bucket-app>
|
|
@@ -172,7 +172,7 @@ export class MemoryRepository {
|
|
|
172
172
|
description: input.description,
|
|
173
173
|
doc_type: input.doc_type,
|
|
174
174
|
tags: input.tags ?? [],
|
|
175
|
-
status: 'active',
|
|
175
|
+
status: input.status ?? 'active',
|
|
176
176
|
related_to: input.related_to ?? null,
|
|
177
177
|
deprecated: false,
|
|
178
178
|
created_at: new Date().toISOString(),
|
package/dist/src/memory/tools.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { statusSchema } from '../shared/status.js';
|
|
2
3
|
const MEMORY_DOC_TYPES = ['plan', 'spec', 'sql', 'testing-todo', 'discovery', 'session-summary', 'other'];
|
|
3
4
|
const MEMORY_KEY_TYPES = ['ticket', 'freeform'];
|
|
4
|
-
const
|
|
5
|
+
const MEMORY_STATUS_DEFAULTS = ['active', 'shipped', 'abandoned'];
|
|
5
6
|
const AUTHORING_SKILL_HINT = "Before your first call in a session, run skill_get(\"memory-bucket-authoring\") to learn the exact frontmatter schema and conventions — don't guess the shape.";
|
|
6
7
|
export function registerMemoryTools(mcp, repo) {
|
|
7
8
|
const roots = repo.listRoots();
|
|
@@ -26,7 +27,7 @@ export function registerMemoryTools(mcp, repo) {
|
|
|
26
27
|
mcp.tool('memory_search', 'Full-text search over memory doc description/body/tags (grep/find-like, ranked by relevance) — unlike memory_get\'s exact-key lookup, this searches by content across all keys. `query` is raw SQLite FTS5 MATCH syntax: bare words, "exact phrases", prefix* wildcards, AND/OR/NOT boolean operators; hyphenated/punctuated terms must be quoted, e.g. "blue-green". Can be combined with doc_type/status/tag filters. Returns ranked hits with a highlighted snippet, not the full body — call memory_get(key) or fetch by id for that. Paused docs are hidden by default — pass include_paused to see them.', {
|
|
27
28
|
query: z.string().describe('FTS5 match expression, e.g. `migration AND rollback` or `"blue green"`'),
|
|
28
29
|
doc_type: z.enum(MEMORY_DOC_TYPES).optional(),
|
|
29
|
-
status:
|
|
30
|
+
status: statusSchema(MEMORY_STATUS_DEFAULTS).optional(),
|
|
30
31
|
tag: z.string().optional(),
|
|
31
32
|
...(multiRoot ? { root: z.string().optional().describe(`filter to one root: ${rootNames}`) } : {}),
|
|
32
33
|
limit: z.number().int().positive().max(100).optional(),
|
|
@@ -45,7 +46,7 @@ export function registerMemoryTools(mcp, repo) {
|
|
|
45
46
|
ids: z.array(z.string()).min(1),
|
|
46
47
|
add_tags: z.array(z.string()).optional(),
|
|
47
48
|
remove_tags: z.array(z.string()).optional(),
|
|
48
|
-
status:
|
|
49
|
+
status: statusSchema(MEMORY_STATUS_DEFAULTS).optional(),
|
|
49
50
|
related_to: z.string().nullable().optional(),
|
|
50
51
|
deprecated: z.boolean().optional().describe('marks docs as deprecated (or un-deprecates when false) — independent of status'),
|
|
51
52
|
}, async ({ ids, add_tags, remove_tags, status, related_to, deprecated }) => {
|
|
@@ -59,12 +60,13 @@ export function registerMemoryTools(mcp, repo) {
|
|
|
59
60
|
description: z.string().describe('distinguishes this doc from others sharing the same key'),
|
|
60
61
|
body: z.string(),
|
|
61
62
|
tags: z.array(z.string()).optional(),
|
|
63
|
+
status: statusSchema(MEMORY_STATUS_DEFAULTS).optional().describe('defaults to "active"'),
|
|
62
64
|
related_to: z.string().optional().describe('id of a related doc, e.g. a spec linking to its plan'),
|
|
63
65
|
folder: z.string().optional().describe('optional subdirectory under the memory root'),
|
|
64
66
|
...(multiRoot ? { root: z.string().describe(`which configured memory root to write into: ${rootNames}`) } : {}),
|
|
65
|
-
}, async ({ key, key_type, doc_type, description, body, tags, related_to, folder, root }) => {
|
|
67
|
+
}, async ({ key, key_type, doc_type, description, body, tags, status, related_to, folder, root }) => {
|
|
66
68
|
try {
|
|
67
|
-
const doc = repo.create({ key, key_type, doc_type, description, body, tags, related_to, folder, root });
|
|
69
|
+
const doc = repo.create({ key, key_type, doc_type, description, body, tags, status, related_to, folder, root });
|
|
68
70
|
return { content: [{ type: 'text', text: JSON.stringify(doc, null, 2) }] };
|
|
69
71
|
}
|
|
70
72
|
catch (err) {
|
|
@@ -78,6 +80,7 @@ export function registerMemoryTools(mcp, repo) {
|
|
|
78
80
|
description: z.string().describe('distinguishes this doc from others sharing the same key'),
|
|
79
81
|
body: z.string(),
|
|
80
82
|
tags: z.array(z.string()).optional(),
|
|
83
|
+
status: statusSchema(MEMORY_STATUS_DEFAULTS).optional().describe('defaults to "active"'),
|
|
81
84
|
related_to: z.string().optional(),
|
|
82
85
|
folder: z.string().optional(),
|
|
83
86
|
...(multiRoot ? { root: z.string().describe(`which configured memory root to write into: ${rootNames}`) } : {}),
|
|
@@ -94,7 +97,7 @@ export function registerMemoryTools(mcp, repo) {
|
|
|
94
97
|
description: z.string().optional(),
|
|
95
98
|
body: z.string().optional(),
|
|
96
99
|
tags: z.array(z.string()).optional(),
|
|
97
|
-
status:
|
|
100
|
+
status: statusSchema(MEMORY_STATUS_DEFAULTS).optional(),
|
|
98
101
|
related_to: z.string().optional(),
|
|
99
102
|
deprecated: z.boolean().optional().describe('marks the doc as deprecated (or un-deprecates when false) — independent of status'),
|
|
100
103
|
}, async ({ id, body, ...frontmatterFields }) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { relocate, relocateMany } from './relocate.js';
|
|
3
|
+
import { statusSchema } from './status.js';
|
|
3
4
|
const AUTHORING_SKILL_HINT = "Before your first call in a session, run skill_get(\"memory-bucket-authoring\") to learn the exact frontmatter schema and conventions — don't guess the shape.";
|
|
4
5
|
const overridesSchema = z
|
|
5
6
|
.object({
|
|
@@ -13,7 +14,7 @@ const overridesSchema = z
|
|
|
13
14
|
key_type: z.enum(['ticket', 'freeform']).optional().describe('memory target only'),
|
|
14
15
|
doc_type: z.enum(['plan', 'spec', 'sql', 'testing-todo', 'discovery', 'session-summary', 'other']).optional().describe('memory target only'),
|
|
15
16
|
tags: z.array(z.string()).optional(),
|
|
16
|
-
status:
|
|
17
|
+
status: statusSchema(['stable', 'beta', 'unreviewed', 'active', 'shipped', 'abandoned']).optional(),
|
|
17
18
|
folder: z.string().optional().describe('optional subdirectory under the target root'),
|
|
18
19
|
root: z.string().optional().describe('which configured root to write into; required if multiple roots exist for the target type'),
|
|
19
20
|
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Status is a free-form label, not a closed enum — the DB column has no CHECK
|
|
4
|
+
* constraint and the web UI's filter dropdown is populated from distinct values
|
|
5
|
+
* actually in use (see buildFacets in web/routes.ts), so any normalized string
|
|
6
|
+
* works end to end. This schema only enforces a consistent shape (lowercase,
|
|
7
|
+
* hyphenated) so casing/typo variants don't silently fragment that dropdown.
|
|
8
|
+
*/
|
|
9
|
+
const STATUS_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
10
|
+
export function normalizeStatus(status) {
|
|
11
|
+
return status.trim().toLowerCase().replace(/\s+/g, '-');
|
|
12
|
+
}
|
|
13
|
+
export function statusSchema(defaults) {
|
|
14
|
+
return z
|
|
15
|
+
.string()
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(40)
|
|
18
|
+
.transform(normalizeStatus)
|
|
19
|
+
.refine((s) => STATUS_PATTERN.test(s), {
|
|
20
|
+
message: 'status must be lowercase alphanumeric with hyphens, e.g. "active" or "needs-review"',
|
|
21
|
+
})
|
|
22
|
+
.describe(`free-form status label, normalized to lowercase-hyphenated; conventional values: ${defaults.join(', ')} — but any value is accepted`);
|
|
23
|
+
}
|
package/dist/src/skills/tools.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
2
|
+
import { statusSchema } from '../shared/status.js';
|
|
3
|
+
const SKILL_STATUS_DEFAULTS = ['stable', 'beta', 'unreviewed'];
|
|
3
4
|
const SKILL_NAME_DESCRIPTION = 'stable id, must be 1-64 chars, lowercase letters/numbers/hyphens only, no leading/trailing/consecutive hyphens — this becomes the skill\'s folder name (agentskills.io spec requirement)';
|
|
4
5
|
const AUTHORING_SKILL_HINT = "Before your first call in a session, run skill_get(\"memory-bucket-authoring\") to learn the exact frontmatter schema and conventions — don't guess the shape.";
|
|
5
6
|
export function registerSkillTools(mcp, repo) {
|
|
@@ -21,7 +22,7 @@ export function registerSkillTools(mcp, repo) {
|
|
|
21
22
|
});
|
|
22
23
|
mcp.tool('skill_search', 'Full-text search over skill description/body/tags (grep/find-like, ranked by relevance) — unlike skill_list\'s substring metadata filter, this searches the full markdown body. `query` is raw SQLite FTS5 MATCH syntax: bare words, "exact phrases", prefix* wildcards, AND/OR/NOT boolean operators; hyphenated/punctuated terms must be quoted, e.g. "blue-green". Can be combined with status/owner/tag filters. Returns ranked hits with a highlighted snippet, not the full body — call skill_get on a hit\'s name for that. Paused skills are hidden by default — pass include_paused to see them.', {
|
|
23
24
|
query: z.string().describe('FTS5 match expression, e.g. `deploy AND rollback` or `"blue green"`'),
|
|
24
|
-
status:
|
|
25
|
+
status: statusSchema(SKILL_STATUS_DEFAULTS).optional(),
|
|
25
26
|
owner: z.string().optional(),
|
|
26
27
|
tag: z.string().optional(),
|
|
27
28
|
limit: z.number().int().positive().max(100).optional(),
|
|
@@ -42,7 +43,7 @@ export function registerSkillTools(mcp, repo) {
|
|
|
42
43
|
add_tags: z.array(z.string()).optional(),
|
|
43
44
|
remove_tags: z.array(z.string()).optional(),
|
|
44
45
|
owner: z.string().nullable().optional(),
|
|
45
|
-
status:
|
|
46
|
+
status: statusSchema(SKILL_STATUS_DEFAULTS).optional(),
|
|
46
47
|
extends: z.string().nullable().optional(),
|
|
47
48
|
deprecated: z.boolean().optional().describe('marks skills as deprecated (or un-deprecates when false) — independent of status'),
|
|
48
49
|
}, async ({ names, add_tags, remove_tags, owner, status, extends: extendsId, deprecated }) => {
|
|
@@ -70,7 +71,7 @@ export function registerSkillTools(mcp, repo) {
|
|
|
70
71
|
license: z.string().optional(),
|
|
71
72
|
compatibility: z.string().max(500).optional().describe('only needed if the skill has specific environment requirements'),
|
|
72
73
|
owner: z.string().optional().describe('squad or "company" — stored in frontmatter.metadata, unused for resolution in V0'),
|
|
73
|
-
status:
|
|
74
|
+
status: statusSchema(SKILL_STATUS_DEFAULTS).optional().describe('defaults to "unreviewed"; stored in frontmatter.metadata'),
|
|
74
75
|
tags: z.array(z.string()).optional(),
|
|
75
76
|
trigger_phrases: z.array(z.string()).optional(),
|
|
76
77
|
extends: z.string().optional().describe('reserved for a future overlay mechanism — stored in frontmatter.metadata'),
|
|
@@ -92,7 +93,7 @@ export function registerSkillTools(mcp, repo) {
|
|
|
92
93
|
license: z.string().optional(),
|
|
93
94
|
compatibility: z.string().max(500).optional(),
|
|
94
95
|
owner: z.string().optional(),
|
|
95
|
-
status:
|
|
96
|
+
status: statusSchema(SKILL_STATUS_DEFAULTS).optional(),
|
|
96
97
|
tags: z.array(z.string()).optional(),
|
|
97
98
|
trigger_phrases: z.array(z.string()).optional(),
|
|
98
99
|
extends: z.string().optional(),
|
|
@@ -125,7 +126,7 @@ export function registerSkillTools(mcp, repo) {
|
|
|
125
126
|
license: z.string().optional(),
|
|
126
127
|
compatibility: z.string().max(500).optional(),
|
|
127
128
|
owner: z.string().optional(),
|
|
128
|
-
status:
|
|
129
|
+
status: statusSchema(SKILL_STATUS_DEFAULTS).optional(),
|
|
129
130
|
tags: z.array(z.string()).optional(),
|
|
130
131
|
trigger_phrases: z.array(z.string()).optional(),
|
|
131
132
|
extends: z.string().optional(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing skill_* (reusable coding patterns) and memory_* (point-in-time working context) tools over a markdown+frontmatter source, cached into SQLite at runtime.",
|
|
6
6
|
"repository": {
|