@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.
Files changed (34) hide show
  1. package/.agents/instructions/knowledgebase.instructions.md +238 -0
  2. package/.agents/instructions/learned-knowledge.instructions.md +71 -0
  3. package/.husky/post-commit +10 -0
  4. package/.husky/post-merge +0 -1
  5. package/.opencode/agents/architect.agent.md +1 -0
  6. package/.opencode/agents/coder.agent.md +1 -0
  7. package/.opencode/agents/deployer.agent.md +1 -0
  8. package/.opencode/agents/designer.agent.md +1 -0
  9. package/.opencode/agents/e2e-tester.agent.md +1 -0
  10. package/.opencode/agents/implementer.agent.md +1 -0
  11. package/.opencode/agents/orchestrator/feature-pipeline.agent.md +1 -0
  12. package/.opencode/agents/orchestrator/orchestrator.agent.md +1 -0
  13. package/.opencode/agents/orchestrator/tdd-orchestrator.agent.md +1 -0
  14. package/.opencode/agents/researcher.agent.md +1 -0
  15. package/.opencode/agents/reviewer.agent.md +1 -0
  16. package/.opencode/agents/tracker.agent.md +2 -0
  17. package/.opencode/agents/unit-tester.agent.md +1 -0
  18. package/README.md +1 -1
  19. package/memory-bank/.vocabulary.json +8 -2
  20. package/package.json +12 -6
  21. package/scripts/knowledgebase-cli.js +228 -0
  22. package/scripts/knowledgebase-cli.test.js +576 -0
  23. package/scripts/knowledgebase-index.js +780 -0
  24. package/scripts/knowledgebase-index.test.js +759 -0
  25. package/scripts/knowledgebase-init.sql +193 -0
  26. package/scripts/mcp-knowledgebase-server.js +330 -0
  27. package/scripts/setup/constants.js +36 -3
  28. package/scripts/setup/hooks.js +2 -2
  29. package/scripts/setup/hooks.test.js +13 -5
  30. package/scripts/setup/index.js +29 -2
  31. package/scripts/setup/index.test.js +36 -1
  32. package/scripts/setup/knowledgebase.js +204 -0
  33. package/scripts/setup/knowledgebase.test.js +248 -0
  34. 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();