@abarcenas/ai-workflow-template 1.34.0 → 1.38.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/knowledgebase.instructions.md +238 -0
- package/.agents/instructions/learned-knowledge.instructions.md +71 -0
- package/.husky/post-commit +10 -0
- package/.husky/post-merge +0 -1
- package/.opencode/agents/architect.agent.md +1 -0
- package/.opencode/agents/coder.agent.md +1 -0
- package/.opencode/agents/deployer.agent.md +1 -0
- package/.opencode/agents/designer.agent.md +1 -0
- package/.opencode/agents/e2e-tester.agent.md +1 -0
- package/.opencode/agents/implementer.agent.md +1 -0
- package/.opencode/agents/orchestrator/feature-pipeline.agent.md +1 -0
- package/.opencode/agents/orchestrator/orchestrator.agent.md +1 -0
- package/.opencode/agents/orchestrator/tdd-orchestrator.agent.md +1 -0
- package/.opencode/agents/researcher.agent.md +1 -0
- package/.opencode/agents/reviewer.agent.md +1 -0
- package/.opencode/agents/tracker.agent.md +2 -0
- package/.opencode/agents/unit-tester.agent.md +1 -0
- package/README.md +1 -1
- package/memory-bank/.vocabulary.json +8 -2
- package/package.json +12 -6
- package/scripts/knowledgebase-cli.js +228 -0
- package/scripts/knowledgebase-cli.test.js +576 -0
- package/scripts/knowledgebase-index.js +780 -0
- package/scripts/knowledgebase-index.test.js +759 -0
- package/scripts/knowledgebase-init.sql +193 -0
- package/scripts/mcp-knowledgebase-server.js +330 -0
- package/scripts/setup/constants.js +36 -3
- package/scripts/setup/hooks.js +2 -2
- package/scripts/setup/hooks.test.js +13 -5
- package/scripts/setup/index.js +29 -2
- package/scripts/setup/index.test.js +36 -1
- package/scripts/setup/knowledgebase.js +204 -0
- package/scripts/setup/knowledgebase.test.js +248 -0
- package/scripts/sync.js +40 -6
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* knowledgebase-cli.js — CLI for knowledgebase operations.
|
|
5
|
+
*
|
|
6
|
+
* Supports sync (index learned knowledge), search (semantic search),
|
|
7
|
+
* list (indexed projects), and stats (knowledgebase summary).
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/knowledgebase-cli.js sync
|
|
11
|
+
* node scripts/knowledgebase-cli.js search "<query>" [--project <id>] [--threshold <n>] [--topK <n>]
|
|
12
|
+
*
|
|
13
|
+
* Default threshold is 0.0 (no minimum), relying on --topK to limit results.
|
|
14
|
+
* node scripts/knowledgebase-cli.js list
|
|
15
|
+
* node scripts/knowledgebase-cli.js stats
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
import { resolve } from 'node:path';
|
|
20
|
+
|
|
21
|
+
// Load .env file into process.env before any configuration reads
|
|
22
|
+
import 'dotenv/config';
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
chunkLearnedKnowledge,
|
|
26
|
+
closePool,
|
|
27
|
+
getStats,
|
|
28
|
+
listProjects,
|
|
29
|
+
registerProject,
|
|
30
|
+
search,
|
|
31
|
+
upsertChunks,
|
|
32
|
+
} from './knowledgebase-index.js';
|
|
33
|
+
|
|
34
|
+
const args = process.argv.slice(2);
|
|
35
|
+
const command = args[0];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Parse --flags from argv, returning { flags, positional }.
|
|
39
|
+
* @param {string[]} argv
|
|
40
|
+
* @returns {{ flags: Record<string, any>, positional: string[] }}
|
|
41
|
+
*/
|
|
42
|
+
function parseFlags(argv) {
|
|
43
|
+
const flags = {};
|
|
44
|
+
const positional = [];
|
|
45
|
+
for (let i = 0; i < argv.length; i++) {
|
|
46
|
+
if (argv[i] === '--project' && i + 1 < argv.length) {
|
|
47
|
+
flags.projectId = argv[++i];
|
|
48
|
+
} else if (argv[i] === '--threshold' && i + 1 < argv.length) {
|
|
49
|
+
flags.threshold = parseFloat(argv[++i]);
|
|
50
|
+
} else if (argv[i] === '--topK' && i + 1 < argv.length) {
|
|
51
|
+
flags.topK = parseInt(argv[++i], 10);
|
|
52
|
+
} else {
|
|
53
|
+
positional.push(argv[i]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Validate threshold range
|
|
58
|
+
if (flags.threshold != null && (isNaN(flags.threshold) || flags.threshold < 0 || flags.threshold > 1)) {
|
|
59
|
+
console.error('[knowledgebase] --threshold must be a number between 0.0 and 1.0');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { flags, positional };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve project ID from --project flag or package.json name field.
|
|
68
|
+
* @param {{ projectId?: string }} flags
|
|
69
|
+
* @returns {string|null}
|
|
70
|
+
*/
|
|
71
|
+
function resolveProjectId(flags) {
|
|
72
|
+
if (flags.projectId) return flags.projectId;
|
|
73
|
+
try {
|
|
74
|
+
const pkg = JSON.parse(readFileSync(resolve('package.json'), 'utf8'));
|
|
75
|
+
return pkg.name || null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function main() {
|
|
82
|
+
try {
|
|
83
|
+
switch (command) {
|
|
84
|
+
// ── sync ──────────────────────────────────────────────────
|
|
85
|
+
case 'sync': {
|
|
86
|
+
const { flags } = parseFlags(args.slice(1));
|
|
87
|
+
|
|
88
|
+
// Graceful degradation when DATABASE_URL is not configured
|
|
89
|
+
if (!process.env.DATABASE_URL) {
|
|
90
|
+
console.log('[knowledgebase] Skipping sync — DATABASE_URL not configured');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Resolve project identifier
|
|
95
|
+
const projectId = resolveProjectId(flags);
|
|
96
|
+
if (!projectId) {
|
|
97
|
+
console.error(
|
|
98
|
+
'[knowledgebase] Could not determine project ID. ' +
|
|
99
|
+
'Provide --project <id> or ensure package.json has a "name" field.'
|
|
100
|
+
);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Read learned-knowledge file
|
|
105
|
+
const kbPath = resolve('.agents/instructions/learned-knowledge.instructions.md');
|
|
106
|
+
let markdown;
|
|
107
|
+
try {
|
|
108
|
+
markdown = readFileSync(kbPath, 'utf8');
|
|
109
|
+
} catch {
|
|
110
|
+
console.error(`[knowledgebase] Could not read file: ${kbPath}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Parse into structured chunks
|
|
115
|
+
const chunks = chunkLearnedKnowledge(markdown, projectId);
|
|
116
|
+
if (chunks.length === 0) {
|
|
117
|
+
console.log('[knowledgebase] No new knowledge chunks found — nothing to index');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Register/update the project in the projects table
|
|
122
|
+
await registerProject(projectId, projectId);
|
|
123
|
+
|
|
124
|
+
// Upsert all chunks (idempotent — duplicates skipped)
|
|
125
|
+
const result = await upsertChunks(chunks);
|
|
126
|
+
|
|
127
|
+
console.log(
|
|
128
|
+
`[knowledgebase] Indexed ${result.inserted} new, ` +
|
|
129
|
+
`updated ${result.updated}, skipped ${result.skipped} chunks ` +
|
|
130
|
+
`from project ${projectId}`
|
|
131
|
+
);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── search ────────────────────────────────────────────────
|
|
136
|
+
case 'search': {
|
|
137
|
+
const { flags, positional } = parseFlags(args.slice(1));
|
|
138
|
+
const query = positional.join(' ');
|
|
139
|
+
if (!query) {
|
|
140
|
+
console.error(
|
|
141
|
+
'Usage: node scripts/knowledgebase-cli.js search "<query>" [--project <id>] [--threshold <n>] [--topK <n>]'
|
|
142
|
+
);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const results = await search(query, {
|
|
147
|
+
project_id: flags.projectId,
|
|
148
|
+
threshold: flags.threshold != null ? flags.threshold : undefined,
|
|
149
|
+
limit: flags.topK || 5,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (results.length === 0) {
|
|
153
|
+
const hint = flags.projectId
|
|
154
|
+
? `No results for project "${flags.projectId}".`
|
|
155
|
+
: 'No results found. The knowledgebase may be empty or DATABASE_URL may not be configured.';
|
|
156
|
+
console.log(`[knowledgebase] ${hint}`);
|
|
157
|
+
} else {
|
|
158
|
+
console.log(`[knowledgebase] Found ${results.length} result(s):\n`);
|
|
159
|
+
for (const r of results) {
|
|
160
|
+
const excerpt = r.content.length > 100
|
|
161
|
+
? r.content.slice(0, 100) + '...'
|
|
162
|
+
: r.content;
|
|
163
|
+
console.log(
|
|
164
|
+
` Project: ${r.project_id}\n` +
|
|
165
|
+
` Similarity: ${r.similarity}\n` +
|
|
166
|
+
` Date: ${r.session_date}\n` +
|
|
167
|
+
` ${excerpt}\n`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── list ──────────────────────────────────────────────────
|
|
175
|
+
case 'list': {
|
|
176
|
+
const projects = await listProjects();
|
|
177
|
+
|
|
178
|
+
if (projects.length === 0) {
|
|
179
|
+
console.log('[knowledgebase] No projects indexed yet.');
|
|
180
|
+
} else {
|
|
181
|
+
console.log(`[knowledgebase] Indexed projects (${projects.length}):\n`);
|
|
182
|
+
for (const p of projects) {
|
|
183
|
+
console.log(
|
|
184
|
+
` ${p.project_id}\n` +
|
|
185
|
+
` Name: ${p.name}\n` +
|
|
186
|
+
` Chunks: ${p.chunk_count}\n` +
|
|
187
|
+
` Last Indexed: ${p.last_indexed || 'never'}\n`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── stats ─────────────────────────────────────────────────
|
|
195
|
+
case 'stats': {
|
|
196
|
+
const s = await getStats();
|
|
197
|
+
console.log(
|
|
198
|
+
`[knowledgebase] Knowledgebase statistics:\n` +
|
|
199
|
+
` Total projects: ${s.total_projects}\n` +
|
|
200
|
+
` Total chunks: ${s.total_chunks}\n` +
|
|
201
|
+
` Database size: ${s.db_size}\n` +
|
|
202
|
+
` Last sync: ${s.last_sync || 'never'}`
|
|
203
|
+
);
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ── default — show usage ──────────────────────────────────
|
|
208
|
+
default:
|
|
209
|
+
console.error('Usage: node scripts/knowledgebase-cli.js <sync|search|list|stats> [args...]\n');
|
|
210
|
+
console.error('Commands:');
|
|
211
|
+
console.error(' sync Index learned knowledge from');
|
|
212
|
+
console.error(' .agents/instructions/learned-knowledge.instructions.md');
|
|
213
|
+
console.error(' search "<query>" [--project <id>] Semantic search across indexed knowledge');
|
|
214
|
+
console.error(' [--threshold <n>] Minimum similarity threshold (0.0–1.0, default 0.0)');
|
|
215
|
+
console.error(' [--topK <n>] Maximum results (default 5)');
|
|
216
|
+
console.error(' list List all indexed projects with chunk counts');
|
|
217
|
+
console.error(' stats Knowledgebase statistics summary');
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
console.error(`[knowledgebase] Error: ${err.message}`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
} finally {
|
|
224
|
+
await closePool();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
main();
|