create-byan-agent 2.42.0 → 2.45.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 +118 -0
- package/install/bin/byan-kanban.js +1 -1
- package/install/bin/create-byan-agent-v2.js +111 -111
- package/install/lib/byan-leantime-integration.js +2 -2
- package/install/lib/byan-web-integration.js +5 -5
- package/install/lib/claude-native-setup.js +11 -11
- package/install/lib/codex-native-setup.js +3 -3
- package/install/lib/exchange/agent-packager.js +1 -1
- package/install/lib/mcp-extensions/gdrive.js +5 -5
- package/install/lib/mcp-extensions/index.js +5 -5
- package/install/lib/phase2-chat.js +21 -21
- package/install/lib/platforms/claude-code.js +2 -2
- package/install/lib/project-agents-generator.js +4 -4
- package/install/lib/staging-consent.js +1 -1
- package/install/lib/subagent-generator.js +2 -3
- package/install/lib/utils/logger.js +4 -4
- package/install/lib/utils/node-detector.js +1 -1
- package/install/lib/yanstaller/agent-launcher.js +1 -1
- package/install/lib/yanstaller/index.js +11 -116
- package/install/lib/yanstaller/platform-selector.js +11 -11
- package/install/src/byan-v2/dispatcher/task-router.js +1 -1
- package/install/src/index.js +1 -1
- package/install/src/webui/api.js +0 -13
- package/install/src/webui/chat/bridge.js +1 -1
- package/install/src/webui/chat/cli-detector.js +1 -1
- package/install/templates/.claude/CLAUDE.md +1 -0
- package/install/templates/.claude/hooks/inject-voice-anchor.js +20 -1
- package/install/templates/.claude/hooks/lib/plain-language.js +155 -0
- package/install/templates/.claude/hooks/plain-language-check.js +53 -0
- package/install/templates/.claude/rules/native-workflows.md +22 -14
- package/install/templates/.claude/rules/plain-language.md +73 -0
- package/install/templates/.claude/settings.json +4 -0
- package/install/templates/_byan/COMPLETION-REPORT.md +0 -1
- package/install/templates/_byan/agent/byan/byan-tao.md +12 -0
- package/install/templates/_byan/core/activation/soul-activation.md +3 -3
- package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-lint-workflows.js +6 -3
- package/install/templates/_byan/mcp/byan-mcp-server/lib/native-tiers.js +35 -17
- package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-lint.js +38 -0
- package/install/templates/_byan/mcp/byan-mcp-server/server.js +37 -0
- package/install/templates/_byan/worker/workers.md +1 -1
- package/install/templates/_byan/workflow/simple/byan/data/mantras.yaml +15 -4
- package/package.json +1 -1
- package/src/byan-v2/dispatcher/task-router.js +1 -1
- package/src/byan-v2/lib/layout-resolver.js +3 -6
- package/install/lib/yanstaller/installer.js +0 -138
- package/install/lib/yanstaller/interviewer.js +0 -88
- package/install/lib/yanstaller/recommender.js +0 -102
- package/install/lib/yanstaller/troubleshooter.js +0 -89
- package/install/lib/yanstaller/validator.js +0 -198
- package/install/lib/yanstaller/wizard.js +0 -109
- package/install/src/byan-v2/dispatcher/task-tool-interface-mock.js +0 -134
- package/install/src/byan-v2/dispatcher/task-tool-interface.js +0 -123
- package/install/templates/_bmad/bmb/agents/agent-builder.md +0 -59
- package/install/templates/_bmad/bmb/agents/byan-test.md +0 -116
- package/install/templates/_bmad/bmb/agents/byan.md +0 -215
- package/install/templates/_bmad/bmb/agents/marc.md +0 -303
- package/install/templates/_bmad/bmb/agents/module-builder.md +0 -60
- package/install/templates/_bmad/bmb/agents/patnote.md +0 -495
- package/install/templates/_bmad/bmb/agents/rachid.md +0 -184
- package/install/templates/_bmad/bmb/agents/workflow-builder.md +0 -61
- package/install/templates/_bmad/bmb/workflows/byan/data/mantras.yaml +0 -272
- package/install/templates/_bmad/bmb/workflows/byan/data/templates.yaml +0 -59
- package/install/templates/_bmad/bmb/workflows/byan/delete-agent-workflow.md +0 -657
- package/install/templates/_bmad/bmb/workflows/byan/edit-agent-workflow.md +0 -688
- package/install/templates/_bmad/bmb/workflows/byan/interview-workflow.md +0 -753
- package/install/templates/_bmad/bmb/workflows/byan/quick-create-workflow.md +0 -450
- package/install/templates/_bmad/bmb/workflows/byan/templates/base-agent-template.md +0 -79
- package/install/templates/_bmad/bmb/workflows/byan/validate-agent-workflow.md +0 -676
- package/install/templates/_bmad/core/agents/carmack.md +0 -238
- package/src/byan-v2/dispatcher/task-tool-interface-mock.js +0 -134
- package/src/byan-v2/dispatcher/task-tool-interface.js +0 -123
|
@@ -26,10 +26,13 @@ export const TIERS = Object.freeze({ CHEAP: 'cheap', BALANCED: 'balanced', DEEP:
|
|
|
26
26
|
//
|
|
27
27
|
// deep MUST be null. Omitting opts.model lets the leaf inherit whatever model the
|
|
28
28
|
// session runs (Opus by default, but Sonnet if the user chose Sonnet). We never
|
|
29
|
-
// PIN UP
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
29
|
+
// PIN UP (nothing is ever forced to opus). cheap/balanced carry a value:
|
|
30
|
+
// exploration leaves get cheap (haiku); explicit mech- leaves AND analysis leaves
|
|
31
|
+
// get balanced (sonnet). Analysis routing to balanced is a deliberate downgrade of
|
|
32
|
+
// the session model for judgment-but-not-frontier work (score/rank/assess/nfr/
|
|
33
|
+
// coverage/recommend) — the heaviest workflow prompts, which rarely need the top
|
|
34
|
+
// model; the 'deep-' label prefix opts a hard analysis leaf back to the session
|
|
35
|
+
// model. VERIFICATION and IMPLEMENTATION still inherit (deep).
|
|
33
36
|
//
|
|
34
37
|
// Values are the harness model-selection aliases (same set as the Agent tool:
|
|
35
38
|
// 'haiku' | 'sonnet' | 'opus'). They are version-independent. If a future
|
|
@@ -37,11 +40,14 @@ export const TIERS = Object.freeze({ CHEAP: 'cheap', BALANCED: 'balanced', DEEP:
|
|
|
37
40
|
// flags every script literal that drifts from it, so the fan-out stays bounded.
|
|
38
41
|
export const TIER_MODEL = Object.freeze({ cheap: 'haiku', balanced: 'sonnet', deep: null });
|
|
39
42
|
|
|
40
|
-
// Leaf task-type taxonomy. EXPLORATION and MECHANICAL
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
// parses, schema matches, lint passes,
|
|
44
|
-
//
|
|
43
|
+
// Leaf task-type taxonomy. EXPLORATION (cheap) and MECHANICAL + ANALYSIS
|
|
44
|
+
// (balanced) are the downgrade classes; VERIFICATION and IMPLEMENTATION stay
|
|
45
|
+
// protected (deep, inherit the session model). MECHANICAL is verification whose
|
|
46
|
+
// outcome is binary and judgment-free (JSON parses, schema matches, lint passes,
|
|
47
|
+
// a test suite exits 0). ANALYSIS bears judgment (score/rank/assess/design/nfr/
|
|
48
|
+
// coverage) but rarely the frontier reasoning that needs the top model, so it
|
|
49
|
+
// auto-routes to balanced (sonnet) — escapable per-leaf via the 'deep-' prefix.
|
|
50
|
+
// Semantic/adversarial VERIFICATION stays deep (a wrong check corrupts silently).
|
|
45
51
|
export const LEAF_TYPES = Object.freeze({
|
|
46
52
|
EXPLORATION: 'exploration',
|
|
47
53
|
MECHANICAL: 'mechanical',
|
|
@@ -57,6 +63,14 @@ export const LEAF_TYPES = Object.freeze({
|
|
|
57
63
|
// script to it (a mech- leaf must carry model: 'sonnet', nothing else).
|
|
58
64
|
export const MECHANICAL_PREFIX = 'mech-';
|
|
59
65
|
|
|
66
|
+
// DEEP_PREFIX is the ANALYSIS escape hatch. Analysis auto-routes to balanced
|
|
67
|
+
// (sonnet); a 'deep-' label prefix opts a specific analysis leaf back OUT of that
|
|
68
|
+
// downgrade and onto the protected deep default (inherit the session model), for
|
|
69
|
+
// genuinely frontier reasoning. Parallel to MECHANICAL_PREFIX: an explicit
|
|
70
|
+
// authoring act the linter honours. 'deep-assess-architecture' rides the session
|
|
71
|
+
// model; 'assess-architecture' rides sonnet. The prefix wins over keyword class.
|
|
72
|
+
export const DEEP_PREFIX = 'deep-';
|
|
73
|
+
|
|
60
74
|
// Label keyword sets, matched as substrings on the leaf LABEL (not the prompt —
|
|
61
75
|
// see classifyLeaf). Protected sets are checked first so any protected signal
|
|
62
76
|
// beats an exploration signal (conservative: when in doubt, do not downgrade).
|
|
@@ -66,7 +80,7 @@ export const MECHANICAL_PREFIX = 'mech-';
|
|
|
66
80
|
// check/review/gate/audit/assert/lint; a leaf that runs tests is labelled
|
|
67
81
|
// 'verify-*' in practice.
|
|
68
82
|
const VERIFICATION_KEYWORDS = ['verify', 'validate', 'check', 'assert', 'gate', 'lint', 'audit', 'review'];
|
|
69
|
-
const ANALYSIS_KEYWORDS = ['analy', 'design', 'architect', 'assess', 'evaluate', 'strategy', 'risk', 'nfr', 'recommend', 'judge', 'score', 'coverage'];
|
|
83
|
+
const ANALYSIS_KEYWORDS = ['analy', 'design', 'architect', 'assess', 'evaluate', 'strategy', 'risk', 'nfr', 'recommend', 'judge', 'score', 'coverage', 'synthes'];
|
|
70
84
|
const IMPLEMENTATION_KEYWORDS = ['implement', 'build', 'write', 'generate', 'create', 'dev', 'rgr', 'refactor', 'fix', 'scaffold', 'save', 'optimize', 'aggregate', 'report', 'present', 'plan', 'map', 'select', 'subprocess', 'sub-'];
|
|
71
85
|
const EXPLORATION_KEYWORDS = ['load', 'read', 'scan', 'list', 'parse', 'detect', 'discover', 'fetch', 'lookup', 'source-tree', 'mode-detection'];
|
|
72
86
|
|
|
@@ -85,9 +99,11 @@ function matchesAny(text, keywords) {
|
|
|
85
99
|
export function classifyLeaf(leaf) {
|
|
86
100
|
const label = String((leaf && leaf.label) || '').toLowerCase();
|
|
87
101
|
if (!label) return LEAF_TYPES.IMPLEMENTATION;
|
|
88
|
-
// Explicit opt-in
|
|
89
|
-
//
|
|
102
|
+
// Explicit opt-in prefixes beat every keyword class (the author's declared
|
|
103
|
+
// intent is the signal): mech- -> balanced; deep- -> the protected deep default
|
|
104
|
+
// (the analysis escape hatch, classified as the deep IMPLEMENTATION bucket).
|
|
90
105
|
if (label.startsWith(MECHANICAL_PREFIX)) return LEAF_TYPES.MECHANICAL;
|
|
106
|
+
if (label.startsWith(DEEP_PREFIX)) return LEAF_TYPES.IMPLEMENTATION;
|
|
91
107
|
if (matchesAny(label, VERIFICATION_KEYWORDS)) return LEAF_TYPES.VERIFICATION;
|
|
92
108
|
if (matchesAny(label, ANALYSIS_KEYWORDS)) return LEAF_TYPES.ANALYSIS;
|
|
93
109
|
if (matchesAny(label, IMPLEMENTATION_KEYWORDS)) return LEAF_TYPES.IMPLEMENTATION;
|
|
@@ -95,14 +111,16 @@ export function classifyLeaf(leaf) {
|
|
|
95
111
|
return LEAF_TYPES.IMPLEMENTATION;
|
|
96
112
|
}
|
|
97
113
|
|
|
98
|
-
// tierFor(taskType) -> a TIERS value.
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
114
|
+
// tierFor(taskType) -> a TIERS value. Auto-routing: EXPLORATION -> cheap (haiku);
|
|
115
|
+
// MECHANICAL and ANALYSIS -> balanced (sonnet); VERIFICATION and IMPLEMENTATION
|
|
116
|
+
// stay deep (inherit the session model). MECHANICAL reaches balanced only through
|
|
117
|
+
// the explicit mech- opt-in; ANALYSIS reaches it by keyword classification (it is
|
|
118
|
+
// the judgment-but-not-frontier class), with the deep- prefix as the per-leaf
|
|
119
|
+
// escape back to deep. No path ever lands opus (no pin-up).
|
|
103
120
|
export function tierFor(taskType) {
|
|
104
121
|
if (taskType === LEAF_TYPES.EXPLORATION) return TIERS.CHEAP;
|
|
105
122
|
if (taskType === LEAF_TYPES.MECHANICAL) return TIERS.BALANCED;
|
|
123
|
+
if (taskType === LEAF_TYPES.ANALYSIS) return TIERS.BALANCED;
|
|
106
124
|
return TIERS.DEEP;
|
|
107
125
|
}
|
|
108
126
|
|
|
@@ -181,6 +181,18 @@ export function modelRoutingViolations(src) {
|
|
|
181
181
|
}
|
|
182
182
|
continue;
|
|
183
183
|
}
|
|
184
|
+
// ANALYSIS floors at balanced (sonnet), like MECHANICAL: sonnet is its tier,
|
|
185
|
+
// haiku sits below it. Analysis auto-routes to sonnet (tierFor); a 'deep-'
|
|
186
|
+
// labelled analysis classifies as IMPLEMENTATION and never reaches here.
|
|
187
|
+
if (cls === LEAF_TYPES.ANALYSIS) {
|
|
188
|
+
if (model !== TIER_MODEL.balanced) {
|
|
189
|
+
out.push({
|
|
190
|
+
id: 'analysis-below-tier',
|
|
191
|
+
msg: `analysis leaf '${label}' carries '${model}' but the analysis tier is '${TIER_MODEL.balanced}' (sonnet); haiku sits below it — prefix the label 'deep-' to keep a hard analysis on the session model instead`,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
184
196
|
out.push({
|
|
185
197
|
id: 'protected-leaf-downgraded',
|
|
186
198
|
msg: `leaf '${label}' is protected (${cls}) but carries downgrade model '${model}'; only exploration (read/load/parse/detect) and explicit mech- leaves may downgrade (STRICT-2 No Downgrade)`,
|
|
@@ -274,6 +286,32 @@ export function untieredExplorationViolations(src) {
|
|
|
274
286
|
return out;
|
|
275
287
|
}
|
|
276
288
|
|
|
289
|
+
// The ANALYSIS half of the same non-blocking advisory. An analysis-labelled leaf
|
|
290
|
+
// that pins no downgrade model runs on the session model (Opus, esp. under a
|
|
291
|
+
// high-effort session) for judgment-but-not-frontier work — the single biggest
|
|
292
|
+
// source of the all-Opus workflow pattern. Surfaces 'add model: sonnet' (or the
|
|
293
|
+
// 'deep-' prefix to keep it deep on purpose). Same permissive-classifier caveat
|
|
294
|
+
// as exploration, so it ships as ADVISORY, not a hard contract rule: the human
|
|
295
|
+
// owns whether a given analysis leaf is truly frontier-hard.
|
|
296
|
+
export function untieredAnalysisViolations(src) {
|
|
297
|
+
const code = stripComments(src);
|
|
298
|
+
const out = [];
|
|
299
|
+
let m;
|
|
300
|
+
LABEL_RE.lastIndex = 0;
|
|
301
|
+
while ((m = LABEL_RE.exec(code))) {
|
|
302
|
+
const label = m[2];
|
|
303
|
+
if (classifyLeaf({ label }) !== LEAF_TYPES.ANALYSIS) continue;
|
|
304
|
+
const objText = sameOptsObjectText(code, m.index, m.index + m[0].length);
|
|
305
|
+
if (!objectHasDowngradeModel(objText)) {
|
|
306
|
+
out.push({
|
|
307
|
+
id: 'untiered-analysis',
|
|
308
|
+
msg: `analysis leaf '${label}' pins no downgrade model; add model: 'sonnet' so judgment-but-not-frontier analysis does not run on the session model (token waste), or prefix the label 'deep-' to keep it on the session model deliberately`,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
|
|
277
315
|
// Shared parsing primitive — every statically-labelled opts object with its
|
|
278
316
|
// order-independent model (or null). This is the ONE place that knows how to
|
|
279
317
|
// read agent() opts out of a script source; tier-script.js (the per-leaf
|
|
@@ -1004,6 +1004,27 @@ const tools = [
|
|
|
1004
1004
|
additionalProperties: false,
|
|
1005
1005
|
},
|
|
1006
1006
|
},
|
|
1007
|
+
// Selective RAG retrieval — returns the top-k most relevant knowledge bodies
|
|
1008
|
+
// VERBATIM (never truncated; negations/prohibitions are returned intact).
|
|
1009
|
+
// GET /api/projects/:projectId/knowledge/retrieve?q=...&k=10&tokenBudget=0
|
|
1010
|
+
// Backed by PG FTS (ts_rank) in prod, LIKE-degraded on SQLite (dev/tests).
|
|
1011
|
+
// Use this instead of knowledge_list when you only need a focused subset.
|
|
1012
|
+
{
|
|
1013
|
+
name: 'byan_api_knowledge_retrieve',
|
|
1014
|
+
description:
|
|
1015
|
+
'Retrieve the top-k most relevant knowledge entries for a query using full-text search (PG) or LIKE fallback (SQLite). Returns bodies VERBATIM — negations and prohibitions are never truncated. GET /api/projects/:projectId/knowledge/retrieve?q=...&k=10&tokenBudget=0. RBAC viewer required. projectId and q are required. Requires BYAN_API_TOKEN.',
|
|
1016
|
+
inputSchema: {
|
|
1017
|
+
type: 'object',
|
|
1018
|
+
properties: {
|
|
1019
|
+
projectId: { type: 'string', description: 'Project id (required — RBAC guard).' },
|
|
1020
|
+
q: { type: 'string', description: 'Search query (required).' },
|
|
1021
|
+
k: { type: 'number', description: 'Max number of results (default 10).' },
|
|
1022
|
+
tokenBudget: { type: 'number', description: 'Total token budget (0 = unlimited).' },
|
|
1023
|
+
},
|
|
1024
|
+
required: ['projectId', 'q'],
|
|
1025
|
+
additionalProperties: false,
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
1007
1028
|
|
|
1008
1029
|
// ─── Memory ───────────────────────────────────────────────────────────
|
|
1009
1030
|
// Route: GET /api/projects/:projectId/memory (RBAC viewer)
|
|
@@ -1437,6 +1458,7 @@ const REMOTE_SAFE_TOOLS = new Set([
|
|
|
1437
1458
|
'byan_api_workflow_runs_get',
|
|
1438
1459
|
'byan_api_knowledge_list',
|
|
1439
1460
|
'byan_api_knowledge_get',
|
|
1461
|
+
'byan_api_knowledge_retrieve',
|
|
1440
1462
|
'byan_api_memory_list',
|
|
1441
1463
|
'byan_api_memory_search',
|
|
1442
1464
|
'byan_api_custom_agents_list',
|
|
@@ -1982,6 +2004,21 @@ export function createByanServer({ token, remoteOnly = false } = {}) {
|
|
|
1982
2004
|
return { content: [{ type: 'text', text: JSON.stringify(body, null, 2) }] };
|
|
1983
2005
|
}
|
|
1984
2006
|
|
|
2007
|
+
if (name === 'byan_api_knowledge_retrieve') {
|
|
2008
|
+
requireToken();
|
|
2009
|
+
if (!args.projectId) throw new Error('projectId is required (RBAC: knowledge is project-scoped).');
|
|
2010
|
+
if (!args.q || String(args.q).trim() === '') throw new Error('q (query) is required.');
|
|
2011
|
+
const qs = buildQuery({
|
|
2012
|
+
q: args.q,
|
|
2013
|
+
k: args.k,
|
|
2014
|
+
tokenBudget: args.tokenBudget,
|
|
2015
|
+
});
|
|
2016
|
+
const body = await apiRequest(
|
|
2017
|
+
`/api/projects/${encodeURIComponent(args.projectId)}/knowledge/retrieve${qs}`
|
|
2018
|
+
);
|
|
2019
|
+
return { content: [{ type: 'text', text: JSON.stringify(body, null, 2) }] };
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1985
2022
|
if (name === 'byan_api_memory_list') {
|
|
1986
2023
|
requireToken();
|
|
1987
2024
|
if (!args.projectId) throw new Error('projectId is required (RBAC: memory is project-scoped).');
|
|
@@ -496,7 +496,7 @@ src/
|
|
|
496
496
|
- **Worker Pool Implementation:** `src/core/worker-pool/worker-pool.js`
|
|
497
497
|
- **Dispatcher Logic:** `src/byan-v2/dispatcher/`
|
|
498
498
|
- **Launcher Workers:** `_byan/worker/launchers/README.md`
|
|
499
|
-
- **Architecture:** `
|
|
499
|
+
- **Architecture:** `_byan-output/conception/01-vision-et-principes.md`
|
|
500
500
|
|
|
501
501
|
---
|
|
502
502
|
|
|
@@ -262,11 +262,22 @@ agents_ia:
|
|
|
262
262
|
- "Contraintes légales/business"
|
|
263
263
|
- "TODOs avec ticket"
|
|
264
264
|
|
|
265
|
+
- id: "IA-26"
|
|
266
|
+
name: "Parler Réel"
|
|
267
|
+
category: "code_quality"
|
|
268
|
+
description: "Parler en français réel et cohérent à l'utilisateur : pas d'anglais gratuit, pas de jargon interne brut, pas de métaphore collée de travers. Un terme technique sans équivalent est gardé mais expliqué une fois. Le test : le lecteur comprend sans dictionnaire."
|
|
269
|
+
priority: "critique"
|
|
270
|
+
forbidden:
|
|
271
|
+
- "Anglais quand le français existe (cutoff, fallback, housekeeping)"
|
|
272
|
+
- "Jargon interne balancé brut (leaf, tier, downgrade, gate, inline, advisory)"
|
|
273
|
+
- "Métaphore collée de travers (forger un token)"
|
|
274
|
+
rule_file: ".claude/rules/plain-language.md"
|
|
275
|
+
|
|
265
276
|
metadata:
|
|
266
|
-
total_mantras:
|
|
277
|
+
total_mantras: 65
|
|
267
278
|
conception_count: 39
|
|
268
|
-
agents_ia_count:
|
|
269
|
-
version: "1.0.
|
|
270
|
-
last_updated: "2026-
|
|
279
|
+
agents_ia_count: 26
|
|
280
|
+
version: "1.0.1"
|
|
281
|
+
last_updated: "2026-07-15"
|
|
271
282
|
authors: ["Yan", "Carson"]
|
|
272
283
|
methodology: "Merise Agile + TDD"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-byan-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.45.0",
|
|
4
4
|
"description": "BYAN v2.8 - Intelligent AI agent creator with ELO trust system + scientific fact-check + Hermes universal dispatcher + native Claude Code integration (hooks, skills, MCP server). Multi-platform (Claude Code, Codex). Merise Agile + TDD + 71 Mantras. ~54% LLM cost savings.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
//
|
|
11
11
|
// This module is the single READ-side authority: "where does logical thing X
|
|
12
12
|
// physically live?". It answers Gen3-first, then falls back through the real
|
|
13
|
-
// on-disk Gen2 variants (flat AND per-module)
|
|
13
|
+
// on-disk Gen2 variants (flat AND per-module). Every
|
|
14
14
|
// lookup is a pure existence check — no writes, no side effects — so it is
|
|
15
15
|
// idempotent and additive: before migration it finds Gen2, after migration it
|
|
16
16
|
// finds Gen3, during migration either works. That is what lets the FS migrator
|
|
@@ -68,8 +68,7 @@ function locate(root, gen3rel, gen2rel) {
|
|
|
68
68
|
|
|
69
69
|
// Resolve an agent source file by name. Gen3 _byan/agent/<name>/<name>.md (or
|
|
70
70
|
// agent.md) first, then Gen2 flat _byan/agents/<name>.md, then Gen2 per-module
|
|
71
|
-
// _byan/<module>/agents/<name>.md,
|
|
72
|
-
// Returns {path, rel, layout} or null.
|
|
71
|
+
// _byan/<module>/agents/<name>.md. Returns {path, rel, layout} or null.
|
|
73
72
|
function resolveAgent(name, opts = {}) {
|
|
74
73
|
const root = resolveProjectRoot(opts.projectRoot);
|
|
75
74
|
const candidates = [
|
|
@@ -78,7 +77,6 @@ function resolveAgent(name, opts = {}) {
|
|
|
78
77
|
{ rel: `_byan/agents/${name}.md`, layout: 'gen2-flat' },
|
|
79
78
|
];
|
|
80
79
|
for (const m of MODULES) candidates.push({ rel: `_byan/${m}/agents/${name}.md`, layout: 'gen2-module' });
|
|
81
|
-
for (const m of MODULES) candidates.push({ rel: `_bmad/${m}/agents/${name}.md`, layout: 'gen1' });
|
|
82
80
|
return firstExisting(root, candidates);
|
|
83
81
|
}
|
|
84
82
|
|
|
@@ -95,7 +93,6 @@ function agentDirs(opts = {}) {
|
|
|
95
93
|
push('_byan/agent', 'gen3', true);
|
|
96
94
|
push('_byan/agents', 'gen2-flat', false);
|
|
97
95
|
for (const m of MODULES) push(`_byan/${m}/agents`, 'gen2-module', false);
|
|
98
|
-
for (const m of MODULES) push(`_bmad/${m}/agents`, 'gen1', false);
|
|
99
96
|
return out;
|
|
100
97
|
}
|
|
101
98
|
|
|
@@ -105,7 +102,7 @@ function isSoulSibling(fileName) {
|
|
|
105
102
|
|
|
106
103
|
// Discover all agents across layouts. Returns [{name, path, rel, layout}],
|
|
107
104
|
// deduped by name with the highest-priority directory winning (Gen3 > flat >
|
|
108
|
-
// module
|
|
105
|
+
// module). Soul/tao siblings are not agents and are skipped.
|
|
109
106
|
function listAgents(opts = {}) {
|
|
110
107
|
const root = resolveProjectRoot(opts.projectRoot);
|
|
111
108
|
const seen = new Map();
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* INSTALLER Module
|
|
3
|
-
*
|
|
4
|
-
* Installs BYAN agents across multiple platforms.
|
|
5
|
-
* Most complex module: 56h development.
|
|
6
|
-
*
|
|
7
|
-
* Phase 3: 56h development
|
|
8
|
-
*
|
|
9
|
-
* @module yanstaller/installer
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const fileUtils = require('../utils/file-utils');
|
|
14
|
-
const logger = require('../utils/logger');
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {Object} InstallConfig
|
|
18
|
-
* @property {string} mode - 'full' | 'minimal' | 'custom'
|
|
19
|
-
* @property {string[]} agents - Agent names to install
|
|
20
|
-
* @property {string} userName - User's name
|
|
21
|
-
* @property {string} language - 'Francais' | 'English'
|
|
22
|
-
* @property {string[]} targetPlatforms - Platforms to install on
|
|
23
|
-
* @property {string} outputFolder - Output folder path
|
|
24
|
-
* @property {string} projectRoot - Project root directory
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @typedef {Object} InstallResult
|
|
29
|
-
* @property {boolean} success
|
|
30
|
-
* @property {number} agentsInstalled - Number of agents installed
|
|
31
|
-
* @property {string[]} platforms - Platforms installed on
|
|
32
|
-
* @property {string[]} errors - Installation errors
|
|
33
|
-
* @property {number} duration - Duration in ms
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Install BYAN agents
|
|
38
|
-
*
|
|
39
|
-
* @param {InstallConfig} config - Installation configuration
|
|
40
|
-
* @returns {Promise<InstallResult>}
|
|
41
|
-
*/
|
|
42
|
-
async function install(config) {
|
|
43
|
-
const startTime = Date.now();
|
|
44
|
-
const errors = [];
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
// TODO: Implement installation
|
|
48
|
-
// 1. Create _bmad/ structure
|
|
49
|
-
// 2. Copy agent files from templates/
|
|
50
|
-
// 3. Generate platform-specific stubs
|
|
51
|
-
// 4. Create config files
|
|
52
|
-
|
|
53
|
-
logger.info(`Installing ${config.agents.length} agents...`);
|
|
54
|
-
|
|
55
|
-
// Placeholder
|
|
56
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
success: true,
|
|
60
|
-
agentsInstalled: config.agents.length,
|
|
61
|
-
platforms: config.targetPlatforms,
|
|
62
|
-
errors,
|
|
63
|
-
duration: Date.now() - startTime
|
|
64
|
-
};
|
|
65
|
-
} catch (error) {
|
|
66
|
-
errors.push(error.message);
|
|
67
|
-
return {
|
|
68
|
-
success: false,
|
|
69
|
-
agentsInstalled: 0,
|
|
70
|
-
platforms: [],
|
|
71
|
-
errors,
|
|
72
|
-
duration: Date.now() - startTime
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Create _bmad/ directory structure
|
|
79
|
-
*
|
|
80
|
-
* @param {string} projectRoot - Project root directory
|
|
81
|
-
* @returns {Promise<void>}
|
|
82
|
-
*/
|
|
83
|
-
async function createBmadStructure(projectRoot) {
|
|
84
|
-
// TODO: Create directories
|
|
85
|
-
// _bmad/
|
|
86
|
-
// ├── _config/
|
|
87
|
-
// ├── _memory/
|
|
88
|
-
// ├── core/
|
|
89
|
-
// ├── bmm/
|
|
90
|
-
// ├── bmb/
|
|
91
|
-
// ├── tea/
|
|
92
|
-
// └── cis/
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Copy agent file from template
|
|
97
|
-
*
|
|
98
|
-
* @param {string} agentName - Agent name
|
|
99
|
-
* @param {string} targetPath - Target directory
|
|
100
|
-
* @returns {Promise<void>}
|
|
101
|
-
*/
|
|
102
|
-
async function copyAgentFile(agentName, targetPath) {
|
|
103
|
-
// TODO: Copy from lib/templates/agents/{agentName}.md
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Generate platform-specific stub
|
|
108
|
-
*
|
|
109
|
-
* @param {string} agentName - Agent name
|
|
110
|
-
* @param {string} platform - Platform name
|
|
111
|
-
* @param {string} targetPath - Target directory
|
|
112
|
-
* @returns {Promise<void>}
|
|
113
|
-
*/
|
|
114
|
-
async function generateStub(agentName, platform, targetPath) {
|
|
115
|
-
// TODO: Generate stub based on platform
|
|
116
|
-
// - Claude Code: MCP config JSON
|
|
117
|
-
// - Codex: .codex/prompts/{agentName}.md
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Create module config file
|
|
122
|
-
*
|
|
123
|
-
* @param {string} moduleName - Module name (core, bmm, bmb, tea, cis)
|
|
124
|
-
* @param {InstallConfig} config - Installation config
|
|
125
|
-
* @param {string} targetPath - Target directory
|
|
126
|
-
* @returns {Promise<void>}
|
|
127
|
-
*/
|
|
128
|
-
async function createModuleConfig(moduleName, config, targetPath) {
|
|
129
|
-
// TODO: Generate config.yaml with user settings
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
module.exports = {
|
|
133
|
-
install,
|
|
134
|
-
createBmadStructure,
|
|
135
|
-
copyAgentFile,
|
|
136
|
-
generateStub,
|
|
137
|
-
createModuleConfig
|
|
138
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* INTERVIEWER Module
|
|
3
|
-
*
|
|
4
|
-
* Conducts quick interview (5-7 questions, <5 min) to personalize installation.
|
|
5
|
-
*
|
|
6
|
-
* Phase 6 (part of 7): 16h development
|
|
7
|
-
*
|
|
8
|
-
* @module yanstaller/interviewer
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const inquirer = require('inquirer');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {Object} InterviewResult
|
|
15
|
-
* @property {string} userName
|
|
16
|
-
* @property {string} language - 'Francais' | 'English'
|
|
17
|
-
* @property {string} mode - 'full' | 'minimal' | 'custom'
|
|
18
|
-
* @property {string[]} agents - Selected agents (if custom mode)
|
|
19
|
-
* @property {string[]} targetPlatforms - Platforms to install on
|
|
20
|
-
* @property {boolean} createSampleAgent - Whether to create sample agent after install
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Run quick interview
|
|
25
|
-
*
|
|
26
|
-
* @param {import('./recommender').Recommendation} recommendation - Recommended config
|
|
27
|
-
* @returns {Promise<InterviewResult>}
|
|
28
|
-
*/
|
|
29
|
-
async function ask(recommendation) {
|
|
30
|
-
// TODO: Implement inquirer prompts
|
|
31
|
-
// Q1: Your name?
|
|
32
|
-
// Q2: Preferred language?
|
|
33
|
-
// Q3: Installation mode? (with recommendation)
|
|
34
|
-
// Q4: (if custom) Which agents?
|
|
35
|
-
// Q5: Which platforms to install on?
|
|
36
|
-
// Q6: Create sample agent after install?
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
userName: 'User',
|
|
40
|
-
language: 'English',
|
|
41
|
-
mode: recommendation.mode,
|
|
42
|
-
agents: recommendation.agents,
|
|
43
|
-
targetPlatforms: ['claude'],
|
|
44
|
-
createSampleAgent: false
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Ask single question
|
|
50
|
-
*
|
|
51
|
-
* @param {string} question - Question text
|
|
52
|
-
* @param {string} type - 'input' | 'list' | 'confirm' | 'checkbox'
|
|
53
|
-
* @param {Array} [choices] - Choices for list/checkbox
|
|
54
|
-
* @returns {Promise<any>}
|
|
55
|
-
*/
|
|
56
|
-
async function askQuestion(question, type, choices = []) {
|
|
57
|
-
// TODO: Use inquirer
|
|
58
|
-
const answer = await inquirer.prompt([
|
|
59
|
-
{
|
|
60
|
-
type,
|
|
61
|
-
name: 'answer',
|
|
62
|
-
message: question,
|
|
63
|
-
choices
|
|
64
|
-
}
|
|
65
|
-
]);
|
|
66
|
-
|
|
67
|
-
return answer.answer;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get available agents list for custom selection
|
|
72
|
-
*
|
|
73
|
-
* @returns {Array<{name: string, value: string, checked: boolean}>}
|
|
74
|
-
*/
|
|
75
|
-
function getAgentChoices() {
|
|
76
|
-
// TODO: Return all 29 agents with descriptions
|
|
77
|
-
return [
|
|
78
|
-
{ name: 'BYAN - Agent Creator', value: 'byan', checked: true },
|
|
79
|
-
{ name: 'RACHID - NPM Deployment', value: 'rachid', checked: true },
|
|
80
|
-
// ... 27 more
|
|
81
|
-
];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = {
|
|
85
|
-
ask,
|
|
86
|
-
askQuestion,
|
|
87
|
-
getAgentChoices
|
|
88
|
-
};
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RECOMMENDER Module
|
|
3
|
-
*
|
|
4
|
-
* Analyzes project and recommends optimal BYAN configuration.
|
|
5
|
-
*
|
|
6
|
-
* Phase 2: 24h development
|
|
7
|
-
*
|
|
8
|
-
* @module yanstaller/recommender
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {Object} Recommendation
|
|
13
|
-
* @property {string} mode - 'full' | 'minimal' | 'custom'
|
|
14
|
-
* @property {string[]} agents - Recommended agent names
|
|
15
|
-
* @property {string} reason - Why this recommendation
|
|
16
|
-
* @property {string} projectType - 'frontend' | 'backend' | 'fullstack' | 'library' | 'unknown'
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Analyze project and recommend configuration
|
|
21
|
-
*
|
|
22
|
-
* @param {import('./detector').DetectionResult} detection - Detection results
|
|
23
|
-
* @returns {Promise<Recommendation>}
|
|
24
|
-
*/
|
|
25
|
-
async function recommend(detection) {
|
|
26
|
-
// TODO: Implement recommendation logic
|
|
27
|
-
// - Analyze package.json, requirements.txt, go.mod, etc.
|
|
28
|
-
// - Detect project type (frontend/backend/fullstack)
|
|
29
|
-
// - Recommend agents based on stack
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
mode: 'minimal',
|
|
33
|
-
agents: ['byan', 'rachid', 'marc', 'patnote', 'carmack'],
|
|
34
|
-
reason: 'Default minimal installation for new users',
|
|
35
|
-
projectType: 'unknown'
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Analyze package.json to detect stack
|
|
41
|
-
*
|
|
42
|
-
* @param {string} packageJsonPath - Path to package.json
|
|
43
|
-
* @returns {Promise<{isFrontend: boolean, isBackend: boolean, framework: string}>}
|
|
44
|
-
*/
|
|
45
|
-
async function analyzePackageJson(packageJsonPath) {
|
|
46
|
-
// TODO: Read package.json, check dependencies
|
|
47
|
-
// - React/Vue/Angular → frontend
|
|
48
|
-
// - Express/Fastify/Nest → backend
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
isFrontend: false,
|
|
52
|
-
isBackend: false,
|
|
53
|
-
framework: 'unknown'
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get agent list for installation mode
|
|
59
|
-
*
|
|
60
|
-
* @param {string} mode - 'full' | 'minimal' | 'custom'
|
|
61
|
-
* @param {string[]} [customAgents] - Custom agent selection
|
|
62
|
-
* @returns {string[]}
|
|
63
|
-
*/
|
|
64
|
-
function getAgentList(mode, customAgents = []) {
|
|
65
|
-
const MINIMAL_AGENTS = ['hermes', 'byan', 'rachid', 'marc', 'patnote', 'carmack'];
|
|
66
|
-
const FULL_AGENTS = [
|
|
67
|
-
// Dispatcher (1)
|
|
68
|
-
'hermes',
|
|
69
|
-
// Core (5)
|
|
70
|
-
'byan', 'rachid', 'marc', 'patnote', 'carmack',
|
|
71
|
-
// BMM (9)
|
|
72
|
-
'analyst', 'pm', 'architect', 'dev', 'sm', 'quinn', 'ux-designer', 'tech-writer', 'quick-flow-solo-dev',
|
|
73
|
-
// BMB (3)
|
|
74
|
-
'agent-builder', 'module-builder', 'workflow-builder',
|
|
75
|
-
// TEA (1)
|
|
76
|
-
'tea',
|
|
77
|
-
// CIS (6)
|
|
78
|
-
'brainstorming-coach', 'creative-problem-solver', 'design-thinking-coach',
|
|
79
|
-
'innovation-strategist', 'presentation-master', 'storyteller',
|
|
80
|
-
// BYAN Test (1)
|
|
81
|
-
'byan-test'
|
|
82
|
-
];
|
|
83
|
-
|
|
84
|
-
switch (mode) {
|
|
85
|
-
case 'full':
|
|
86
|
-
return FULL_AGENTS;
|
|
87
|
-
case 'minimal':
|
|
88
|
-
return MINIMAL_AGENTS;
|
|
89
|
-
case 'custom':
|
|
90
|
-
case 'manual':
|
|
91
|
-
// Ensure hermes is always included
|
|
92
|
-
return [...new Set(['hermes', ...customAgents])];
|
|
93
|
-
default:
|
|
94
|
-
return MINIMAL_AGENTS;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = {
|
|
99
|
-
recommend,
|
|
100
|
-
analyzePackageJson,
|
|
101
|
-
getAgentList
|
|
102
|
-
};
|