@abarcenas/ai-workflow-template 1.41.0 → 1.44.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/.agents/instructions/knowledge-retrieval.instructions.md +69 -0
- package/.agents/instructions/knowledgebase.instructions.md +43 -22
- package/.agents/instructions/learned-knowledge.instructions.md +180 -0
- package/.agents/instructions/memory-schema.instructions.md +22 -0
- package/.husky/pre-commit +1 -0
- package/.opencode/agents/architect.agent.md +1 -0
- package/.opencode/agents/coder.agent.md +1 -1
- package/.opencode/agents/deployer.agent.md +3 -2
- package/.opencode/agents/designer.agent.md +4 -3
- package/.opencode/agents/e2e-tester.agent.md +5 -4
- package/.opencode/agents/implementer.agent.md +1 -0
- package/.opencode/agents/orchestrator/feature-pipeline.agent.md +6 -2
- package/.opencode/agents/orchestrator/orchestrator.agent.md +5 -1
- package/.opencode/agents/orchestrator/tdd-orchestrator.agent.md +7 -1
- package/.opencode/agents/researcher.agent.md +9 -1
- package/.opencode/agents/reviewer.agent.md +2 -0
- package/.opencode/agents/tracker.agent.md +8 -6
- package/.opencode/agents/unit-tester.agent.md +6 -5
- package/README.md +124 -304
- package/memory-bank/.vocabulary.json +125 -31
- package/package.json +1 -1
- package/scripts/mcp-knowledgebase-server.js +85 -19
- package/scripts/mcp-knowledgebase-server.test.js +745 -0
- package/scripts/setup/constants.js +2 -1
- package/scripts/sync.js +1 -0
- package/scripts/sync.test.js +4 -3
- package/scripts/validate-memory-schema.js +28 -3
- package/scripts/validate-memory-schema.test.js +328 -0
- package/scripts/vocab-sync.js +216 -0
- package/scripts/vocab-sync.test.js +814 -0
|
@@ -9,50 +9,144 @@
|
|
|
9
9
|
"task": "Individual task tracking (tasks/TASK*.md)",
|
|
10
10
|
"decision": "ADR-style architecture/technical decisions"
|
|
11
11
|
},
|
|
12
|
-
|
|
13
12
|
"tags": {
|
|
14
13
|
"agent_roles": [
|
|
15
|
-
"designer",
|
|
16
|
-
"
|
|
14
|
+
"designer",
|
|
15
|
+
"architect",
|
|
16
|
+
"researcher",
|
|
17
|
+
"coder",
|
|
18
|
+
"implementer",
|
|
19
|
+
"tester",
|
|
20
|
+
"reviewer",
|
|
21
|
+
"tracker",
|
|
22
|
+
"deployer",
|
|
23
|
+
"orchestrator"
|
|
17
24
|
],
|
|
18
25
|
"workflow": [
|
|
19
|
-
"bootstrap",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
26
|
+
"bootstrap",
|
|
27
|
+
"setup",
|
|
28
|
+
"configuration",
|
|
29
|
+
"migration",
|
|
30
|
+
"refactor",
|
|
31
|
+
"tdd",
|
|
32
|
+
"feature-pipeline",
|
|
33
|
+
"onboarding",
|
|
34
|
+
"normalization",
|
|
35
|
+
"research",
|
|
36
|
+
"spike",
|
|
37
|
+
"implementation",
|
|
38
|
+
"implementation-planning",
|
|
22
39
|
"documentation"
|
|
23
40
|
],
|
|
24
41
|
"memory_ops": [
|
|
25
|
-
"decision",
|
|
26
|
-
"
|
|
42
|
+
"decision",
|
|
43
|
+
"discovery",
|
|
44
|
+
"status-update",
|
|
45
|
+
"task-plan",
|
|
46
|
+
"retrospective",
|
|
47
|
+
"bug-fix",
|
|
48
|
+
"verification"
|
|
27
49
|
],
|
|
28
50
|
"topic": [
|
|
29
|
-
"
|
|
30
|
-
"
|
|
51
|
+
"agent-exercise",
|
|
52
|
+
"agents",
|
|
53
|
+
"chunk-parser",
|
|
54
|
+
"commit",
|
|
55
|
+
"credential",
|
|
56
|
+
"dotenv",
|
|
57
|
+
"embeddings",
|
|
58
|
+
"env-remediation",
|
|
59
|
+
"feature-vocab-sync",
|
|
60
|
+
"fix-kb-registerproject",
|
|
61
|
+
"float32array",
|
|
62
|
+
"git",
|
|
63
|
+
"graceful-failure",
|
|
64
|
+
"knowledge-vector-gaps",
|
|
65
|
+
"knowledgebase",
|
|
66
|
+
"learned-knowledge",
|
|
67
|
+
"mcp",
|
|
68
|
+
"package-structure",
|
|
69
|
+
"pgvector",
|
|
70
|
+
"pipeline-follow-up",
|
|
71
|
+
"pre-commit",
|
|
72
|
+
"readme",
|
|
73
|
+
"security",
|
|
74
|
+
"test-hardening",
|
|
75
|
+
"vocabulary"
|
|
31
76
|
]
|
|
32
77
|
},
|
|
33
|
-
|
|
34
78
|
"entity_patterns": {
|
|
35
|
-
"vitest":
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
79
|
+
"vitest": [
|
|
80
|
+
"vitest",
|
|
81
|
+
"vitest\\.config",
|
|
82
|
+
"@vitest\\/coverage"
|
|
83
|
+
],
|
|
84
|
+
"playwright": [
|
|
85
|
+
"playwright",
|
|
86
|
+
"@playwright",
|
|
87
|
+
"browser.*test"
|
|
88
|
+
],
|
|
89
|
+
"graphify": [
|
|
90
|
+
"graphify",
|
|
91
|
+
"knowledge graph",
|
|
92
|
+
"graph\\.json"
|
|
93
|
+
],
|
|
94
|
+
"memory-bank": [
|
|
95
|
+
"memory-bank",
|
|
96
|
+
"memory bank",
|
|
97
|
+
"activeContext",
|
|
98
|
+
"systemPatterns"
|
|
99
|
+
],
|
|
100
|
+
"husky": [
|
|
101
|
+
"husky",
|
|
102
|
+
"pre-commit",
|
|
103
|
+
"git hook"
|
|
104
|
+
],
|
|
105
|
+
"tdd-orchestrator": [
|
|
106
|
+
"tdd orchestrator",
|
|
107
|
+
"RED.*GREEN.*REFACTOR"
|
|
108
|
+
],
|
|
109
|
+
"mcp-server": [
|
|
110
|
+
"mcp",
|
|
111
|
+
"modelcontextprotocol",
|
|
112
|
+
"stdio",
|
|
113
|
+
"mcp server"
|
|
114
|
+
],
|
|
115
|
+
"sqlite-vec": [
|
|
116
|
+
"sqlite-vec",
|
|
117
|
+
"sqlite.vec",
|
|
118
|
+
"better-sqlite3"
|
|
119
|
+
],
|
|
120
|
+
"transformers.js": [
|
|
121
|
+
"@xenova\\/transformers",
|
|
122
|
+
"transformers\\.js",
|
|
123
|
+
"all-MiniLM"
|
|
124
|
+
],
|
|
125
|
+
"opencode": [
|
|
126
|
+
"opencode",
|
|
127
|
+
"OpenCode",
|
|
128
|
+
"open code"
|
|
129
|
+
],
|
|
130
|
+
"npm": [
|
|
131
|
+
"npm",
|
|
132
|
+
"npm package",
|
|
133
|
+
"npm install"
|
|
134
|
+
]
|
|
46
135
|
},
|
|
47
|
-
|
|
48
136
|
"file_category_map": {
|
|
49
|
-
"projectbrief":
|
|
50
|
-
"productContext":
|
|
51
|
-
"systemPatterns":
|
|
52
|
-
"techContext":
|
|
53
|
-
"activeContext":
|
|
54
|
-
"progress":
|
|
137
|
+
"projectbrief": "brief",
|
|
138
|
+
"productContext": "product",
|
|
139
|
+
"systemPatterns": "architecture",
|
|
140
|
+
"techContext": "tech",
|
|
141
|
+
"activeContext": "context",
|
|
142
|
+
"progress": "progress"
|
|
55
143
|
},
|
|
56
|
-
|
|
57
|
-
|
|
144
|
+
"doc_types": [
|
|
145
|
+
"spike",
|
|
146
|
+
"architecture",
|
|
147
|
+
"configuration",
|
|
148
|
+
"orchestrator-log",
|
|
149
|
+
"tracker-log",
|
|
150
|
+
"decision"
|
|
151
|
+
]
|
|
58
152
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abarcenas/ai-workflow-template",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.44.0",
|
|
4
4
|
"description": "A comprehensive template repository for AI-assisted development workflows using GitHub Copilot. This template provides a structured approach to leveraging AI assistance through pre-configured skills, prompts, agents, and coding standards.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,11 +30,13 @@ import {
|
|
|
30
30
|
chunkLearnedKnowledge,
|
|
31
31
|
getStats,
|
|
32
32
|
listProjects,
|
|
33
|
+
registerProject,
|
|
33
34
|
getPool,
|
|
34
35
|
closePool,
|
|
35
36
|
} from './knowledgebase-index.js';
|
|
36
37
|
import { readFileSync } from 'node:fs';
|
|
37
38
|
import { resolve } from 'node:path';
|
|
39
|
+
import { fileURLToPath } from 'node:url';
|
|
38
40
|
|
|
39
41
|
const server = new Server(
|
|
40
42
|
{
|
|
@@ -72,7 +74,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
72
74
|
},
|
|
73
75
|
threshold: {
|
|
74
76
|
type: 'number',
|
|
75
|
-
default: 0.
|
|
77
|
+
default: 0.1,
|
|
76
78
|
description: 'Minimum similarity threshold (0.0–1.0). Higher values return fewer but more relevant results.',
|
|
77
79
|
},
|
|
78
80
|
limit: {
|
|
@@ -130,18 +132,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
130
132
|
],
|
|
131
133
|
}));
|
|
132
134
|
|
|
135
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Redact connection-string credentials from an error message.
|
|
139
|
+
*
|
|
140
|
+
* Every postgres:// or postgresql:// URL token in the message has its
|
|
141
|
+
* userinfo credentials replaced with *** and its query string (or fragment)
|
|
142
|
+
* replaced with ?*** / #***, while the host and path are preserved verbatim
|
|
143
|
+
* (e.g. postgres://user:secret@host:5432/kb?password=hunter2 →
|
|
144
|
+
* postgres://***@host:5432/kb?***). Messages without a URL token are returned
|
|
145
|
+
* unchanged so generic errors (e.g. "Unknown tool: ...") stay readable — the
|
|
146
|
+
* engine helper returns '***' for non-URLs, which would hide every error
|
|
147
|
+
* message.
|
|
148
|
+
*
|
|
149
|
+
* Unlike the engine helper (knowledgebase-index.js:62) — which fails closed
|
|
150
|
+
* by returning '***' when `new URL()` throws — this helper FAILS CLOSED on
|
|
151
|
+
* unparseable tokens by using a pure regex instead of URL parsing: libpq
|
|
152
|
+
* unix-socket authorities such as postgres://user:secret@/var/run/postgresql
|
|
153
|
+
* (or postgresql://user:secret@/tmp?host=/tmp) make `new URL()` throw, so a
|
|
154
|
+
* parse-based helper would return the message unchanged and leak the
|
|
155
|
+
* credentials. The regex strips the userinfo and the query/fragment from
|
|
156
|
+
* EVERY token and preserves the host/path even when the URL cannot be parsed.
|
|
157
|
+
*
|
|
158
|
+
* @param {string} message
|
|
159
|
+
* @returns {string}
|
|
160
|
+
*/
|
|
161
|
+
function redactConnectionString(message) {
|
|
162
|
+
if (typeof message !== 'string' || message.length === 0) return message;
|
|
163
|
+
return message.replace(
|
|
164
|
+
/(postgres(?:ql)?:\/\/)([^/\s]+)@([^?#\s]*)([?#][^\s]*)?/gi,
|
|
165
|
+
(match, scheme, userinfo, hostAndPath, queryOrFragment) =>
|
|
166
|
+
`${scheme}***@${hostAndPath}${queryOrFragment ? queryOrFragment[0] + '***' : ''}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
133
170
|
// ── Handle tool calls ────────────────────────────────────────────────
|
|
134
171
|
|
|
135
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Handle an MCP tool call.
|
|
174
|
+
*
|
|
175
|
+
* Exported for testability — the stdio bootstrap (main) is guarded to
|
|
176
|
+
* direct-run only, so tests can import this handler without opening a
|
|
177
|
+
* stdio transport or a database connection.
|
|
178
|
+
* @param {{ params: { name: string, arguments: Record<string, any> } }} request
|
|
179
|
+
* @returns {Promise<{ content: Array<{ type: string, text: string }>, isError?: boolean }>}
|
|
180
|
+
*/
|
|
181
|
+
export async function handleToolCall(request) {
|
|
136
182
|
const { name, arguments: args } = request.params;
|
|
137
183
|
|
|
138
184
|
try {
|
|
139
185
|
switch (name) {
|
|
140
186
|
case 'knowledgebase_search': {
|
|
187
|
+
// projectId is an optional filter — a whitespace-only value is dropped
|
|
188
|
+
// to match-all (graceful degradation, mirroring the INDEX handler's
|
|
189
|
+
// trim/validate parity) and the trimmed value is passed to the engine.
|
|
141
190
|
const results = await search(args.query, {
|
|
142
|
-
project_id: args.projectId || undefined,
|
|
191
|
+
project_id: args.projectId?.trim() || undefined,
|
|
143
192
|
threshold: args.threshold ?? 0.1,
|
|
144
|
-
limit: args.limit
|
|
193
|
+
limit: args.limit ?? 5,
|
|
145
194
|
});
|
|
146
195
|
|
|
147
196
|
if (results.length === 0) {
|
|
@@ -180,7 +229,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
180
229
|
|
|
181
230
|
case 'knowledgebase_index': {
|
|
182
231
|
const projectId = args.projectId;
|
|
183
|
-
if (!projectId) {
|
|
232
|
+
if (!projectId?.trim()) {
|
|
184
233
|
return {
|
|
185
234
|
content: [{
|
|
186
235
|
type: 'text',
|
|
@@ -189,6 +238,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
189
238
|
isError: true,
|
|
190
239
|
};
|
|
191
240
|
}
|
|
241
|
+
const pid = projectId.trim();
|
|
192
242
|
|
|
193
243
|
let content = args.content;
|
|
194
244
|
if (!content) {
|
|
@@ -213,25 +263,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
213
263
|
}
|
|
214
264
|
}
|
|
215
265
|
|
|
216
|
-
const chunks = chunkLearnedKnowledge(content,
|
|
266
|
+
const chunks = chunkLearnedKnowledge(content, pid);
|
|
217
267
|
if (chunks.length === 0) {
|
|
218
268
|
return {
|
|
219
269
|
content: [{
|
|
220
270
|
type: 'text',
|
|
221
|
-
text: `No valid knowledge chunks found for project "${
|
|
271
|
+
text: `No valid knowledge chunks found for project "${pid}". ` +
|
|
222
272
|
'Ensure the content contains "## Session:" headers with ' +
|
|
223
273
|
'"**New knowledge:**" sections.',
|
|
224
274
|
}],
|
|
225
275
|
};
|
|
226
276
|
}
|
|
227
277
|
|
|
278
|
+
// Register/update the project in the projects table (idempotent upsert)
|
|
279
|
+
await registerProject(pid, pid);
|
|
280
|
+
|
|
228
281
|
const result = await upsertChunks(chunks);
|
|
229
282
|
return {
|
|
230
283
|
content: [{
|
|
231
284
|
type: 'text',
|
|
232
285
|
text:
|
|
233
286
|
`Indexed ${result.inserted} chunks, updated ${result.updated}, ` +
|
|
234
|
-
`skipped ${result.skipped} for project "${
|
|
287
|
+
`skipped ${result.skipped} for project "${pid}".`,
|
|
235
288
|
}],
|
|
236
289
|
};
|
|
237
290
|
}
|
|
@@ -307,12 +360,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
307
360
|
return {
|
|
308
361
|
content: [{
|
|
309
362
|
type: 'text',
|
|
310
|
-
text: `Error: ${err.message}`,
|
|
363
|
+
text: `Error: ${redactConnectionString(err.message)}`,
|
|
311
364
|
}],
|
|
312
365
|
isError: true,
|
|
313
366
|
};
|
|
314
367
|
}
|
|
315
|
-
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
server.setRequestHandler(CallToolRequestSchema, handleToolCall);
|
|
316
371
|
|
|
317
372
|
// ── Start server ─────────────────────────────────────────────────────
|
|
318
373
|
|
|
@@ -322,13 +377,24 @@ async function main() {
|
|
|
322
377
|
console.error('[knowledgebase-mcp] Server started via stdio transport');
|
|
323
378
|
}
|
|
324
379
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
380
|
+
/**
|
|
381
|
+
* Only start the stdio server when this file is executed directly
|
|
382
|
+
* (node scripts/mcp-knowledgebase-server.js). When the module is imported
|
|
383
|
+
* — e.g. by tests exercising the exported handleToolCall — no stdio
|
|
384
|
+
* transport is opened and the process can exit cleanly.
|
|
385
|
+
*/
|
|
386
|
+
const isDirectRun =
|
|
387
|
+
process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
330
388
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
});
|
|
389
|
+
if (isDirectRun) {
|
|
390
|
+
process.on('SIGTERM', () => {
|
|
391
|
+
console.error('[knowledgebase-mcp] SIGTERM received, closing pool');
|
|
392
|
+
closePool().catch(() => {});
|
|
393
|
+
process.exit(0);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
main().catch((err) => {
|
|
397
|
+
console.error('[knowledgebase-mcp] Fatal error:', err);
|
|
398
|
+
process.exit(1);
|
|
399
|
+
});
|
|
400
|
+
}
|