chati-dev 4.3.0 → 4.4.0

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