@cloudcli-ai/cloudcli 1.37.0 → 1.37.1

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 (112) hide show
  1. package/dist/assets/index-D3jfzuKN.css +32 -0
  2. package/dist/assets/{index-eGqPeIEu.js → index-DTMWjJj8.js} +324 -305
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/modules/commands/commands.routes.js +3 -3
  5. package/dist-server/server/modules/commands/commands.routes.js.map +1 -1
  6. package/dist-server/server/modules/commands/tests/commands.test.js +2 -7
  7. package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -1
  8. package/dist-server/server/modules/database/index.js +2 -0
  9. package/dist-server/server/modules/database/index.js.map +1 -1
  10. package/dist-server/server/modules/database/migrations.js +18 -1
  11. package/dist-server/server/modules/database/migrations.js.map +1 -1
  12. package/dist-server/server/modules/database/repositories/provider-models.js +112 -0
  13. package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -0
  14. package/dist-server/server/modules/database/repositories/sessions.db.js +63 -7
  15. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  16. package/dist-server/server/modules/database/schema.js +28 -3
  17. package/dist-server/server/modules/database/schema.js.map +1 -1
  18. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +102 -0
  19. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -0
  20. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +2 -1
  21. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -1
  22. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +22 -0
  23. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
  24. package/dist-server/server/modules/file-tree/file-tree.module.js +5 -1
  25. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -1
  26. package/dist-server/server/modules/file-tree/file-tree.service.js +50 -18
  27. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -1
  28. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +83 -7
  29. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -1
  30. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +46 -14
  31. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  32. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +8 -15
  33. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -1
  34. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +58 -71
  35. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  36. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +1 -54
  37. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  38. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +7 -7
  39. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  40. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +32 -669
  41. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
  42. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +105 -328
  43. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  44. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +0 -12
  45. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
  46. package/dist-server/server/modules/providers/provider.routes.js +139 -31
  47. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  48. package/dist-server/server/modules/providers/services/provider-models.service.js +167 -199
  49. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  50. package/dist-server/server/modules/providers/services/provider-runtime.service.js +2 -2
  51. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -1
  52. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +12 -4
  53. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
  54. package/dist-server/server/modules/providers/services/sessions.service.js +62 -3
  55. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  56. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +53 -17
  57. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  58. package/dist-server/server/modules/providers/tests/opencode-models.test.js +15 -126
  59. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
  60. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +5 -5
  61. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
  62. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +175 -292
  63. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
  64. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +2 -6
  65. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -1
  66. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +1 -0
  67. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -1
  68. package/dist-server/server/modules/providers/tests/provider.routes.test.js +126 -0
  69. package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -0
  70. package/dist-server/server/modules/providers/tests/sessions.service.test.js +87 -0
  71. package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -0
  72. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +5 -1
  73. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  74. package/package.json +3 -3
  75. package/server/modules/commands/commands.routes.ts +3 -3
  76. package/server/modules/commands/tests/commands.test.ts +2 -7
  77. package/server/modules/database/index.ts +2 -0
  78. package/server/modules/database/migrations.ts +20 -0
  79. package/server/modules/database/repositories/provider-models.ts +168 -0
  80. package/server/modules/database/repositories/sessions.db.ts +85 -8
  81. package/server/modules/database/schema.ts +29 -3
  82. package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -0
  83. package/server/modules/database/tests/sessions-provider-mapping.test.ts +2 -1
  84. package/server/modules/database/tests/sessions.db.integration.test.ts +32 -0
  85. package/server/modules/file-tree/file-tree.module.ts +5 -1
  86. package/server/modules/file-tree/file-tree.service.ts +68 -20
  87. package/server/modules/file-tree/tests/file-tree.service.test.ts +104 -7
  88. package/server/modules/providers/list/claude/claude-models.provider.ts +46 -14
  89. package/server/modules/providers/list/claude/claude-runtime.provider.js +8 -16
  90. package/server/modules/providers/list/codex/codex-models.provider.ts +58 -99
  91. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +1 -60
  92. package/server/modules/providers/list/codex/codex-sessions.provider.ts +7 -7
  93. package/server/modules/providers/list/cursor/cursor-models.provider.ts +32 -710
  94. package/server/modules/providers/list/opencode/opencode-models.provider.ts +105 -413
  95. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +0 -13
  96. package/server/modules/providers/provider.routes.ts +185 -33
  97. package/server/modules/providers/services/provider-models.service.ts +223 -288
  98. package/server/modules/providers/services/provider-runtime.service.ts +2 -3
  99. package/server/modules/providers/services/session-conversations-search.service.ts +12 -4
  100. package/server/modules/providers/services/sessions.service.ts +87 -3
  101. package/server/modules/providers/tests/codex-sessions.test.ts +57 -18
  102. package/server/modules/providers/tests/opencode-models.test.ts +34 -135
  103. package/server/modules/providers/tests/opencode-sessions.test.ts +5 -5
  104. package/server/modules/providers/tests/provider-models.service.test.ts +353 -450
  105. package/server/modules/providers/tests/provider-runtime.service.test.ts +2 -6
  106. package/server/modules/providers/tests/provider-token-usage.service.test.ts +1 -0
  107. package/server/modules/providers/tests/provider.routes.test.ts +183 -0
  108. package/server/modules/providers/tests/sessions.service.test.ts +127 -0
  109. package/server/modules/websocket/services/chat-websocket.service.ts +5 -1
  110. package/server/shared/interfaces.ts +4 -6
  111. package/server/shared/types.ts +29 -17
  112. package/dist/assets/index-DSlds633.css +0 -32
@@ -7,7 +7,6 @@ import TOML from '@iarna/toml';
7
7
  import type { IProviderModels } from '@/shared/interfaces.js';
8
8
  import type {
9
9
  ProviderCurrentActiveModel,
10
- ProviderModelOption,
11
10
  ProviderModelsDefinition,
12
11
  } from '@/shared/types.js';
13
12
  import {
@@ -16,11 +15,60 @@ import {
16
15
  readOptionalString,
17
16
  } from '@/shared/utils.js';
18
17
 
19
- export const CODEX_FALLBACK_MODELS: ProviderModelsDefinition = {
18
+ /** Curated Codex catalog shipped as immutable CloudCLI defaults. */
19
+ export const CODEX_PREDEFINED_MODELS: ProviderModelsDefinition = {
20
20
  OPTIONS: [
21
+ {
22
+ value: 'gpt-5.6-sol',
23
+ label: 'GPT-5.6 Sol',
24
+ description: 'Latest frontier agentic coding model.',
25
+ effort: {
26
+ default: 'low',
27
+ values: [
28
+ { value: 'low' },
29
+ { value: 'medium' },
30
+ { value: 'high' },
31
+ { value: 'xhigh' },
32
+ { value: 'max' },
33
+ { value: 'ultra' },
34
+ ],
35
+ },
36
+ },
37
+ {
38
+ value: 'gpt-5.6-terra',
39
+ label: 'GPT-5.6 Terra',
40
+ description: 'Balanced agentic coding model for everyday work.',
41
+ effort: {
42
+ default: 'medium',
43
+ values: [
44
+ { value: 'low' },
45
+ { value: 'medium' },
46
+ { value: 'high' },
47
+ { value: 'xhigh' },
48
+ { value: 'max' },
49
+ { value: 'ultra' },
50
+ ],
51
+ },
52
+ },
53
+ {
54
+ value: 'gpt-5.6-luna',
55
+ label: 'GPT-5.6 Luna',
56
+ description: 'Fast and affordable agentic coding model.',
57
+ effort: {
58
+ default: 'medium',
59
+ values: [
60
+ { value: 'low' },
61
+ { value: 'medium' },
62
+ { value: 'high' },
63
+ { value: 'xhigh' },
64
+ { value: 'max' },
65
+ ],
66
+ },
67
+ },
21
68
  {
22
69
  value: 'gpt-5.5',
23
- label: 'gpt-5.5',
70
+ label: 'GPT-5.5',
71
+ description: 'Frontier model for complex coding, research, and real-world work.',
24
72
  effort: {
25
73
  default: 'medium',
26
74
  values: [{ value: 'low' }, { value: 'medium' }, { value: 'high' }, { value: 'xhigh' }],
@@ -28,7 +76,8 @@ export const CODEX_FALLBACK_MODELS: ProviderModelsDefinition = {
28
76
  },
29
77
  {
30
78
  value: 'gpt-5.4',
31
- label: 'gpt-5.4',
79
+ label: 'GPT-5.4',
80
+ description: 'Strong model for everyday coding.',
32
81
  effort: {
33
82
  default: 'medium',
34
83
  values: [{ value: 'low' }, { value: 'medium' }, { value: 'high' }, { value: 'xhigh' }],
@@ -36,113 +85,23 @@ export const CODEX_FALLBACK_MODELS: ProviderModelsDefinition = {
36
85
  },
37
86
  {
38
87
  value: 'gpt-5.4-mini',
39
- label: 'gpt-5.4-mini',
88
+ label: 'GPT-5.4 Mini',
89
+ description: 'Small, fast, and cost-efficient model for simpler coding tasks.',
40
90
  effort: {
41
91
  default: 'medium',
42
92
  values: [{ value: 'low' }, { value: 'medium' }, { value: 'high' }, { value: 'xhigh' }],
43
93
  },
44
94
  },
45
95
  ],
46
- DEFAULT: 'gpt-5.4',
96
+ DEFAULT: 'gpt-5.6-sol',
47
97
  };
48
98
 
49
- type CodexCachedModel = {
50
- slug?: string;
51
- display_name?: string;
52
- description?: string;
53
- priority?: number;
54
- visibility?: string;
55
- supported_in_api?: boolean;
56
- default_reasoning_level?: string;
57
- supported_reasoning_levels?: Array<{
58
- effort?: string;
59
- description?: string;
60
- }>;
61
- };
62
-
63
- const CODEX_MODELS_CACHE_PATH = path.join(os.homedir(), '.codex', 'models_cache.json');
64
99
  const CODEX_CONFIG_PATH = path.join(os.homedir(), '.codex', 'config.toml');
65
100
 
66
- const isCodexCachedModel = (value: unknown): value is CodexCachedModel => {
67
- const record = readObjectRecord(value);
68
- return Boolean(record && readOptionalString(record.slug));
69
- };
70
-
71
- const readCodexPriority = (value: unknown): number => (
72
- typeof value === 'number' && Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER
73
- );
74
-
75
- const mapCodexModel = (model: CodexCachedModel): ProviderModelOption => {
76
- const effortValues = Array.isArray(model.supported_reasoning_levels)
77
- ? model.supported_reasoning_levels
78
- .map((level) => {
79
- const value = readOptionalString(level?.effort);
80
- if (!value) {
81
- return null;
82
- }
83
-
84
- return {
85
- value,
86
- description: readOptionalString(level?.description),
87
- };
88
- })
89
- .filter((level): level is NonNullable<typeof level> => Boolean(level))
90
- : [];
91
-
92
- return {
93
- value: model.slug as string,
94
- label: readOptionalString(model.display_name) ?? (model.slug as string),
95
- description: readOptionalString(model.description),
96
- effort: effortValues.length > 0
97
- ? {
98
- default: readOptionalString(model.default_reasoning_level) ?? undefined,
99
- values: effortValues,
100
- }
101
- : undefined,
102
- };
103
- };
104
-
105
- const buildCodexModelsDefinition = (models: CodexCachedModel[]): ProviderModelsDefinition => {
106
- const sortedModels = [...models]
107
- .filter((model) => model.visibility === 'list' && model.supported_in_api !== false)
108
- .sort((left, right) => readCodexPriority(left.priority) - readCodexPriority(right.priority));
109
-
110
- const options: ProviderModelOption[] = [];
111
- const seenValues = new Set<string>();
112
-
113
- for (const model of sortedModels) {
114
- const mappedModel = mapCodexModel(model);
115
- if (seenValues.has(mappedModel.value)) {
116
- continue;
117
- }
118
-
119
- seenValues.add(mappedModel.value);
120
- options.push(mappedModel);
121
- }
122
-
123
- if (options.length === 0) {
124
- return CODEX_FALLBACK_MODELS;
125
- }
126
-
127
- return {
128
- OPTIONS: options,
129
- DEFAULT: options[0]?.value ?? CODEX_FALLBACK_MODELS.DEFAULT,
130
- };
131
- };
132
-
101
+ /** Provider registry model adapter for Codex predefined models and active config. */
133
102
  export class CodexProviderModels implements IProviderModels {
134
103
  async getSupportedModels(): Promise<ProviderModelsDefinition> {
135
- try {
136
- const raw = await readFile(CODEX_MODELS_CACHE_PATH, 'utf8');
137
- const parsed = readObjectRecord(JSON.parse(raw));
138
- const models = Array.isArray(parsed?.models)
139
- ? parsed.models.filter(isCodexCachedModel)
140
- : [];
141
-
142
- return buildCodexModelsDefinition(models);
143
- } catch {
144
- return CODEX_FALLBACK_MODELS;
145
- }
104
+ return CODEX_PREDEFINED_MODELS;
146
105
  }
147
106
 
148
107
  async getCurrentActiveModel(): Promise<ProviderCurrentActiveModel> {
@@ -134,23 +134,7 @@ export class CodexSessionSynchronizer implements IProviderSessionSynchronizer {
134
134
  };
135
135
  }
136
136
 
137
- // Sessions started by sending a message from cloudcli carry a distinct
138
- // app-allocated session_id mapped to the provider id. For these we title the
139
- // conversation from the first user message the user typed, instead of the
140
- // generic "Untitled Codex Session" placeholder. Sessions discovered purely
141
- // by indexing (session_id === provider_session_id) keep the existing
142
- // thread_name/last-agent-message setup below.
143
- const isAppCreated =
144
- existingSession != null &&
145
- existingSession.provider_session_id != null &&
146
- existingSession.session_id !== existingSession.provider_session_id;
147
-
148
- let sessionName = isAppCreated
149
- ? await this.extractFirstUserMessageFromStart(filePath)
150
- : undefined;
151
- if (!sessionName) {
152
- sessionName = nameMap.get(parsed.sessionId);
153
- }
137
+ let sessionName = nameMap.get(parsed.sessionId);
154
138
  if (!sessionName) {
155
139
  sessionName = await this.extractLastAgentMessageFromEnd(filePath);
156
140
  }
@@ -180,49 +164,6 @@ export class CodexSessionSynchronizer implements IProviderSessionSynchronizer {
180
164
  return typeof source === 'object' && source !== null && 'subagent' in source;
181
165
  }
182
166
 
183
- /**
184
- * Returns the first user message text in a Codex transcript, used to title
185
- * app-created sessions from the prompt the user sent from cloudcli.
186
- *
187
- * Reads the `event_msg`/`user_message` payload rather than the raw
188
- * `response_item` user turn so injected `<environment_context>` boilerplate is
189
- * never mistaken for the user's prompt.
190
- */
191
- private async extractFirstUserMessageFromStart(filePath: string): Promise<string | undefined> {
192
- try {
193
- const content = await readFile(filePath, 'utf8');
194
- const lines = content.split(/\r?\n/);
195
-
196
- for (const rawLine of lines) {
197
- const line = rawLine.trim();
198
- if (!line) {
199
- continue;
200
- }
201
-
202
- let parsed: unknown;
203
- try {
204
- parsed = JSON.parse(line);
205
- } catch {
206
- continue;
207
- }
208
-
209
- const data = parsed as Record<string, unknown>;
210
- const eventType = typeof data.type === 'string' ? data.type : undefined;
211
- const payload = data.payload as Record<string, unknown> | undefined;
212
- const payloadType = typeof payload?.type === 'string' ? payload.type : undefined;
213
- const message = typeof payload?.message === 'string' ? payload.message : undefined;
214
-
215
- if (eventType === 'event_msg' && payloadType === 'user_message' && message?.trim()) {
216
- return message;
217
- }
218
- }
219
- } catch {
220
- // Ignore missing/unreadable files so sync can continue.
221
- }
222
-
223
- return undefined;
224
- }
225
-
226
167
  private async extractLastAgentMessageFromEnd(filePath: string): Promise<string | undefined> {
227
168
  try {
228
169
  const content = await readFile(filePath, 'utf8');
@@ -143,7 +143,7 @@ function decodeJavaScriptStringLiteral(literal: string): string {
143
143
 
144
144
  function extractNestedCodexCommands(source: string): string[] {
145
145
  const commands: string[] = [];
146
- const commandPattern = /\bcommand\s*:\s*("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)/gs;
146
+ const commandPattern = /(?:["']command["']|\bcommand)\s*:\s*("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)/gs;
147
147
  for (const match of source.matchAll(commandPattern)) {
148
148
  commands.push(decodeJavaScriptStringLiteral(match[1]));
149
149
  }
@@ -173,7 +173,7 @@ function extractNestedCodexCommands(source: string): string[] {
173
173
  */
174
174
  function translateCodexExecInput(input: unknown): { toolName: string; toolInput: string } | null {
175
175
  const source = typeof input === 'string' ? input : String(input || '');
176
- if (/\btools\.shell_command\s*\(/.test(source)) {
176
+ if (/\btools\.(?:shell_command|exec_command)\s*\(/.test(source)) {
177
177
  const commands = extractNestedCodexCommands(source);
178
178
  if (commands.length > 0) {
179
179
  return {
@@ -506,19 +506,19 @@ async function getCodexSessionMessages(
506
506
  if (entry.type === 'response_item' && entry.payload?.type === 'custom_tool_call') {
507
507
  let toolName = entry.payload.name || 'custom_tool';
508
508
  const input = entry.payload.input || '';
509
+ let toolInput = input;
509
510
 
510
511
  if (toolName === 'exec') {
511
512
  const translated = translateCodexExecInput(input);
512
- if (!translated) {
513
- ignoredToolCallIds.add(entry.payload.call_id);
514
- continue;
513
+ if (translated) {
514
+ toolName = translated.toolName;
515
+ toolInput = translated.toolInput;
515
516
  }
516
- toolName = translated.toolName;
517
517
  messages.push({
518
518
  type: 'tool_use',
519
519
  timestamp: entry.timestamp,
520
520
  toolName,
521
- toolInput: translated.toolInput,
521
+ toolInput,
522
522
  toolCallId: entry.payload.call_id,
523
523
  });
524
524
  execToolCallIds.add(entry.payload.call_id);