@kafca/agentdock 0.1.30 → 0.1.31

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 (92) hide show
  1. package/README.md +4 -0
  2. package/dist/renderer/assets/{Badge-DlVJI1Ys.js → Badge-DaHt-aUT.js} +1 -1
  3. package/dist/renderer/assets/{Chat-oa8OjaHQ.js → Chat-Dzeq3kiD.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-C-N8KS5C.js → ChatMarkdown-B-L5Roai.js} +1 -1
  5. package/dist/renderer/assets/{Config-D9sL_d4D.js → Config-BI4LJ7Fw.js} +1 -1
  6. package/dist/renderer/assets/{CronList-Z5JU3DHk.js → CronList-Dic7pblj.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-D3BwbG43.js → Dashboard-C0_ATyGe.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-QOj765Ul.js → EmptyState-SQsG1DZP.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-J7n01mPu.js → KnowledgeDetail-D4yUJzp7.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-BFnH0NVk.js → KnowledgeHome-L0tsg-oo.js} +1 -1
  11. package/dist/renderer/assets/{Logs-DfSUifXc.js → Logs-C2Jdr3uQ.js} +1 -1
  12. package/dist/renderer/assets/{Modal-QjEGhyru.js → Modal-GUH3iPXo.js} +1 -1
  13. package/dist/renderer/assets/{Page-qdHFSw7x.js → Page-m42FBy97.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-DS_rfvhh.js → ProjectDetail-RF_sagPO.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-COtyZd7H.js → ProjectList-Cyr8RDK3.js} +1 -1
  16. package/dist/renderer/assets/{Select-BQ8mncVu.js → Select-CRlDgI5s.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-DjVnjuQy.js → SessionChat-_HhzMwEO.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-88dgGZJ8.js → SessionList-DNwZjGTv.js} +1 -1
  19. package/dist/renderer/assets/ThreadChat-DxBmdsAm.js +23 -0
  20. package/dist/renderer/assets/{Workspace-D_hzSJjX.js → Workspace-DFphG85O.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-BMpknulW.js → arrow-left-bILMzse7.js} +1 -1
  22. package/dist/renderer/assets/{book-open-CiaOeQbU.js → book-open-BNBWEEve.js} +1 -1
  23. package/dist/renderer/assets/{check-CgwYH4GF.js → check-MGp5kvnb.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-BzD2S1OO.js → chevron-down-zsfoTlh7.js} +1 -1
  25. package/dist/renderer/assets/{circle-BDHD7g7l.js → circle-BX_xUSg-.js} +1 -1
  26. package/dist/renderer/assets/{desktop-BiR5LPL5.js → desktop-CgrO_cdQ.js} +1 -1
  27. package/dist/renderer/assets/{desktop-BkMW-h5p.js → desktop-O8_6ZCVZ.js} +2 -2
  28. package/dist/renderer/assets/{funnel-Bruf5FYA.js → funnel-7442U1wq.js} +1 -1
  29. package/dist/renderer/assets/{heart-D7Mz04B0.js → heart-B3d8bnSH.js} +1 -1
  30. package/dist/renderer/assets/{index-gZIRr4_o.js → index-5YUqCvBf.js} +1 -1
  31. package/dist/renderer/assets/{index-CL1e8m3U.js → index-BBaYsVjU.js} +2 -2
  32. package/dist/renderer/assets/{pencil-C6gzDMse.js → pencil-QzWgkmoH.js} +1 -1
  33. package/dist/renderer/assets/{play-DqTXX-Pr.js → play-Bsc8hSI7.js} +1 -1
  34. package/dist/renderer/assets/{plug-ykmbeaO3.js → plug-CRY7sjvB.js} +1 -1
  35. package/dist/renderer/assets/{plus-DHE60vMX.js → plus-Dr5Ei8Ud.js} +1 -1
  36. package/dist/renderer/assets/projects-BDYSOFIJ.js +1 -0
  37. package/dist/renderer/assets/{save-CGIvrdQI.js → save-giJnp2Ki.js} +1 -1
  38. package/dist/renderer/assets/{search-D7IFAwyE.js → search-DcvHLmKs.js} +1 -1
  39. package/dist/renderer/assets/{server-aOsirp7I.js → server-D_Qu8If5.js} +1 -1
  40. package/dist/renderer/assets/{session-utils-Dxfp4ohQ.js → session-utils-CsASahfU.js} +1 -1
  41. package/dist/renderer/assets/{sessions-Db1XPbG2.js → sessions-eMpPqp4P.js} +1 -1
  42. package/dist/renderer/assets/{shield-check-ChXeQK-d.js → shield-check-BpF0uIw-.js} +1 -1
  43. package/dist/renderer/assets/{trash-2-CfN-c1zw.js → trash-2-OJFmx3xk.js} +1 -1
  44. package/dist/renderer/assets/{user-C7OHaBp4.js → user-GL_ivaV6.js} +1 -1
  45. package/dist/renderer/assets/{wifi-off-CpaJigye.js → wifi-off-CQT5VNQl.js} +1 -1
  46. package/dist/renderer/index.html +1 -1
  47. package/dist-electron/electron/agent-runtime-detector.test.js +30 -0
  48. package/dist-electron/electron/local-core-refactor.test.js +422 -0
  49. package/dist-electron/electron/plugin-kernel.test.js +81 -1
  50. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +28 -3
  51. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +102 -15
  52. package/dist-electron/services/local-ai-core/src/agents/claudecode/behavior.js +5 -0
  53. package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +36 -0
  54. package/dist-electron/services/local-ai-core/src/agents/claudecode/index.js +15 -0
  55. package/dist-electron/services/local-ai-core/src/agents/codex/behavior.js +5 -0
  56. package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +24 -0
  57. package/dist-electron/services/local-ai-core/src/agents/codex/index.js +15 -0
  58. package/dist-electron/services/local-ai-core/src/agents/hermes/behavior.js +29 -0
  59. package/dist-electron/services/local-ai-core/src/agents/hermes/definition.js +22 -0
  60. package/dist-electron/services/local-ai-core/src/agents/hermes/index.js +15 -0
  61. package/dist-electron/services/local-ai-core/src/agents/index.js +98 -0
  62. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/behavior.js +5 -0
  63. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +14 -0
  64. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +27 -0
  65. package/dist-electron/services/local-ai-core/src/agents/opencode/behavior.js +5 -0
  66. package/dist-electron/services/local-ai-core/src/agents/opencode/definition.js +18 -0
  67. package/dist-electron/services/local-ai-core/src/agents/opencode/index.js +15 -0
  68. package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +119 -0
  69. package/dist-electron/services/local-ai-core/src/agents/pi/behavior.js +5 -0
  70. package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +23 -0
  71. package/dist-electron/services/local-ai-core/src/agents/pi/index.js +15 -0
  72. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +139 -0
  73. package/dist-electron/services/local-ai-core/src/agents/shared/acp-behavior.js +11 -0
  74. package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +60 -0
  75. package/dist-electron/services/local-ai-core/src/agents/shared/definition.js +12 -0
  76. package/dist-electron/services/local-ai-core/src/agents/shared/launch-utils.js +122 -0
  77. package/dist-electron/services/local-ai-core/src/agents/shared/progress-replay.js +19 -0
  78. package/dist-electron/services/local-ai-core/src/agents/shared/replay-prefix.js +68 -0
  79. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +0 -2
  80. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +0 -1
  81. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +8 -7
  82. package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -130
  83. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +22 -397
  84. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +9 -45
  85. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +62 -1
  86. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +2 -12
  87. package/dist-electron/shared/desktop.js +3 -1
  88. package/dist-electron/src/pages/Threads/thread-chat-model.js +27 -18
  89. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +57 -18
  90. package/package.json +1 -1
  91. package/dist/renderer/assets/ThreadChat-BCdbTxBo.js +0 -23
  92. package/dist/renderer/assets/projects-Bx5p10th.js +0 -1
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizePlatformTypes = normalizePlatformTypes;
4
4
  exports.isLocalCoreNativeAcpProject = isLocalCoreNativeAcpProject;
5
5
  exports.toLocalCoreProjectConfig = toLocalCoreProjectConfig;
6
- const node_module_1 = require("node:module");
7
- const node_fs_1 = require("node:fs");
8
6
  const node_path_1 = require("node:path");
9
7
  const desktop_js_1 = require("../../../../shared/desktop.js");
8
+ const index_js_1 = require("../agents/index.js");
9
+ const launch_utils_js_1 = require("../agents/shared/launch-utils.js");
10
10
  function normalizePlatformTypes(project) {
11
11
  return Array.isArray(project?.platforms)
12
12
  ? project.platforms.map((platform) => (0, desktop_js_1.normalizeDesktopPlatformType)(platform?.type)).filter(Boolean)
@@ -18,348 +18,16 @@ function isLocalCoreNativeAcpProject(project) {
18
18
  || agentType === 'acp'
19
19
  || agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE;
20
20
  }
21
- function resolveAgentModel(project, providers) {
21
+ function resolveAgentModel(project, providers, definition) {
22
22
  const agentType = String(project.agent?.type || '').trim().toLowerCase();
23
23
  const rawModel = String(project.agent?.options?.model || '').trim();
24
24
  const normalizedModel = (0, desktop_js_1.normalizeDesktopAgentModel)(agentType, rawModel);
25
- if (agentType === 'pi') {
26
- return rawModel || getFirstProviderModelId(providers);
27
- }
28
- if (agentType !== 'opencode') {
29
- return normalizedModel;
30
- }
31
- const configuredProviderModel = getFirstProviderModelRef(providers);
32
- if (configuredProviderModel &&
33
- (!rawModel || normalizedModel === desktop_js_1.DEFAULT_DESKTOP_OPENCODE_MODEL)) {
34
- return configuredProviderModel;
35
- }
36
- return normalizedModel;
37
- }
38
- function getFirstProviderModelId(providers) {
39
- for (const provider of providers) {
40
- const modelId = getProviderDefaultModelId(provider);
41
- if (modelId) {
42
- return modelId;
43
- }
44
- }
45
- return '';
46
- }
47
- function getFirstProviderModelRef(providers) {
48
- for (const provider of providers) {
49
- const providerId = normalizeOpencodeProviderId(provider.name);
50
- const modelId = getProviderDefaultModelId(provider);
51
- if (providerId && modelId) {
52
- return `${providerId}/${modelId}`;
53
- }
54
- }
55
- return '';
56
- }
57
- function getProviderDefaultModelId(provider) {
58
- const directModel = String(provider.model || '').trim();
59
- if (directModel) {
60
- return directModel;
61
- }
62
- const firstModel = Array.isArray(provider.models)
63
- ? provider.models.find((entry) => String(entry?.model || '').trim())
64
- : null;
65
- return String(firstModel?.model || '').trim();
66
- }
67
- function buildOpencodeInlineConfig(model, providers) {
68
- const config = {
69
- $schema: 'https://opencode.ai/config.json',
70
- };
71
- const env = {};
72
- if (model) {
73
- config.model = model;
74
- }
75
- const providerConfig = {};
76
- for (const provider of providers) {
77
- const providerId = normalizeOpencodeProviderId(provider.name);
78
- if (!providerId) {
79
- continue;
80
- }
81
- const entry = {
82
- name: String(provider.name || providerId),
83
- };
84
- if (shouldUseOpenAiCompatibleProvider(providerId)) {
85
- entry.npm = '@ai-sdk/openai-compatible';
86
- }
87
- const options = {};
88
- const baseUrl = String(provider.base_url || '').trim();
89
- if (baseUrl) {
90
- options.baseURL = baseUrl;
91
- }
92
- const apiKey = String(provider.api_key || '').trim();
93
- if (apiKey) {
94
- const envName = opencodeProviderApiKeyEnvName(providerId);
95
- env[envName] = apiKey;
96
- options.apiKey = `{env:${envName}}`;
97
- }
98
- if (Object.keys(options).length > 0) {
99
- entry.options = options;
100
- }
101
- const models = buildOpencodeProviderModels(provider);
102
- if (Object.keys(models).length > 0) {
103
- entry.models = models;
104
- }
105
- providerConfig[providerId] = entry;
106
- }
107
- if (Object.keys(providerConfig).length > 0) {
108
- config.provider = providerConfig;
109
- }
110
- return {
111
- config,
112
- env,
113
- };
114
- }
115
- function buildOpencodeProviderModels(provider) {
116
- const models = {};
117
- const addModel = (model, alias) => {
118
- const modelId = String(model || '').trim();
119
- if (!modelId || models[modelId]) {
120
- return;
121
- }
122
- models[modelId] = {
123
- name: String(alias || modelId).trim() || modelId,
124
- };
125
- };
126
- addModel(provider.model);
127
- for (const model of Array.isArray(provider.models) ? provider.models : []) {
128
- addModel(model?.model, model?.alias);
129
- }
130
- return models;
131
- }
132
- function collectProviderEnv(providers) {
133
- const env = {};
134
- for (const provider of providers) {
135
- if (!provider.env || typeof provider.env !== 'object') {
136
- continue;
137
- }
138
- for (const [key, value] of Object.entries(provider.env)) {
139
- const envKey = key.trim();
140
- if (envKey) {
141
- env[envKey] = String(value ?? '');
142
- }
143
- }
144
- }
145
- return env;
146
- }
147
- function collectPiProviderEnv(providers) {
148
- const env = {};
149
- for (const provider of providers) {
150
- const apiKey = String(provider.api_key || '').trim();
151
- const envName = piProviderApiKeyEnvName(provider.name);
152
- if (apiKey && envName) {
153
- env[envName] = apiKey;
154
- }
155
- }
156
- return env;
157
- }
158
- function resolvePiProviderModel(providers, model) {
159
- const [explicitProvider, explicitModel] = splitProviderModelRef(model);
160
- if (explicitProvider && explicitModel) {
161
- return {
162
- providerId: normalizePiProviderId(explicitProvider),
163
- modelId: explicitModel,
164
- };
165
- }
166
- for (const provider of providers) {
167
- const providerId = normalizePiProviderId(provider.name);
168
- const modelId = getProviderDefaultModelId(provider);
169
- if (providerId && modelId && (!model || model === modelId)) {
170
- return { providerId, modelId };
171
- }
172
- }
173
- const fallbackProvider = providers.find((provider) => normalizePiProviderId(provider.name));
174
- return {
175
- providerId: normalizePiProviderId(fallbackProvider?.name),
176
- modelId: model,
177
- };
178
- }
179
- function splitProviderModelRef(value) {
180
- const trimmed = value.trim();
181
- const slashIndex = trimmed.indexOf('/');
182
- if (slashIndex <= 0 || slashIndex >= trimmed.length - 1) {
183
- return ['', trimmed];
184
- }
185
- return [trimmed.slice(0, slashIndex), trimmed.slice(slashIndex + 1)];
186
- }
187
- function normalizePiProviderId(providerName) {
188
- const providerId = normalizeProviderId(providerName);
189
- const aliases = {
190
- google: 'google',
191
- gemini: 'google',
192
- kimi: 'kimi-coding',
193
- moonshot: 'moonshotai',
194
- zhipuai: 'zai',
195
- };
196
- return aliases[providerId] || providerId;
197
- }
198
- function piProviderAgentDir(configState, projectName) {
199
- const configDir = (0, node_path_1.dirname)(configState.path);
200
- const safeProjectName = String(projectName || 'workspace')
201
- .trim()
202
- .replace(/[^a-zA-Z0-9._-]+/g, '-')
203
- .replace(/^-+|-+$/g, '') || 'workspace';
204
- return (0, node_path_1.resolve)(configDir, '.pi-agent', safeProjectName);
205
- }
206
- function writeJsonFile(path, value, mode = 0o600) {
207
- (0, node_fs_1.writeFileSync)(path, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode });
208
- (0, node_fs_1.chmodSync)(path, mode);
209
- }
210
- function writePiProviderRuntimeConfig(configState, project, providers, model) {
211
- if (providers.length === 0) {
212
- return {};
213
- }
214
- const { providerId, modelId } = resolvePiProviderModel(providers, model);
215
- const agentDir = piProviderAgentDir(configState, project.name);
216
- (0, node_fs_1.mkdirSync)(agentDir, { recursive: true, mode: 0o700 });
217
- (0, node_fs_1.chmodSync)(agentDir, 0o700);
218
- const auth = {};
219
- const modelProviders = {};
220
- for (const provider of providers) {
221
- const id = normalizePiProviderId(provider.name);
222
- if (!id) {
223
- continue;
224
- }
225
- const apiKey = String(provider.api_key || '').trim();
226
- const baseUrl = String(provider.base_url || '').trim();
227
- if (apiKey) {
228
- auth[id] = { type: 'api_key', key: apiKey };
229
- }
230
- if (baseUrl || apiKey) {
231
- modelProviders[id] = {
232
- name: String(provider.name || id).trim() || id,
233
- ...(baseUrl ? { baseUrl } : {}),
234
- ...(apiKey ? { apiKey } : {}),
235
- };
236
- }
237
- }
238
- writeJsonFile((0, node_path_1.resolve)(agentDir, 'auth.json'), auth);
239
- writeJsonFile((0, node_path_1.resolve)(agentDir, 'models.json'), { providers: modelProviders });
240
- writeJsonFile((0, node_path_1.resolve)(agentDir, 'settings.json'), {
241
- ...(providerId ? { defaultProvider: providerId } : {}),
242
- ...(modelId ? { defaultModel: modelId } : {}),
243
- quietStartup: true,
244
- }, 0o644);
245
- return {
246
- PI_CODING_AGENT_DIR: agentDir,
247
- };
248
- }
249
- function normalizeOpencodeProviderId(value) {
250
- return String(value || '')
251
- .trim()
252
- .toLowerCase()
253
- .replace(/[^a-z0-9._-]+/g, '-')
254
- .replace(/^-+|-+$/g, '');
255
- }
256
- function normalizeProviderId(value) {
257
- return String(value || '')
258
- .trim()
259
- .toLowerCase()
260
- .replace(/[^a-z0-9]+/g, '-')
261
- .replace(/^-+|-+$/g, '');
262
- }
263
- function piProviderApiKeyEnvName(providerName) {
264
- const providerId = normalizeProviderId(providerName);
265
- const envNames = {
266
- anthropic: 'ANTHROPIC_API_KEY',
267
- 'azure-openai': 'AZURE_OPENAI_API_KEY',
268
- 'azure-openai-responses': 'AZURE_OPENAI_API_KEY',
269
- cerebras: 'CEREBRAS_API_KEY',
270
- cloudflare: 'CLOUDFLARE_API_KEY',
271
- 'cloudflare-ai-gateway': 'CLOUDFLARE_API_KEY',
272
- 'cloudflare-workers-ai': 'CLOUDFLARE_API_KEY',
273
- deepseek: 'DEEPSEEK_API_KEY',
274
- fireworks: 'FIREWORKS_API_KEY',
275
- gemini: 'GEMINI_API_KEY',
276
- google: 'GEMINI_API_KEY',
277
- groq: 'GROQ_API_KEY',
278
- huggingface: 'HF_TOKEN',
279
- kimi: 'KIMI_API_KEY',
280
- 'kimi-coding': 'KIMI_API_KEY',
281
- minimax: 'MINIMAX_API_KEY',
282
- 'minimax-cn': 'MINIMAX_CN_API_KEY',
283
- mistral: 'MISTRAL_API_KEY',
284
- moonshot: 'KIMI_API_KEY',
285
- openai: 'OPENAI_API_KEY',
286
- opencode: 'OPENCODE_API_KEY',
287
- 'opencode-go': 'OPENCODE_API_KEY',
288
- openrouter: 'OPENROUTER_API_KEY',
289
- siliconflow: 'SILICONFLOW_API_KEY',
290
- vercel: 'AI_GATEWAY_API_KEY',
291
- 'vercel-ai-gateway': 'AI_GATEWAY_API_KEY',
292
- xai: 'XAI_API_KEY',
293
- zai: 'ZAI_API_KEY',
294
- zhipuai: 'ZAI_API_KEY',
295
- };
296
- return envNames[providerId] || '';
297
- }
298
- function opencodeProviderApiKeyEnvName(providerId) {
299
- const suffix = providerId.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
300
- return `AI_WORKSTATION_OPENCODE_${suffix || 'PROVIDER'}_API_KEY`;
301
- }
302
- function shouldUseOpenAiCompatibleProvider(providerId) {
303
- const builtInNonCompatibleProviders = new Set([
304
- 'anthropic',
305
- 'google',
306
- 'gemini',
307
- ]);
308
- return !builtInNonCompatibleProviders.has(providerId);
309
- }
310
- function resolveBundledAcpCommand(packageName, binName) {
311
- const require = (0, node_module_1.createRequire)(__filename);
312
- const packageJsonPath = resolveBundledPackageJsonPath(packageName);
313
- const packageJson = require(packageJsonPath);
314
- const binField = packageJson.bin;
315
- const relativeBinPath = typeof binField === 'string'
316
- ? binField
317
- : binField?.[binName];
318
- if (!relativeBinPath) {
319
- throw new Error(`Bundled package "${packageName}" does not declare the ${binName} bin.`);
320
- }
321
- return {
322
- command: process.execPath,
323
- args: [(0, node_path_1.resolve)((0, node_path_1.dirname)(packageJsonPath), relativeBinPath)],
324
- };
325
- }
326
- function resolveBundledPackageJsonPath(packageName) {
327
- const require = (0, node_module_1.createRequire)(__filename);
328
- try {
329
- return require.resolve(`${packageName}/package.json`);
330
- }
331
- catch (error) {
332
- if (error?.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
333
- throw error;
334
- }
335
- }
336
- for (const basePath of require.resolve.paths(packageName) || []) {
337
- const packageJsonPath = (0, node_path_1.resolve)(basePath, ...packageName.split('/'), 'package.json');
338
- if ((0, node_fs_1.existsSync)(packageJsonPath)) {
339
- return packageJsonPath;
340
- }
341
- }
342
- let current = (0, node_path_1.dirname)(require.resolve(packageName));
343
- while (current && current !== (0, node_path_1.dirname)(current)) {
344
- const packageJsonPath = (0, node_path_1.resolve)(current, 'package.json');
345
- if ((0, node_fs_1.existsSync)(packageJsonPath)) {
346
- return packageJsonPath;
347
- }
348
- current = (0, node_path_1.dirname)(current);
349
- }
350
- throw new Error(`Bundled package "${packageName}" package.json could not be resolved.`);
351
- }
352
- function resolveBundledCodexCommand() {
353
- return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, 'codex-acp');
354
- }
355
- function resolveBundledClaudeCodeCommand() {
356
- return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, 'claude-agent-acp');
357
- }
358
- function resolveBundledPiAcpCommand() {
359
- return resolveBundledAcpCommand(desktop_js_1.DESKTOP_PI_ACP_PACKAGE, 'pi-acp');
360
- }
361
- function resolveBundledPiCommand() {
362
- return resolveBundledAcpCommand(desktop_js_1.DESKTOP_PI_CODING_AGENT_PACKAGE, 'pi').args[0];
25
+ return definition?.resolveModel?.({
26
+ project,
27
+ providers,
28
+ rawModel,
29
+ normalizedModel,
30
+ }) || normalizedModel;
363
31
  }
364
32
  function toLocalCoreProjectConfig(configState, project) {
365
33
  const rawWorkDir = String(project.agent?.options?.work_dir || '.').trim() || '.';
@@ -377,63 +45,22 @@ function toLocalCoreProjectConfig(configState, project) {
377
45
  : {};
378
46
  const agentType = String(project.agent?.type || '').trim().toLowerCase();
379
47
  const providers = Array.isArray(project.agent?.providers) ? project.agent.providers : [];
380
- const model = resolveAgentModel(project, providers);
381
- const providerEnv = collectProviderEnv(providers);
382
- const piProviderEnv = agentType === 'pi'
383
- ? collectPiProviderEnv(providers)
384
- : {};
385
- const opencodeInlineConfig = agentType === 'opencode'
386
- ? buildOpencodeInlineConfig(model, providers)
387
- : null;
388
- const inferredOpencodeEnv = agentType === 'opencode'
389
- ? {
390
- ...(opencodeInlineConfig?.env || {}),
391
- OPENCODE_CONFIG_CONTENT: JSON.stringify(opencodeInlineConfig?.config || { $schema: 'https://opencode.ai/config.json' }),
392
- }
393
- : {};
394
- const inferredClaudeCodeEnv = agentType === 'claudecode' && model
395
- ? {
396
- ANTHROPIC_MODEL: model,
397
- }
398
- : {};
399
- const bundledPiAcp = agentType === 'pi'
400
- ? resolveBundledPiAcpCommand()
401
- : null;
402
- const bundledPiCommand = agentType === 'pi'
403
- ? resolveBundledPiCommand()
404
- : '';
405
- const piProviderRuntimeEnv = agentType === 'pi'
406
- ? writePiProviderRuntimeConfig(configState, project, providers, model)
407
- : {};
408
- const inferredPiEnv = agentType === 'pi'
409
- ? {
410
- ...piProviderEnv,
411
- ...piProviderRuntimeEnv,
412
- PI_ACP_PI_COMMAND: bundledPiCommand,
413
- }
414
- : {};
415
- const bundledCodex = agentType === 'codex'
416
- ? resolveBundledCodexCommand()
417
- : null;
418
- const bundledClaudeCode = agentType === 'claudecode'
419
- ? resolveBundledClaudeCodeCommand()
420
- : null;
421
- const inferredCommand = agentType === 'opencode'
422
- ? 'opencode'
423
- : bundledPiAcp?.command || bundledCodex?.command || bundledClaudeCode?.command || '';
48
+ const definition = (0, index_js_1.resolveAgentRuntimeDefinition)(agentType);
49
+ const model = resolveAgentModel(project, providers, definition);
50
+ const providerEnv = (0, launch_utils_js_1.collectProviderEnv)(providers);
51
+ const launchDefaults = definition?.buildLaunchConfig?.({
52
+ configState,
53
+ project,
54
+ agentType,
55
+ providers,
56
+ model,
57
+ }) || {};
58
+ const inferredCommand = launchDefaults.command || '';
424
59
  const command = String(project.agent?.options?.command || inferredCommand).trim();
425
60
  if (!command) {
426
61
  throw new Error(`Workspace "${project.name}" requires [projects.agent.options].command for Local AI Core ACP execution.`);
427
62
  }
428
- const defaultArgs = agentType === 'opencode'
429
- ? ['acp']
430
- : agentType === 'pi'
431
- ? [...(bundledPiAcp?.args || [])]
432
- : agentType === 'codex'
433
- ? [...(bundledCodex?.args || [])]
434
- : agentType === 'claudecode'
435
- ? [...(bundledClaudeCode?.args || [])]
436
- : [];
63
+ const defaultArgs = launchDefaults.args || [];
437
64
  return {
438
65
  workspaceId: project.name,
439
66
  agentType,
@@ -441,9 +68,7 @@ function toLocalCoreProjectConfig(configState, project) {
441
68
  command,
442
69
  args: args.length > 0 ? args : defaultArgs,
443
70
  env: {
444
- ...inferredOpencodeEnv,
445
- ...inferredClaudeCodeEnv,
446
- ...inferredPiEnv,
71
+ ...(launchDefaults.env || {}),
447
72
  ...providerEnv,
448
73
  ...env,
449
74
  },
@@ -6,44 +6,16 @@ const node_path_1 = require("node:path");
6
6
  const node_module_1 = require("node:module");
7
7
  const node_child_process_1 = require("node:child_process");
8
8
  const desktop_js_1 = require("../../../../shared/desktop.js");
9
- const DISPLAY_NAMES = {
10
- pi: 'Pi',
11
- opencode: 'OpenCode',
12
- codex: 'Codex',
13
- claudecode: 'Claude Code',
14
- cursor: 'Cursor',
15
- gemini: 'Gemini',
16
- qoder: 'Qoder',
17
- iflow: 'iFlow',
18
- [desktop_js_1.LOCALCORE_ACP_AGENT_TYPE]: 'LocalCore ACP',
19
- };
20
- const COMMAND_CANDIDATES = {
21
- pi: ['pi'],
22
- opencode: ['opencode'],
23
- codex: ['codex-acp', 'codex'],
24
- claudecode: ['claude-agent-acp', 'claude'],
25
- cursor: ['cursor-agent', 'cursor'],
26
- gemini: ['gemini'],
27
- qoder: ['qoder'],
28
- iflow: ['iflow'],
29
- };
30
- const VERSION_ARGUMENTS = {
31
- pi: ['--version'],
32
- opencode: ['--version'],
33
- codex: ['--version'],
34
- claudecode: ['--version'],
35
- cursor: ['--version'],
36
- gemini: ['--version'],
37
- qoder: ['--version'],
38
- iflow: ['--version'],
39
- };
9
+ const index_js_1 = require("../agents/index.js");
40
10
  function detectInstalledAgentRuntimes(options = {}) {
41
11
  const env = options.env || process.env;
42
12
  const configuredCommands = collectConfiguredAgentCommands(options.config);
43
13
  const detectedAt = (options.now || new Date()).toISOString();
44
14
  const versionTimeoutMs = options.versionTimeoutMs ?? 2500;
45
15
  return desktop_js_1.DESKTOP_AGENT_TYPE_OPTIONS.map((agentType) => {
46
- if (agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE) {
16
+ const definition = (0, index_js_1.resolveAgentRuntimeDefinition)(agentType);
17
+ const detection = definition?.detection;
18
+ if (detection?.builtin || agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE) {
47
19
  return {
48
20
  agentType,
49
21
  runtimeId: agentType,
@@ -64,21 +36,13 @@ function detectInstalledAgentRuntimes(options = {}) {
64
36
  ? installedRuntime(agentType, resolved, 'config', detectedAt, env, versionTimeoutMs)
65
37
  : missingRuntime(agentType, detectedAt, `Configured command not found: ${configured}`);
66
38
  }
67
- if (agentType === 'pi' || agentType === 'codex' || agentType === 'claudecode') {
68
- const bundled = agentType === 'pi'
69
- ? resolveBundledAcpPackage(options.requireFrom, desktop_js_1.DESKTOP_PI_CODING_AGENT_PACKAGE, ['dist/cli.js'])
70
- : agentType === 'codex'
71
- ? resolveBundledAcpPackage(options.requireFrom, desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, ['bin/codex-acp.js'])
72
- : resolveBundledAcpPackage(options.requireFrom, desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, [
73
- 'dist/cli.js',
74
- 'bin/claude-agent-acp.js',
75
- 'cli.js',
76
- ]);
39
+ for (const bundledRuntime of detection?.bundledRuntimes || []) {
40
+ const bundled = resolveBundledAcpPackage(options.requireFrom, bundledRuntime.packageName, bundledRuntime.candidates);
77
41
  if (bundled) {
78
42
  return installedRuntime(agentType, bundled, 'bundled', detectedAt, env, versionTimeoutMs);
79
43
  }
80
44
  }
81
- for (const command of COMMAND_CANDIDATES[agentType] || [agentType]) {
45
+ for (const command of detection?.commandCandidates || [agentType]) {
82
46
  const resolved = resolveCommand(command, env);
83
47
  if (resolved) {
84
48
  return installedRuntime(agentType, resolved, 'path', detectedAt, env, versionTimeoutMs);
@@ -143,7 +107,7 @@ function missingRuntime(agentType, detectedAt, error) {
143
107
  };
144
108
  }
145
109
  function displayName(agentType) {
146
- return DISPLAY_NAMES[agentType] || agentType;
110
+ return (0, index_js_1.resolveAgentRuntimeDefinition)(agentType)?.displayName || agentType;
147
111
  }
148
112
  function collectConfiguredAgentCommands(config) {
149
113
  const commands = new Map();
@@ -194,7 +158,7 @@ function isExecutableFile(path) {
194
158
  }
195
159
  }
196
160
  function detectRuntimeVersion(agentType, command, env, timeoutMs) {
197
- const args = VERSION_ARGUMENTS[agentType];
161
+ const args = (0, index_js_1.resolveAgentRuntimeDefinition)(agentType)?.detection?.versionArgs;
198
162
  if (!args || agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE) {
199
163
  return {};
200
164
  }
@@ -42,6 +42,8 @@ const DEFAULT_CONFIG = `# Managed by Local AI Core
42
42
  `;
43
43
  const LOG_FILE_NAME = 'local-core.log';
44
44
  const LOG_FILE_MAX_BYTES = 2 * 1024 * 1024;
45
+ const LOG_TAIL_CHUNK_BYTES = 64 * 1024;
46
+ const LOG_MAX_RETURN_LINES = 5000;
45
47
  class FileBackedLocalCoreRuntimeState {
46
48
  userDataPath;
47
49
  onLog;
@@ -112,7 +114,13 @@ class FileBackedLocalCoreRuntimeState {
112
114
  return this.settings.knowledge;
113
115
  }
114
116
  getLogs(limit = 200) {
115
- return this.logs.slice(-Math.max(limit, 1));
117
+ const normalizedLimit = normalizeLogLimit(limit);
118
+ const current = tailLogFile(this.logPath, normalizedLimit);
119
+ if (current.length >= normalizedLimit) {
120
+ return current.slice(-normalizedLimit);
121
+ }
122
+ const rotated = tailLogFile(`${this.logPath}.1`, normalizedLimit - current.length);
123
+ return [...rotated, ...current].slice(-normalizedLimit);
116
124
  }
117
125
  pushLog(message) {
118
126
  if (!message) {
@@ -273,6 +281,59 @@ function normalizePluginSettings(input) {
273
281
  }
274
282
  return output;
275
283
  }
284
+ function normalizeLogLimit(limit) {
285
+ if (!Number.isFinite(limit)) {
286
+ return 200;
287
+ }
288
+ return Math.min(Math.max(Math.floor(limit), 1), LOG_MAX_RETURN_LINES);
289
+ }
290
+ function tailLogFile(path, limit) {
291
+ if (limit <= 0 || !(0, node_fs_1.existsSync)(path)) {
292
+ return [];
293
+ }
294
+ let fd = -1;
295
+ try {
296
+ const size = (0, node_fs_1.statSync)(path).size;
297
+ if (size <= 0) {
298
+ return [];
299
+ }
300
+ fd = (0, node_fs_1.openSync)(path, 'r');
301
+ const chunks = [];
302
+ let position = size;
303
+ let newlineCount = 0;
304
+ while (position > 0 && newlineCount <= limit) {
305
+ const bytesToRead = Math.min(LOG_TAIL_CHUNK_BYTES, position);
306
+ position -= bytesToRead;
307
+ const chunk = Buffer.allocUnsafe(bytesToRead);
308
+ const bytesRead = (0, node_fs_1.readSync)(fd, chunk, 0, bytesToRead, position);
309
+ const slice = bytesRead === bytesToRead ? chunk : chunk.subarray(0, bytesRead);
310
+ chunks.unshift(slice);
311
+ for (let index = 0; index < slice.length; index += 1) {
312
+ if (slice[index] === 10) {
313
+ newlineCount += 1;
314
+ }
315
+ }
316
+ }
317
+ return Buffer.concat(chunks)
318
+ .toString('utf8')
319
+ .split(/\r?\n/)
320
+ .filter((line) => line.length > 0)
321
+ .slice(-limit);
322
+ }
323
+ catch {
324
+ return [];
325
+ }
326
+ finally {
327
+ if (fd >= 0) {
328
+ try {
329
+ (0, node_fs_1.closeSync)(fd);
330
+ }
331
+ catch {
332
+ // Log reads are best-effort; failed closes cannot be surfaced to callers.
333
+ }
334
+ }
335
+ }
336
+ }
276
337
  function createLocalCoreRuntimeState(options) {
277
338
  return new FileBackedLocalCoreRuntimeState(options.userDataPath, options.onLog);
278
339
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RuntimeDetectionService = void 0;
4
4
  const desktop_js_1 = require("../../../../shared/desktop.js");
5
+ const index_js_1 = require("../agents/index.js");
5
6
  const agent_runtime_detector_js_1 = require("./agent-runtime-detector.js");
6
7
  const runtime_detection_store_js_1 = require("./runtime-detection-store.js");
7
8
  class RuntimeDetectionService {
@@ -124,16 +125,5 @@ function changedRuntimes(previous, next) {
124
125
  });
125
126
  }
126
127
  function displayName(agentType) {
127
- const names = {
128
- pi: 'Pi',
129
- opencode: 'OpenCode',
130
- codex: 'Codex',
131
- claudecode: 'Claude Code',
132
- cursor: 'Cursor',
133
- gemini: 'Gemini',
134
- qoder: 'Qoder',
135
- iflow: 'iFlow',
136
- [desktop_js_1.LOCALCORE_ACP_AGENT_TYPE]: 'LocalCore ACP',
137
- };
138
- return names[agentType] || agentType;
128
+ return (0, index_js_1.resolveAgentRuntimeDefinition)(agentType)?.displayName || agentType;
139
129
  }
@@ -29,6 +29,7 @@ exports.DESKTOP_AGENT_TYPE_OPTIONS = [
29
29
  'gemini',
30
30
  'qoder',
31
31
  'iflow',
32
+ 'hermes',
32
33
  'localcore-acp',
33
34
  ];
34
35
  exports.DESKTOP_PLATFORM_TYPE_OPTIONS = [
@@ -56,7 +57,7 @@ exports.DESKTOP_PROVIDER_PRESET_OPTIONS = [
56
57
  'ollama',
57
58
  ];
58
59
  exports.DESKTOP_PROVIDER_THINKING_OPTIONS = ['', 'enabled', 'disabled'];
59
- exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['pi', 'opencode', 'codex', 'claudecode', 'acp', 'localcore-acp'];
60
+ exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['pi', 'opencode', 'codex', 'claudecode', 'hermes', 'acp', 'localcore-acp'];
60
61
  exports.LOCALCORE_ACP_AGENT_TYPE = 'localcore-acp';
61
62
  exports.SCHEDULER_PROTOCOL_INSTRUCTION = [
62
63
  '[Scheduler Tools]',
@@ -242,5 +243,6 @@ function isAcpAgentType(agentType) {
242
243
  || normalized === 'opencode'
243
244
  || normalized === 'codex'
244
245
  || normalized === 'claudecode'
246
+ || normalized === 'hermes'
245
247
  || normalized === exports.LOCALCORE_ACP_AGENT_TYPE;
246
248
  }