create-byan-agent 2.0.1 → 2.1.1
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/API-BYAN-V2.md +741 -0
- package/BMAD-QUICK-REFERENCE.md +370 -0
- package/CHANGELOG-v2.1.0.md +371 -0
- package/LICENSE +1 -1
- package/MIGRATION-v2.0-to-v2.1.md +430 -0
- package/README-BYAN-V2.md +446 -0
- package/README.md +264 -201
- package/install/.eslintrc.js +20 -0
- package/install/.prettierrc +7 -0
- package/install/BUGFIX-CHALK.md +173 -0
- package/install/BUGFIX-DOCUMENTATION-INDEX.md +299 -0
- package/install/BUGFIX-PATH-RESOLUTION.md +293 -0
- package/install/BUGFIX-QUICKSTART.md +184 -0
- package/install/BUGFIX-SUMMARY.txt +91 -0
- package/install/BUGFIX-VISUAL-SUMMARY.md +253 -0
- package/install/DEPLOYMENT-GUIDE-V2.md +431 -0
- package/install/DOCS-INDEX.md +261 -0
- package/install/GUIDE-INSTALLATION-BYAN-SIMPLE.md +1083 -0
- package/install/INSTALLER-V2-CHANGES.md +472 -0
- package/install/LICENSE +21 -0
- package/install/PUBLICATION-CHECKLIST.md +265 -0
- package/install/PUBLISH-GUIDE.md +190 -0
- package/install/QUICKSTART.md +311 -0
- package/install/README-NPM-PUBLISH.md +298 -0
- package/install/README-NPM-SHORT.md +298 -0
- package/install/README-NPM.md +433 -0
- package/install/README-RACHID.md +302 -0
- package/install/README-V2-INDEX.md +306 -0
- package/install/README.md +298 -0
- package/install/RESUME-EXECUTIF-YAN.md +408 -0
- package/install/UPDATE-SUMMARY.md +205 -0
- package/install/__tests__/integration/detection-flow.test.js +154 -0
- package/install/__tests__/platforms/claude-code.test.js +175 -0
- package/install/__tests__/platforms/codex.test.js +80 -0
- package/install/__tests__/platforms/copilot-cli.test.js +118 -0
- package/install/__tests__/platforms/vscode.test.js +67 -0
- package/install/__tests__/utils/file-utils.test.js +87 -0
- package/install/__tests__/utils/git-detector.test.js +80 -0
- package/install/__tests__/utils/logger.test.js +83 -0
- package/install/__tests__/utils/node-detector.test.js +71 -0
- package/install/__tests__/utils/os-detector.test.js +63 -0
- package/install/__tests__/utils/yaml-utils.test.js +85 -0
- package/install/__tests__/yanstaller/detector.test.js +210 -0
- package/install/coverage/clover.xml +219 -0
- package/install/coverage/coverage-final.json +13 -0
- package/install/coverage/lcov-report/base.css +224 -0
- package/install/coverage/lcov-report/block-navigation.js +87 -0
- package/install/coverage/lcov-report/favicon.png +0 -0
- package/install/coverage/lcov-report/index.html +146 -0
- package/install/coverage/lcov-report/lib/errors.js.html +268 -0
- package/install/coverage/lcov-report/lib/exit-codes.js.html +247 -0
- package/install/coverage/lcov-report/lib/index.html +131 -0
- package/install/coverage/lcov-report/lib/platforms/claude-code.js.html +343 -0
- package/install/coverage/lcov-report/lib/platforms/codex.js.html +361 -0
- package/install/coverage/lcov-report/lib/platforms/copilot-cli.js.html +454 -0
- package/install/coverage/lcov-report/lib/platforms/index.html +176 -0
- package/install/coverage/lcov-report/lib/platforms/index.js.html +127 -0
- package/install/coverage/lcov-report/lib/platforms/vscode.js.html +238 -0
- package/install/coverage/lcov-report/lib/utils/config-loader.js.html +322 -0
- package/install/coverage/lcov-report/lib/utils/file-utils.js.html +397 -0
- package/install/coverage/lcov-report/lib/utils/git-detector.js.html +190 -0
- package/install/coverage/lcov-report/lib/utils/index.html +206 -0
- package/install/coverage/lcov-report/lib/utils/logger.js.html +277 -0
- package/install/coverage/lcov-report/lib/utils/node-detector.js.html +259 -0
- package/install/coverage/lcov-report/lib/utils/os-detector.js.html +307 -0
- package/install/coverage/lcov-report/lib/utils/yaml-utils.js.html +346 -0
- package/install/coverage/lcov-report/lib/yanstaller/backuper.js.html +409 -0
- package/install/coverage/lcov-report/lib/yanstaller/detector.js.html +508 -0
- package/install/coverage/lcov-report/lib/yanstaller/index.html +236 -0
- package/install/coverage/lcov-report/lib/yanstaller/index.js.html +364 -0
- package/install/coverage/lcov-report/lib/yanstaller/installer.js.html +505 -0
- package/install/coverage/lcov-report/lib/yanstaller/interviewer.js.html +349 -0
- package/install/coverage/lcov-report/lib/yanstaller/recommender.js.html +379 -0
- package/install/coverage/lcov-report/lib/yanstaller/troubleshooter.js.html +352 -0
- package/install/coverage/lcov-report/lib/yanstaller/validator.js.html +679 -0
- package/install/coverage/lcov-report/lib/yanstaller/wizard.js.html +412 -0
- package/install/coverage/lcov-report/platforms/claude-code.js.html +343 -0
- package/install/coverage/lcov-report/platforms/codex.js.html +361 -0
- package/install/coverage/lcov-report/platforms/copilot-cli.js.html +454 -0
- package/install/coverage/lcov-report/platforms/index.html +176 -0
- package/install/coverage/lcov-report/platforms/index.js.html +127 -0
- package/install/coverage/lcov-report/platforms/vscode.js.html +238 -0
- package/install/coverage/lcov-report/prettify.css +1 -0
- package/install/coverage/lcov-report/prettify.js +2 -0
- package/install/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/install/coverage/lcov-report/sorter.js +210 -0
- package/install/coverage/lcov-report/utils/file-utils.js.html +397 -0
- package/install/coverage/lcov-report/utils/git-detector.js.html +190 -0
- package/install/coverage/lcov-report/utils/index.html +191 -0
- package/install/coverage/lcov-report/utils/logger.js.html +277 -0
- package/install/coverage/lcov-report/utils/node-detector.js.html +259 -0
- package/install/coverage/lcov-report/utils/os-detector.js.html +307 -0
- package/install/coverage/lcov-report/utils/yaml-utils.js.html +346 -0
- package/install/coverage/lcov-report/yanstaller/detector.js.html +508 -0
- package/install/coverage/lcov-report/yanstaller/index.html +116 -0
- package/install/coverage/lcov.info +414 -0
- package/install/install.sh +239 -0
- package/install/jest.config.js +33 -0
- package/install/lib/errors.js +61 -0
- package/install/lib/exit-codes.js +54 -0
- package/install/lib/platforms/claude-code.js +86 -0
- package/install/lib/platforms/codex.js +92 -0
- package/install/lib/platforms/copilot-cli.js +123 -0
- package/install/lib/platforms/index.js +14 -0
- package/install/lib/platforms/vscode.js +51 -0
- package/install/lib/utils/config-loader.js +79 -0
- package/install/lib/utils/file-utils.js +104 -0
- package/install/lib/utils/git-detector.js +35 -0
- package/install/lib/utils/logger.js +64 -0
- package/install/lib/utils/node-detector.js +58 -0
- package/install/lib/utils/os-detector.js +74 -0
- package/install/lib/utils/yaml-utils.js +87 -0
- package/install/lib/yanstaller/backuper.js +108 -0
- package/install/lib/yanstaller/detector.js +141 -0
- package/install/lib/yanstaller/index.js +93 -0
- package/install/lib/yanstaller/installer.js +140 -0
- package/install/lib/yanstaller/interviewer.js +88 -0
- package/install/lib/yanstaller/recommender.js +98 -0
- package/install/lib/yanstaller/troubleshooter.js +89 -0
- package/install/lib/yanstaller/validator.js +198 -0
- package/install/lib/yanstaller/wizard.js +109 -0
- package/install/package-npm.json +55 -0
- package/install/package.json +63 -0
- package/install/src/byan-v2/context/copilot-context.js +79 -0
- package/install/src/byan-v2/context/session-state.js +98 -0
- package/install/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
- package/install/src/byan-v2/dispatcher/local-executor.js +221 -0
- package/install/src/byan-v2/dispatcher/task-router.js +122 -0
- package/install/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
- package/install/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
- package/install/src/byan-v2/generation/agent-profile-validator.js +113 -0
- package/install/src/byan-v2/generation/profile-template.js +113 -0
- package/install/src/byan-v2/generation/templates/default-agent.md +49 -0
- package/install/src/byan-v2/generation/templates/test-template.md +1 -0
- package/install/src/byan-v2/index.js +199 -0
- package/install/src/byan-v2/observability/error-tracker.js +105 -0
- package/install/src/byan-v2/observability/logger.js +154 -0
- package/install/src/byan-v2/observability/metrics-collector.js +194 -0
- package/install/src/byan-v2/orchestrator/analysis-state.js +268 -0
- package/install/src/byan-v2/orchestrator/generation-state.js +340 -0
- package/install/src/byan-v2/orchestrator/interview-state.js +271 -0
- package/install/src/byan-v2/orchestrator/state-machine.js +204 -0
- package/install/src/core/cache/cache.js +126 -0
- package/install/src/core/context/context.js +86 -0
- package/install/src/core/dispatcher/dispatcher.js +135 -0
- package/install/src/core/worker-pool/worker-pool.js +194 -0
- package/install/src/core/workflow/workflow-executor.js +220 -0
- package/install/src/index.js +139 -0
- package/install/src/observability/dashboard/dashboard.js +191 -0
- package/install/src/observability/logger/structured-logger.js +254 -0
- package/install/src/observability/metrics/metrics-collector.js +325 -0
- package/install/switch-to-v2.sh +126 -0
- package/install/test-chalk-fix.sh +210 -0
- package/install/test-installer-v2.sh +204 -0
- package/install/test-path-resolution.sh +200 -0
- package/package.json +53 -33
- package/src/byan-v2/context/copilot-context.js +79 -0
- package/src/byan-v2/context/session-state.js +98 -0
- package/src/byan-v2/data/mantras.json +852 -0
- package/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
- package/src/byan-v2/dispatcher/five-whys-analyzer.js +310 -0
- package/src/byan-v2/dispatcher/local-executor.js +221 -0
- package/src/byan-v2/dispatcher/task-router.js +122 -0
- package/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
- package/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
- package/src/byan-v2/generation/agent-profile-validator.js +113 -0
- package/src/byan-v2/generation/mantra-validator.js +416 -0
- package/src/byan-v2/generation/profile-template.js +113 -0
- package/src/byan-v2/generation/templates/default-agent.md +49 -0
- package/src/byan-v2/generation/templates/test-template.md +1 -0
- package/src/byan-v2/index.js +652 -0
- package/src/byan-v2/integration/voice-integration.js +295 -0
- package/src/byan-v2/observability/error-tracker.js +105 -0
- package/src/byan-v2/observability/logger.js +154 -0
- package/src/byan-v2/observability/metrics-collector.js +194 -0
- package/src/byan-v2/orchestrator/active-listener.js +541 -0
- package/src/byan-v2/orchestrator/analysis-state.js +268 -0
- package/src/byan-v2/orchestrator/generation-state.js +340 -0
- package/src/byan-v2/orchestrator/glossary-builder.js +431 -0
- package/src/byan-v2/orchestrator/interview-state.js +353 -0
- package/src/byan-v2/orchestrator/state-machine.js +253 -0
- package/src/core/cache/cache.js +126 -0
- package/src/core/context/context.js +86 -0
- package/src/core/dispatcher/dispatcher.js +135 -0
- package/src/core/worker-pool/worker-pool.js +194 -0
- package/src/core/workflow/workflow-executor.js +220 -0
- package/src/index.js +139 -0
- package/src/observability/dashboard/dashboard.js +191 -0
- package/src/observability/logger/structured-logger.js +254 -0
- package/src/observability/metrics/metrics-collector.js +325 -0
- package/templates/.github/agents/bmad-agent-test-dynamic.md +0 -21
- package/templates/.github/agents/franck.md +0 -379
- /package/{CHANGELOG.md → install/CHANGELOG.md} +0 -0
- /package/{bin → install/bin}/create-byan-agent-backup.js +0 -0
- /package/{bin → install/bin}/create-byan-agent-fixed.js +0 -0
- /package/{bin → install/bin}/create-byan-agent-v2.js +0 -0
- /package/{bin → install/bin}/create-byan-agent.js +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmad-master.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-agent-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-module-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-workflow-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-analyst.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-architect.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-dev.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-pm.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quinn.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-sm.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-tech-writer.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-ux-designer.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-byan-test.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-byan.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-carmack.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-brainstorming-coach.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-creative-problem-solver.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-design-thinking-coach.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-innovation-strategist.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-presentation-master.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-storyteller.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-marc.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-patnote.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-rachid.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-tea-tea.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/agent-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/byan-test.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/byan.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/marc.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/module-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/patnote.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/rachid.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/workflow-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/mantras.yaml +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/templates.yaml +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/delete-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/edit-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/interview-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/quick-create-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/templates/base-agent-template.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/validate-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/core/agents/carmack.md +0 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Cache with TTL support for reducing token consumption
|
|
3
|
+
* Provides in-memory caching with automatic expiration
|
|
4
|
+
*
|
|
5
|
+
* @class SimpleCache
|
|
6
|
+
* @example
|
|
7
|
+
* const cache = new SimpleCache();
|
|
8
|
+
* cache.set('key1', 'value1', 5000); // TTL 5 seconds
|
|
9
|
+
* const value = cache.get('key1');
|
|
10
|
+
*/
|
|
11
|
+
class SimpleCache {
|
|
12
|
+
/**
|
|
13
|
+
* Initialize a new SimpleCache instance
|
|
14
|
+
*/
|
|
15
|
+
constructor() {
|
|
16
|
+
this.store = new Map();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Store a value in cache with optional TTL
|
|
21
|
+
* @param {string} key - Cache key
|
|
22
|
+
* @param {*} value - Value to cache
|
|
23
|
+
* @param {number} [ttl] - Time to live in milliseconds (optional)
|
|
24
|
+
* @throws {Error} If key is not a string
|
|
25
|
+
* @returns {void}
|
|
26
|
+
*/
|
|
27
|
+
set(key, value, ttl) {
|
|
28
|
+
if (typeof key !== 'string' || !key) {
|
|
29
|
+
throw new Error('Cache key must be a non-empty string');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const entry = {
|
|
33
|
+
value,
|
|
34
|
+
timestamp: Date.now(),
|
|
35
|
+
ttl: ttl || null
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.store.set(key, entry);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Retrieve a value from cache
|
|
43
|
+
* @param {string} key - Cache key
|
|
44
|
+
* @returns {*|null} Cached value or null if not found or expired
|
|
45
|
+
*/
|
|
46
|
+
get(key) {
|
|
47
|
+
const entry = this.store.get(key);
|
|
48
|
+
|
|
49
|
+
if (!entry) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check if TTL has expired
|
|
54
|
+
if (entry.ttl && (Date.now() - entry.timestamp) > entry.ttl) {
|
|
55
|
+
this.store.delete(key);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return entry.value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if a key exists and is not expired
|
|
64
|
+
* @param {string} key - Cache key
|
|
65
|
+
* @returns {boolean} True if key exists and not expired
|
|
66
|
+
*/
|
|
67
|
+
has(key) {
|
|
68
|
+
const value = this.get(key);
|
|
69
|
+
return value !== null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Delete a specific cache entry
|
|
74
|
+
* @param {string} key - Cache key to delete
|
|
75
|
+
* @returns {boolean} True if key was deleted, false if not found
|
|
76
|
+
*/
|
|
77
|
+
delete(key) {
|
|
78
|
+
return this.store.delete(key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Clear all cache entries
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
clear() {
|
|
86
|
+
this.store.clear();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the number of entries in cache (includes expired but not cleaned)
|
|
91
|
+
* @returns {number} Number of cache entries
|
|
92
|
+
*/
|
|
93
|
+
size() {
|
|
94
|
+
return this.store.size;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get all non-expired keys
|
|
99
|
+
* @returns {string[]} Array of valid keys
|
|
100
|
+
*/
|
|
101
|
+
keys() {
|
|
102
|
+
const validKeys = [];
|
|
103
|
+
for (const [key] of this.store) {
|
|
104
|
+
if (this.get(key) !== null) {
|
|
105
|
+
validKeys.push(key);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return validKeys;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Clean up expired entries
|
|
113
|
+
* @returns {number} Number of entries removed
|
|
114
|
+
*/
|
|
115
|
+
cleanup() {
|
|
116
|
+
let removed = 0;
|
|
117
|
+
for (const [key] of this.store) {
|
|
118
|
+
if (this.get(key) === null) {
|
|
119
|
+
removed++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return removed;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = SimpleCache;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Layer for managing conversational context across agents
|
|
3
|
+
* Provides a hierarchical structure for storing and retrieving context data
|
|
4
|
+
*
|
|
5
|
+
* @class ContextLayer
|
|
6
|
+
* @example
|
|
7
|
+
* const ctx = new ContextLayer();
|
|
8
|
+
* ctx.addLayer('user', { name: 'Yan', role: 'dev' });
|
|
9
|
+
* const userData = ctx.getLayer('user');
|
|
10
|
+
*/
|
|
11
|
+
class ContextLayer {
|
|
12
|
+
/**
|
|
13
|
+
* Initialize a new ContextLayer instance
|
|
14
|
+
*/
|
|
15
|
+
constructor() {
|
|
16
|
+
this.layers = {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Add or update a context layer
|
|
21
|
+
* @param {string} name - Layer name/identifier
|
|
22
|
+
* @param {object} data - Layer data to store
|
|
23
|
+
* @throws {Error} If name is not a string or data is not an object
|
|
24
|
+
* @returns {void}
|
|
25
|
+
*/
|
|
26
|
+
addLayer(name, data) {
|
|
27
|
+
if (typeof name !== 'string' || !name) {
|
|
28
|
+
throw new Error('Layer name must be a non-empty string');
|
|
29
|
+
}
|
|
30
|
+
if (typeof data !== 'object' || data === null) {
|
|
31
|
+
throw new Error('Layer data must be an object');
|
|
32
|
+
}
|
|
33
|
+
this.layers[name] = { ...data, _timestamp: Date.now() };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Retrieve a specific context layer
|
|
38
|
+
* @param {string} name - Layer name to retrieve
|
|
39
|
+
* @returns {object|null} Layer data (deep copy) or null if not found
|
|
40
|
+
*/
|
|
41
|
+
getLayer(name) {
|
|
42
|
+
if (!this.layers[name]) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return JSON.parse(JSON.stringify(this.layers[name]));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get all context layers
|
|
50
|
+
* @returns {object} All layers as a key-value object (deep copy)
|
|
51
|
+
*/
|
|
52
|
+
getAllLayers() {
|
|
53
|
+
return JSON.parse(JSON.stringify(this.layers));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Remove a specific context layer
|
|
58
|
+
* @param {string} name - Layer name to remove
|
|
59
|
+
* @returns {boolean} True if layer was removed, false if not found
|
|
60
|
+
*/
|
|
61
|
+
clearLayer(name) {
|
|
62
|
+
if (this.layers[name]) {
|
|
63
|
+
delete this.layers[name];
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Serialize all layers to JSON string
|
|
71
|
+
* @returns {string} JSON representation of all layers
|
|
72
|
+
*/
|
|
73
|
+
serialize() {
|
|
74
|
+
return JSON.stringify(this.layers);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Clear all context layers
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
clearAll() {
|
|
82
|
+
this.layers = {};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = ContextLayer;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Economic Dispatcher for routing tasks to appropriate AI models
|
|
3
|
+
* Routes tasks based on complexity keywords to optimize cost/performance
|
|
4
|
+
*
|
|
5
|
+
* @class EconomicDispatcher
|
|
6
|
+
* @example
|
|
7
|
+
* const dispatcher = new EconomicDispatcher();
|
|
8
|
+
* const model = dispatcher.dispatch('explore codebase'); // Returns 'haiku'
|
|
9
|
+
*/
|
|
10
|
+
class EconomicDispatcher {
|
|
11
|
+
/**
|
|
12
|
+
* Initialize a new EconomicDispatcher instance
|
|
13
|
+
*/
|
|
14
|
+
constructor() {
|
|
15
|
+
// Model classification patterns
|
|
16
|
+
this.patterns = {
|
|
17
|
+
haiku: [
|
|
18
|
+
'explore', 'simple', 'quick', 'search', 'find', 'list', 'show',
|
|
19
|
+
'check', 'verify', 'read', 'get', 'view', 'display', 'basic'
|
|
20
|
+
],
|
|
21
|
+
sonnet: [
|
|
22
|
+
'implement', 'code', 'complex', 'develop', 'create', 'build',
|
|
23
|
+
'write', 'fix', 'refactor', 'optimize', 'integrate', 'design'
|
|
24
|
+
],
|
|
25
|
+
opus: [
|
|
26
|
+
'architect', 'critical', 'review', 'analyze', 'evaluate', 'plan',
|
|
27
|
+
'strategy', 'security', 'performance', 'scalability', 'system-design',
|
|
28
|
+
'architectural', 'mission-critical', 'production'
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Relative costs (Haiku = 1x baseline)
|
|
33
|
+
this.costs = {
|
|
34
|
+
haiku: 1,
|
|
35
|
+
sonnet: 5,
|
|
36
|
+
opus: 15
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Dispatch a task to the appropriate model
|
|
42
|
+
* @param {string} task - Task description
|
|
43
|
+
* @returns {string} Model name ('haiku', 'sonnet', or 'opus')
|
|
44
|
+
* @throws {Error} If task is not a string
|
|
45
|
+
*/
|
|
46
|
+
dispatch(task) {
|
|
47
|
+
if (typeof task !== 'string' || !task) {
|
|
48
|
+
throw new Error('Task must be a non-empty string');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const taskLower = task.toLowerCase();
|
|
52
|
+
|
|
53
|
+
// Helper to check for whole word match or start of compound words
|
|
54
|
+
const hasKeyword = (patterns) => {
|
|
55
|
+
return patterns.some(pattern => {
|
|
56
|
+
const regex = new RegExp(`\\b${pattern}\\b`, 'i');
|
|
57
|
+
return regex.test(task);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Check Opus patterns first (highest priority for critical tasks)
|
|
62
|
+
if (hasKeyword(this.patterns.opus)) {
|
|
63
|
+
return 'opus';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check Sonnet patterns (medium complexity)
|
|
67
|
+
if (hasKeyword(this.patterns.sonnet)) {
|
|
68
|
+
return 'sonnet';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check Haiku patterns (simple tasks)
|
|
72
|
+
if (hasKeyword(this.patterns.haiku)) {
|
|
73
|
+
return 'haiku';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Default to Sonnet for unclassified tasks (balanced choice)
|
|
77
|
+
return 'sonnet';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the relative cost of a model
|
|
82
|
+
* @param {string} model - Model name ('haiku', 'sonnet', or 'opus')
|
|
83
|
+
* @returns {number} Relative cost multiplier
|
|
84
|
+
* @throws {Error} If model is unknown
|
|
85
|
+
*/
|
|
86
|
+
getModelCost(model) {
|
|
87
|
+
if (!this.costs[model]) {
|
|
88
|
+
throw new Error(`Unknown model: ${model}`);
|
|
89
|
+
}
|
|
90
|
+
return this.costs[model];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get cost comparison between two models
|
|
95
|
+
* @param {string} model1 - First model
|
|
96
|
+
* @param {string} model2 - Second model
|
|
97
|
+
* @returns {number} Cost ratio (model1/model2)
|
|
98
|
+
*/
|
|
99
|
+
compareCosts(model1, model2) {
|
|
100
|
+
const cost1 = this.getModelCost(model1);
|
|
101
|
+
const cost2 = this.getModelCost(model2);
|
|
102
|
+
return cost1 / cost2;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get all available models with their costs
|
|
107
|
+
* @returns {object} Models and their costs
|
|
108
|
+
*/
|
|
109
|
+
getAllModels() {
|
|
110
|
+
return { ...this.costs };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Estimate cost savings by using recommended model vs default
|
|
115
|
+
* @param {string} task - Task description
|
|
116
|
+
* @param {string} defaultModel - Default model to compare against
|
|
117
|
+
* @returns {object} Savings information
|
|
118
|
+
*/
|
|
119
|
+
estimateSavings(task, defaultModel = 'sonnet') {
|
|
120
|
+
const recommended = this.dispatch(task);
|
|
121
|
+
const recommendedCost = this.getModelCost(recommended);
|
|
122
|
+
const defaultCost = this.getModelCost(defaultModel);
|
|
123
|
+
const savings = ((defaultCost - recommendedCost) / defaultCost) * 100;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
recommended,
|
|
127
|
+
recommendedCost,
|
|
128
|
+
defaultCost,
|
|
129
|
+
savingsPercent: Math.round(savings),
|
|
130
|
+
shouldSwitch: savings > 0
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = EconomicDispatcher;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker for executing tasks asynchronously
|
|
3
|
+
* Represents a single worker in the pool
|
|
4
|
+
*
|
|
5
|
+
* @class Worker
|
|
6
|
+
*/
|
|
7
|
+
class Worker {
|
|
8
|
+
/**
|
|
9
|
+
* Create a new Worker
|
|
10
|
+
* @param {number} id - Unique worker identifier
|
|
11
|
+
*/
|
|
12
|
+
constructor(id) {
|
|
13
|
+
this.id = id;
|
|
14
|
+
this.status = 'idle'; // idle, busy, error
|
|
15
|
+
this.currentTask = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Execute a task
|
|
20
|
+
* @param {Function|object} task - Task to execute (function or object with execute method)
|
|
21
|
+
* @returns {Promise<*>} Task result
|
|
22
|
+
*/
|
|
23
|
+
async execute(task) {
|
|
24
|
+
this.status = 'busy';
|
|
25
|
+
this.currentTask = task;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
let result;
|
|
29
|
+
|
|
30
|
+
if (typeof task === 'function') {
|
|
31
|
+
result = await task();
|
|
32
|
+
} else if (task && typeof task.execute === 'function') {
|
|
33
|
+
result = await task.execute();
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error('Task must be a function or have an execute method');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.status = 'idle';
|
|
39
|
+
this.currentTask = null;
|
|
40
|
+
return result;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
this.status = 'error';
|
|
43
|
+
this.currentTask = null;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Worker Pool for managing parallel task execution
|
|
51
|
+
* Provides a pool of workers with automatic task queuing
|
|
52
|
+
*
|
|
53
|
+
* @class WorkerPool
|
|
54
|
+
* @example
|
|
55
|
+
* const pool = new WorkerPool(3);
|
|
56
|
+
* const result = await pool.submitTask(async () => { return 'done'; });
|
|
57
|
+
*/
|
|
58
|
+
class WorkerPool {
|
|
59
|
+
/**
|
|
60
|
+
* Create a new WorkerPool
|
|
61
|
+
* @param {number} maxWorkers - Maximum number of concurrent workers
|
|
62
|
+
* @throws {Error} If maxWorkers is not a positive number
|
|
63
|
+
*/
|
|
64
|
+
constructor(maxWorkers = 4) {
|
|
65
|
+
if (typeof maxWorkers !== 'number' || maxWorkers < 1) {
|
|
66
|
+
throw new Error('maxWorkers must be a positive number');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.maxWorkers = maxWorkers;
|
|
70
|
+
this.workers = [];
|
|
71
|
+
this.taskQueue = [];
|
|
72
|
+
this.activeTasks = 0;
|
|
73
|
+
this.isShutdown = false;
|
|
74
|
+
|
|
75
|
+
// Initialize workers
|
|
76
|
+
for (let i = 0; i < maxWorkers; i++) {
|
|
77
|
+
this.workers.push(new Worker(i));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Submit a task to the pool
|
|
83
|
+
* @param {Function|object} task - Task to execute
|
|
84
|
+
* @returns {Promise<*>} Promise that resolves with task result
|
|
85
|
+
*/
|
|
86
|
+
submitTask(task) {
|
|
87
|
+
if (this.isShutdown) {
|
|
88
|
+
return Promise.reject(new Error('Worker pool is shutdown'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
this.taskQueue.push({ task, resolve, reject });
|
|
93
|
+
this._processQueue();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Process the task queue
|
|
99
|
+
* @private
|
|
100
|
+
*/
|
|
101
|
+
async _processQueue() {
|
|
102
|
+
// Find an idle worker
|
|
103
|
+
const idleWorker = this.workers.find(w => w.status === 'idle');
|
|
104
|
+
|
|
105
|
+
if (!idleWorker || this.taskQueue.length === 0) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { task, resolve, reject } = this.taskQueue.shift();
|
|
110
|
+
this.activeTasks++;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const result = await idleWorker.execute(task);
|
|
114
|
+
this.activeTasks--;
|
|
115
|
+
resolve(result);
|
|
116
|
+
|
|
117
|
+
// Process next task if any
|
|
118
|
+
if (this.taskQueue.length > 0) {
|
|
119
|
+
this._processQueue();
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.activeTasks--;
|
|
123
|
+
reject(error);
|
|
124
|
+
|
|
125
|
+
// Reset worker to idle on error
|
|
126
|
+
idleWorker.status = 'idle';
|
|
127
|
+
|
|
128
|
+
// Continue processing queue
|
|
129
|
+
if (this.taskQueue.length > 0) {
|
|
130
|
+
this._processQueue();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get number of active workers
|
|
137
|
+
* @returns {number} Number of busy workers
|
|
138
|
+
*/
|
|
139
|
+
getActiveWorkers() {
|
|
140
|
+
return this.workers.filter(w => w.status === 'busy').length;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get number of idle workers
|
|
145
|
+
* @returns {number} Number of idle workers
|
|
146
|
+
*/
|
|
147
|
+
getIdleWorkers() {
|
|
148
|
+
return this.workers.filter(w => w.status === 'idle').length;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get current queue size
|
|
153
|
+
* @returns {number} Number of queued tasks
|
|
154
|
+
*/
|
|
155
|
+
getQueueSize() {
|
|
156
|
+
return this.taskQueue.length;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get pool statistics
|
|
161
|
+
* @returns {object} Pool statistics
|
|
162
|
+
*/
|
|
163
|
+
getStats() {
|
|
164
|
+
return {
|
|
165
|
+
totalWorkers: this.workers.length,
|
|
166
|
+
activeWorkers: this.getActiveWorkers(),
|
|
167
|
+
idleWorkers: this.getIdleWorkers(),
|
|
168
|
+
queueSize: this.getQueueSize(),
|
|
169
|
+
activeTasks: this.activeTasks
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Shutdown the pool gracefully
|
|
175
|
+
* Waits for active tasks to complete
|
|
176
|
+
* @returns {Promise<void>}
|
|
177
|
+
*/
|
|
178
|
+
async shutdown() {
|
|
179
|
+
this.isShutdown = true;
|
|
180
|
+
|
|
181
|
+
// Wait for all active tasks to complete
|
|
182
|
+
while (this.activeTasks > 0) {
|
|
183
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Clear queue and reject pending tasks
|
|
187
|
+
while (this.taskQueue.length > 0) {
|
|
188
|
+
const { reject } = this.taskQueue.shift();
|
|
189
|
+
reject(new Error('Worker pool shutdown'));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = { WorkerPool, Worker };
|