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.
Files changed (147) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +12 -4
  3. package/framework/agents/build/dev.md +5 -1
  4. package/framework/agents/discover/greenfield-wu.md +16 -1
  5. package/framework/agents/plan/tasks.md +31 -0
  6. package/framework/agents/plan/ux-brand-architect.md +21 -2
  7. package/framework/agents/plan/ux-component-engineer.md +10 -0
  8. package/framework/agents/quality/qa-implementation.md +1 -1
  9. package/framework/agents/quality/qa-planning.md +1 -1
  10. package/framework/agents/quality/qa-visual.md +24 -21
  11. package/framework/config.yaml +5 -4
  12. package/framework/constitution.md +58 -11
  13. package/framework/context/governance.md +12 -10
  14. package/framework/context/root.md +2 -2
  15. package/framework/data/entity-registry.yaml +12 -4
  16. package/framework/data/qa-rubrics.yaml +335 -0
  17. package/framework/domains/constitution.yaml +3 -3
  18. package/framework/executors/json-validate.js +80 -0
  19. package/framework/executors/npm-script.js +72 -0
  20. package/framework/executors/path-check.js +67 -0
  21. package/framework/executors/registry.yaml +36 -0
  22. package/framework/hooks/advance-trigger.js +47 -3
  23. package/framework/hooks/constitution-guard.js +9 -4
  24. package/framework/hooks/git-push-authority.js +113 -0
  25. package/framework/hooks/license-guard.js +59 -9
  26. package/framework/hooks/model-governance.js +40 -17
  27. package/framework/hooks/prism-engine.js +78 -11
  28. package/framework/hooks/session-digest.js +12 -3
  29. package/framework/hooks/settings.json +7 -3
  30. package/framework/hooks/style-guard.js +52 -3
  31. package/framework/hooks/team-quality-gate.js +43 -5
  32. package/framework/i18n/en.yaml +3 -3
  33. package/framework/i18n/es.yaml +3 -3
  34. package/framework/i18n/fr.yaml +3 -3
  35. package/framework/i18n/pt.yaml +3 -3
  36. package/framework/intelligence/confidence.yaml +85 -6
  37. package/framework/intelligence/context-engine.md +9 -5
  38. package/framework/intelligence/decision-engine.md +1 -1
  39. package/framework/orchestrator/chati-router.js +1 -1
  40. package/framework/orchestrator/chati-update.md +19 -3
  41. package/framework/orchestrator/chati.md +19 -1
  42. package/framework/quality-gates/planning-gate.md +2 -0
  43. package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
  44. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  45. package/framework/scaffold/saas-dashboard/README.md +58 -0
  46. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  47. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  48. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  49. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  50. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  51. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  52. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  53. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  54. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  55. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  56. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  57. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  58. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  59. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  60. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  61. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  62. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  63. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  64. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  65. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  66. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  67. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  68. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  69. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  70. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  71. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  72. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  73. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  74. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  75. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  76. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  77. package/framework/schemas/session.schema.json +5 -0
  78. package/framework/schemas/task.schema.json +9 -0
  79. package/framework/scripts/visual-qa.js +87 -1
  80. package/framework/tasks/orchestrator-health.md +4 -4
  81. package/framework/tasks/qa-impl-verdict.md +11 -5
  82. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  83. package/package.json +3 -3
  84. package/src/config/context-file-generator.js +0 -6
  85. package/src/dashboard/renderer.js +0 -36
  86. package/src/executors/runner.js +204 -0
  87. package/src/installer/core.js +2 -1
  88. package/src/installer/templates.js +5 -6
  89. package/src/intelligence/registry-manager.js +1 -1
  90. package/src/license/client.js +9 -3
  91. package/src/license/commands.js +12 -2
  92. package/src/license/machine-id.js +42 -1
  93. package/src/memory/gotchas.js +58 -40
  94. package/src/memory/magic-docs.js +1 -1
  95. package/src/memory/session-digest.js +9 -4
  96. package/src/orchestrator/cli.js +174 -14
  97. package/src/orchestrator/doctor.js +98 -16
  98. package/src/orchestrator/pipeline-manager.js +44 -22
  99. package/src/orchestrator/session-manager.js +56 -8
  100. package/src/telemetry/sender.js +7 -19
  101. package/src/terminal/run-team.js +3 -3
  102. package/src/upgrade/tracked-files-detector.js +34 -16
  103. package/src/utils/feature-flags.js +1 -1
  104. package/src/utils/flatten-entities.js +4 -40
  105. package/src/utils/schema-validator.js +0 -14
  106. package/src/wizard/i18n.js +3 -3
  107. package/src/api/index.js +0 -120
  108. package/src/autonomy/autonomous-gate.js +0 -294
  109. package/src/autonomy/build-loop.js +0 -281
  110. package/src/autonomy/build-state.js +0 -286
  111. package/src/autonomy/cause-analyzer.js +0 -177
  112. package/src/autonomy/escalation.js +0 -214
  113. package/src/autonomy/index.js +0 -51
  114. package/src/autonomy/mode-manager.js +0 -225
  115. package/src/autonomy/mode-suggester.js +0 -283
  116. package/src/autonomy/progress-reporter.js +0 -275
  117. package/src/autonomy/safety-net.js +0 -370
  118. package/src/config/agent-customizer.js +0 -231
  119. package/src/decision/analyzer.js +0 -291
  120. package/src/decision/engine.js +0 -250
  121. package/src/decision/index.js +0 -38
  122. package/src/decision/registry-healer.js +0 -468
  123. package/src/decision/registry-updater.js +0 -339
  124. package/src/extensions/loader.js +0 -145
  125. package/src/extensions/registry.js +0 -134
  126. package/src/gates/circuit-breaker.js +0 -151
  127. package/src/gates/g1-planning-complete.js +0 -154
  128. package/src/gates/g2-qa-planning.js +0 -156
  129. package/src/gates/g3-implementation.js +0 -215
  130. package/src/gates/g4-qa-implementation.js +0 -240
  131. package/src/gates/g5-deploy-ready.js +0 -181
  132. package/src/gates/gate-base.js +0 -185
  133. package/src/gates/index.js +0 -46
  134. package/src/health/auto-fix.js +0 -216
  135. package/src/health/engine.js +0 -246
  136. package/src/merger/semantic-merger.js +0 -292
  137. package/src/preview/detector.js +0 -238
  138. package/src/preview/index.js +0 -20
  139. package/src/preview/launcher.js +0 -235
  140. package/src/preview/log-buffer.js +0 -103
  141. package/src/quality/metrics-collector.js +0 -281
  142. package/src/quality/test-runner.js +0 -366
  143. package/src/tasks/executor.js +0 -195
  144. package/src/tasks/index.js +0 -4
  145. package/src/tasks/loader.js +0 -210
  146. package/src/tasks/router.js +0 -182
  147. 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
- }
@@ -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
- }
@@ -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';