winter-super-cli 2026.6.5 → 2026.6.7

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.
@@ -1,30 +1,19 @@
1
- import { isSmallModel } from './model-capabilities.js';
2
-
3
1
  export function isWeakTier(modelTier = '') {
4
- return isSmallModel(modelTier);
2
+ return true;
5
3
  }
6
4
 
7
5
  export function buildSmallModelAmplification({ modelTier = '', workflowProfile = 'general', depth = 'standard' } = {}) {
8
- const weak = isWeakTier(modelTier);
9
- if (!weak) {
10
- return {
11
- weak: false,
12
- maxToolTurns: 8,
13
- enforceSelfCritique: false,
14
- hint: '',
15
- };
16
- }
17
-
18
6
  const deepLike = depth === 'deep' || /debug|backend|data|devops|ai/.test(workflowProfile);
19
- const maxToolTurns = deepLike ? 14 : 10;
7
+ const maxToolTurns = deepLike ? 18 : 14;
20
8
 
21
9
  const hint = [
22
- '[Small Model Amplifier]',
23
- '- You are running in weak-model compensation mode.',
24
- '- Mandatory loop: PLAN (requirements + files + risks) -> TOOL ACTIONS -> VERIFY -> SELF-CHECK -> FINAL.',
10
+ '[Winter Strength Amplifier]',
11
+ '- Every model, including tiny/local/free models, must run at Winter maximum capability.',
12
+ '- Mandatory internal loop: PLAN (requirements + files + risks) -> TOOL ACTIONS -> VERIFY -> PRIVATE SELF-CHECK -> FINAL.',
25
13
  '- Do not skip verification. If verification fails, iterate until max loops.',
26
- '- Before final answer, run a private self-critique: missing edge cases, missing tests, over-claims, and incorrect assumptions.',
14
+ '- Before final answer, run a private self-critique silently; do not print the self-check or an improved-answer preface.',
27
15
  '- Prefer concrete evidence from tool outputs over reasoning guesses.',
16
+ '- Use CodeGraph/codebase index context before broad file reads when available.',
28
17
  ].join('\n');
29
18
 
30
19
  return {
@@ -34,4 +23,3 @@ export function buildSmallModelAmplification({ modelTier = '', workflowProfile =
34
23
  hint,
35
24
  };
36
25
  }
37
-
@@ -15,6 +15,7 @@ import { redactSecrets } from './secret-env.js';
15
15
  import { formatRuntimeEnvironmentSummary, getRuntimeEnvironment } from './runtime-env.js';
16
16
  import { ContextLoader } from './context-loader.js';
17
17
  import { ECCManager } from './ecc.js';
18
+ import { buildTuiSnapshot, renderLandingTui } from './tui.js';
18
19
  import { HtmlFxManager } from '../integrations/htmlfx-manager.js';
19
20
  import { selectWorkflow } from '../ai/workflow-selector.js';
20
21
  import { getProfileBlueprint } from '../ai/profile-blueprints.js';
@@ -73,6 +74,7 @@ export class CommandParser {
73
74
  resources: this.handleResources.bind(this),
74
75
  htmlfx: this.handleHtmlFx.bind(this),
75
76
  'memory-vault': this.handleMemoryVault.bind(this),
77
+ tui: this.handleTui.bind(this),
76
78
  provider: this.handleProvider.bind(this),
77
79
  providers: this.showProviders.bind(this),
78
80
  model: this.handleModel.bind(this),
@@ -121,6 +123,7 @@ export class CommandParser {
121
123
  '/forget': (args) => this.session.clearMemory(args.length > 0 ? args.join(' ') : null),
122
124
  '/memories': () => this.showMemories(),
123
125
  '/memory-vault': () => this.handleMemoryVault(args),
126
+ '/tui': () => this.handleTui(args),
124
127
  '/plans': () => this.showPlans(),
125
128
  '/plan': () => this.handlePlan(args),
126
129
  '/cache': () => this.handleCache(args),
@@ -220,6 +223,15 @@ export class CommandParser {
220
223
  }
221
224
  }
222
225
 
226
+ async handleTui() {
227
+ await this.ai.init?.();
228
+ const snapshot = buildTuiSnapshot(this);
229
+ console.log(`\n${renderLandingTui(snapshot, {
230
+ colors,
231
+ title: 'Winter Dashboard',
232
+ })}\n`);
233
+ }
234
+
223
235
  async searchResourceFiles(root, query, limit = 30) {
224
236
  const matches = [];
225
237
  const needle = String(query || '').toLowerCase();
@@ -962,6 +974,150 @@ EXECUTION CONTRACT:
962
974
  );
963
975
  }
964
976
 
977
+ buildPlanSlug(task) {
978
+ return String(task || 'plan')
979
+ .toLowerCase()
980
+ .replace(/[^a-z0-9]+/g, '-')
981
+ .replace(/^-+|-+$/g, '')
982
+ .slice(0, 48) || 'plan';
983
+ }
984
+
985
+ getPlanScaffoldSpec(task, workflow = {}) {
986
+ const slug = this.buildPlanSlug(task);
987
+ const featureName = slug.replace(/-/g, ' ');
988
+ const profile = String(workflow.profile || 'general');
989
+ const family = profile.split('-')[0] || 'general';
990
+
991
+ const common = {
992
+ dirs: ['docs', 'tests'],
993
+ files: {
994
+ 'docs/plan-notes.md': [
995
+ `# ${featureName}`,
996
+ '',
997
+ `- Profile: ${profile}`,
998
+ '- Status: scaffolded by Winter plan apply',
999
+ '',
1000
+ ].join('\n'),
1001
+ 'tests/README.md': [
1002
+ '# Test Plan',
1003
+ '',
1004
+ '- Add smoke tests for the generated plan.',
1005
+ '- Keep verification commands close to the final implementation stack.',
1006
+ '',
1007
+ ].join('\n'),
1008
+ },
1009
+ };
1010
+
1011
+ const specs = {
1012
+ webapp: {
1013
+ dirs: ['src/app', `src/features/${slug}`, 'src/components', 'src/lib', 'tests/e2e'],
1014
+ files: {
1015
+ [`src/features/${slug}/README.md`]: `# ${featureName}\n\nFeature slice for the plan.\n`,
1016
+ [`src/features/${slug}/tasks.md`]: '',
1017
+ 'tests/e2e/README.md': '# E2E Tests\n\nAdd Playwright or browser smoke tests here.\n',
1018
+ },
1019
+ },
1020
+ mobile: {
1021
+ dirs: ['src/navigation', `src/features/${slug}`, 'src/screens', 'src/services', 'src/components', 'src/state', 'tests'],
1022
+ files: {
1023
+ [`src/features/${slug}/README.md`]: `# ${featureName}\n\nMobile feature module for screens, hooks, API calls, and state.\n`,
1024
+ [`src/features/${slug}/tasks.md`]: '',
1025
+ 'src/navigation/README.md': '# Navigation\n\nDefine app navigation graph and route ownership here.\n',
1026
+ 'src/services/README.md': '# Services\n\nPlace API clients, storage adapters, and platform services here.\n',
1027
+ },
1028
+ },
1029
+ backend: {
1030
+ dirs: [`src/modules/${slug}`, `src/modules/${slug}/dto`, `src/modules/${slug}/tests`, 'src/config', 'src/common'],
1031
+ files: {
1032
+ [`src/modules/${slug}/README.md`]: `# ${featureName}\n\nBackend module scaffold for routes/controllers/services/tests.\n`,
1033
+ [`src/modules/${slug}/tasks.md`]: '',
1034
+ 'src/config/README.md': '# Config\n\nDocument environment variables and runtime config here.\n',
1035
+ },
1036
+ },
1037
+ desktop: {
1038
+ dirs: ['src/main', 'src/preload', 'src/renderer', `src/features/${slug}`, 'tests'],
1039
+ files: {
1040
+ [`src/features/${slug}/README.md`]: `# ${featureName}\n\nDesktop feature module scaffold.\n`,
1041
+ [`src/features/${slug}/tasks.md`]: '',
1042
+ 'src/main/README.md': '# Main Process\n\nKeep privileged runtime code here.\n',
1043
+ 'src/preload/README.md': '# Preload\n\nExpose minimal validated IPC APIs here.\n',
1044
+ },
1045
+ },
1046
+ ai: {
1047
+ dirs: ['src/ingestion', 'src/retrieval', 'src/generation', 'src/evals', `src/features/${slug}`],
1048
+ files: {
1049
+ [`src/features/${slug}/README.md`]: `# ${featureName}\n\nAI feature scaffold for pipeline wiring and evals.\n`,
1050
+ [`src/features/${slug}/tasks.md`]: '',
1051
+ 'src/evals/README.md': '# Evals\n\nTrack regression prompts, datasets, and quality thresholds here.\n',
1052
+ },
1053
+ },
1054
+ };
1055
+
1056
+ const spec = specs[family] || {
1057
+ dirs: [`src/features/${slug}`, 'src/lib', 'tests'],
1058
+ files: {
1059
+ [`src/features/${slug}/README.md`]: `# ${featureName}\n\nFeature scaffold generated from Winter plan apply.\n`,
1060
+ [`src/features/${slug}/tasks.md`]: '',
1061
+ },
1062
+ };
1063
+
1064
+ return {
1065
+ slug,
1066
+ family,
1067
+ dirs: [...common.dirs, ...spec.dirs],
1068
+ files: { ...common.files, ...spec.files },
1069
+ };
1070
+ }
1071
+
1072
+ async writeFileIfMissing(filePath, content) {
1073
+ try {
1074
+ await fs.writeFile(filePath, content, { encoding: 'utf8', flag: 'wx' });
1075
+ return true;
1076
+ } catch (error) {
1077
+ if (error?.code === 'EEXIST') return false;
1078
+ throw error;
1079
+ }
1080
+ }
1081
+
1082
+ async applyPlanProfileScaffold({ task, selected, workflow }) {
1083
+ const spec = this.getPlanScaffoldSpec(task, workflow);
1084
+ const created = [];
1085
+ const skipped = [];
1086
+
1087
+ for (const dir of spec.dirs) {
1088
+ const dirPath = path.join(this.projectPath, dir);
1089
+ await fs.mkdir(dirPath, { recursive: true });
1090
+ created.push(dir);
1091
+ }
1092
+
1093
+ const taskListContent = [
1094
+ `# ${selected.title}`,
1095
+ '',
1096
+ `- Task: ${task}`,
1097
+ `- Profile: ${workflow.profile}`,
1098
+ '',
1099
+ '## Steps',
1100
+ ...selected.steps.map(step => `- [ ] ${step}`),
1101
+ '',
1102
+ ].join('\n');
1103
+
1104
+ const files = { ...spec.files };
1105
+ for (const fileName of Object.keys(files)) {
1106
+ if (fileName.endsWith('/tasks.md')) {
1107
+ files[fileName] = taskListContent;
1108
+ }
1109
+ }
1110
+
1111
+ for (const [relativePath, content] of Object.entries(files)) {
1112
+ const filePath = path.join(this.projectPath, relativePath);
1113
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
1114
+ const didCreate = await this.writeFileIfMissing(filePath, content);
1115
+ (didCreate ? created : skipped).push(relativePath);
1116
+ }
1117
+
1118
+ return { ...spec, created, skipped };
1119
+ }
1120
+
965
1121
  async exportPlanArtifact({ task, workflow, selected, outputPath, format = 'md' }) {
966
1122
  const normalizedFormat = format === 'json' ? 'json' : 'md';
967
1123
  const finalPath = this.resolvePlanOutputPath(task, normalizedFormat, outputPath);
@@ -1004,6 +1160,7 @@ EXECUTION CONTRACT:
1004
1160
  }
1005
1161
 
1006
1162
  async applyPlanSkeleton({ task, selected, workflow, exportPath = null }) {
1163
+ const scaffold = await this.applyPlanProfileScaffold({ task, selected, workflow });
1007
1164
  const targetPath = path.join(this.projectPath, '.winter', 'plan-task-list.md');
1008
1165
  const skeleton = [
1009
1166
  '# Plan Task List',
@@ -1012,10 +1169,15 @@ EXECUTION CONTRACT:
1012
1169
  `- Profile: ${workflow.profile}`,
1013
1170
  `- Plan: ${selected.title}`,
1014
1171
  ...(exportPath ? [`- Plan File: ${path.relative(this.projectPath, exportPath) || exportPath}`] : []),
1172
+ `- Scaffold Profile: ${scaffold.family}`,
1015
1173
  '',
1016
1174
  '## TODO',
1017
1175
  ...selected.steps.map(step => `- [ ] ${step}`),
1018
1176
  '',
1177
+ '## Scaffold Created',
1178
+ ...scaffold.created.map(item => `- ${item}`),
1179
+ ...(scaffold.skipped.length ? ['', '## Existing Files Kept', ...scaffold.skipped.map(item => `- ${item}`)] : []),
1180
+ '',
1019
1181
  ].join('\n');
1020
1182
  await fs.mkdir(path.dirname(targetPath), { recursive: true });
1021
1183
  await fs.writeFile(targetPath, skeleton, 'utf8');
@@ -226,7 +226,7 @@ export class ContextLoader {
226
226
  this.readTextIfExists(pageAgentAgentsPath, 2200),
227
227
  ]);
228
228
 
229
- const hasRequired = Boolean(karpathy || agents || designReadme || designBrands.length > 0 || pageAgentWinter);
229
+ const hasRequired = Boolean(karpathy || agents || designReadme || designBrands.length > 0 || pageAgentWinter || pageAgentAgents);
230
230
  if (!hasRequired) return '';
231
231
 
232
232
  const lines = [];
@@ -1,6 +1,7 @@
1
1
  import readline from 'readline';
2
2
  import { colors } from './snowflake-logo.js';
3
- import { padVisible, renderBox, terminalWidth, visibleWidth } from './terminal-ui.js';
3
+ import { drawInFixedArea, enableFixedPanel, moveToPromptRow, moveToScrollRegion, padVisible, renderBox, terminalWidth } from './terminal-ui.js';
4
+ import { buildTuiSnapshot, renderInputPanel } from './tui.js';
4
5
 
5
6
  export class WinterInputController {
6
7
  constructor(repl) {
@@ -11,9 +12,20 @@ export class WinterInputController {
11
12
  const repl = this.repl;
12
13
  if (!repl.running || repl.readlineClosed) return;
13
14
  const panel = this.buildInputPanel();
14
- process.stdout.write(`\n${panel.top}\n${panel.status}\n${panel.hint}\n`);
15
- repl.rl.setPrompt(panel.prompt);
16
- repl.rl.prompt();
15
+
16
+ // Queue indicator
17
+ const queueCount = repl.taskQueue?.length || 0;
18
+ const queueTag = queueCount > 0
19
+ ? ` ${colors.yellow}⧗ ${queueCount} pending${colors.reset}`
20
+ : '';
21
+
22
+ const lines = [panel.top + queueTag, panel.status, panel.hint].filter(l => l && l.trim() !== '');
23
+ process.stdout.write('\n' + lines.join('\n') + '\n');
24
+
25
+ if (typeof repl.rl?.setPrompt === 'function') {
26
+ repl.rl.setPrompt(panel.prompt);
27
+ }
28
+ repl.rl?.prompt?.();
17
29
  }
18
30
 
19
31
  closeInputBox() {
@@ -25,38 +37,10 @@ export class WinterInputController {
25
37
 
26
38
  buildInputPanel() {
27
39
  const repl = this.repl;
28
- const width = Math.max(64, terminalWidth(66, 124) - 2);
29
- const box = repl.useUnicodeUi
30
- ? { topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯', horizontal: '─', vertical: '│' }
31
- : { topLeft: '+', topRight: '+', bottomLeft: '+', bottomRight: '+', horizontal: '-', vertical: '|' };
32
- const provider = repl.ai?.getActiveProvider?.() || 'provider';
33
- const model = repl.ai?.providers?.[provider]?.model || 'model';
34
- const sessionId = repl.session?.getSessionId?.()?.slice(0, 8) || 'session';
35
- const projectName = repl.projectPath ? repl.projectPath.split(/[\\/]/).filter(Boolean).pop() : 'project';
36
- const queueText = repl.taskQueue?.length > 0 ? `queue:${repl.taskQueue.length}` : 'ready';
37
- const title = ' Winter CLI ';
38
- const titleWidth = visibleWidth(title);
39
- const topFill = Math.max(0, width - titleWidth);
40
- const leftFill = Math.floor(topFill / 2);
41
- const rightFill = topFill - leftFill;
42
- const statusText = [
43
- `model ${provider}/${model}`,
44
- `project ${projectName}`,
45
- `session ${sessionId}`,
46
- queueText,
47
- ].join(' ');
48
- const hintText = '@file @Agent task !cmd Ctrl+V image /context /doctor full';
49
- const hintInnerWidth = Math.max(20, width - 2);
50
- const status = `${colors.magenta}${box.vertical}${colors.reset} ${colors.dim}${padVisible(statusText, hintInnerWidth)}${colors.reset} ${colors.magenta}${box.vertical}${colors.reset}`;
51
- const hint = `${colors.magenta}${box.vertical}${colors.reset} ${colors.dim}${padVisible(hintText, hintInnerWidth)}${colors.reset} ${colors.magenta}${box.vertical}${colors.reset}`;
52
- const prompt = `${colors.magenta}${box.vertical}${colors.reset} ${colors.bright}${colors.cyan}winter${colors.reset}${colors.dim} > ${colors.reset}`;
53
- return {
54
- top: `${colors.magenta}${box.topLeft}${box.horizontal.repeat(leftFill)}${title}${box.horizontal.repeat(rightFill)}${box.topRight}${colors.reset}`,
55
- status,
56
- hint,
57
- prompt,
58
- bottom: `${colors.magenta}${box.bottomLeft}${box.horizontal.repeat(width)}${box.bottomRight}${colors.reset}`,
59
- };
40
+ return renderInputPanel(buildTuiSnapshot(repl), {
41
+ colors,
42
+ width: terminalWidth(66, 124),
43
+ });
60
44
  }
61
45
 
62
46
  installSlashSuggestions() {
@@ -80,10 +64,24 @@ export class WinterInputController {
80
64
  return;
81
65
  }
82
66
 
83
- if (key.name === 'escape' && repl.isProcessing) {
84
- repl.isCancelled = true;
85
- if (repl.spinner) repl.spinner.stop();
86
- console.log(`\n${colors.red}[ Đã nhận lệnh HỦY... AI sẽ kết thúc ở thao tác tiếp theo ]${colors.reset}`);
67
+ if (key.name === 'escape') {
68
+ if (repl.isProcessing) {
69
+ // Cancel current AI turn
70
+ repl.isCancelled = true;
71
+ if (repl.spinner) repl.spinner.stop();
72
+ console.log(`\n${colors.red}[ Đã nhận lệnh HỦY... AI sẽ kết thúc ở thao tác tiếp theo ]${colors.reset}`);
73
+ } else {
74
+ // Double-ESC to end session
75
+ const now = Date.now();
76
+ if (this._lastEscTime && (now - this._lastEscTime) < 500) {
77
+ console.log(`\n\n${colors.cyan}Cảm ơn đã sử dụng Winter!${colors.reset}`);
78
+ console.log(`${colors.yellow}Tiếp tục phiên làm việc:${colors.reset}`);
79
+ console.log(`${colors.bright}${colors.green}winter --session ${repl.session?.getSessionId?.() || ''}${colors.reset}\n`);
80
+ process.exit(0);
81
+ }
82
+ this._lastEscTime = now;
83
+ console.log(`${colors.dim}Press ESC again to end session${colors.reset}`);
84
+ }
87
85
  return;
88
86
  }
89
87
 
@@ -116,13 +114,13 @@ export class WinterInputController {
116
114
 
117
115
  repl.inputQueue = repl.inputQueue
118
116
  .then(async () => {
119
- this.closeInputBox();
117
+ repl.closeInputBox?.();
120
118
  await this.processPastedImageTask(prompt, image);
121
119
  })
122
120
  .catch((error) => {
123
- this.closeInputBox();
121
+ repl.closeInputBox?.();
124
122
  console.log(`\n${colors.red}✖ Paste image error: ${error.message}${colors.reset}\n`);
125
- if (repl.running && !repl.readlineClosed) this.showInputPrompt();
123
+ if (repl.running && !repl.readlineClosed) repl.showInputPrompt?.();
126
124
  });
127
125
  return true;
128
126
  } finally {
@@ -134,15 +132,17 @@ export class WinterInputController {
134
132
  const repl = this.repl;
135
133
  repl.isProcessing = true;
136
134
  repl.isCancelled = false;
135
+ repl.currentAbortController = new AbortController();
137
136
  try {
138
137
  await repl.chat(prompt, [image]);
139
138
  } finally {
140
139
  repl.isProcessing = false;
140
+ repl.currentAbortController = null;
141
141
  if (repl.taskQueue.length > 0) {
142
142
  const nextTask = repl.taskQueue.shift();
143
143
  setTimeout(() => repl.processInputTask(nextTask), 0);
144
144
  } else if (!repl.readlineClosed) {
145
- this.showInputPrompt();
145
+ repl.showInputPrompt?.();
146
146
  }
147
147
  }
148
148
  }
@@ -247,12 +247,23 @@ export class WinterInputController {
247
247
 
248
248
  this.clearSlashMenuRender();
249
249
 
250
+ const ASCII_BOX = {
251
+ topLeft: '+',
252
+ topRight: '+',
253
+ bottomLeft: '+',
254
+ bottomRight: '+',
255
+ horizontal: '-',
256
+ vertical: '|',
257
+ teeLeft: '+',
258
+ teeRight: '+',
259
+ };
250
260
  const rendered = renderBox({
251
261
  title: 'Command Palette',
252
262
  width: terminalWidth(66, 110, 88),
253
263
  borderColor: colors.magenta,
254
264
  titleColor: colors.cyan,
255
265
  body,
266
+ boxChars: ASCII_BOX,
256
267
  });
257
268
 
258
269
  process.stdout.write(`\n${rendered}\n`);
@@ -1,4 +1,5 @@
1
1
  import { formatRuntimeEnvironmentSummary, getRuntimeEnvironment } from './runtime-env.js';
2
+ import { getModelBudgetMultiplier } from '../ai/model-capabilities.js';
2
3
 
3
4
  /**
4
5
  * PromptBuilder — Builds system prompts for Winter CLI agents.
@@ -49,26 +50,32 @@ export class PromptBuilder {
49
50
  const sessionContext = this.session?.getContext?.() || {};
50
51
  const environmentSummary = this.tools?.getRuntimeEnvironmentSummary?.() || this._defaultEnvironmentSummary();
51
52
  const requiredLocalResources = this.getRequiredLocalResources();
52
- const projectContextBudget = options.projectContextBudget || 3200;
53
- const compactSystemPrompt = options.compactSystemPrompt || projectContextBudget <= 1600;
53
+ const scale = getModelBudgetMultiplier(options.modelTier);
54
+ const projectContextBudget = options.projectContextBudget || Math.round(3200 * scale);
55
+ const compactSystemPrompt = options.compactSystemPrompt ?? (scale <= 0.75);
56
+ const memoryBudget = Math.round(1200 * scale);
57
+ const planBudget = Math.round(1200 * scale);
58
+ const requiredResourcesBudget = Math.round((compactSystemPrompt ? 1200 : 1600) * scale);
59
+ const workflowBudget = Math.round(900 * scale);
60
+ const blueprintBudget = Math.round(700 * scale);
54
61
 
55
62
  const memoryStr = memories.length > 0
56
- ? this._formatMemories(memories)
63
+ ? this._formatMemories(memories, { maxTotalChars: memoryBudget })
57
64
  : '';
58
65
  const requiredResourcesStr = requiredLocalResources
59
- ? `\n## Required Local Resource Rules\n${this._compactText(requiredLocalResources, 1800, 'required local resources')}`
66
+ ? `\n## Required Local Resource Rules\n${this._compactText(requiredLocalResources, requiredResourcesBudget, 'required local resources')}`
60
67
  : '';
61
68
  const plansStr = plans.length > 0
62
- ? this._formatPlans(plans)
69
+ ? this._formatPlans(plans, { maxTotalChars: planBudget })
63
70
  : '';
64
71
  const skillsStr = Array.isArray(sessionContext.activeSkills) && sessionContext.activeSkills.length > 0
65
72
  ? `\n## Auto-applied Skills\n${sessionContext.activeSkills.slice(0, 12).map(skill => `- ${skill}`).join('\n')}${sessionContext.activeSkills.length > 12 ? '\n- ...' : ''}`
66
73
  : '';
67
74
  const workflowStr = sessionContext.workflowHints
68
- ? `\n## Workflow Auto-Selection\n${this._compactText(sessionContext.workflowHints, 900, 'workflow hints')}`
75
+ ? `\n## Workflow Auto-Selection\n${this._compactText(sessionContext.workflowHints, workflowBudget, 'workflow hints')}`
69
76
  : '';
70
77
  const blueprintStr = sessionContext.workflowBlueprint
71
- ? `\n## Profile Blueprint\n${this._compactText(sessionContext.workflowBlueprint, 700, 'workflow blueprint')}`
78
+ ? `\n## Profile Blueprint\n${this._compactText(sessionContext.workflowBlueprint, blueprintBudget, 'workflow blueprint')}`
72
79
  : '';
73
80
  const startupPlanStr = sessionContext.bootstrapPlan?.title
74
81
  ? `\n## Startup Plan\n- ${sessionContext.bootstrapPlan.title}: ${sessionContext.bootstrapPlan.description}`
@@ -164,12 +171,14 @@ export class PromptBuilder {
164
171
  const plans = this.session?.getPlans?.() || [];
165
172
  const sessionContext = this.session?.getContext?.() || {};
166
173
  const requiredLocalResources = this.getRequiredLocalResources();
174
+ const scale = getModelBudgetMultiplier(this.ai?._modelTier || '');
175
+ const projectContextBudget = Math.round(3200 * (scale || 1));
167
176
 
168
- const memoryStr = memories.length > 0 ? this._formatMemories(memories, { maxTotalChars: 900 }) : '';
177
+ const memoryStr = memories.length > 0 ? this._formatMemories(memories, { maxTotalChars: Math.round(900 * (scale || 1)) }) : '';
169
178
  const requiredResourcesStr = requiredLocalResources
170
- ? `\n## Required Local Resource Rules\n${this._compactText(requiredLocalResources, 1600, 'required local resources')}`
179
+ ? `\n## Required Local Resource Rules\n${this._compactText(requiredLocalResources, Math.round(1600 * (scale || 1)), 'required local resources')}`
171
180
  : '';
172
- const plansStr = plans.length > 0 ? this._formatPlans(plans, { maxTotalChars: 900 }) : '';
181
+ const plansStr = plans.length > 0 ? this._formatPlans(plans, { maxTotalChars: Math.round(900 * (scale || 1)) }) : '';
173
182
  const skillsStr = Array.isArray(sessionContext.activeSkills) && sessionContext.activeSkills.length > 0
174
183
  ? `\n## Auto-applied Skills\n${sessionContext.activeSkills.slice(0, 12).map(skill => `- ${skill}`).join('\n')}${sessionContext.activeSkills.length > 12 ? '\n- ...' : ''}`
175
184
  : '';
@@ -217,7 +226,7 @@ export class PromptBuilder {
217
226
  `Working directory: ${this.projectPath}`,
218
227
  `Current session: ${this.session?.getSessionId?.()?.substring(0, 8) || 'unknown'}`,
219
228
  `${requiredResourcesStr}${memoryStr}${plansStr}${skillsStr}${startupPlanStr}`,
220
- context ? `\n## Project Context\n${this._compactText(context, 3200, 'project context')}` : '',
229
+ context ? `\n## Project Context\n${this._compactText(context, projectContextBudget, 'project context')}` : '',
221
230
  ].join('\n');
222
231
  }
223
232
 
@@ -354,6 +354,9 @@ export async function handleSlashCommand(repl, input) {
354
354
  case '/scorecard':
355
355
  await repl.showCapabilityScorecard();
356
356
  return;
357
+ case '/tui':
358
+ repl.showTuiDashboard();
359
+ return;
357
360
 
358
361
  // Git Auto-Pilot
359
362
  case '/commit':