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
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @fileoverview Single source of truth for constitution metadata used by
3
+ * integrity checks.
4
+ *
5
+ * Every check that counts `## Article` headings (doctor, registry health,
6
+ * installer validator, stale-scan check 13) compares against THIS constant,
7
+ * so adding a constitutional article is a one-line bump here. The stale-scan
8
+ * asserts the canonical constitution.md actually contains this many articles,
9
+ * which keeps the constant honest.
10
+ */
11
+
12
+ export const EXPECTED_ARTICLE_COUNT = 25;
@@ -14,21 +14,45 @@ import { resolveFrameworkDir } from './framework-dir.js';
14
14
 
15
15
  /**
16
16
  * All known feature flags with their default values.
17
- * New features start as false (opt-in).
17
+ * New features start as false (opt-in). Defaults describe the state when
18
+ * config.yaml is absent; installed projects get their real values written by
19
+ * generateConfigYaml, and parseFeaturesSection only honors keys listed here,
20
+ * so EVERY boolean flag documented in config.yaml must appear in this map or
21
+ * the user's toggle is silently ignored (which froze 11 flags until 4.4.1).
22
+ * The numeric team_* and build_wave_size keys are intentionally absent: the
23
+ * parser is boolean-only and those values are read directly from config.yaml
24
+ * by their consumers.
18
25
  */
19
26
  const DEFAULTS = {
27
+ // Core framework flags
20
28
  hybrid_budget: false,
21
29
  anti_dash: false,
22
30
  rate_limiter_integration: false,
23
31
  l5_keywords: false,
24
32
  prompt_size_guard: false,
25
- ids_decision_engine: false,
26
33
  surface_criteria: false,
27
34
  parallel_fallback: false,
28
35
  tool_mesh: false,
29
36
  tech_presets: false,
30
37
  doctor_autofix: false,
31
38
  brandbook: false,
39
+ // Intelligence upgrade flags
40
+ undercover_mode: false,
41
+ memory_extraction: false,
42
+ memory_consolidation: false,
43
+ daily_digest: false,
44
+ structured_session_memory: false,
45
+ static_prism_boundary: false,
46
+ token_bracket_estimation: false,
47
+ model_fallback: false,
48
+ frustration_detection: false,
49
+ bash_security_checks: false,
50
+ // Agent Teams (Article XXI). NOTE: isAgentTeamsEnabled in cli.js keeps its
51
+ // own reader with Claude-provider defaulting; this entry exists so a config
52
+ // toggle is at least visible through the generic API.
53
+ agent_teams: false,
54
+ // Execution Kinds (Article XXV)
55
+ execution_kinds: false,
32
56
  };
33
57
 
34
58
  /**
@@ -1,46 +1,10 @@
1
1
  /**
2
- * @fileoverview Shared entity-flattening utilities.
2
+ * @fileoverview Shared entity-flattening utility.
3
3
  *
4
- * Two variants exist because the registry YAML stores entities in two different
5
- * shapes depending on who reads it:
6
- *
7
- * - flattenEntitiesFromRegistry: receives the full registry object
8
- * (i.e. the result of yaml.load()), where each category's value is an Array.
9
- * Used by decision/analyzer.js and decision/engine.js.
10
- *
11
- * - flattenEntitiesMap: receives only the `registry.entities` map,
12
- * where each category's value is a nested object keyed by entity name.
13
- * Used by intelligence/registry-manager.js.
14
- *
15
- * Keep both functions here so there is a single canonical implementation.
16
- */
17
-
18
- /**
19
- * Flatten a full entity registry (as returned by yaml.load) into a flat array.
20
- *
21
- * Each category value must be an Array of entity objects.
22
- * The `type` field is inferred from the category key.
23
- *
24
- * @param {object} registry - Full registry object with a top-level `entities` key.
25
- * @returns {object[]} Flat array of entity objects, each with a `type` field added.
4
+ * flattenEntitiesMap receives the `registry.entities` map, where each category's
5
+ * value is a nested object keyed by entity name. Used by
6
+ * intelligence/registry-manager.js.
26
7
  */
27
- export function flattenEntitiesFromRegistry(registry) {
28
- const entities = [];
29
-
30
- if (!registry || !registry.entities) {
31
- return entities;
32
- }
33
-
34
- Object.entries(registry.entities).forEach(([type, typeEntities]) => {
35
- if (Array.isArray(typeEntities)) {
36
- typeEntities.forEach(entity => {
37
- entities.push({ ...entity, type });
38
- });
39
- }
40
- });
41
-
42
- return entities;
43
- }
44
8
 
45
9
  /**
46
10
  * Flatten the `entities` section of the registry (a nested object map) into a flat array.
@@ -177,20 +177,6 @@ export const SESSION_SCHEMA = {
177
177
  },
178
178
  };
179
179
 
180
- /**
181
- * Build state schema (build-state.json).
182
- */
183
- export const BUILD_STATE_SCHEMA = {
184
- required: ['sessionId', 'status', 'checkpoints'],
185
- properties: {
186
- sessionId: { type: 'string', required: true },
187
- status: { type: 'string', required: true, enum: ['idle', 'running', 'completed', 'failed', 'abandoned'] },
188
- checkpoints: { type: 'array', required: true },
189
- startedAt: { type: 'string' },
190
- totalAttempts: { type: 'number', min: 0 },
191
- },
192
- };
193
-
194
180
  /**
195
181
  * Config schema (config.yaml).
196
182
  */
@@ -39,7 +39,7 @@ const FALLBACK_EN = {
39
39
  agents_count: 'Specialized agent definitions across DISCOVER, PLAN, BUILD, DEPLOY phases',
40
40
  workflows_count: '6 workflow blueprints',
41
41
  templates_count: '6 templates (PRD, Brownfield PRD, Architecture, Task, QA Gate, Quick Brief)',
42
- constitution: 'Constitution (23 Articles + Preamble)',
42
+ constitution: 'Constitution (25 Articles + Preamble)',
43
43
  session_mgmt: 'Session management system',
44
44
  quality_gates: 'Quality gates (3-tier verdicts)',
45
45
  proceed: 'Proceed with installation?',
@@ -47,7 +47,7 @@ const FALLBACK_EN = {
47
47
  created_chati: 'Created .chati/ session directory',
48
48
  created_framework: 'Created chati.dev/ system directory (agents, templates, workflows)',
49
49
  created_commands: 'Created .claude/commands/ (thin router)',
50
- installed_constitution: 'Installed Constitution (Articles I-XXIII)',
50
+ installed_constitution: 'Installed Constitution (Articles I-XXV)',
51
51
  created_session: 'Created session.yaml schema',
52
52
  created_claude_md: 'Created CLAUDE.md',
53
53
  configured_mcps: 'Configured MCPs:',
@@ -55,7 +55,7 @@ const FALLBACK_EN = {
55
55
  agents_valid: 'All agents implement 8 protocols',
56
56
  handoff_ok: 'Handoff protocol: OK',
57
57
  validation_ok: 'Self-validation criteria: OK',
58
- constitution_ok: 'Constitution: 23 articles verified',
58
+ constitution_ok: 'Constitution: 25 articles verified',
59
59
  created_memories: 'Created .chati/memories/ (Memory Layer)',
60
60
  installed_intelligence: 'Installed Intelligence Layer (Context Engine, Memory, Registry)',
61
61
  intelligence_valid: 'Intelligence: 6 spec files verified',
package/src/api/index.js DELETED
@@ -1,120 +0,0 @@
1
- /**
2
- * @fileoverview Public API surface for chati-dev.
3
- *
4
- * Re-exports stable functions from core modules, providing
5
- * a clean entry point for programmatic usage.
6
- *
7
- * @example
8
- * import { createSession, runHealthChecks, classifyIntent } from 'chati-dev/api';
9
- */
10
-
11
- // ---------------------------------------------------------------------------
12
- // Health & Diagnostics
13
- // ---------------------------------------------------------------------------
14
-
15
- export { runHealthChecks } from '../health/engine.js';
16
-
17
- // ---------------------------------------------------------------------------
18
- // Context Engine (PRISM)
19
- // ---------------------------------------------------------------------------
20
-
21
- export { runPrism } from '../context/engine.js';
22
-
23
- // ---------------------------------------------------------------------------
24
- // Orchestrator
25
- // ---------------------------------------------------------------------------
26
-
27
- export { classifyIntent, INTENT_TYPES } from '../orchestrator/intent-classifier.js';
28
- export {
29
- initPipeline,
30
- advancePipeline,
31
- initQuickFlowPipeline,
32
- initStandardFlowPipeline,
33
- } from '../orchestrator/pipeline-manager.js';
34
- export { selectAgent } from '../orchestrator/agent-selector.js';
35
-
36
- // ---------------------------------------------------------------------------
37
- // Session Management
38
- // ---------------------------------------------------------------------------
39
-
40
- import { initSession as _initSession } from '../orchestrator/session-manager.js';
41
-
42
- export {
43
- initSession,
44
- loadSession,
45
- updateSession,
46
- validateSession,
47
- getSessionSummary,
48
- claimSession,
49
- releaseSession,
50
- getSessionOwner,
51
- } from '../orchestrator/session-manager.js';
52
-
53
- // ---------------------------------------------------------------------------
54
- // Autonomy
55
- // ---------------------------------------------------------------------------
56
-
57
- export { runBuildLoop } from '../autonomy/build-loop.js';
58
- export { checkSafety, SAFETY_TRIGGERS } from '../autonomy/safety-net.js';
59
-
60
- // ---------------------------------------------------------------------------
61
- // Memory
62
- // ---------------------------------------------------------------------------
63
-
64
- export { recordError, getGotchas } from '../memory/gotchas.js';
65
-
66
- // ---------------------------------------------------------------------------
67
- // Quality
68
- // ---------------------------------------------------------------------------
69
-
70
- export { getMetricsHistory, getQualityDashboard, recordMetric } from '../quality/metrics-collector.js';
71
-
72
- // ---------------------------------------------------------------------------
73
- // Extensions
74
- // ---------------------------------------------------------------------------
75
-
76
- export {
77
- registerExtension,
78
- getExtensions,
79
- executeExtensions,
80
- clearExtensions,
81
- EXTENSION_POINTS,
82
- } from '../extensions/registry.js';
83
- export { loadProjectExtensions, validateExtension } from '../extensions/loader.js';
84
-
85
- // ---------------------------------------------------------------------------
86
- // Configuration
87
- // ---------------------------------------------------------------------------
88
-
89
- export { loadCustomization, applyCustomization, validateCustomization } from '../config/agent-customizer.js';
90
- export { IDE_CONFIGS, getIDEChoices } from '../config/ide-configs.js';
91
-
92
- // ---------------------------------------------------------------------------
93
- // Convenience Wrapper
94
- // ---------------------------------------------------------------------------
95
-
96
- /**
97
- * Create and initialize a new chati.dev session.
98
- *
99
- * Convenience wrapper that initializes session state.
100
- *
101
- * @param {string} projectDir - Project root directory
102
- * @param {object} [options]
103
- * @param {string} [options.mode='discover'] - Initial pipeline mode
104
- * @param {boolean} [options.isGreenfield=true] - Project type
105
- * @param {string} [options.language='en'] - Interaction language
106
- * @param {string} [options.projectName=''] - Project name
107
- * @param {string[]} [options.ides=[]] - Selected IDEs
108
- * @param {string[]} [options.mcps=[]] - Selected MCPs
109
- * @returns {{ created: boolean, session: object, path: string }}
110
- */
111
- export function createSession(projectDir, options = {}) {
112
- return _initSession(projectDir, {
113
- mode: options.mode || 'discover',
114
- isGreenfield: options.isGreenfield !== false,
115
- language: options.language || 'en',
116
- projectName: options.projectName || '',
117
- ides: options.ides || [],
118
- mcps: options.mcps || [],
119
- });
120
- }
@@ -1,294 +0,0 @@
1
- /**
2
- * @fileoverview Autonomous quality gate evaluation
3
- * Evaluates quality gates without human input using score-based heuristics
4
- */
5
-
6
- import { loadSession, updateSession } from '../orchestrator/session-manager.js';
7
-
8
- /**
9
- * Gate result types.
10
- */
11
- export const GATE_RESULTS = {
12
- PASS: 'pass',
13
- FAIL: 'fail',
14
- REVIEW: 'review', // Borderline — pause for human review even in autonomous mode
15
- };
16
-
17
- // Minimum passing scores per agent (conservative: 90 default)
18
- const GATE_THRESHOLDS = {
19
- 'qa-planning': 95, // Highest — gates planning→build transition
20
- 'qa-implementation': 95, // Gates build→deploy transition
21
- 'qa-visual': 90, // Visual quality gate
22
- 'brief': 90, // Requirements are critical
23
- 'detail': 90,
24
- 'architect': 90,
25
- 'ux': 90,
26
- 'phases': 90,
27
- 'tasks': 90,
28
- 'dev': 90,
29
- 'devops': 90,
30
- 'greenfield-wu': 90,
31
- 'brownfield-wu': 90,
32
- // Default for any other agent
33
- '_default': 90,
34
- };
35
-
36
- // Review range: within 5 points of threshold triggers REVIEW
37
- const REVIEW_RANGE = 5;
38
-
39
- /**
40
- * Evaluate a quality gate autonomously.
41
- *
42
- * @param {object} gateInput
43
- * @param {string} gateInput.agent - Agent that produced the work
44
- * @param {number} gateInput.score - Self-reported quality score (0-100)
45
- * @param {string[]} gateInput.criteriaResults - Which criteria passed
46
- * @param {string[]} gateInput.allCriteria - All criteria for this gate
47
- * @param {number} [gateInput.confidence] - Agent's confidence (0-100)
48
- * @param {string[]} [gateInput.warnings] - Any warnings produced
49
- * @returns {{ result: string, score: number, reasoning: string, canProceed: boolean }}
50
- */
51
- export function evaluateGate(gateInput) {
52
- const {
53
- agent,
54
- score,
55
- criteriaResults = [],
56
- allCriteria = [],
57
- confidence = 100,
58
- warnings = [],
59
- } = gateInput;
60
-
61
- // Validate inputs
62
- if (typeof score !== 'number' || score < 0 || score > 100) {
63
- throw new Error(`Invalid score: ${score}. Must be 0-100.`);
64
- }
65
-
66
- const threshold = getGateThreshold(agent);
67
- const criteriaScore = allCriteria.length > 0
68
- ? (criteriaResults.length / allCriteria.length) * 100
69
- : 100;
70
-
71
- // Combine self-reported score and criteria score
72
- const weightedScore = (score * 0.6) + (criteriaScore * 0.4);
73
-
74
- // Factor in confidence
75
- const confidencePenalty = confidence < 80 ? (80 - confidence) * 0.2 : 0;
76
- const finalScore = Math.max(0, weightedScore - confidencePenalty);
77
-
78
- // Factor in warnings
79
- const warningPenalty = warnings.length * 3;
80
- const adjustedScore = Math.max(0, finalScore - warningPenalty);
81
-
82
- // Determine result
83
- let result;
84
- const reasoning = [];
85
-
86
- if (adjustedScore >= threshold) {
87
- result = GATE_RESULTS.PASS;
88
- reasoning.push(`Score ${Math.round(adjustedScore)}% meets threshold ${threshold}%`);
89
- } else if (adjustedScore >= threshold - REVIEW_RANGE) {
90
- result = GATE_RESULTS.REVIEW;
91
- reasoning.push(`Score ${Math.round(adjustedScore)}% is borderline (threshold: ${threshold}%)`);
92
- reasoning.push('Manual review recommended');
93
- } else {
94
- result = GATE_RESULTS.FAIL;
95
- reasoning.push(`Score ${Math.round(adjustedScore)}% below threshold ${threshold}%`);
96
- }
97
-
98
- // Add details
99
- reasoning.push(`Criteria: ${criteriaResults.length}/${allCriteria.length} passed`);
100
-
101
- if (confidence < 80) {
102
- reasoning.push(`Low confidence (${confidence}%) reduced score by ${Math.round(confidencePenalty)}%`);
103
- }
104
-
105
- if (warnings.length > 0) {
106
- reasoning.push(`${warnings.length} warning(s) reduced score by ${warningPenalty}%`);
107
- }
108
-
109
- return {
110
- result,
111
- score: Math.round(adjustedScore),
112
- reasoning: reasoning.join('. '),
113
- canProceed: result === GATE_RESULTS.PASS,
114
- details: {
115
- rawScore: Math.round(score),
116
- criteriaScore: Math.round(criteriaScore),
117
- weightedScore: Math.round(weightedScore),
118
- confidencePenalty: Math.round(confidencePenalty),
119
- warningPenalty,
120
- finalScore: Math.round(adjustedScore),
121
- threshold,
122
- },
123
- };
124
- }
125
-
126
- /**
127
- * Get the minimum passing score for an agent's gate.
128
- * Different agents have different thresholds.
129
- * @param {string} agentName
130
- * @returns {number} Minimum score (0-100)
131
- */
132
- export function getGateThreshold(agentName) {
133
- return GATE_THRESHOLDS[agentName] || GATE_THRESHOLDS._default;
134
- }
135
-
136
- /**
137
- * Check if gate result allows pipeline to continue.
138
- * @param {string} result - GATE_RESULTS value
139
- * @param {string} executionMode - 'autonomous' | 'human-in-the-loop'
140
- * @returns {{ proceed: boolean, action: string }}
141
- */
142
- export function resolveGateAction(result, executionMode) {
143
- if (result === GATE_RESULTS.PASS) {
144
- return {
145
- proceed: true,
146
- action: 'continue',
147
- };
148
- }
149
-
150
- if (result === GATE_RESULTS.FAIL) {
151
- return {
152
- proceed: false,
153
- action: executionMode === 'autonomous' ? 'pause_for_review' : 'wait_for_user',
154
- };
155
- }
156
-
157
- // REVIEW result
158
- if (executionMode === 'autonomous') {
159
- return {
160
- proceed: false,
161
- action: 'pause_for_review',
162
- };
163
- }
164
-
165
- return {
166
- proceed: false,
167
- action: 'wait_for_user',
168
- };
169
- }
170
-
171
- /**
172
- * Get gate evaluation history.
173
- * @param {string} projectDir
174
- * @returns {object[]}
175
- */
176
- export function getGateHistory(projectDir) {
177
- const result = loadSession(projectDir);
178
- if (!result.loaded || !result.session) {
179
- return [];
180
- }
181
- return result.session.gate_evaluations || [];
182
- }
183
-
184
- /**
185
- * Record a gate evaluation.
186
- * @param {string} projectDir
187
- * @param {object} evaluation
188
- */
189
- export function recordGateEvaluation(projectDir, evaluation) {
190
- const result = loadSession(projectDir);
191
-
192
- if (!result.loaded || !result.session) {
193
- return;
194
- }
195
-
196
- const gate_evaluations = result.session.gate_evaluations || [];
197
- gate_evaluations.push({
198
- ...evaluation,
199
- timestamp: new Date().toISOString(),
200
- });
201
-
202
- updateSession(projectDir, { gate_evaluations });
203
- }
204
-
205
- /**
206
- * Get gate statistics.
207
- * @param {string} projectDir
208
- * @returns {{ total: number, passed: number, failed: number, reviewed: number, passRate: number }}
209
- */
210
- export function getGateStatistics(projectDir) {
211
- const history = getGateHistory(projectDir);
212
-
213
- const stats = {
214
- total: history.length,
215
- passed: 0,
216
- failed: 0,
217
- reviewed: 0,
218
- };
219
-
220
- history.forEach(evaluation => {
221
- if (evaluation.result === GATE_RESULTS.PASS) {
222
- stats.passed++;
223
- } else if (evaluation.result === GATE_RESULTS.FAIL) {
224
- stats.failed++;
225
- } else if (evaluation.result === GATE_RESULTS.REVIEW) {
226
- stats.reviewed++;
227
- }
228
- });
229
-
230
- stats.passRate = stats.total > 0
231
- ? Math.round((stats.passed / stats.total) * 100)
232
- : 0;
233
-
234
- return stats;
235
- }
236
-
237
- /**
238
- * Get agent-specific gate statistics.
239
- * @param {string} projectDir
240
- * @param {string} agentName
241
- * @returns {{ total: number, passed: number, failed: number, reviewed: number, averageScore: number }}
242
- */
243
- export function getAgentGateStatistics(projectDir, agentName) {
244
- const history = getGateHistory(projectDir);
245
- const agentEvaluations = history.filter(e => e.agent === agentName);
246
-
247
- const stats = {
248
- total: agentEvaluations.length,
249
- passed: 0,
250
- failed: 0,
251
- reviewed: 0,
252
- averageScore: 0,
253
- };
254
-
255
- if (stats.total === 0) {
256
- return stats;
257
- }
258
-
259
- let totalScore = 0;
260
-
261
- agentEvaluations.forEach(evaluation => {
262
- if (evaluation.result === GATE_RESULTS.PASS) {
263
- stats.passed++;
264
- } else if (evaluation.result === GATE_RESULTS.FAIL) {
265
- stats.failed++;
266
- } else if (evaluation.result === GATE_RESULTS.REVIEW) {
267
- stats.reviewed++;
268
- }
269
-
270
- totalScore += evaluation.score || 0;
271
- });
272
-
273
- stats.averageScore = Math.round(totalScore / stats.total);
274
-
275
- return stats;
276
- }
277
-
278
- /**
279
- * Clear gate evaluation history.
280
- * @param {string} projectDir
281
- * @returns {{ cleared: number }}
282
- */
283
- export function clearGateHistory(projectDir) {
284
- const result = loadSession(projectDir);
285
- if (!result.loaded || !result.session) {
286
- return { cleared: 0 };
287
- }
288
-
289
- const count = result.session.gate_evaluations?.length || 0;
290
-
291
- updateSession(projectDir, { gate_evaluations: [] });
292
-
293
- return { cleared: count };
294
- }