chati-dev 4.3.0 → 4.4.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/README.md +18 -13
- package/bin/chati.js +32 -4
- package/framework/agents/build/dev.md +9 -5
- package/framework/agents/discover/brief.md +2 -0
- package/framework/agents/discover/brownfield-wu.md +2 -0
- package/framework/agents/discover/greenfield-wu.md +18 -1
- package/framework/agents/plan/detail.md +2 -0
- package/framework/agents/plan/tasks.md +31 -0
- package/framework/agents/plan/ux-brand-architect.md +21 -2
- package/framework/agents/plan/ux-component-engineer.md +10 -0
- package/framework/agents/quality/qa-implementation.md +1 -1
- package/framework/agents/quality/qa-planning.md +1 -1
- package/framework/agents/quality/qa-visual.md +33 -21
- package/framework/config.yaml +5 -4
- package/framework/constitution.md +58 -11
- package/framework/context/governance.md +12 -10
- package/framework/context/root.md +2 -2
- package/framework/data/entity-registry.yaml +12 -4
- package/framework/data/qa-rubrics.yaml +335 -0
- package/framework/domains/constitution.yaml +3 -3
- package/framework/executors/json-validate.js +80 -0
- package/framework/executors/npm-script.js +72 -0
- package/framework/executors/path-check.js +67 -0
- package/framework/executors/registry.yaml +36 -0
- package/framework/hooks/advance-trigger.js +47 -3
- package/framework/hooks/constitution-guard.js +9 -4
- package/framework/hooks/git-push-authority.js +113 -0
- package/framework/hooks/license-guard.js +59 -9
- package/framework/hooks/model-governance.js +40 -17
- package/framework/hooks/prism-engine.js +78 -11
- package/framework/hooks/session-digest.js +12 -3
- package/framework/hooks/settings.json +7 -3
- package/framework/hooks/style-guard.js +52 -3
- package/framework/hooks/team-quality-gate.js +43 -5
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/confidence.yaml +85 -6
- package/framework/intelligence/context-engine.md +9 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/orchestrator/chati-router.js +59 -5
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +20 -1
- package/framework/quality-gates/planning-gate.md +2 -0
- package/framework/rules/human-writing-style.md +47 -0
- package/framework/scaffold/motion-premium/README.md +12 -2
- package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +1 -1
- package/framework/scaffold/motion-premium/scaffold.yaml +6 -1
- package/framework/scaffold/motion-premium-3d/README.md +10 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
- package/framework/scaffold/motion-premium-3d/scaffold.yaml +3 -0
- package/framework/scaffold/saas-dashboard/README.md +58 -0
- package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
- package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
- package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
- package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
- package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
- package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
- package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
- package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
- package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
- package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
- package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
- package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
- package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
- package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
- package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
- package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
- package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
- package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
- package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
- package/framework/schemas/session.schema.json +5 -0
- package/framework/schemas/task.schema.json +9 -0
- package/framework/scripts/visual-qa.js +101 -3
- package/framework/tasks/orchestrator-health.md +4 -4
- package/framework/tasks/qa-impl-verdict.md +11 -5
- package/framework/templates/brandbook-html-tmpl.md +1 -1
- package/framework/templates/qa-gate-tmpl.yaml +24 -11
- package/package.json +4 -3
- package/src/config/context-file-generator.js +0 -6
- package/src/dashboard/renderer.js +0 -36
- package/src/executors/runner.js +204 -0
- package/src/installer/core.js +13 -3
- package/src/installer/templates.js +5 -6
- package/src/intelligence/registry-manager.js +1 -1
- package/src/license/client.js +9 -3
- package/src/license/commands.js +12 -2
- package/src/license/machine-id.js +42 -1
- package/src/memory/gotchas.js +58 -40
- package/src/memory/magic-docs.js +1 -1
- package/src/memory/session-digest.js +9 -4
- package/src/orchestrator/cli.js +186 -15
- package/src/orchestrator/doctor.js +98 -16
- package/src/orchestrator/pipeline-manager.js +44 -22
- package/src/orchestrator/session-manager.js +64 -8
- package/src/telemetry/sender.js +7 -19
- package/src/terminal/run-team.js +3 -3
- package/src/upgrade/tracked-files-detector.js +34 -16
- package/src/utils/feature-flags.js +1 -1
- package/src/utils/flatten-entities.js +4 -40
- package/src/utils/schema-validator.js +0 -14
- package/src/wizard/i18n.js +3 -3
- package/src/api/index.js +0 -120
- package/src/autonomy/autonomous-gate.js +0 -294
- package/src/autonomy/build-loop.js +0 -281
- package/src/autonomy/build-state.js +0 -286
- package/src/autonomy/cause-analyzer.js +0 -177
- package/src/autonomy/escalation.js +0 -214
- package/src/autonomy/index.js +0 -51
- package/src/autonomy/mode-manager.js +0 -225
- package/src/autonomy/mode-suggester.js +0 -283
- package/src/autonomy/progress-reporter.js +0 -275
- package/src/autonomy/safety-net.js +0 -370
- package/src/config/agent-customizer.js +0 -231
- package/src/decision/analyzer.js +0 -291
- package/src/decision/engine.js +0 -250
- package/src/decision/index.js +0 -38
- package/src/decision/registry-healer.js +0 -468
- package/src/decision/registry-updater.js +0 -339
- package/src/extensions/loader.js +0 -145
- package/src/extensions/registry.js +0 -134
- package/src/gates/circuit-breaker.js +0 -151
- package/src/gates/g1-planning-complete.js +0 -154
- package/src/gates/g2-qa-planning.js +0 -156
- package/src/gates/g3-implementation.js +0 -215
- package/src/gates/g4-qa-implementation.js +0 -240
- package/src/gates/g5-deploy-ready.js +0 -181
- package/src/gates/gate-base.js +0 -185
- package/src/gates/index.js +0 -46
- package/src/health/auto-fix.js +0 -216
- package/src/health/engine.js +0 -246
- package/src/merger/semantic-merger.js +0 -292
- package/src/preview/detector.js +0 -238
- package/src/preview/index.js +0 -20
- package/src/preview/launcher.js +0 -235
- package/src/preview/log-buffer.js +0 -103
- package/src/quality/metrics-collector.js +0 -281
- package/src/quality/test-runner.js +0 -366
- package/src/tasks/executor.js +0 -195
- package/src/tasks/index.js +0 -4
- package/src/tasks/loader.js +0 -210
- package/src/tasks/router.js +0 -182
- package/src/utils/event-bus.js +0 -126
package/src/autonomy/index.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Autonomy module barrel exports
|
|
3
|
-
* Execution modes, quality gates, progress reporting, and safety nets
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
EXECUTION_MODES,
|
|
8
|
-
getCurrentMode,
|
|
9
|
-
setExecutionMode,
|
|
10
|
-
canActAutonomously,
|
|
11
|
-
getAlwaysHumanAgents,
|
|
12
|
-
getModeHistory,
|
|
13
|
-
clearExecutionMode,
|
|
14
|
-
getModeStatistics,
|
|
15
|
-
} from './mode-manager.js';
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
suggestMode,
|
|
19
|
-
calculateRiskScore,
|
|
20
|
-
getHighRiskDomains,
|
|
21
|
-
} from './mode-suggester.js';
|
|
22
|
-
|
|
23
|
-
export {
|
|
24
|
-
GATE_RESULTS,
|
|
25
|
-
evaluateGate,
|
|
26
|
-
getGateThreshold,
|
|
27
|
-
resolveGateAction,
|
|
28
|
-
getGateHistory,
|
|
29
|
-
recordGateEvaluation,
|
|
30
|
-
getGateStatistics,
|
|
31
|
-
getAgentGateStatistics,
|
|
32
|
-
clearGateHistory,
|
|
33
|
-
} from './autonomous-gate.js';
|
|
34
|
-
|
|
35
|
-
export {
|
|
36
|
-
buildProgressReport,
|
|
37
|
-
formatProgressLine,
|
|
38
|
-
formatDetailedReport,
|
|
39
|
-
calculateCompletion,
|
|
40
|
-
getStageProgress,
|
|
41
|
-
} from './progress-reporter.js';
|
|
42
|
-
|
|
43
|
-
export {
|
|
44
|
-
SAFETY_TRIGGERS,
|
|
45
|
-
checkSafety,
|
|
46
|
-
evaluateTrigger,
|
|
47
|
-
getRecommendedAction,
|
|
48
|
-
getCriticalRiskKeywords,
|
|
49
|
-
isCriticalRisk,
|
|
50
|
-
buildSafetyReport,
|
|
51
|
-
} from './safety-net.js';
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Manages execution mode transitions for chati.dev
|
|
3
|
-
* Handles human-in-the-loop vs autonomous execution modes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { loadSession, updateSession } from '../orchestrator/session-manager.js';
|
|
7
|
-
|
|
8
|
-
export const EXECUTION_MODES = {
|
|
9
|
-
HUMAN_IN_THE_LOOP: 'human-in-the-loop',
|
|
10
|
-
AUTONOMOUS: 'autonomous',
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Agents that ALWAYS require human validation
|
|
14
|
-
const ALWAYS_HUMAN_AGENTS = ['brief', 'deviation'];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Get current execution mode from session.
|
|
18
|
-
* @param {string} projectDir
|
|
19
|
-
* @returns {{ mode: string, setAt: string|null, reason: string|null }}
|
|
20
|
-
*/
|
|
21
|
-
export function getCurrentMode(projectDir) {
|
|
22
|
-
const result = loadSession(projectDir);
|
|
23
|
-
|
|
24
|
-
if (!result.loaded || !result.session) {
|
|
25
|
-
return {
|
|
26
|
-
mode: EXECUTION_MODES.HUMAN_IN_THE_LOOP,
|
|
27
|
-
setAt: null,
|
|
28
|
-
reason: null,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const session = result.session;
|
|
33
|
-
|
|
34
|
-
if (!session.execution_mode) {
|
|
35
|
-
return {
|
|
36
|
-
mode: EXECUTION_MODES.HUMAN_IN_THE_LOOP,
|
|
37
|
-
setAt: null,
|
|
38
|
-
reason: null,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
mode: session.execution_mode.mode || EXECUTION_MODES.HUMAN_IN_THE_LOOP,
|
|
44
|
-
setAt: session.execution_mode.setAt || null,
|
|
45
|
-
reason: session.execution_mode.reason || null,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Set execution mode with reason and persist to session.
|
|
51
|
-
* @param {string} projectDir
|
|
52
|
-
* @param {string} mode - 'human-in-the-loop' | 'autonomous'
|
|
53
|
-
* @param {string} reason - Why this mode was selected
|
|
54
|
-
* @returns {{ set: boolean, previous: string }}
|
|
55
|
-
*/
|
|
56
|
-
export function setExecutionMode(projectDir, mode, reason) {
|
|
57
|
-
if (!Object.values(EXECUTION_MODES).includes(mode)) {
|
|
58
|
-
throw new Error(`Invalid execution mode: ${mode}`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const result = loadSession(projectDir);
|
|
62
|
-
|
|
63
|
-
if (!result.loaded || !result.session) {
|
|
64
|
-
return {
|
|
65
|
-
set: false,
|
|
66
|
-
previous: EXECUTION_MODES.HUMAN_IN_THE_LOOP,
|
|
67
|
-
error: result.error || 'Failed to load session',
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const session = result.session;
|
|
72
|
-
const previous = session.execution_mode?.mode || EXECUTION_MODES.HUMAN_IN_THE_LOOP;
|
|
73
|
-
|
|
74
|
-
// Initialize mode_transitions array if it doesn't exist
|
|
75
|
-
if (!session.mode_transitions) {
|
|
76
|
-
session.mode_transitions = [];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Record the transition
|
|
80
|
-
const transition = {
|
|
81
|
-
from: previous,
|
|
82
|
-
to: mode,
|
|
83
|
-
timestamp: new Date().toISOString(),
|
|
84
|
-
reason,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
session.mode_transitions.push(transition);
|
|
88
|
-
|
|
89
|
-
// Update current mode
|
|
90
|
-
const updates = {
|
|
91
|
-
execution_mode: {
|
|
92
|
-
mode,
|
|
93
|
-
setAt: transition.timestamp,
|
|
94
|
-
reason,
|
|
95
|
-
},
|
|
96
|
-
mode_transitions: session.mode_transitions,
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
updateSession(projectDir, updates);
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
set: true,
|
|
103
|
-
previous,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Check if current mode allows autonomous action for a given agent.
|
|
109
|
-
* Even in autonomous mode, some agents always require human input (brief, deviation).
|
|
110
|
-
* @param {string} mode
|
|
111
|
-
* @param {string} agentName
|
|
112
|
-
* @returns {{ allowed: boolean, reason: string }}
|
|
113
|
-
*/
|
|
114
|
-
export function canActAutonomously(mode, agentName) {
|
|
115
|
-
// Brief and deviation ALWAYS require human input
|
|
116
|
-
if (ALWAYS_HUMAN_AGENTS.includes(agentName)) {
|
|
117
|
-
return {
|
|
118
|
-
allowed: false,
|
|
119
|
-
reason: `${agentName} always requires human interaction`,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// In human-in-the-loop mode, nothing is autonomous
|
|
124
|
-
if (mode === EXECUTION_MODES.HUMAN_IN_THE_LOOP) {
|
|
125
|
-
return {
|
|
126
|
-
allowed: false,
|
|
127
|
-
reason: 'Human-in-the-loop mode requires user validation',
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// In autonomous mode, all non-always-human agents can act autonomously
|
|
132
|
-
return {
|
|
133
|
-
allowed: true,
|
|
134
|
-
reason: 'Autonomous mode enabled for this agent',
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Get agents that ALWAYS require human validation regardless of mode.
|
|
140
|
-
* @returns {string[]}
|
|
141
|
-
*/
|
|
142
|
-
export function getAlwaysHumanAgents() {
|
|
143
|
-
return [...ALWAYS_HUMAN_AGENTS];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get mode transition history.
|
|
148
|
-
* @param {string} projectDir
|
|
149
|
-
* @returns {object[]}
|
|
150
|
-
*/
|
|
151
|
-
export function getModeHistory(projectDir) {
|
|
152
|
-
const result = loadSession(projectDir);
|
|
153
|
-
if (!result.loaded || !result.session) {
|
|
154
|
-
return [];
|
|
155
|
-
}
|
|
156
|
-
return result.session.mode_transitions || [];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Clear execution mode (reset to default).
|
|
161
|
-
* @param {string} projectDir
|
|
162
|
-
* @returns {{ cleared: boolean }}
|
|
163
|
-
*/
|
|
164
|
-
export function clearExecutionMode(projectDir) {
|
|
165
|
-
const result = loadSession(projectDir);
|
|
166
|
-
|
|
167
|
-
if (!result.loaded || !result.session) {
|
|
168
|
-
return {
|
|
169
|
-
cleared: false,
|
|
170
|
-
error: result.error || 'Failed to load session',
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const previous = result.session.execution_mode;
|
|
175
|
-
|
|
176
|
-
updateSession(projectDir, { execution_mode: null });
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
cleared: true,
|
|
180
|
-
previous: previous || null,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Get mode statistics from history.
|
|
186
|
-
* @param {string} projectDir
|
|
187
|
-
* @returns {{ totalTransitions: number, timeInAutonomous: number, timeInHuman: number, currentStreak: number }}
|
|
188
|
-
*/
|
|
189
|
-
export function getModeStatistics(projectDir) {
|
|
190
|
-
const history = getModeHistory(projectDir);
|
|
191
|
-
const current = getCurrentMode(projectDir);
|
|
192
|
-
|
|
193
|
-
let timeInAutonomous = 0;
|
|
194
|
-
let timeInHuman = 0;
|
|
195
|
-
let currentStreak = 0;
|
|
196
|
-
|
|
197
|
-
for (let i = 0; i < history.length; i++) {
|
|
198
|
-
const transition = history[i];
|
|
199
|
-
const nextTransition = history[i + 1];
|
|
200
|
-
|
|
201
|
-
// Calculate time in each mode
|
|
202
|
-
if (nextTransition) {
|
|
203
|
-
const duration = new Date(nextTransition.timestamp) - new Date(transition.timestamp);
|
|
204
|
-
if (transition.to === EXECUTION_MODES.AUTONOMOUS) {
|
|
205
|
-
timeInAutonomous += duration;
|
|
206
|
-
} else {
|
|
207
|
-
timeInHuman += duration;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Calculate current streak
|
|
212
|
-
if (transition.to === current.mode) {
|
|
213
|
-
currentStreak++;
|
|
214
|
-
} else {
|
|
215
|
-
currentStreak = 0;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
totalTransitions: history.length,
|
|
221
|
-
timeInAutonomous: Math.floor(timeInAutonomous / 1000), // seconds
|
|
222
|
-
timeInHuman: Math.floor(timeInHuman / 1000), // seconds
|
|
223
|
-
currentStreak,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Suggests optimal execution mode based on project context
|
|
3
|
-
* Analyzes risk factors to recommend human-in-the-loop vs autonomous execution
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { EXECUTION_MODES } from './mode-manager.js';
|
|
7
|
-
|
|
8
|
-
// Factor weights for mode suggestion
|
|
9
|
-
const WEIGHTS = {
|
|
10
|
-
GREENFIELD: 30,
|
|
11
|
-
HIGH_TASK_COUNT: 20,
|
|
12
|
-
RISK_DOMAIN: 25,
|
|
13
|
-
HAS_HISTORY: 25,
|
|
14
|
-
RECENT_GOTCHA: 15,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// Risk domains that increase score towards human-in-the-loop
|
|
18
|
-
const HIGH_RISK_DOMAINS = [
|
|
19
|
-
'security',
|
|
20
|
-
'database',
|
|
21
|
-
'infrastructure',
|
|
22
|
-
'authentication',
|
|
23
|
-
'authorization',
|
|
24
|
-
'payment',
|
|
25
|
-
'data-migration',
|
|
26
|
-
'encryption',
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Suggest execution mode based on project context.
|
|
31
|
-
*
|
|
32
|
-
* Factors:
|
|
33
|
-
* - Project type: greenfield → human (higher risk), brownfield → autonomous
|
|
34
|
-
* - Complexity: high (>10 tasks) → human, low → autonomous
|
|
35
|
-
* - Risk: security/infra → human, UI/docs → autonomous
|
|
36
|
-
* - History: first time → human, executed before → autonomous
|
|
37
|
-
* - Gotchas: recent gotchas in domain → human
|
|
38
|
-
*
|
|
39
|
-
* @param {object} context
|
|
40
|
-
* @param {boolean} context.isGreenfield
|
|
41
|
-
* @param {number} [context.taskCount] - Estimated task count
|
|
42
|
-
* @param {string[]} [context.riskDomains] - e.g. ['security', 'database', 'infrastructure']
|
|
43
|
-
* @param {boolean} [context.hasHistory] - Project was built before
|
|
44
|
-
* @param {number} [context.recentGotchas] - Number of recent gotchas
|
|
45
|
-
* @returns {{ suggestion: string, confidence: number, factors: object[], reasoning: string }}
|
|
46
|
-
*/
|
|
47
|
-
export function suggestMode(context) {
|
|
48
|
-
const factors = [];
|
|
49
|
-
let humanScore = 0;
|
|
50
|
-
|
|
51
|
-
// Factor 1: Project type
|
|
52
|
-
if (context.isGreenfield) {
|
|
53
|
-
humanScore += WEIGHTS.GREENFIELD;
|
|
54
|
-
factors.push({
|
|
55
|
-
name: 'project_type',
|
|
56
|
-
value: 'greenfield',
|
|
57
|
-
impact: WEIGHTS.GREENFIELD,
|
|
58
|
-
direction: 'human',
|
|
59
|
-
reason: 'Greenfield projects have higher uncertainty',
|
|
60
|
-
});
|
|
61
|
-
} else {
|
|
62
|
-
humanScore -= WEIGHTS.GREENFIELD;
|
|
63
|
-
factors.push({
|
|
64
|
-
name: 'project_type',
|
|
65
|
-
value: 'brownfield',
|
|
66
|
-
impact: -WEIGHTS.GREENFIELD,
|
|
67
|
-
direction: 'autonomous',
|
|
68
|
-
reason: 'Brownfield projects have established patterns',
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Factor 2: Task complexity
|
|
73
|
-
const taskCount = context.taskCount || 0;
|
|
74
|
-
if (taskCount > 10) {
|
|
75
|
-
humanScore += WEIGHTS.HIGH_TASK_COUNT;
|
|
76
|
-
factors.push({
|
|
77
|
-
name: 'task_count',
|
|
78
|
-
value: taskCount,
|
|
79
|
-
impact: WEIGHTS.HIGH_TASK_COUNT,
|
|
80
|
-
direction: 'human',
|
|
81
|
-
reason: `High task count (${taskCount}) increases complexity`,
|
|
82
|
-
});
|
|
83
|
-
} else if (taskCount > 0) {
|
|
84
|
-
factors.push({
|
|
85
|
-
name: 'task_count',
|
|
86
|
-
value: taskCount,
|
|
87
|
-
impact: 0,
|
|
88
|
-
direction: 'neutral',
|
|
89
|
-
reason: `Moderate task count (${taskCount}) is manageable`,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Factor 3: Risk domains
|
|
94
|
-
const riskDomains = context.riskDomains || [];
|
|
95
|
-
const highRiskCount = riskDomains.filter(domain =>
|
|
96
|
-
HIGH_RISK_DOMAINS.includes(domain.toLowerCase())
|
|
97
|
-
).length;
|
|
98
|
-
|
|
99
|
-
if (highRiskCount > 0) {
|
|
100
|
-
const riskImpact = Math.min(highRiskCount * WEIGHTS.RISK_DOMAIN, 75); // Cap at 75
|
|
101
|
-
humanScore += riskImpact;
|
|
102
|
-
factors.push({
|
|
103
|
-
name: 'risk_domains',
|
|
104
|
-
value: riskDomains,
|
|
105
|
-
impact: riskImpact,
|
|
106
|
-
direction: 'human',
|
|
107
|
-
reason: `High-risk domains detected: ${riskDomains.join(', ')}`,
|
|
108
|
-
});
|
|
109
|
-
} else if (riskDomains.length > 0) {
|
|
110
|
-
factors.push({
|
|
111
|
-
name: 'risk_domains',
|
|
112
|
-
value: riskDomains,
|
|
113
|
-
impact: 0,
|
|
114
|
-
direction: 'neutral',
|
|
115
|
-
reason: `Low-risk domains: ${riskDomains.join(', ')}`,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Factor 4: Project history
|
|
120
|
-
if (context.hasHistory) {
|
|
121
|
-
humanScore -= WEIGHTS.HAS_HISTORY;
|
|
122
|
-
factors.push({
|
|
123
|
-
name: 'history',
|
|
124
|
-
value: true,
|
|
125
|
-
impact: -WEIGHTS.HAS_HISTORY,
|
|
126
|
-
direction: 'autonomous',
|
|
127
|
-
reason: 'Project has been built before',
|
|
128
|
-
});
|
|
129
|
-
} else {
|
|
130
|
-
humanScore += WEIGHTS.HAS_HISTORY;
|
|
131
|
-
factors.push({
|
|
132
|
-
name: 'history',
|
|
133
|
-
value: false,
|
|
134
|
-
impact: WEIGHTS.HAS_HISTORY,
|
|
135
|
-
direction: 'human',
|
|
136
|
-
reason: 'First-time project execution',
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Factor 5: Recent gotchas
|
|
141
|
-
const recentGotchas = context.recentGotchas || 0;
|
|
142
|
-
if (recentGotchas > 0) {
|
|
143
|
-
const gotchaImpact = Math.min(recentGotchas * WEIGHTS.RECENT_GOTCHA, 45); // Cap at 3 gotchas
|
|
144
|
-
humanScore += gotchaImpact;
|
|
145
|
-
factors.push({
|
|
146
|
-
name: 'gotchas',
|
|
147
|
-
value: recentGotchas,
|
|
148
|
-
impact: gotchaImpact,
|
|
149
|
-
direction: 'human',
|
|
150
|
-
reason: `${recentGotchas} recent gotcha(s) detected`,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Calculate confidence based on factor strength
|
|
155
|
-
const totalImpact = factors.reduce((sum, f) => sum + Math.abs(f.impact), 0);
|
|
156
|
-
const confidence = Math.min(Math.round((totalImpact / 150) * 100), 100);
|
|
157
|
-
|
|
158
|
-
// Determine suggestion
|
|
159
|
-
const suggestion = humanScore > 50
|
|
160
|
-
? EXECUTION_MODES.HUMAN_IN_THE_LOOP
|
|
161
|
-
: EXECUTION_MODES.AUTONOMOUS;
|
|
162
|
-
|
|
163
|
-
// Build reasoning
|
|
164
|
-
const reasoning = buildReasoning(suggestion, humanScore, factors);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
suggestion,
|
|
168
|
-
confidence,
|
|
169
|
-
factors,
|
|
170
|
-
reasoning,
|
|
171
|
-
score: humanScore,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Calculate risk score from project context.
|
|
177
|
-
* @param {object} context
|
|
178
|
-
* @returns {{ score: number, level: 'low'|'medium'|'high', factors: string[] }}
|
|
179
|
-
*/
|
|
180
|
-
export function calculateRiskScore(context) {
|
|
181
|
-
const riskFactors = [];
|
|
182
|
-
let score = 0;
|
|
183
|
-
|
|
184
|
-
// Greenfield adds base risk
|
|
185
|
-
if (context.isGreenfield) {
|
|
186
|
-
score += 25;
|
|
187
|
-
riskFactors.push('greenfield project');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// High task count adds complexity risk
|
|
191
|
-
if (context.taskCount > 10) {
|
|
192
|
-
score += 20;
|
|
193
|
-
riskFactors.push(`high task count (${context.taskCount})`);
|
|
194
|
-
} else if (context.taskCount > 5) {
|
|
195
|
-
score += 10;
|
|
196
|
-
riskFactors.push(`moderate task count (${context.taskCount})`);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Risk domains
|
|
200
|
-
const riskDomains = context.riskDomains || [];
|
|
201
|
-
const highRiskCount = riskDomains.filter(domain =>
|
|
202
|
-
HIGH_RISK_DOMAINS.includes(domain.toLowerCase())
|
|
203
|
-
).length;
|
|
204
|
-
|
|
205
|
-
score += highRiskCount * 15;
|
|
206
|
-
if (highRiskCount > 0) {
|
|
207
|
-
riskFactors.push(`${highRiskCount} high-risk domain(s)`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// No history adds risk
|
|
211
|
-
if (!context.hasHistory) {
|
|
212
|
-
score += 15;
|
|
213
|
-
riskFactors.push('no project history');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Recent gotchas
|
|
217
|
-
if (context.recentGotchas > 0) {
|
|
218
|
-
score += Math.min(context.recentGotchas * 10, 30);
|
|
219
|
-
riskFactors.push(`${context.recentGotchas} recent gotcha(s)`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Determine level
|
|
223
|
-
let level;
|
|
224
|
-
if (score < 30) {
|
|
225
|
-
level = 'low';
|
|
226
|
-
} else if (score < 60) {
|
|
227
|
-
level = 'medium';
|
|
228
|
-
} else {
|
|
229
|
-
level = 'high';
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
score,
|
|
234
|
-
level,
|
|
235
|
-
factors: riskFactors,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Build human-readable reasoning for mode suggestion.
|
|
241
|
-
* @param {string} suggestion
|
|
242
|
-
* @param {number} score
|
|
243
|
-
* @param {object[]} factors
|
|
244
|
-
* @returns {string}
|
|
245
|
-
*/
|
|
246
|
-
function buildReasoning(suggestion, score, factors) {
|
|
247
|
-
const lines = [];
|
|
248
|
-
|
|
249
|
-
if (suggestion === EXECUTION_MODES.HUMAN_IN_THE_LOOP) {
|
|
250
|
-
lines.push(`Recommending human-in-the-loop mode (score: ${Math.round(score)}/100 towards human).`);
|
|
251
|
-
} else {
|
|
252
|
-
lines.push(`Recommending autonomous mode (score: ${Math.round(score)}/100 towards human, below threshold).`);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const humanFactors = factors.filter(f => f.direction === 'human');
|
|
256
|
-
const autoFactors = factors.filter(f => f.direction === 'autonomous');
|
|
257
|
-
|
|
258
|
-
if (humanFactors.length > 0) {
|
|
259
|
-
lines.push('');
|
|
260
|
-
lines.push('Factors favoring human validation:');
|
|
261
|
-
humanFactors.forEach(f => {
|
|
262
|
-
lines.push(` • ${f.reason} (+${f.impact})`);
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (autoFactors.length > 0) {
|
|
267
|
-
lines.push('');
|
|
268
|
-
lines.push('Factors favoring autonomous execution:');
|
|
269
|
-
autoFactors.forEach(f => {
|
|
270
|
-
lines.push(` • ${f.reason} (${f.impact})`);
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return lines.join('\n');
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Get high-risk domain list.
|
|
279
|
-
* @returns {string[]}
|
|
280
|
-
*/
|
|
281
|
-
export function getHighRiskDomains() {
|
|
282
|
-
return [...HIGH_RISK_DOMAINS];
|
|
283
|
-
}
|