chati-dev 4.3.1 → 4.4.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/README.md +18 -13
- package/bin/chati.js +28 -4
- package/framework/agents/build/dev.md +5 -1
- package/framework/agents/discover/greenfield-wu.md +16 -1
- 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 +24 -21
- package/framework/config.yaml +5 -4
- package/framework/constitution.md +60 -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/manifest.json +1351 -0
- package/framework/manifest.sig +1 -0
- package/framework/orchestrator/chati-router.js +1 -1
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +24 -3
- package/framework/quality-gates/planning-gate.md +2 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
- 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 +87 -1
- package/framework/tasks/orchestrator-health.md +4 -4
- package/framework/tasks/qa-impl-verdict.md +11 -5
- package/framework/templates/qa-gate-tmpl.yaml +24 -11
- package/package.json +4 -4
- package/src/config/claude-settings-generator.js +9 -6
- 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 +35 -4
- package/src/installer/manifest.js +30 -4
- package/src/installer/signing-public-key.pem +1 -1
- package/src/installer/templates.js +5 -6
- package/src/installer/validator.js +2 -1
- package/src/intelligence/registry-manager.js +3 -2
- 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 +7 -2
- package/src/memory/session-digest.js +9 -4
- package/src/orchestrator/cli.js +195 -23
- package/src/orchestrator/deviation-handler.js +5 -3
- package/src/orchestrator/doctor.js +98 -16
- package/src/orchestrator/pipeline-manager.js +44 -22
- package/src/orchestrator/session-manager.js +56 -8
- package/src/telemetry/sender.js +7 -19
- package/src/terminal/run-parallel.js +14 -14
- package/src/terminal/run-team.js +3 -3
- package/src/upgrade/backup.js +22 -44
- package/src/upgrade/migrator.js +51 -12
- package/src/upgrade/tracked-files-detector.js +34 -16
- package/src/utils/constitution-meta.js +12 -0
- package/src/utils/feature-flags.js +26 -2
- 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
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Cause analysis for failed build loop tasks.
|
|
3
|
-
*
|
|
4
|
-
* Analyzes agent output to classify failure categories, detect
|
|
5
|
-
* repetitive patterns, and generate retry guidance.
|
|
6
|
-
*
|
|
7
|
-
* Constitution Article XVII — Execution Mode Governance.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// Failure Categories
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Categories of task failures.
|
|
16
|
-
* @enum {string}
|
|
17
|
-
*/
|
|
18
|
-
export const FAILURE_CATEGORIES = {
|
|
19
|
-
SYNTAX_ERROR: 'syntax_error',
|
|
20
|
-
TEST_FAILURE: 'test_failure',
|
|
21
|
-
LINT_VIOLATION: 'lint_violation',
|
|
22
|
-
TYPE_ERROR: 'type_error',
|
|
23
|
-
TIMEOUT: 'timeout',
|
|
24
|
-
SCOPE_VIOLATION: 'scope_violation',
|
|
25
|
-
DEPENDENCY: 'dependency',
|
|
26
|
-
RUNTIME_ERROR: 'runtime_error',
|
|
27
|
-
UNKNOWN: 'unknown',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Patterns for classifying failure output.
|
|
32
|
-
*/
|
|
33
|
-
const CATEGORY_PATTERNS = [
|
|
34
|
-
{ regex: /SyntaxError|Unexpected token|parsing error|unterminated/i, category: FAILURE_CATEGORIES.SYNTAX_ERROR },
|
|
35
|
-
{ regex: /test.*fail|assertion.*fail|expect.*receive|expected.*but got/i, category: FAILURE_CATEGORIES.TEST_FAILURE },
|
|
36
|
-
{ regex: /lint.*error|eslint|prettier.*error|formatting/i, category: FAILURE_CATEGORIES.LINT_VIOLATION },
|
|
37
|
-
{ regex: /TypeError|type.*mismatch|cannot read propert|is not a function/i, category: FAILURE_CATEGORIES.TYPE_ERROR },
|
|
38
|
-
{ regex: /timeout|ETIMEDOUT|exceeded.*time|timed out/i, category: FAILURE_CATEGORIES.TIMEOUT },
|
|
39
|
-
{ regex: /scope.*violation|cannot write|not allowed.*mode|Article XI/i, category: FAILURE_CATEGORIES.SCOPE_VIOLATION },
|
|
40
|
-
{ regex: /Cannot find module|ENOENT|module not found|import.*failed|missing dependency/i, category: FAILURE_CATEGORIES.DEPENDENCY },
|
|
41
|
-
{ regex: /ReferenceError|RangeError|Error:|runtime error|ENOMEM/i, category: FAILURE_CATEGORIES.RUNTIME_ERROR },
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Public API
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Analyze the cause of a task failure.
|
|
50
|
-
*
|
|
51
|
-
* @param {string} output - Agent output/error text
|
|
52
|
-
* @param {Array<{category: string, output: string}>} [previousAttempts=[]] - History of prior attempts
|
|
53
|
-
* @returns {{ category: string, rootCause: string, suggestion: string, isRepetitive: boolean }}
|
|
54
|
-
*/
|
|
55
|
-
export function analyzeCause(output, previousAttempts = []) {
|
|
56
|
-
const text = output || '';
|
|
57
|
-
const category = classifyOutput(text);
|
|
58
|
-
const rootCause = extractRootCause(text, category);
|
|
59
|
-
const suggestion = generateSuggestion(category, rootCause);
|
|
60
|
-
const isRepetitive = checkRepetitive(category, previousAttempts);
|
|
61
|
-
|
|
62
|
-
return { category, rootCause, suggestion, isRepetitive };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Build retry guidance for the next attempt based on cause analysis.
|
|
67
|
-
*
|
|
68
|
-
* @param {{ category: string, rootCause: string, suggestion: string, isRepetitive: boolean }} analysis
|
|
69
|
-
* @param {number} attempt - Current attempt number
|
|
70
|
-
* @returns {string} Guidance text for the agent
|
|
71
|
-
*/
|
|
72
|
-
export function buildRetryGuidance(analysis, attempt) {
|
|
73
|
-
const parts = [];
|
|
74
|
-
|
|
75
|
-
parts.push(`## Retry Guidance (Attempt ${attempt})`);
|
|
76
|
-
parts.push('');
|
|
77
|
-
parts.push(`**Previous failure**: ${analysis.category}`);
|
|
78
|
-
|
|
79
|
-
if (analysis.rootCause) {
|
|
80
|
-
parts.push(`**Root cause**: ${analysis.rootCause}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
parts.push(`**Suggestion**: ${analysis.suggestion}`);
|
|
84
|
-
|
|
85
|
-
if (analysis.isRepetitive) {
|
|
86
|
-
parts.push('');
|
|
87
|
-
parts.push('**WARNING**: This is a REPETITIVE failure. The same category of error occurred in previous attempts.');
|
|
88
|
-
parts.push('You MUST try a fundamentally different approach — do not repeat the same fix.');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return parts.join('\n');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// Internal Helpers
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Classify output text into a failure category.
|
|
100
|
-
*
|
|
101
|
-
* @param {string} text
|
|
102
|
-
* @returns {string}
|
|
103
|
-
*/
|
|
104
|
-
function classifyOutput(text) {
|
|
105
|
-
for (const { regex, category } of CATEGORY_PATTERNS) {
|
|
106
|
-
if (regex.test(text)) {
|
|
107
|
-
return category;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return FAILURE_CATEGORIES.UNKNOWN;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Extract a concise root cause from the output.
|
|
115
|
-
*
|
|
116
|
-
* @param {string} text
|
|
117
|
-
* @param {string} category
|
|
118
|
-
* @returns {string}
|
|
119
|
-
*/
|
|
120
|
-
function extractRootCause(text, category) {
|
|
121
|
-
if (!text) return 'No output available';
|
|
122
|
-
|
|
123
|
-
// Try to find the most informative error line
|
|
124
|
-
const lines = text.split('\n').filter(l => l.trim());
|
|
125
|
-
|
|
126
|
-
// Look for lines containing "Error:" or similar markers
|
|
127
|
-
const errorLine = lines.find(l =>
|
|
128
|
-
/error:|Error:|ERR!|FAIL|failed/i.test(l)
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
if (errorLine) {
|
|
132
|
-
return errorLine.trim().slice(0, 200);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Fall back to last non-empty line (often the summary)
|
|
136
|
-
if (lines.length > 0) {
|
|
137
|
-
return lines[lines.length - 1].trim().slice(0, 200);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return `${category} detected (no specific error line found)`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Generate a suggestion based on the failure category.
|
|
145
|
-
*
|
|
146
|
-
* @param {string} category
|
|
147
|
-
* @param {string} rootCause
|
|
148
|
-
* @returns {string}
|
|
149
|
-
*/
|
|
150
|
-
function generateSuggestion(category, _rootCause) {
|
|
151
|
-
const suggestions = {
|
|
152
|
-
[FAILURE_CATEGORIES.SYNTAX_ERROR]: 'Check for missing brackets, semicolons, or malformed expressions. Review the exact line mentioned in the error.',
|
|
153
|
-
[FAILURE_CATEGORIES.TEST_FAILURE]: 'Review the failing test assertions. Ensure the implementation matches the expected behavior described in the test.',
|
|
154
|
-
[FAILURE_CATEGORIES.LINT_VIOLATION]: 'Fix formatting and style issues. Check import ordering, unused variables, and indentation.',
|
|
155
|
-
[FAILURE_CATEGORIES.TYPE_ERROR]: 'Verify that variable types match expected types. Check for null/undefined access and incorrect function signatures.',
|
|
156
|
-
[FAILURE_CATEGORIES.TIMEOUT]: 'The operation took too long. Consider optimizing the approach or breaking the task into smaller pieces.',
|
|
157
|
-
[FAILURE_CATEGORIES.SCOPE_VIOLATION]: 'The write operation is outside the allowed scope for the current mode. Only modify files within the permitted directories.',
|
|
158
|
-
[FAILURE_CATEGORIES.DEPENDENCY]: 'A required module or dependency is missing. Ensure all imports reference existing files and packages are installed.',
|
|
159
|
-
[FAILURE_CATEGORIES.RUNTIME_ERROR]: 'A runtime error occurred during execution. Check for logic errors, invalid operations, and edge cases.',
|
|
160
|
-
[FAILURE_CATEGORIES.UNKNOWN]: 'Review the full output to identify the issue. The error does not match known patterns.',
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
return suggestions[category] || suggestions[FAILURE_CATEGORIES.UNKNOWN];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Check if the same failure category appeared in previous attempts.
|
|
168
|
-
*
|
|
169
|
-
* @param {string} category
|
|
170
|
-
* @param {Array<{category: string}>} previousAttempts
|
|
171
|
-
* @returns {boolean}
|
|
172
|
-
*/
|
|
173
|
-
function checkRepetitive(category, previousAttempts) {
|
|
174
|
-
if (category === FAILURE_CATEGORIES.UNKNOWN) return false;
|
|
175
|
-
const sameCategory = previousAttempts.filter(a => a.category === category);
|
|
176
|
-
return sameCategory.length >= 2;
|
|
177
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Progressive escalation for build loop retries.
|
|
3
|
-
*
|
|
4
|
-
* When a task fails repeatedly, escalation progressively increases
|
|
5
|
-
* the resources (model tier, context enrichment) and ultimately
|
|
6
|
-
* pauses for human intervention.
|
|
7
|
-
*
|
|
8
|
-
* Constitution Article XVII — Execution Mode Governance.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
// Escalation Levels
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Escalation level definitions.
|
|
17
|
-
* @enum {number}
|
|
18
|
-
*/
|
|
19
|
-
export const ESCALATION_LEVELS = {
|
|
20
|
-
/** Standard — use configured model, no extra context. */
|
|
21
|
-
STANDARD: 0,
|
|
22
|
-
/** Enriched — same model, inject cause analysis + retry guidance. */
|
|
23
|
-
ENRICHED: 1,
|
|
24
|
-
/** Upgraded — escalate to higher-tier model (e.g. sonnet → opus). */
|
|
25
|
-
UPGRADED: 2,
|
|
26
|
-
/** Max — pause execution and request human intervention. */
|
|
27
|
-
MAX: 3,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Model upgrade map — maps current model tier to the next tier.
|
|
32
|
-
* Keys are logical tier names used in chati config.
|
|
33
|
-
*/
|
|
34
|
-
const MODEL_UPGRADE_MAP = {
|
|
35
|
-
haiku: 'sonnet',
|
|
36
|
-
sonnet: 'opus',
|
|
37
|
-
opus: 'opus', // opus is ceiling
|
|
38
|
-
// Gemini equivalents
|
|
39
|
-
flash: 'pro',
|
|
40
|
-
pro: 'pro',
|
|
41
|
-
// Codex equivalents
|
|
42
|
-
codex: 'codex',
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Thresholds for automatic escalation.
|
|
47
|
-
*/
|
|
48
|
-
const ESCALATION_THRESHOLDS = {
|
|
49
|
-
/** Attempts before escalating from STANDARD to ENRICHED. */
|
|
50
|
-
ENRICHED_AFTER: 2,
|
|
51
|
-
/** Attempts before escalating from ENRICHED to UPGRADED. */
|
|
52
|
-
UPGRADED_AFTER: 4,
|
|
53
|
-
/** Attempts before escalating from UPGRADED to MAX. */
|
|
54
|
-
MAX_AFTER: 7,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
// Public API
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Get the current escalation level for a task checkpoint.
|
|
63
|
-
*
|
|
64
|
-
* @param {{ attempts: number, escalationLevel?: number }} checkpoint
|
|
65
|
-
* @returns {number} Current escalation level (0-3)
|
|
66
|
-
*/
|
|
67
|
-
export function getEscalationLevel(checkpoint) {
|
|
68
|
-
if (!checkpoint) return ESCALATION_LEVELS.STANDARD;
|
|
69
|
-
|
|
70
|
-
// Explicit level takes precedence (set by previous escalation)
|
|
71
|
-
if (typeof checkpoint.escalationLevel === 'number') {
|
|
72
|
-
return checkpoint.escalationLevel;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Derive from attempt count
|
|
76
|
-
const attempts = checkpoint.attempts || 0;
|
|
77
|
-
|
|
78
|
-
if (attempts >= ESCALATION_THRESHOLDS.MAX_AFTER) {
|
|
79
|
-
return ESCALATION_LEVELS.MAX;
|
|
80
|
-
}
|
|
81
|
-
if (attempts >= ESCALATION_THRESHOLDS.UPGRADED_AFTER) {
|
|
82
|
-
return ESCALATION_LEVELS.UPGRADED;
|
|
83
|
-
}
|
|
84
|
-
if (attempts >= ESCALATION_THRESHOLDS.ENRICHED_AFTER) {
|
|
85
|
-
return ESCALATION_LEVELS.ENRICHED;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return ESCALATION_LEVELS.STANDARD;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Determine whether escalation should occur based on checkpoint
|
|
93
|
-
* state and cause analysis.
|
|
94
|
-
*
|
|
95
|
-
* @param {{ attempts: number, escalationLevel?: number }} checkpoint
|
|
96
|
-
* @param {{ isRepetitive: boolean, category: string }} analysis - Cause analysis result
|
|
97
|
-
* @returns {{ escalate: boolean, newLevel: number, reason: string }}
|
|
98
|
-
*/
|
|
99
|
-
export function shouldEscalate(checkpoint, analysis) {
|
|
100
|
-
const currentLevel = getEscalationLevel(checkpoint);
|
|
101
|
-
const attempts = checkpoint?.attempts || 0;
|
|
102
|
-
|
|
103
|
-
// Already at max — no further escalation
|
|
104
|
-
if (currentLevel >= ESCALATION_LEVELS.MAX) {
|
|
105
|
-
return {
|
|
106
|
-
escalate: false,
|
|
107
|
-
newLevel: ESCALATION_LEVELS.MAX,
|
|
108
|
-
reason: 'Already at maximum escalation level',
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Repetitive failures trigger immediate escalation (+1 level)
|
|
113
|
-
if (analysis?.isRepetitive) {
|
|
114
|
-
const newLevel = Math.min(currentLevel + 1, ESCALATION_LEVELS.MAX);
|
|
115
|
-
return {
|
|
116
|
-
escalate: true,
|
|
117
|
-
newLevel,
|
|
118
|
-
reason: `Repetitive ${analysis.category} failure — escalating to level ${newLevel}`,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Threshold-based escalation
|
|
123
|
-
let targetLevel = ESCALATION_LEVELS.STANDARD;
|
|
124
|
-
if (attempts >= ESCALATION_THRESHOLDS.MAX_AFTER) {
|
|
125
|
-
targetLevel = ESCALATION_LEVELS.MAX;
|
|
126
|
-
} else if (attempts >= ESCALATION_THRESHOLDS.UPGRADED_AFTER) {
|
|
127
|
-
targetLevel = ESCALATION_LEVELS.UPGRADED;
|
|
128
|
-
} else if (attempts >= ESCALATION_THRESHOLDS.ENRICHED_AFTER) {
|
|
129
|
-
targetLevel = ESCALATION_LEVELS.ENRICHED;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (targetLevel > currentLevel) {
|
|
133
|
-
return {
|
|
134
|
-
escalate: true,
|
|
135
|
-
newLevel: targetLevel,
|
|
136
|
-
reason: `Attempt ${attempts} reached threshold for level ${targetLevel}`,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
escalate: false,
|
|
142
|
-
newLevel: currentLevel,
|
|
143
|
-
reason: 'No escalation needed',
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Get configuration for a given escalation level.
|
|
149
|
-
*
|
|
150
|
-
* @param {number} level - Escalation level (0-3)
|
|
151
|
-
* @param {string} [currentModel='sonnet'] - Current model tier name
|
|
152
|
-
* @returns {{ model: string|null, contextBoost: boolean, shouldPause: boolean, description: string }}
|
|
153
|
-
*/
|
|
154
|
-
export function getEscalationConfig(level, currentModel = 'sonnet') {
|
|
155
|
-
switch (level) {
|
|
156
|
-
case ESCALATION_LEVELS.STANDARD:
|
|
157
|
-
return {
|
|
158
|
-
model: null, // no override
|
|
159
|
-
contextBoost: false,
|
|
160
|
-
shouldPause: false,
|
|
161
|
-
description: 'Standard execution — no escalation',
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
case ESCALATION_LEVELS.ENRICHED:
|
|
165
|
-
return {
|
|
166
|
-
model: null, // same model
|
|
167
|
-
contextBoost: true,
|
|
168
|
-
shouldPause: false,
|
|
169
|
-
description: 'Enriched context — cause analysis + retry guidance injected',
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
case ESCALATION_LEVELS.UPGRADED:
|
|
173
|
-
return {
|
|
174
|
-
model: MODEL_UPGRADE_MAP[currentModel] || currentModel,
|
|
175
|
-
contextBoost: true,
|
|
176
|
-
shouldPause: false,
|
|
177
|
-
description: `Model upgraded from ${currentModel} to ${MODEL_UPGRADE_MAP[currentModel] || currentModel}`,
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
case ESCALATION_LEVELS.MAX:
|
|
181
|
-
return {
|
|
182
|
-
model: MODEL_UPGRADE_MAP[currentModel] || currentModel,
|
|
183
|
-
contextBoost: true,
|
|
184
|
-
shouldPause: true,
|
|
185
|
-
description: 'Maximum escalation — pausing for human intervention',
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
default:
|
|
189
|
-
return {
|
|
190
|
-
model: null,
|
|
191
|
-
contextBoost: false,
|
|
192
|
-
shouldPause: false,
|
|
193
|
-
description: `Unknown escalation level: ${level}`,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Build a human-readable escalation summary.
|
|
200
|
-
*
|
|
201
|
-
* @param {number} level - Escalation level
|
|
202
|
-
* @param {string} reason - Escalation reason
|
|
203
|
-
* @returns {string}
|
|
204
|
-
*/
|
|
205
|
-
export function buildEscalationSummary(level, reason) {
|
|
206
|
-
const levelNames = ['STANDARD', 'ENRICHED', 'UPGRADED', 'MAX'];
|
|
207
|
-
const name = levelNames[level] || 'UNKNOWN';
|
|
208
|
-
return `[Escalation ${name}] ${reason}`;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Exported for testing — escalation thresholds.
|
|
213
|
-
*/
|
|
214
|
-
export { ESCALATION_THRESHOLDS };
|
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
|
-
}
|