@kafca/agentdock 0.1.24 → 0.1.26
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.
- package/README.md +2 -0
- package/dist/renderer/assets/{Badge-CXcUMqb-.js → Badge-qZHTUGI3.js} +1 -1
- package/dist/renderer/assets/{Chat-BRxdPzi-.js → Chat-W35BzaZk.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-sWGBIfIb.js → ChatMarkdown-DxKT_YGp.js} +1 -1
- package/dist/renderer/assets/{Config-DqxuxIGg.js → Config-COTX6LDN.js} +1 -1
- package/dist/renderer/assets/{CronList-OgHxbti5.js → CronList-kxlfu9Iq.js} +1 -1
- package/dist/renderer/assets/{Dashboard-DmklXiH1.js → Dashboard-Y4PGxzuV.js} +2 -2
- package/dist/renderer/assets/{EmptyState-BvDmi8dq.js → EmptyState-Cjq33EOF.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Bj59Hdpo.js → KnowledgeDetail-CztNt7i8.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-CigQ-nSo.js → KnowledgeHome-BAOyy3I9.js} +1 -1
- package/dist/renderer/assets/{Logs-Bfc7gBpY.js → Logs-PRZ1IIEi.js} +1 -1
- package/dist/renderer/assets/{Modal-CfmiFknz.js → Modal-B1rgqkBM.js} +1 -1
- package/dist/renderer/assets/{Page-BxtLEw_b.js → Page-CjzAhgaU.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-CcUphxGm.js → ProjectDetail-XGh_5XxQ.js} +1 -1
- package/dist/renderer/assets/{ProjectList-CVkvDIfy.js → ProjectList-BkPTpQRZ.js} +1 -1
- package/dist/renderer/assets/{Select-DgQMZ0MD.js → Select-BZd1QJVw.js} +1 -1
- package/dist/renderer/assets/{SessionChat-CRmGKfBx.js → SessionChat-C3sOTWGT.js} +1 -1
- package/dist/renderer/assets/{SessionList-D0E8XbYw.js → SessionList-B5WK1big.js} +1 -1
- package/dist/renderer/assets/ThreadChat-DWiBLHC7.js +23 -0
- package/dist/renderer/assets/{Workspace-Q4g4rlRT.js → Workspace-CQ64VK-o.js} +1 -1
- package/dist/renderer/assets/{arrow-left-BySN_zhF.js → arrow-left-FLdaWHZ8.js} +1 -1
- package/dist/renderer/assets/{book-open-BGlrnrTc.js → book-open-DaSioPS9.js} +1 -1
- package/dist/renderer/assets/{check-BiJogEa5.js → check-BiSmsuGR.js} +1 -1
- package/dist/renderer/assets/{chevron-down-D2fHRJv6.js → chevron-down-pZ2KjmDR.js} +1 -1
- package/dist/renderer/assets/{circle-CIcjixmI.js → circle-296S3nw9.js} +1 -1
- package/dist/renderer/assets/{desktop-DyA_NYew.js → desktop-88jgnOZV.js} +1 -1
- package/dist/renderer/assets/{desktop-DAXY9Bxv.js → desktop-BkMW-h5p.js} +2 -2
- package/dist/renderer/assets/{funnel-BUzwb-id.js → funnel-Dvz31PLy.js} +1 -1
- package/dist/renderer/assets/{heart-DZEQ1z_V.js → heart-D9mxSZVO.js} +1 -1
- package/dist/renderer/assets/{index-DgsIo4vJ.js → index-CZA4lqvM.js} +1 -1
- package/dist/renderer/assets/{index-CB_KyLOr.js → index-dOdOWAa2.js} +3 -3
- package/dist/renderer/assets/{pencil-DGL4agcl.js → pencil-B2fRbaAo.js} +1 -1
- package/dist/renderer/assets/{play-DzasCLM4.js → play-CWPRHypD.js} +1 -1
- package/dist/renderer/assets/{plug-dubNMe_m.js → plug-B7IBVwSo.js} +1 -1
- package/dist/renderer/assets/{plus-DN4kML4k.js → plus-Cn3Awirs.js} +1 -1
- package/dist/renderer/assets/projects-CmCopAi6.js +1 -0
- package/dist/renderer/assets/{save-CNIc9tjl.js → save-MVjXRqom.js} +1 -1
- package/dist/renderer/assets/{search-C0EGbF3I.js → search-Bu5c7wTX.js} +1 -1
- package/dist/renderer/assets/{server-BMxQ4zmc.js → server-aDvfqBg_.js} +1 -1
- package/dist/renderer/assets/{session-utils-Bf5O-iMi.js → session-utils-DjDpjT9r.js} +1 -1
- package/dist/renderer/assets/{sessions-BMSs6rEI.js → sessions-D7dV8h0H.js} +1 -1
- package/dist/renderer/assets/{shield-check-i3Tf1TUz.js → shield-check-DJdEhc_e.js} +1 -1
- package/dist/renderer/assets/{trash-2-SKrcp18f.js → trash-2-BF3ejnXL.js} +1 -1
- package/dist/renderer/assets/{user-cNUZddjZ.js → user-BwuWCrin.js} +1 -1
- package/dist/renderer/assets/{wifi-off-Dyb84ANR.js → wifi-off-BahJZfDs.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/agent-runtime-detector.test.js +64 -0
- package/dist-electron/electron/architecture-docs.test.js +56 -0
- package/dist-electron/electron/channel-content.test.js +8 -0
- package/dist-electron/electron/lac-cli.test.js +248 -0
- package/dist-electron/electron/local-core-refactor.test.js +795 -20
- package/dist-electron/electron/plugin-kernel.test.js +108 -0
- package/dist-electron/electron/renderer-packaging.test.js +77 -0
- package/dist-electron/electron/workspace-task-store.test.js +57 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +67 -6
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js +76 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +201 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +29 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +30 -18
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +112 -210
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +60 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +44 -27
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +104 -12
- package/dist-electron/services/local-ai-core/src/channel/shared/file-utils.js +13 -1
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +8 -1
- package/dist-electron/services/local-ai-core/src/cli/lac.js +3 -1
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +1 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +221 -10
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +39 -9
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +439 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +208 -303
- package/dist-electron/shared/desktop.js +7 -3
- package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +187 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +1 -0
- package/dist-electron/src/pages/Threads/thread-chat-page-state.js +96 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.js +18 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +277 -0
- package/package.json +4 -2
- package/dist/renderer/assets/ThreadChat-DUgqZSBB.js +0 -23
- package/dist/renderer/assets/projects-migPtfRe.js +0 -1
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLarkTurnState = createLarkTurnState;
|
|
4
4
|
exports.foldToolResultForLark = foldToolResultForLark;
|
|
5
|
+
exports.summarizeToolCallForLark = summarizeToolCallForLark;
|
|
6
|
+
exports.isPendingToolProgressForLark = isPendingToolProgressForLark;
|
|
5
7
|
exports.consumeLarkBridgeEvent = consumeLarkBridgeEvent;
|
|
6
8
|
exports.renderLarkBridgeEventMessage = renderLarkBridgeEventMessage;
|
|
9
|
+
exports.renderLarkBridgeEventMessages = renderLarkBridgeEventMessages;
|
|
7
10
|
exports.getLarkRenderedMessageId = getLarkRenderedMessageId;
|
|
8
11
|
exports.setLarkRenderedMessageId = setLarkRenderedMessageId;
|
|
9
12
|
function createLarkTurnState(sessionKey, sourceMessageId) {
|
|
@@ -16,6 +19,8 @@ function createLarkTurnState(sessionKey, sourceMessageId) {
|
|
|
16
19
|
finalText: '',
|
|
17
20
|
progressMessageIds: {},
|
|
18
21
|
thinkingSteps: [],
|
|
22
|
+
pendingThoughtKey: undefined,
|
|
23
|
+
pendingThoughtText: undefined,
|
|
19
24
|
toolCalls: [],
|
|
20
25
|
statusLines: [],
|
|
21
26
|
buttonRows: [],
|
|
@@ -33,6 +38,21 @@ function foldToolResultForLark(content) {
|
|
|
33
38
|
return normalized;
|
|
34
39
|
return parts.slice(0, 2).join(' - ');
|
|
35
40
|
}
|
|
41
|
+
function summarizeToolCallForLark(event, content) {
|
|
42
|
+
const toolCall = event.toolCall;
|
|
43
|
+
if (toolCall) {
|
|
44
|
+
const name = String(toolCall.name || '').trim() || summarizeToolContentForLark(content);
|
|
45
|
+
const input = formatToolInputForLark(toolCall.input);
|
|
46
|
+
return [name.startsWith('🔧 ') ? name : `🔧 ${name}`, input ? `参数:${input}` : '']
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.join('\n\n');
|
|
49
|
+
}
|
|
50
|
+
return summarizeToolContentForLark(content);
|
|
51
|
+
}
|
|
52
|
+
function isPendingToolProgressForLark(content) {
|
|
53
|
+
const normalized = foldToolResultForLark(content).toLowerCase();
|
|
54
|
+
return normalized.startsWith('🔧 ') && normalized.includes(' - pending');
|
|
55
|
+
}
|
|
36
56
|
function consumeLarkBridgeEvent(turn, event, options) {
|
|
37
57
|
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
38
58
|
if (event.type === 'typing_start') {
|
|
@@ -45,6 +65,8 @@ function consumeLarkBridgeEvent(turn, event, options) {
|
|
|
45
65
|
turn.previewText = '';
|
|
46
66
|
turn.finalText = '';
|
|
47
67
|
turn.thinkingSteps = [];
|
|
68
|
+
turn.pendingThoughtKey = undefined;
|
|
69
|
+
turn.pendingThoughtText = undefined;
|
|
48
70
|
turn.toolCalls = [];
|
|
49
71
|
turn.buttonRows = [];
|
|
50
72
|
turn.statusLines = [];
|
|
@@ -56,6 +78,12 @@ function consumeLarkBridgeEvent(turn, event, options) {
|
|
|
56
78
|
return;
|
|
57
79
|
}
|
|
58
80
|
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
81
|
+
if (content.startsWith('💭 ')) {
|
|
82
|
+
turn.pendingThoughtKey = event.previewHandle || 'thinking-preview';
|
|
83
|
+
turn.pendingThoughtText = content;
|
|
84
|
+
pushUniqueLarkTurnLine(turn.thinkingSteps, content.slice(3).trim());
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
59
87
|
turn.previewText = content;
|
|
60
88
|
return;
|
|
61
89
|
}
|
|
@@ -77,6 +105,8 @@ function consumeLarkBridgeEvent(turn, event, options) {
|
|
|
77
105
|
return;
|
|
78
106
|
}
|
|
79
107
|
if (content.startsWith('💭 ')) {
|
|
108
|
+
turn.pendingThoughtKey = progressKey('thinking', event);
|
|
109
|
+
turn.pendingThoughtText = content;
|
|
80
110
|
pushUniqueLarkTurnLine(turn.thinkingSteps, content.slice(3).trim());
|
|
81
111
|
return;
|
|
82
112
|
}
|
|
@@ -95,10 +125,13 @@ function renderLarkBridgeEventMessage(turn, event) {
|
|
|
95
125
|
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
96
126
|
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
97
127
|
if (content.startsWith('💭 ')) {
|
|
98
|
-
return
|
|
128
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
99
129
|
}
|
|
100
130
|
if (content.startsWith('🔧 ')) {
|
|
101
|
-
|
|
131
|
+
if (isPendingToolProgressForLark(content)) {
|
|
132
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
133
|
+
}
|
|
134
|
+
return renderToolMessage(progressKey('tool', event), summarizeToolCallForLark(event, content));
|
|
102
135
|
}
|
|
103
136
|
return {
|
|
104
137
|
key: 'final',
|
|
@@ -113,10 +146,13 @@ function renderLarkBridgeEventMessage(turn, event) {
|
|
|
113
146
|
}
|
|
114
147
|
if (event.type === 'reply') {
|
|
115
148
|
if (content.startsWith('💭 ')) {
|
|
116
|
-
return
|
|
149
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
117
150
|
}
|
|
118
151
|
if (content.startsWith('🔧 ')) {
|
|
119
|
-
|
|
152
|
+
if (isPendingToolProgressForLark(content)) {
|
|
153
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
154
|
+
}
|
|
155
|
+
return renderToolMessage(progressKey('tool', event), summarizeToolCallForLark(event, content));
|
|
120
156
|
}
|
|
121
157
|
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
122
158
|
return renderProgressMessage(progressKey('status', event), content);
|
|
@@ -139,23 +175,35 @@ function renderLarkBridgeEventMessage(turn, event) {
|
|
|
139
175
|
isFinal: false,
|
|
140
176
|
};
|
|
141
177
|
}
|
|
178
|
+
function renderLarkBridgeEventMessages(turn, event) {
|
|
179
|
+
const rendered = renderLarkBridgeEventMessage(turn, event);
|
|
180
|
+
if (isThoughtBridgeEvent(event)) {
|
|
181
|
+
return [rendered];
|
|
182
|
+
}
|
|
183
|
+
const pendingThought = takePendingLarkThoughtRender(turn);
|
|
184
|
+
return pendingThought ? [pendingThought, rendered] : [rendered];
|
|
185
|
+
}
|
|
186
|
+
function takePendingLarkThoughtRender(turn) {
|
|
187
|
+
const text = String(turn.pendingThoughtText || '').trim();
|
|
188
|
+
if (!text) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const rendered = renderProgressMessage(turn.pendingThoughtKey || 'thinking-preview', text);
|
|
192
|
+
turn.pendingThoughtKey = undefined;
|
|
193
|
+
turn.pendingThoughtText = undefined;
|
|
194
|
+
return rendered;
|
|
195
|
+
}
|
|
142
196
|
function getLarkRenderedMessageId(turn, rendered) {
|
|
143
197
|
if (rendered.isFinal) {
|
|
144
|
-
|
|
145
|
-
return turn.replyMessageId;
|
|
146
|
-
}
|
|
147
|
-
return turn.finalMessageId || turn.messageId;
|
|
198
|
+
return turn.finalMessageId || turn.messageId || turn.replyMessageId;
|
|
148
199
|
}
|
|
149
200
|
return turn.progressMessageIds[rendered.key];
|
|
150
201
|
}
|
|
151
202
|
function setLarkRenderedMessageId(turn, rendered, messageId) {
|
|
152
203
|
if (rendered.isFinal) {
|
|
153
|
-
if (rendered.finalSource === 'reply') {
|
|
154
|
-
turn.replyMessageId = messageId;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
204
|
turn.finalMessageId = messageId;
|
|
158
205
|
turn.messageId = messageId;
|
|
206
|
+
turn.replyMessageId = messageId;
|
|
159
207
|
return;
|
|
160
208
|
}
|
|
161
209
|
turn.progressMessageIds[rendered.key] = messageId;
|
|
@@ -168,6 +216,12 @@ function renderProgressMessage(key, text) {
|
|
|
168
216
|
isFinal: false,
|
|
169
217
|
};
|
|
170
218
|
}
|
|
219
|
+
function renderToolMessage(key, text) {
|
|
220
|
+
return {
|
|
221
|
+
...renderProgressMessage(key, text),
|
|
222
|
+
updatePolicy: 'create-only',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
171
225
|
function progressKey(prefix, event) {
|
|
172
226
|
const stableId = String(event.messageId || event.previewHandle || '').trim();
|
|
173
227
|
if (stableId) {
|
|
@@ -176,6 +230,44 @@ function progressKey(prefix, event) {
|
|
|
176
230
|
const content = String(event.content || '').trim().replace(/\s+/g, ' ');
|
|
177
231
|
return `${prefix}:${content.slice(0, 120)}`;
|
|
178
232
|
}
|
|
233
|
+
function isThoughtBridgeEvent(event) {
|
|
234
|
+
if (event.type !== 'preview_start' && event.type !== 'update_message' && event.type !== 'reply') {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
return String(event.content || '').trim().startsWith('💭 ');
|
|
238
|
+
}
|
|
239
|
+
function summarizeToolContentForLark(content) {
|
|
240
|
+
const normalized = String(content || '').trim();
|
|
241
|
+
if (!normalized.startsWith('🔧 ')) {
|
|
242
|
+
return normalized;
|
|
243
|
+
}
|
|
244
|
+
const withoutOutput = normalized.split(' - ')[0]?.trim() || normalized;
|
|
245
|
+
return withoutOutput
|
|
246
|
+
.replace(/\s+-\s*(running|pending|completed|failed|error|cancelled|canceled)\s*$/i, '')
|
|
247
|
+
.replace(/:\s*(running|pending|completed|failed|error|cancelled|canceled)\s*$/i, '')
|
|
248
|
+
.trim();
|
|
249
|
+
}
|
|
250
|
+
function formatToolInputForLark(input) {
|
|
251
|
+
if (input == null) {
|
|
252
|
+
return '';
|
|
253
|
+
}
|
|
254
|
+
if (typeof input === 'string') {
|
|
255
|
+
return inlineCode(input);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
return inlineCode(JSON.stringify(input));
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return inlineCode(String(input));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function inlineCode(value) {
|
|
265
|
+
const normalized = value.trim();
|
|
266
|
+
if (!normalized) {
|
|
267
|
+
return '';
|
|
268
|
+
}
|
|
269
|
+
return `\`${normalized.replace(/`/g, '\\`')}\``;
|
|
270
|
+
}
|
|
179
271
|
function pushUniqueLarkTurnLine(target, value) {
|
|
180
272
|
const normalized = value.trim();
|
|
181
273
|
if (!normalized) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.prepareChannelFile = prepareChannelFile;
|
|
4
|
+
exports.resolveChannelFilePath = resolveChannelFilePath;
|
|
4
5
|
exports.sanitizeChannelFileName = sanitizeChannelFileName;
|
|
5
6
|
const promises_1 = require("node:fs/promises");
|
|
6
7
|
const node_path_1 = require("node:path");
|
|
7
8
|
async function prepareChannelFile(input) {
|
|
8
|
-
const filePath =
|
|
9
|
+
const filePath = resolveChannelFilePath(input.path, input.workspacePath);
|
|
9
10
|
if (!filePath) {
|
|
10
11
|
throw new Error('Missing file path');
|
|
11
12
|
}
|
|
@@ -27,6 +28,17 @@ async function prepareChannelFile(input) {
|
|
|
27
28
|
fileSize: fileStat.size,
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
function resolveChannelFilePath(filePath, workspacePath) {
|
|
32
|
+
const normalized = String(filePath || '').trim();
|
|
33
|
+
if (!normalized) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
if ((0, node_path_1.isAbsolute)(normalized)) {
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
const workspaceRoot = String(workspacePath || '').trim();
|
|
40
|
+
return workspaceRoot ? (0, node_path_1.resolve)(workspaceRoot, normalized) : normalized;
|
|
41
|
+
}
|
|
30
42
|
function sanitizeChannelFileName(fileName) {
|
|
31
43
|
const normalized = String(fileName || '').trim().replace(/[\/\\]+/g, '_');
|
|
32
44
|
return normalized || 'file';
|
package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js
CHANGED
|
@@ -643,6 +643,10 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
643
643
|
if (slashCommand?.name === 'new') {
|
|
644
644
|
const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'WeChat'} ${new Date().toLocaleTimeString()}`;
|
|
645
645
|
const nextThread = await router.createThread(input.workspaceId, title);
|
|
646
|
+
const inheritedMode = this.options.store.getThreadRow?.(threadId)?.agent_mode || '';
|
|
647
|
+
if (inheritedMode && inheritedMode !== 'default') {
|
|
648
|
+
this.options.store.updateThreadAgentMode?.(nextThread.id, inheritedMode);
|
|
649
|
+
}
|
|
646
650
|
const now = new Date().toISOString();
|
|
647
651
|
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
|
|
648
652
|
this.options.store.upsertPlatformThreadBinding({
|
|
@@ -676,7 +680,9 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
676
680
|
return { paired: true, threadId };
|
|
677
681
|
}
|
|
678
682
|
this.options.store.updatePlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId, input.contextToken || input.messageId, platformKey);
|
|
679
|
-
const wrappedText =
|
|
683
|
+
const wrappedText = slashCommand
|
|
684
|
+
? input.text
|
|
685
|
+
: (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
|
|
680
686
|
await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
|
|
681
687
|
return { paired: true, threadId };
|
|
682
688
|
}
|
|
@@ -920,6 +926,7 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
920
926
|
const file = await (0, file_utils_js_1.prepareChannelFile)({
|
|
921
927
|
path: part.path,
|
|
922
928
|
fileName: part.fileName,
|
|
929
|
+
workspacePath: typeof part.metadata?.workspacePath === 'string' ? part.metadata.workspacePath : undefined,
|
|
923
930
|
maxBytes: WEIXIN_MAX_UPLOAD_FILE_SIZE,
|
|
924
931
|
platformLabel: 'WeChat',
|
|
925
932
|
});
|
|
@@ -75,6 +75,7 @@ async function handleChannelSendFile(flags, env, io, json) {
|
|
|
75
75
|
type: 'file',
|
|
76
76
|
path: filePath,
|
|
77
77
|
fileName: getFlag(flags, 'name') || undefined,
|
|
78
|
+
metadata: context.workspacePath ? { workspacePath: context.workspacePath } : undefined,
|
|
78
79
|
}],
|
|
79
80
|
});
|
|
80
81
|
const file = result.attachments?.[0];
|
|
@@ -226,6 +227,7 @@ function resolveContext(flags, env) {
|
|
|
226
227
|
return {
|
|
227
228
|
baseUrl: getFlag(flags, 'base-url') || String(env.LOCAL_AI_CORE_BASE || DEFAULT_BASE_URL),
|
|
228
229
|
workspaceId: getFlag(flags, 'workspace') || String(env.LOCAL_AI_WORKSPACE_ID || ''),
|
|
230
|
+
workspacePath: getFlag(flags, 'workspace-path') || String(env.LOCAL_AI_WORKSPACE_PATH || ''),
|
|
229
231
|
threadId: normalizeMaybeBooleanFlag(getFlag(flags, 'thread')) || String(env.LOCAL_AI_THREAD_ID || ''),
|
|
230
232
|
platform,
|
|
231
233
|
routeType: String(env.LOCAL_AI_ROUTE_TYPE || '') || (platform === 'lark' && chatId && platformUserId ? 'channel.chat' : ''),
|
|
@@ -301,7 +303,7 @@ function printUsage(output) {
|
|
|
301
303
|
' lac scheduler edit <job-id> [--cron "<expr>"] [--message "<text>"] [--desc "<label>"] [--enabled true|false] [--execution-mode same-thread|side-thread] [--json]',
|
|
302
304
|
' lac scheduler del <job-id> [--json]',
|
|
303
305
|
' lac scheduler run <job-id> [--json]',
|
|
304
|
-
' lac channel send-file --path "<file>" [--target <chat-or-user-id>] [--workspace <id>] [--platform lark] [--name <filename>] [--json]',
|
|
306
|
+
' lac channel send-file --path "<file>" [--target <chat-or-user-id>] [--workspace <id>] [--workspace-path <path>] [--platform lark] [--name <filename>] [--json]',
|
|
305
307
|
].join('\n') + '\n');
|
|
306
308
|
}
|
|
307
309
|
function formatJobLine(job) {
|
|
@@ -163,6 +163,7 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
163
163
|
}
|
|
164
164
|
const agentPlugins = [
|
|
165
165
|
localCoreAgentPlugin,
|
|
166
|
+
(0, agent_localcore_acp_plugin_js_1.createBuiltinPiAgentPlugin)(),
|
|
166
167
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinOpencodeAgentPlugin)(),
|
|
167
168
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinCodexAgentPlugin)(),
|
|
168
169
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinClaudeCodeAgentPlugin)(),
|
package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBuiltinLocalCoreAcpAgentPlugin = createBuiltinLocalCoreAcpAgentPlugin;
|
|
4
4
|
exports.createBuiltinOpencodeAgentPlugin = createBuiltinOpencodeAgentPlugin;
|
|
5
|
+
exports.createBuiltinPiAgentPlugin = createBuiltinPiAgentPlugin;
|
|
5
6
|
exports.createBuiltinCodexAgentPlugin = createBuiltinCodexAgentPlugin;
|
|
6
7
|
exports.createBuiltinClaudeCodeAgentPlugin = createBuiltinClaudeCodeAgentPlugin;
|
|
7
8
|
exports.createBuiltinStaticAgentCapabilityPlugin = createBuiltinStaticAgentCapabilityPlugin;
|
|
@@ -86,6 +87,14 @@ function createBuiltinOpencodeAgentPlugin() {
|
|
|
86
87
|
displayName: 'OpenCode',
|
|
87
88
|
});
|
|
88
89
|
}
|
|
90
|
+
function createBuiltinPiAgentPlugin() {
|
|
91
|
+
return createBuiltinAgentPlugin({
|
|
92
|
+
pluginId: 'builtin.agent-pi',
|
|
93
|
+
agentType: 'pi',
|
|
94
|
+
match: (normalizedAgentType) => normalizedAgentType === 'pi',
|
|
95
|
+
displayName: 'Pi',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
89
98
|
function createBuiltinCodexAgentPlugin() {
|
|
90
99
|
return createBuiltinAgentPlugin({
|
|
91
100
|
pluginId: 'builtin.agent-codex',
|
|
@@ -4,6 +4,7 @@ exports.normalizePlatformTypes = normalizePlatformTypes;
|
|
|
4
4
|
exports.isLocalCoreNativeAcpProject = isLocalCoreNativeAcpProject;
|
|
5
5
|
exports.toLocalCoreProjectConfig = toLocalCoreProjectConfig;
|
|
6
6
|
const node_module_1 = require("node:module");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
7
8
|
const node_path_1 = require("node:path");
|
|
8
9
|
const desktop_js_1 = require("../../../../shared/desktop.js");
|
|
9
10
|
function normalizePlatformTypes(project) {
|
|
@@ -17,10 +18,13 @@ function isLocalCoreNativeAcpProject(project) {
|
|
|
17
18
|
|| agentType === 'acp'
|
|
18
19
|
|| agentType === desktop_js_1.LOCALCORE_ACP_AGENT_TYPE;
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function resolveAgentModel(project, providers) {
|
|
21
22
|
const agentType = String(project.agent?.type || '').trim().toLowerCase();
|
|
22
23
|
const rawModel = String(project.agent?.options?.model || '').trim();
|
|
23
24
|
const normalizedModel = (0, desktop_js_1.normalizeDesktopAgentModel)(agentType, rawModel);
|
|
25
|
+
if (agentType === 'pi') {
|
|
26
|
+
return rawModel || getFirstProviderModelId(providers);
|
|
27
|
+
}
|
|
24
28
|
if (agentType !== 'opencode') {
|
|
25
29
|
return normalizedModel;
|
|
26
30
|
}
|
|
@@ -31,6 +35,15 @@ function resolveOpencodeModel(project, providers) {
|
|
|
31
35
|
}
|
|
32
36
|
return normalizedModel;
|
|
33
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
|
+
}
|
|
34
47
|
function getFirstProviderModelRef(providers) {
|
|
35
48
|
for (const provider of providers) {
|
|
36
49
|
const providerId = normalizeOpencodeProviderId(provider.name);
|
|
@@ -131,6 +144,108 @@ function collectProviderEnv(providers) {
|
|
|
131
144
|
}
|
|
132
145
|
return env;
|
|
133
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
|
+
}
|
|
134
249
|
function normalizeOpencodeProviderId(value) {
|
|
135
250
|
return String(value || '')
|
|
136
251
|
.trim()
|
|
@@ -138,6 +253,48 @@ function normalizeOpencodeProviderId(value) {
|
|
|
138
253
|
.replace(/[^a-z0-9._-]+/g, '-')
|
|
139
254
|
.replace(/^-+|-+$/g, '');
|
|
140
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
|
+
}
|
|
141
298
|
function opencodeProviderApiKeyEnvName(providerId) {
|
|
142
299
|
const suffix = providerId.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
|
|
143
300
|
return `AI_WORKSTATION_OPENCODE_${suffix || 'PROVIDER'}_API_KEY`;
|
|
@@ -152,7 +309,7 @@ function shouldUseOpenAiCompatibleProvider(providerId) {
|
|
|
152
309
|
}
|
|
153
310
|
function resolveBundledAcpCommand(packageName, binName) {
|
|
154
311
|
const require = (0, node_module_1.createRequire)(__filename);
|
|
155
|
-
const packageJsonPath =
|
|
312
|
+
const packageJsonPath = resolveBundledPackageJsonPath(packageName);
|
|
156
313
|
const packageJson = require(packageJsonPath);
|
|
157
314
|
const binField = packageJson.bin;
|
|
158
315
|
const relativeBinPath = typeof binField === 'string'
|
|
@@ -166,12 +323,44 @@ function resolveBundledAcpCommand(packageName, binName) {
|
|
|
166
323
|
args: [(0, node_path_1.resolve)((0, node_path_1.dirname)(packageJsonPath), relativeBinPath)],
|
|
167
324
|
};
|
|
168
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
|
+
}
|
|
169
352
|
function resolveBundledCodexCommand() {
|
|
170
353
|
return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, 'codex-acp');
|
|
171
354
|
}
|
|
172
355
|
function resolveBundledClaudeCodeCommand() {
|
|
173
356
|
return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, 'claude-agent-acp');
|
|
174
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];
|
|
363
|
+
}
|
|
175
364
|
function toLocalCoreProjectConfig(configState, project) {
|
|
176
365
|
const rawWorkDir = String(project.agent?.options?.work_dir || '.').trim() || '.';
|
|
177
366
|
const configDir = (0, node_path_1.dirname)(configState.path);
|
|
@@ -188,8 +377,11 @@ function toLocalCoreProjectConfig(configState, project) {
|
|
|
188
377
|
: {};
|
|
189
378
|
const agentType = String(project.agent?.type || '').trim().toLowerCase();
|
|
190
379
|
const providers = Array.isArray(project.agent?.providers) ? project.agent.providers : [];
|
|
191
|
-
const model =
|
|
380
|
+
const model = resolveAgentModel(project, providers);
|
|
192
381
|
const providerEnv = collectProviderEnv(providers);
|
|
382
|
+
const piProviderEnv = agentType === 'pi'
|
|
383
|
+
? collectPiProviderEnv(providers)
|
|
384
|
+
: {};
|
|
193
385
|
const opencodeInlineConfig = agentType === 'opencode'
|
|
194
386
|
? buildOpencodeInlineConfig(model, providers)
|
|
195
387
|
: null;
|
|
@@ -204,6 +396,22 @@ function toLocalCoreProjectConfig(configState, project) {
|
|
|
204
396
|
ANTHROPIC_MODEL: model,
|
|
205
397
|
}
|
|
206
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
|
+
: {};
|
|
207
415
|
const bundledCodex = agentType === 'codex'
|
|
208
416
|
? resolveBundledCodexCommand()
|
|
209
417
|
: null;
|
|
@@ -212,18 +420,20 @@ function toLocalCoreProjectConfig(configState, project) {
|
|
|
212
420
|
: null;
|
|
213
421
|
const inferredCommand = agentType === 'opencode'
|
|
214
422
|
? 'opencode'
|
|
215
|
-
: bundledCodex?.command || bundledClaudeCode?.command || '';
|
|
423
|
+
: bundledPiAcp?.command || bundledCodex?.command || bundledClaudeCode?.command || '';
|
|
216
424
|
const command = String(project.agent?.options?.command || inferredCommand).trim();
|
|
217
425
|
if (!command) {
|
|
218
426
|
throw new Error(`Workspace "${project.name}" requires [projects.agent.options].command for Local AI Core ACP execution.`);
|
|
219
427
|
}
|
|
220
428
|
const defaultArgs = agentType === 'opencode'
|
|
221
429
|
? ['acp']
|
|
222
|
-
: agentType === '
|
|
223
|
-
? [...(
|
|
224
|
-
: agentType === '
|
|
225
|
-
? [...(
|
|
226
|
-
:
|
|
430
|
+
: agentType === 'pi'
|
|
431
|
+
? [...(bundledPiAcp?.args || [])]
|
|
432
|
+
: agentType === 'codex'
|
|
433
|
+
? [...(bundledCodex?.args || [])]
|
|
434
|
+
: agentType === 'claudecode'
|
|
435
|
+
? [...(bundledClaudeCode?.args || [])]
|
|
436
|
+
: [];
|
|
227
437
|
return {
|
|
228
438
|
workspaceId: project.name,
|
|
229
439
|
agentType,
|
|
@@ -231,9 +441,10 @@ function toLocalCoreProjectConfig(configState, project) {
|
|
|
231
441
|
command,
|
|
232
442
|
args: args.length > 0 ? args : defaultArgs,
|
|
233
443
|
env: {
|
|
234
|
-
...providerEnv,
|
|
235
444
|
...inferredOpencodeEnv,
|
|
236
445
|
...inferredClaudeCodeEnv,
|
|
446
|
+
...inferredPiEnv,
|
|
447
|
+
...providerEnv,
|
|
237
448
|
...env,
|
|
238
449
|
},
|
|
239
450
|
model,
|