@codexa/cli 9.0.6 → 9.0.8
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/commands/decide.ts +120 -3
- package/commands/discover.ts +18 -9
- package/commands/integration.test.ts +754 -0
- package/commands/knowledge.test.ts +2 -6
- package/commands/knowledge.ts +20 -4
- package/commands/patterns.ts +8 -644
- package/commands/product.ts +41 -104
- package/commands/spec-resolver.test.ts +2 -13
- package/commands/standards.ts +33 -3
- package/commands/task.ts +21 -4
- package/commands/utils.test.ts +25 -87
- package/commands/utils.ts +20 -82
- package/context/assembly.ts +81 -0
- package/context/domains.test.ts +278 -0
- package/context/domains.ts +156 -0
- package/context/generator.ts +272 -0
- package/context/index.ts +21 -0
- package/context/scoring.ts +106 -0
- package/context/sections.ts +247 -0
- package/db/schema.ts +40 -5
- package/db/test-helpers.ts +33 -0
- package/gates/standards-validator.test.ts +447 -0
- package/gates/standards-validator.ts +164 -125
- package/gates/typecheck-validator.ts +296 -92
- package/gates/validator.ts +93 -8
- package/package.json +4 -2
- package/protocol/process-return.ts +39 -4
- package/templates/loader.ts +22 -0
- package/templates/subagent-context.md +34 -0
- package/templates/subagent-return-protocol.md +29 -0
- package/workflow.ts +54 -84
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// v8.3: Limite maximo de contexto para subagents (16KB)
|
|
2
|
+
export const MAX_CONTEXT_SIZE = 16384;
|
|
3
|
+
|
|
4
|
+
export interface ContextSection {
|
|
5
|
+
name: string;
|
|
6
|
+
content: string;
|
|
7
|
+
priority: number; // Lower = kept during truncation
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ContextData {
|
|
11
|
+
db: any;
|
|
12
|
+
task: any;
|
|
13
|
+
spec: any;
|
|
14
|
+
context: any;
|
|
15
|
+
project: any;
|
|
16
|
+
taskFiles: string[];
|
|
17
|
+
domain: string;
|
|
18
|
+
archAnalysis: any;
|
|
19
|
+
decisions: any[];
|
|
20
|
+
allDecisions: any[];
|
|
21
|
+
relevantStandards: any[];
|
|
22
|
+
criticalKnowledge: any[];
|
|
23
|
+
truncatedCritical: number;
|
|
24
|
+
infoKnowledge: any[];
|
|
25
|
+
truncatedInfo: number;
|
|
26
|
+
productContext: any;
|
|
27
|
+
patterns: any[];
|
|
28
|
+
depReasoning: any[];
|
|
29
|
+
libContexts: any[];
|
|
30
|
+
graphDecisions: any[];
|
|
31
|
+
discoveredPatterns: any[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function assembleSections(header: string, sections: ContextSection[]): string {
|
|
35
|
+
// Sort by priority (lower = higher priority, kept during truncation)
|
|
36
|
+
const sorted = [...sections].sort((a, b) => a.priority - b.priority);
|
|
37
|
+
|
|
38
|
+
let output = header;
|
|
39
|
+
for (const section of sorted) {
|
|
40
|
+
output += section.content;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Protocolo de retorno (sempre incluido)
|
|
44
|
+
output += `
|
|
45
|
+
### RETORNO OBRIGATORIO
|
|
46
|
+
\`\`\`json
|
|
47
|
+
{"status": "completed|blocked", "summary": "...", "files_created": [], "files_modified": [], "reasoning": {"approach": "como abordou", "challenges": [], "recommendations": "para proximas tasks"}}
|
|
48
|
+
\`\`\`
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
// v8.3: Overall size cap com truncamento inteligente por secao
|
|
52
|
+
if (output.length > MAX_CONTEXT_SIZE) {
|
|
53
|
+
const parts = output.split('\n### ');
|
|
54
|
+
let trimmed = parts[0]; // Sempre manter header
|
|
55
|
+
let breakIndex = parts.length;
|
|
56
|
+
|
|
57
|
+
for (let i = 1; i < parts.length; i++) {
|
|
58
|
+
const candidate = trimmed + '\n### ' + parts[i];
|
|
59
|
+
if (candidate.length > MAX_CONTEXT_SIZE - 200) {
|
|
60
|
+
breakIndex = i;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
trimmed = candidate;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Coletar nomes das secoes omitidas
|
|
67
|
+
const omittedNames: string[] = [];
|
|
68
|
+
for (let i = breakIndex; i < parts.length; i++) {
|
|
69
|
+
const name = parts[i].split('\n')[0].trim();
|
|
70
|
+
if (name) omittedNames.push(name);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (omittedNames.length > 0) {
|
|
74
|
+
trimmed += `\n\n[CONTEXTO TRUNCADO: ${omittedNames.length} secao(oes) omitida(s) (${omittedNames.join(', ')}). Use: codexa context detail <secao>]`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
output = trimmed;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return output;
|
|
81
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
getAgentDomain,
|
|
4
|
+
domainToScope,
|
|
5
|
+
adjustSectionPriorities,
|
|
6
|
+
AGENT_DOMAIN,
|
|
7
|
+
DOMAIN_PROFILES,
|
|
8
|
+
} from "./domains";
|
|
9
|
+
import type { ContextSection } from "./assembly";
|
|
10
|
+
|
|
11
|
+
function makeSections(): ContextSection[] {
|
|
12
|
+
return [
|
|
13
|
+
{ name: "STANDARDS", content: "...", priority: 1 },
|
|
14
|
+
{ name: "ALERTAS", content: "...", priority: 2 },
|
|
15
|
+
{ name: "ARQUITETURA", content: "...", priority: 3 },
|
|
16
|
+
{ name: "DECISOES", content: "...", priority: 4 },
|
|
17
|
+
{ name: "CONTEXTO DE TASKS ANTERIORES", content: "...", priority: 5 },
|
|
18
|
+
{ name: "GRAPH", content: "...", priority: 6 },
|
|
19
|
+
{ name: "PRODUTO", content: "...", priority: 7 },
|
|
20
|
+
{ name: "DISCOVERIES", content: "...", priority: 8 },
|
|
21
|
+
{ name: "UTILITIES", content: "...", priority: 8 },
|
|
22
|
+
{ name: "PATTERNS", content: "...", priority: 9 },
|
|
23
|
+
{ name: "HINTS", content: "...", priority: 10 },
|
|
24
|
+
{ name: "STACK", content: "...", priority: 11 },
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ── getAgentDomain ───────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
describe("getAgentDomain", () => {
|
|
31
|
+
it("maps backend agents correctly", () => {
|
|
32
|
+
expect(getAgentDomain("backend-javascript")).toBe("backend");
|
|
33
|
+
expect(getAgentDomain("expert-csharp-developer")).toBe("backend");
|
|
34
|
+
expect(getAgentDomain("golang-pro")).toBe("backend");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("maps frontend agents correctly", () => {
|
|
38
|
+
expect(getAgentDomain("expert-nextjs-developer")).toBe("frontend");
|
|
39
|
+
expect(getAgentDomain("frontend-flutter")).toBe("frontend");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("maps database agent correctly", () => {
|
|
43
|
+
expect(getAgentDomain("expert-postgres-developer")).toBe("database");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("maps testing agent correctly", () => {
|
|
47
|
+
expect(getAgentDomain("testing-unit")).toBe("testing");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("maps review agent correctly", () => {
|
|
51
|
+
expect(getAgentDomain("expert-code-reviewer")).toBe("review");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("maps security agent correctly", () => {
|
|
55
|
+
expect(getAgentDomain("security-specialist")).toBe("security");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("maps explore agent correctly", () => {
|
|
59
|
+
expect(getAgentDomain("deep-explore")).toBe("explore");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("maps architecture agent correctly", () => {
|
|
63
|
+
expect(getAgentDomain("architect")).toBe("architecture");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns null for unknown agents", () => {
|
|
67
|
+
expect(getAgentDomain("unknown-agent")).toBeNull();
|
|
68
|
+
expect(getAgentDomain("general-purpose")).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("returns null for null/undefined/empty input", () => {
|
|
72
|
+
expect(getAgentDomain(null)).toBeNull();
|
|
73
|
+
expect(getAgentDomain(undefined)).toBeNull();
|
|
74
|
+
expect(getAgentDomain("")).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// ── domainToScope ────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
describe("domainToScope", () => {
|
|
81
|
+
it("maps code domains to their scope names", () => {
|
|
82
|
+
expect(domainToScope("backend")).toBe("backend");
|
|
83
|
+
expect(domainToScope("frontend")).toBe("frontend");
|
|
84
|
+
expect(domainToScope("database")).toBe("database");
|
|
85
|
+
expect(domainToScope("testing")).toBe("testing");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("maps cross-cutting domains to 'all'", () => {
|
|
89
|
+
expect(domainToScope("review")).toBe("all");
|
|
90
|
+
expect(domainToScope("security")).toBe("all");
|
|
91
|
+
expect(domainToScope("explore")).toBe("all");
|
|
92
|
+
expect(domainToScope("architecture")).toBe("all");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("returns 'all' for null domain", () => {
|
|
96
|
+
expect(domainToScope(null)).toBe("all");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Regression: verifies the split("-")[0] bug is fixed
|
|
100
|
+
it("expert-postgres-developer resolves to 'database' scope (not 'expert')", () => {
|
|
101
|
+
const domain = getAgentDomain("expert-postgres-developer");
|
|
102
|
+
expect(domainToScope(domain)).toBe("database");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("expert-nextjs-developer resolves to 'frontend' scope (not 'expert')", () => {
|
|
106
|
+
const domain = getAgentDomain("expert-nextjs-developer");
|
|
107
|
+
expect(domainToScope(domain)).toBe("frontend");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("golang-pro resolves to 'backend' scope (not 'golang')", () => {
|
|
111
|
+
const domain = getAgentDomain("golang-pro");
|
|
112
|
+
expect(domainToScope(domain)).toBe("backend");
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// ── adjustSectionPriorities ──────────────────────────────────
|
|
117
|
+
|
|
118
|
+
describe("adjustSectionPriorities", () => {
|
|
119
|
+
it("null domain passes all sections through unchanged", () => {
|
|
120
|
+
const sections = makeSections();
|
|
121
|
+
const result = adjustSectionPriorities(sections, null);
|
|
122
|
+
expect(result).toHaveLength(12);
|
|
123
|
+
expect(result).toEqual(sections);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("explore domain excludes relevance-0 sections", () => {
|
|
127
|
+
const result = adjustSectionPriorities(makeSections(), "explore");
|
|
128
|
+
const names = result.map(s => s.name);
|
|
129
|
+
|
|
130
|
+
// explore profile: 7 sections have relevance 0
|
|
131
|
+
expect(names).not.toContain("STANDARDS");
|
|
132
|
+
expect(names).not.toContain("CONTEXTO DE TASKS ANTERIORES");
|
|
133
|
+
expect(names).not.toContain("GRAPH");
|
|
134
|
+
expect(names).not.toContain("PRODUTO");
|
|
135
|
+
expect(names).not.toContain("UTILITIES");
|
|
136
|
+
expect(names).not.toContain("PATTERNS");
|
|
137
|
+
expect(names).not.toContain("HINTS");
|
|
138
|
+
|
|
139
|
+
// Should contain the 5 non-zero sections
|
|
140
|
+
expect(names).toContain("ALERTAS");
|
|
141
|
+
expect(names).toContain("ARQUITETURA");
|
|
142
|
+
expect(names).toContain("DECISOES");
|
|
143
|
+
expect(names).toContain("DISCOVERIES");
|
|
144
|
+
expect(names).toContain("STACK");
|
|
145
|
+
expect(result).toHaveLength(5);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("essential sections (relevance=3) get priority boosted by -2", () => {
|
|
149
|
+
const result = adjustSectionPriorities(makeSections(), "backend");
|
|
150
|
+
|
|
151
|
+
// backend: DECISOES=3 (base 4 + offset -2 = 2)
|
|
152
|
+
const decisoes = result.find(s => s.name === "DECISOES");
|
|
153
|
+
expect(decisoes?.priority).toBe(2);
|
|
154
|
+
|
|
155
|
+
// backend: UTILITIES=3 (base 8 + offset -2 = 6)
|
|
156
|
+
const utilities = result.find(s => s.name === "UTILITIES");
|
|
157
|
+
expect(utilities?.priority).toBe(6);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("priority floor is 1 (never goes below)", () => {
|
|
161
|
+
const result = adjustSectionPriorities(makeSections(), "backend");
|
|
162
|
+
|
|
163
|
+
// backend: STANDARDS=3 (base 1 + offset -2 = -1 → floor 1)
|
|
164
|
+
const standards = result.find(s => s.name === "STANDARDS");
|
|
165
|
+
expect(standards?.priority).toBe(1);
|
|
166
|
+
|
|
167
|
+
// backend: ALERTAS=3 (base 2 + offset -2 = 0 → floor 1)
|
|
168
|
+
const alertas = result.find(s => s.name === "ALERTAS");
|
|
169
|
+
expect(alertas?.priority).toBe(1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("nice-to-have sections (relevance=1) get deprioritized by +4", () => {
|
|
173
|
+
const result = adjustSectionPriorities(makeSections(), "backend");
|
|
174
|
+
|
|
175
|
+
// backend: PRODUTO=1 (base 7 + offset +4 = 11)
|
|
176
|
+
const produto = result.find(s => s.name === "PRODUTO");
|
|
177
|
+
expect(produto?.priority).toBe(11);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("useful sections (relevance=2) keep base priority", () => {
|
|
181
|
+
const result = adjustSectionPriorities(makeSections(), "backend");
|
|
182
|
+
|
|
183
|
+
// backend: ARQUITETURA=2 (base 3 + offset 0 = 3)
|
|
184
|
+
const arq = result.find(s => s.name === "ARQUITETURA");
|
|
185
|
+
expect(arq?.priority).toBe(3);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("testing domain excludes only PRODUTO (relevance=0)", () => {
|
|
189
|
+
const result = adjustSectionPriorities(makeSections(), "testing");
|
|
190
|
+
const names = result.map(s => s.name);
|
|
191
|
+
expect(names).not.toContain("PRODUTO");
|
|
192
|
+
expect(result).toHaveLength(11);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("testing domain boosts CONTEXTO DE TASKS ANTERIORES (relevance=3)", () => {
|
|
196
|
+
const result = adjustSectionPriorities(makeSections(), "testing");
|
|
197
|
+
const ctx = result.find(s => s.name === "CONTEXTO DE TASKS ANTERIORES");
|
|
198
|
+
// base 5 + offset -2 = 3
|
|
199
|
+
expect(ctx?.priority).toBe(3);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("database domain excludes PRODUTO (relevance=0)", () => {
|
|
203
|
+
const result = adjustSectionPriorities(makeSections(), "database");
|
|
204
|
+
const names = result.map(s => s.name);
|
|
205
|
+
expect(names).not.toContain("PRODUTO");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("frontend domain keeps PRODUTO with boosted priority", () => {
|
|
209
|
+
const result = adjustSectionPriorities(makeSections(), "frontend");
|
|
210
|
+
const produto = result.find(s => s.name === "PRODUTO");
|
|
211
|
+
// frontend: PRODUTO=3 (base 7 + offset -2 = 5)
|
|
212
|
+
expect(produto?.priority).toBe(5);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("security domain excludes PRODUTO (relevance=0)", () => {
|
|
216
|
+
const result = adjustSectionPriorities(makeSections(), "security");
|
|
217
|
+
const names = result.map(s => s.name);
|
|
218
|
+
expect(names).not.toContain("PRODUTO");
|
|
219
|
+
expect(result).toHaveLength(11);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("handles unknown section names gracefully (forward compatibility)", () => {
|
|
223
|
+
const sections: ContextSection[] = [
|
|
224
|
+
{ name: "FUTURE_SECTION", content: "...", priority: 5 },
|
|
225
|
+
{ name: "STANDARDS", content: "...", priority: 1 },
|
|
226
|
+
];
|
|
227
|
+
const result = adjustSectionPriorities(sections, "backend");
|
|
228
|
+
expect(result).toHaveLength(2);
|
|
229
|
+
const future = result.find(s => s.name === "FUTURE_SECTION");
|
|
230
|
+
expect(future?.priority).toBe(5); // unchanged
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ── DOMAIN_PROFILES completeness ─────────────────────────────
|
|
235
|
+
|
|
236
|
+
describe("DOMAIN_PROFILES completeness", () => {
|
|
237
|
+
const allSectionNames = [
|
|
238
|
+
"STANDARDS", "ALERTAS", "ARQUITETURA", "DECISOES",
|
|
239
|
+
"CONTEXTO DE TASKS ANTERIORES", "GRAPH", "PRODUTO",
|
|
240
|
+
"DISCOVERIES", "UTILITIES", "PATTERNS", "HINTS", "STACK",
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
it("every domain profile covers all 12 sections", () => {
|
|
244
|
+
for (const [domain, profile] of Object.entries(DOMAIN_PROFILES)) {
|
|
245
|
+
for (const section of allSectionNames) {
|
|
246
|
+
expect(profile[section as keyof typeof profile]).toBeDefined();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("all relevance values are 0, 1, 2, or 3", () => {
|
|
252
|
+
for (const [domain, profile] of Object.entries(DOMAIN_PROFILES)) {
|
|
253
|
+
for (const [section, relevance] of Object.entries(profile)) {
|
|
254
|
+
expect([0, 1, 2, 3]).toContain(relevance);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// ── AGENT_DOMAIN completeness ────────────────────────────────
|
|
261
|
+
|
|
262
|
+
describe("AGENT_DOMAIN completeness", () => {
|
|
263
|
+
it("maps all 11 known agents", () => {
|
|
264
|
+
const knownAgents = [
|
|
265
|
+
"backend-javascript", "expert-csharp-developer", "golang-pro",
|
|
266
|
+
"expert-nextjs-developer", "frontend-flutter",
|
|
267
|
+
"expert-postgres-developer",
|
|
268
|
+
"testing-unit",
|
|
269
|
+
"expert-code-reviewer",
|
|
270
|
+
"security-specialist",
|
|
271
|
+
"deep-explore",
|
|
272
|
+
"architect",
|
|
273
|
+
];
|
|
274
|
+
for (const agent of knownAgents) {
|
|
275
|
+
expect(AGENT_DOMAIN[agent]).toBeDefined();
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// DOMAIN-BASED CONTEXT PRIORITY (v9.4)
|
|
3
|
+
// Replaces binary AGENT_SECTIONS with relevance-based filtering.
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import type { ContextSection } from "./assembly";
|
|
7
|
+
|
|
8
|
+
export type AgentDomain =
|
|
9
|
+
| "backend"
|
|
10
|
+
| "frontend"
|
|
11
|
+
| "database"
|
|
12
|
+
| "testing"
|
|
13
|
+
| "review"
|
|
14
|
+
| "security"
|
|
15
|
+
| "explore"
|
|
16
|
+
| "architecture";
|
|
17
|
+
|
|
18
|
+
export type Relevance = 0 | 1 | 2 | 3;
|
|
19
|
+
|
|
20
|
+
export type SectionName =
|
|
21
|
+
| "STANDARDS"
|
|
22
|
+
| "ALERTAS"
|
|
23
|
+
| "ARQUITETURA"
|
|
24
|
+
| "DECISOES"
|
|
25
|
+
| "CONTEXTO DE TASKS ANTERIORES"
|
|
26
|
+
| "GRAPH"
|
|
27
|
+
| "PRODUTO"
|
|
28
|
+
| "DISCOVERIES"
|
|
29
|
+
| "UTILITIES"
|
|
30
|
+
| "PATTERNS"
|
|
31
|
+
| "HINTS"
|
|
32
|
+
| "STACK";
|
|
33
|
+
|
|
34
|
+
export type DomainProfile = Record<SectionName, Relevance>;
|
|
35
|
+
|
|
36
|
+
// ── Agent → Domain mapping ───────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export const AGENT_DOMAIN: Record<string, AgentDomain> = {
|
|
39
|
+
"backend-javascript": "backend",
|
|
40
|
+
"expert-csharp-developer": "backend",
|
|
41
|
+
"golang-pro": "backend",
|
|
42
|
+
"expert-nextjs-developer": "frontend",
|
|
43
|
+
"frontend-flutter": "frontend",
|
|
44
|
+
"expert-postgres-developer": "database",
|
|
45
|
+
"testing-unit": "testing",
|
|
46
|
+
"expert-code-reviewer": "review",
|
|
47
|
+
"security-specialist": "security",
|
|
48
|
+
"deep-explore": "explore",
|
|
49
|
+
"architect": "architecture",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// ── Domain → Section relevance profiles ──────────────────────
|
|
53
|
+
//
|
|
54
|
+
// 3 = essential (priority offset -2, survives truncation)
|
|
55
|
+
// 2 = useful (priority offset 0, base priority kept)
|
|
56
|
+
// 1 = nice-to-have (priority offset +4, dropped first on truncation)
|
|
57
|
+
// 0 = noise (excluded entirely)
|
|
58
|
+
|
|
59
|
+
export const DOMAIN_PROFILES: Record<AgentDomain, DomainProfile> = {
|
|
60
|
+
backend: {
|
|
61
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 2, "DECISOES": 3,
|
|
62
|
+
"CONTEXTO DE TASKS ANTERIORES": 2, "GRAPH": 2, "PRODUTO": 1,
|
|
63
|
+
"DISCOVERIES": 2, "UTILITIES": 3, "PATTERNS": 2, "HINTS": 2, "STACK": 2,
|
|
64
|
+
},
|
|
65
|
+
frontend: {
|
|
66
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 2, "DECISOES": 3,
|
|
67
|
+
"CONTEXTO DE TASKS ANTERIORES": 2, "GRAPH": 2, "PRODUTO": 3,
|
|
68
|
+
"DISCOVERIES": 2, "UTILITIES": 3, "PATTERNS": 3, "HINTS": 2, "STACK": 2,
|
|
69
|
+
},
|
|
70
|
+
database: {
|
|
71
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 3, "DECISOES": 3,
|
|
72
|
+
"CONTEXTO DE TASKS ANTERIORES": 2, "GRAPH": 2, "PRODUTO": 0,
|
|
73
|
+
"DISCOVERIES": 2, "UTILITIES": 1, "PATTERNS": 2, "HINTS": 2, "STACK": 3,
|
|
74
|
+
},
|
|
75
|
+
testing: {
|
|
76
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 1, "DECISOES": 2,
|
|
77
|
+
"CONTEXTO DE TASKS ANTERIORES": 3, "GRAPH": 1, "PRODUTO": 0,
|
|
78
|
+
"DISCOVERIES": 2, "UTILITIES": 3, "PATTERNS": 3, "HINTS": 2, "STACK": 1,
|
|
79
|
+
},
|
|
80
|
+
review: {
|
|
81
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 3, "DECISOES": 3,
|
|
82
|
+
"CONTEXTO DE TASKS ANTERIORES": 2, "GRAPH": 2, "PRODUTO": 1,
|
|
83
|
+
"DISCOVERIES": 2, "UTILITIES": 3, "PATTERNS": 2, "HINTS": 3, "STACK": 2,
|
|
84
|
+
},
|
|
85
|
+
security: {
|
|
86
|
+
"STANDARDS": 3, "ALERTAS": 3, "ARQUITETURA": 2, "DECISOES": 2,
|
|
87
|
+
"CONTEXTO DE TASKS ANTERIORES": 1, "GRAPH": 1, "PRODUTO": 0,
|
|
88
|
+
"DISCOVERIES": 2, "UTILITIES": 1, "PATTERNS": 1, "HINTS": 2, "STACK": 3,
|
|
89
|
+
},
|
|
90
|
+
explore: {
|
|
91
|
+
"STANDARDS": 0, "ALERTAS": 1, "ARQUITETURA": 3, "DECISOES": 1,
|
|
92
|
+
"CONTEXTO DE TASKS ANTERIORES": 0, "GRAPH": 0, "PRODUTO": 0,
|
|
93
|
+
"DISCOVERIES": 1, "UTILITIES": 0, "PATTERNS": 0, "HINTS": 0, "STACK": 3,
|
|
94
|
+
},
|
|
95
|
+
architecture: {
|
|
96
|
+
"STANDARDS": 2, "ALERTAS": 2, "ARQUITETURA": 3, "DECISOES": 3,
|
|
97
|
+
"CONTEXTO DE TASKS ANTERIORES": 2, "GRAPH": 2, "PRODUTO": 3,
|
|
98
|
+
"DISCOVERIES": 2, "UTILITIES": 1, "PATTERNS": 2, "HINTS": 1, "STACK": 3,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ── Priority offset per relevance level ──────────────────────
|
|
103
|
+
|
|
104
|
+
const RELEVANCE_OFFSET: Record<Relevance, number> = {
|
|
105
|
+
3: -2, // essential: boost
|
|
106
|
+
2: 0, // useful: keep as-is
|
|
107
|
+
1: 4, // nice-to-have: deprioritize
|
|
108
|
+
0: 0, // noise: excluded before this applies
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// ── Functions ────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
export function getAgentDomain(agentName: string | null | undefined): AgentDomain | null {
|
|
114
|
+
if (!agentName) return null;
|
|
115
|
+
return AGENT_DOMAIN[agentName] ?? null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function domainToScope(domain: AgentDomain | null): string {
|
|
119
|
+
if (!domain) return "all";
|
|
120
|
+
|
|
121
|
+
const scopeMap: Record<AgentDomain, string> = {
|
|
122
|
+
backend: "backend",
|
|
123
|
+
frontend: "frontend",
|
|
124
|
+
database: "database",
|
|
125
|
+
testing: "testing",
|
|
126
|
+
review: "all",
|
|
127
|
+
security: "all",
|
|
128
|
+
explore: "all",
|
|
129
|
+
architecture: "all",
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return scopeMap[domain];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function adjustSectionPriorities(
|
|
136
|
+
sections: ContextSection[],
|
|
137
|
+
domain: AgentDomain | null,
|
|
138
|
+
): ContextSection[] {
|
|
139
|
+
if (!domain) return sections;
|
|
140
|
+
|
|
141
|
+
const profile = DOMAIN_PROFILES[domain];
|
|
142
|
+
|
|
143
|
+
return sections
|
|
144
|
+
.filter(s => {
|
|
145
|
+
const relevance = profile[s.name as SectionName];
|
|
146
|
+
// Unknown section names pass through (forward compatibility)
|
|
147
|
+
return relevance === undefined || relevance > 0;
|
|
148
|
+
})
|
|
149
|
+
.map(s => {
|
|
150
|
+
const relevance = profile[s.name as SectionName];
|
|
151
|
+
if (relevance === undefined) return s;
|
|
152
|
+
|
|
153
|
+
const offset = RELEVANCE_OFFSET[relevance];
|
|
154
|
+
return { ...s, priority: Math.max(1, s.priority + offset) };
|
|
155
|
+
});
|
|
156
|
+
}
|