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