openhorse 0.2.13 → 0.2.17

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 (103) hide show
  1. package/dist/commands/index.d.ts.map +1 -1
  2. package/dist/commands/index.js +217 -49
  3. package/dist/commands/index.js.map +1 -1
  4. package/dist/commands/types.d.ts +4 -1
  5. package/dist/commands/types.d.ts.map +1 -1
  6. package/dist/commands/types.js.map +1 -1
  7. package/dist/core/checkpoint.d.ts +7 -0
  8. package/dist/core/checkpoint.d.ts.map +1 -1
  9. package/dist/core/checkpoint.js +10 -0
  10. package/dist/core/checkpoint.js.map +1 -1
  11. package/dist/core/cost-tracker.d.ts.map +1 -1
  12. package/dist/core/cost-tracker.js +11 -0
  13. package/dist/core/cost-tracker.js.map +1 -1
  14. package/dist/ink-ui/components/PromptInput.d.ts.map +1 -1
  15. package/dist/ink-ui/components/PromptInput.js +5 -3
  16. package/dist/ink-ui/components/PromptInput.js.map +1 -1
  17. package/dist/ink-ui/components/SelectList.d.ts.map +1 -1
  18. package/dist/ink-ui/components/SelectList.js +10 -4
  19. package/dist/ink-ui/components/SelectList.js.map +1 -1
  20. package/dist/ink-ui/components/StatusLine.d.ts +3 -1
  21. package/dist/ink-ui/components/StatusLine.d.ts.map +1 -1
  22. package/dist/ink-ui/components/StatusLine.js +5 -3
  23. package/dist/ink-ui/components/StatusLine.js.map +1 -1
  24. package/dist/ink-ui/components/ToolActivity.d.ts +3 -1
  25. package/dist/ink-ui/components/ToolActivity.d.ts.map +1 -1
  26. package/dist/ink-ui/components/ToolActivity.js +35 -9
  27. package/dist/ink-ui/components/ToolActivity.js.map +1 -1
  28. package/dist/ink-ui/launch.d.ts.map +1 -1
  29. package/dist/ink-ui/launch.js +39 -10
  30. package/dist/ink-ui/launch.js.map +1 -1
  31. package/dist/ink-ui/screens/ReplScreen.d.ts +3 -1
  32. package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
  33. package/dist/ink-ui/screens/ReplScreen.js +63 -93
  34. package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
  35. package/dist/print-ui/launch.d.ts.map +1 -1
  36. package/dist/print-ui/launch.js +1 -0
  37. package/dist/print-ui/launch.js.map +1 -1
  38. package/dist/runtime/agent-runtime-controller.d.ts +5 -0
  39. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  40. package/dist/runtime/agent-runtime-controller.js +15 -3
  41. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  42. package/dist/runtime/agent-status.d.ts +5 -0
  43. package/dist/runtime/agent-status.d.ts.map +1 -1
  44. package/dist/runtime/agent-status.js +28 -2
  45. package/dist/runtime/agent-status.js.map +1 -1
  46. package/dist/runtime/chat-controller.d.ts +4 -0
  47. package/dist/runtime/chat-controller.d.ts.map +1 -1
  48. package/dist/runtime/chat-controller.js +199 -67
  49. package/dist/runtime/chat-controller.js.map +1 -1
  50. package/dist/runtime/turn-controller.d.ts +4 -0
  51. package/dist/runtime/turn-controller.d.ts.map +1 -1
  52. package/dist/runtime/turn-controller.js +8 -0
  53. package/dist/runtime/turn-controller.js.map +1 -1
  54. package/dist/runtime/ui-events.d.ts +7 -0
  55. package/dist/runtime/ui-events.d.ts.map +1 -1
  56. package/dist/runtime/ui-events.js.map +1 -1
  57. package/dist/runtime/ui-view-model.d.ts +287 -0
  58. package/dist/runtime/ui-view-model.d.ts.map +1 -0
  59. package/dist/runtime/ui-view-model.js +642 -0
  60. package/dist/runtime/ui-view-model.js.map +1 -0
  61. package/dist/services/file-glob.d.ts +6 -2
  62. package/dist/services/file-glob.d.ts.map +1 -1
  63. package/dist/services/file-glob.js +10 -4
  64. package/dist/services/file-glob.js.map +1 -1
  65. package/dist/services/model-catalog.d.ts +14 -0
  66. package/dist/services/model-catalog.d.ts.map +1 -0
  67. package/dist/services/model-catalog.js +73 -0
  68. package/dist/services/model-catalog.js.map +1 -0
  69. package/dist/services/model-context.d.ts.map +1 -1
  70. package/dist/services/model-context.js +3 -0
  71. package/dist/services/model-context.js.map +1 -1
  72. package/dist/services/session-storage.d.ts +1 -0
  73. package/dist/services/session-storage.d.ts.map +1 -1
  74. package/dist/services/session-storage.js.map +1 -1
  75. package/dist/services/verification-profile.d.ts +15 -0
  76. package/dist/services/verification-profile.d.ts.map +1 -1
  77. package/dist/services/verification-profile.js +67 -0
  78. package/dist/services/verification-profile.js.map +1 -1
  79. package/dist/terminal-ui/completion.d.ts.map +1 -1
  80. package/dist/terminal-ui/completion.js +9 -6
  81. package/dist/terminal-ui/completion.js.map +1 -1
  82. package/dist/terminal-ui/launch.d.ts +15 -1
  83. package/dist/terminal-ui/launch.d.ts.map +1 -1
  84. package/dist/terminal-ui/launch.js +300 -56
  85. package/dist/terminal-ui/launch.js.map +1 -1
  86. package/dist/terminal-ui/raw-editor.d.ts +4 -0
  87. package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
  88. package/dist/terminal-ui/raw-editor.js +29 -0
  89. package/dist/terminal-ui/raw-editor.js.map +1 -1
  90. package/dist/tui-ui/launch.d.ts.map +1 -1
  91. package/dist/tui-ui/launch.js +1 -0
  92. package/dist/tui-ui/launch.js.map +1 -1
  93. package/dist/tui-ui/layout.d.ts.map +1 -1
  94. package/dist/tui-ui/layout.js +21 -28
  95. package/dist/tui-ui/layout.js.map +1 -1
  96. package/dist/tui-ui/pickers.d.ts.map +1 -1
  97. package/dist/tui-ui/pickers.js +21 -62
  98. package/dist/tui-ui/pickers.js.map +1 -1
  99. package/dist/tui-ui/state.d.ts +2 -4
  100. package/dist/tui-ui/state.d.ts.map +1 -1
  101. package/dist/tui-ui/state.js +13 -11
  102. package/dist/tui-ui/state.js.map +1 -1
  103. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AAuOjB,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,CAErF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAQrE;AA2oCD,iBAAe,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgUpF;AA0xCD,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAE5C;AAED,wBAAgB,kBAAkB,IAAI,YAAY,EAAE,CAEnD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAElE;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AAuQjB,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,CAErF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAQrE;AA6yCD,iBAAe,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgUpF;AAoyCD,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAE5C;AAED,wBAAgB,kBAAkB,IAAI,YAAY,EAAE,CAEnD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAElE;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,CAAC"}
@@ -17,7 +17,7 @@ exports.getCommandNames = getCommandNames;
17
17
  exports.executeChat = handleChat;
18
18
  const chalk_1 = __importDefault(require("chalk"));
19
19
  const types_1 = require("./types");
20
- const ui_events_1 = require("../runtime/ui-events");
20
+ const ui_view_model_1 = require("../runtime/ui-view-model");
21
21
  const task_manager_1 = require("../services/task-manager");
22
22
  const agent_runner_1 = require("../services/agent-runner");
23
23
  const config_1 = require("../services/config");
@@ -38,6 +38,7 @@ const project_instructions_1 = require("../services/project-instructions");
38
38
  const prompt_context_1 = require("../services/prompt-context");
39
39
  const doctor_1 = require("../services/doctor");
40
40
  const model_context_1 = require("../services/model-context");
41
+ const model_catalog_1 = require("../services/model-catalog");
41
42
  const workspace_diff_1 = require("../services/workspace-diff");
42
43
  const commit_plan_1 = require("../services/commit-plan");
43
44
  const tool_artifacts_1 = require("../core/tool-artifacts");
@@ -66,7 +67,10 @@ const CATEGORY_ORDER = [
66
67
  'legacy',
67
68
  ];
68
69
  function commandUICapabilities(ctx) {
69
- return (0, ui_events_1.resolveUiRendererCapabilities)(ctx.uiCapabilities);
70
+ return (0, ui_view_model_1.createStatusSnapshot)({
71
+ renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
72
+ capabilities: ctx.uiCapabilities,
73
+ }).renderer.capabilities;
70
74
  }
71
75
  function formatTokenCount(tokens) {
72
76
  if (tokens >= 1000000)
@@ -83,6 +87,23 @@ function formatDurationMs(ms) {
83
87
  return `${(ms / 1000).toFixed(1)}s`;
84
88
  return `${Math.round(ms)}ms`;
85
89
  }
90
+ function formatRendererStatus(ctx) {
91
+ const snapshot = (0, ui_view_model_1.createStatusSnapshot)({
92
+ renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
93
+ capabilities: ctx.uiCapabilities,
94
+ });
95
+ const status = snapshot.renderer.status === 'beta' || (0, config_1.isBetaUIRenderer)(snapshot.renderer.name)
96
+ ? WARN('beta')
97
+ : snapshot.renderer.status === 'stable'
98
+ ? SUCCESS('stable')
99
+ : snapshot.renderer.status === 'non-interactive'
100
+ ? DIM('non-interactive')
101
+ : DIM('custom');
102
+ return `${BRAND(snapshot.renderer.name)} ${status} ${DIM(snapshot.renderer.capabilityLabels.join(', '))}`;
103
+ }
104
+ function formatModelAliasHelp() {
105
+ return Object.keys((0, model_catalog_1.getModelCatalogAliases)()).sort().join(', ');
106
+ }
86
107
  function formatLoopBudgetSource(stats) {
87
108
  const source = stats.loopBudgetSource ?? 'unknown';
88
109
  if (source === 'config' && stats.loopBudgetBaseProfile) {
@@ -280,6 +301,7 @@ function showStatus(ctx) {
280
301
  console.log(` Model ${BRAND(modelId)}`);
281
302
  console.log(` Context ${DIM(`${formatTokenCount(modelContext.contextWindow)} tokens (${modelContext.source}${modelContext.source === 'fuzzy' ? `:${modelContext.matchedId}` : ''})`)}`);
282
303
  console.log(` Compact ${compactStats.enabled ? SUCCESS('auto') : WARN('off')} ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}, used ${compactStats.ctxPercent}%`)}`);
304
+ console.log(` Renderer ${formatRendererStatus(ctx)}`);
283
305
  console.log();
284
306
  console.log(` Agents ${SUCCESS(brainStatus.agents.length)} registered`);
285
307
  console.log(` Tasks ${brainStatus.pendingTasks} pending (${brainStatus.strategy} strategy)`);
@@ -516,6 +538,9 @@ function formatTraceEventLine(event) {
516
538
  `commands=${commands.length}`,
517
539
  `files=${files.length}`,
518
540
  ];
541
+ if (event.verificationRisky) {
542
+ details.push(`risk=${WARN('high')}(${files.length} files)`);
543
+ }
519
544
  const commandPreview = commands.length
520
545
  ? ` cmds: ${commands.slice(0, 4).join(' && ')}${commands.length > 4 ? ' && ...' : ''}`
521
546
  : '';
@@ -582,6 +607,123 @@ function handleTrace(ctx, args = '') {
582
607
  console.log(DIM('Trace stores metadata only; full transcript and tool output stay in session/artifacts.'));
583
608
  return { success: true };
584
609
  }
610
+ function latestToolTrace(events) {
611
+ for (let index = events.length - 1; index >= 0; index--) {
612
+ const event = events[index];
613
+ if (event.type !== 'tool_result' && event.type !== 'tool_call')
614
+ continue;
615
+ const callId = event.callId;
616
+ const result = event.type === 'tool_result' ? event : undefined;
617
+ const call = event.type === 'tool_call'
618
+ ? event
619
+ : callId
620
+ ? events.slice(0, index).reverse().find(candidate => candidate.type === 'tool_call' && candidate.callId === callId)
621
+ : undefined;
622
+ return { call, result };
623
+ }
624
+ return null;
625
+ }
626
+ function parseLastToolArgs(args = '') {
627
+ const parts = args.trim().split(/\s+/).filter(Boolean);
628
+ return {
629
+ full: parts.includes('--full'),
630
+ preview: !parts.includes('--no-preview'),
631
+ };
632
+ }
633
+ function printLastToolArtifactPreview(projectPath, label, artifactId, full) {
634
+ if (!artifactId)
635
+ return;
636
+ const artifact = (0, tool_artifacts_1.findArtifact)(projectPath, artifactId);
637
+ if (!artifact) {
638
+ console.log(` ${label} preview ${DIM(`artifact not found or ambiguous: ${artifactId}`)}`);
639
+ return;
640
+ }
641
+ const content = (0, tool_artifacts_1.retrieveArtifact)(artifact.path);
642
+ if (content == null) {
643
+ console.log(` ${label} preview ${DIM(`artifact cannot be read: ${artifact.id}`)}`);
644
+ return;
645
+ }
646
+ const redacted = (0, session_storage_1.redactTraceText)(content);
647
+ const maxPreviewBytes = 4 * 1024;
648
+ const shouldTruncate = !full && Buffer.byteLength(redacted, 'utf8') > maxPreviewBytes;
649
+ const preview = shouldTruncate
650
+ ? Buffer.from(redacted, 'utf8').subarray(0, maxPreviewBytes).toString('utf8')
651
+ : redacted;
652
+ console.log(` ${label} preview`);
653
+ console.log(` ${DIM('─'.repeat(40))}`);
654
+ for (const line of preview.split('\n')) {
655
+ console.log(` ${line}`);
656
+ }
657
+ if (shouldTruncate) {
658
+ console.log(` ${DIM(`... preview truncated at ${(0, format_1.formatBytes)(maxPreviewBytes)}. Use /last-tool --full or /artifacts show ${artifact.id} --full.`)}`);
659
+ }
660
+ }
661
+ function lastToolInputLabel(toolName) {
662
+ return toolName === 'exec_command' ? 'Command' : 'Args';
663
+ }
664
+ function lastToolField(label) {
665
+ return label.padEnd(13, ' ');
666
+ }
667
+ function handleLastTool(ctx, args = '') {
668
+ const options = parseLastToolArgs(args);
669
+ const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
670
+ if (!session) {
671
+ console.log(ERROR('No active session.'));
672
+ console.log(DIM('Use /resume <session-id> first, or start a chat turn to create a session.'));
673
+ return { success: false };
674
+ }
675
+ const events = (0, session_storage_1.readSessionTraceEvents)(session.id);
676
+ const latest = latestToolTrace(events);
677
+ if (!latest) {
678
+ console.log(DIM(`No tool trace events recorded for session ${session.id.slice(0, 8)} yet.`));
679
+ return { success: true };
680
+ }
681
+ const call = latest.call;
682
+ const result = latest.result;
683
+ const source = result ?? call;
684
+ const argsSource = call ?? result;
685
+ const name = source?.name ?? 'tool';
686
+ const inputLabel = lastToolInputLabel(name);
687
+ const callId = source?.callId ?? call?.callId;
688
+ const status = result ? (result.success === false ? ERROR('error') : SUCCESS('ok')) : WARN('running');
689
+ console.log(HEADER('Last Tool'));
690
+ console.log(DIM('─'.repeat(40)));
691
+ console.log(` Tool ${ACCENT(name)}`);
692
+ console.log(` Turn ${DIM(source?.turnId ?? 'unknown')}`);
693
+ if (callId)
694
+ console.log(` Call ${DIM(callId)}`);
695
+ console.log(` Status ${status}`);
696
+ if (typeof result?.duration === 'number') {
697
+ console.log(` Time ${DIM(formatDurationMs(result.duration))}`);
698
+ }
699
+ if (argsSource?.argsSummary) {
700
+ console.log(` ${lastToolField(inputLabel)}${DIM((0, session_storage_1.redactTraceText)(argsSource.argsSummary))}`);
701
+ }
702
+ if (argsSource?.argsArtifactId) {
703
+ const size = typeof argsSource.argsBytes === 'number' ? ` (${(0, format_1.formatBytes)(argsSource.argsBytes)})` : '';
704
+ console.log(` ${lastToolField(`${inputLabel} full`)}${DIM(`/artifacts show ${argsSource.argsArtifactId} --full${size}`)}`);
705
+ }
706
+ if (typeof result?.outputBytes === 'number') {
707
+ const modelVisible = typeof result.modelVisibleBytes === 'number'
708
+ ? `, model-visible ${(0, format_1.formatBytes)(result.modelVisibleBytes)}`
709
+ : '';
710
+ console.log(` Output ${DIM(`${(0, format_1.formatBytes)(result.outputBytes)}${modelVisible}`)}`);
711
+ }
712
+ if (result?.artifactId) {
713
+ console.log(` Output full ${DIM(`/artifacts show ${result.artifactId} --full`)}`);
714
+ }
715
+ if (result?.error) {
716
+ console.log(` Error ${ERROR((0, session_storage_1.redactTraceText)(result.error))}`);
717
+ }
718
+ if (options.preview) {
719
+ const projectPath = session.projectPath || ctx.cwd;
720
+ printLastToolArtifactPreview(projectPath, inputLabel, argsSource?.argsArtifactId, options.full);
721
+ printLastToolArtifactPreview(projectPath, 'Output', result?.artifactId, options.full);
722
+ }
723
+ console.log();
724
+ console.log(DIM('Use /last-tool --full for redacted full previews, --no-preview for metadata only, or /trace latest for the ordered turn timeline.'));
725
+ return { success: true };
726
+ }
585
727
  function formatDateTime(timestamp) {
586
728
  return new Date(timestamp).toLocaleString();
587
729
  }
@@ -876,6 +1018,47 @@ function showHarness(ctx, args = '') {
876
1018
  console.log(DIM(' (no contract established)'));
877
1019
  }
878
1020
  console.log();
1021
+ // Context source
1022
+ console.log(HEADER(' Context Source'));
1023
+ const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
1024
+ const isRestored = session?.transcriptDisplayStartTime != null;
1025
+ const isCompactActive = Boolean(state.promptAssemblyStats);
1026
+ console.log(` Root ${ACCENT(state.rootObjective || contract?.objective || '(none)')}`);
1027
+ console.log(` Active ${DIM(state.activeInstruction || contract?.userIntent || '(none)')}`);
1028
+ console.log(` Source ${isRestored ? WARN('restored session') : DIM('live turn')}`);
1029
+ if (isRestored && session) {
1030
+ const restoredTime = session.transcriptDisplayStartTime
1031
+ ? new Date(session.transcriptDisplayStartTime).toLocaleString()
1032
+ : 'unknown';
1033
+ console.log(` Restored ${DIM(restoredTime)}`);
1034
+ }
1035
+ if (isCompactActive) {
1036
+ console.log(` Compact ${SUCCESS('active')}`);
1037
+ }
1038
+ console.log();
1039
+ // Evidence index summary
1040
+ console.log(HEADER(' Evidence Index'));
1041
+ const evidenceItems = state.evidenceIndex?.length ?? 0;
1042
+ const evidenceKinds = new Map();
1043
+ if (state.evidenceIndex) {
1044
+ for (const item of state.evidenceIndex) {
1045
+ const kind = item.kind || 'unknown';
1046
+ evidenceKinds.set(kind, (evidenceKinds.get(kind) || 0) + 1);
1047
+ }
1048
+ }
1049
+ console.log(` Total ${ACCENT(String(evidenceItems))} items`);
1050
+ if (evidenceKinds.size > 0) {
1051
+ const kinds = Array.from(evidenceKinds.entries())
1052
+ .sort((a, b) => b[1] - a[1])
1053
+ .slice(0, 10);
1054
+ for (const [kind, count] of kinds) {
1055
+ console.log(` ${DIM(kind.padEnd(16))} ${count}`);
1056
+ }
1057
+ }
1058
+ else {
1059
+ console.log(DIM(' (no evidence records yet)'));
1060
+ }
1061
+ console.log();
879
1062
  // Intent history
880
1063
  console.log(HEADER(' Recent Intents'));
881
1064
  const intents = state.intentHistory?.slice(-5) ?? [];
@@ -1007,51 +1190,13 @@ function showConfig(ctx) {
1007
1190
  return { success: true };
1008
1191
  }
1009
1192
  function handleModel(ctx, args) {
1010
- // 模型别名映射
1011
- const MODEL_ALIASES = {
1012
- 'opus': 'claude-opus-4-7',
1013
- 'sonnet': 'claude-sonnet-4-6',
1014
- 'haiku': 'claude-haiku-4-5-20251001',
1015
- 'claude': 'claude-sonnet-4-6',
1016
- 'gpt4': 'gpt-4o',
1017
- 'gpt4o': 'gpt-4o',
1018
- 'gpt35': 'gpt-3.5-turbo',
1019
- // Bailian (coding.dashscope.aliyuncs.com) — OpenAI-compatible
1020
- 'qwen': 'qwen3.5-plus',
1021
- 'qwenplus': 'qwen3.5-plus',
1022
- 'qwen36': 'qwen3.6-plus',
1023
- 'qwenmax': 'qwen3-max-2026-01-23',
1024
- 'coder': 'qwen3-coder-plus',
1025
- 'codernext': 'qwen3-coder-next',
1026
- 'glm': 'glm-5',
1027
- 'glm47': 'glm-4.7',
1028
- 'kimi': 'kimi-k2.5',
1029
- 'minimax': 'MiniMax-M2.5',
1030
- };
1031
- // 可用模型列表
1032
- const AVAILABLE_MODELS = [
1033
- { name: 'claude-opus-4-7', alias: 'opus', provider: 'Anthropic' },
1034
- { name: 'claude-sonnet-4-6', alias: 'sonnet', provider: 'Anthropic' },
1035
- { name: 'claude-haiku-4-5-20251001', alias: 'haiku', provider: 'Anthropic' },
1036
- { name: 'gpt-4o', alias: 'gpt4o', provider: 'OpenAI' },
1037
- { name: 'gpt-3.5-turbo', alias: 'gpt35', provider: 'OpenAI' },
1038
- { name: 'glm-5', alias: 'glm', provider: 'Bailian (Zhipu)' },
1039
- { name: 'glm-4.7', alias: 'glm47', provider: 'Bailian (Zhipu)' },
1040
- { name: 'qwen3.5-plus', alias: 'qwen', provider: 'Bailian (Alibaba)' },
1041
- { name: 'qwen3.6-plus', alias: 'qwen36', provider: 'Bailian (Alibaba)' },
1042
- { name: 'qwen3-max-2026-01-23', alias: 'qwenmax', provider: 'Bailian (Alibaba)' },
1043
- { name: 'qwen3-coder-plus', alias: 'coder', provider: 'Bailian (Alibaba)' },
1044
- { name: 'qwen3-coder-next', alias: 'codernext', provider: 'Bailian (Alibaba)' },
1045
- { name: 'kimi-k2.5', alias: 'kimi', provider: 'Bailian (Moonshot)' },
1046
- { name: 'MiniMax-M2.5', alias: 'minimax', provider: 'Bailian (MiniMax)' },
1047
- ];
1048
1193
  const trimmedArgs = args.trim().toLowerCase();
1049
1194
  // 显示当前模型
1050
1195
  if (!args || trimmedArgs === '?' || trimmedArgs === 'info') {
1051
1196
  console.log();
1052
1197
  if (ctx.llm) {
1053
1198
  const currentModel = ctx.llm.getModel();
1054
- const aliasEntry = AVAILABLE_MODELS.find(m => m.name === currentModel || m.alias === currentModel);
1199
+ const aliasEntry = (0, model_catalog_1.getModelCatalogEntry)(currentModel);
1055
1200
  const contextInfo = (0, model_context_1.resolveModelContext)(currentModel);
1056
1201
  const compactStats = (0, auto_compact_1.getAutoCompact)({ modelId: currentModel }).getStats();
1057
1202
  console.log(HEADER('Current Model'));
@@ -1080,12 +1225,25 @@ function handleModel(ctx, args) {
1080
1225
  console.log(HEADER('Available Models'));
1081
1226
  console.log(DIM('─'.repeat(40)));
1082
1227
  const currentModel = ctx.llm?.getModel() || '';
1083
- for (const m of AVAILABLE_MODELS) {
1084
- const isCurrent = m.name === currentModel || m.alias === currentModel;
1085
- const marker = isCurrent ? SUCCESS('●') : DIM('○');
1086
- const contextInfo = (0, model_context_1.resolveModelContext)(m.name);
1087
- console.log(` ${marker} ${ACCENT(m.name)} ${DIM(`(${m.alias})`)} ${DIM(`${formatTokenCount(contextInfo.contextWindow)} ctx`)} ${isCurrent ? BRAND('(current)') : ''}`);
1088
- console.log(` ${DIM(m.provider)}`);
1228
+ const modelPicker = (0, ui_view_model_1.createModelPickerState)({
1229
+ currentModel,
1230
+ models: (0, model_catalog_1.listModelCatalogEntries)().map(model => {
1231
+ const contextInfo = (0, model_context_1.resolveModelContext)(model.name);
1232
+ return {
1233
+ ...model,
1234
+ contextWindow: contextInfo.contextWindow,
1235
+ maxOutputTokens: contextInfo.maxOutputTokens,
1236
+ source: contextInfo.source,
1237
+ };
1238
+ }),
1239
+ });
1240
+ for (const item of modelPicker.visibleItems) {
1241
+ const marker = item.isCurrent ? SUCCESS('●') : DIM('○');
1242
+ const alias = item.alias ? `(${item.alias})` : '';
1243
+ const context = `${formatTokenCount(item.contextWindow ?? 0)} ctx`;
1244
+ const current = item.isCurrent ? BRAND('(current)') : '';
1245
+ console.log(` ${marker} ${ACCENT(item.name)} ${DIM(alias)} ${DIM(context)} ${current}`);
1246
+ console.log(` ${DIM(item.provider ?? 'unknown')}`);
1089
1247
  }
1090
1248
  console.log();
1091
1249
  console.log(DIM('Use /model <name|alias> to switch, e.g. /model sonnet'));
@@ -1103,7 +1261,7 @@ function handleModel(ctx, args) {
1103
1261
  console.log(` ${ACCENT('/model <name>')} Switch to specific model`);
1104
1262
  console.log(` ${ACCENT('/model <alias>')} Switch using alias (opus, sonnet, haiku)`);
1105
1263
  console.log();
1106
- console.log(DIM('Aliases: opus, sonnet, haiku, gpt4o, qwen, glm'));
1264
+ console.log(DIM(`Aliases: ${formatModelAliasHelp()}`));
1107
1265
  console.log();
1108
1266
  return { success: true };
1109
1267
  }
@@ -1114,7 +1272,7 @@ function handleModel(ctx, args) {
1114
1272
  return { success: false };
1115
1273
  }
1116
1274
  // 解析别名
1117
- const resolvedModel = MODEL_ALIASES[trimmedArgs] || args.trim();
1275
+ const resolvedModel = (0, model_catalog_1.resolveModelAlias)(args);
1118
1276
  ctx.llm.setModel(resolvedModel);
1119
1277
  (0, auto_compact_1.getAutoCompact)({ modelId: resolvedModel });
1120
1278
  ctx.store.setState({ currentModel: resolvedModel });
@@ -1893,6 +2051,7 @@ async function handleCompact(ctx, args) {
1893
2051
  console.log();
1894
2052
  return { success: true };
1895
2053
  }
2054
+ console.log(DIM((0, agent_status_1.compactStatus)()));
1896
2055
  try {
1897
2056
  const autoCompact = (0, auto_compact_1.getAutoCompact)();
1898
2057
  autoCompact.configure({
@@ -2680,6 +2839,15 @@ const COMMANDS = [
2680
2839
  type: 'builtin',
2681
2840
  execute: (ctx, args) => handleTrace(ctx, args),
2682
2841
  },
2842
+ {
2843
+ name: 'last-tool',
2844
+ aliases: ['tool-last'],
2845
+ description: 'Show the latest tool call/result with full inspection hints',
2846
+ category: 'diagnostics',
2847
+ priority: 15,
2848
+ type: 'builtin',
2849
+ execute: (ctx, args) => handleLastTool(ctx, args),
2850
+ },
2683
2851
  {
2684
2852
  name: 'artifacts',
2685
2853
  aliases: ['artifact'],