chati-dev 4.5.12 → 4.5.14

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 (55) 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 +2 -2
  25. package/framework/i18n/es.yaml +2 -2
  26. package/framework/i18n/fr.yaml +2 -2
  27. package/framework/i18n/pt.yaml +2 -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 +60 -192
  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 +80 -60
  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/i18n.js +2 -2
@@ -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,193 +24,73 @@ 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
- };
67
-
68
- // ---------------------------------------------------------------------------
69
- // Replacement Configuration Builder
70
- // ---------------------------------------------------------------------------
71
-
72
- /**
73
- * Build the complete replacement config for a given provider.
74
- * Returns { strings, patterns } where:
75
- * - strings: ordered [search, replace] pairs for replaceAll
76
- * - patterns: { pattern, replacement } objects for regex replace
77
- *
78
- * Ordering: most-specific strings first to prevent partial matches.
79
- */
80
- function buildReplacementConfig(provider) {
81
- const meta = PROVIDER_META[provider];
82
- const modelMap = PROVIDER_MODEL_MAPS[provider];
83
-
84
- if (!meta || !modelMap) {
85
- throw new Error(`Unknown provider: ${provider}`);
86
- }
87
-
88
- const { cliName, contextFile, localFile } = meta;
89
- const { deep, light, minimal } = modelMap;
90
-
91
- // --- String replacements (ordered, most specific first) ---
92
- const strings = [
93
- // File references (most specific first)
94
- ['CLAUDE.local.md', localFile],
95
- ['CLAUDE.md', contextFile],
96
- ['.claude/rules/chati/', 'chati.dev/context/'],
97
-
98
- // Provider name (most specific first)
99
- ['Claude Code processes', `${cliName} processes`],
100
- ['Claude Code CLI', cliName],
101
- ['Claude Code', cliName],
102
-
103
- // Behavioral
104
- ['NEVER act as generic Claude', 'NEVER act as generic AI assistant'],
105
-
106
- // /model commands (specific model names)
107
- ['/model opus', `/model ${deep}`],
108
- ['/model sonnet', `/model ${light}`],
109
- ['/model haiku', `/model ${minimal}`],
110
- ];
111
-
112
- // --- Regex patterns for model names in structured contexts ---
113
- const patterns = [
114
- // Identity section: **Model**: opus | ...
115
- { pattern: /(\*\*Model\*\*:\s*)opus/g, replacement: `$1${deep}` },
116
- { pattern: /(\*\*Model\*\*:\s*)sonnet/g, replacement: `$1${light}` },
117
- { pattern: /(\*\*Model\*\*:\s*)haiku/g, replacement: `$1${minimal}` },
118
-
119
- // YAML-like blocks: default: sonnet, upgrade_to: opus, etc.
120
- { pattern: /(default:\s*)opus/g, replacement: `$1${deep}` },
121
- { pattern: /(default:\s*)sonnet/g, replacement: `$1${light}` },
122
- { pattern: /(default:\s*)haiku/g, replacement: `$1${minimal}` },
123
- { pattern: /(upgrade_to:\s*)opus/g, replacement: `$1${deep}` },
124
- { pattern: /(upgrade_to:\s*)sonnet/g, replacement: `$1${light}` },
125
- { pattern: /(downgrade_to:\s*)haiku/g, replacement: `$1${minimal}` },
126
- { pattern: /(downgrade_to:\s*)sonnet/g, replacement: `$1${light}` },
127
- { pattern: /(recommended:\s*)opus/g, replacement: `$1${deep}` },
128
- { pattern: /(recommended:\s*)sonnet/g, replacement: `$1${light}` },
129
- { pattern: /(actual:\s*)opus/g, replacement: `$1${deep}` },
130
- { pattern: /(actual:\s*)sonnet/g, replacement: `$1${light}` },
131
- { pattern: /(model:\s*)opus/g, replacement: `$1${deep}` },
132
- { pattern: /(model:\s*)sonnet/g, replacement: `$1${light}` },
133
-
134
- // Table cells: | opus | or | sonnet | or | haiku |
135
- { pattern: /(\|\s*)opus(\s*\|)/g, replacement: `$1${deep}$2` },
136
- { pattern: /(\|\s*)sonnet(\s*\|)/g, replacement: `$1${light}$2` },
137
- { pattern: /(\|\s*)haiku(\s*\|)/g, replacement: `$1${minimal}$2` },
138
-
139
- // Upgrade/downgrade conditions in prose: "sonnet if ...", "opus if ..."
140
- // Negative lookbehind prevents double-prefix when deep model contains a tier name (e.g. claude-sonnet)
141
- { pattern: /(?<!-)opus if /g, replacement: `${deep} if ` },
142
- { pattern: /(?<!-)sonnet if /g, replacement: `${light} if ` },
143
- { pattern: /(?<!-)haiku if /g, replacement: `${minimal} if ` },
144
-
145
- // Constitution/governance model tier definitions
146
- { pattern: /\*\*opus\*\*:/g, replacement: `**${deep}**:` },
147
- { pattern: /\*\*sonnet\*\*:/g, replacement: `**${light}**:` },
148
- { pattern: /\*\*haiku\*\*:/g, replacement: `**${minimal}**:` },
149
- { pattern: /opus \(deep reasoning\)/g, replacement: `${deep} (deep reasoning)` },
150
- { pattern: /sonnet \(structured\)/g, replacement: `${light} (structured)` },
151
- { pattern: /haiku \(lightweight\)/g, replacement: `${minimal} (lightweight)` },
152
-
153
- // Provider field in agent Identity: claude (default) with optional conditional
154
- { pattern: /- \*\*Provider\*\*: claude \(default\)(?:\s*\|[^\n]*)?/g,
155
- replacement: `- **Provider**: ${provider} (default)` },
156
-
157
- // Provider in table rows: | claude (default) | or | claude (default) | gemini (...) |
158
- { pattern: /(\|\s*)claude \(default\)(?:\s*\|[^|\n]*)?\s*(\|)/g,
159
- replacement: `$1${provider} (default) $2` },
160
-
161
- // "claude" as primary provider in prose
162
- { pattern: /primary provider \(claude\)/g, replacement: `primary provider (${provider})` },
163
- { pattern: /fallback_provider: claude/g, replacement: `fallback_provider: ${provider}` },
164
- { pattern: /fall back to the primary provider \(claude\)/g,
165
- replacement: `fall back to the primary provider (${provider})` },
166
- { pattern: /primary provider: claude/g, replacement: `primary provider: ${provider}` },
167
-
168
- // /chati providers display: swap PRIMARY designation
169
- // Note: "Claude Code CLI" may already be replaced by string replacements, so match any trailing text
170
- { pattern: /claude\s+PRIMARY\s+Enabled\s+.+/g,
171
- replacement: `${provider} PRIMARY Enabled ${cliName}` },
172
-
173
- // CLAUDE.md Update sections in agents
174
- { pattern: /### CLAUDE\.md Update/g, replacement: `### ${contextFile} Update` },
175
- { pattern: /### CLAUDE\.md Final Update/g, replacement: `### ${contextFile} Final Update` },
176
- { pattern: /Update CLAUDE\.md/g, replacement: `Update ${contextFile}` },
177
- ];
178
-
179
- // Codex CLI uses $chati for skill invocation, not /chati.
180
- // Lookbehind prevents replacing /chati in file paths (e.g., orchestrator/chati.md).
181
- if (provider === 'codex') {
182
- patterns.push({
183
- pattern: /(?<![/\w])\/chati/g,
184
- replacement: '$$chati',
185
- });
186
- }
187
-
188
- return { strings, patterns };
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
+ );
189
47
  }
190
48
 
191
- // ---------------------------------------------------------------------------
192
- // Main Adapter Function
193
- // ---------------------------------------------------------------------------
49
+ const CODEX_CREDENTIAL_BOUNDARY = `
50
+ ## Codex external provider credential boundary
51
+
52
+ Commands returned in any \`spawn_command\`, \`parallel_spawn_command\` or
53
+ \`parallel_spawn_commands\` start another provider CLI. Codex MUST execute each
54
+ command through its native local execution path so the child CLI can access its
55
+ existing local credentials:
56
+
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.
64
+
65
+ Never test a routed provider command inside the workspace sandbox first. A
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.
73
+ `;
74
+
75
+ function renderNativeInvocation(content, invocation) {
76
+ if (invocation === '/chati') return content;
77
+ return content.replace(/(?<![./\w])\/chati(?![-/\w])/g, invocation);
78
+ }
194
79
 
195
- /**
196
- * Adapt a single framework file for the target provider.
197
- *
198
- * @param {string} content - Original file content (Claude Code version)
199
- * @param {string} filePath - Relative path within chati.dev/ (e.g. 'orchestrator/chati.md')
200
- * @param {string} provider - Target provider: 'gemini', 'codex'
201
- * @returns {string} Adapted content for the target provider
202
- */
203
80
  export function adaptFrameworkFile(content, filePath, provider) {
204
81
  if (!content) return content;
82
+ if (!HARNESS_PROFILES[provider]) throw new Error(`Unknown provider: ${provider}`);
205
83
 
206
- let result = content;
84
+ let result = renderNativeInvocation(content, HARNESS_PROFILES[provider].invocation);
207
85
  if (filePath === 'orchestrator/chati.md') {
208
- result = result.replace(
209
- /<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
210
- 'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
211
- );
212
- }
213
-
214
- if (provider === 'claude') return result;
215
-
216
- const config = buildReplacementConfig(provider);
217
-
218
- // 1. Apply ordered string replacements (most specific first)
219
- for (const [search, replace] of config.strings) {
220
- result = result.replaceAll(search, replace);
86
+ result = stripLegacyBuildSurface(result);
221
87
  }
222
88
 
223
- // 2. Apply regex patterns (model names + structured contexts)
224
- for (const { pattern, replacement } of config.patterns) {
225
- result = result.replace(pattern, replacement);
89
+ if (provider === 'codex' && filePath === 'orchestrator/chati.md') {
90
+ const routedAction = '## Action: Routed Interactive Agent';
91
+ result = result.includes(routedAction)
92
+ ? result.replace(routedAction, `${CODEX_CREDENTIAL_BOUNDARY}\n${routedAction}`)
93
+ : `${result.trimEnd()}\n\n${CODEX_CREDENTIAL_BOUNDARY.trimStart()}`;
226
94
  }
227
95
 
228
96
  return result;
@@ -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 = {