chati-dev 4.3.1 → 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 +12 -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 +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 +1 -1
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +19 -1
- 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 +3 -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 +2 -1
- 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 +174 -14
- 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-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
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Real code execution validation.
|
|
3
|
-
*
|
|
4
|
-
* Detects test runners, executes tests and lint commands,
|
|
5
|
-
* and parses output for structured results.
|
|
6
|
-
*
|
|
7
|
-
* Constitution Article XIV — Framework Registry Governance.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { existsSync, readFileSync } from 'fs';
|
|
11
|
-
import { join } from 'path';
|
|
12
|
-
import { execSync } from 'child_process';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Test Runner Detection
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {object} TestDetection
|
|
20
|
-
* @property {string|null} command - Test command to run
|
|
21
|
-
* @property {string} runner - Detected runner name (node:test|jest|vitest|mocha|unknown)
|
|
22
|
-
* @property {boolean} detected - Whether a test setup was found
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Detect the test command and runner for a project.
|
|
27
|
-
*
|
|
28
|
-
* Detection order:
|
|
29
|
-
* 1. package.json scripts.test
|
|
30
|
-
* 2. vitest.config.* presence
|
|
31
|
-
* 3. jest.config.* presence
|
|
32
|
-
* 4. .mocharc.* presence
|
|
33
|
-
*
|
|
34
|
-
* @param {string} projectDir - Project root directory
|
|
35
|
-
* @returns {TestDetection}
|
|
36
|
-
*/
|
|
37
|
-
export function detectTestCommand(projectDir) {
|
|
38
|
-
const pkgPath = join(projectDir, 'package.json');
|
|
39
|
-
|
|
40
|
-
// Check package.json scripts.test
|
|
41
|
-
if (existsSync(pkgPath)) {
|
|
42
|
-
try {
|
|
43
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
44
|
-
const testScript = pkg.scripts?.test;
|
|
45
|
-
|
|
46
|
-
if (testScript && testScript !== 'echo "Error: no test specified" && exit 1') {
|
|
47
|
-
const runner = detectRunnerFromScript(testScript);
|
|
48
|
-
return { command: 'npm test', runner, detected: true };
|
|
49
|
-
}
|
|
50
|
-
} catch { /* expected: package.json may be malformed or missing */
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Check for vitest.config.*
|
|
55
|
-
const vitestConfigs = ['vitest.config.ts', 'vitest.config.js', 'vitest.config.mts'];
|
|
56
|
-
for (const cfg of vitestConfigs) {
|
|
57
|
-
if (existsSync(join(projectDir, cfg))) {
|
|
58
|
-
return { command: 'npx vitest run', runner: 'vitest', detected: true };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Check for jest.config.*
|
|
63
|
-
const jestConfigs = ['jest.config.ts', 'jest.config.js', 'jest.config.json'];
|
|
64
|
-
for (const cfg of jestConfigs) {
|
|
65
|
-
if (existsSync(join(projectDir, cfg))) {
|
|
66
|
-
return { command: 'npx jest', runner: 'jest', detected: true };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Check for .mocharc.*
|
|
71
|
-
const mochaConfigs = ['.mocharc.yml', '.mocharc.yaml', '.mocharc.json', '.mocharc.js'];
|
|
72
|
-
for (const cfg of mochaConfigs) {
|
|
73
|
-
if (existsSync(join(projectDir, cfg))) {
|
|
74
|
-
return { command: 'npx mocha', runner: 'mocha', detected: true };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return { command: null, runner: 'unknown', detected: false };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Detect runner from a test script string.
|
|
83
|
-
*
|
|
84
|
-
* @param {string} script
|
|
85
|
-
* @returns {string}
|
|
86
|
-
*/
|
|
87
|
-
function detectRunnerFromScript(script) {
|
|
88
|
-
if (/node\s+--test/.test(script)) return 'node:test';
|
|
89
|
-
if (/vitest/.test(script)) return 'vitest';
|
|
90
|
-
if (/jest/.test(script)) return 'jest';
|
|
91
|
-
if (/mocha/.test(script)) return 'mocha';
|
|
92
|
-
if (/tap/.test(script)) return 'tap';
|
|
93
|
-
return 'unknown';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
// Test Execution
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @typedef {object} TestResult
|
|
102
|
-
* @property {boolean} success - All tests passed
|
|
103
|
-
* @property {number} total - Total test count
|
|
104
|
-
* @property {number} passed - Tests passed
|
|
105
|
-
* @property {number} failed - Tests failed
|
|
106
|
-
* @property {number} skipped - Tests skipped
|
|
107
|
-
* @property {number} duration - Execution time in ms
|
|
108
|
-
* @property {string} rawOutput - Full command output
|
|
109
|
-
* @property {string} runner - Detected runner
|
|
110
|
-
*/
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Run tests in a project directory.
|
|
114
|
-
*
|
|
115
|
-
* @param {string} projectDir
|
|
116
|
-
* @param {{ timeout?: number, command?: string }} [options={}]
|
|
117
|
-
* @returns {TestResult}
|
|
118
|
-
*/
|
|
119
|
-
export function runTests(projectDir, options = {}) {
|
|
120
|
-
const detection = detectTestCommand(projectDir);
|
|
121
|
-
const command = options.command || detection.command;
|
|
122
|
-
const timeout = options.timeout || 120_000;
|
|
123
|
-
|
|
124
|
-
if (!command) {
|
|
125
|
-
return {
|
|
126
|
-
success: false,
|
|
127
|
-
total: 0,
|
|
128
|
-
passed: 0,
|
|
129
|
-
failed: 0,
|
|
130
|
-
skipped: 0,
|
|
131
|
-
duration: 0,
|
|
132
|
-
rawOutput: 'No test command detected',
|
|
133
|
-
runner: 'unknown',
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const start = Date.now();
|
|
138
|
-
let rawOutput, exitCode;
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
rawOutput = execSync(command, {
|
|
142
|
-
cwd: projectDir,
|
|
143
|
-
encoding: 'utf-8',
|
|
144
|
-
timeout,
|
|
145
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
146
|
-
});
|
|
147
|
-
exitCode = 0;
|
|
148
|
-
} catch (err) {
|
|
149
|
-
exitCode = err.status || 1;
|
|
150
|
-
rawOutput = (err.stdout || '') + (err.stderr || '');
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const duration = Date.now() - start;
|
|
154
|
-
const parsed = parseTestOutput(rawOutput, detection.runner);
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
success: exitCode === 0 && parsed.failed === 0,
|
|
158
|
-
total: parsed.total,
|
|
159
|
-
passed: parsed.passed,
|
|
160
|
-
failed: parsed.failed,
|
|
161
|
-
skipped: parsed.skipped,
|
|
162
|
-
duration,
|
|
163
|
-
rawOutput: rawOutput.slice(0, 5000),
|
|
164
|
-
runner: detection.runner,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ---------------------------------------------------------------------------
|
|
169
|
-
// Lint Execution
|
|
170
|
-
// ---------------------------------------------------------------------------
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* @typedef {object} LintResult
|
|
174
|
-
* @property {boolean} success - No lint errors
|
|
175
|
-
* @property {number} errors - Error count
|
|
176
|
-
* @property {number} warnings - Warning count
|
|
177
|
-
* @property {string} rawOutput - Full command output
|
|
178
|
-
*/
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Run lint in a project directory.
|
|
182
|
-
*
|
|
183
|
-
* @param {string} projectDir
|
|
184
|
-
* @param {{ timeout?: number, command?: string }} [options={}]
|
|
185
|
-
* @returns {LintResult}
|
|
186
|
-
*/
|
|
187
|
-
export function runLint(projectDir, options = {}) {
|
|
188
|
-
const timeout = options.timeout || 60_000;
|
|
189
|
-
let command = options.command;
|
|
190
|
-
|
|
191
|
-
// Auto-detect lint command
|
|
192
|
-
if (!command) {
|
|
193
|
-
const pkgPath = join(projectDir, 'package.json');
|
|
194
|
-
if (existsSync(pkgPath)) {
|
|
195
|
-
try {
|
|
196
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
197
|
-
if (pkg.scripts?.lint) {
|
|
198
|
-
command = 'npm run lint';
|
|
199
|
-
}
|
|
200
|
-
} catch { /* expected: package.json may be malformed */
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!command) {
|
|
206
|
-
return { success: true, errors: 0, warnings: 0, rawOutput: 'No lint command detected' };
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let rawOutput, exitCode;
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
rawOutput = execSync(command, {
|
|
213
|
-
cwd: projectDir,
|
|
214
|
-
encoding: 'utf-8',
|
|
215
|
-
timeout,
|
|
216
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
217
|
-
});
|
|
218
|
-
exitCode = 0;
|
|
219
|
-
} catch (err) {
|
|
220
|
-
exitCode = err.status || 1;
|
|
221
|
-
rawOutput = (err.stdout || '') + (err.stderr || '');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const { errors, warnings } = parseLintOutput(rawOutput);
|
|
225
|
-
|
|
226
|
-
return {
|
|
227
|
-
success: exitCode === 0 && errors === 0,
|
|
228
|
-
errors,
|
|
229
|
-
warnings,
|
|
230
|
-
rawOutput: rawOutput.slice(0, 5000),
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// ---------------------------------------------------------------------------
|
|
235
|
-
// Output Parsing
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Parse test output to extract counts.
|
|
240
|
-
*
|
|
241
|
-
* @param {string} output
|
|
242
|
-
* @param {string} runner
|
|
243
|
-
* @returns {{ total: number, passed: number, failed: number, skipped: number }}
|
|
244
|
-
*/
|
|
245
|
-
export function parseTestOutput(output, runner) {
|
|
246
|
-
if (!output) {
|
|
247
|
-
return { total: 0, passed: 0, failed: 0, skipped: 0 };
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
switch (runner) {
|
|
251
|
-
case 'node:test':
|
|
252
|
-
return parseNodeTestOutput(output);
|
|
253
|
-
case 'jest':
|
|
254
|
-
return parseJestOutput(output);
|
|
255
|
-
case 'vitest':
|
|
256
|
-
return parseVitestOutput(output);
|
|
257
|
-
case 'mocha':
|
|
258
|
-
return parseMochaOutput(output);
|
|
259
|
-
default:
|
|
260
|
-
return parseGenericOutput(output);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Parse node:test TAP-like output.
|
|
266
|
-
*/
|
|
267
|
-
function parseNodeTestOutput(output) {
|
|
268
|
-
const testsMatch = output.match(/# tests (\d+)/);
|
|
269
|
-
const passMatch = output.match(/# pass (\d+)/);
|
|
270
|
-
const failMatch = output.match(/# fail (\d+)/);
|
|
271
|
-
const skipMatch = output.match(/# skipped (\d+)/);
|
|
272
|
-
|
|
273
|
-
const total = testsMatch ? parseInt(testsMatch[1], 10) : 0;
|
|
274
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
275
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
276
|
-
const skipped = skipMatch ? parseInt(skipMatch[1], 10) : 0;
|
|
277
|
-
|
|
278
|
-
return { total, passed, failed, skipped };
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Parse Jest output.
|
|
283
|
-
*/
|
|
284
|
-
function parseJestOutput(output) {
|
|
285
|
-
// Jest format: "Tests: 3 failed, 47 passed, 50 total"
|
|
286
|
-
const totalMatch = output.match(/(\d+)\s+total/);
|
|
287
|
-
const passedMatch = output.match(/(\d+)\s+passed/);
|
|
288
|
-
const failMatch = output.match(/(\d+)\s+failed/);
|
|
289
|
-
const skipMatch = output.match(/(\d+)\s+skipped/);
|
|
290
|
-
|
|
291
|
-
const total = totalMatch ? parseInt(totalMatch[1], 10) : 0;
|
|
292
|
-
const passed = passedMatch ? parseInt(passedMatch[1], 10) : 0;
|
|
293
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
294
|
-
const skipped = skipMatch ? parseInt(skipMatch[1], 10) : 0;
|
|
295
|
-
|
|
296
|
-
return { total, passed, failed, skipped };
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Parse Vitest output.
|
|
301
|
-
*/
|
|
302
|
-
function parseVitestOutput(output) {
|
|
303
|
-
const passMatch = output.match(/(\d+)\s+passed/);
|
|
304
|
-
const failMatch = output.match(/(\d+)\s+failed/);
|
|
305
|
-
const skipMatch = output.match(/(\d+)\s+skipped/);
|
|
306
|
-
|
|
307
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
308
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
309
|
-
const skipped = skipMatch ? parseInt(skipMatch[1], 10) : 0;
|
|
310
|
-
const total = passed + failed + skipped;
|
|
311
|
-
|
|
312
|
-
return { total, passed, failed, skipped };
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Parse Mocha output.
|
|
317
|
-
*/
|
|
318
|
-
function parseMochaOutput(output) {
|
|
319
|
-
const passMatch = output.match(/(\d+)\s+passing/);
|
|
320
|
-
const failMatch = output.match(/(\d+)\s+failing/);
|
|
321
|
-
const pendMatch = output.match(/(\d+)\s+pending/);
|
|
322
|
-
|
|
323
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
324
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
325
|
-
const skipped = pendMatch ? parseInt(pendMatch[1], 10) : 0;
|
|
326
|
-
const total = passed + failed + skipped;
|
|
327
|
-
|
|
328
|
-
return { total, passed, failed, skipped };
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Generic fallback parser.
|
|
333
|
-
*/
|
|
334
|
-
function parseGenericOutput(output) {
|
|
335
|
-
const passMatch = output.match(/(\d+)\s+pass/i);
|
|
336
|
-
const failMatch = output.match(/(\d+)\s+fail/i);
|
|
337
|
-
|
|
338
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
339
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
340
|
-
const total = passed + failed;
|
|
341
|
-
|
|
342
|
-
return { total, passed, failed, skipped: 0 };
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Parse lint output for error/warning counts.
|
|
347
|
-
*
|
|
348
|
-
* @param {string} output
|
|
349
|
-
* @returns {{ errors: number, warnings: number }}
|
|
350
|
-
*/
|
|
351
|
-
function parseLintOutput(output) {
|
|
352
|
-
// ESLint format: "X problems (Y errors, Z warnings)"
|
|
353
|
-
const eslintMatch = output.match(/(\d+)\s+problems?\s*\((\d+)\s+errors?,\s*(\d+)\s+warnings?\)/);
|
|
354
|
-
if (eslintMatch) {
|
|
355
|
-
return {
|
|
356
|
-
errors: parseInt(eslintMatch[2], 10),
|
|
357
|
-
warnings: parseInt(eslintMatch[3], 10),
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Count error/warning lines
|
|
362
|
-
const errorLines = (output.match(/error/gi) || []).length;
|
|
363
|
-
const warningLines = (output.match(/warning/gi) || []).length;
|
|
364
|
-
|
|
365
|
-
return { errors: errorLines, warnings: warningLines };
|
|
366
|
-
}
|
package/src/tasks/executor.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Task Executor — Executes a task definition with PRISM context injection.
|
|
3
|
-
*
|
|
4
|
-
* The executor prepares the full execution context for an agent by:
|
|
5
|
-
* 1. Loading the task definition
|
|
6
|
-
* 2. Injecting PRISM context layers
|
|
7
|
-
* 3. Building the instruction payload
|
|
8
|
-
* 4. Validating criteria post-execution (for autonomous mode)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Build the execution payload for a task.
|
|
13
|
-
*
|
|
14
|
-
* This produces the complete context that gets injected into
|
|
15
|
-
* the agent's prompt when executing a task.
|
|
16
|
-
*
|
|
17
|
-
* @param {object} task - Task definition from loader
|
|
18
|
-
* @param {object} options
|
|
19
|
-
* @param {object} [options.prismContext] - PRISM context output (xml, bracket, layers)
|
|
20
|
-
* @param {object} [options.handoff] - Handoff data from previous agent
|
|
21
|
-
* @param {object} [options.sessionState] - Current session state
|
|
22
|
-
* @param {string} [options.mode] - Execution mode ('human-in-the-loop' | 'autonomous')
|
|
23
|
-
* @returns {{ payload: object, warnings: string[] }}
|
|
24
|
-
*/
|
|
25
|
-
export function buildExecutionPayload(task, options = {}) {
|
|
26
|
-
const warnings = [];
|
|
27
|
-
|
|
28
|
-
if (!task) {
|
|
29
|
-
return { payload: null, warnings: ['No task provided to executor.'] };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const mode = options.mode || 'human-in-the-loop';
|
|
33
|
-
const isAutonomous = mode === 'autonomous';
|
|
34
|
-
|
|
35
|
-
// Warn if task requires input but we're in autonomous mode
|
|
36
|
-
if (task.requires_input && isAutonomous) {
|
|
37
|
-
warnings.push(
|
|
38
|
-
`Task '${task.id}' requires user input but running in autonomous mode. ` +
|
|
39
|
-
'Gate will pause for input.'
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Warn if task doesn't support autonomous gate but mode is autonomous
|
|
44
|
-
if (isAutonomous && !task.autonomous_gate) {
|
|
45
|
-
warnings.push(
|
|
46
|
-
`Task '${task.id}' does not have autonomous_gate enabled. ` +
|
|
47
|
-
'Human validation will be required.'
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const payload = {
|
|
52
|
-
task: {
|
|
53
|
-
id: task.id,
|
|
54
|
-
agent: task.agent,
|
|
55
|
-
phase: task.phase,
|
|
56
|
-
instructions: task.instructions,
|
|
57
|
-
criteria: task.criteria,
|
|
58
|
-
outputs: task.outputs,
|
|
59
|
-
handoff_to: task.handoff_to,
|
|
60
|
-
},
|
|
61
|
-
context: {
|
|
62
|
-
prism: options.prismContext || null,
|
|
63
|
-
handoff: options.handoff || null,
|
|
64
|
-
session: sanitizeSessionState(options.sessionState),
|
|
65
|
-
},
|
|
66
|
-
execution: {
|
|
67
|
-
mode,
|
|
68
|
-
autonomous_gate: task.autonomous_gate,
|
|
69
|
-
requires_input: task.requires_input,
|
|
70
|
-
parallelizable: task.parallelizable,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return { payload, warnings };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Validate task execution results against criteria.
|
|
79
|
-
*
|
|
80
|
-
* Each criterion is a string describing what must be true.
|
|
81
|
-
* The validator returns a structured result for the orchestrator
|
|
82
|
-
* to decide whether to proceed or require intervention.
|
|
83
|
-
*
|
|
84
|
-
* @param {object} task - Task definition
|
|
85
|
-
* @param {object} results - Execution results to validate
|
|
86
|
-
* @param {string[]} [results.completedCriteria] - Criteria marked as met
|
|
87
|
-
* @param {string[]} [results.outputs] - Produced output files
|
|
88
|
-
* @param {number} [results.confidence] - Self-reported confidence (0-100)
|
|
89
|
-
* @returns {{ valid: boolean, score: number, unmet: string[], details: string }}
|
|
90
|
-
*/
|
|
91
|
-
export function validateResults(task, results = {}) {
|
|
92
|
-
if (!task || !task.criteria || task.criteria.length === 0) {
|
|
93
|
-
return { valid: true, score: 100, unmet: [], details: 'No criteria defined.' };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const completed = new Set(results.completedCriteria || []);
|
|
97
|
-
const unmet = [];
|
|
98
|
-
|
|
99
|
-
for (const criterion of task.criteria) {
|
|
100
|
-
if (!completed.has(criterion)) {
|
|
101
|
-
unmet.push(criterion);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const score = Math.round(((task.criteria.length - unmet.length) / task.criteria.length) * 100);
|
|
106
|
-
|
|
107
|
-
// Check outputs
|
|
108
|
-
const expectedOutputs = task.outputs || [];
|
|
109
|
-
const producedOutputs = results.outputs || [];
|
|
110
|
-
const missingOutputs = expectedOutputs.filter(o => !producedOutputs.includes(o));
|
|
111
|
-
|
|
112
|
-
if (missingOutputs.length > 0) {
|
|
113
|
-
unmet.push(`Missing outputs: ${missingOutputs.join(', ')}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Confidence check for autonomous mode
|
|
117
|
-
const confidence = results.confidence ?? 100;
|
|
118
|
-
const confidenceMet = confidence >= 90;
|
|
119
|
-
|
|
120
|
-
const valid = unmet.length === 0 && confidenceMet;
|
|
121
|
-
|
|
122
|
-
let details;
|
|
123
|
-
if (valid) {
|
|
124
|
-
details = `All ${task.criteria.length} criteria met. Confidence: ${confidence}%.`;
|
|
125
|
-
} else {
|
|
126
|
-
const parts = [];
|
|
127
|
-
if (unmet.length > 0) parts.push(`${unmet.length} unmet criteria`);
|
|
128
|
-
if (!confidenceMet) parts.push(`Low confidence: ${confidence}%`);
|
|
129
|
-
details = parts.join('. ');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return { valid, score, unmet, details };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Determine the post-execution action based on validation results.
|
|
137
|
-
*
|
|
138
|
-
* @param {object} validation - Result from validateResults
|
|
139
|
-
* @param {string} mode - 'autonomous' | 'human-in-the-loop'
|
|
140
|
-
* @param {object} task - Task definition
|
|
141
|
-
* @returns {{ action: string, reason: string }}
|
|
142
|
-
* action: 'proceed' | 'retry' | 'escalate' | 'gate'
|
|
143
|
-
*/
|
|
144
|
-
export function determinePostAction(validation, mode, task) {
|
|
145
|
-
// Human-in-the-loop always gates
|
|
146
|
-
if (mode !== 'autonomous') {
|
|
147
|
-
return {
|
|
148
|
-
action: 'gate',
|
|
149
|
-
reason: 'Human-in-the-loop mode requires user approval.',
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Autonomous mode with autonomous gate
|
|
154
|
-
if (validation.valid) {
|
|
155
|
-
return {
|
|
156
|
-
action: 'proceed',
|
|
157
|
-
reason: `All criteria met (score: ${validation.score}%). Proceeding to ${task.handoff_to || 'next'}.`,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Partial pass — try to determine severity
|
|
162
|
-
if (validation.score >= 90) {
|
|
163
|
-
return {
|
|
164
|
-
action: 'gate',
|
|
165
|
-
reason: `Score ${validation.score}% is close but below threshold. Human review recommended.`,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (validation.score >= 50) {
|
|
170
|
-
return {
|
|
171
|
-
action: 'retry',
|
|
172
|
-
reason: `Score ${validation.score}%. ${validation.unmet.length} criteria unmet. Retry with focused attention.`,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
action: 'escalate',
|
|
178
|
-
reason: `Score ${validation.score}%. Major gaps detected. Escalating to orchestrator.`,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Sanitize session state to remove sensitive or oversized data.
|
|
184
|
-
*/
|
|
185
|
-
function sanitizeSessionState(state) {
|
|
186
|
-
if (!state) return null;
|
|
187
|
-
|
|
188
|
-
return {
|
|
189
|
-
mode: state.mode || 'discover',
|
|
190
|
-
current_agent: state.current_agent || null,
|
|
191
|
-
pipeline_position: state.pipeline_position || null,
|
|
192
|
-
completed_agents: state.completed_agents || [],
|
|
193
|
-
phase: state.phase || null,
|
|
194
|
-
};
|
|
195
|
-
}
|
package/src/tasks/index.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { loadTask, parseTaskContent, loadAllTasks, getAgentTasks, getTaskSummary } from './loader.js';
|
|
2
|
-
export { TaskRouter, createRouter } from './router.js';
|
|
3
|
-
export { buildExecutionPayload, validateResults, determinePostAction } from './executor.js';
|
|
4
|
-
export { buildHandoff, formatHandoff, saveHandoff, loadHandoff, parseHandoffContent } from './handoff.js';
|