@kafca/agentdock 0.1.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.
Files changed (79) hide show
  1. package/README.md +70 -0
  2. package/bin/agentdock.mjs +275 -0
  3. package/build/icon.png +0 -0
  4. package/dist/renderer/assets/index-BaNpzC6d.js +482 -0
  5. package/dist/renderer/assets/index-CLWJyO0E.css +11 -0
  6. package/dist/renderer/favicon.svg +19 -0
  7. package/dist/renderer/index.html +14 -0
  8. package/dist/renderer/logo-options.svg +153 -0
  9. package/dist-electron/electron/knowledge-skill-script.test.js +125 -0
  10. package/dist-electron/electron/lac-cli.test.js +221 -0
  11. package/dist-electron/electron/local-core-refactor.test.js +1075 -0
  12. package/dist-electron/electron/main.js +163 -0
  13. package/dist-electron/electron/plugin-kernel.test.js +534 -0
  14. package/dist-electron/electron/preload.js +2 -0
  15. package/dist-electron/package.json +3 -0
  16. package/dist-electron/packages/contracts/src/index.js +18 -0
  17. package/dist-electron/packages/contracts/src/local-core.js +2 -0
  18. package/dist-electron/packages/core-sdk/src/index.js +406 -0
  19. package/dist-electron/packages/knowledge-api/src/ai-vector-provider.js +388 -0
  20. package/dist-electron/packages/knowledge-api/src/index.js +146 -0
  21. package/dist-electron/packages/knowledge-api/src/sqlite-store.js +467 -0
  22. package/dist-electron/packages/knowledge-api/src/thread-knowledge-store.js +21 -0
  23. package/dist-electron/packages/knowledge-api/test/ai-vector-provider.test.js +412 -0
  24. package/dist-electron/packages/plugin-sdk/src/index.js +2 -0
  25. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +369 -0
  26. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +110 -0
  27. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +171 -0
  28. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +635 -0
  29. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +190 -0
  30. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +244 -0
  31. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +52 -0
  32. package/dist-electron/services/local-ai-core/src/cli/lac.js +290 -0
  33. package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +976 -0
  34. package/dist-electron/services/local-ai-core/src/gateway/local-core-weixin-gateway.js +1143 -0
  35. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +291 -0
  36. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +67 -0
  37. package/dist-electron/services/local-ai-core/src/kernel/diagnostics.js +27 -0
  38. package/dist-electron/services/local-ai-core/src/kernel/event-bus.js +27 -0
  39. package/dist-electron/services/local-ai-core/src/kernel/lifecycle-manager.js +85 -0
  40. package/dist-electron/services/local-ai-core/src/kernel/plugin-registry.js +60 -0
  41. package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +114 -0
  42. package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +59 -0
  43. package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +56 -0
  44. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +7 -0
  45. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +7 -0
  46. package/dist-electron/services/local-ai-core/src/plugins/builtin/runtime-capabilities-plugin.js +62 -0
  47. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-cron-plugin.js +49 -0
  48. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-lark-plugin.js +38 -0
  49. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-weixin-plugin.js +38 -0
  50. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +230 -0
  51. package/dist-electron/services/local-ai-core/src/router/workspace-router-types.js +2 -0
  52. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +389 -0
  53. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +315 -0
  54. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +282 -0
  55. package/dist-electron/services/local-ai-core/src/runtime/server.js +465 -0
  56. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +38 -0
  57. package/dist-electron/services/local-ai-core/src/scheduler/adapters.js +2 -0
  58. package/dist-electron/services/local-ai-core/src/scheduler/cron-command-detector.js +70 -0
  59. package/dist-electron/services/local-ai-core/src/scheduler/cron.js +53 -0
  60. package/dist-electron/services/local-ai-core/src/scheduler/execution-policy.js +2 -0
  61. package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +66 -0
  62. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +77 -0
  63. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +46 -0
  64. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js +64 -0
  65. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +133 -0
  66. package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +66 -0
  67. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +78 -0
  68. package/dist-electron/services/local-ai-core/src/thread/workspace-thread-id.js +17 -0
  69. package/dist-electron/services/local-ai-core/src/thread/workspace-thread-mappers.js +43 -0
  70. package/dist-electron/shared/desktop.js +195 -0
  71. package/dist-electron/src/api/client.js +73 -0
  72. package/dist-electron/src/api/sessions.js +21 -0
  73. package/dist-electron/src/lib/session-utils.js +51 -0
  74. package/dist-electron/src/pages/Threads/thread-chat-model.js +246 -0
  75. package/dist-electron/src/pages/Threads/thread-chat-model.test.js +76 -0
  76. package/dist-electron/src/pages/Threads/thread-chat-permission.js +26 -0
  77. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +102 -0
  78. package/dist-electron/src/pages/Threads/thread-chat-task-state.js +65 -0
  79. package/package.json +146 -0
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinLarkChannelPlugin = createBuiltinLarkChannelPlugin;
4
+ const local_core_lark_gateway_js_1 = require("../../gateway/local-core-lark-gateway.js");
5
+ function createBuiltinLarkChannelPlugin(options) {
6
+ let runtime = null;
7
+ let unsubscribeBridgeEvents = null;
8
+ return {
9
+ manifest: {
10
+ id: 'builtin.channel-lark',
11
+ kind: 'channel',
12
+ version: '0.1.0',
13
+ provides: [
14
+ 'channel:lark',
15
+ ],
16
+ configSchema: {
17
+ fields: [
18
+ { key: 'appId', type: 'string', label: 'App ID' },
19
+ { key: 'appSecret', type: 'string', label: 'App Secret' },
20
+ ],
21
+ },
22
+ },
23
+ capabilities: {
24
+ channels: [
25
+ {
26
+ id: 'channel.lark',
27
+ platform: 'lark',
28
+ routeType: 'channel.chat',
29
+ displayName: 'LocalCore Lark',
30
+ },
31
+ ],
32
+ },
33
+ createRuntime(ctx) {
34
+ if (!runtime) {
35
+ runtime = {
36
+ channel: new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
37
+ store: options.store,
38
+ readConfig: options.readConfig,
39
+ getWorkspaceRouter: options.getWorkspaceRouter,
40
+ eventBus: ctx.bus,
41
+ log: options.log,
42
+ }),
43
+ };
44
+ unsubscribeBridgeEvents = ctx.bus.on('platform.bridge.updated', (event) => {
45
+ void runtime?.channel.onBridgeEvent?.(event);
46
+ });
47
+ }
48
+ return runtime;
49
+ },
50
+ async start() {
51
+ await runtime?.channel.refreshBindings?.();
52
+ },
53
+ async stop() {
54
+ unsubscribeBridgeEvents?.();
55
+ unsubscribeBridgeEvents = null;
56
+ runtime?.channel.close?.();
57
+ },
58
+ };
59
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinWeixinChannelPlugin = createBuiltinWeixinChannelPlugin;
4
+ const local_core_weixin_gateway_js_1 = require("../../gateway/local-core-weixin-gateway.js");
5
+ function createBuiltinWeixinChannelPlugin(options) {
6
+ let runtime = null;
7
+ let unsubscribeBridgeEvents = null;
8
+ return {
9
+ manifest: {
10
+ id: 'builtin.channel-weixin',
11
+ kind: 'channel',
12
+ version: '0.1.0',
13
+ provides: [
14
+ 'channel:weixin',
15
+ ],
16
+ configSchema: {
17
+ fields: [],
18
+ },
19
+ },
20
+ capabilities: {
21
+ channels: [
22
+ {
23
+ id: 'channel.weixin',
24
+ platform: 'weixin',
25
+ routeType: 'channel.chat',
26
+ displayName: 'LocalCore WeChat',
27
+ },
28
+ ],
29
+ },
30
+ createRuntime(ctx) {
31
+ if (!runtime) {
32
+ runtime = {
33
+ channel: new local_core_weixin_gateway_js_1.LocalCoreWeixinGateway({
34
+ store: options.store,
35
+ readConfig: options.readConfig,
36
+ getWorkspaceRouter: options.getWorkspaceRouter,
37
+ eventBus: ctx.bus,
38
+ log: options.log,
39
+ }),
40
+ };
41
+ unsubscribeBridgeEvents = ctx.bus.on('platform.bridge.updated', (event) => {
42
+ void runtime?.channel.onBridgeEvent?.(event);
43
+ });
44
+ }
45
+ return runtime;
46
+ },
47
+ async start() {
48
+ await runtime?.channel.refreshBindings?.();
49
+ },
50
+ async stop() {
51
+ unsubscribeBridgeEvents?.();
52
+ unsubscribeBridgeEvents = null;
53
+ runtime?.channel.close?.();
54
+ },
55
+ };
56
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinAiVectorKnowledgePlugin = createBuiltinAiVectorKnowledgePlugin;
4
+ const index_js_1 = require("../../../../../packages/knowledge-api/src/index.js");
5
+ function createBuiltinAiVectorKnowledgePlugin(options) {
6
+ return (0, index_js_1.createAiVectorKnowledgePlugin)(options);
7
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinNoopKnowledgePlugin = createBuiltinNoopKnowledgePlugin;
4
+ const index_js_1 = require("../../../../../packages/knowledge-api/src/index.js");
5
+ function createBuiltinNoopKnowledgePlugin() {
6
+ return (0, index_js_1.createNoopKnowledgePlugin)();
7
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runtimeCapabilitiesPlugin = void 0;
4
+ const desktop_js_1 = require("../../../../../shared/desktop.js");
5
+ exports.runtimeCapabilitiesPlugin = {
6
+ manifest: {
7
+ id: 'builtin.runtime-capabilities',
8
+ kind: 'composite',
9
+ version: '0.1.0',
10
+ provides: [
11
+ 'agent:opencode',
12
+ 'agent:codex',
13
+ 'agent:claudecode',
14
+ 'agent:cursor',
15
+ 'agent:gemini',
16
+ 'agent:qoder',
17
+ 'agent:iflow',
18
+ `agent:${desktop_js_1.LOCALCORE_ACP_AGENT_TYPE}`,
19
+ 'channel:localcore-lark',
20
+ `channel:${desktop_js_1.LOCALCORE_ACP_AGENT_TYPE}`,
21
+ 'knowledge:ai-vector',
22
+ 'scheduler:cron',
23
+ ],
24
+ },
25
+ capabilities: {
26
+ agents: desktop_js_1.DESKTOP_AGENT_TYPE_OPTIONS.map((agentType) => ({
27
+ id: `agent.${agentType}`,
28
+ agentType,
29
+ displayName: agentType,
30
+ })),
31
+ channels: [
32
+ {
33
+ id: 'channel.localcore-lark',
34
+ platform: 'lark',
35
+ routeType: 'lark_chat',
36
+ displayName: 'LocalCore Lark',
37
+ },
38
+ {
39
+ id: `channel.${desktop_js_1.LOCALCORE_ACP_AGENT_TYPE}`,
40
+ platform: desktop_js_1.LOCALCORE_ACP_AGENT_TYPE,
41
+ displayName: 'LocalCore ACP',
42
+ },
43
+ ],
44
+ knowledge: [
45
+ {
46
+ id: 'knowledge.ai-vector',
47
+ sourceType: 'ai-vector',
48
+ enabled: true,
49
+ displayName: 'AI Vector Knowledge',
50
+ },
51
+ ],
52
+ schedulers: [
53
+ {
54
+ id: 'scheduler.cron',
55
+ triggerTypes: ['cron', 'once'],
56
+ deliveryPlatforms: ['lark'],
57
+ enabled: true,
58
+ displayName: 'Cron Scheduler',
59
+ },
60
+ ],
61
+ },
62
+ };
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinCronSchedulerPlugin = createBuiltinCronSchedulerPlugin;
4
+ const cron_js_1 = require("../../scheduler/cron.js");
5
+ class CronSchedulerTriggerRuntime {
6
+ triggerTypes = ['cron', 'once'];
7
+ supports(job) {
8
+ return job.triggerType === 'cron' || job.triggerType === 'once';
9
+ }
10
+ isDue(job, now) {
11
+ if (job.triggerType === 'once') {
12
+ return Boolean(job.runAt && Date.parse(job.runAt) <= now.getTime() && !job.lastRunAt);
13
+ }
14
+ if (!job.cronExpr) {
15
+ return false;
16
+ }
17
+ if (!(0, cron_js_1.cronMatchesDate)(job.cronExpr, now)) {
18
+ return false;
19
+ }
20
+ const minuteStart = (0, cron_js_1.floorToMinute)(now).toISOString();
21
+ return !job.lastRunAt || job.lastRunAt < minuteStart;
22
+ }
23
+ }
24
+ function createBuiltinCronSchedulerPlugin() {
25
+ return {
26
+ manifest: {
27
+ id: 'builtin.scheduler-cron',
28
+ kind: 'scheduler',
29
+ version: '0.1.0',
30
+ provides: ['scheduler.trigger.cron'],
31
+ },
32
+ capabilities: {
33
+ schedulers: [
34
+ {
35
+ id: 'scheduler.trigger.cron',
36
+ triggerTypes: ['cron', 'once'],
37
+ deliveryTargets: [],
38
+ enabled: true,
39
+ displayName: 'Cron Trigger',
40
+ },
41
+ ],
42
+ },
43
+ createRuntime() {
44
+ return {
45
+ triggers: [new CronSchedulerTriggerRuntime()],
46
+ };
47
+ },
48
+ };
49
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinLarkSchedulerPlugin = createBuiltinLarkSchedulerPlugin;
4
+ const lark_schedule_adapter_js_1 = require("../../scheduler/lark-schedule-adapter.js");
5
+ function createBuiltinLarkSchedulerPlugin(options) {
6
+ return {
7
+ manifest: {
8
+ id: 'builtin.scheduler-lark',
9
+ kind: 'scheduler',
10
+ version: '0.1.0',
11
+ dependsOn: ['builtin.channel-lark'],
12
+ provides: ['scheduler.delivery.lark'],
13
+ },
14
+ capabilities: {
15
+ schedulers: [
16
+ {
17
+ id: 'scheduler.delivery.lark',
18
+ triggerTypes: [],
19
+ deliveryTargets: ['lark'],
20
+ enabled: true,
21
+ displayName: 'Lark Scheduled Delivery',
22
+ },
23
+ ],
24
+ },
25
+ createRuntime() {
26
+ return {
27
+ executors: [
28
+ new lark_schedule_adapter_js_1.LarkScheduleAdapter({
29
+ store: options.store,
30
+ getWorkspaceRouter: options.getWorkspaceRouter,
31
+ getChannelRuntime: options.getChannelRuntime,
32
+ log: options.log,
33
+ }),
34
+ ],
35
+ };
36
+ },
37
+ };
38
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinWeixinSchedulerPlugin = createBuiltinWeixinSchedulerPlugin;
4
+ const weixin_schedule_adapter_js_1 = require("../../scheduler/weixin-schedule-adapter.js");
5
+ function createBuiltinWeixinSchedulerPlugin(options) {
6
+ return {
7
+ manifest: {
8
+ id: 'builtin.scheduler-weixin',
9
+ kind: 'scheduler',
10
+ version: '0.1.0',
11
+ dependsOn: ['builtin.channel-weixin'],
12
+ provides: ['scheduler.delivery.weixin'],
13
+ },
14
+ capabilities: {
15
+ schedulers: [
16
+ {
17
+ id: 'scheduler.delivery.weixin',
18
+ triggerTypes: [],
19
+ deliveryTargets: ['weixin'],
20
+ enabled: true,
21
+ displayName: 'WeChat Scheduled Delivery',
22
+ },
23
+ ],
24
+ },
25
+ createRuntime() {
26
+ return {
27
+ executors: [
28
+ new weixin_schedule_adapter_js_1.WeixinScheduleAdapter({
29
+ store: options.store,
30
+ getWorkspaceRouter: options.getWorkspaceRouter,
31
+ getChannelRuntime: options.getChannelRuntime,
32
+ log: options.log,
33
+ }),
34
+ ],
35
+ };
36
+ },
37
+ };
38
+ }
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizePlatformTypes = normalizePlatformTypes;
4
+ exports.isLocalCoreNativeAcpProject = isLocalCoreNativeAcpProject;
5
+ exports.toLocalCoreProjectConfig = toLocalCoreProjectConfig;
6
+ const node_module_1 = require("node:module");
7
+ const node_path_1 = require("node:path");
8
+ const desktop_js_1 = require("../../../../shared/desktop.js");
9
+ function normalizePlatformTypes(project) {
10
+ return Array.isArray(project?.platforms)
11
+ ? project.platforms.map((platform) => (0, desktop_js_1.normalizeDesktopPlatformType)(platform?.type)).filter(Boolean)
12
+ : [];
13
+ }
14
+ function isLocalCoreNativeAcpProject(project) {
15
+ const agentType = String(project?.agent?.type || '').trim().toLowerCase();
16
+ return !agentType
17
+ || agentType === 'acp'
18
+ || agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE;
19
+ }
20
+ function resolveOpencodeModel(project, providers) {
21
+ const agentType = String(project.agent?.type || '').trim().toLowerCase();
22
+ const rawModel = String(project.agent?.options?.model || '').trim();
23
+ const normalizedModel = (0, desktop_js_1.normalizeDesktopAgentModel)(agentType, rawModel);
24
+ if (agentType !== 'opencode') {
25
+ return normalizedModel;
26
+ }
27
+ const configuredProviderModel = getFirstProviderModelRef(providers);
28
+ if (configuredProviderModel &&
29
+ (!rawModel || normalizedModel === desktop_js_1.DEFAULT_DESKTOP_OPENCODE_MODEL)) {
30
+ return configuredProviderModel;
31
+ }
32
+ return normalizedModel;
33
+ }
34
+ function getFirstProviderModelRef(providers) {
35
+ for (const provider of providers) {
36
+ const providerId = normalizeOpencodeProviderId(provider.name);
37
+ const modelId = getProviderDefaultModelId(provider);
38
+ if (providerId && modelId) {
39
+ return `${providerId}/${modelId}`;
40
+ }
41
+ }
42
+ return '';
43
+ }
44
+ function getProviderDefaultModelId(provider) {
45
+ const directModel = String(provider.model || '').trim();
46
+ if (directModel) {
47
+ return directModel;
48
+ }
49
+ const firstModel = Array.isArray(provider.models)
50
+ ? provider.models.find((entry) => String(entry?.model || '').trim())
51
+ : null;
52
+ return String(firstModel?.model || '').trim();
53
+ }
54
+ function buildOpencodeInlineConfig(model, providers) {
55
+ const config = {
56
+ $schema: 'https://opencode.ai/config.json',
57
+ };
58
+ const env = {};
59
+ if (model) {
60
+ config.model = model;
61
+ }
62
+ const providerConfig = {};
63
+ for (const provider of providers) {
64
+ const providerId = normalizeOpencodeProviderId(provider.name);
65
+ if (!providerId) {
66
+ continue;
67
+ }
68
+ const entry = {
69
+ name: String(provider.name || providerId),
70
+ };
71
+ if (shouldUseOpenAiCompatibleProvider(providerId)) {
72
+ entry.npm = '@ai-sdk/openai-compatible';
73
+ }
74
+ const options = {};
75
+ const baseUrl = String(provider.base_url || '').trim();
76
+ if (baseUrl) {
77
+ options.baseURL = baseUrl;
78
+ }
79
+ const apiKey = String(provider.api_key || '').trim();
80
+ if (apiKey) {
81
+ const envName = opencodeProviderApiKeyEnvName(providerId);
82
+ env[envName] = apiKey;
83
+ options.apiKey = `{env:${envName}}`;
84
+ }
85
+ if (Object.keys(options).length > 0) {
86
+ entry.options = options;
87
+ }
88
+ const models = buildOpencodeProviderModels(provider);
89
+ if (Object.keys(models).length > 0) {
90
+ entry.models = models;
91
+ }
92
+ providerConfig[providerId] = entry;
93
+ }
94
+ if (Object.keys(providerConfig).length > 0) {
95
+ config.provider = providerConfig;
96
+ }
97
+ return {
98
+ config,
99
+ env,
100
+ };
101
+ }
102
+ function buildOpencodeProviderModels(provider) {
103
+ const models = {};
104
+ const addModel = (model, alias) => {
105
+ const modelId = String(model || '').trim();
106
+ if (!modelId || models[modelId]) {
107
+ return;
108
+ }
109
+ models[modelId] = {
110
+ name: String(alias || modelId).trim() || modelId,
111
+ };
112
+ };
113
+ addModel(provider.model);
114
+ for (const model of Array.isArray(provider.models) ? provider.models : []) {
115
+ addModel(model?.model, model?.alias);
116
+ }
117
+ return models;
118
+ }
119
+ function collectProviderEnv(providers) {
120
+ const env = {};
121
+ for (const provider of providers) {
122
+ if (!provider.env || typeof provider.env !== 'object') {
123
+ continue;
124
+ }
125
+ for (const [key, value] of Object.entries(provider.env)) {
126
+ const envKey = key.trim();
127
+ if (envKey) {
128
+ env[envKey] = String(value ?? '');
129
+ }
130
+ }
131
+ }
132
+ return env;
133
+ }
134
+ function normalizeOpencodeProviderId(value) {
135
+ return String(value || '')
136
+ .trim()
137
+ .toLowerCase()
138
+ .replace(/[^a-z0-9._-]+/g, '-')
139
+ .replace(/^-+|-+$/g, '');
140
+ }
141
+ function opencodeProviderApiKeyEnvName(providerId) {
142
+ const suffix = providerId.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
143
+ return `AI_WORKSTATION_OPENCODE_${suffix || 'PROVIDER'}_API_KEY`;
144
+ }
145
+ function shouldUseOpenAiCompatibleProvider(providerId) {
146
+ const builtInNonCompatibleProviders = new Set([
147
+ 'anthropic',
148
+ 'google',
149
+ 'gemini',
150
+ ]);
151
+ return !builtInNonCompatibleProviders.has(providerId);
152
+ }
153
+ function resolveBundledClaudeCodeCommand() {
154
+ const require = (0, node_module_1.createRequire)(__filename);
155
+ const packageJsonPath = require.resolve(`${desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE}/package.json`);
156
+ const packageJson = require(packageJsonPath);
157
+ const binField = packageJson.bin;
158
+ const relativeBinPath = typeof binField === 'string'
159
+ ? binField
160
+ : binField?.['claude-agent-acp'];
161
+ if (!relativeBinPath) {
162
+ throw new Error(`Bundled package "${desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE}" does not declare the claude-agent-acp bin.`);
163
+ }
164
+ return {
165
+ command: process.execPath,
166
+ args: [(0, node_path_1.resolve)((0, node_path_1.dirname)(packageJsonPath), relativeBinPath)],
167
+ };
168
+ }
169
+ function toLocalCoreProjectConfig(configState, project) {
170
+ const rawWorkDir = String(project.agent?.options?.work_dir || '.').trim() || '.';
171
+ const configDir = (0, node_path_1.dirname)(configState.path);
172
+ const workDir = (0, node_path_1.isAbsolute)(rawWorkDir) ? rawWorkDir : (0, node_path_1.resolve)(configDir, rawWorkDir);
173
+ const rawArgs = project.agent?.options?.args;
174
+ const args = Array.isArray(rawArgs)
175
+ ? rawArgs.map((value) => String(value || '')).filter(Boolean)
176
+ : [];
177
+ const rawEnv = project.agent?.options?.env;
178
+ const env = rawEnv && typeof rawEnv === 'object'
179
+ ? Object.fromEntries(Object.entries(rawEnv)
180
+ .filter(([key]) => key)
181
+ .map(([key, value]) => [key, String(value ?? '')]))
182
+ : {};
183
+ const agentType = String(project.agent?.type || '').trim().toLowerCase();
184
+ const providers = Array.isArray(project.agent?.providers) ? project.agent.providers : [];
185
+ const model = resolveOpencodeModel(project, providers);
186
+ const providerEnv = collectProviderEnv(providers);
187
+ const opencodeInlineConfig = agentType === 'opencode'
188
+ ? buildOpencodeInlineConfig(model, providers)
189
+ : null;
190
+ const inferredOpencodeEnv = agentType === 'opencode'
191
+ ? {
192
+ ...(opencodeInlineConfig?.env || {}),
193
+ OPENCODE_CONFIG_CONTENT: JSON.stringify(opencodeInlineConfig?.config || { $schema: 'https://opencode.ai/config.json' }),
194
+ }
195
+ : {};
196
+ const inferredClaudeCodeEnv = agentType === 'claudecode' && model
197
+ ? {
198
+ ANTHROPIC_MODEL: model,
199
+ }
200
+ : {};
201
+ const bundledClaudeCode = agentType === 'claudecode'
202
+ ? resolveBundledClaudeCodeCommand()
203
+ : null;
204
+ const inferredCommand = agentType === 'opencode'
205
+ ? 'opencode'
206
+ : bundledClaudeCode?.command || '';
207
+ const command = String(project.agent?.options?.command || inferredCommand).trim();
208
+ if (!command) {
209
+ throw new Error(`Workspace "${project.name}" requires [projects.agent.options].command for Local AI Core ACP execution.`);
210
+ }
211
+ const defaultArgs = agentType === 'opencode'
212
+ ? ['acp']
213
+ : agentType === 'claudecode'
214
+ ? [...(bundledClaudeCode?.args || [])]
215
+ : [];
216
+ return {
217
+ workspaceId: project.name,
218
+ agentType,
219
+ workDir,
220
+ command,
221
+ args: args.length > 0 ? args : defaultArgs,
222
+ env: {
223
+ ...providerEnv,
224
+ ...inferredOpencodeEnv,
225
+ ...inferredClaudeCodeEnv,
226
+ ...env,
227
+ },
228
+ model,
229
+ };
230
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });