chati-dev 4.5.13 → 4.5.15

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 (57) hide show
  1. package/framework/agents/build/dev.md +4 -5
  2. package/framework/agents/deploy/devops.md +9 -10
  3. package/framework/agents/discover/brief.md +7 -13
  4. package/framework/agents/discover/brownfield-wu.md +5 -11
  5. package/framework/agents/discover/greenfield-wu.md +7 -12
  6. package/framework/agents/plan/architect.md +1 -1
  7. package/framework/agents/plan/detail.md +5 -5
  8. package/framework/agents/plan/phases.md +4 -5
  9. package/framework/agents/plan/tasks.md +4 -5
  10. package/framework/agents/plan/ux-brand-architect.md +1 -1
  11. package/framework/agents/plan/ux.md +1 -1
  12. package/framework/agents/quality/qa-implementation.md +4 -5
  13. package/framework/agents/quality/qa-planning.md +4 -5
  14. package/framework/agents/quality/qa-visual.md +4 -4
  15. package/framework/agents/shared/visualizer.md +1 -1
  16. package/framework/config.yaml +5 -5
  17. package/framework/constitution.md +24 -26
  18. package/framework/context/governance.md +6 -6
  19. package/framework/context/root.md +4 -3
  20. package/framework/data/entity-registry.yaml +3 -3
  21. package/framework/data/model-limits.json +5 -2
  22. package/framework/hooks/model-governance.js +3 -2
  23. package/framework/hooks/prism-engine.js +1 -1
  24. package/framework/i18n/en.yaml +6 -2
  25. package/framework/i18n/es.yaml +6 -2
  26. package/framework/i18n/fr.yaml +6 -2
  27. package/framework/i18n/pt.yaml +6 -2
  28. package/framework/intelligence/context-engine.md +12 -16
  29. package/framework/manifest.json +63 -63
  30. package/framework/manifest.sig +1 -1
  31. package/framework/orchestrator/chati-router.js +40 -6
  32. package/framework/orchestrator/chati.md +12 -13
  33. package/framework/schemas/session.schema.json +1 -1
  34. package/package.json +1 -1
  35. package/src/config/context-file-generator.js +54 -246
  36. package/src/config/framework-adapter.js +45 -208
  37. package/src/context/bracket-tracker.js +3 -3
  38. package/src/context/engine.js +1 -1
  39. package/src/installer/core.js +190 -66
  40. package/src/installer/provider-overlay.js +1 -1
  41. package/src/installer/templates.js +55 -65
  42. package/src/installer-v2/index.js +2 -0
  43. package/src/memory/magic-docs.js +45 -26
  44. package/src/orchestrator/cli.js +50 -45
  45. package/src/orchestrator/handoff-engine.js +7 -5
  46. package/src/orchestrator/session-manager.js +24 -3
  47. package/src/terminal/cli-registry.js +5 -5
  48. package/src/terminal/prompt-builder.js +14 -10
  49. package/src/terminal/run-agent.js +10 -6
  50. package/src/terminal/run-parallel.js +6 -2
  51. package/src/terminal/run-team.js +7 -2
  52. package/src/terminal/spawner.js +34 -42
  53. package/src/utils/config-parser.js +2 -2
  54. package/src/utils/provider-limits.js +3 -1
  55. package/src/wizard/feedback.js +11 -0
  56. package/src/wizard/i18n.js +6 -2
  57. package/src/wizard/index.js +17 -7
@@ -1,23 +1,11 @@
1
1
  /**
2
- * @fileoverview Framework file adapter for multi-CLI support.
2
+ * @fileoverview Native harness overlays over a provider-neutral framework.
3
3
  *
4
- * Transforms Claude Code-specific framework files (orchestrator, agents,
5
- * constitution, context) into provider-native versions at install time.
6
- * Each LLM reads instructions written for it — zero runtime translation.
7
- *
8
- * Constitution Article XIX — framework files are pre-adapted per provider.
4
+ * Shared framework documents contain only Chati invariants and routing
5
+ * contracts. Provider overlays add mechanics that genuinely belong to a
6
+ * harness. They never translate another provider's instructions.
9
7
  */
10
8
 
11
- import { PROVIDER_MODEL_MAPS } from '../installer/templates.js';
12
-
13
- // ---------------------------------------------------------------------------
14
- // Adaptable Files
15
- // ---------------------------------------------------------------------------
16
-
17
- /**
18
- * Set of framework file paths (relative to chati.dev/) that need
19
- * provider-specific adaptation when the selected provider is not Claude.
20
- */
21
9
  export const ADAPTABLE_FILES = new Set([
22
10
  'constitution.md',
23
11
  'orchestrator/chati.md',
@@ -36,217 +24,66 @@ export const ADAPTABLE_FILES = new Set([
36
24
  'agents/deploy/devops.md',
37
25
  'context/governance.md',
38
26
  'context/root.md',
27
+ 'domains/agents/orchestrator.yaml',
28
+ 'tasks/orchestrator-escalate.md',
29
+ 'tasks/orchestrator-route.md',
30
+ 'tasks/orchestrator-status.md',
31
+ 'tasks/qa-planning-risk-matrix.md',
32
+ 'tasks/qa-planning-test-strategy.md',
39
33
  ]);
40
34
 
41
- // ---------------------------------------------------------------------------
42
- // Provider Metadata
43
- // ---------------------------------------------------------------------------
44
-
45
- const PROVIDER_META = {
46
- claude: {
47
- cliName: 'Claude Code',
48
- contextFile: 'CLAUDE.md',
49
- localFile: 'CLAUDE.local.md',
50
- },
51
- gemini: {
52
- cliName: 'Gemini CLI',
53
- contextFile: 'GEMINI.md',
54
- localFile: '.gemini/session-lock.md',
55
- },
56
- codex: {
57
- cliName: 'Codex CLI',
58
- contextFile: 'AGENTS.md',
59
- localFile: 'AGENTS.override.md',
60
- },
61
- grok: {
62
- cliName: 'Grok CLI',
63
- contextFile: 'AGENTS.md',
64
- localFile: '.grok/session-lock.md',
65
- },
66
- };
35
+ export const HARNESS_PROFILES = Object.freeze({
36
+ claude: Object.freeze({ contextFile: 'CLAUDE.md', sessionLockFile: 'CLAUDE.local.md', invocation: '/chati' }),
37
+ gemini: Object.freeze({ contextFile: 'GEMINI.md', sessionLockFile: '.gemini/session-lock.md', invocation: '/chati' }),
38
+ codex: Object.freeze({ contextFile: 'AGENTS.md', sessionLockFile: 'AGENTS.override.md', invocation: '$chati' }),
39
+ grok: Object.freeze({ contextFile: 'AGENTS.md', sessionLockFile: '.grok/session-lock.md', invocation: '/chati' }),
40
+ });
41
+
42
+ export function stripLegacyBuildSurface(content) {
43
+ return content.replace(
44
+ /<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
45
+ 'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
46
+ );
47
+ }
67
48
 
68
49
  const CODEX_CREDENTIAL_BOUNDARY = `
69
50
  ## Codex external provider credential boundary
70
51
 
71
52
  Commands returned in any \`spawn_command\`, \`parallel_spawn_command\` or
72
53
  \`parallel_spawn_commands\` start another provider CLI. Codex MUST execute each
73
- of these commands with native escalated execution so the child CLI can access
74
- its existing local credentials:
54
+ command through its native local execution path so the child CLI can access its
55
+ existing local credentials:
75
56
 
76
- - Set \`sandbox_permissions\` to \`require_escalated\`.
77
- - Explain that Chati needs to run the selected provider CLI using its existing
78
- local authentication.
79
- - Offer the narrow reusable prefix made from the first two command arguments:
80
- \`["node", "<absolute path from the command to run-agent.js>"]\`.
81
- - Keep the project working directory and the router-provided command unchanged.
57
+ - If the active Codex host requires approval to leave a restricted workspace
58
+ sandbox, request the narrow native approval it exposes for the exact command.
59
+ - Do not invent approval fields or tool parameters that this Codex host does not
60
+ expose.
61
+ - Explain that Chati needs the selected provider CLI to use its existing local
62
+ authentication.
63
+ - Keep the project working directory and router-provided command unchanged.
82
64
 
83
65
  Never test a routed provider command inside the workspace sandbox first. A
84
- \`PROVIDER_NOT_READY\` or \`PROVIDER_NOT_AUTHENTICATED\` result obtained inside
85
- that sandbox is inconclusive because the sandbox can hide OS credentials. If a
86
- sandboxed attempt already failed, rerun it once with native escalated execution.
87
- Only a failure from that escalated attempt may be reported as an authentication
88
- failure. Do not repeat the same sandboxed command and do not offer to skip a
89
- required v2 pipeline stage.
66
+ \`PROVIDER_NOT_READY\` or \`PROVIDER_NOT_AUTHENTICATED\` result obtained there is
67
+ inconclusive because the sandbox can hide OS credentials. If a sandboxed attempt
68
+ already failed, rerun it once through Codex's native approved local execution
69
+ path. Only a failure from that attempt may be reported as an authentication
70
+ failure.
71
+ Do not repeat the same sandboxed command and do not offer to skip a required
72
+ v2 pipeline stage.
90
73
  `;
91
74
 
92
- // ---------------------------------------------------------------------------
93
- // Replacement Configuration Builder
94
- // ---------------------------------------------------------------------------
95
-
96
- /**
97
- * Build the complete replacement config for a given provider.
98
- * Returns { strings, patterns } where:
99
- * - strings: ordered [search, replace] pairs for replaceAll
100
- * - patterns: { pattern, replacement } objects for regex replace
101
- *
102
- * Ordering: most-specific strings first to prevent partial matches.
103
- */
104
- function buildReplacementConfig(provider) {
105
- const meta = PROVIDER_META[provider];
106
- const modelMap = PROVIDER_MODEL_MAPS[provider];
107
-
108
- if (!meta || !modelMap) {
109
- throw new Error(`Unknown provider: ${provider}`);
110
- }
111
-
112
- const { cliName, contextFile, localFile } = meta;
113
- const { deep, light, minimal } = modelMap;
114
-
115
- // --- String replacements (ordered, most specific first) ---
116
- const strings = [
117
- // File references (most specific first)
118
- ['CLAUDE.local.md', localFile],
119
- ['CLAUDE.md', contextFile],
120
- ['.claude/rules/chati/', 'chati.dev/context/'],
121
-
122
- // Provider name (most specific first)
123
- ['Claude Code processes', `${cliName} processes`],
124
- ['Claude Code CLI', cliName],
125
- ['Claude Code', cliName],
126
-
127
- // Behavioral
128
- ['NEVER act as generic Claude', 'NEVER act as generic AI assistant'],
129
-
130
- // /model commands (specific model names)
131
- ['/model opus', `/model ${deep}`],
132
- ['/model sonnet', `/model ${light}`],
133
- ['/model haiku', `/model ${minimal}`],
134
- ];
135
-
136
- // --- Regex patterns for model names in structured contexts ---
137
- const patterns = [
138
- // Identity section: **Model**: opus | ...
139
- { pattern: /(\*\*Model\*\*:\s*)opus/g, replacement: `$1${deep}` },
140
- { pattern: /(\*\*Model\*\*:\s*)sonnet/g, replacement: `$1${light}` },
141
- { pattern: /(\*\*Model\*\*:\s*)haiku/g, replacement: `$1${minimal}` },
142
-
143
- // YAML-like blocks: default: sonnet, upgrade_to: opus, etc.
144
- { pattern: /(default:\s*)opus/g, replacement: `$1${deep}` },
145
- { pattern: /(default:\s*)sonnet/g, replacement: `$1${light}` },
146
- { pattern: /(default:\s*)haiku/g, replacement: `$1${minimal}` },
147
- { pattern: /(upgrade_to:\s*)opus/g, replacement: `$1${deep}` },
148
- { pattern: /(upgrade_to:\s*)sonnet/g, replacement: `$1${light}` },
149
- { pattern: /(downgrade_to:\s*)haiku/g, replacement: `$1${minimal}` },
150
- { pattern: /(downgrade_to:\s*)sonnet/g, replacement: `$1${light}` },
151
- { pattern: /(recommended:\s*)opus/g, replacement: `$1${deep}` },
152
- { pattern: /(recommended:\s*)sonnet/g, replacement: `$1${light}` },
153
- { pattern: /(actual:\s*)opus/g, replacement: `$1${deep}` },
154
- { pattern: /(actual:\s*)sonnet/g, replacement: `$1${light}` },
155
- { pattern: /(model:\s*)opus/g, replacement: `$1${deep}` },
156
- { pattern: /(model:\s*)sonnet/g, replacement: `$1${light}` },
157
-
158
- // Table cells: | opus | or | sonnet | or | haiku |
159
- { pattern: /(\|\s*)opus(\s*\|)/g, replacement: `$1${deep}$2` },
160
- { pattern: /(\|\s*)sonnet(\s*\|)/g, replacement: `$1${light}$2` },
161
- { pattern: /(\|\s*)haiku(\s*\|)/g, replacement: `$1${minimal}$2` },
162
-
163
- // Upgrade/downgrade conditions in prose: "sonnet if ...", "opus if ..."
164
- // Negative lookbehind prevents double-prefix when deep model contains a tier name (e.g. claude-sonnet)
165
- { pattern: /(?<!-)opus if /g, replacement: `${deep} if ` },
166
- { pattern: /(?<!-)sonnet if /g, replacement: `${light} if ` },
167
- { pattern: /(?<!-)haiku if /g, replacement: `${minimal} if ` },
168
-
169
- // Constitution/governance model tier definitions
170
- { pattern: /\*\*opus\*\*:/g, replacement: `**${deep}**:` },
171
- { pattern: /\*\*sonnet\*\*:/g, replacement: `**${light}**:` },
172
- { pattern: /\*\*haiku\*\*:/g, replacement: `**${minimal}**:` },
173
- { pattern: /opus \(deep reasoning\)/g, replacement: `${deep} (deep reasoning)` },
174
- { pattern: /sonnet \(structured\)/g, replacement: `${light} (structured)` },
175
- { pattern: /haiku \(lightweight\)/g, replacement: `${minimal} (lightweight)` },
176
-
177
- // Provider field in agent Identity: claude (default) with optional conditional
178
- { pattern: /- \*\*Provider\*\*: claude \(default\)(?:\s*\|[^\n]*)?/g,
179
- replacement: `- **Provider**: ${provider} (default)` },
180
-
181
- // Provider in table rows: | claude (default) | or | claude (default) | gemini (...) |
182
- { pattern: /(\|\s*)claude \(default\)(?:\s*\|[^|\n]*)?\s*(\|)/g,
183
- replacement: `$1${provider} (default) $2` },
184
-
185
- // "claude" as primary provider in prose
186
- { pattern: /primary provider \(claude\)/g, replacement: `primary provider (${provider})` },
187
- { pattern: /fallback_provider: claude/g, replacement: `fallback_provider: ${provider}` },
188
- { pattern: /fall back to the primary provider \(claude\)/g,
189
- replacement: `fall back to the primary provider (${provider})` },
190
- { pattern: /primary provider: claude/g, replacement: `primary provider: ${provider}` },
191
-
192
- // /chati providers display: swap PRIMARY designation
193
- // Note: "Claude Code CLI" may already be replaced by string replacements, so match any trailing text
194
- { pattern: /claude\s+PRIMARY\s+Enabled\s+.+/g,
195
- replacement: `${provider} PRIMARY Enabled ${cliName}` },
196
-
197
- // CLAUDE.md Update sections in agents
198
- { pattern: /### CLAUDE\.md Update/g, replacement: `### ${contextFile} Update` },
199
- { pattern: /### CLAUDE\.md Final Update/g, replacement: `### ${contextFile} Final Update` },
200
- { pattern: /Update CLAUDE\.md/g, replacement: `Update ${contextFile}` },
201
- ];
202
-
203
- // Codex CLI uses $chati for skill invocation, not /chati.
204
- // Lookbehind prevents replacing /chati in file paths (e.g., orchestrator/chati.md).
205
- if (provider === 'codex') {
206
- patterns.push({
207
- pattern: /(?<![/\w])\/chati/g,
208
- replacement: '$$chati',
209
- });
210
- }
211
-
212
- return { strings, patterns };
75
+ function renderNativeInvocation(content, invocation) {
76
+ if (invocation === '/chati') return content;
77
+ return content.replace(/(?<![./\w])\/chati(?![-/\w])/g, invocation);
213
78
  }
214
79
 
215
- // ---------------------------------------------------------------------------
216
- // Main Adapter Function
217
- // ---------------------------------------------------------------------------
218
-
219
- /**
220
- * Adapt a single framework file for the target provider.
221
- *
222
- * @param {string} content - Original file content (Claude Code version)
223
- * @param {string} filePath - Relative path within chati.dev/ (e.g. 'orchestrator/chati.md')
224
- * @param {string} provider - Target provider: 'gemini', 'codex'
225
- * @returns {string} Adapted content for the target provider
226
- */
227
80
  export function adaptFrameworkFile(content, filePath, provider) {
228
81
  if (!content) return content;
82
+ if (!HARNESS_PROFILES[provider]) throw new Error(`Unknown provider: ${provider}`);
229
83
 
230
- let result = content;
84
+ let result = renderNativeInvocation(content, HARNESS_PROFILES[provider].invocation);
231
85
  if (filePath === 'orchestrator/chati.md') {
232
- result = result.replace(
233
- /<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
234
- 'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
235
- );
236
- }
237
-
238
- if (provider === 'claude') return result;
239
-
240
- const config = buildReplacementConfig(provider);
241
-
242
- // 1. Apply ordered string replacements (most specific first)
243
- for (const [search, replace] of config.strings) {
244
- result = result.replaceAll(search, replace);
245
- }
246
-
247
- // 2. Apply regex patterns (model names + structured contexts)
248
- for (const { pattern, replacement } of config.patterns) {
249
- result = result.replace(pattern, replacement);
86
+ result = stripLegacyBuildSurface(result);
250
87
  }
251
88
 
252
89
  if (provider === 'codex' && filePath === 'orchestrator/chati.md') {
@@ -38,11 +38,11 @@ const MEMORY_LEVELS = {
38
38
  /**
39
39
  * Calculate bracket from remaining context percentage.
40
40
  * @param {number} remainingPercent - 0 to 100
41
- * @param {string} [provider='claude'] - Provider name for context window scaling
41
+ * @param {string|null} [provider=null] - Provider name for context window scaling
42
42
  * @param {string} [model] - Model tier (opus, sonnet, haiku) for precise context limits
43
- * @returns {{ bracket: string, activeLayers: string[], tokenBudget: number, budgetRatio: number, memoryLevel: string, handoffRequired: boolean, provider: string }}
43
+ * @returns {{ bracket: string, activeLayers: string[], tokenBudget: number, budgetRatio: number, memoryLevel: string, handoffRequired: boolean, provider: string|null }}
44
44
  */
45
- export function calculateBracket(remainingPercent, provider = 'claude', model) {
45
+ export function calculateBracket(remainingPercent, provider = null, model) {
46
46
  const pct = Math.max(0, Math.min(100, remainingPercent));
47
47
 
48
48
  let name = 'CRITICAL';
@@ -49,7 +49,7 @@ export function runPrism(input) {
49
49
  const layers = [];
50
50
 
51
51
  // 1. Calculate bracket (provider-aware for proportional budgets)
52
- const bracket = calculateBracket(input.remainingPercent, input.provider || 'claude');
52
+ const bracket = calculateBracket(input.remainingPercent, input.provider || null);
53
53
 
54
54
  // 2. Build context for layer processors
55
55
  const ctx = {