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.
- package/README.md +18 -13
- package/bin/chati.js +28 -4
- package/framework/agents/build/dev.md +5 -1
- package/framework/agents/discover/greenfield-wu.md +16 -1
- package/framework/agents/plan/tasks.md +31 -0
- package/framework/agents/plan/ux-brand-architect.md +21 -2
- package/framework/agents/plan/ux-component-engineer.md +10 -0
- package/framework/agents/quality/qa-implementation.md +1 -1
- package/framework/agents/quality/qa-planning.md +1 -1
- package/framework/agents/quality/qa-visual.md +24 -21
- package/framework/config.yaml +5 -4
- package/framework/constitution.md +60 -11
- package/framework/context/governance.md +12 -10
- package/framework/context/root.md +2 -2
- package/framework/data/entity-registry.yaml +12 -4
- package/framework/data/qa-rubrics.yaml +335 -0
- package/framework/domains/constitution.yaml +3 -3
- package/framework/executors/json-validate.js +80 -0
- package/framework/executors/npm-script.js +72 -0
- package/framework/executors/path-check.js +67 -0
- package/framework/executors/registry.yaml +36 -0
- package/framework/hooks/advance-trigger.js +47 -3
- package/framework/hooks/constitution-guard.js +9 -4
- package/framework/hooks/git-push-authority.js +113 -0
- package/framework/hooks/license-guard.js +59 -9
- package/framework/hooks/model-governance.js +40 -17
- package/framework/hooks/prism-engine.js +78 -11
- package/framework/hooks/session-digest.js +12 -3
- package/framework/hooks/settings.json +7 -3
- package/framework/hooks/style-guard.js +52 -3
- package/framework/hooks/team-quality-gate.js +43 -5
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/confidence.yaml +85 -6
- package/framework/intelligence/context-engine.md +9 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/manifest.json +1351 -0
- package/framework/manifest.sig +1 -0
- package/framework/orchestrator/chati-router.js +1 -1
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +24 -3
- package/framework/quality-gates/planning-gate.md +2 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
- package/framework/scaffold/saas-dashboard/README.md +58 -0
- package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
- package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
- package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
- package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
- package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
- package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
- package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
- package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
- package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
- package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
- package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
- package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
- package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
- package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
- package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
- package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
- package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
- package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
- package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
- package/framework/schemas/session.schema.json +5 -0
- package/framework/schemas/task.schema.json +9 -0
- package/framework/scripts/visual-qa.js +87 -1
- package/framework/tasks/orchestrator-health.md +4 -4
- package/framework/tasks/qa-impl-verdict.md +11 -5
- package/framework/templates/qa-gate-tmpl.yaml +24 -11
- package/package.json +4 -4
- package/src/config/claude-settings-generator.js +9 -6
- package/src/config/context-file-generator.js +0 -6
- package/src/dashboard/renderer.js +0 -36
- package/src/executors/runner.js +204 -0
- package/src/installer/core.js +35 -4
- package/src/installer/manifest.js +30 -4
- package/src/installer/signing-public-key.pem +1 -1
- package/src/installer/templates.js +5 -6
- package/src/installer/validator.js +2 -1
- package/src/intelligence/registry-manager.js +3 -2
- package/src/license/client.js +9 -3
- package/src/license/commands.js +12 -2
- package/src/license/machine-id.js +42 -1
- package/src/memory/gotchas.js +58 -40
- package/src/memory/magic-docs.js +7 -2
- package/src/memory/session-digest.js +9 -4
- package/src/orchestrator/cli.js +195 -23
- package/src/orchestrator/deviation-handler.js +5 -3
- package/src/orchestrator/doctor.js +98 -16
- package/src/orchestrator/pipeline-manager.js +44 -22
- package/src/orchestrator/session-manager.js +56 -8
- package/src/telemetry/sender.js +7 -19
- package/src/terminal/run-parallel.js +14 -14
- package/src/terminal/run-team.js +3 -3
- package/src/upgrade/backup.js +22 -44
- package/src/upgrade/migrator.js +51 -12
- package/src/upgrade/tracked-files-detector.js +34 -16
- package/src/utils/constitution-meta.js +12 -0
- package/src/utils/feature-flags.js +26 -2
- package/src/utils/flatten-entities.js +4 -40
- package/src/utils/schema-validator.js +0 -14
- package/src/wizard/i18n.js +3 -3
- package/src/api/index.js +0 -120
- package/src/autonomy/autonomous-gate.js +0 -294
- package/src/autonomy/build-loop.js +0 -281
- package/src/autonomy/build-state.js +0 -286
- package/src/autonomy/cause-analyzer.js +0 -177
- package/src/autonomy/escalation.js +0 -214
- package/src/autonomy/index.js +0 -51
- package/src/autonomy/mode-manager.js +0 -225
- package/src/autonomy/mode-suggester.js +0 -283
- package/src/autonomy/progress-reporter.js +0 -275
- package/src/autonomy/safety-net.js +0 -370
- package/src/config/agent-customizer.js +0 -231
- package/src/decision/analyzer.js +0 -291
- package/src/decision/engine.js +0 -250
- package/src/decision/index.js +0 -38
- package/src/decision/registry-healer.js +0 -468
- package/src/decision/registry-updater.js +0 -339
- package/src/extensions/loader.js +0 -145
- package/src/extensions/registry.js +0 -134
- package/src/gates/circuit-breaker.js +0 -151
- package/src/gates/g1-planning-complete.js +0 -154
- package/src/gates/g2-qa-planning.js +0 -156
- package/src/gates/g3-implementation.js +0 -215
- package/src/gates/g4-qa-implementation.js +0 -240
- package/src/gates/g5-deploy-ready.js +0 -181
- package/src/gates/gate-base.js +0 -185
- package/src/gates/index.js +0 -46
- package/src/health/auto-fix.js +0 -216
- package/src/health/engine.js +0 -246
- package/src/merger/semantic-merger.js +0 -292
- package/src/preview/detector.js +0 -238
- package/src/preview/index.js +0 -20
- package/src/preview/launcher.js +0 -235
- package/src/preview/log-buffer.js +0 -103
- package/src/quality/metrics-collector.js +0 -281
- package/src/quality/test-runner.js +0 -366
- package/src/tasks/executor.js +0 -195
- package/src/tasks/index.js +0 -4
- package/src/tasks/loader.js +0 -210
- package/src/tasks/router.js +0 -182
- package/src/utils/event-bus.js +0 -126
|
@@ -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
|
|
2
|
+
* @fileoverview Shared entity-flattening utility.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
*/
|
package/src/wizard/i18n.js
CHANGED
|
@@ -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 (
|
|
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-
|
|
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:
|
|
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
|
-
}
|