role-os 1.1.0 → 1.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 +19 -0
- package/README.md +2 -1
- package/package.json +1 -1
- package/src/packs.mjs +140 -53
- package/src/route.mjs +36 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Pack auto-selection in `roleos route` — suggests best pack when confidence is high
|
|
7
|
+
- `roleos route --pack=<name>` — use a specific pack for routing
|
|
8
|
+
- Pack mismatch detection — warns when a pack doesn't fit the task, suggests the correct alternative
|
|
9
|
+
- Pack fallback — mismatched or unknown packs fall back to free routing automatically
|
|
10
|
+
- `checkPackMismatch()` API with 7 guard sets covering all pack×task-type combinations
|
|
11
|
+
- `getPackRoles()` API with conditional Orchestrator support
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Docs pack: Support Triage Lead now opens (was Feedback Synthesizer). Feedback Synthesizer is second. Release Engineer + Deployment Verifier moved to optional (overhead for docs-only tasks).
|
|
15
|
+
- Pack calibration applied from comparison evidence: conditional Orchestrator, Security Reviewer in Treatment, Product Strategist opens Research, mismatch guards on all 7 packs.
|
|
16
|
+
|
|
17
|
+
### Evidence
|
|
18
|
+
- Pack comparison: calibrated packs now win or tie 6/7 (was 2/7 pre-calibration)
|
|
19
|
+
- Misfit honesty: 0 full bluffs, 0 undetected partial bluffs (was 1 + 3)
|
|
20
|
+
- 230 tests, zero failures
|
|
21
|
+
|
|
3
22
|
## 1.1.0
|
|
4
23
|
|
|
5
24
|
### Added
|
package/README.md
CHANGED
|
@@ -180,7 +180,8 @@ Role OS operates **locally only**. It copies markdown templates and writes packe
|
|
|
180
180
|
- v0.1–v0.4: Foundation — trials, adoption, treatment pack, starter pack
|
|
181
181
|
- v1.0.0: 32 roles, full CLI, proven treatment, multi-repo portability
|
|
182
182
|
- v1.0.2: Role OS lockdown (bootstrap truth fixes, init --force)
|
|
183
|
-
-
|
|
183
|
+
- v1.1.0: 31 roles, full routing spine, conflict detection, escalation, evidence, dispatch, 7 proven team packs. 35 execution trials. 212 tests.
|
|
184
|
+
- **v1.2.0**: Calibrated packs promoted to default entry. Auto-selection, mismatch detection, alternative suggestion, free-routing fallback. 230 tests.
|
|
184
185
|
|
|
185
186
|
## License
|
|
186
187
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "role-os",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Role OS — a multi-Claude operating system where 31 specialized roles execute work through contracts, conflict detection, escalation, and structured evidence. 7 proven team packs for common task families.",
|
|
5
5
|
"homepage": "https://mcp-tool-shop-org.github.io/role-os/",
|
|
6
6
|
"bugs": {
|
package/src/packs.mjs
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Proven Team Packs.
|
|
2
|
+
* Proven Team Packs — Calibrated.
|
|
3
3
|
*
|
|
4
4
|
* Battle-tested role combinations for common task families.
|
|
5
|
-
* Each pack was proven through execution trials (G1–G10)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Each pack was proven through execution trials (G1–G10) and
|
|
6
|
+
* calibrated by pack comparison trials (PACK-COMPARISON.md).
|
|
7
|
+
*
|
|
8
|
+
* Calibration findings applied:
|
|
9
|
+
* - Orchestrator is conditional (only when task is multi-role + ambiguous)
|
|
10
|
+
* - Every pack has mismatch detection + alternative suggestion
|
|
11
|
+
* - Treatment includes Security Reviewer by default
|
|
12
|
+
* - Research opens with Product Strategist (framing before research)
|
|
13
|
+
* - Docs has upstream-synthesis gate
|
|
8
14
|
*
|
|
9
15
|
* Usage: `roleos route --pack feature` or auto-detected from packet content.
|
|
10
16
|
*/
|
|
11
17
|
|
|
18
|
+
// ── Mismatch detection ────────────────────────────────────────────────────────
|
|
19
|
+
// Each pack declares what it is NOT for, and which pack IS right.
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Object} MismatchGuard
|
|
23
|
+
* @property {string[]} notForSignals - Content patterns that indicate this pack is wrong
|
|
24
|
+
* @property {string} suggestInstead - Which pack to suggest instead
|
|
25
|
+
* @property {string} reason - Why this pack is wrong for that signal
|
|
26
|
+
*/
|
|
27
|
+
|
|
12
28
|
// ── Pack definitions ──────────────────────────────────────────────────────────
|
|
13
29
|
|
|
14
30
|
export const TEAM_PACKS = {
|
|
@@ -24,6 +40,7 @@ export const TEAM_PACKS = {
|
|
|
24
40
|
"Test Engineer",
|
|
25
41
|
"Critic Reviewer",
|
|
26
42
|
],
|
|
43
|
+
orchestratorRequired: true, // multi-role, cross-functional — Orchestrator adds value
|
|
27
44
|
optionalRoles: ["UI Designer", "Frontend Developer", "Security Reviewer"],
|
|
28
45
|
chainOrder: "Product Strategist → Spec Writer → Backend Engineer → Test Engineer",
|
|
29
46
|
requiredArtifacts: ["scope doc", "spec", "implementation", "test results", "verdict"],
|
|
@@ -34,7 +51,11 @@ export const TEAM_PACKS = {
|
|
|
34
51
|
],
|
|
35
52
|
escalationOwner: "Orchestrator",
|
|
36
53
|
dispatchDefaults: { model: "sonnet", maxTurns: 30, maxBudgetUsd: 5.0 },
|
|
37
|
-
trialEvidence: "G1 (Product), G2 (Engineering) — 6/6 gold-task passes",
|
|
54
|
+
trialEvidence: "G1 (Product), G2 (Engineering) — 6/6 gold-task passes. Pack comparison: wins vs free routing.",
|
|
55
|
+
mismatchGuards: [
|
|
56
|
+
{ notForSignals: ["security review", "threat model", "vulnerability", "injection"], suggestInstead: "security", reason: "This is a security review, not a feature build" },
|
|
57
|
+
{ notForSignals: ["launch", "announce", "release notes", "messaging"], suggestInstead: "launch", reason: "This is launch/messaging work, not feature implementation" },
|
|
58
|
+
],
|
|
38
59
|
},
|
|
39
60
|
|
|
40
61
|
// ── Bugfix / Repair ───────────────────────────────────────────────────────
|
|
@@ -42,22 +63,26 @@ export const TEAM_PACKS = {
|
|
|
42
63
|
name: "Bugfix / Repair",
|
|
43
64
|
description: "Diagnose → fix → verify → review. Minimal chain, fast turnaround.",
|
|
44
65
|
roles: [
|
|
45
|
-
"Orchestrator",
|
|
46
66
|
"Repo Researcher",
|
|
47
67
|
"Backend Engineer",
|
|
48
68
|
"Test Engineer",
|
|
49
69
|
"Critic Reviewer",
|
|
50
70
|
],
|
|
71
|
+
orchestratorRequired: false, // clear scope, single-domain — Orchestrator is overhead
|
|
51
72
|
optionalRoles: ["Frontend Developer", "Performance Engineer"],
|
|
52
73
|
chainOrder: "Repo Researcher → Backend Engineer → Test Engineer",
|
|
53
74
|
requiredArtifacts: ["repo map / diagnosis", "fix implementation", "regression tests", "verdict"],
|
|
54
75
|
stopConditions: [
|
|
55
|
-
"Repo Researcher cannot reproduce → escalate to
|
|
76
|
+
"Repo Researcher cannot reproduce → escalate to user",
|
|
56
77
|
"Fix introduces new failures → loop back to Backend Engineer",
|
|
57
78
|
],
|
|
58
|
-
escalationOwner: "
|
|
79
|
+
escalationOwner: "Critic Reviewer",
|
|
59
80
|
dispatchDefaults: { model: "sonnet", maxTurns: 20, maxBudgetUsd: 3.0 },
|
|
60
|
-
trialEvidence: "G2 (Engineering), G7 (Repo Researcher)
|
|
81
|
+
trialEvidence: "G2 (Engineering), G7 (Repo Researcher), I-2 (shipped real fix). Pack comparison: free routing wins (Orchestrator overhead).",
|
|
82
|
+
mismatchGuards: [
|
|
83
|
+
{ notForSignals: ["launch", "announce", "release notes"], suggestInstead: "launch", reason: "This is launch work, not a bugfix" },
|
|
84
|
+
{ notForSignals: ["research", "should we", "tradeoff", "strategy"], suggestInstead: "research", reason: "This is a research/strategy question, not a bug to fix" },
|
|
85
|
+
],
|
|
61
86
|
},
|
|
62
87
|
|
|
63
88
|
// ── Security Review ───────────────────────────────────────────────────────
|
|
@@ -65,57 +90,66 @@ export const TEAM_PACKS = {
|
|
|
65
90
|
name: "Security Review",
|
|
66
91
|
description: "Threat model → code review → dependency audit → verdict",
|
|
67
92
|
roles: [
|
|
68
|
-
"Orchestrator",
|
|
69
93
|
"Security Reviewer",
|
|
70
94
|
"Dependency Auditor",
|
|
71
95
|
"Critic Reviewer",
|
|
72
96
|
],
|
|
97
|
+
orchestratorRequired: false, // single-domain, clear scope
|
|
73
98
|
optionalRoles: ["Backend Engineer", "Test Engineer"],
|
|
74
99
|
chainOrder: "Security Reviewer → Dependency Auditor",
|
|
75
100
|
requiredArtifacts: ["threat model", "code review findings", "dependency audit", "verdict"],
|
|
76
101
|
stopConditions: [
|
|
77
|
-
"Critical vulnerability found → immediate escalation to
|
|
102
|
+
"Critical vulnerability found → immediate escalation to user",
|
|
78
103
|
"Dependency with known CVE → flag for Engineering",
|
|
79
104
|
],
|
|
80
|
-
escalationOwner: "
|
|
105
|
+
escalationOwner: "Security Reviewer",
|
|
81
106
|
dispatchDefaults: { model: "sonnet", maxTurns: 25, maxBudgetUsd: 4.0 },
|
|
82
|
-
trialEvidence: "G6 (Security Reviewer, Dependency Auditor) — 2/2 gold-task passes",
|
|
107
|
+
trialEvidence: "G6 (Security Reviewer, Dependency Auditor) — 2/2 gold-task passes. I-3 Critic found 3 gaps prior roles missed.",
|
|
108
|
+
mismatchGuards: [
|
|
109
|
+
{ notForSignals: ["documentation", "handbook", "restructure", "navigation"], suggestInstead: "docs", reason: "This is docs/structure work, not a security review" },
|
|
110
|
+
{ notForSignals: ["feature", "implement", "build", "add command"], suggestInstead: "feature", reason: "This is feature work, not a security review" },
|
|
111
|
+
],
|
|
83
112
|
},
|
|
84
113
|
|
|
85
114
|
// ── Docs / Handbook / Release ─────────────────────────────────────────────
|
|
86
115
|
docs: {
|
|
87
|
-
name: "Docs / Handbook
|
|
88
|
-
description: "
|
|
116
|
+
name: "Docs / Handbook",
|
|
117
|
+
description: "Triage → synthesize → structure → write → metadata → review",
|
|
89
118
|
roles: [
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"Deployment Verifier",
|
|
119
|
+
"Support Triage Lead", // interpret raw input (triage reports, issue lists, feedback)
|
|
120
|
+
"Feedback Synthesizer", // cluster and theme the interpreted input
|
|
121
|
+
"Docs Architect", // structure and write the docs
|
|
122
|
+
"Metadata Curator", // verify metadata alignment
|
|
95
123
|
"Critic Reviewer",
|
|
96
124
|
],
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
125
|
+
orchestratorRequired: false,
|
|
126
|
+
optionalRoles: ["Repo Translator", "Brand Guardian", "Release Engineer", "Deployment Verifier"],
|
|
127
|
+
chainOrder: "Support Triage Lead → Feedback Synthesizer → Docs Architect → Metadata Curator",
|
|
128
|
+
requiredArtifacts: ["classified input", "synthesized themes", "docs structure", "metadata audit", "verdict"],
|
|
100
129
|
stopConditions: [
|
|
130
|
+
"Support Triage Lead finds input data ambiguous → request clarification",
|
|
131
|
+
"Feedback Synthesizer finds insufficient signal → escalate to user",
|
|
101
132
|
"Docs Architect finds product direction unclear → escalate to Product Strategist",
|
|
102
|
-
"Deployment Verifier finds broken artifacts → loop back to Release Engineer",
|
|
103
133
|
],
|
|
104
|
-
escalationOwner: "
|
|
134
|
+
escalationOwner: "Docs Architect",
|
|
105
135
|
dispatchDefaults: { model: "sonnet", maxTurns: 25, maxBudgetUsd: 4.0 },
|
|
106
|
-
trialEvidence: "G4 (Docs Architect), G7 (Treatment
|
|
136
|
+
trialEvidence: "G4 (Docs Architect), G7 (Treatment), I-4 (shipped page). Calibrated: Support Triage Lead + Feedback Synthesizer upstream. Release/Deploy moved to optional (overhead for docs-only tasks).",
|
|
137
|
+
mismatchGuards: [
|
|
138
|
+
{ notForSignals: ["research", "should we", "competitive", "strategy"], suggestInstead: "research", reason: "This is a research/strategy question — decide before documenting" },
|
|
139
|
+
{ notForSignals: ["security", "threat", "vulnerability"], suggestInstead: "security", reason: "This is a security review, not docs work" },
|
|
140
|
+
],
|
|
107
141
|
},
|
|
108
142
|
|
|
109
143
|
// ── Launch / Messaging ────────────────────────────────────────────────────
|
|
110
144
|
launch: {
|
|
111
145
|
name: "Launch / Messaging",
|
|
112
|
-
description: "Plan launch → write copy
|
|
146
|
+
description: "Plan launch → write copy. Hard pipeline: Strategist → Copywriter.",
|
|
113
147
|
roles: [
|
|
114
|
-
"Orchestrator",
|
|
115
148
|
"Launch Strategist",
|
|
116
149
|
"Launch Copywriter",
|
|
117
150
|
"Critic Reviewer",
|
|
118
151
|
],
|
|
152
|
+
orchestratorRequired: false, // smallest pack, hard pipeline, no decomposition needed
|
|
119
153
|
optionalRoles: ["Content Strategist", "Community Manager"],
|
|
120
154
|
chainOrder: "Launch Strategist → Launch Copywriter",
|
|
121
155
|
requiredArtifacts: ["launch plan", "release copy", "verdict"],
|
|
@@ -123,42 +157,51 @@ export const TEAM_PACKS = {
|
|
|
123
157
|
"Launch Strategist finds no proof assets → delay launch",
|
|
124
158
|
"Launch Copywriter finds product claims unverifiable → escalate to Product Strategist",
|
|
125
159
|
],
|
|
126
|
-
escalationOwner: "
|
|
160
|
+
escalationOwner: "Launch Strategist",
|
|
127
161
|
dispatchDefaults: { model: "sonnet", maxTurns: 20, maxBudgetUsd: 3.0 },
|
|
128
|
-
trialEvidence: "G3 (
|
|
162
|
+
trialEvidence: "G3 (pipeline proven), I-5 (v1.1.0 launch, Accept). Pack comparison: tie/marginal win. TRUE DEFAULT.",
|
|
163
|
+
mismatchGuards: [
|
|
164
|
+
{ notForSignals: ["bug", "fix", "crash", "broken", "error"], suggestInstead: "bugfix", reason: "This is a bug to fix, not a launch to plan" },
|
|
165
|
+
{ notForSignals: ["implement", "build", "add command", "new feature"], suggestInstead: "feature", reason: "This is feature work — build first, launch second" },
|
|
166
|
+
],
|
|
129
167
|
},
|
|
130
168
|
|
|
131
169
|
// ── Research / Strategy ───────────────────────────────────────────────────
|
|
132
170
|
research: {
|
|
133
171
|
name: "Research / Strategy",
|
|
134
|
-
description: "
|
|
172
|
+
description: "Frame decision → gather evidence → synthesize → recommend",
|
|
135
173
|
roles: [
|
|
136
|
-
"
|
|
174
|
+
"Product Strategist", // REORDERED: framing first, then research
|
|
137
175
|
"UX Researcher",
|
|
138
176
|
"Competitive Analyst",
|
|
139
177
|
"Feedback Synthesizer",
|
|
140
|
-
"Product Strategist",
|
|
141
178
|
"Critic Reviewer",
|
|
142
179
|
],
|
|
180
|
+
orchestratorRequired: false, // clear pipeline, Product Strategist frames
|
|
143
181
|
optionalRoles: ["Trend Researcher", "User Interview Synthesizer"],
|
|
144
|
-
chainOrder: "UX Researcher → Competitive Analyst → Feedback Synthesizer
|
|
145
|
-
requiredArtifacts: ["friction inventory", "competitive landscape", "signal synthesis", "
|
|
182
|
+
chainOrder: "Product Strategist → UX Researcher → Competitive Analyst → Feedback Synthesizer",
|
|
183
|
+
requiredArtifacts: ["decision frame", "friction inventory", "competitive landscape", "signal synthesis", "verdict"],
|
|
146
184
|
stopConditions: [
|
|
147
|
-
"
|
|
185
|
+
"Product Strategist finds the question too vague → request clarification",
|
|
186
|
+
"UX Researcher finds insufficient user data → escalate to Product Strategist",
|
|
148
187
|
"Competitive Analyst finds no comparable products → narrow scope",
|
|
149
188
|
],
|
|
150
|
-
escalationOwner: "
|
|
189
|
+
escalationOwner: "Product Strategist",
|
|
151
190
|
dispatchDefaults: { model: "sonnet", maxTurns: 25, maxBudgetUsd: 4.0 },
|
|
152
|
-
trialEvidence: "G8 (Research cluster), G9 (Growth/Product)
|
|
191
|
+
trialEvidence: "G8 (Research cluster), G9 (Growth/Product), I-6 (game dev decision). Calibrated: Product Strategist now opens (framing before research).",
|
|
192
|
+
mismatchGuards: [
|
|
193
|
+
{ notForSignals: ["implement", "build", "add command", "write code"], suggestInstead: "feature", reason: "This is implementation work, not research" },
|
|
194
|
+
{ notForSignals: ["bug", "fix", "crash", "broken"], suggestInstead: "bugfix", reason: "This is a bugfix, not a research question" },
|
|
195
|
+
],
|
|
153
196
|
},
|
|
154
197
|
|
|
155
198
|
// ── Treatment (repo polish) ───────────────────────────────────────────────
|
|
156
199
|
treatment: {
|
|
157
200
|
name: "Treatment (Repo Polish)",
|
|
158
|
-
description: "Full repo treatment: research → audit → docs → metadata → release → deploy → verify",
|
|
201
|
+
description: "Full repo treatment: research → security → audit → docs → metadata → release → deploy → verify",
|
|
159
202
|
roles: [
|
|
160
|
-
"Orchestrator",
|
|
161
203
|
"Repo Researcher",
|
|
204
|
+
"Security Reviewer", // ADDED: was optional, now default (pack comparison finding)
|
|
162
205
|
"Coverage Auditor",
|
|
163
206
|
"Docs Architect",
|
|
164
207
|
"Metadata Curator",
|
|
@@ -166,16 +209,22 @@ export const TEAM_PACKS = {
|
|
|
166
209
|
"Deployment Verifier",
|
|
167
210
|
"Critic Reviewer",
|
|
168
211
|
],
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
212
|
+
orchestratorRequired: false, // long but sequential — each role has a clear handoff
|
|
213
|
+
optionalRoles: ["Brand Guardian", "Repo Translator", "Dependency Auditor"],
|
|
214
|
+
chainOrder: "Repo Researcher → Security Reviewer → Coverage Auditor → Docs Architect → Metadata Curator → Release Engineer → Deployment Verifier",
|
|
215
|
+
requiredArtifacts: ["repo map", "security findings", "coverage audit", "docs", "metadata audit", "release", "deployment verification", "verdict"],
|
|
172
216
|
stopConditions: [
|
|
217
|
+
"Security Reviewer finds critical vulnerability → block release until resolved",
|
|
173
218
|
"Coverage Auditor finds false confidence → flag for Test Engineer",
|
|
174
219
|
"Deployment Verifier finds broken live artifacts → loop back to Release Engineer",
|
|
175
220
|
],
|
|
176
|
-
escalationOwner: "
|
|
221
|
+
escalationOwner: "Repo Researcher",
|
|
177
222
|
dispatchDefaults: { model: "sonnet", maxTurns: 30, maxBudgetUsd: 5.0 },
|
|
178
|
-
trialEvidence: "G6 (
|
|
223
|
+
trialEvidence: "G6-G7 (roles proven), I-7 (full chain, Accept-with-notes). Calibrated: Security Reviewer now default (was optional — pack comparison loss).",
|
|
224
|
+
mismatchGuards: [
|
|
225
|
+
{ notForSignals: ["launch", "announce", "release notes", "social", "messaging"], suggestInstead: "launch", reason: "This is launch/messaging work — Treatment audits repos, it doesn't write announcements" },
|
|
226
|
+
{ notForSignals: ["research", "should we", "competitive", "strategy"], suggestInstead: "research", reason: "This is a research/strategy question, not a repo treatment" },
|
|
227
|
+
],
|
|
179
228
|
},
|
|
180
229
|
};
|
|
181
230
|
|
|
@@ -193,9 +242,6 @@ const PACK_KEYWORDS = {
|
|
|
193
242
|
|
|
194
243
|
/**
|
|
195
244
|
* Suggest the best pack for a packet based on content analysis.
|
|
196
|
-
*
|
|
197
|
-
* @param {string} content - Packet markdown content
|
|
198
|
-
* @returns {{ pack: string, confidence: string, scores: Record<string, number> } | null}
|
|
199
245
|
*/
|
|
200
246
|
export function suggestPack(content) {
|
|
201
247
|
const lower = content.toLowerCase();
|
|
@@ -219,10 +265,52 @@ export function suggestPack(content) {
|
|
|
219
265
|
}
|
|
220
266
|
|
|
221
267
|
/**
|
|
222
|
-
*
|
|
268
|
+
* Check if a pack is a mismatch for the given content.
|
|
269
|
+
* Returns null if no mismatch, or the suggested alternative if mismatch detected.
|
|
270
|
+
*
|
|
271
|
+
* @param {string} packName
|
|
272
|
+
* @param {string} content - Packet content
|
|
273
|
+
* @returns {{ suggestInstead: string, reason: string } | null}
|
|
274
|
+
*/
|
|
275
|
+
export function checkPackMismatch(packName, content) {
|
|
276
|
+
const pack = TEAM_PACKS[packName];
|
|
277
|
+
if (!pack || !pack.mismatchGuards) return null;
|
|
278
|
+
|
|
279
|
+
const lower = content.toLowerCase();
|
|
280
|
+
for (const guard of pack.mismatchGuards) {
|
|
281
|
+
const triggered = guard.notForSignals.some(signal => lower.includes(signal));
|
|
282
|
+
if (triggered) {
|
|
283
|
+
return { suggestInstead: guard.suggestInstead, reason: guard.reason };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get a pack's effective roles (with conditional Orchestrator).
|
|
223
291
|
*
|
|
224
|
-
* @param {string}
|
|
225
|
-
* @
|
|
292
|
+
* @param {string} packName
|
|
293
|
+
* @param {boolean} [forceOrchestrator=false]
|
|
294
|
+
* @returns {string[] | null}
|
|
295
|
+
*/
|
|
296
|
+
export function getPackRoles(packName, forceOrchestrator = false) {
|
|
297
|
+
const pack = TEAM_PACKS[packName];
|
|
298
|
+
if (!pack) return null;
|
|
299
|
+
|
|
300
|
+
const roles = [...pack.roles];
|
|
301
|
+
// Add Orchestrator only if the pack requires it or forced
|
|
302
|
+
if ((pack.orchestratorRequired || forceOrchestrator) && !roles.includes("Orchestrator")) {
|
|
303
|
+
roles.unshift("Orchestrator");
|
|
304
|
+
}
|
|
305
|
+
// Remove Orchestrator if pack doesn't require it and not forced
|
|
306
|
+
if (!pack.orchestratorRequired && !forceOrchestrator && roles[0] === "Orchestrator") {
|
|
307
|
+
roles.shift();
|
|
308
|
+
}
|
|
309
|
+
return roles;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get a pack by name.
|
|
226
314
|
*/
|
|
227
315
|
export function getPack(name) {
|
|
228
316
|
return TEAM_PACKS[name] || null;
|
|
@@ -230,8 +318,6 @@ export function getPack(name) {
|
|
|
230
318
|
|
|
231
319
|
/**
|
|
232
320
|
* List all available packs.
|
|
233
|
-
*
|
|
234
|
-
* @returns {Array<{name: string, description: string, roleCount: number}>}
|
|
235
321
|
*/
|
|
236
322
|
export function listPacks() {
|
|
237
323
|
return Object.entries(TEAM_PACKS).map(([key, pack]) => ({
|
|
@@ -240,5 +326,6 @@ export function listPacks() {
|
|
|
240
326
|
description: pack.description,
|
|
241
327
|
roleCount: pack.roles.length,
|
|
242
328
|
optionalCount: pack.optionalRoles.length,
|
|
329
|
+
orchestratorRequired: pack.orchestratorRequired,
|
|
243
330
|
}));
|
|
244
331
|
}
|
package/src/route.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { resolve, dirname } from "node:path";
|
|
|
3
3
|
import { readFileSafe } from "./fs-utils.mjs";
|
|
4
4
|
import { detectConflicts } from "./conflicts.mjs";
|
|
5
5
|
import { resolveConflict, resolveSplit, formatEscalation } from "./escalation.mjs";
|
|
6
|
+
import { suggestPack, getPack, checkPackMismatch, getPackRoles } from "./packs.mjs";
|
|
6
7
|
|
|
7
8
|
// ── Full 32-Role Catalog ─────────────────────────────────────────────────────
|
|
8
9
|
// Every role in the OS is scoreable. Keywords from routing-rules.md + contracts.
|
|
@@ -407,6 +408,8 @@ const HANDOFF_HINTS = {
|
|
|
407
408
|
|
|
408
409
|
export async function routeCommand(args) {
|
|
409
410
|
const verbose = args.includes("--verbose");
|
|
411
|
+
const packFlag = args.find(a => a.startsWith("--pack="));
|
|
412
|
+
const requestedPack = packFlag ? packFlag.split("=")[1] : null;
|
|
410
413
|
const packetFile = args.find(a => !a.startsWith("--"));
|
|
411
414
|
|
|
412
415
|
if (!packetFile) {
|
|
@@ -454,7 +457,39 @@ export async function routeCommand(args) {
|
|
|
454
457
|
console.log(`\nroleos route — ${packetFile}\n`);
|
|
455
458
|
console.log(`Detected type: ${type}`);
|
|
456
459
|
if (deliverableType) console.log(`Deliverable type: ${deliverableType}`);
|
|
457
|
-
|
|
460
|
+
|
|
461
|
+
// ── Pack suggestion / selection ──
|
|
462
|
+
const packSuggestion = suggestPack(content);
|
|
463
|
+
if (requestedPack) {
|
|
464
|
+
const pack = getPack(requestedPack);
|
|
465
|
+
if (!pack) {
|
|
466
|
+
console.log(`\n⚠ Unknown pack: "${requestedPack}". Falling back to free routing.`);
|
|
467
|
+
} else {
|
|
468
|
+
const mismatch = checkPackMismatch(requestedPack, content);
|
|
469
|
+
if (mismatch) {
|
|
470
|
+
console.log(`\n⚠ Pack mismatch detected: ${mismatch.reason}`);
|
|
471
|
+
console.log(` → Suggested alternative: roleos route --pack=${mismatch.suggestInstead} ${packetFile}`);
|
|
472
|
+
console.log(` Falling back to free routing for this task.`);
|
|
473
|
+
} else {
|
|
474
|
+
const packRoles = getPackRoles(requestedPack);
|
|
475
|
+
console.log(`\nUsing pack: ${pack.name} (${packRoles.length} roles)`);
|
|
476
|
+
console.log(`Chain: ${pack.chainOrder}`);
|
|
477
|
+
console.log(`Roles: ${packRoles.join(" → ")}`);
|
|
478
|
+
console.log(`\nPack artifacts: ${pack.requiredArtifacts.join(", ")}`);
|
|
479
|
+
console.log(`Stop conditions:`);
|
|
480
|
+
for (const sc of pack.stopConditions) {
|
|
481
|
+
console.log(` • ${sc}`);
|
|
482
|
+
}
|
|
483
|
+
console.log(`\nNext: assign roles and begin execution.`);
|
|
484
|
+
return; // Pack selected — skip free routing output
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
} else if (packSuggestion && packSuggestion.confidence !== "low") {
|
|
488
|
+
console.log(`\nSuggested pack: ${packSuggestion.pack} (${packSuggestion.confidence} confidence)`);
|
|
489
|
+
console.log(` → Use: roleos route --pack=${packSuggestion.pack} ${packetFile}`);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
console.log(`\nRouting confidence: ${confidence}`);
|
|
458
493
|
|
|
459
494
|
if (confidence === "low") {
|
|
460
495
|
console.log(` ↳ Few strong role signals detected. Consider reviewing the packet for missing context.`);
|