chati-dev 4.2.2 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -53
- package/bin/chati.js +150 -5
- package/framework/agents/build/dev.md +509 -76
- package/framework/agents/deploy/devops.md +40 -25
- package/framework/agents/discover/brief.md +156 -22
- package/framework/agents/discover/brownfield-wu.md +24 -14
- package/framework/agents/discover/greenfield-wu.md +100 -14
- package/framework/agents/plan/architect-data-engineer.md +6 -6
- package/framework/agents/plan/architect-system.md +46 -12
- package/framework/agents/plan/architect.md +40 -20
- package/framework/agents/plan/detail.md +36 -24
- package/framework/agents/plan/phases.md +36 -26
- package/framework/agents/plan/tasks.md +114 -33
- package/framework/agents/plan/ux-brand-architect.md +240 -8
- package/framework/agents/plan/ux-component-engineer.md +28 -13
- package/framework/agents/plan/ux-researcher.md +7 -6
- package/framework/agents/plan/ux.md +55 -22
- package/framework/agents/quality/qa-implementation.md +143 -74
- package/framework/agents/quality/qa-planning.md +115 -42
- package/framework/agents/quality/qa-visual.md +439 -0
- package/framework/agents/shared/visualizer.md +128 -0
- package/framework/config.yaml +7 -6
- package/framework/constitution.md +127 -44
- package/framework/context/governance.md +12 -7
- package/framework/context/quality.md +6 -5
- package/framework/context/root.md +6 -6
- package/framework/data/entity-registry.yaml +377 -4
- package/framework/data/model-limits.json +19 -0
- package/framework/domains/agents/qa-visual.yaml +74 -0
- package/framework/domains/constitution.yaml +46 -2
- package/framework/domains/workflows/greenfield-fullstack.yaml +2 -2
- package/framework/hooks/advance-trigger.js +131 -0
- package/framework/hooks/brief-validator.js +83 -0
- package/framework/hooks/constitution-guard.js +24 -5
- package/framework/hooks/license-guard.js +62 -27
- package/framework/hooks/mode-governance.js +13 -2
- package/framework/hooks/model-governance.js +1 -0
- package/framework/hooks/post-dev.js +207 -0
- package/framework/hooks/prism-engine.js +274 -105
- package/framework/hooks/reasoning-escalator.js +371 -0
- package/framework/hooks/reference-trigger.js +117 -0
- package/framework/hooks/session-digest.js +50 -1
- package/framework/hooks/settings.json +32 -1
- package/framework/hooks/style-guard.js +25 -6
- package/framework/hooks/team-quality-gate.js +19 -12
- package/framework/hooks/undercover-guard.js +4 -2
- 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/context-engine.md +4 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/intelligence/hooks-performance.md +3 -3
- package/framework/migrations/v1.0-to-v1.1.yaml +1 -1
- package/framework/migrations/v1.4-to-v2.0.yaml +11 -11
- package/framework/migrations/v4.0-to-v4.1.yaml +2 -2
- package/framework/migrations/v4.2-to-v4.3.yaml +29 -0
- package/framework/orchestrator/chati-router.js +387 -0
- package/framework/orchestrator/chati-update.md +40 -40
- package/framework/orchestrator/chati.md +294 -94
- package/framework/scaffold/motion-premium/README.md +89 -0
- package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
- package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
- package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
- package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
- package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
- package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
- package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
- package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
- package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
- package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
- package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
- package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
- package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
- package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
- package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +174 -0
- package/framework/scaffold/motion-premium-3d/README.md +80 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
- package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
- package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
- package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
- package/framework/scaffold/motion-premium-3d/scaffold.yaml +133 -0
- package/framework/schemas/session.schema.json +109 -21
- package/framework/scripts/reference-capture.js +430 -0
- package/framework/scripts/visual-qa.js +674 -0
- package/framework/tasks/orchestrator-handoff.md +1 -1
- package/framework/tasks/orchestrator-resume.md +1 -1
- package/framework/tasks/orchestrator-route.md +1 -1
- package/framework/tasks/orchestrator-status.md +3 -3
- package/framework/tasks/qa-planning-gate-define.md +1 -1
- package/framework/templates/brandbook-html-tmpl.md +1 -1
- package/framework/templates/brandbook-tmpl.yaml +1 -1
- package/framework/templates/component-spec-tmpl.yaml +1 -1
- package/framework/templates/design-token-tmpl.yaml +1 -1
- package/framework/templates/icon-system-tmpl.yaml +1 -1
- package/framework/templates/team-planning-tasks.yaml +6 -5
- package/framework/workflows/brownfield-discovery.yaml +2 -2
- package/framework/workflows/brownfield-fullstack.yaml +15 -11
- package/framework/workflows/brownfield-service.yaml +14 -10
- package/framework/workflows/brownfield-ui.yaml +15 -11
- package/framework/workflows/greenfield-fullstack.yaml +16 -13
- package/framework/workflows/quick-flow.yaml +3 -3
- package/framework/workflows/standard-flow.yaml +12 -9
- package/package.json +10 -5
- package/src/autonomy/autonomous-gate.js +1 -0
- package/src/autonomy/build-state.js +1 -2
- package/src/autonomy/progress-reporter.js +1 -1
- package/src/config/agent-customizer.js +11 -3
- package/src/config/claude-settings-generator.js +27 -7
- package/src/config/context-file-generator.js +41 -21
- package/src/config/framework-adapter.js +1 -0
- package/src/config/gemini-hooks-generator.js +19 -7
- package/src/config/mcp-configs.js +1 -0
- package/src/context/layers/l1-global.js +2 -1
- package/src/dashboard/data-reader.js +4 -3
- package/src/dashboard/layout.js +2 -1
- package/src/decision/analyzer.js +6 -30
- package/src/decision/engine.js +4 -28
- package/src/decision/registry-healer.js +3 -2
- package/src/decision/registry-updater.js +23 -14
- package/src/extensions/loader.js +2 -8
- package/src/gates/g1-planning-complete.js +2 -1
- package/src/gates/g2-qa-planning.js +2 -1
- package/src/gates/g3-implementation.js +2 -1
- package/src/gates/g4-qa-implementation.js +3 -2
- package/src/gates/g5-deploy-ready.js +2 -1
- package/src/health/engine.js +4 -3
- package/src/installer/core.js +422 -81
- package/src/installer/preflight.js +131 -0
- package/src/installer/provider-overlay.js +3 -3
- package/src/installer/scaffold-applier.js +358 -0
- package/src/installer/templates.js +46 -29
- package/src/installer/validator.js +17 -12
- package/src/intelligence/registry-manager.js +22 -29
- package/src/intelligence/timeline.js +11 -6
- package/src/license/commands.js +1 -1
- package/src/license/wait.js +102 -0
- package/src/memory/agent-memory.js +81 -0
- package/src/memory/dream.js +32 -1
- package/src/merger/replace-merger.js +28 -15
- package/src/orchestrator/agent-selector.js +2 -1
- package/src/orchestrator/cli.js +1869 -71
- package/src/orchestrator/doctor.js +270 -0
- package/src/orchestrator/handoff-engine.js +4 -3
- package/src/orchestrator/index.js +2 -0
- package/src/orchestrator/pipeline-manager.js +306 -15
- package/src/orchestrator/session-manager.js +331 -6
- package/src/tasks/handoff.js +3 -2
- package/src/telemetry/config.js +4 -3
- package/src/telemetry/schema.js +1 -0
- package/src/terminal/collector.js +3 -2
- package/src/terminal/index.js +1 -2
- package/src/terminal/isolation.js +52 -18
- package/src/terminal/prompt-builder.js +42 -25
- package/src/terminal/run-parallel.js +1 -1
- package/src/terminal/run-team.js +3 -3
- package/src/terminal/team-task-list.js +43 -4
- package/src/upgrade/backup.js +3 -2
- package/src/upgrade/checker.js +3 -2
- package/src/upgrade/migrator.js +65 -7
- package/src/upgrade/tracked-files-detector.js +86 -0
- package/src/upgrade/user-messages.js +94 -0
- package/src/utils/config-parser.js +2 -1
- package/src/utils/feature-flags.js +2 -1
- package/src/utils/flatten-entities.js +69 -0
- package/src/utils/framework-dir.js +16 -0
- package/src/utils/model-id.js +85 -0
- package/src/utils/provider-limits.js +84 -23
- package/src/utils/schema-validator.js +1 -1
- package/src/wizard/i18n.js +5 -4
- package/src/wizard/index.js +14 -0
- package/assets/logo - c/303/263pia.png +0 -0
- package/assets/logo.svg +0 -42
- package/assets/logo2.png +0 -0
- package/assets/social-preview.png +0 -0
- package/scripts/bundle-framework.js +0 -69
- package/scripts/changelog-generator.js +0 -222
- package/scripts/codebase-mapper.js +0 -728
- package/scripts/commit-message-generator.js +0 -167
- package/scripts/coverage-analyzer.js +0 -260
- package/scripts/dependency-analyzer.js +0 -280
- package/scripts/doctor/checks/agents.js +0 -77
- package/scripts/doctor/checks/constitution.js +0 -41
- package/scripts/doctor/checks/domain-alignment.js +0 -58
- package/scripts/doctor/checks/prism-layers.js +0 -84
- package/scripts/doctor/checks/registry.js +0 -55
- package/scripts/doctor/checks/schemas.js +0 -61
- package/scripts/doctor/fixes/reference-fix.js +0 -100
- package/scripts/doctor/fixes/registry-fix.js +0 -56
- package/scripts/doctor/index.js +0 -212
- package/scripts/framework-analyzer.js +0 -308
- package/scripts/generate-constitution-domain.js +0 -253
- package/scripts/generate-signing-key.js +0 -33
- package/scripts/health-check.js +0 -481
- package/scripts/ide-sync.js +0 -326
- package/scripts/performance-analyzer.js +0 -325
- package/scripts/plan-tracker.js +0 -278
- package/scripts/populate-entity-registry.js +0 -481
- package/scripts/pr-review.js +0 -317
- package/scripts/rollback-manager.js +0 -310
- package/scripts/semantic-lint.js +0 -328
- package/scripts/sign-manifest.js +0 -53
- package/scripts/stuck-detector.js +0 -343
- package/scripts/test-quality-assessment.js +0 -257
- package/scripts/validate-agents.js +0 -368
- package/scripts/validate-package.js +0 -505
- package/scripts/validate-tasks.js +0 -465
- package/src/autonomy/worktree-manager.js +0 -250
- package/src/intelligence/decision-engine.js +0 -256
- package/src/intelligence/document-sharder.js +0 -221
- package/src/intelligence/elicitation.js +0 -265
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview /chati doctor — silent boot-time self-diagnostic.
|
|
3
|
+
*
|
|
4
|
+
* Runs a battery of fast (< 200ms) filesystem + version checks every time
|
|
5
|
+
* /chati boots. Pass-silent, fail-loud: the intent is that the user never
|
|
6
|
+
* sees doctor output when everything is fine; they see a specific,
|
|
7
|
+
* actionable message ONLY when something is off.
|
|
8
|
+
*
|
|
9
|
+
* Six checks, two severities:
|
|
10
|
+
*
|
|
11
|
+
* id severity description
|
|
12
|
+
* --------- -------- -----------
|
|
13
|
+
* license BLOCK ~/.chati-dev/license.yaml status != VALID (fail-open if missing)
|
|
14
|
+
* scaffold BLOCK projectDir/.chati.dev/ directory exists
|
|
15
|
+
* session BLOCK .chati/session.yaml parses cleanly (or is absent)
|
|
16
|
+
* hooks WARN .claude/settings.json has expected hook registrations
|
|
17
|
+
* model WARN session.active_model is populated (hook fills on first fire)
|
|
18
|
+
* node BLOCK process version >= 22
|
|
19
|
+
*
|
|
20
|
+
* BLOCK failures short-circuit boot with a fix instruction. WARN failures
|
|
21
|
+
* surface as non-blocking notices.
|
|
22
|
+
*
|
|
23
|
+
* Each check is a PURE FUNCTION on (options) — takes everything it needs
|
|
24
|
+
* as args (no global state). runDoctor composes them and aggregates the
|
|
25
|
+
* verdict.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { existsSync, readFileSync } from 'fs';
|
|
29
|
+
import { join } from 'path';
|
|
30
|
+
import { readLicenseStatus } from '../license/wait.js';
|
|
31
|
+
|
|
32
|
+
export const SEVERITY = Object.freeze({
|
|
33
|
+
BLOCK: 'BLOCK',
|
|
34
|
+
WARN: 'WARN',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {object} CheckResult
|
|
39
|
+
* @property {string} id
|
|
40
|
+
* @property {'BLOCK'|'WARN'} severity
|
|
41
|
+
* @property {'pass'|'fail'} status
|
|
42
|
+
* @property {string} message
|
|
43
|
+
* @property {string} [fix] Suggested fix when status=fail.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Individual checks — pure functions.
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* License status. Fail-open: missing file = pass (matches license-guard.js).
|
|
52
|
+
* @param {{ home?: string }} opts
|
|
53
|
+
* @returns {CheckResult}
|
|
54
|
+
*/
|
|
55
|
+
export function checkLicense({ home = process.env.HOME || '' } = {}) {
|
|
56
|
+
// F-A5-003: delegate to the canonical reader in license/wait.js so the
|
|
57
|
+
// doctor and the runtime-block path share a single source of truth. If
|
|
58
|
+
// the YAML shape changes, both fail/pass the same way.
|
|
59
|
+
const result = readLicenseStatus(home);
|
|
60
|
+
if (!result.present) {
|
|
61
|
+
return { id: 'license', severity: SEVERITY.BLOCK, status: 'pass', message: 'No license file (demo mode allowed — fail-open).' };
|
|
62
|
+
}
|
|
63
|
+
if (result.error) {
|
|
64
|
+
return {
|
|
65
|
+
id: 'license',
|
|
66
|
+
severity: SEVERITY.BLOCK,
|
|
67
|
+
status: 'fail',
|
|
68
|
+
message: `Cannot read license file: ${result.error}`,
|
|
69
|
+
fix: 'Restore ~/.chati-dev/license.yaml or run: npx chati-dev activate --key=YOUR-KEY',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const status = result.status || 'UNKNOWN';
|
|
73
|
+
if (status === 'VALID') {
|
|
74
|
+
return { id: 'license', severity: SEVERITY.BLOCK, status: 'pass', message: 'License: VALID.' };
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
id: 'license',
|
|
78
|
+
severity: SEVERITY.BLOCK,
|
|
79
|
+
status: 'fail',
|
|
80
|
+
message: `License status: ${status}`,
|
|
81
|
+
fix: 'Paste in another terminal: npx chati-dev activate --key=YOUR-KEY',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Scaffold presence in the project. Required — without it, hooks and
|
|
87
|
+
* agent files are unreachable.
|
|
88
|
+
* @param {{ projectDir: string }} opts
|
|
89
|
+
* @returns {CheckResult}
|
|
90
|
+
*/
|
|
91
|
+
export function checkScaffold({ projectDir }) {
|
|
92
|
+
const scaffoldDir = join(projectDir, '.chati.dev');
|
|
93
|
+
if (existsSync(scaffoldDir)) {
|
|
94
|
+
return { id: 'scaffold', severity: SEVERITY.BLOCK, status: 'pass', message: '.chati.dev/ scaffold present.' };
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
id: 'scaffold',
|
|
98
|
+
severity: SEVERITY.BLOCK,
|
|
99
|
+
status: 'fail',
|
|
100
|
+
message: '.chati.dev/ scaffold directory not found in project root.',
|
|
101
|
+
fix: 'Run: npx chati-dev init (from the project root)',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Session file integrity. Absence is fine (pre-init state). Presence
|
|
107
|
+
* with parse error is a BLOCK — we cannot route agent messages.
|
|
108
|
+
* @param {{ projectDir: string }} opts
|
|
109
|
+
* @returns {CheckResult}
|
|
110
|
+
*/
|
|
111
|
+
export function checkSession({ projectDir }) {
|
|
112
|
+
const sessionPath = join(projectDir, '.chati', 'session.yaml');
|
|
113
|
+
if (!existsSync(sessionPath)) {
|
|
114
|
+
return {
|
|
115
|
+
id: 'session', severity: SEVERITY.BLOCK, status: 'pass',
|
|
116
|
+
message: 'Session not yet initialized (pre-init or fresh project).',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const raw = readFileSync(sessionPath, 'utf-8');
|
|
121
|
+
// Minimal integrity: must contain at least one YAML-ish `key:` line and
|
|
122
|
+
// no obviously malformed constructs.
|
|
123
|
+
const hasKey = /^\s*\w+:/m.test(raw);
|
|
124
|
+
const hasBadStructure = /\[\s*\w+:\s*/.test(raw); // `[key:` is not valid YAML shorthand
|
|
125
|
+
if (!hasKey || hasBadStructure) {
|
|
126
|
+
return {
|
|
127
|
+
id: 'session',
|
|
128
|
+
severity: SEVERITY.BLOCK,
|
|
129
|
+
status: 'fail',
|
|
130
|
+
message: 'session.yaml is present but appears corrupted.',
|
|
131
|
+
fix: 'Inspect .chati/session.yaml manually, or re-run: npx chati-dev init',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return { id: 'session', severity: SEVERITY.BLOCK, status: 'pass', message: 'session.yaml parses cleanly.' };
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return {
|
|
137
|
+
id: 'session',
|
|
138
|
+
severity: SEVERITY.BLOCK,
|
|
139
|
+
status: 'fail',
|
|
140
|
+
message: `Cannot read session.yaml: ${err.message}`,
|
|
141
|
+
fix: 'Check filesystem permissions on .chati/session.yaml',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Hook drift detection. Looks for a representative sample of expected
|
|
148
|
+
* hooks in .claude/settings.json. Missing = WARN (hook system is
|
|
149
|
+
* advisory; system still works).
|
|
150
|
+
* @param {{ projectDir: string }} opts
|
|
151
|
+
* @returns {CheckResult}
|
|
152
|
+
*/
|
|
153
|
+
export function checkHooks({ projectDir }) {
|
|
154
|
+
const settingsPath = join(projectDir, '.claude', 'settings.json');
|
|
155
|
+
if (!existsSync(settingsPath)) {
|
|
156
|
+
return {
|
|
157
|
+
id: 'hooks', severity: SEVERITY.WARN, status: 'pass',
|
|
158
|
+
message: '.claude/settings.json not found — skipping hook drift check.',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const raw = readFileSync(settingsPath, 'utf-8');
|
|
163
|
+
const settings = JSON.parse(raw);
|
|
164
|
+
const hookConfigs = settings && settings.hooks ? settings.hooks : {};
|
|
165
|
+
const expected = ['prism-engine.js', 'license-guard.js'];
|
|
166
|
+
const flat = JSON.stringify(hookConfigs);
|
|
167
|
+
const missing = expected.filter(h => !flat.includes(h));
|
|
168
|
+
if (missing.length === 0) {
|
|
169
|
+
return { id: 'hooks', severity: SEVERITY.WARN, status: 'pass', message: 'Expected hooks registered.' };
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
id: 'hooks',
|
|
173
|
+
severity: SEVERITY.WARN,
|
|
174
|
+
status: 'fail',
|
|
175
|
+
message: `Missing hook registrations: ${missing.join(', ')}`,
|
|
176
|
+
fix: 'Re-run installer to refresh .claude/settings.json: npx chati-dev init (is idempotent)',
|
|
177
|
+
};
|
|
178
|
+
} catch (err) {
|
|
179
|
+
return {
|
|
180
|
+
id: 'hooks',
|
|
181
|
+
severity: SEVERITY.WARN,
|
|
182
|
+
status: 'fail',
|
|
183
|
+
message: `Cannot parse .claude/settings.json: ${err.message}`,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Active model detection. Populated by /chati boot or by prism-engine
|
|
190
|
+
* on first fire. Absent = WARN — context bracket will still compute via
|
|
191
|
+
* provider default, just less precise.
|
|
192
|
+
* @param {{ projectDir: string }} opts
|
|
193
|
+
* @returns {CheckResult}
|
|
194
|
+
*/
|
|
195
|
+
export function checkModel({ projectDir }) {
|
|
196
|
+
const sessionPath = join(projectDir, '.chati', 'session.yaml');
|
|
197
|
+
if (!existsSync(sessionPath)) {
|
|
198
|
+
return {
|
|
199
|
+
id: 'model', severity: SEVERITY.WARN, status: 'pass',
|
|
200
|
+
message: 'Session not yet initialized — model detection deferred.',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const raw = readFileSync(sessionPath, 'utf-8');
|
|
205
|
+
const match = raw.match(/^\s*active_model:\s*(.+)$/m);
|
|
206
|
+
const value = match ? match[1].trim().replace(/^["']|["']$/g, '') : '';
|
|
207
|
+
if (!value || value === 'null' || value === '~' || value === '') {
|
|
208
|
+
return {
|
|
209
|
+
id: 'model',
|
|
210
|
+
severity: SEVERITY.WARN,
|
|
211
|
+
status: 'fail',
|
|
212
|
+
message: 'active_model not set — hook will populate on next prompt.',
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return { id: 'model', severity: SEVERITY.WARN, status: 'pass', message: `active_model: ${value}` };
|
|
216
|
+
} catch {
|
|
217
|
+
return {
|
|
218
|
+
id: 'model', severity: SEVERITY.WARN, status: 'pass',
|
|
219
|
+
message: 'Cannot read active_model; deferring to hook.',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Node version gate. Framework assumes Node 22+ for modern ESM, fetch,
|
|
226
|
+
* globbing. Earlier versions break test runs and hook spawns.
|
|
227
|
+
* @param {{ versionString?: string }} opts
|
|
228
|
+
* @returns {CheckResult}
|
|
229
|
+
*/
|
|
230
|
+
export function checkNode({ versionString = process.version } = {}) {
|
|
231
|
+
const match = versionString.match(/^v?(\d+)/);
|
|
232
|
+
const major = match ? parseInt(match[1], 10) : 0;
|
|
233
|
+
if (major >= 22) {
|
|
234
|
+
return { id: 'node', severity: SEVERITY.BLOCK, status: 'pass', message: `Node ${versionString} OK.` };
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
id: 'node',
|
|
238
|
+
severity: SEVERITY.BLOCK,
|
|
239
|
+
status: 'fail',
|
|
240
|
+
message: `Node ${versionString} is below the required v22.`,
|
|
241
|
+
fix: 'Install Node 22+: https://nodejs.org/en/download',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// runDoctor — aggregate all six checks.
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @param {{ projectDir: string, home?: string }} opts
|
|
251
|
+
* @returns {{
|
|
252
|
+
* ok: boolean,
|
|
253
|
+
* checks: CheckResult[],
|
|
254
|
+
* blockers: CheckResult[],
|
|
255
|
+
* warnings: CheckResult[]
|
|
256
|
+
* }}
|
|
257
|
+
*/
|
|
258
|
+
export function runDoctor(opts) {
|
|
259
|
+
const checks = [
|
|
260
|
+
checkLicense({ home: opts.home }),
|
|
261
|
+
checkScaffold({ projectDir: opts.projectDir }),
|
|
262
|
+
checkSession({ projectDir: opts.projectDir }),
|
|
263
|
+
checkHooks({ projectDir: opts.projectDir }),
|
|
264
|
+
checkModel({ projectDir: opts.projectDir }),
|
|
265
|
+
checkNode(),
|
|
266
|
+
];
|
|
267
|
+
const blockers = checks.filter(c => c.status === 'fail' && c.severity === SEVERITY.BLOCK);
|
|
268
|
+
const warnings = checks.filter(c => c.status === 'fail' && c.severity === SEVERITY.WARN);
|
|
269
|
+
return { ok: blockers.length === 0, checks, blockers, warnings };
|
|
270
|
+
}
|
|
@@ -12,6 +12,7 @@ import { updateClaudeMd } from '../memory/magic-docs.js';
|
|
|
12
12
|
import { generateContextFiles } from '../config/context-file-generator.js';
|
|
13
13
|
import { existsSync, readdirSync } from 'fs';
|
|
14
14
|
import { join } from 'path';
|
|
15
|
+
import { resolveFrameworkDir } from '../utils/framework-dir.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Execute a full agent-to-agent handoff.
|
|
@@ -151,11 +152,11 @@ export function validateHandoffPreconditions(params, projectDir = '.') {
|
|
|
151
152
|
// Deterministic artifact checks for UX agent handoffs
|
|
152
153
|
const agent = params.fromTask?.agent || params.fromTask?.id?.split('-')[0] || '';
|
|
153
154
|
if (agent === 'ux') {
|
|
154
|
-
const brandbookPath = join(projectDir,
|
|
155
|
+
const brandbookPath = join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', '4-UX', 'brandbook.html');
|
|
155
156
|
if (!existsSync(brandbookPath)) {
|
|
156
157
|
issues.push('brandbook.html is missing — UX handoff requires the visual brandbook file on disk');
|
|
157
158
|
}
|
|
158
|
-
const discoveryLogPath = join(projectDir,
|
|
159
|
+
const discoveryLogPath = join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', '4-UX', 'component-discovery-log.md');
|
|
159
160
|
if (!existsSync(discoveryLogPath)) {
|
|
160
161
|
issues.push('component-discovery-log.md is missing — UX handoff requires component discovery documentation');
|
|
161
162
|
}
|
|
@@ -225,7 +226,7 @@ export function loadHandoffContext(projectDir, fromAgent) {
|
|
|
225
226
|
* @returns {object[]} Array of handoff summaries
|
|
226
227
|
*/
|
|
227
228
|
export function getHandoffHistory(projectDir) {
|
|
228
|
-
const handoffsDir = join(projectDir,
|
|
229
|
+
const handoffsDir = join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', 'handoffs');
|
|
229
230
|
|
|
230
231
|
if (!existsSync(handoffsDir)) {
|
|
231
232
|
return [];
|