chati-dev 4.0.1 → 4.0.2

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 (44) hide show
  1. package/framework/agents/build/dev.md +23 -3
  2. package/framework/agents/plan/ux.md +354 -8
  3. package/framework/config.yaml +3 -3
  4. package/framework/constitution.md +4 -3
  5. package/framework/domains/agents/architect.yaml +1 -3
  6. package/framework/domains/agents/brief.yaml +1 -1
  7. package/framework/domains/agents/brownfield-wu.yaml +2 -2
  8. package/framework/domains/agents/detail.yaml +1 -1
  9. package/framework/domains/agents/devops.yaml +2 -4
  10. package/framework/domains/agents/greenfield-wu.yaml +2 -2
  11. package/framework/domains/agents/phases.yaml +1 -1
  12. package/framework/domains/agents/qa-implementation.yaml +4 -6
  13. package/framework/domains/agents/qa-planning.yaml +7 -10
  14. package/framework/domains/agents/tasks.yaml +1 -1
  15. package/framework/domains/agents/ux.yaml +21 -3
  16. package/framework/domains/constitution.yaml +4 -4
  17. package/framework/domains/global.yaml +1 -1
  18. package/framework/intelligence/context-engine.md +1 -1
  19. package/framework/templates/brandbook-tmpl.yaml +40 -0
  20. package/framework/templates/component-spec-tmpl.yaml +50 -3
  21. package/package.json +1 -1
  22. package/src/api/index.js +10 -19
  23. package/src/autonomy/build-loop.js +1 -1
  24. package/src/autonomy/cause-analyzer.js +1 -1
  25. package/src/autonomy/worktree-manager.js +7 -2
  26. package/src/config/agent-customizer.js +1 -5
  27. package/src/config/context-file-generator.js +1 -1
  28. package/src/context/bracket-tracker.js +2 -13
  29. package/src/decision/engine.js +4 -0
  30. package/src/health/auto-fix.js +1 -1
  31. package/src/installer/core.js +8 -1
  32. package/src/intelligence/context-status.js +2 -17
  33. package/src/intelligence/decision-engine.js +5 -2
  34. package/src/intelligence/timeline.js +1 -1
  35. package/src/merger/semantic-merger.js +1 -1
  36. package/src/orchestrator/pipeline-manager.js +33 -46
  37. package/src/quality/metrics-collector.js +0 -2
  38. package/src/telemetry/config.js +2 -2
  39. package/src/telemetry/schema.js +1 -1
  40. package/src/terminal/isolation.js +10 -1
  41. package/src/terminal/prompt-builder.js +77 -9
  42. package/src/utils/brackets.js +29 -0
  43. package/src/utils/event-bus.js +1 -1
  44. package/src/utils/provider-limits.js +13 -0
@@ -15,6 +15,37 @@ import { getCurrentVersion } from '../upgrade/checker.js';
15
15
  */
16
16
  export const PIPELINE_PHASES = ['discover', 'plan', 'build', 'deploy'];
17
17
 
18
+ /**
19
+ * Emit telemetry events for pipeline completion and flush to backend.
20
+ *
21
+ * @param {object} state - Pipeline state
22
+ */
23
+ function emitPipelineComplete(state) {
24
+ const pipelineType = state.isQuickFlow ? 'quick-flow' : state.isStandardFlow ? 'standard' : 'full';
25
+ const totalDuration = Date.now() - new Date(state.startedAt).getTime();
26
+ telemetryTrack('pipeline_completed', {
27
+ pipelineType,
28
+ totalDuration,
29
+ agentsRun: state.completedAgents.length,
30
+ finalStatus: 'completed',
31
+ deviationCount: (state.modeTransitions || []).length,
32
+ });
33
+ telemetryTrack('session_completed', {
34
+ sessionId: state.sessionId || 'unknown',
35
+ pipelineType,
36
+ mode: state.phase === 'deploy' ? 'deploy' : 'build',
37
+ finalStage: state.phase,
38
+ duration: totalDuration,
39
+ agentCount: state.completedAgents.length,
40
+ success: true,
41
+ });
42
+ const flushedEvents = telemetryFlush();
43
+ if (flushedEvents.length > 0) {
44
+ const tConfig = getTelemetryConfig(state.targetDir || process.cwd());
45
+ sendEvents(flushedEvents, { ...tConfig, version: state.chatiVersion || 'unknown' });
46
+ }
47
+ }
48
+
18
49
  /**
19
50
  * Agent status values.
20
51
  */
@@ -294,29 +325,7 @@ export function advancePipeline(pipelineState, completedAgent, results = {}) {
294
325
 
295
326
  // Pipeline complete
296
327
  newState.completedAt = new Date().toISOString();
297
- const pipelineType1 = newState.isQuickFlow ? 'quick-flow' : newState.isStandardFlow ? 'standard' : 'full';
298
- const totalDuration1 = Date.now() - new Date(newState.startedAt).getTime();
299
- telemetryTrack('pipeline_completed', {
300
- pipelineType: pipelineType1,
301
- totalDuration: totalDuration1,
302
- agentsRun: newState.completedAgents.length,
303
- finalStatus: 'completed',
304
- deviationCount: (newState.modeTransitions || []).length,
305
- });
306
- telemetryTrack('session_completed', {
307
- sessionId: newState.sessionId || 'unknown',
308
- pipelineType: pipelineType1,
309
- mode: newState.phase === 'deploy' ? 'deploy' : 'build',
310
- finalStage: newState.phase,
311
- duration: totalDuration1,
312
- agentCount: newState.completedAgents.length,
313
- success: true,
314
- });
315
- const flushedEvents = telemetryFlush();
316
- if (flushedEvents.length > 0) {
317
- const tConfig = getTelemetryConfig(newState.targetDir || process.cwd());
318
- sendEvents(flushedEvents, { ...tConfig, version: newState.chatiVersion || 'unknown' });
319
- }
328
+ emitPipelineComplete(newState);
320
329
  return {
321
330
  state: newState,
322
331
  nextAction: 'complete',
@@ -366,29 +375,7 @@ export function advancePipeline(pipelineState, completedAgent, results = {}) {
366
375
 
367
376
  // Pipeline complete
368
377
  newState.completedAt = new Date().toISOString();
369
- const pipelineType2 = newState.isQuickFlow ? 'quick-flow' : newState.isStandardFlow ? 'standard' : 'full';
370
- const totalDuration2 = Date.now() - new Date(newState.startedAt).getTime();
371
- telemetryTrack('pipeline_completed', {
372
- pipelineType: pipelineType2,
373
- totalDuration: totalDuration2,
374
- agentsRun: newState.completedAgents.length,
375
- finalStatus: 'completed',
376
- deviationCount: (newState.modeTransitions || []).length,
377
- });
378
- telemetryTrack('session_completed', {
379
- sessionId: newState.sessionId || 'unknown',
380
- pipelineType: pipelineType2,
381
- mode: newState.phase === 'deploy' ? 'deploy' : 'build',
382
- finalStage: newState.phase,
383
- duration: totalDuration2,
384
- agentCount: newState.completedAgents.length,
385
- success: true,
386
- });
387
- const flushedEvents2 = telemetryFlush();
388
- if (flushedEvents2.length > 0) {
389
- const tConfig2 = getTelemetryConfig(newState.targetDir || process.cwd());
390
- sendEvents(flushedEvents2, { ...tConfig2, version: newState.chatiVersion || 'unknown' });
391
- }
378
+ emitPipelineComplete(newState);
392
379
  return {
393
380
  state: newState,
394
381
  nextAction: 'complete',
@@ -199,14 +199,12 @@ export function calculateTrend(metrics) {
199
199
  let sumY = 0;
200
200
  let sumXY = 0;
201
201
  let sumX2 = 0;
202
- let sumY2 = 0;
203
202
 
204
203
  for (let i = 0; i < n; i++) {
205
204
  sumX += i;
206
205
  sumY += values[i];
207
206
  sumXY += i * values[i];
208
207
  sumX2 += i * i;
209
- sumY2 += values[i] * values[i];
210
208
  }
211
209
 
212
210
  const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
@@ -26,8 +26,8 @@ export function getTelemetryConfig(targetDir) {
26
26
  const defaults = {
27
27
  enabled: true,
28
28
  anonymousId: null,
29
- endpoint: 'https://chati-telemetry.vercel.app/api/events',
30
- apiKey: '10b0b54ba4f392fa46379ba778062ab0af5ca61e79609a7dce4aadd660104b56',
29
+ endpoint: process.env.CHATI_TELEMETRY_ENDPOINT || 'https://chati-telemetry.vercel.app/api/events',
30
+ apiKey: process.env.CHATI_TELEMETRY_KEY || '10b0b54ba4f392fa46379ba778062ab0af5ca61e79609a7dce4aadd660104b56',
31
31
  };
32
32
 
33
33
  if (!existsSync(configPath)) return defaults;
@@ -25,7 +25,7 @@ export const TELEMETRY_EVENTS = [
25
25
  // Property Schemas (allowed fields per event type)
26
26
  // ---------------------------------------------------------------------------
27
27
 
28
- const EVENT_PROPERTIES = {
28
+ export const EVENT_PROPERTIES = {
29
29
  installation_completed: [
30
30
  'providers', 'editors', 'projectType', 'language',
31
31
  'primaryProvider', 'installDuration',
@@ -1,3 +1,5 @@
1
+ import { posix } from 'path';
2
+
1
3
  /**
2
4
  * @fileoverview Write scope isolation for multi-terminal execution.
3
5
  *
@@ -96,7 +98,14 @@ export function isPathAllowed(agent, filePath) {
96
98
  return false;
97
99
  }
98
100
 
99
- const normalised = filePath.replace(/\\/g, '/');
101
+ // Normalize backslashes and resolve traversal sequences (../)
102
+ const normalised = posix.normalize(filePath.replace(/\\/g, '/'));
103
+
104
+ // Reject paths that escape the project root
105
+ if (normalised.startsWith('../') || normalised.startsWith('/')) {
106
+ return false;
107
+ }
108
+
100
109
  return scope.some(prefix => normalised === prefix || normalised.startsWith(prefix));
101
110
  }
102
111
 
@@ -17,6 +17,7 @@ import { resolveOverlayPath } from '../installer/provider-overlay.js';
17
17
  import { resolveProviderForAgent } from './cli-registry.js';
18
18
  import { buildCompactGotchasSummary } from '../memory/gotchas-injector.js';
19
19
  import { estimateTokens } from './cost-tracker.js';
20
+ import { PROVIDER_LIMITS as PROVIDER_TOKEN_LIMITS } from '../utils/provider-limits.js';
20
21
 
21
22
  // Import AGENT_MODELS from model-governance (safe — named export,
22
23
  // does not trigger main() which is guarded by fileURLToPath check).
@@ -186,12 +187,15 @@ export function buildAgentPrompt(config) {
186
187
  // 8. Session context (uses resolved model/provider)
187
188
  sections.push(buildSessionSection(config, { model, provider: resolvedProvider }));
188
189
 
189
- // 9. Output format instructions (handoff template — includes provider/model for audit)
190
+ // 9. Anti-laziness reinforcement (proven remediation techniques)
191
+ sections.push(buildAntiLazinessSection(config.agent));
192
+
193
+ // 10. Output format instructions (handoff template — includes provider/model for audit)
190
194
  sections.push(buildOutputInstructions({ provider: resolvedProvider, model }));
191
195
 
192
196
  const prompt = sections.join('\n\n---\n\n');
193
197
 
194
- // 10. Prompt size guard — validate before returning
198
+ // 11. Prompt size guard — validate before returning
195
199
  const sizeCheck = validatePromptSize(prompt, resolvedProvider);
196
200
 
197
201
  return {
@@ -362,17 +366,81 @@ function buildSessionSection(config, resolvedModelInfo = {}) {
362
366
  }
363
367
 
364
368
  // ---------------------------------------------------------------------------
365
- // Prompt Size Guard
369
+ // Anti-Laziness Reinforcement
366
370
  // ---------------------------------------------------------------------------
367
371
 
368
372
  /**
369
- * Provider-specific token limits for prompt size validation.
373
+ * Agents whose output is code or artifacts benefit most from anti-laziness.
374
+ * Planning/discovery agents get a lighter version.
370
375
  */
371
- const PROVIDER_TOKEN_LIMITS = {
372
- claude: 200_000,
373
- gemini: 1_000_000,
374
- codex: 128_000,
375
- };
376
+ const CODE_PRODUCING_AGENTS = new Set(['dev', 'architect', 'ux', 'devops']);
377
+
378
+ /**
379
+ * Build anti-laziness reinforcement section.
380
+ *
381
+ * Injects proven remediation techniques into every spawned agent prompt.
382
+ * Techniques sourced from empirical research (Microsoft Research, LazyBench):
383
+ * - Stakes framing (+10% performance)
384
+ * - Step-by-step structure (+34% -> 80% accuracy)
385
+ * - Completeness enforcement (+45% output quality)
386
+ *
387
+ * @param {string} agent - Agent name
388
+ * @returns {string} Formatted anti-laziness section
389
+ */
390
+ export function buildAntiLazinessSection(agent) {
391
+ const isCodeAgent = CODE_PRODUCING_AGENTS.has(agent);
392
+
393
+ const lines = [
394
+ '<!-- ANTI-LAZINESS REINFORCEMENT -->',
395
+ '## Output Quality Requirements',
396
+ '',
397
+ 'This is production-critical work for a real project. Every artifact you produce will be consumed by downstream agents and must be complete and accurate.',
398
+ '',
399
+ '### Completeness Rules',
400
+ '1. Before starting, count all deliverables. Lock that count.',
401
+ '2. Produce EVERY deliverable completely. No shortcuts, no placeholders.',
402
+ '3. After finishing, cross-check: output count MUST match initial scope.',
403
+ '',
404
+ ];
405
+
406
+ if (isCodeAgent) {
407
+ lines.push(
408
+ '### Code Output Rules',
409
+ '- NEVER use placeholder comments: `// ...`, `// rest of code`, `// TODO`, `// implement here`',
410
+ '- NEVER output skeleton/stub code when full implementation is expected',
411
+ '- NEVER describe what code should do instead of writing it',
412
+ '- NEVER compress or skip sections when approaching output limits',
413
+ '',
414
+ );
415
+ }
416
+
417
+ if (agent === 'ux') {
418
+ lines.push(
419
+ '### Design Anti-Bias Rules',
420
+ '- NEVER default to centered single-column layouts — vary layout structure across sections',
421
+ '- NEVER use oversaturated primary colors (HSL saturation > 80%) without brand justification',
422
+ '- NEVER use only one sans-serif font (Inter, Roboto) — evaluate serif and display alternatives',
423
+ '- NEVER show only happy-path states — every component needs empty, loading, error, and disabled states',
424
+ '- NEVER use lorem ipsum, "John Doe", or generic placeholder content',
425
+ '- NEVER animate width/height/top/left — use transform and opacity only',
426
+ '',
427
+ );
428
+ }
429
+
430
+ lines.push(
431
+ '### When Approaching Output Limits',
432
+ '- Do NOT compress remaining sections',
433
+ '- Do NOT skip to conclusion',
434
+ '- Write at full quality to a clean breakpoint',
435
+ '- Signal clearly: `[PAUSED at deliverable X of Y. Continuing in next iteration.]`',
436
+ );
437
+
438
+ return lines.join('\n');
439
+ }
440
+
441
+ // ---------------------------------------------------------------------------
442
+ // Prompt Size Guard
443
+ // ---------------------------------------------------------------------------
376
444
 
377
445
  /**
378
446
  * Validate prompt size against provider-specific limits.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview Canonical bracket definitions for context window management.
3
+ *
4
+ * Single source of truth for bracket thresholds, layer configurations,
5
+ * and budget ratios. Consumers import from here to avoid duplication.
6
+ *
7
+ * Progressive Reinforcement Model (v4.0):
8
+ * As context depletes, budget INCREASES (model needs MORE reinforcement).
9
+ * Budget expressed as ratio of provider's total context window.
10
+ */
11
+
12
+ /**
13
+ * Bracket definitions as an object (keyed by name).
14
+ * @type {Record<string, {min: number, max: number, layers: string[], budgetRatio: number}>}
15
+ */
16
+ export const BRACKETS = {
17
+ FRESH: { min: 60, max: 100, layers: ['L0', 'L1', 'L2', 'L3', 'L4', 'L5'], budgetRatio: 0.015 },
18
+ MODERATE: { min: 40, max: 60, layers: ['L0', 'L1', 'L2', 'L3', 'L5'], budgetRatio: 0.025 },
19
+ DEPLETED: { min: 25, max: 40, layers: ['L0', 'L1', 'L2'], budgetRatio: 0.040 },
20
+ CRITICAL: { min: 0, max: 25, layers: ['L0', 'L1'], budgetRatio: 0.050 },
21
+ };
22
+
23
+ /**
24
+ * Bracket definitions as an ordered array (for iteration/lookup by range).
25
+ * @type {Array<{name: string, min: number, max: number, layers: string[], budgetRatio: number}>}
26
+ */
27
+ export const BRACKETS_LIST = Object.entries(BRACKETS).map(
28
+ ([name, data]) => ({ name, ...data }),
29
+ );
@@ -7,7 +7,7 @@
7
7
 
8
8
  /**
9
9
  * @deprecated Not currently imported by any production module.
10
- * Retained for potential future integration. Remove if still unused by v4.0.
10
+ * Retained for potential future integration. Review for removal or integration by v5.0.
11
11
  */
12
12
 
13
13
  import { EventEmitter } from 'node:events';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @fileoverview Canonical provider context window limits.
3
+ *
4
+ * Single source of truth for provider token limits used by
5
+ * bracket-tracker, context-status, and prompt-builder.
6
+ */
7
+
8
+ /** Provider context window limits (tokens). */
9
+ export const PROVIDER_LIMITS = {
10
+ claude: 200_000,
11
+ gemini: 1_000_000,
12
+ codex: 128_000,
13
+ };