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,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StateMachine Core - Story 4.1
|
|
3
|
+
* Manages workflow state transitions for BYAN v2 orchestrator
|
|
4
|
+
*
|
|
5
|
+
* States: INTERVIEW → ANALYSIS → GENERATION → COMPLETED (+ ERROR from any state)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const Logger = require('../observability/logger');
|
|
9
|
+
const ErrorTracker = require('../observability/error-tracker');
|
|
10
|
+
|
|
11
|
+
class StateMachine {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.logger = options.logger || new Logger();
|
|
14
|
+
this.errorTracker = options.errorTracker || new ErrorTracker();
|
|
15
|
+
|
|
16
|
+
// AC1: Define five states
|
|
17
|
+
this.STATES = {
|
|
18
|
+
INTERVIEW: 'INTERVIEW',
|
|
19
|
+
ANALYSIS: 'ANALYSIS',
|
|
20
|
+
GENERATION: 'GENERATION',
|
|
21
|
+
COMPLETED: 'COMPLETED',
|
|
22
|
+
ERROR: 'ERROR'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// AC2: Valid state transitions
|
|
26
|
+
this.validTransitions = {
|
|
27
|
+
INTERVIEW: ['ANALYSIS', 'ERROR'],
|
|
28
|
+
ANALYSIS: ['GENERATION', 'ERROR'],
|
|
29
|
+
GENERATION: ['COMPLETED', 'ERROR'],
|
|
30
|
+
COMPLETED: [], // Terminal state
|
|
31
|
+
ERROR: [] // Terminal state
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// State metadata
|
|
35
|
+
this.currentState = this.STATES.INTERVIEW;
|
|
36
|
+
this.stateMetadata = {
|
|
37
|
+
name: this.STATES.INTERVIEW,
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
attempts: 0
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// AC5: Hooks for state enter/exit
|
|
43
|
+
this.enterHooks = {}; // { stateName: [callbacks] }
|
|
44
|
+
this.exitHooks = {}; // { stateName: [callbacks] }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* AC3: Validate and execute state transition
|
|
49
|
+
* @param {string} newState - Target state
|
|
50
|
+
* @returns {Object} { success, previousState, newState, error? }
|
|
51
|
+
*/
|
|
52
|
+
transition(newState) {
|
|
53
|
+
const previousState = this.currentState;
|
|
54
|
+
|
|
55
|
+
// Validate newState exists
|
|
56
|
+
if (!newState || !this.STATES[newState]) {
|
|
57
|
+
const error = new Error(`Unknown state: ${newState}`);
|
|
58
|
+
this.errorTracker.trackError({
|
|
59
|
+
error,
|
|
60
|
+
component: 'StateMachine',
|
|
61
|
+
operation: 'transition',
|
|
62
|
+
currentState: this.currentState,
|
|
63
|
+
attemptedState: newState
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: error.message
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Validate transition is allowed
|
|
72
|
+
if (!this.validTransitions[this.currentState].includes(newState)) {
|
|
73
|
+
const error = new Error(
|
|
74
|
+
`Invalid transition from ${this.currentState} to ${newState}`
|
|
75
|
+
);
|
|
76
|
+
this.errorTracker.trackError({
|
|
77
|
+
error,
|
|
78
|
+
component: 'StateMachine',
|
|
79
|
+
operation: 'transition',
|
|
80
|
+
currentState: this.currentState,
|
|
81
|
+
attemptedState: newState
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: error.message
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Execute transition with hooks
|
|
90
|
+
try {
|
|
91
|
+
// AC5: Call exit hooks
|
|
92
|
+
this._executeHooks(this.exitHooks[this.currentState], {
|
|
93
|
+
from: this.currentState,
|
|
94
|
+
to: newState
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Update state
|
|
98
|
+
this.currentState = newState;
|
|
99
|
+
this.stateMetadata = {
|
|
100
|
+
name: newState,
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
attempts: 0
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// AC5: Call enter hooks
|
|
106
|
+
this._executeHooks(this.enterHooks[newState], {
|
|
107
|
+
from: previousState,
|
|
108
|
+
to: newState
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Log successful transition
|
|
112
|
+
this.logger.info('State transition', {
|
|
113
|
+
from: previousState,
|
|
114
|
+
to: newState,
|
|
115
|
+
timestamp: this.stateMetadata.timestamp
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
success: true,
|
|
120
|
+
previousState,
|
|
121
|
+
newState
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
// If hooks fail, track but complete transition
|
|
125
|
+
this.errorTracker.trackError({
|
|
126
|
+
error,
|
|
127
|
+
component: 'StateMachine',
|
|
128
|
+
operation: 'transition-hooks',
|
|
129
|
+
state: newState
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
success: true,
|
|
134
|
+
previousState,
|
|
135
|
+
newState,
|
|
136
|
+
hookError: error.message
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* AC4: Get current state with metadata
|
|
143
|
+
* @returns {Object} { name, timestamp, attempts }
|
|
144
|
+
*/
|
|
145
|
+
getCurrentState() {
|
|
146
|
+
return { ...this.stateMetadata };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Increment retry attempts for current state
|
|
151
|
+
*/
|
|
152
|
+
incrementAttempts() {
|
|
153
|
+
this.stateMetadata.attempts++;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* AC5: Register state enter hook
|
|
158
|
+
* @param {string} stateName - State to hook into
|
|
159
|
+
* @param {Function} callback - Hook function
|
|
160
|
+
*/
|
|
161
|
+
onStateEnter(stateName, callback) {
|
|
162
|
+
if (!this.enterHooks[stateName]) {
|
|
163
|
+
this.enterHooks[stateName] = [];
|
|
164
|
+
}
|
|
165
|
+
this.enterHooks[stateName].push(callback);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* AC5: Register state exit hook
|
|
170
|
+
* @param {string} stateName - State to hook into
|
|
171
|
+
* @param {Function} callback - Hook function
|
|
172
|
+
*/
|
|
173
|
+
onStateExit(stateName, callback) {
|
|
174
|
+
if (!this.exitHooks[stateName]) {
|
|
175
|
+
this.exitHooks[stateName] = [];
|
|
176
|
+
}
|
|
177
|
+
this.exitHooks[stateName].push(callback);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Execute all hooks for a state
|
|
182
|
+
* @private
|
|
183
|
+
*/
|
|
184
|
+
_executeHooks(hooks, context) {
|
|
185
|
+
if (!hooks || hooks.length === 0) return;
|
|
186
|
+
|
|
187
|
+
hooks.forEach(hook => {
|
|
188
|
+
try {
|
|
189
|
+
hook(context);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// Track hook error but don't block transition
|
|
192
|
+
this.errorTracker.trackError({
|
|
193
|
+
error,
|
|
194
|
+
component: 'StateMachine',
|
|
195
|
+
operation: 'hook-execution',
|
|
196
|
+
context
|
|
197
|
+
});
|
|
198
|
+
throw error; // Re-throw to be caught by transition()
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = StateMachine;
|
|
@@ -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;
|