@comfanion/workflow 4.36.23 → 4.36.25
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/README.md +31 -0
- package/package.json +1 -1
- package/src/build-info.json +2 -2
- package/src/opencode/FLOW.yaml +21 -5
- package/src/opencode/agents/analyst.md +1 -1
- package/src/opencode/agents/architect.md +56 -16
- package/src/opencode/agents/change-manager.md +1 -1
- package/src/opencode/agents/coder.md +1 -1
- package/src/opencode/agents/dev.md +1 -1
- package/src/opencode/agents/pm.md +1 -1
- package/src/opencode/agents/researcher.md +1 -1
- package/src/opencode/config.yaml +7 -3
- package/src/opencode/plugins/file-indexer.ts +4 -1
- package/src/opencode/skills/unit-writing/SKILL.md +315 -106
- package/src/opencode/skills/unit-writing/template.md +7 -132
- package/src/opencode/skills/unit-writing/templates/data-model.md +57 -0
- package/src/opencode/skills/unit-writing/templates/entity.md +85 -0
- package/src/opencode/skills/unit-writing/templates/events-index.md +42 -0
- package/src/opencode/skills/unit-writing/templates/index.md +61 -0
- package/src/opencode/tools/search.ts +2 -1
- package/src/vectorizer/index.js +42 -4
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# {{Unit Name}} Data Model
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0
|
|
4
|
+
**Date:** {{YYYY-MM-DD}}
|
|
5
|
+
**Status:** Active
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Design Principles
|
|
10
|
+
|
|
11
|
+
| Principle | Description |
|
|
12
|
+
|-----------|-------------|
|
|
13
|
+
| {{Principle}} | {{Why this matters}} |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Entity Relationship Diagram
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
{{ASCII or Mermaid diagram}}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Tables
|
|
26
|
+
|
|
27
|
+
### {{Table Name}}
|
|
28
|
+
|
|
29
|
+
{{Purpose of this table}}
|
|
30
|
+
|
|
31
|
+
| Field | Type | Constraints | Description |
|
|
32
|
+
|-------|------|-------------|-------------|
|
|
33
|
+
| id | UUID | PK | Primary identifier |
|
|
34
|
+
| {{field}} | {{type}} | {{constraints}} | {{description}} |
|
|
35
|
+
|
|
36
|
+
**Indexes:**
|
|
37
|
+
- `({{fields}})` — {{purpose}}
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Relations
|
|
42
|
+
|
|
43
|
+
| Relation | Type | Description |
|
|
44
|
+
|----------|------|-------------|
|
|
45
|
+
| {{table_a}} → {{table_b}} | 1:N | {{description}} |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Status Lifecycle
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
{{state_a}} ──► {{state_b}} ──► {{state_c}}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| Status | Description | Transitions To |
|
|
56
|
+
|--------|-------------|----------------|
|
|
57
|
+
| {{status}} | {{meaning}} | {{allowed_next}} |
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# {{Name}}
|
|
2
|
+
|
|
3
|
+
```yaml
|
|
4
|
+
type: entity
|
|
5
|
+
status: draft | approved
|
|
6
|
+
version: "1.0"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
{{What this entity represents, its role in the domain.}}
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Boundaries
|
|
18
|
+
|
|
19
|
+
| Aspect | Details |
|
|
20
|
+
|--------|---------|
|
|
21
|
+
| **Owns** | {{fields, behavior}} |
|
|
22
|
+
| **Part of** | {{parent domain/module path}} |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Data Model
|
|
27
|
+
|
|
28
|
+
| Field | Type | Constraints | Description |
|
|
29
|
+
|-------|------|-------------|-------------|
|
|
30
|
+
| id | UUID | PK | Primary identifier |
|
|
31
|
+
| {{field}} | {{type}} | {{constraints}} | {{description}} |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Relations
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
{{Entity}} ──► {{Other}} ({{type}})
|
|
39
|
+
{{Entity}} ──< {{Other}} ({{type}})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Relation | Target | Type | Description |
|
|
43
|
+
|----------|--------|------|-------------|
|
|
44
|
+
| {{name}} | {{target}} | N:1 / 1:N / N:M | {{description}} |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## State Machine
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
{{state_a}} ──► {{state_b}} ──► {{state_c}}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| State | Description | Transitions To |
|
|
55
|
+
|-------|-------------|----------------|
|
|
56
|
+
| {{state}} | {{meaning}} | {{allowed_next}} |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Operations
|
|
61
|
+
|
|
62
|
+
| Operation | Input | Output | Description |
|
|
63
|
+
|-----------|-------|--------|-------------|
|
|
64
|
+
| Create | {{params}} | Entity | {{description}} |
|
|
65
|
+
| {{op}} | {{params}} | {{result}} | {{description}} |
|
|
66
|
+
|
|
67
|
+
**Business Rules:**
|
|
68
|
+
- {{rule}}
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Errors
|
|
73
|
+
|
|
74
|
+
| Error | Code | When |
|
|
75
|
+
|-------|------|------|
|
|
76
|
+
| {{Error}} | {{CODE}} | {{condition}} |
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## References
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
→ Parent: {{parent path}}
|
|
84
|
+
→ Related: {{related path}}
|
|
85
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# {{Unit Name}} Events
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0
|
|
4
|
+
**Date:** {{YYYY-MM-DD}}
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
{{Brief description of event patterns in this unit}}
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Event Flow
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
{{ASCII diagram: sources → processing → sinks}}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Topics
|
|
23
|
+
|
|
24
|
+
### Produced Events
|
|
25
|
+
|
|
26
|
+
| Topic | Events | Key | Description |
|
|
27
|
+
|-------|--------|-----|-------------|
|
|
28
|
+
| {{topic}} | {{EventType}} | {{partition_key}} | {{description}} |
|
|
29
|
+
|
|
30
|
+
### Consumed Events
|
|
31
|
+
|
|
32
|
+
| Topic | Events | Source |
|
|
33
|
+
|-------|--------|--------|
|
|
34
|
+
| {{topic}} | {{EventType}} | {{source_system}} |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Schema Files
|
|
39
|
+
|
|
40
|
+
| Schema | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| [{{event}}.avsc]({{event}}.avsc) | {{description}} |
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# {{Name}}
|
|
2
|
+
|
|
3
|
+
```yaml
|
|
4
|
+
type: module | domain | service | entity
|
|
5
|
+
status: draft | approved
|
|
6
|
+
version: "1.0"
|
|
7
|
+
created: {{YYYY-MM-DD}}
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
{{One paragraph describing what this unit does, what problem it solves, and key characteristics.}}
|
|
15
|
+
|
|
16
|
+
**Not responsible for:**
|
|
17
|
+
- {{What this unit explicitly doesn't handle}}
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Boundaries
|
|
22
|
+
|
|
23
|
+
| Aspect | Details |
|
|
24
|
+
|--------|---------|
|
|
25
|
+
| **Owns** | {{tables, domain objects, behavior}} |
|
|
26
|
+
| **Uses** | → Unit: `{{dependency}}` ({{purpose}}) |
|
|
27
|
+
| **Provides** | {{APIs, events, services to others}} |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
{{ASCII diagram showing high-level structure}}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Documents
|
|
40
|
+
|
|
41
|
+
| Document | Description |
|
|
42
|
+
|----------|-------------|
|
|
43
|
+
| [data-model.md](data-model.md) | Database schema |
|
|
44
|
+
| [api/](api/) | API specifications |
|
|
45
|
+
| [events/](events/) | Event schemas |
|
|
46
|
+
|
|
47
|
+
## Child Units
|
|
48
|
+
|
|
49
|
+
| Unit | Type | Description |
|
|
50
|
+
|------|------|-------------|
|
|
51
|
+
| [services/{{service}}/](services/{{service}}/) | service | {{description}} |
|
|
52
|
+
| [domains/{{domain}}/](domains/{{domain}}/) | domain | {{description}} |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## References
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
→ Architecture: docs/architecture.md
|
|
60
|
+
→ Related: modules/{{related}}/ or services/{{related}}/
|
|
61
|
+
```
|
|
@@ -44,6 +44,7 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
44
44
|
limit: tool.schema.number().optional().default(5).describe("Number of results to return (default: 5)"),
|
|
45
45
|
searchAll: tool.schema.boolean().optional().default(false).describe("Search all indexes instead of just one"),
|
|
46
46
|
freshen: tool.schema.boolean().optional().default(true).describe("Auto-update stale files before searching (default: true)"),
|
|
47
|
+
includeArchived: tool.schema.boolean().optional().default(false).describe("Include archived files in results (default: false). Files are archived if in /archive/ folder or have 'archived: true' in frontmatter."),
|
|
47
48
|
},
|
|
48
49
|
|
|
49
50
|
async execute(args, context) {
|
|
@@ -88,7 +89,7 @@ Prerequisites: Run 'npx @comfanion/workflow index --index <name>' first.`,
|
|
|
88
89
|
if (args.freshen !== false) {
|
|
89
90
|
await indexer.freshen()
|
|
90
91
|
}
|
|
91
|
-
const results = await indexer.search(args.query, limit)
|
|
92
|
+
const results = await indexer.search(args.query, limit, args.includeArchived)
|
|
92
93
|
allResults.push(...results.map((r: any) => ({ ...r, _index: idx })))
|
|
93
94
|
await indexer.unloadModel() // Free memory after each index search
|
|
94
95
|
}
|
package/src/vectorizer/index.js
CHANGED
|
@@ -181,6 +181,30 @@ class CodebaseIndexer {
|
|
|
181
181
|
return crypto.createHash('md5').update(content).digest('hex');
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Check if file is archived (should be excluded from default search)
|
|
186
|
+
* Archived if:
|
|
187
|
+
* - Path contains /archive/ folder
|
|
188
|
+
* - File has frontmatter with archived: true
|
|
189
|
+
*/
|
|
190
|
+
isArchived(relPath, content) {
|
|
191
|
+
// Check path
|
|
192
|
+
if (relPath.includes('/archive/') || relPath.startsWith('archive/')) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check frontmatter (YAML between --- markers at start of file)
|
|
197
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
198
|
+
if (frontmatterMatch) {
|
|
199
|
+
const frontmatter = frontmatterMatch[1];
|
|
200
|
+
if (/^archived:\s*true/m.test(frontmatter)) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
184
208
|
async embed(text) {
|
|
185
209
|
const model = await this.loadModel();
|
|
186
210
|
const result = await model(text, { pooling: 'mean', normalize: true });
|
|
@@ -246,6 +270,7 @@ class CodebaseIndexer {
|
|
|
246
270
|
}
|
|
247
271
|
|
|
248
272
|
const chunks = this.chunkCode(content);
|
|
273
|
+
const archived = this.isArchived(relPath, content);
|
|
249
274
|
const data = [];
|
|
250
275
|
|
|
251
276
|
for (let i = 0; i < chunks.length; i++) {
|
|
@@ -254,7 +279,8 @@ class CodebaseIndexer {
|
|
|
254
279
|
file: relPath,
|
|
255
280
|
chunk_index: i,
|
|
256
281
|
content: chunks[i],
|
|
257
|
-
vector: embedding
|
|
282
|
+
vector: embedding,
|
|
283
|
+
archived: archived
|
|
258
284
|
});
|
|
259
285
|
}
|
|
260
286
|
|
|
@@ -279,8 +305,11 @@ class CodebaseIndexer {
|
|
|
279
305
|
|
|
280
306
|
/**
|
|
281
307
|
* Semantic search across indexed codebase
|
|
308
|
+
* @param {string} query - Search query
|
|
309
|
+
* @param {number} limit - Max results (default 5)
|
|
310
|
+
* @param {boolean} includeArchived - Include archived files (default false)
|
|
282
311
|
*/
|
|
283
|
-
async search(query, limit = 5) {
|
|
312
|
+
async search(query, limit = 5, includeArchived = false) {
|
|
284
313
|
const tableName = 'chunks';
|
|
285
314
|
const tables = await this.db.tableNames();
|
|
286
315
|
if (!tables.includes(tableName)) {
|
|
@@ -289,9 +318,18 @@ class CodebaseIndexer {
|
|
|
289
318
|
|
|
290
319
|
const queryEmbedding = await this.embed(query);
|
|
291
320
|
const table = await this.db.openTable(tableName);
|
|
292
|
-
const results = await table.search(queryEmbedding).limit(limit).execute();
|
|
293
321
|
|
|
294
|
-
|
|
322
|
+
// Fetch more results if we need to filter archived
|
|
323
|
+
const fetchLimit = includeArchived ? limit : limit * 3;
|
|
324
|
+
let results = await table.search(queryEmbedding).limit(fetchLimit).execute();
|
|
325
|
+
|
|
326
|
+
// Filter out archived files unless explicitly requested
|
|
327
|
+
if (!includeArchived) {
|
|
328
|
+
results = results.filter(r => !r.archived);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Trim to requested limit
|
|
332
|
+
return results.slice(0, limit);
|
|
295
333
|
}
|
|
296
334
|
|
|
297
335
|
/**
|