chati-dev 4.0.11 → 4.1.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.
Files changed (107) hide show
  1. package/README.md +5 -0
  2. package/bin/chati.js +16 -0
  3. package/framework/agents/build/dev.md +43 -10
  4. package/framework/agents/discover/brief.md +38 -8
  5. package/framework/agents/discover/brownfield-wu.md +44 -3
  6. package/framework/agents/discover/greenfield-wu.md +14 -0
  7. package/framework/agents/plan/architect.md +6 -0
  8. package/framework/agents/plan/detail.md +25 -0
  9. package/framework/agents/plan/tasks.md +29 -1
  10. package/framework/agents/plan/ux-brand-architect.md +215 -0
  11. package/framework/agents/plan/ux-component-engineer.md +289 -0
  12. package/framework/agents/plan/ux-researcher.md +166 -0
  13. package/framework/agents/plan/ux.md +126 -1008
  14. package/framework/agents/quality/qa-implementation.md +121 -22
  15. package/framework/agents/quality/qa-planning.md +18 -0
  16. package/framework/config.yaml +15 -4
  17. package/framework/constitution.md +8 -2
  18. package/framework/context/root.md +1 -1
  19. package/framework/data/entity-registry.yaml +59 -3
  20. package/framework/hooks/constitution-guard.js +67 -1
  21. package/framework/hooks/license-guard.js +4 -4
  22. package/framework/hooks/model-governance.js +2 -1
  23. package/framework/hooks/prism-engine.js +74 -6
  24. package/framework/hooks/read-protection.js +1 -1
  25. package/framework/hooks/session-digest.js +159 -7
  26. package/framework/hooks/settings.json +16 -4
  27. package/framework/hooks/style-guard.js +134 -0
  28. package/framework/hooks/undercover-guard.js +220 -0
  29. package/framework/intelligence/context-engine.md +21 -0
  30. package/framework/intelligence/hooks-performance.md +54 -0
  31. package/framework/intelligence/memory-layer.md +47 -0
  32. package/framework/migrations/v4.0-to-v4.1.yaml +165 -0
  33. package/framework/orchestrator/chati.md +327 -1067
  34. package/framework/templates/brandbook-html-tmpl.md +107 -0
  35. package/framework/templates/session-memory-tmpl.yaml +68 -0
  36. package/package.json +1 -1
  37. package/src/autonomy/build-state.js +1 -1
  38. package/src/autonomy/worktree-manager.js +13 -13
  39. package/src/config/agent-customizer.js +1 -1
  40. package/src/config/gemini-hooks-generator.js +6 -6
  41. package/src/config/ide-configs.js +1 -1
  42. package/src/context/bracket-tracker.js +25 -4
  43. package/src/context/engine.js +37 -7
  44. package/src/context/formatter.js +45 -1
  45. package/src/context/index.js +3 -3
  46. package/src/dashboard/data-reader.js +7 -7
  47. package/src/decision/engine.js +2 -2
  48. package/src/decision/registry-healer.js +1 -1
  49. package/src/decision/registry-updater.js +2 -2
  50. package/src/extensions/loader.js +1 -1
  51. package/src/gates/g1-planning-complete.js +1 -1
  52. package/src/gates/g2-qa-planning.js +1 -1
  53. package/src/gates/g3-implementation.js +4 -4
  54. package/src/gates/g4-qa-implementation.js +2 -2
  55. package/src/health/auto-fix.js +3 -3
  56. package/src/health/engine.js +2 -2
  57. package/src/installer/brownfield-upgrader.js +3 -3
  58. package/src/installer/manifest.js +1 -1
  59. package/src/installer/transaction.js +1 -1
  60. package/src/installer/validator.js +2 -2
  61. package/src/intelligence/decision-engine.js +1 -1
  62. package/src/intelligence/memory-manager.js +1 -1
  63. package/src/intelligence/registry-manager.js +2 -2
  64. package/src/intelligence/timeline.js +1 -1
  65. package/src/license/client.js +1 -1
  66. package/src/license/commands.js +2 -2
  67. package/src/memory/agent-memory.js +3 -3
  68. package/src/memory/daily-digest.js +170 -0
  69. package/src/memory/dream.js +254 -0
  70. package/src/memory/gotchas.js +2 -2
  71. package/src/memory/index.js +18 -0
  72. package/src/memory/magic-docs.js +98 -0
  73. package/src/memory/memory-extractor.js +163 -0
  74. package/src/memory/session-digest.js +144 -6
  75. package/src/merger/yaml-merger.js +1 -1
  76. package/src/orchestrator/cli.js +980 -0
  77. package/src/orchestrator/handoff-engine.js +25 -4
  78. package/src/orchestrator/index.js +9 -0
  79. package/src/orchestrator/session-manager.js +1 -1
  80. package/src/preview/detector.js +3 -3
  81. package/src/preview/launcher.js +2 -2
  82. package/src/quality/metrics-collector.js +1 -1
  83. package/src/quality/test-runner.js +2 -4
  84. package/src/scanning/density-scanner.js +51 -0
  85. package/src/scanning/env-scanner.js +97 -0
  86. package/src/scanning/index.js +7 -0
  87. package/src/scanning/leakage-scanner.js +54 -0
  88. package/src/scanning/placeholder-scanner.js +40 -0
  89. package/src/scanning/security-scanner.js +94 -0
  90. package/src/security/bash-security.js +335 -0
  91. package/src/security/index.js +9 -0
  92. package/src/telemetry/config.js +3 -3
  93. package/src/telemetry/sender.js +1 -1
  94. package/src/terminal/cli-registry.js +1 -1
  95. package/src/terminal/cost-tracker.js +1 -2
  96. package/src/terminal/prompt-builder.js +11 -27
  97. package/src/terminal/rate-limiter.js +1 -2
  98. package/src/terminal/run-agent.js +3 -3
  99. package/src/terminal/spawner.js +41 -4
  100. package/src/upgrade/checker.js +2 -2
  101. package/src/upgrade/migrator.js +1 -1
  102. package/src/utils/config-parser.js +1 -1
  103. package/src/utils/file-lock.js +3 -3
  104. package/src/utils/provider-limits.js +35 -4
  105. package/src/wizard/i18n.js +2 -2
  106. package/src/wizard/index.js +2 -1
  107. package/src/wizard/questions.js +4 -2
@@ -56,6 +56,144 @@ export function buildSessionDigest(projectDir, sessionState) {
56
56
  return digest;
57
57
  }
58
58
 
59
+ /**
60
+ * Maximum characters for the structured digest (~10K tokens).
61
+ */
62
+ const MAX_STRUCTURED_CHARS = 40_000;
63
+
64
+ /**
65
+ * Section token budgets for structured digest (chars = tokens * 4).
66
+ */
67
+ const SECTION_BUDGETS = {
68
+ current_agent: 400, // ~100 tokens
69
+ pipeline_position: 400, // ~100 tokens
70
+ active_task: 2000, // ~500 tokens
71
+ files_changed: 4000, // ~1000 tokens
72
+ blockers: 4000, // ~1000 tokens
73
+ decisions_made: 12000, // ~3000 tokens
74
+ gotchas_found: 8000, // ~2000 tokens
75
+ next_steps: 9200, // ~2300 tokens
76
+ };
77
+
78
+ /**
79
+ * Build a structured 8-section session digest with token budgets.
80
+ * Richer than buildSessionDigest — captures decisions, blockers, gotchas,
81
+ * files changed, and next steps for better context recovery after compaction.
82
+ *
83
+ * Inspired by Claude Code's structured session memory (10 sections, 12K tokens).
84
+ *
85
+ * @param {string} projectDir - Project directory
86
+ * @param {object} sessionState - Current session.yaml data
87
+ * @param {object} [enrichment={}] - Additional context from hooks/agents
88
+ * @param {string[]} [enrichment.filesChanged] - Files modified in session
89
+ * @param {string[]} [enrichment.blockers] - Active blockers
90
+ * @param {Array<{what: string, why: string}>} [enrichment.decisions] - Decisions with rationale
91
+ * @param {object[]} [enrichment.gotchas] - Gotchas discovered
92
+ * @param {string[]} [enrichment.nextSteps] - Planned next steps
93
+ * @returns {object} Structured digest with 8 sections
94
+ */
95
+ export function buildStructuredDigest(projectDir, sessionState, enrichment = {}) {
96
+ const timestamp = new Date().toISOString();
97
+
98
+ const truncate = (text, maxChars) => {
99
+ if (!text) return '';
100
+ const str = String(text);
101
+ return str.length <= maxChars ? str : str.slice(0, maxChars - 3) + '...';
102
+ };
103
+
104
+ const truncateArray = (arr, maxChars) => {
105
+ if (!arr || arr.length === 0) return [];
106
+ let total = 0;
107
+ const result = [];
108
+ for (const item of arr) {
109
+ const str = typeof item === 'object' ? JSON.stringify(item) : String(item);
110
+ if (total + str.length > maxChars) break;
111
+ total += str.length;
112
+ result.push(item);
113
+ }
114
+ return result;
115
+ };
116
+
117
+ const digest = {
118
+ version: '2.0',
119
+ timestamp,
120
+ date: timestamp.split('T')[0],
121
+
122
+ // Section 1: Current agent
123
+ current_agent: truncate(
124
+ sessionState.current_agent || sessionState.agents
125
+ ? Object.entries(sessionState.agents || {}).find(([, v]) => v.status === 'in_progress')?.[0] || null
126
+ : null,
127
+ SECTION_BUDGETS.current_agent,
128
+ ),
129
+
130
+ // Section 2: Pipeline position
131
+ pipeline_position: truncate(
132
+ sessionState.pipeline?.phase || sessionState.project?.state || 'unknown',
133
+ SECTION_BUDGETS.pipeline_position,
134
+ ),
135
+
136
+ // Section 3: Active task
137
+ active_task: truncate(
138
+ enrichment.activeTask || null,
139
+ SECTION_BUDGETS.active_task,
140
+ ),
141
+
142
+ // Section 4: Files changed
143
+ files_changed: truncateArray(
144
+ enrichment.filesChanged || [],
145
+ SECTION_BUDGETS.files_changed,
146
+ ),
147
+
148
+ // Section 5: Blockers
149
+ blockers: truncateArray(
150
+ enrichment.blockers || [],
151
+ SECTION_BUDGETS.blockers,
152
+ ),
153
+
154
+ // Section 6: Decisions made
155
+ decisions_made: truncateArray(
156
+ enrichment.decisions || [],
157
+ SECTION_BUDGETS.decisions_made,
158
+ ),
159
+
160
+ // Section 7: Gotchas found
161
+ gotchas_found: truncateArray(
162
+ enrichment.gotchas || [],
163
+ SECTION_BUDGETS.gotchas_found,
164
+ ),
165
+
166
+ // Section 8: Next steps
167
+ next_steps: truncateArray(
168
+ enrichment.nextSteps || [],
169
+ SECTION_BUDGETS.next_steps,
170
+ ),
171
+
172
+ // Preserve base summary for backward compat
173
+ summary: {
174
+ total_agents: Object.keys(sessionState.agents || {}).length,
175
+ completed_agents: Object.values(sessionState.agents || {}).filter(a => a.status === 'completed').length,
176
+ mode: sessionState.mode || 'discover',
177
+ },
178
+ };
179
+
180
+ // Final budget enforcement — iterative truncation until within budget
181
+ const truncOrder = ['next_steps', 'gotchas_found', 'files_changed', 'blockers', 'decisions_made'];
182
+ let pass = 0;
183
+ while (JSON.stringify(digest).length > MAX_STRUCTURED_CHARS && pass < truncOrder.length) {
184
+ const field = truncOrder[pass];
185
+ if (Array.isArray(digest[field]) && digest[field].length > 1) {
186
+ digest[field] = digest[field].slice(0, Math.max(1, Math.ceil(digest[field].length / 2)));
187
+ } else {
188
+ pass++;
189
+ }
190
+ // If we halved and still too big, move to next field
191
+ if (JSON.stringify(digest).length > MAX_STRUCTURED_CHARS) pass++;
192
+ }
193
+
194
+ return digest;
195
+ }
196
+
59
197
  /**
60
198
  * Save session digest to disk.
61
199
  * @param {string} projectDir - Project directory
@@ -95,7 +233,7 @@ export function saveSessionDigest(projectDir, digest) {
95
233
  saved: true,
96
234
  path: digestPath,
97
235
  };
98
- } catch {
236
+ } catch { /* expected: operation may fail gracefully */
99
237
  return {
100
238
  saved: false,
101
239
  path: digestPath,
@@ -139,7 +277,7 @@ export function loadLatestDigest(projectDir) {
139
277
  loaded: true,
140
278
  digest,
141
279
  };
142
- } catch {
280
+ } catch { /* expected: file may not exist */
143
281
  return {
144
282
  loaded: false,
145
283
  digest: null,
@@ -181,7 +319,7 @@ export function listDigests(projectDir) {
181
319
  completion_rate: digest.summary?.completion_rate || 0,
182
320
  total_agents: digest.summary?.total_agents || 0,
183
321
  };
184
- } catch {
322
+ } catch { /* expected: operation may fail gracefully */
185
323
  return {
186
324
  filename,
187
325
  timestamp: null,
@@ -193,7 +331,7 @@ export function listDigests(projectDir) {
193
331
  };
194
332
  }
195
333
  });
196
- } catch {
334
+ } catch { /* expected: operation may fail gracefully */
197
335
  return [];
198
336
  }
199
337
  }
@@ -224,7 +362,7 @@ export function pruneDigests(projectDir, keepCount = 10) {
224
362
  const filepath = join(dir, filename);
225
363
  try {
226
364
  unlinkSync(filepath);
227
- } catch {
365
+ } catch { /* expected: file may already be deleted */
228
366
  // Ignore delete errors
229
367
  }
230
368
  });
@@ -233,7 +371,7 @@ export function pruneDigests(projectDir, keepCount = 10) {
233
371
  deleted: toDelete.length,
234
372
  kept: toKeep.length,
235
373
  };
236
- } catch {
374
+ } catch { /* expected: file may already be deleted */
237
375
  return { deleted: 0, kept: 0 };
238
376
  }
239
377
  }
@@ -120,7 +120,7 @@ export function mergeYamlFiles(existingContent, newContent) {
120
120
  const newObj = yaml.load(newContent) || {};
121
121
  const merged = deepMergeYaml(existingObj, newObj);
122
122
  return yaml.dump(merged, { lineWidth: -1, noRefs: true });
123
- } catch {
123
+ } catch { /* expected: YAML may be invalid */
124
124
  // If YAML parsing fails, return existing content unchanged
125
125
  return existingContent;
126
126
  }