@kafca/agentdock 0.1.20 → 0.1.21
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 +7 -0
- package/dist/renderer/assets/{Badge-C1f8JpRb.js → Badge-BRmQIqbd.js} +1 -1
- package/dist/renderer/assets/{Chat-S50iFg3I.js → Chat-D94ODABB.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-VWL9Vnpz.js → ChatMarkdown-DqW7OUvV.js} +1 -1
- package/dist/renderer/assets/{Config-Yc9ExUI6.js → Config-9lgzpTCp.js} +1 -1
- package/dist/renderer/assets/{CronList-DTboWazi.js → CronList-BYZ-x_bp.js} +1 -1
- package/dist/renderer/assets/{Dashboard-CzXCvZVR.js → Dashboard-COISXbQy.js} +2 -2
- package/dist/renderer/assets/{EmptyState-9FbY2o6z.js → EmptyState-w5-I9zg7.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-D_BDc4Zt.js → KnowledgeDetail-DVxwrTLw.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-DsUA_BCR.js → KnowledgeHome-BKkubcwi.js} +1 -1
- package/dist/renderer/assets/{Logs-DDAmR67f.js → Logs-D7HxZ8Nb.js} +1 -1
- package/dist/renderer/assets/{Modal-Bt5VBC6S.js → Modal-Ceu_MP2e.js} +1 -1
- package/dist/renderer/assets/{Page-Da_Kc6Qm.js → Page-CpSczAz8.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-B4Ps80yv.js → ProjectDetail-FJ_bNXLF.js} +1 -1
- package/dist/renderer/assets/{ProjectList-BWTP9npz.js → ProjectList-DZKL4K9C.js} +1 -1
- package/dist/renderer/assets/{Select-DWs3hVUh.js → Select-BHQk6qCU.js} +1 -1
- package/dist/renderer/assets/{SessionChat-DOhUnOfH.js → SessionChat-DpgSXF3m.js} +1 -1
- package/dist/renderer/assets/{SessionList-ChZYFXuo.js → SessionList-CU6drQ4N.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-nhnikHnk.js → ThreadChat-D3s4GXGh.js} +1 -1
- package/dist/renderer/assets/{Workspace-pq_JYdTN.js → Workspace-B7looTVo.js} +1 -1
- package/dist/renderer/assets/{arrow-left-CR39hNvq.js → arrow-left-Dtal-eOi.js} +1 -1
- package/dist/renderer/assets/{book-open-Bot2WKl8.js → book-open-q814R_Ov.js} +1 -1
- package/dist/renderer/assets/{check-Drbl2nU3.js → check-DjfCdLvw.js} +1 -1
- package/dist/renderer/assets/{circle-BXFfAwnA.js → circle-vfhmyE8v.js} +1 -1
- package/dist/renderer/assets/{desktop-5k3W66fH.js → desktop-BPIxWbkM.js} +1 -1
- package/dist/renderer/assets/desktop-DZHC4PDB.js +3 -0
- package/dist/renderer/assets/{funnel-BNKYan_N.js → funnel-CUQibo1I.js} +1 -1
- package/dist/renderer/assets/{heart-wUOSwQE-.js → heart-DG9_b8P1.js} +1 -1
- package/dist/renderer/assets/{index-DT5la73R.js → index-Bn8ane6_.js} +2 -2
- package/dist/renderer/assets/{index-CmOphqrf.js → index-Ds0IN5rP.js} +1 -1
- package/dist/renderer/assets/{pencil-D7-8ggue.js → pencil-Dij0LlRY.js} +1 -1
- package/dist/renderer/assets/{play-BCYOAfet.js → play-CPFGjIyJ.js} +1 -1
- package/dist/renderer/assets/{plug-Dsik74Yl.js → plug-DH3RKQyn.js} +1 -1
- package/dist/renderer/assets/{plus-CKrU26_l.js → plus-afkK9_Y8.js} +1 -1
- package/dist/renderer/assets/projects-DTDS9SnT.js +1 -0
- package/dist/renderer/assets/{save-q7M2_eAl.js → save-B-cKgWcy.js} +1 -1
- package/dist/renderer/assets/{search-BptY4_MT.js → search-DR6PeYkt.js} +1 -1
- package/dist/renderer/assets/{server-DSSEF0D8.js → server-BM6KOB5a.js} +1 -1
- package/dist/renderer/assets/{session-utils-BFuqPZ5x.js → session-utils-BDuThM0a.js} +1 -1
- package/dist/renderer/assets/{sessions-CrWo3g3u.js → sessions-C1yKps4T.js} +1 -1
- package/dist/renderer/assets/{shield-check-CCU722RQ.js → shield-check-BFjMG-r2.js} +1 -1
- package/dist/renderer/assets/{trash-2-DaeeiV8x.js → trash-2-CW1heMCf.js} +1 -1
- package/dist/renderer/assets/{user-Bkz8J7Yw.js → user-r_2sHG7m.js} +1 -1
- package/dist/renderer/assets/{wifi-off-P8xdIOHU.js → wifi-off-VMUokMpE.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/agent-runtime-detector.test.js +11 -0
- package/dist-electron/electron/local-core-refactor.test.js +96 -0
- package/dist-electron/electron/plugin-kernel.test.js +43 -9
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +9 -9
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +60 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +122 -5
- package/dist-electron/services/local-ai-core/src/gateway/local-core-weixin-gateway.js +50 -2
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +2 -1
- 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 +19 -8
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +23 -12
- package/dist-electron/shared/desktop.js +4 -2
- package/package.json +2 -1
- package/dist/renderer/assets/desktop-D4Z7M9RM.js +0 -3
- package/dist/renderer/assets/projects-CGDtNb0M.js +0 -1
|
@@ -453,7 +453,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
453
453
|
return { paired: true, threadId };
|
|
454
454
|
}
|
|
455
455
|
this.options.store.clearPlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId);
|
|
456
|
-
|
|
456
|
+
const wrappedText = (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
|
|
457
|
+
await router.sendThreadMessage(threadId, this.createThreadMessageInput(wrappedText, input.contentParts));
|
|
457
458
|
return { paired: true, threadId };
|
|
458
459
|
}
|
|
459
460
|
close() {
|
|
@@ -610,18 +611,41 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
610
611
|
catch {
|
|
611
612
|
parsedContent = {};
|
|
612
613
|
}
|
|
614
|
+
const messageType = String(message.message_type || '').trim().toLowerCase();
|
|
613
615
|
const text = String(parsedContent.text || '').trim();
|
|
614
|
-
|
|
615
|
-
|
|
616
|
+
const contentParts = [];
|
|
617
|
+
if (text) {
|
|
618
|
+
contentParts.push({ type: 'text', text });
|
|
619
|
+
}
|
|
620
|
+
if (messageType === 'image') {
|
|
621
|
+
const imageKey = String(parsedContent.image_key || parsedContent.file_key || '').trim();
|
|
622
|
+
if (imageKey) {
|
|
623
|
+
try {
|
|
624
|
+
contentParts.push(await this.downloadMessageImage(workspaceId, String(message.message_id || ''), imageKey));
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
const errorText = `[Image download failed: ${error instanceof Error ? error.message : String(error)}]`;
|
|
628
|
+
contentParts.push({ type: 'text', text: errorText });
|
|
629
|
+
this.options.log?.(`localcore-lark image download failed for ${workspaceId}: message=${String(message.message_id || '')} imageKey=${imageKey} error=${error instanceof Error ? error.message : String(error)}`);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (contentParts.length === 0) {
|
|
634
|
+
this.options.log?.(`localcore-lark ignored unsupported message for ${workspaceId}: type=${String(message.message_type || 'unknown')} contentKeys=${JSON.stringify(Object.keys(parsedContent))}`);
|
|
616
635
|
return;
|
|
617
636
|
}
|
|
637
|
+
const displayText = text || (contentParts.some((part) => part.type === 'image') ? '[Image]' : contentParts
|
|
638
|
+
.filter((part) => part.type === 'text')
|
|
639
|
+
.map((part) => part.text)
|
|
640
|
+
.join('\n\n')
|
|
641
|
+
.trim());
|
|
618
642
|
const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
|
|
619
643
|
const chatId = String(message.chat_id || platformUserId).trim();
|
|
620
644
|
if (!platformUserId || !chatId) {
|
|
621
645
|
this.options.log?.(`localcore-lark ignored message without sender/chat for ${workspaceId}: senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`);
|
|
622
646
|
return;
|
|
623
647
|
}
|
|
624
|
-
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} text=${JSON.stringify(
|
|
648
|
+
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
|
|
625
649
|
await this.handleInboundMessage({
|
|
626
650
|
workspaceId,
|
|
627
651
|
platformUserId,
|
|
@@ -629,10 +653,103 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
629
653
|
displayName: String(payload?.sender?.sender_id?.user_id ||
|
|
630
654
|
payload?.sender?.sender_id?.open_id ||
|
|
631
655
|
`Lark ${platformUserId.slice(-6)}`),
|
|
632
|
-
text,
|
|
656
|
+
text: displayText,
|
|
633
657
|
messageId: String(message.message_id || (0, node_crypto_1.randomUUID)()),
|
|
658
|
+
contentParts,
|
|
634
659
|
});
|
|
635
660
|
}
|
|
661
|
+
createWrappedContentParts(wrappedText, parts) {
|
|
662
|
+
const nonTextParts = Array.isArray(parts)
|
|
663
|
+
? parts.filter((part) => part.type !== 'text')
|
|
664
|
+
: [];
|
|
665
|
+
return [
|
|
666
|
+
{ type: 'text', text: wrappedText },
|
|
667
|
+
...nonTextParts,
|
|
668
|
+
];
|
|
669
|
+
}
|
|
670
|
+
createThreadMessageInput(wrappedText, parts) {
|
|
671
|
+
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
672
|
+
if (!hasNonTextPart) {
|
|
673
|
+
return wrappedText;
|
|
674
|
+
}
|
|
675
|
+
return {
|
|
676
|
+
displayText: wrappedText,
|
|
677
|
+
contentParts: this.createWrappedContentParts(wrappedText, parts),
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
async downloadMessageImage(workspaceId, messageId, imageKey) {
|
|
681
|
+
const state = this.runtime.get(workspaceId);
|
|
682
|
+
if (!state?.client) {
|
|
683
|
+
throw new Error('Lark client is not connected');
|
|
684
|
+
}
|
|
685
|
+
if (!messageId) {
|
|
686
|
+
throw new Error('Lark image message is missing message_id');
|
|
687
|
+
}
|
|
688
|
+
const resource = await state.client.im.messageResource.get({
|
|
689
|
+
path: {
|
|
690
|
+
message_id: messageId,
|
|
691
|
+
file_key: imageKey,
|
|
692
|
+
},
|
|
693
|
+
params: {
|
|
694
|
+
type: 'image',
|
|
695
|
+
},
|
|
696
|
+
});
|
|
697
|
+
const buffer = await this.readLarkResourceBuffer(resource);
|
|
698
|
+
if (buffer.length === 0) {
|
|
699
|
+
throw new Error('Lark image resource is empty');
|
|
700
|
+
}
|
|
701
|
+
const headerMime = this.extractHeaderMimeType(resource?.headers);
|
|
702
|
+
return {
|
|
703
|
+
type: 'image',
|
|
704
|
+
data: buffer.toString('base64'),
|
|
705
|
+
mimeType: headerMime || this.sniffImageMimeType(buffer),
|
|
706
|
+
fileName: `${imageKey}.${this.sniffImageExtension(buffer)}`,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
async readLarkResourceBuffer(resource) {
|
|
710
|
+
const readable = resource?.getReadableStream?.();
|
|
711
|
+
if (!readable || typeof readable.on !== 'function') {
|
|
712
|
+
throw new Error('Lark resource did not provide a readable stream');
|
|
713
|
+
}
|
|
714
|
+
const chunks = [];
|
|
715
|
+
await new Promise((resolve, reject) => {
|
|
716
|
+
readable.on('data', (chunk) => {
|
|
717
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
718
|
+
});
|
|
719
|
+
readable.on('error', reject);
|
|
720
|
+
readable.on('end', resolve);
|
|
721
|
+
});
|
|
722
|
+
return Buffer.concat(chunks);
|
|
723
|
+
}
|
|
724
|
+
extractHeaderMimeType(headers) {
|
|
725
|
+
const value = headers && typeof headers === 'object'
|
|
726
|
+
? headers['content-type'] || headers['Content-Type']
|
|
727
|
+
: '';
|
|
728
|
+
return String(value || '').split(';')[0]?.trim() || '';
|
|
729
|
+
}
|
|
730
|
+
sniffImageMimeType(buffer) {
|
|
731
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8)
|
|
732
|
+
return 'image/jpeg';
|
|
733
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47)
|
|
734
|
+
return 'image/png';
|
|
735
|
+
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46)
|
|
736
|
+
return 'image/gif';
|
|
737
|
+
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46)
|
|
738
|
+
return 'image/webp';
|
|
739
|
+
return 'application/octet-stream';
|
|
740
|
+
}
|
|
741
|
+
sniffImageExtension(buffer) {
|
|
742
|
+
const mimeType = this.sniffImageMimeType(buffer);
|
|
743
|
+
if (mimeType === 'image/jpeg')
|
|
744
|
+
return 'jpg';
|
|
745
|
+
if (mimeType === 'image/png')
|
|
746
|
+
return 'png';
|
|
747
|
+
if (mimeType === 'image/gif')
|
|
748
|
+
return 'gif';
|
|
749
|
+
if (mimeType === 'image/webp')
|
|
750
|
+
return 'webp';
|
|
751
|
+
return 'bin';
|
|
752
|
+
}
|
|
636
753
|
attachWsDiagnostics(workspaceId, wsClient) {
|
|
637
754
|
const on = typeof wsClient?.on === 'function' ? wsClient.on.bind(wsClient) : null;
|
|
638
755
|
if (!on) {
|
|
@@ -585,7 +585,8 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
585
585
|
return { paired: true, threadId };
|
|
586
586
|
}
|
|
587
587
|
this.options.store.updatePlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId, input.contextToken || input.messageId, 'weixin');
|
|
588
|
-
|
|
588
|
+
const wrappedText = (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
|
|
589
|
+
await router.sendThreadMessage(threadId, this.createThreadMessageInput(wrappedText, input.contentParts));
|
|
589
590
|
return { paired: true, threadId };
|
|
590
591
|
}
|
|
591
592
|
// ==================== Private: Bindings ====================
|
|
@@ -799,6 +800,7 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
799
800
|
const msgId = msg.msg_id ?? String(Date.now());
|
|
800
801
|
// Handle attachments
|
|
801
802
|
let attachmentText = '';
|
|
803
|
+
const attachmentParts = [];
|
|
802
804
|
if (mediaItems.length > 0) {
|
|
803
805
|
const uploadsDir = node_path_1.default.join(binding.stateDir, 'weixin-uploads');
|
|
804
806
|
for (const [idx, item] of mediaItems.entries()) {
|
|
@@ -807,6 +809,14 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
807
809
|
if (att) {
|
|
808
810
|
attachmentText += attachmentText ? '\n' : '';
|
|
809
811
|
attachmentText += att.kind === 'image' ? `[Image: ${att.path}]` : `[File "${att.name}": ${att.path}]`;
|
|
812
|
+
if (att.kind === 'image' && att.data) {
|
|
813
|
+
attachmentParts.push({
|
|
814
|
+
type: 'image',
|
|
815
|
+
data: att.data,
|
|
816
|
+
mimeType: att.mimeType,
|
|
817
|
+
fileName: att.name,
|
|
818
|
+
});
|
|
819
|
+
}
|
|
810
820
|
}
|
|
811
821
|
}
|
|
812
822
|
catch (dlErr) {
|
|
@@ -825,6 +835,10 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
825
835
|
text: fullText,
|
|
826
836
|
messageId: msgId,
|
|
827
837
|
contextToken: msg.context_token,
|
|
838
|
+
contentParts: [
|
|
839
|
+
...(text ? [{ type: 'text', text }] : []),
|
|
840
|
+
...attachmentParts,
|
|
841
|
+
],
|
|
828
842
|
});
|
|
829
843
|
}
|
|
830
844
|
}
|
|
@@ -991,7 +1005,41 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
991
1005
|
const filePath = node_path_1.default.join(uploadsDir, fileName);
|
|
992
1006
|
node_fs_1.default.mkdirSync(uploadsDir, { recursive: true });
|
|
993
1007
|
node_fs_1.default.writeFileSync(filePath, resultBuf);
|
|
994
|
-
return {
|
|
1008
|
+
return {
|
|
1009
|
+
path: filePath,
|
|
1010
|
+
kind,
|
|
1011
|
+
name: declaredName,
|
|
1012
|
+
data: kind === 'image' ? resultBuf.toString('base64') : undefined,
|
|
1013
|
+
mimeType: kind === 'image' ? this.mimeTypeForImageExt(ext) : undefined,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
createWrappedContentParts(wrappedText, parts) {
|
|
1017
|
+
const nonTextParts = Array.isArray(parts)
|
|
1018
|
+
? parts.filter((part) => part.type !== 'text')
|
|
1019
|
+
: [];
|
|
1020
|
+
return [
|
|
1021
|
+
{ type: 'text', text: wrappedText },
|
|
1022
|
+
...nonTextParts,
|
|
1023
|
+
];
|
|
1024
|
+
}
|
|
1025
|
+
createThreadMessageInput(wrappedText, parts) {
|
|
1026
|
+
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
1027
|
+
if (!hasNonTextPart) {
|
|
1028
|
+
return wrappedText;
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
displayText: wrappedText,
|
|
1032
|
+
contentParts: this.createWrappedContentParts(wrappedText, parts),
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
mimeTypeForImageExt(ext) {
|
|
1036
|
+
if (ext === '.jpg')
|
|
1037
|
+
return 'image/jpeg';
|
|
1038
|
+
if (ext === '.png')
|
|
1039
|
+
return 'image/png';
|
|
1040
|
+
if (ext === '.gif')
|
|
1041
|
+
return 'image/gif';
|
|
1042
|
+
return 'application/octet-stream';
|
|
995
1043
|
}
|
|
996
1044
|
// ==================== Private: Turn State ====================
|
|
997
1045
|
createTurnState(sessionKey) {
|
|
@@ -35,7 +35,7 @@ function bootstrapLocalCoreKernel(options) {
|
|
|
35
35
|
const lifecycle = new lifecycle_manager_js_1.LocalCoreLifecycleManager(plugins, context);
|
|
36
36
|
const diagnostics = new diagnostics_js_1.LocalCoreDiagnostics(plugins, lifecycle);
|
|
37
37
|
const builtIns = [
|
|
38
|
-
...['
|
|
38
|
+
...['cursor', 'gemini', 'qoder', 'iflow'].map((agentType) => (0, agent_localcore_acp_plugin_js_1.createBuiltinStaticAgentCapabilityPlugin)(agentType)),
|
|
39
39
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinLocalCoreAcpAgentPlugin)(),
|
|
40
40
|
(0, scheduler_cron_plugin_js_1.createBuiltinCronSchedulerPlugin)(),
|
|
41
41
|
];
|
|
@@ -164,6 +164,7 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
164
164
|
const agentPlugins = [
|
|
165
165
|
localCoreAgentPlugin,
|
|
166
166
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinOpencodeAgentPlugin)(),
|
|
167
|
+
(0, agent_localcore_acp_plugin_js_1.createBuiltinCodexAgentPlugin)(),
|
|
167
168
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinClaudeCodeAgentPlugin)(),
|
|
168
169
|
];
|
|
169
170
|
let workspaceRouter;
|
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.createBuiltinCodexAgentPlugin = createBuiltinCodexAgentPlugin;
|
|
5
6
|
exports.createBuiltinClaudeCodeAgentPlugin = createBuiltinClaudeCodeAgentPlugin;
|
|
6
7
|
exports.createBuiltinStaticAgentCapabilityPlugin = createBuiltinStaticAgentCapabilityPlugin;
|
|
7
8
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
@@ -85,6 +86,14 @@ function createBuiltinOpencodeAgentPlugin() {
|
|
|
85
86
|
displayName: 'OpenCode',
|
|
86
87
|
});
|
|
87
88
|
}
|
|
89
|
+
function createBuiltinCodexAgentPlugin() {
|
|
90
|
+
return createBuiltinAgentPlugin({
|
|
91
|
+
pluginId: 'builtin.agent-codex',
|
|
92
|
+
agentType: 'codex',
|
|
93
|
+
match: (normalizedAgentType) => normalizedAgentType === 'codex',
|
|
94
|
+
displayName: 'Codex',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
88
97
|
function createBuiltinClaudeCodeAgentPlugin() {
|
|
89
98
|
return createBuiltinAgentPlugin({
|
|
90
99
|
pluginId: 'builtin.agent-claudecode',
|
|
@@ -150,22 +150,28 @@ function shouldUseOpenAiCompatibleProvider(providerId) {
|
|
|
150
150
|
]);
|
|
151
151
|
return !builtInNonCompatibleProviders.has(providerId);
|
|
152
152
|
}
|
|
153
|
-
function
|
|
153
|
+
function resolveBundledAcpCommand(packageName, binName) {
|
|
154
154
|
const require = (0, node_module_1.createRequire)(__filename);
|
|
155
|
-
const packageJsonPath = require.resolve(`${
|
|
155
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`);
|
|
156
156
|
const packageJson = require(packageJsonPath);
|
|
157
157
|
const binField = packageJson.bin;
|
|
158
158
|
const relativeBinPath = typeof binField === 'string'
|
|
159
159
|
? binField
|
|
160
|
-
: binField?.[
|
|
160
|
+
: binField?.[binName];
|
|
161
161
|
if (!relativeBinPath) {
|
|
162
|
-
throw new Error(`Bundled package "${
|
|
162
|
+
throw new Error(`Bundled package "${packageName}" does not declare the ${binName} bin.`);
|
|
163
163
|
}
|
|
164
164
|
return {
|
|
165
165
|
command: process.execPath,
|
|
166
166
|
args: [(0, node_path_1.resolve)((0, node_path_1.dirname)(packageJsonPath), relativeBinPath)],
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
|
+
function resolveBundledCodexCommand() {
|
|
170
|
+
return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, 'codex-acp');
|
|
171
|
+
}
|
|
172
|
+
function resolveBundledClaudeCodeCommand() {
|
|
173
|
+
return resolveBundledAcpCommand(desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, 'claude-agent-acp');
|
|
174
|
+
}
|
|
169
175
|
function toLocalCoreProjectConfig(configState, project) {
|
|
170
176
|
const rawWorkDir = String(project.agent?.options?.work_dir || '.').trim() || '.';
|
|
171
177
|
const configDir = (0, node_path_1.dirname)(configState.path);
|
|
@@ -198,21 +204,26 @@ function toLocalCoreProjectConfig(configState, project) {
|
|
|
198
204
|
ANTHROPIC_MODEL: model,
|
|
199
205
|
}
|
|
200
206
|
: {};
|
|
207
|
+
const bundledCodex = agentType === 'codex'
|
|
208
|
+
? resolveBundledCodexCommand()
|
|
209
|
+
: null;
|
|
201
210
|
const bundledClaudeCode = agentType === 'claudecode'
|
|
202
211
|
? resolveBundledClaudeCodeCommand()
|
|
203
212
|
: null;
|
|
204
213
|
const inferredCommand = agentType === 'opencode'
|
|
205
214
|
? 'opencode'
|
|
206
|
-
: bundledClaudeCode?.command || '';
|
|
215
|
+
: bundledCodex?.command || bundledClaudeCode?.command || '';
|
|
207
216
|
const command = String(project.agent?.options?.command || inferredCommand).trim();
|
|
208
217
|
if (!command) {
|
|
209
218
|
throw new Error(`Workspace "${project.name}" requires [projects.agent.options].command for Local AI Core ACP execution.`);
|
|
210
219
|
}
|
|
211
220
|
const defaultArgs = agentType === 'opencode'
|
|
212
221
|
? ['acp']
|
|
213
|
-
: agentType === '
|
|
214
|
-
? [...(
|
|
215
|
-
:
|
|
222
|
+
: agentType === 'codex'
|
|
223
|
+
? [...(bundledCodex?.args || [])]
|
|
224
|
+
: agentType === 'claudecode'
|
|
225
|
+
? [...(bundledClaudeCode?.args || [])]
|
|
226
|
+
: [];
|
|
216
227
|
return {
|
|
217
228
|
workspaceId: project.name,
|
|
218
229
|
agentType,
|
|
@@ -18,7 +18,7 @@ const DISPLAY_NAMES = {
|
|
|
18
18
|
};
|
|
19
19
|
const COMMAND_CANDIDATES = {
|
|
20
20
|
opencode: ['opencode'],
|
|
21
|
-
codex: ['codex'],
|
|
21
|
+
codex: ['codex-acp', 'codex'],
|
|
22
22
|
claudecode: ['claude-agent-acp'],
|
|
23
23
|
cursor: ['cursor-agent', 'cursor'],
|
|
24
24
|
gemini: ['gemini'],
|
|
@@ -61,8 +61,14 @@ function detectInstalledAgentRuntimes(options = {}) {
|
|
|
61
61
|
? installedRuntime(agentType, resolved, 'config', detectedAt, env, versionTimeoutMs)
|
|
62
62
|
: missingRuntime(agentType, detectedAt, `Configured command not found: ${configured}`);
|
|
63
63
|
}
|
|
64
|
-
if (agentType === 'claudecode') {
|
|
65
|
-
const bundled =
|
|
64
|
+
if (agentType === 'codex' || agentType === 'claudecode') {
|
|
65
|
+
const bundled = agentType === 'codex'
|
|
66
|
+
? resolveBundledAcpPackage(options.requireFrom, desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, ['bin/codex-acp.js'])
|
|
67
|
+
: resolveBundledAcpPackage(options.requireFrom, desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, [
|
|
68
|
+
'dist/cli.js',
|
|
69
|
+
'bin/claude-agent-acp.js',
|
|
70
|
+
'cli.js',
|
|
71
|
+
]);
|
|
66
72
|
if (bundled) {
|
|
67
73
|
return installedRuntime(agentType, bundled, 'bundled', detectedAt, env, versionTimeoutMs);
|
|
68
74
|
}
|
|
@@ -215,18 +221,23 @@ function parseVersionOutput(output) {
|
|
|
215
221
|
const match = text.match(/\d+(?:\.\d+)+(?:[-+._a-zA-Z0-9]*)?/);
|
|
216
222
|
return match?.[0] || text || undefined;
|
|
217
223
|
}
|
|
218
|
-
function
|
|
224
|
+
function resolveBundledAcpPackage(requireFrom, packageName, candidates) {
|
|
219
225
|
try {
|
|
220
226
|
const require = (0, node_module_1.createRequire)(requireFrom || (0, node_path_1.join)(process.cwd(), 'package.json'));
|
|
221
|
-
const packageJsonPath = require.resolve(`${
|
|
227
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`);
|
|
222
228
|
const packageDir = (0, node_path_1.dirname)(packageJsonPath);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
const packageJson = require(packageJsonPath);
|
|
230
|
+
const binField = packageJson.bin;
|
|
231
|
+
if (typeof binField === 'string') {
|
|
232
|
+
candidates = [binField, ...candidates];
|
|
233
|
+
}
|
|
234
|
+
else if (binField && typeof binField === 'object') {
|
|
235
|
+
candidates = [...Object.values(binField), ...candidates];
|
|
236
|
+
}
|
|
237
|
+
for (const candidate of candidates) {
|
|
238
|
+
const candidatePath = (0, node_path_1.join)(packageDir, candidate);
|
|
239
|
+
if ((0, node_fs_1.existsSync)(candidatePath)) {
|
|
240
|
+
return candidatePath;
|
|
230
241
|
}
|
|
231
242
|
}
|
|
232
243
|
return packageJsonPath;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SCHEDULER_PROTOCOL_INSTRUCTION = exports.LOCALCORE_ACP_AGENT_TYPE = exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = exports.DESKTOP_PROVIDER_THINKING_OPTIONS = exports.DESKTOP_PROVIDER_PRESET_OPTIONS = exports.DESKTOP_PLATFORM_TYPE_OPTIONS = exports.DESKTOP_AGENT_TYPE_OPTIONS = exports.DESKTOP_LARK_SDK_PACKAGE = exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = exports.DEFAULT_DESKTOP_OPENCODE_MODEL = exports.DEFAULT_DESKTOP_AGENT_TYPE = void 0;
|
|
3
|
+
exports.SCHEDULER_PROTOCOL_INSTRUCTION = exports.LOCALCORE_ACP_AGENT_TYPE = exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = exports.DESKTOP_PROVIDER_THINKING_OPTIONS = exports.DESKTOP_PROVIDER_PRESET_OPTIONS = exports.DESKTOP_PLATFORM_TYPE_OPTIONS = exports.DESKTOP_AGENT_TYPE_OPTIONS = exports.DESKTOP_LARK_SDK_PACKAGE = exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = exports.DESKTOP_CODEX_ACP_PACKAGE = exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = exports.DEFAULT_DESKTOP_OPENCODE_MODEL = exports.DEFAULT_DESKTOP_AGENT_TYPE = void 0;
|
|
4
4
|
exports.deriveDesktopRuntimePhase = deriveDesktopRuntimePhase;
|
|
5
5
|
exports.deriveDesktopRuntimeRoles = deriveDesktopRuntimeRoles;
|
|
6
6
|
exports.normalizeDesktopPlatformType = normalizeDesktopPlatformType;
|
|
@@ -15,6 +15,7 @@ exports.isAcpAgentType = isAcpAgentType;
|
|
|
15
15
|
exports.DEFAULT_DESKTOP_AGENT_TYPE = 'opencode';
|
|
16
16
|
exports.DEFAULT_DESKTOP_OPENCODE_MODEL = 'opencode/minimax-m2.5-free';
|
|
17
17
|
exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = '';
|
|
18
|
+
exports.DESKTOP_CODEX_ACP_PACKAGE = '@zed-industries/codex-acp';
|
|
18
19
|
exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = '@agentclientprotocol/claude-agent-acp';
|
|
19
20
|
exports.DESKTOP_LARK_SDK_PACKAGE = '@larksuiteoapi/node-sdk';
|
|
20
21
|
exports.DESKTOP_AGENT_TYPE_OPTIONS = [
|
|
@@ -52,7 +53,7 @@ exports.DESKTOP_PROVIDER_PRESET_OPTIONS = [
|
|
|
52
53
|
'ollama',
|
|
53
54
|
];
|
|
54
55
|
exports.DESKTOP_PROVIDER_THINKING_OPTIONS = ['', 'enabled', 'disabled'];
|
|
55
|
-
exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['opencode', 'claudecode', 'acp', 'localcore-acp'];
|
|
56
|
+
exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['opencode', 'codex', 'claudecode', 'acp', 'localcore-acp'];
|
|
56
57
|
exports.LOCALCORE_ACP_AGENT_TYPE = 'localcore-acp';
|
|
57
58
|
exports.SCHEDULER_PROTOCOL_INSTRUCTION = [
|
|
58
59
|
'[Scheduler Tools]',
|
|
@@ -190,6 +191,7 @@ function isAcpAgentType(agentType) {
|
|
|
190
191
|
const normalized = String(agentType || '').trim().toLowerCase();
|
|
191
192
|
return normalized === 'acp'
|
|
192
193
|
|| normalized === 'opencode'
|
|
194
|
+
|| normalized === 'codex'
|
|
193
195
|
|| normalized === 'claudecode'
|
|
194
196
|
|| normalized === exports.LOCALCORE_ACP_AGENT_TYPE;
|
|
195
197
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kafca/agentdock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist-electron/electron/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@radix-ui/react-select": "^2.2.6",
|
|
50
50
|
"@radix-ui/react-slot": "^1.2.4",
|
|
51
51
|
"@tailwindcss/typography": "^0.5.19",
|
|
52
|
+
"@zed-industries/codex-acp": "^0.12.0",
|
|
52
53
|
"clsx": "^2.1.1",
|
|
53
54
|
"highlight.js": "^11.11.1",
|
|
54
55
|
"i18next": "^25.1.2",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
const u="opencode",s="opencode/minimax-m2.5-free";const h=["opencode","codex","claudecode","cursor","gemini","qoder","iflow","localcore-acp"],_=["telegram","feishu","lark","discord","slack","dingtalk","wecom","weixin","qq","qqbot","line"],l=["opencode","claudecode","acp","localcore-acp"],c="localcore-acp",d=["[Scheduler Tools]","If the user asks to create, view, edit, delete, or manually run a scheduled task for this conversation, use the Bash tool to run the local scheduler CLI.","Use these commands:",'lac scheduler add --cron "<5-field cron>" --message "<exact message to send>" --desc "<short label>" [--execution-mode same-thread|side-thread]',"lac scheduler list","lac scheduler list --thread","lac scheduler info <job-id>",'lac scheduler edit <job-id> [--cron "<5-field cron>"] [--message "<exact message>"] [--desc "<short label>"] [--enabled true|false] [--execution-mode same-thread|side-thread]',"lac scheduler del <job-id>","lac scheduler run <job-id>","Environment variables LOCAL_AI_WORKSPACE_ID, LOCAL_AI_THREAD_ID, LOCAL_AI_PLATFORM, LOCAL_AI_CHAT_ID, and LOCAL_AI_PLATFORM_USER_ID are already set when available.","Prefer relying on those variables instead of inventing your own route or creating session-only cron jobs.","By default, `lac scheduler list` shows all scheduled tasks in the current workspace. Use `lac scheduler list --thread` to show only the current conversation thread.","Use `--execution-mode same-thread` to reuse the current thread, or `--execution-mode side-thread` to run in a dedicated scheduled thread.","Only use the scheduler CLI when the user explicitly asks for scheduled automation.","[/Scheduler Tools]"].join(`
|
|
2
|
-
`),i={allow:"allow",deny:"deny","allow all":"allow all",allowall:"allow all","perm:allow":"allow","perm:deny":"deny","perm:allow_all":"allow all"};function E(e,t=[]){return[d,...t.flatMap(o=>o?["",o]:[]),"","[User Message]",e,"[/User Message]"].join(`
|
|
3
|
-
`)}function m(e){switch(String(e||"").trim().toLowerCase()){case"opencode":return s;case"claudecode":return"";default:return""}}function O(e,t){const o=String(e||"").trim().toLowerCase(),r=String(t||"").trim();return o?o==="opencode"?r||s:o==="claudecode"&&r.startsWith("opencode/")?"":r:r}function n(e){return e&&i[String(e).trim().toLowerCase()]||null}function f(e){return!!n(e==null?void 0:e.data)}function T(e){if(!e||typeof e!="object")return null;const t=e,o=typeof t.text=="string"?t.text:typeof t.Text=="string"?t.Text:"",r=typeof t.data=="string"?t.data:typeof t.Data=="string"?t.Data:"";if(!o||!r)return null;const a=n(r);return a?{text:a,data:a}:{text:o,data:r}}function A(e){return e?l.includes(String(e).trim().toLowerCase()):!1}function D(e){const t=String(e||"").trim().toLowerCase();return t==="acp"||t==="opencode"||t==="claudecode"||t===c}export{h as D,n as a,D as b,O as c,_ as d,u as e,m as g,f as i,T as n,A as s,E as w};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{y as t}from"./index-DT5la73R.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
|