role-os 2.0.0 → 2.2.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/CHANGELOG.md +61 -0
- package/README.es.md +123 -54
- package/README.fr.md +90 -21
- package/README.hi.md +90 -21
- package/README.it.md +130 -61
- package/README.ja.md +91 -22
- package/README.md +72 -16
- package/README.pt-BR.md +90 -21
- package/README.zh.md +160 -88
- package/package.json +2 -2
- package/src/artifacts.mjs +569 -437
- package/src/brainstorm-render.mjs +462 -0
- package/src/brainstorm-roles.mjs +774 -0
- package/src/brainstorm.mjs +778 -0
- package/src/dispatch.mjs +339 -310
- package/src/evidence.mjs +9 -9
- package/src/mission-run.mjs +111 -13
- package/src/mission.mjs +508 -388
- package/src/packs.mjs +430 -359
- package/src/route.mjs +715 -564
- package/src/run.mjs +5 -2
- package/starter-pack/agents/engineering/audit-synthesizer.md +56 -0
- package/starter-pack/agents/engineering/component-auditor.md +46 -0
- package/starter-pack/agents/engineering/seam-auditor.md +46 -0
- package/starter-pack/agents/engineering/test-truth-auditor.md +48 -0
package/src/route.mjs
CHANGED
|
@@ -1,564 +1,715 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { resolve, dirname } from "node:path";
|
|
3
|
-
import { readFileSafe } from "./fs-utils.mjs";
|
|
4
|
-
import { detectConflicts } from "./conflicts.mjs";
|
|
5
|
-
import { resolveConflict, resolveSplit, formatEscalation } from "./escalation.mjs";
|
|
6
|
-
import { suggestPack, getPack, checkPackMismatch, getPackRoles } from "./packs.mjs";
|
|
7
|
-
|
|
8
|
-
// ── Full
|
|
9
|
-
// Every role in the OS is scoreable. Keywords from routing-rules.md + contracts.
|
|
10
|
-
// Triggers are strong multi-word signals worth bonus points.
|
|
11
|
-
|
|
12
|
-
export const ROLE_CATALOG = [
|
|
13
|
-
// ── CORE ──
|
|
14
|
-
{
|
|
15
|
-
name: "Orchestrator", pack: "core", phase: 0,
|
|
16
|
-
alwaysInclude: true,
|
|
17
|
-
keywords: [],
|
|
18
|
-
triggers: ["multi-step", "cross-functional", "decomposition", "sequencing"],
|
|
19
|
-
excludeWhen: [],
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name: "Product Strategist", pack: "product", phase: 1,
|
|
23
|
-
keywords: ["product", "scope", "intent", "prioritize", "tradeoff", "framing", "user value", "feature shaping"],
|
|
24
|
-
triggers: ["problem framing", "scope definition", "tradeoff decision"],
|
|
25
|
-
excludeWhen: [],
|
|
26
|
-
deliverableAffinity: ["Plan"],
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: "Critic Reviewer", pack: "core", phase: 99,
|
|
30
|
-
alwaysInclude: true,
|
|
31
|
-
keywords: [],
|
|
32
|
-
triggers: ["final acceptance", "quality gate", "truthful rejection"],
|
|
33
|
-
excludeWhen: [],
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
// ── DESIGN ──
|
|
37
|
-
{
|
|
38
|
-
name: "UI Designer", pack: "design", phase: 2,
|
|
39
|
-
keywords: ["ui", "screen", "layout", "hierarchy", "interaction", "visual", "design", "flow", "component", "wireframe"],
|
|
40
|
-
triggers: ["information hierarchy", "user flow", "interaction design", "screen structure"],
|
|
41
|
-
excludeWhen: ["no user interface", "cli only", "backend only"],
|
|
42
|
-
deliverableAffinity: ["Design"],
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: "Brand Guardian", pack: "design", phase: 2,
|
|
46
|
-
keywords: ["brand", "identity", "terminology", "tone", "contamination", "fork", "residue", "purge", "naming"],
|
|
47
|
-
triggers: ["identity contamination", "fork residue", "terminology consistency", "replacement doctrine"],
|
|
48
|
-
excludeWhen: ["no brand concern", "internal tooling only"],
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
// ── ENGINEERING ──
|
|
52
|
-
{
|
|
53
|
-
name: "Backend Engineer", pack: "engineering", phase: 3,
|
|
54
|
-
keywords: ["api", "server", "data", "persistence", "contract", "model", "migration", "bridge", "wiring", "session", "state", "database", "endpoint"],
|
|
55
|
-
triggers: ["server-side", "data flow", "system contract"],
|
|
56
|
-
excludeWhen: ["frontend only", "docs only"],
|
|
57
|
-
deliverableAffinity: ["Code"],
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: "Frontend Developer", pack: "engineering", phase: 3,
|
|
61
|
-
keywords: ["frontend", "render", "component", "client", "tui", "display", "view", "react", "css", "html", "dom"],
|
|
62
|
-
triggers: ["ui implementation", "client state", "interaction wiring", "frontend integration"],
|
|
63
|
-
excludeWhen: ["backend only", "no ui"],
|
|
64
|
-
deliverableAffinity: ["Code"],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: "Test Engineer", pack: "engineering", phase: 4,
|
|
68
|
-
keywords: ["test", "verify", "regression", "coverage", "assertion", "edge case", "vitest", "jest", "spec"],
|
|
69
|
-
triggers: ["test plan", "regression defense", "verification coverage"],
|
|
70
|
-
excludeWhen: [],
|
|
71
|
-
deliverableAffinity: ["Test"],
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: "Performance Engineer", pack: "engineering", phase: 3,
|
|
75
|
-
keywords: ["performance", "profiling", "latency", "memory", "benchmark", "optimization", "hot path", "budget", "slow", "bottleneck"],
|
|
76
|
-
triggers: ["performance regression", "hot path analysis", "performance budget"],
|
|
77
|
-
excludeWhen: ["no performance concern"],
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
name: "Refactor Engineer", pack: "engineering", phase: 3,
|
|
81
|
-
keywords: ["refactor", "duplication", "boundary", "complexity", "cleanup", "modularize", "split", "extract", "simplify"],
|
|
82
|
-
triggers: ["structure cleanup", "module boundary", "complexity reduction", "duplication elimination"],
|
|
83
|
-
excludeWhen: ["new feature", "behavior change required"],
|
|
84
|
-
deliverableAffinity: ["Code"],
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
name: "Security Reviewer", pack: "engineering", phase: 3,
|
|
88
|
-
keywords: ["security", "injection", "auth", "authentication", "authorization", "secrets", "owasp", "threat", "vulnerability", "xss", "csrf", "sanitize"],
|
|
89
|
-
triggers: ["security review", "threat model", "owasp pattern", "secret scanning"],
|
|
90
|
-
excludeWhen: ["no security surface"],
|
|
91
|
-
deliverableAffinity: ["Review"],
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
name: "Dependency Auditor", pack: "engineering", phase: 3,
|
|
95
|
-
keywords: ["dependency", "dependencies", "vulnerability", "supply chain", "stale", "outdated", "audit", "npm audit", "dependabot"],
|
|
96
|
-
triggers: ["dependency health", "supply-chain risk", "vulnerability scanning"],
|
|
97
|
-
excludeWhen: ["no external dependencies"],
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
// ── TREATMENT ──
|
|
101
|
-
{
|
|
102
|
-
name: "Repo Researcher", pack: "treatment", phase: 1,
|
|
103
|
-
keywords: ["repo structure", "entrypoint", "seam", "build command", "test command", "codebase", "architecture", "map"],
|
|
104
|
-
triggers: ["repo structure mapping", "entrypoint discovery", "dependency verification"],
|
|
105
|
-
excludeWhen: ["repo already well understood"],
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: "Repo Translator", pack: "treatment", phase: 5,
|
|
109
|
-
keywords: ["translate", "translation", "localize", "localization", "i18n", "multilingual", "language", "readme translation", "polyglot"],
|
|
110
|
-
triggers: ["readme translation", "docs translation", "cross-audience adaptation"],
|
|
111
|
-
excludeWhen: ["english only", "no translation needed"],
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
name: "Docs Architect", pack: "treatment", phase: 3,
|
|
115
|
-
keywords: ["documentation", "handbook", "docs", "starlight", "guide", "tutorial", "reference", "api docs", "navigation", "hierarchy", "findability", "labeling", "taxonomy", "sitemap"],
|
|
116
|
-
triggers: ["handbook creation", "docs site", "starlight setup", "documentation restructuring", "navigation design", "content organization", "information structure"],
|
|
117
|
-
excludeWhen: ["no docs needed"],
|
|
118
|
-
deliverableAffinity: ["Plan"],
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: "Metadata Curator", pack: "treatment", phase: 5,
|
|
122
|
-
keywords: ["metadata", "manifest", "package.json", "badge", "topic", "homepage", "description", "registry", "npm"],
|
|
123
|
-
triggers: ["package manifest audit", "badge verification", "registry metadata"],
|
|
124
|
-
excludeWhen: ["no package metadata"],
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: "Coverage Auditor", pack: "treatment", phase: 4,
|
|
128
|
-
keywords: ["coverage", "test coverage", "uncovered", "false confidence", "missing test", "untested"],
|
|
129
|
-
triggers: ["coverage assessment", "false confidence detection", "missing defense"],
|
|
130
|
-
excludeWhen: ["no test suite"],
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: "Deployment Verifier", pack: "treatment", phase: 6,
|
|
134
|
-
keywords: ["deploy", "deployment", "live", "landing page", "published", "badge", "verify live", "spot check"],
|
|
135
|
-
triggers: ["post-deploy verification", "landing page check", "badge resolution", "translation spot-check"],
|
|
136
|
-
excludeWhen: ["not yet deployed"],
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "Release Engineer", pack: "treatment", phase: 5,
|
|
140
|
-
keywords: ["release", "version", "changelog", "tag", "publish", "package", "bump", "npm publish", "staging"],
|
|
141
|
-
triggers: ["version bump", "changelog update", "publish readiness", "release execution"],
|
|
142
|
-
excludeWhen: ["not releasing"],
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
// ── GROWTH ──
|
|
146
|
-
{
|
|
147
|
-
name: "Launch Strategist", pack: "growth", phase: 6,
|
|
148
|
-
keywords: ["launch", "go-to-market", "channel", "timing", "proof", "success criteria", "announcement"],
|
|
149
|
-
triggers: ["launch planning", "proof packaging", "channel selection", "success criteria"],
|
|
150
|
-
excludeWhen: ["internal tool", "not launching"],
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: "Content Strategist", pack: "growth", phase: 6,
|
|
154
|
-
keywords: ["content", "article", "blog", "case study", "tutorial", "marketing content", "content calendar"],
|
|
155
|
-
triggers: ["content planning", "technical article", "case study angle", "docs-to-marketing bridge"],
|
|
156
|
-
excludeWhen: ["no content needed"],
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: "Community Manager", pack: "growth", phase: 6,
|
|
160
|
-
keywords: ["community", "issue triage", "discussion", "contribution", "contributor", "feedback loop", "open source"],
|
|
161
|
-
triggers: ["community response", "contribution guidance", "community health"],
|
|
162
|
-
excludeWhen: ["private repo", "no community"],
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
name: "Support Triage Lead", pack: "growth", phase: 6,
|
|
166
|
-
keywords: ["support", "triage", "bug report", "user error", "recurring", "priority assignment"],
|
|
167
|
-
triggers: ["support classification", "bug vs user error", "recurring pattern"],
|
|
168
|
-
excludeWhen: ["no support surface"],
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
// ── MARKETING ──
|
|
172
|
-
{
|
|
173
|
-
name: "Launch Copywriter", pack: "marketing", phase: 6,
|
|
174
|
-
keywords: ["copy", "messaging", "positioning", "release notes", "announcement", "conversion"],
|
|
175
|
-
triggers: ["launch messaging", "release notes", "positioning copy"],
|
|
176
|
-
excludeWhen: ["internal tool", "not launching"],
|
|
177
|
-
deliverableAffinity: ["Copy"],
|
|
178
|
-
},
|
|
179
|
-
|
|
180
|
-
// ── PRODUCT ──
|
|
181
|
-
{
|
|
182
|
-
name: "Feedback Synthesizer", pack: "product", phase: 1,
|
|
183
|
-
keywords: ["feedback", "signal", "cluster", "theme", "complaint", "user signal", "sentiment"],
|
|
184
|
-
triggers: ["signal clustering", "theme extraction", "complaint-to-action"],
|
|
185
|
-
excludeWhen: ["no user feedback available"],
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
name: "Roadmap Prioritizer", pack: "product", phase: 1,
|
|
189
|
-
keywords: ["roadmap", "prioritize", "backlog", "sequence", "leverage", "dependency", "stop doing"],
|
|
190
|
-
triggers: ["work sequencing", "backlog ordering", "dependency mapping", "stop doing"],
|
|
191
|
-
excludeWhen: ["single task", "no prioritization needed"],
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
name: "Spec Writer", pack: "product", phase: 2,
|
|
195
|
-
keywords: ["spec", "specification", "acceptance criteria", "edge case", "requirements", "nfr", "non-functional"],
|
|
196
|
-
triggers: ["execution-grade spec", "acceptance criteria", "edge case enumeration"],
|
|
197
|
-
excludeWhen: ["spec already exists"],
|
|
198
|
-
deliverableAffinity: ["Plan"],
|
|
199
|
-
},
|
|
200
|
-
|
|
201
|
-
// ── RESEARCH ──
|
|
202
|
-
{
|
|
203
|
-
name: "UX Researcher", pack: "research", phase: 1,
|
|
204
|
-
keywords: ["usability", "friction", "heuristic", "user flow", "ux", "user experience", "pain point"],
|
|
205
|
-
triggers: ["user flow friction", "heuristic evaluation", "usability issue"],
|
|
206
|
-
excludeWhen: ["no user interface", "cli only"],
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
name: "Competitive Analyst", pack: "research", phase: 1,
|
|
210
|
-
keywords: ["competitive", "competitor", "differentiation", "positioning", "landscape", "alternative"],
|
|
211
|
-
triggers: ["competitive landscape", "differentiation assessment", "positioning gap"],
|
|
212
|
-
excludeWhen: ["no competitors"],
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
name: "Trend Researcher", pack: "research", phase: 1,
|
|
216
|
-
keywords: ["trend", "ecosystem", "adoption", "market", "emerging", "signal"],
|
|
217
|
-
triggers: ["technology trend", "ecosystem signal", "adoption timing"],
|
|
218
|
-
excludeWhen: ["no trend relevance"],
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
name: "User Interview Synthesizer", pack: "research", phase: 1,
|
|
222
|
-
keywords: ["interview", "mental model", "unmet need", "user research", "synthesis", "qualitative"],
|
|
223
|
-
triggers: ["interview theme", "mental model mapping", "unmet needs ranking"],
|
|
224
|
-
excludeWhen: ["no interview data"],
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
"
|
|
388
|
-
"
|
|
389
|
-
"
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
//
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve, dirname } from "node:path";
|
|
3
|
+
import { readFileSafe } from "./fs-utils.mjs";
|
|
4
|
+
import { detectConflicts } from "./conflicts.mjs";
|
|
5
|
+
import { resolveConflict, resolveSplit, formatEscalation } from "./escalation.mjs";
|
|
6
|
+
import { suggestPack, getPack, checkPackMismatch, getPackRoles } from "./packs.mjs";
|
|
7
|
+
|
|
8
|
+
// ── Full 31-Role Catalog ─────────────────────────────────────────────────────
|
|
9
|
+
// Every role in the OS is scoreable. Keywords from routing-rules.md + contracts.
|
|
10
|
+
// Triggers are strong multi-word signals worth bonus points.
|
|
11
|
+
|
|
12
|
+
export const ROLE_CATALOG = [
|
|
13
|
+
// ── CORE ──
|
|
14
|
+
{
|
|
15
|
+
name: "Orchestrator", pack: "core", phase: 0,
|
|
16
|
+
alwaysInclude: true,
|
|
17
|
+
keywords: [],
|
|
18
|
+
triggers: ["multi-step", "cross-functional", "decomposition", "sequencing"],
|
|
19
|
+
excludeWhen: [],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "Product Strategist", pack: "product", phase: 1,
|
|
23
|
+
keywords: ["product", "scope", "intent", "prioritize", "tradeoff", "framing", "user value", "feature shaping"],
|
|
24
|
+
triggers: ["problem framing", "scope definition", "tradeoff decision"],
|
|
25
|
+
excludeWhen: [],
|
|
26
|
+
deliverableAffinity: ["Plan"],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Critic Reviewer", pack: "core", phase: 99,
|
|
30
|
+
alwaysInclude: true,
|
|
31
|
+
keywords: [],
|
|
32
|
+
triggers: ["final acceptance", "quality gate", "truthful rejection"],
|
|
33
|
+
excludeWhen: [],
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// ── DESIGN ──
|
|
37
|
+
{
|
|
38
|
+
name: "UI Designer", pack: "design", phase: 2,
|
|
39
|
+
keywords: ["ui", "screen", "layout", "hierarchy", "interaction", "visual", "design", "flow", "component", "wireframe"],
|
|
40
|
+
triggers: ["information hierarchy", "user flow", "interaction design", "screen structure"],
|
|
41
|
+
excludeWhen: ["no user interface", "cli only", "backend only"],
|
|
42
|
+
deliverableAffinity: ["Design"],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Brand Guardian", pack: "design", phase: 2,
|
|
46
|
+
keywords: ["brand", "identity", "terminology", "tone", "contamination", "fork", "residue", "purge", "naming"],
|
|
47
|
+
triggers: ["identity contamination", "fork residue", "terminology consistency", "replacement doctrine"],
|
|
48
|
+
excludeWhen: ["no brand concern", "internal tooling only"],
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// ── ENGINEERING ──
|
|
52
|
+
{
|
|
53
|
+
name: "Backend Engineer", pack: "engineering", phase: 3,
|
|
54
|
+
keywords: ["api", "server", "data", "persistence", "contract", "model", "migration", "bridge", "wiring", "session", "state", "database", "endpoint"],
|
|
55
|
+
triggers: ["server-side", "data flow", "system contract"],
|
|
56
|
+
excludeWhen: ["frontend only", "docs only"],
|
|
57
|
+
deliverableAffinity: ["Code"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "Frontend Developer", pack: "engineering", phase: 3,
|
|
61
|
+
keywords: ["frontend", "render", "component", "client", "tui", "display", "view", "react", "css", "html", "dom"],
|
|
62
|
+
triggers: ["ui implementation", "client state", "interaction wiring", "frontend integration"],
|
|
63
|
+
excludeWhen: ["backend only", "no ui"],
|
|
64
|
+
deliverableAffinity: ["Code"],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "Test Engineer", pack: "engineering", phase: 4,
|
|
68
|
+
keywords: ["test", "verify", "regression", "coverage", "assertion", "edge case", "vitest", "jest", "spec"],
|
|
69
|
+
triggers: ["test plan", "regression defense", "verification coverage"],
|
|
70
|
+
excludeWhen: [],
|
|
71
|
+
deliverableAffinity: ["Test"],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "Performance Engineer", pack: "engineering", phase: 3,
|
|
75
|
+
keywords: ["performance", "profiling", "latency", "memory", "benchmark", "optimization", "hot path", "budget", "slow", "bottleneck"],
|
|
76
|
+
triggers: ["performance regression", "hot path analysis", "performance budget"],
|
|
77
|
+
excludeWhen: ["no performance concern"],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "Refactor Engineer", pack: "engineering", phase: 3,
|
|
81
|
+
keywords: ["refactor", "duplication", "boundary", "complexity", "cleanup", "modularize", "split", "extract", "simplify"],
|
|
82
|
+
triggers: ["structure cleanup", "module boundary", "complexity reduction", "duplication elimination"],
|
|
83
|
+
excludeWhen: ["new feature", "behavior change required"],
|
|
84
|
+
deliverableAffinity: ["Code"],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "Security Reviewer", pack: "engineering", phase: 3,
|
|
88
|
+
keywords: ["security", "injection", "auth", "authentication", "authorization", "secrets", "owasp", "threat", "vulnerability", "xss", "csrf", "sanitize"],
|
|
89
|
+
triggers: ["security review", "threat model", "owasp pattern", "secret scanning"],
|
|
90
|
+
excludeWhen: ["no security surface"],
|
|
91
|
+
deliverableAffinity: ["Review"],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "Dependency Auditor", pack: "engineering", phase: 3,
|
|
95
|
+
keywords: ["dependency", "dependencies", "vulnerability", "supply chain", "stale", "outdated", "audit", "npm audit", "dependabot"],
|
|
96
|
+
triggers: ["dependency health", "supply-chain risk", "vulnerability scanning"],
|
|
97
|
+
excludeWhen: ["no external dependencies"],
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// ── TREATMENT ──
|
|
101
|
+
{
|
|
102
|
+
name: "Repo Researcher", pack: "treatment", phase: 1,
|
|
103
|
+
keywords: ["repo structure", "entrypoint", "seam", "build command", "test command", "codebase", "architecture", "map"],
|
|
104
|
+
triggers: ["repo structure mapping", "entrypoint discovery", "dependency verification"],
|
|
105
|
+
excludeWhen: ["repo already well understood"],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "Repo Translator", pack: "treatment", phase: 5,
|
|
109
|
+
keywords: ["translate", "translation", "localize", "localization", "i18n", "multilingual", "language", "readme translation", "polyglot"],
|
|
110
|
+
triggers: ["readme translation", "docs translation", "cross-audience adaptation"],
|
|
111
|
+
excludeWhen: ["english only", "no translation needed"],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "Docs Architect", pack: "treatment", phase: 3,
|
|
115
|
+
keywords: ["documentation", "handbook", "docs", "starlight", "guide", "tutorial", "reference", "api docs", "navigation", "hierarchy", "findability", "labeling", "taxonomy", "sitemap"],
|
|
116
|
+
triggers: ["handbook creation", "docs site", "starlight setup", "documentation restructuring", "navigation design", "content organization", "information structure"],
|
|
117
|
+
excludeWhen: ["no docs needed"],
|
|
118
|
+
deliverableAffinity: ["Plan"],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "Metadata Curator", pack: "treatment", phase: 5,
|
|
122
|
+
keywords: ["metadata", "manifest", "package.json", "badge", "topic", "homepage", "description", "registry", "npm"],
|
|
123
|
+
triggers: ["package manifest audit", "badge verification", "registry metadata"],
|
|
124
|
+
excludeWhen: ["no package metadata"],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "Coverage Auditor", pack: "treatment", phase: 4,
|
|
128
|
+
keywords: ["coverage", "test coverage", "uncovered", "false confidence", "missing test", "untested"],
|
|
129
|
+
triggers: ["coverage assessment", "false confidence detection", "missing defense"],
|
|
130
|
+
excludeWhen: ["no test suite"],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "Deployment Verifier", pack: "treatment", phase: 6,
|
|
134
|
+
keywords: ["deploy", "deployment", "live", "landing page", "published", "badge", "verify live", "spot check"],
|
|
135
|
+
triggers: ["post-deploy verification", "landing page check", "badge resolution", "translation spot-check"],
|
|
136
|
+
excludeWhen: ["not yet deployed"],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "Release Engineer", pack: "treatment", phase: 5,
|
|
140
|
+
keywords: ["release", "version", "changelog", "tag", "publish", "package", "bump", "npm publish", "staging"],
|
|
141
|
+
triggers: ["version bump", "changelog update", "publish readiness", "release execution"],
|
|
142
|
+
excludeWhen: ["not releasing"],
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// ── GROWTH ──
|
|
146
|
+
{
|
|
147
|
+
name: "Launch Strategist", pack: "growth", phase: 6,
|
|
148
|
+
keywords: ["launch", "go-to-market", "channel", "timing", "proof", "success criteria", "announcement"],
|
|
149
|
+
triggers: ["launch planning", "proof packaging", "channel selection", "success criteria"],
|
|
150
|
+
excludeWhen: ["internal tool", "not launching"],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "Content Strategist", pack: "growth", phase: 6,
|
|
154
|
+
keywords: ["content", "article", "blog", "case study", "tutorial", "marketing content", "content calendar"],
|
|
155
|
+
triggers: ["content planning", "technical article", "case study angle", "docs-to-marketing bridge"],
|
|
156
|
+
excludeWhen: ["no content needed"],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "Community Manager", pack: "growth", phase: 6,
|
|
160
|
+
keywords: ["community", "issue triage", "discussion", "contribution", "contributor", "feedback loop", "open source"],
|
|
161
|
+
triggers: ["community response", "contribution guidance", "community health"],
|
|
162
|
+
excludeWhen: ["private repo", "no community"],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "Support Triage Lead", pack: "growth", phase: 6,
|
|
166
|
+
keywords: ["support", "triage", "bug report", "user error", "recurring", "priority assignment"],
|
|
167
|
+
triggers: ["support classification", "bug vs user error", "recurring pattern"],
|
|
168
|
+
excludeWhen: ["no support surface"],
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// ── MARKETING ──
|
|
172
|
+
{
|
|
173
|
+
name: "Launch Copywriter", pack: "marketing", phase: 6,
|
|
174
|
+
keywords: ["copy", "messaging", "positioning", "release notes", "announcement", "conversion"],
|
|
175
|
+
triggers: ["launch messaging", "release notes", "positioning copy"],
|
|
176
|
+
excludeWhen: ["internal tool", "not launching"],
|
|
177
|
+
deliverableAffinity: ["Copy"],
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// ── PRODUCT ──
|
|
181
|
+
{
|
|
182
|
+
name: "Feedback Synthesizer", pack: "product", phase: 1,
|
|
183
|
+
keywords: ["feedback", "signal", "cluster", "theme", "complaint", "user signal", "sentiment"],
|
|
184
|
+
triggers: ["signal clustering", "theme extraction", "complaint-to-action"],
|
|
185
|
+
excludeWhen: ["no user feedback available"],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "Roadmap Prioritizer", pack: "product", phase: 1,
|
|
189
|
+
keywords: ["roadmap", "prioritize", "backlog", "sequence", "leverage", "dependency", "stop doing"],
|
|
190
|
+
triggers: ["work sequencing", "backlog ordering", "dependency mapping", "stop doing"],
|
|
191
|
+
excludeWhen: ["single task", "no prioritization needed"],
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: "Spec Writer", pack: "product", phase: 2,
|
|
195
|
+
keywords: ["spec", "specification", "acceptance criteria", "edge case", "requirements", "nfr", "non-functional"],
|
|
196
|
+
triggers: ["execution-grade spec", "acceptance criteria", "edge case enumeration"],
|
|
197
|
+
excludeWhen: ["spec already exists"],
|
|
198
|
+
deliverableAffinity: ["Plan"],
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
// ── RESEARCH ──
|
|
202
|
+
{
|
|
203
|
+
name: "UX Researcher", pack: "research", phase: 1,
|
|
204
|
+
keywords: ["usability", "friction", "heuristic", "user flow", "ux", "user experience", "pain point"],
|
|
205
|
+
triggers: ["user flow friction", "heuristic evaluation", "usability issue"],
|
|
206
|
+
excludeWhen: ["no user interface", "cli only"],
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "Competitive Analyst", pack: "research", phase: 1,
|
|
210
|
+
keywords: ["competitive", "competitor", "differentiation", "positioning", "landscape", "alternative"],
|
|
211
|
+
triggers: ["competitive landscape", "differentiation assessment", "positioning gap"],
|
|
212
|
+
excludeWhen: ["no competitors"],
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "Trend Researcher", pack: "research", phase: 1,
|
|
216
|
+
keywords: ["trend", "ecosystem", "adoption", "market", "emerging", "signal"],
|
|
217
|
+
triggers: ["technology trend", "ecosystem signal", "adoption timing"],
|
|
218
|
+
excludeWhen: ["no trend relevance"],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: "User Interview Synthesizer", pack: "research", phase: 1,
|
|
222
|
+
keywords: ["interview", "mental model", "unmet need", "user research", "synthesis", "qualitative"],
|
|
223
|
+
triggers: ["interview theme", "mental model mapping", "unmet needs ranking"],
|
|
224
|
+
excludeWhen: ["no interview data"],
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// ── BRAINSTORM ──
|
|
228
|
+
{
|
|
229
|
+
name: "Context Scout", pack: "brainstorm", phase: 1,
|
|
230
|
+
keywords: ["landscape", "terminology", "adjacent", "prior art", "domain", "context"],
|
|
231
|
+
triggers: ["domain landscape", "adjacent space mapping", "terminology mapping"],
|
|
232
|
+
excludeWhen: ["no exploration needed"],
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "User Value Scout", pack: "brainstorm", phase: 1,
|
|
236
|
+
keywords: ["pain", "desire", "behavior", "unmet need", "user segment", "user value"],
|
|
237
|
+
triggers: ["user pain mapping", "unmet need discovery", "desire mapping"],
|
|
238
|
+
excludeWhen: ["no user concern"],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "Creative Leap Scout", pack: "brainstorm", phase: 1,
|
|
242
|
+
keywords: ["novel", "unexpected", "combination", "analogy", "bold", "creative", "divergent"],
|
|
243
|
+
triggers: ["cross-domain analogy", "unexpected combination", "bold bet"],
|
|
244
|
+
excludeWhen: ["conservative approach required"],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "Normalizer", pack: "brainstorm", phase: 2,
|
|
248
|
+
keywords: ["dedup", "normalize", "cluster", "conflict", "calibrate", "finding"],
|
|
249
|
+
triggers: ["finding normalization", "conflict detection", "evidence calibration"],
|
|
250
|
+
excludeWhen: [],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "Synthesizer", pack: "brainstorm", phase: 3,
|
|
254
|
+
keywords: ["synthesize", "theme", "direction", "pattern", "tension", "consensus"],
|
|
255
|
+
triggers: ["direction selection", "theme extraction", "tension preservation"],
|
|
256
|
+
excludeWhen: [],
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: "Product Expander", pack: "brainstorm", phase: 4,
|
|
260
|
+
keywords: ["expand", "features", "core loop", "proof", "target user", "product shape"],
|
|
261
|
+
triggers: ["concept expansion", "product shape", "smallest proof version"],
|
|
262
|
+
excludeWhen: [],
|
|
263
|
+
deliverableAffinity: ["Plan"],
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: "Judge", pack: "brainstorm", phase: 5,
|
|
267
|
+
keywords: ["judge", "gate", "disposition", "quality", "accept", "revise", "reject"],
|
|
268
|
+
triggers: ["quality gate", "disposition routing", "revision targeting"],
|
|
269
|
+
excludeWhen: [],
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
// ── BRAINSTORM (v1.0 optional roles) ──
|
|
273
|
+
{
|
|
274
|
+
name: "Mechanics Scout", pack: "brainstorm", phase: 1,
|
|
275
|
+
keywords: ["structural", "operational", "mechanism", "how it works", "feasibility"],
|
|
276
|
+
triggers: ["structural feasibility", "operational mechanism"],
|
|
277
|
+
excludeWhen: [],
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "Market Scout", pack: "brainstorm", phase: 1,
|
|
281
|
+
keywords: ["market", "existing", "whitespace", "sameness", "positioning"],
|
|
282
|
+
triggers: ["market whitespace", "existing solutions", "sameness trap"],
|
|
283
|
+
excludeWhen: [],
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "Contrarian Scout", pack: "brainstorm", phase: 2,
|
|
287
|
+
keywords: ["challenge", "contrarian", "counter", "weakness", "overgeneralization"],
|
|
288
|
+
triggers: ["evidence challenge", "finding challenge", "false novelty"],
|
|
289
|
+
excludeWhen: [],
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: "Feasibility Scout", pack: "brainstorm", phase: 1,
|
|
293
|
+
keywords: ["feasible", "provable", "buildable", "timeline", "complexity"],
|
|
294
|
+
triggers: ["feasibility assessment", "proof timeline"],
|
|
295
|
+
excludeWhen: [],
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: "Quality Bar Scout", pack: "brainstorm", phase: 1,
|
|
299
|
+
keywords: ["excellence", "quality", "adequate", "bar", "standard"],
|
|
300
|
+
triggers: ["quality threshold", "excellence criteria"],
|
|
301
|
+
excludeWhen: [],
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "Scenario Expander", pack: "brainstorm", phase: 4,
|
|
305
|
+
keywords: ["scenario", "user situation", "edge case", "failure mode", "context"],
|
|
306
|
+
triggers: ["concrete scenario", "user situation", "failure mode analysis"],
|
|
307
|
+
excludeWhen: [],
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: "Moat Expander", pack: "brainstorm", phase: 4,
|
|
311
|
+
keywords: ["moat", "defensibility", "stickiness", "competitive", "differentiation"],
|
|
312
|
+
triggers: ["defensibility analysis", "competitive moat", "phase planning"],
|
|
313
|
+
excludeWhen: [],
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
// ── BRAINSTORM v0.3 (specialized analysts with hard boundaries) ──
|
|
317
|
+
{
|
|
318
|
+
name: "Context Analyst", pack: "brainstorm", phase: 1,
|
|
319
|
+
keywords: ["terminology", "genealogy", "adjacency", "category", "boundary", "lineage"],
|
|
320
|
+
triggers: ["terminology genealogy", "category boundary mapping", "adjacency analysis"],
|
|
321
|
+
excludeWhen: [],
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "User Value Analyst", pack: "brainstorm", phase: 1,
|
|
325
|
+
keywords: ["jobs", "friction", "willingness", "avoidance", "desire", "pain"],
|
|
326
|
+
triggers: ["jobs-to-be-done analysis", "friction mapping", "willingness signal detection"],
|
|
327
|
+
excludeWhen: [],
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "Mechanics Analyst", pack: "brainstorm", phase: 1,
|
|
331
|
+
keywords: ["loop", "dependency", "constraint", "failure mode", "irreducible"],
|
|
332
|
+
triggers: ["loop decomposition", "dependency chain analysis", "failure mode identification"],
|
|
333
|
+
excludeWhen: [],
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: "Positioning Analyst", pack: "brainstorm", phase: 1,
|
|
337
|
+
keywords: ["substitute", "wedge", "timing", "category frame", "claim"],
|
|
338
|
+
triggers: ["wedge identification", "substitute comparison", "claim timing analysis"],
|
|
339
|
+
excludeWhen: [],
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "Contrarian Analyst", pack: "brainstorm", phase: 2,
|
|
343
|
+
keywords: ["challenge", "overstated", "premature", "contradiction", "false"],
|
|
344
|
+
triggers: ["targeted challenge", "claim attack", "contradiction exposure"],
|
|
345
|
+
excludeWhen: [],
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
// ── DEEP AUDIT ──
|
|
349
|
+
{
|
|
350
|
+
name: "Component Auditor", pack: "deep-audit", phase: 3,
|
|
351
|
+
keywords: ["audit", "component", "correctness", "dead code", "error handling", "state management"],
|
|
352
|
+
triggers: ["deep audit", "component audit", "code audit", "line-by-line audit"],
|
|
353
|
+
excludeWhen: ["test audit only", "boundary audit only"],
|
|
354
|
+
deliverableAffinity: ["Review"],
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "Seam Auditor", pack: "deep-audit", phase: 4,
|
|
358
|
+
keywords: ["boundary", "seam", "interface", "contract", "integration", "dependency direction"],
|
|
359
|
+
triggers: ["boundary audit", "seam inspection", "interface mismatch", "cross-component"],
|
|
360
|
+
excludeWhen: ["single component only", "test audit only"],
|
|
361
|
+
deliverableAffinity: ["Review"],
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "Test Truth Auditor", pack: "deep-audit", phase: 3,
|
|
365
|
+
keywords: ["test coverage", "test truth", "ceremonial test", "test gap", "mock fidelity"],
|
|
366
|
+
triggers: ["test truth audit", "coverage reality", "test quality assessment"],
|
|
367
|
+
excludeWhen: ["no tests exist", "implementation audit only"],
|
|
368
|
+
deliverableAffinity: ["Review"],
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "Audit Synthesizer", pack: "deep-audit", phase: 5,
|
|
372
|
+
keywords: ["synthesis", "verdict", "action plan", "reconcile", "cross-cutting"],
|
|
373
|
+
triggers: ["audit synthesis", "repo verdict", "finding reconciliation"],
|
|
374
|
+
excludeWhen: ["component audit still running", "no findings to synthesize"],
|
|
375
|
+
deliverableAffinity: ["Review"],
|
|
376
|
+
},
|
|
377
|
+
];
|
|
378
|
+
|
|
379
|
+
// ── Deliverable type → role affinity ──────────────────────────────────────────
|
|
380
|
+
|
|
381
|
+
const DELIVERABLE_TYPES = ["Plan", "Design", "Code", "Test", "Copy", "Review"];
|
|
382
|
+
|
|
383
|
+
// ── Packet type → role score bias ─────────────────────────────────────────────
|
|
384
|
+
// These boost relevant roles by packet type, but don't lock the chain.
|
|
385
|
+
|
|
386
|
+
const TYPE_BIAS = {
|
|
387
|
+
feature: ["Product Strategist", "UI Designer", "Backend Engineer", "Frontend Developer", "Test Engineer"],
|
|
388
|
+
integration: ["Backend Engineer", "Frontend Developer", "Test Engineer", "Refactor Engineer"],
|
|
389
|
+
identity: ["Brand Guardian", "Metadata Curator", "UI Designer", "Frontend Developer"],
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// ── Phase ordering (for chain assembly) ───────────────────────────────────────
|
|
393
|
+
// Lower phase = earlier in chain. Same phase = sorted by pack then name.
|
|
394
|
+
|
|
395
|
+
function phaseOf(role) {
|
|
396
|
+
return role.phase ?? 3;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ── Scoring ───────────────────────────────────────────────────────────────────
|
|
400
|
+
|
|
401
|
+
const MIN_SCORE_THRESHOLD = 2; // Minimum score to be included in chain
|
|
402
|
+
|
|
403
|
+
function scoreRole(role, content, packetType, deliverableType) {
|
|
404
|
+
if (role.alwaysInclude) return { score: Infinity, reasons: ["always included"], matched: [] };
|
|
405
|
+
|
|
406
|
+
const lower = content.toLowerCase();
|
|
407
|
+
let score = 0;
|
|
408
|
+
const matched = [];
|
|
409
|
+
|
|
410
|
+
// Keyword hits (1 point each)
|
|
411
|
+
for (const kw of role.keywords) {
|
|
412
|
+
if (lower.includes(kw)) {
|
|
413
|
+
score += 1;
|
|
414
|
+
matched.push(kw);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Trigger phrase bonus (2 points each — strong signals)
|
|
419
|
+
for (const trigger of role.triggers) {
|
|
420
|
+
if (lower.includes(trigger)) {
|
|
421
|
+
score += 2;
|
|
422
|
+
if (!matched.includes(trigger)) matched.push(`[trigger] ${trigger}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Packet type bias (+1 if role is in the type's preferred set)
|
|
427
|
+
const biased = TYPE_BIAS[packetType] || [];
|
|
428
|
+
if (biased.includes(role.name)) {
|
|
429
|
+
score += 1;
|
|
430
|
+
matched.push(`[type-bias] ${packetType}`);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Deliverable type affinity (+1)
|
|
434
|
+
if (deliverableType && role.deliverableAffinity?.includes(deliverableType)) {
|
|
435
|
+
score += 1;
|
|
436
|
+
matched.push(`[deliverable] ${deliverableType}`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// excludeWhen enforcement — suppress role if exclusion patterns match
|
|
440
|
+
if (score > 0 && role.excludeWhen) {
|
|
441
|
+
for (const exclusion of role.excludeWhen) {
|
|
442
|
+
if (lower.includes(exclusion)) {
|
|
443
|
+
return { score: 0, reasons: [`excluded: "${exclusion}"`], matched: [] };
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return { score, reasons: matched.length > 0 ? matched : [], matched };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ── Type detection ────────────────────────────────────────────────────────────
|
|
452
|
+
|
|
453
|
+
function detectType(content) {
|
|
454
|
+
const typeMatch = content.match(/## Packet Type\n(\w+)/);
|
|
455
|
+
if (typeMatch && ["feature", "integration", "identity"].includes(typeMatch[1])) {
|
|
456
|
+
return typeMatch[1];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const lower = content.toLowerCase();
|
|
460
|
+
if (lower.includes("contamination") || lower.includes("residue") || lower.includes("purge")) {
|
|
461
|
+
return "identity";
|
|
462
|
+
}
|
|
463
|
+
// Use word-boundary-aware matching to avoid false positives like "integration testing"
|
|
464
|
+
if (lower.includes("wiring") || lower.includes("bridge") || /\bintegration\b(?!\s+test)/.test(lower) || lower.includes("seam")) {
|
|
465
|
+
return "integration";
|
|
466
|
+
}
|
|
467
|
+
return "feature";
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// ── Deliverable type extraction ───────────────────────────────────────────────
|
|
471
|
+
|
|
472
|
+
function extractDeliverableType(content) {
|
|
473
|
+
const match = content.match(/## Deliverable Type\n(\w+)/);
|
|
474
|
+
if (match && DELIVERABLE_TYPES.includes(match[1])) return match[1];
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ── Chain assembly ────────────────────────────────────────────────────────────
|
|
479
|
+
// Scored roles → ordered chain. Phase-sorted, not template-locked.
|
|
480
|
+
|
|
481
|
+
function assembleChain(scoredRoles) {
|
|
482
|
+
// Sort by phase, then pack, then name
|
|
483
|
+
const chain = scoredRoles.sort((a, b) => {
|
|
484
|
+
const pa = phaseOf(a.role);
|
|
485
|
+
const pb = phaseOf(b.role);
|
|
486
|
+
if (pa !== pb) return pa - pb;
|
|
487
|
+
if (a.role.pack !== b.role.pack) return a.role.pack.localeCompare(b.role.pack);
|
|
488
|
+
return a.role.name.localeCompare(b.role.name);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
return chain;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// ── Confidence assessment ─────────────────────────────────────────────────────
|
|
495
|
+
|
|
496
|
+
function assessConfidence(scoredRoles) {
|
|
497
|
+
const strongRoles = scoredRoles.filter(r => !r.role.alwaysInclude && r.score >= MIN_SCORE_THRESHOLD);
|
|
498
|
+
if (strongRoles.length >= 3) return "high";
|
|
499
|
+
if (strongRoles.length >= 1) return "medium";
|
|
500
|
+
return "low";
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ── File reference extraction ─────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
function extractFileRefs(content, packetDir) {
|
|
506
|
+
const refs = [];
|
|
507
|
+
const inputsMatch = content.match(/## Inputs\n([\s\S]*?)(?=\n## |\n---)/);
|
|
508
|
+
if (!inputsMatch) return refs;
|
|
509
|
+
|
|
510
|
+
const inputsSection = inputsMatch[1];
|
|
511
|
+
const pathPattern = /(?:^|\s|`)((?:\.\/|\.\.\/|[a-zA-Z][\w\-]*\/)[^\s`\n,)]+\.\w+)/gm;
|
|
512
|
+
let match;
|
|
513
|
+
while ((match = pathPattern.exec(inputsSection)) !== null) {
|
|
514
|
+
const ref = match[1];
|
|
515
|
+
const resolved = resolve(dirname(packetDir), "..", "..", ref);
|
|
516
|
+
refs.push({ ref, resolved, exists: existsSync(resolved) });
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return refs;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ── Handoff hints ─────────────────────────────────────────────────────────────
|
|
523
|
+
|
|
524
|
+
const HANDOFF_HINTS = {
|
|
525
|
+
"Orchestrator": "decomposes into role-owned packets with verified dependencies",
|
|
526
|
+
"Product Strategist": "hands off: scope doc, prioritized requirements, tradeoff decisions",
|
|
527
|
+
"UI Designer": "hands off: screen structure, interaction flow, visual direction",
|
|
528
|
+
"Brand Guardian": "hands off: terminology audit, contamination report, replacement rules",
|
|
529
|
+
"Backend Engineer": "hands off: implemented APIs, data contracts, migration scripts",
|
|
530
|
+
"Frontend Developer": "hands off: implemented UI, client state, integration wiring",
|
|
531
|
+
"Test Engineer": "hands off: test results, coverage report, edge case findings",
|
|
532
|
+
"Performance Engineer": "hands off: profiling results, identified hot paths, optimization plan",
|
|
533
|
+
"Refactor Engineer": "hands off: restructured code, boundary changes, diff summary",
|
|
534
|
+
"Security Reviewer": "hands off: threat model, flagged patterns, recommended mitigations",
|
|
535
|
+
"Dependency Auditor": "hands off: audit report, vulnerability triage, update recommendations",
|
|
536
|
+
"Repo Researcher": "hands off: repo map, entrypoints, build/test commands, seam inventory",
|
|
537
|
+
"Repo Translator": "hands off: translated files, verification notes, degenerate output flags",
|
|
538
|
+
"Docs Architect": "hands off: docs structure, handbook setup, navigation hierarchy",
|
|
539
|
+
"Metadata Curator": "hands off: updated manifests, badge status, registry alignment report",
|
|
540
|
+
"Coverage Auditor": "hands off: coverage report, false confidence inventory, missing defenses",
|
|
541
|
+
"Deployment Verifier": "hands off: verification checklist, live artifact status, broken links",
|
|
542
|
+
"Release Engineer": "hands off: versioned package, changelog, tag, publish confirmation",
|
|
543
|
+
"Launch Strategist": "hands off: launch plan, channel selection, success criteria, timing",
|
|
544
|
+
"Content Strategist": "hands off: content plan, article outlines, calendar",
|
|
545
|
+
"Community Manager": "hands off: triage report, response drafts, health assessment",
|
|
546
|
+
"Support Triage Lead": "hands off: classified tickets, priority assignments, recurring patterns",
|
|
547
|
+
"Launch Copywriter": "hands off: release notes, positioning copy, announcement drafts",
|
|
548
|
+
"Feedback Synthesizer": "hands off: signal clusters, themes, actionable insights",
|
|
549
|
+
"Roadmap Prioritizer": "hands off: sequenced backlog, dependency map, stop-doing list",
|
|
550
|
+
"Spec Writer": "hands off: execution-grade spec, acceptance criteria, edge cases, NFRs",
|
|
551
|
+
"UX Researcher": "hands off: friction inventory, heuristic findings, design input",
|
|
552
|
+
"Competitive Analyst": "hands off: landscape map, differentiation analysis, positioning gaps",
|
|
553
|
+
"Trend Researcher": "hands off: trend report, impact assessment, timing recommendations",
|
|
554
|
+
"User Interview Synthesizer": "hands off: theme report, mental models, unmet needs ranking",
|
|
555
|
+
"Critic Reviewer": "accepts, rejects, or blocks based on contract and evidence",
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
// ── Main route command ────────────────────────────────────────────────────────
|
|
559
|
+
|
|
560
|
+
export async function routeCommand(args) {
|
|
561
|
+
const verbose = args.includes("--verbose");
|
|
562
|
+
const packFlag = args.find(a => a.startsWith("--pack="));
|
|
563
|
+
const requestedPack = packFlag ? packFlag.split("=")[1] : null;
|
|
564
|
+
const packetFile = args.find(a => !a.startsWith("--"));
|
|
565
|
+
|
|
566
|
+
if (!packetFile) {
|
|
567
|
+
const err = new Error("Usage: roleos route <packet-file>");
|
|
568
|
+
err.exitCode = 1;
|
|
569
|
+
err.hint = "Provide the path to a packet file.";
|
|
570
|
+
throw err;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const content = readFileSafe(packetFile);
|
|
574
|
+
if (content === null) {
|
|
575
|
+
const err = new Error(`Packet not found: ${packetFile}`);
|
|
576
|
+
err.exitCode = 1;
|
|
577
|
+
err.hint = "Check the file path and try again.";
|
|
578
|
+
throw err;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const type = detectType(content);
|
|
582
|
+
const deliverableType = extractDeliverableType(content);
|
|
583
|
+
|
|
584
|
+
// Score all 32 roles
|
|
585
|
+
const allScored = ROLE_CATALOG.map(role => ({
|
|
586
|
+
role,
|
|
587
|
+
...scoreRole(role, content, type, deliverableType),
|
|
588
|
+
}));
|
|
589
|
+
|
|
590
|
+
// Partition: always-include + above-threshold + considered + not-triggered
|
|
591
|
+
const alwaysInclude = allScored.filter(r => r.role.alwaysInclude);
|
|
592
|
+
const recommended = allScored.filter(r => !r.role.alwaysInclude && r.score >= MIN_SCORE_THRESHOLD);
|
|
593
|
+
const considered = allScored.filter(r => !r.role.alwaysInclude && r.score > 0 && r.score < MIN_SCORE_THRESHOLD);
|
|
594
|
+
const notTriggered = allScored.filter(r => !r.role.alwaysInclude && r.score === 0);
|
|
595
|
+
|
|
596
|
+
// Assemble chain from always-include + recommended
|
|
597
|
+
const chainRoles = assembleChain([...alwaysInclude, ...recommended]);
|
|
598
|
+
const confidence = assessConfidence(allScored);
|
|
599
|
+
const fileRefs = extractFileRefs(content, resolve(packetFile));
|
|
600
|
+
|
|
601
|
+
// Chain size warning
|
|
602
|
+
const chainWarning = chainRoles.length > 7
|
|
603
|
+
? "\n ⚠ Large chain (>7 roles). Consider splitting into sub-packets."
|
|
604
|
+
: "";
|
|
605
|
+
|
|
606
|
+
// ── Output ──
|
|
607
|
+
|
|
608
|
+
console.log(`\nroleos route — ${packetFile}\n`);
|
|
609
|
+
console.log(`Detected type: ${type}`);
|
|
610
|
+
if (deliverableType) console.log(`Deliverable type: ${deliverableType}`);
|
|
611
|
+
|
|
612
|
+
// ── Pack suggestion / selection ──
|
|
613
|
+
const packSuggestion = suggestPack(content);
|
|
614
|
+
if (requestedPack) {
|
|
615
|
+
const pack = getPack(requestedPack);
|
|
616
|
+
if (!pack) {
|
|
617
|
+
console.log(`\n⚠ Unknown pack: "${requestedPack}". Falling back to free routing.`);
|
|
618
|
+
} else {
|
|
619
|
+
const mismatch = checkPackMismatch(requestedPack, content);
|
|
620
|
+
if (mismatch) {
|
|
621
|
+
console.log(`\n⚠ Pack mismatch detected: ${mismatch.reason}`);
|
|
622
|
+
console.log(` → Suggested alternative: roleos route --pack=${mismatch.suggestInstead} ${packetFile}`);
|
|
623
|
+
console.log(` Falling back to free routing for this task.`);
|
|
624
|
+
} else {
|
|
625
|
+
const packRoles = getPackRoles(requestedPack);
|
|
626
|
+
console.log(`\nUsing pack: ${pack.name} (${packRoles.length} roles)`);
|
|
627
|
+
console.log(`Chain: ${pack.chainOrder}`);
|
|
628
|
+
console.log(`Roles: ${packRoles.join(" → ")}`);
|
|
629
|
+
console.log(`\nPack artifacts: ${pack.requiredArtifacts.join(", ")}`);
|
|
630
|
+
console.log(`Stop conditions:`);
|
|
631
|
+
for (const sc of pack.stopConditions) {
|
|
632
|
+
console.log(` • ${sc}`);
|
|
633
|
+
}
|
|
634
|
+
console.log(`\nNext: assign roles and begin execution.`);
|
|
635
|
+
return; // Pack selected — skip free routing output
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
} else if (packSuggestion && packSuggestion.confidence !== "low") {
|
|
639
|
+
console.log(`\nSuggested pack: ${packSuggestion.pack} (${packSuggestion.confidence} confidence)`);
|
|
640
|
+
console.log(` → Use: roleos route --pack=${packSuggestion.pack} ${packetFile}`);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
console.log(`\nRouting confidence: ${confidence}`);
|
|
644
|
+
|
|
645
|
+
if (confidence === "low") {
|
|
646
|
+
console.log(` ↳ Few strong role signals detected. Consider reviewing the packet for missing context.`);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
console.log(`\nRecommended chain (${chainRoles.length} roles):${chainWarning}`);
|
|
650
|
+
chainRoles.forEach((r, i) => {
|
|
651
|
+
const hint = HANDOFF_HINTS[r.role.name] || "";
|
|
652
|
+
const reason = r.role.alwaysInclude
|
|
653
|
+
? "always included"
|
|
654
|
+
: `${r.matched.join(", ")} (score: ${r.score})`;
|
|
655
|
+
console.log(` ${i + 1}. ${r.role.name}`);
|
|
656
|
+
console.log(` why: ${reason}`);
|
|
657
|
+
if (hint) console.log(` handoff: ${hint}`);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
if (considered.length > 0) {
|
|
661
|
+
console.log(`\nAlso considered (scored but below threshold of ${MIN_SCORE_THRESHOLD}):`);
|
|
662
|
+
for (const r of considered.sort((a, b) => b.score - a.score)) {
|
|
663
|
+
console.log(` - ${r.role.name}: ${r.matched.join(", ")} (score: ${r.score})`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (verbose) {
|
|
668
|
+
console.log(`\nNot triggered: ${notTriggered.length} roles with 0 keyword signals`);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// ── Conflict detection + escalation routing ──
|
|
672
|
+
const conflicts = detectConflicts(chainRoles);
|
|
673
|
+
if (conflicts.length > 0) {
|
|
674
|
+
console.log(`\nConflict detection (${conflicts.length} finding${conflicts.length > 1 ? "s" : ""}):`);
|
|
675
|
+
for (const f of conflicts) {
|
|
676
|
+
const icon = f.severity === "error" ? "✗" : "!";
|
|
677
|
+
console.log(` ${icon} [${f.type}] ${f.message}`);
|
|
678
|
+
console.log(` repair: ${f.repair}`);
|
|
679
|
+
const escalation = resolveConflict(f);
|
|
680
|
+
console.log(` escalation: ${escalation.targetRole} (${escalation.recovery}) → ${escalation.requiredArtifact}`);
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
console.log(`\nConflict detection: clean — no conflicts found.`);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (fileRefs.length > 0) {
|
|
687
|
+
console.log(`\nDependency verification:`);
|
|
688
|
+
let hasIssues = false;
|
|
689
|
+
for (const ref of fileRefs) {
|
|
690
|
+
const status = ref.exists ? "OK" : "MISSING";
|
|
691
|
+
const marker = ref.exists ? "+" : "!";
|
|
692
|
+
console.log(` ${marker} ${ref.ref} — ${status}`);
|
|
693
|
+
if (!ref.exists) hasIssues = true;
|
|
694
|
+
}
|
|
695
|
+
if (hasIssues) {
|
|
696
|
+
console.log(`\n WARNING: Some referenced files are missing. Verify before proceeding.`);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Stop conditions with escalation routing
|
|
701
|
+
console.log(`\nStop conditions (auto-routed):`);
|
|
702
|
+
console.log(` • blocked verdict → auto-routes based on block reason (missing info → Product Strategist, dependency → Orchestrator, etc.)`);
|
|
703
|
+
console.log(` • rejected verdict → routes back to producing role or Orchestrator based on rejection type`);
|
|
704
|
+
if (chainRoles.length > 7) {
|
|
705
|
+
const splitEsc = resolveSplit(chainRoles.length);
|
|
706
|
+
console.log(` • split needed:`);
|
|
707
|
+
console.log(formatEscalation(splitEsc));
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
console.log(`\nNext: assign roles and begin execution, or adjust the chain.`);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// ── Exports for testing ───────────────────────────────────────────────────────
|
|
714
|
+
|
|
715
|
+
export { scoreRole, detectType, assembleChain, assessConfidence, extractFileRefs, extractDeliverableType, MIN_SCORE_THRESHOLD };
|