@kafca/agentdock 0.1.56 → 0.1.57
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-DjcoXx2J.js → Badge-CDTbmw1h.js} +1 -1
- package/dist/renderer/assets/Card-DayUo35w.js +1 -0
- package/dist/renderer/assets/Config-ByGMQuzR.js +21 -0
- package/dist/renderer/assets/CronList-XqHdVlgu.js +1 -0
- package/dist/renderer/assets/Dashboard-CZj-oANw.js +41 -0
- package/dist/renderer/assets/{EmptyState-DIZLiccW.js → EmptyState-EFMkOjZO.js} +1 -1
- package/dist/renderer/assets/HighlightedMarkdown-DyvF3DHK.js +12 -0
- package/dist/renderer/assets/Input-DxoWVc9d.js +1 -0
- package/dist/renderer/assets/{KnowledgeDetail-CJ9IYOsa.js → KnowledgeDetail-CbUb2tG7.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-BLGPwnBO.js → KnowledgeHome-BWV1gz4f.js} +3 -3
- package/dist/renderer/assets/Logs-DqnanQTc.js +6 -0
- package/dist/renderer/assets/{Modal-CQiUpfl4.js → Modal-yY7TzR0x.js} +3 -3
- package/dist/renderer/assets/MonitorList-CIjGQkFs.js +1 -0
- package/dist/renderer/assets/Page-vwHNUdoj.js +1 -0
- package/dist/renderer/assets/{Select-D6z65IT3.js → Select-CmbK36pN.js} +2 -2
- package/dist/renderer/assets/ThreadChat-4OceMgM4.js +86 -0
- package/dist/renderer/assets/Workspace-DplPJOjJ.js +19 -0
- package/dist/renderer/assets/{arrow-left-CV5cL3f4.js → arrow-left-C8HfBt2K.js} +1 -1
- package/dist/renderer/assets/{book-open-DThvB7pj.js → book-open-BCdZWncQ.js} +1 -1
- package/dist/renderer/assets/channels-hgO3cAIx.js +6 -0
- package/dist/renderer/assets/chevron-down-BPk77tqY.js +11 -0
- package/dist/renderer/assets/index-BIKL3fTP.css +11 -0
- package/dist/renderer/assets/index-BlA4xPdd.js +41 -0
- package/dist/renderer/assets/index-wYpjqVqC.js +167 -0
- package/dist/renderer/assets/knowledge-7pl06KuH.js +1 -0
- package/dist/renderer/assets/{pencil-Dv5WxhdC.js → pencil-CB1SWZ9A.js} +1 -1
- package/dist/renderer/assets/{play-DnCnft83.js → play-BvsoXUrM.js} +1 -1
- package/dist/renderer/assets/{plus-DsxIagzS.js → plus-CokBDnaL.js} +1 -1
- package/dist/renderer/assets/{save-CST01lIc.js → save-D-w4kATO.js} +1 -1
- package/dist/renderer/assets/{search-B_bqy6Wd.js → search-Cnsn6i4Q.js} +1 -1
- package/dist/renderer/assets/{shield-check-D6lG5Aoc.js → shield-check-Cjja2Gh6.js} +1 -1
- package/dist/renderer/assets/threads-BCm6j4eI.js +1 -0
- package/dist/renderer/assets/{trash-2-Cefngb6Q.js → trash-2-CIxz9qYY.js} +1 -1
- package/dist/renderer/index.html +2 -2
- package/dist-electron/packages/contracts/src/automation.js +2 -0
- package/dist-electron/packages/contracts/src/channels.js +2 -0
- package/dist-electron/packages/contracts/src/knowledge.js +2 -0
- package/dist-electron/packages/contracts/src/local-core.js +15 -0
- package/dist-electron/packages/contracts/src/runtime.js +2 -0
- package/dist-electron/packages/contracts/src/scheduler.js +2 -0
- package/dist-electron/packages/contracts/src/threads.js +2 -0
- package/dist-electron/packages/core-sdk/src/automation.js +32 -0
- package/dist-electron/packages/core-sdk/src/channels.js +121 -0
- package/dist-electron/packages/core-sdk/src/client.js +455 -0
- package/dist-electron/packages/core-sdk/src/index.js +43 -607
- package/dist-electron/packages/core-sdk/src/knowledge.js +85 -0
- package/dist-electron/packages/core-sdk/src/request.js +22 -0
- package/dist-electron/packages/core-sdk/src/runtime.js +214 -0
- package/dist-electron/packages/core-sdk/src/scheduler.js +32 -0
- package/dist-electron/packages/core-sdk/src/threads.js +67 -0
- package/dist-electron/packages/plugin-sdk/src/agents.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/automation.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/channels.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/index.js +21 -0
- package/dist-electron/packages/plugin-sdk/src/knowledge.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/runtime.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/scheduler.js +2 -0
- package/dist-electron/packages/plugin-sdk/src/threads.js +2 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +5 -8
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +2 -2
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +3 -3
- package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +5 -5
- package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +12 -12
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +2 -2
- package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +11 -11
- package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +3 -3
- package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +7 -7
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +2 -2
- package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +3 -3
- package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +3 -3
- package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +2 -2
- package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +4 -4
- package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +2 -2
- package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +2 -2
- package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +3 -3
- package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +1 -1
- package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +4 -4
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +33 -18
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -2
- package/dist-electron/services/local-ai-core/src/channel/lark/gateway-utils.js +91 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/inbound-handler.js +180 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +52 -486
- package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +124 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
- package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +50 -469
- package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +156 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +100 -0
- package/dist-electron/services/local-ai-core/src/cli/lac.js +6 -6
- package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
- package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
- package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
- package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
- package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
- package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
- package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
- package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
- package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
- package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
- package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
- package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
- package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
- package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
- package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
- package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
- package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
- package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
- package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
- package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
- package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
- package/dist-electron/shared/desktop.js +1 -64
- package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
- package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
- package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
- package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
- package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
- package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
- package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
- package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
- package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
- package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
- package/dist-electron/tests/electron/core-client.test.js +284 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
- package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
- package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
- package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
- package/dist-electron/tests/integration/lark-gateway.test.js +4 -4
- package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
- package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
- package/package.json +9 -4
- package/dist/renderer/assets/Chat-C5Bkm9-M.js +0 -2
- package/dist/renderer/assets/ChatMarkdown-uc36EzyD.js +0 -45
- package/dist/renderer/assets/Config-DHtQuuLy.js +0 -21
- package/dist/renderer/assets/CronList-BYUnhzSC.js +0 -1
- package/dist/renderer/assets/Dashboard-BPnGMDg3.js +0 -26
- package/dist/renderer/assets/Logs-Dyd2Uwlt.js +0 -1
- package/dist/renderer/assets/MonitorList-Byg3E3Gt.js +0 -1
- package/dist/renderer/assets/Page-7DxXvTMm.js +0 -1
- package/dist/renderer/assets/ProjectDetail-Dfr5s0Ja.js +0 -11
- package/dist/renderer/assets/ProjectList-CDDQjAQ_.js +0 -1
- package/dist/renderer/assets/SessionChat-s7CAaCPL.js +0 -1
- package/dist/renderer/assets/SessionList-D-OycKKS.js +0 -1
- package/dist/renderer/assets/ThreadChat-CLdFynB5.js +0 -28
- package/dist/renderer/assets/Workspace-xfT5z4j_.js +0 -19
- package/dist/renderer/assets/bot-CWQ5-ovl.js +0 -6
- package/dist/renderer/assets/check-DKM7zfWG.js +0 -6
- package/dist/renderer/assets/chevron-down-Dfw2KU87.js +0 -6
- package/dist/renderer/assets/circle-CoP4RA4s.js +0 -6
- package/dist/renderer/assets/desktop-CsDYrOOU.js +0 -1
- package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
- package/dist/renderer/assets/funnel-DpVLlG3g.js +0 -6
- package/dist/renderer/assets/heart-BMD36ejP.js +0 -6
- package/dist/renderer/assets/index-COxSYBjE.js +0 -182
- package/dist/renderer/assets/index-CTGTI-cm.js +0 -41
- package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
- package/dist/renderer/assets/projects-DgjHcNgt.js +0 -1
- package/dist/renderer/assets/server-ecH4GNwa.js +0 -11
- package/dist/renderer/assets/session-utils-Dd_WKMYW.js +0 -6
- package/dist/renderer/assets/sessions-BQ33Mv4k.js +0 -1
- package/dist/renderer/assets/user-D_8RSH-T.js +0 -6
- package/dist/renderer/assets/wifi-off-DB9D-pOu.js +0 -11
- package/dist-electron/src/api/client.js +0 -73
- package/dist-electron/src/api/sessions.js +0 -21
- package/dist-electron/src/lib/session-utils.js +0 -51
- package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
- package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const client_js_1 = require("../../packages/core-sdk/src/client.js");
|
|
9
|
+
class FakeEventSource {
|
|
10
|
+
listeners = new Map();
|
|
11
|
+
onerror = null;
|
|
12
|
+
onopen = null;
|
|
13
|
+
closed = false;
|
|
14
|
+
addEventListener(type, listener) {
|
|
15
|
+
const listeners = this.listeners.get(type) || new Set();
|
|
16
|
+
listeners.add(listener);
|
|
17
|
+
this.listeners.set(type, listeners);
|
|
18
|
+
}
|
|
19
|
+
emit(type, payload) {
|
|
20
|
+
for (const listener of this.listeners.get(type) || []) {
|
|
21
|
+
listener({ data: typeof payload === 'string' ? payload : JSON.stringify(payload) });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
close() {
|
|
25
|
+
this.closed = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
(0, node_test_1.default)('core client shares one event source across subscribers and closes it after the last unsubscribe', () => {
|
|
29
|
+
const sources = [];
|
|
30
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
31
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1/',
|
|
32
|
+
eventSourceFactory: () => {
|
|
33
|
+
const source = new FakeEventSource();
|
|
34
|
+
sources.push(source);
|
|
35
|
+
return source;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
const first = client.events.subscribe(() => { });
|
|
39
|
+
const second = client.events.subscribe(() => { });
|
|
40
|
+
strict_1.default.equal(sources.length, 1);
|
|
41
|
+
strict_1.default.equal(client.baseUrl, 'http://127.0.0.1:9831/api/local/v1');
|
|
42
|
+
first();
|
|
43
|
+
strict_1.default.equal(sources[0].closed, false);
|
|
44
|
+
second();
|
|
45
|
+
strict_1.default.equal(sources[0].closed, true);
|
|
46
|
+
});
|
|
47
|
+
(0, node_test_1.default)('core clients with the same base URL share one event source across instances', () => {
|
|
48
|
+
const sources = [];
|
|
49
|
+
const firstClient = (0, client_js_1.createCoreClient)({
|
|
50
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1/',
|
|
51
|
+
eventSourceFactory: () => {
|
|
52
|
+
const source = new FakeEventSource();
|
|
53
|
+
sources.push(source);
|
|
54
|
+
return source;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const secondClient = (0, client_js_1.createCoreClient)({
|
|
58
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1',
|
|
59
|
+
eventSourceFactory: () => {
|
|
60
|
+
const source = new FakeEventSource();
|
|
61
|
+
sources.push(source);
|
|
62
|
+
return source;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const firstEventTypes = [];
|
|
66
|
+
const secondEventTypes = [];
|
|
67
|
+
const stopFirst = firstClient.events.subscribe((event) => firstEventTypes.push(event.type));
|
|
68
|
+
const stopSecond = secondClient.events.subscribe((event) => secondEventTypes.push(event.type));
|
|
69
|
+
strict_1.default.equal(sources.length, 1);
|
|
70
|
+
sources[0].emit('presence.updated', { type: 'presence.updated', live: true });
|
|
71
|
+
strict_1.default.deepEqual(firstEventTypes, ['presence.updated']);
|
|
72
|
+
strict_1.default.deepEqual(secondEventTypes, ['presence.updated']);
|
|
73
|
+
stopFirst();
|
|
74
|
+
strict_1.default.equal(sources[0].closed, false);
|
|
75
|
+
stopSecond();
|
|
76
|
+
strict_1.default.equal(sources[0].closed, true);
|
|
77
|
+
});
|
|
78
|
+
(0, node_test_1.default)('core client ignores malformed events and maps stream events to bridge subscribers', () => {
|
|
79
|
+
const source = new FakeEventSource();
|
|
80
|
+
const events = [];
|
|
81
|
+
const bridgeContents = [];
|
|
82
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
83
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1',
|
|
84
|
+
eventSourceFactory: () => source,
|
|
85
|
+
});
|
|
86
|
+
const stopEvents = client.events.subscribe((event) => events.push(event.type));
|
|
87
|
+
const stopBridge = client.events.subscribeBridge((event) => bridgeContents.push(event.content || ''));
|
|
88
|
+
source.emit('stream.updated', '{not-json');
|
|
89
|
+
source.emit('stream.updated', {
|
|
90
|
+
type: 'stream.updated',
|
|
91
|
+
stream: { type: 'reply', sessionKey: 'workspace:thread', content: 'done' },
|
|
92
|
+
});
|
|
93
|
+
strict_1.default.deepEqual(events, ['stream.updated']);
|
|
94
|
+
strict_1.default.deepEqual(bridgeContents, ['done']);
|
|
95
|
+
stopBridge();
|
|
96
|
+
stopEvents();
|
|
97
|
+
});
|
|
98
|
+
(0, node_test_1.default)('core client ignores valid JSON events that do not match the event contract', () => {
|
|
99
|
+
const source = new FakeEventSource();
|
|
100
|
+
const events = [];
|
|
101
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
102
|
+
baseUrl: 'http://127.0.0.1:9841/api/local/v1',
|
|
103
|
+
eventSourceFactory: () => source,
|
|
104
|
+
});
|
|
105
|
+
const stop = client.events.subscribe((event) => events.push(event.type));
|
|
106
|
+
source.emit('runtime.updated', { type: 'runtime.updated' });
|
|
107
|
+
source.emit('presence.updated', { type: 'presence.updated', live: 'yes' });
|
|
108
|
+
source.emit('stream.updated', { type: 'stream.updated', stream: { content: 'missing bridge type' } });
|
|
109
|
+
source.emit('presence.updated', { type: 'presence.updated', live: false });
|
|
110
|
+
strict_1.default.deepEqual(events, ['presence.updated']);
|
|
111
|
+
stop();
|
|
112
|
+
});
|
|
113
|
+
(0, node_test_1.default)('core client rejects events whose nested payload misses required contract fields', () => {
|
|
114
|
+
const source = new FakeEventSource();
|
|
115
|
+
const events = [];
|
|
116
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
117
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1',
|
|
118
|
+
eventSourceFactory: () => source,
|
|
119
|
+
});
|
|
120
|
+
const stop = client.events.subscribe((event) => events.push(event.type));
|
|
121
|
+
source.emit('run.updated', { type: 'run.updated', run: {} });
|
|
122
|
+
source.emit('message.created', { type: 'message.created', threadId: 'thread-1', message: {} });
|
|
123
|
+
source.emit('scheduler.run.updated', { type: 'scheduler.run.updated', run: { id: 'run-1' } });
|
|
124
|
+
source.emit('run.updated', {
|
|
125
|
+
type: 'run.updated',
|
|
126
|
+
run: {
|
|
127
|
+
id: 'run-1',
|
|
128
|
+
threadId: 'thread-1',
|
|
129
|
+
status: 'running',
|
|
130
|
+
startedAt: '2026-06-21T00:00:00.000Z',
|
|
131
|
+
updatedAt: '2026-06-21T00:00:01.000Z',
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
strict_1.default.deepEqual(events, ['run.updated']);
|
|
135
|
+
stop();
|
|
136
|
+
});
|
|
137
|
+
(0, node_test_1.default)('identical listener functions retain independent subscriptions', () => {
|
|
138
|
+
const source = new FakeEventSource();
|
|
139
|
+
let calls = 0;
|
|
140
|
+
const listener = () => {
|
|
141
|
+
calls += 1;
|
|
142
|
+
};
|
|
143
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
144
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1',
|
|
145
|
+
eventSourceFactory: () => source,
|
|
146
|
+
});
|
|
147
|
+
const stopFirst = client.events.subscribe(listener);
|
|
148
|
+
const stopSecond = client.events.subscribe(listener);
|
|
149
|
+
stopFirst();
|
|
150
|
+
strict_1.default.equal(source.closed, false);
|
|
151
|
+
source.emit('presence.updated', { type: 'presence.updated', live: true });
|
|
152
|
+
strict_1.default.equal(calls, 1);
|
|
153
|
+
stopSecond();
|
|
154
|
+
strict_1.default.equal(source.closed, true);
|
|
155
|
+
});
|
|
156
|
+
(0, node_test_1.default)('one failing event listener does not prevent other subscribers from receiving the event', () => {
|
|
157
|
+
const source = new FakeEventSource();
|
|
158
|
+
const events = [];
|
|
159
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
160
|
+
baseUrl: 'http://127.0.0.1:9844/api/local/v1',
|
|
161
|
+
eventSourceFactory: () => source,
|
|
162
|
+
});
|
|
163
|
+
const stopFailing = client.events.subscribe(() => {
|
|
164
|
+
throw new Error('listener failed');
|
|
165
|
+
});
|
|
166
|
+
const stopHealthy = client.events.subscribe((event) => events.push(event.type));
|
|
167
|
+
source.emit('presence.updated', { type: 'presence.updated', live: true });
|
|
168
|
+
strict_1.default.deepEqual(events, ['presence.updated']);
|
|
169
|
+
stopFailing();
|
|
170
|
+
stopHealthy();
|
|
171
|
+
});
|
|
172
|
+
(0, node_test_1.default)('core client schedules only one reconnect while an error is outstanding', () => {
|
|
173
|
+
const sources = [];
|
|
174
|
+
const reconnects = [];
|
|
175
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
176
|
+
baseUrl: 'http://127.0.0.1:9831/api/local/v1',
|
|
177
|
+
eventSourceFactory: () => {
|
|
178
|
+
const source = new FakeEventSource();
|
|
179
|
+
sources.push(source);
|
|
180
|
+
return source;
|
|
181
|
+
},
|
|
182
|
+
scheduleReconnect: (callback) => {
|
|
183
|
+
reconnects.push(callback);
|
|
184
|
+
return reconnects.length;
|
|
185
|
+
},
|
|
186
|
+
cancelReconnect: () => { },
|
|
187
|
+
});
|
|
188
|
+
const stop = client.events.subscribe(() => { });
|
|
189
|
+
sources[0].onerror?.();
|
|
190
|
+
sources[0].onerror?.();
|
|
191
|
+
strict_1.default.equal(reconnects.length, 1);
|
|
192
|
+
reconnects[0]();
|
|
193
|
+
strict_1.default.equal(sources.length, 2);
|
|
194
|
+
stop();
|
|
195
|
+
});
|
|
196
|
+
(0, node_test_1.default)('an obsolete event source cannot schedule another reconnect after replacement', () => {
|
|
197
|
+
const sources = [];
|
|
198
|
+
const reconnects = [];
|
|
199
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
200
|
+
baseUrl: 'http://127.0.0.1:9842/api/local/v1',
|
|
201
|
+
eventSourceFactory: () => {
|
|
202
|
+
const source = new FakeEventSource();
|
|
203
|
+
sources.push(source);
|
|
204
|
+
return source;
|
|
205
|
+
},
|
|
206
|
+
scheduleReconnect: (callback) => {
|
|
207
|
+
reconnects.push(callback);
|
|
208
|
+
return reconnects.length;
|
|
209
|
+
},
|
|
210
|
+
cancelReconnect: () => { },
|
|
211
|
+
});
|
|
212
|
+
const stop = client.events.subscribe(() => { });
|
|
213
|
+
sources[0].onerror?.();
|
|
214
|
+
reconnects[0]();
|
|
215
|
+
sources[0].onerror?.();
|
|
216
|
+
strict_1.default.equal(reconnects.length, 1);
|
|
217
|
+
stop();
|
|
218
|
+
});
|
|
219
|
+
(0, node_test_1.default)('core client reports reconnect so consumers can recover missed state', () => {
|
|
220
|
+
const sources = [];
|
|
221
|
+
const reconnects = [];
|
|
222
|
+
const states = [];
|
|
223
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
224
|
+
baseUrl: 'http://127.0.0.1:9845/api/local/v1',
|
|
225
|
+
eventSourceFactory: () => {
|
|
226
|
+
const source = new FakeEventSource();
|
|
227
|
+
sources.push(source);
|
|
228
|
+
return source;
|
|
229
|
+
},
|
|
230
|
+
scheduleReconnect: (callback) => {
|
|
231
|
+
reconnects.push(callback);
|
|
232
|
+
return reconnects.length;
|
|
233
|
+
},
|
|
234
|
+
cancelReconnect: () => { },
|
|
235
|
+
});
|
|
236
|
+
const stop = client.events.subscribeConnectionState((state) => states.push(state));
|
|
237
|
+
sources[0].onopen?.();
|
|
238
|
+
sources[0].onerror?.();
|
|
239
|
+
reconnects[0]();
|
|
240
|
+
sources[1].onopen?.();
|
|
241
|
+
strict_1.default.deepEqual(states, ['connected', 'disconnected', 'connected']);
|
|
242
|
+
stop();
|
|
243
|
+
strict_1.default.equal(sources[1].closed, true);
|
|
244
|
+
});
|
|
245
|
+
(0, node_test_1.default)('core client rejects partially populated scheduler and automation payloads', () => {
|
|
246
|
+
const source = new FakeEventSource();
|
|
247
|
+
const events = [];
|
|
248
|
+
const client = (0, client_js_1.createCoreClient)({
|
|
249
|
+
baseUrl: 'http://127.0.0.1:9843/api/local/v1',
|
|
250
|
+
eventSourceFactory: () => source,
|
|
251
|
+
});
|
|
252
|
+
const stop = client.events.subscribe((event) => events.push(event.type));
|
|
253
|
+
source.emit('scheduler.job.updated', {
|
|
254
|
+
type: 'scheduler.job.updated',
|
|
255
|
+
job: {
|
|
256
|
+
id: 'job-1',
|
|
257
|
+
workspaceId: 'workspace-1',
|
|
258
|
+
platform: 'local',
|
|
259
|
+
triggerType: 'cron',
|
|
260
|
+
promptTemplate: 'run',
|
|
261
|
+
enabled: true,
|
|
262
|
+
createdAt: '',
|
|
263
|
+
updatedAt: '',
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
source.emit('automation.monitor.updated', {
|
|
267
|
+
type: 'automation.monitor.updated',
|
|
268
|
+
monitor: {
|
|
269
|
+
id: 'monitor-1',
|
|
270
|
+
workspaceId: 'workspace-1',
|
|
271
|
+
title: 'price',
|
|
272
|
+
sourceType: 'stock.quote',
|
|
273
|
+
sourceConfig: {},
|
|
274
|
+
condition: {},
|
|
275
|
+
promptTemplate: 'analyze',
|
|
276
|
+
enabled: true,
|
|
277
|
+
cooldownMs: 1000,
|
|
278
|
+
createdAt: '',
|
|
279
|
+
updatedAt: '',
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
strict_1.default.deepEqual(events, []);
|
|
283
|
+
stop();
|
|
284
|
+
});
|
|
@@ -1021,6 +1021,60 @@ model = "deepseek-v4-flash"
|
|
|
1021
1021
|
strict_1.default.match(response.body.error, /Unknown route/);
|
|
1022
1022
|
strict_1.default.equal(response.body.errorInfo?.severity, 'error');
|
|
1023
1023
|
});
|
|
1024
|
+
(0, node_test_1.default)('server rejects malformed endpoint input with a 400 response before domain dispatch', async () => {
|
|
1025
|
+
let dispatched = false;
|
|
1026
|
+
const controller = new node_events_1.EventEmitter();
|
|
1027
|
+
const workspaceRouter = {
|
|
1028
|
+
createThread: async () => {
|
|
1029
|
+
dispatched = true;
|
|
1030
|
+
return {};
|
|
1031
|
+
},
|
|
1032
|
+
};
|
|
1033
|
+
const server = new server_js_1.LocalAiCoreServer({ controller, workspaceRouter }, { port: 0 });
|
|
1034
|
+
const response = await invokeServer(server, 'POST', '/api/local/v1/threads', { workspaceId: 42 });
|
|
1035
|
+
strict_1.default.equal(response.statusCode, 400);
|
|
1036
|
+
strict_1.default.equal(response.body.ok, false);
|
|
1037
|
+
strict_1.default.match(response.body.error, /workspaceId/);
|
|
1038
|
+
strict_1.default.equal(dispatched, false);
|
|
1039
|
+
const emptyResponse = await invokeServer(server, 'POST', '/api/local/v1/threads', { workspaceId: ' ' });
|
|
1040
|
+
strict_1.default.equal(emptyResponse.statusCode, 400);
|
|
1041
|
+
strict_1.default.match(emptyResponse.body.error, /workspaceId/);
|
|
1042
|
+
strict_1.default.equal(dispatched, false);
|
|
1043
|
+
});
|
|
1044
|
+
(0, node_test_1.default)('server validates the actual desktop settings contract before dispatch', async () => {
|
|
1045
|
+
let dispatched = false;
|
|
1046
|
+
const controller = new node_events_1.EventEmitter();
|
|
1047
|
+
controller.saveSettings = async () => {
|
|
1048
|
+
dispatched = true;
|
|
1049
|
+
return {};
|
|
1050
|
+
};
|
|
1051
|
+
const server = new server_js_1.LocalAiCoreServer({ controller }, { port: 0 });
|
|
1052
|
+
const invalidKnowledge = await invokeServer(server, 'POST', '/api/local/v1/runtime/settings', { knowledge: 42 });
|
|
1053
|
+
strict_1.default.equal(invalidKnowledge.statusCode, 400);
|
|
1054
|
+
strict_1.default.match(invalidKnowledge.body.error, /knowledge/);
|
|
1055
|
+
const invalidPlugins = await invokeServer(server, 'POST', '/api/local/v1/runtime/settings', { plugins: [] });
|
|
1056
|
+
strict_1.default.equal(invalidPlugins.statusCode, 400);
|
|
1057
|
+
strict_1.default.match(invalidPlugins.body.error, /plugins/);
|
|
1058
|
+
const invalidPluginSettings = await invokeServer(server, 'POST', '/api/local/v1/runtime/settings', {
|
|
1059
|
+
plugins: { 'channel.lark': { enabled: 'yes' } },
|
|
1060
|
+
});
|
|
1061
|
+
strict_1.default.equal(invalidPluginSettings.statusCode, 400);
|
|
1062
|
+
strict_1.default.match(invalidPluginSettings.body.error, /plugins\.channel\.lark\.enabled/);
|
|
1063
|
+
const invalidAuthMode = await invokeServer(server, 'POST', '/api/local/v1/runtime/settings', {
|
|
1064
|
+
knowledge: { authMode: 'cookie' },
|
|
1065
|
+
});
|
|
1066
|
+
strict_1.default.equal(invalidAuthMode.statusCode, 400);
|
|
1067
|
+
strict_1.default.match(invalidAuthMode.body.error, /knowledge\.authMode/);
|
|
1068
|
+
strict_1.default.equal(dispatched, false);
|
|
1069
|
+
const valid = await invokeServer(server, 'POST', '/api/local/v1/runtime/settings', {
|
|
1070
|
+
autoStartService: true,
|
|
1071
|
+
defaultProject: 'workspace-stable',
|
|
1072
|
+
knowledge: { authMode: 'bearer', token: 'secret' },
|
|
1073
|
+
plugins: { 'channel.lark': { enabled: true, config: { appId: 'app-id' } } },
|
|
1074
|
+
});
|
|
1075
|
+
strict_1.default.equal(valid.statusCode, 200);
|
|
1076
|
+
strict_1.default.equal(dispatched, true);
|
|
1077
|
+
});
|
|
1024
1078
|
(0, node_test_1.default)('server diagnostics routes dispatch through generic bindings', async () => {
|
|
1025
1079
|
const calls = [];
|
|
1026
1080
|
const controller = Object.assign(new node_events_1.EventEmitter(), {
|
|
@@ -31,6 +31,15 @@ const rootDir = node_process_1.default.cwd();
|
|
|
31
31
|
strict_1.default.ok(buildIndex >= 0, 'pnpm e2e:smoke must start from a production build');
|
|
32
32
|
strict_1.default.ok(smokeIndex > buildIndex, 'pnpm e2e:smoke must run smoke checks after the production build');
|
|
33
33
|
});
|
|
34
|
+
(0, node_test_1.default)('development startup rewrites workspace aliases before launching Electron', () => {
|
|
35
|
+
const devScript = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, 'scripts', 'dev.mjs'), 'utf8');
|
|
36
|
+
const aliasCommandIndex = devScript.indexOf("['exec', 'tsc-alias', '-p', 'tsconfig.electron.json']");
|
|
37
|
+
const readyAssignmentIndex = devScript.indexOf('electronReady = true', aliasCommandIndex);
|
|
38
|
+
const launchIndex = devScript.indexOf('maybeLaunchElectron()', readyAssignmentIndex);
|
|
39
|
+
strict_1.default.ok(aliasCommandIndex >= 0, 'pnpm dev must rewrite emitted @cc/* aliases');
|
|
40
|
+
strict_1.default.ok(readyAssignmentIndex > aliasCommandIndex, 'Electron must become ready only after alias rewriting is configured');
|
|
41
|
+
strict_1.default.ok(launchIndex > readyAssignmentIndex, 'Electron must launch only after alias rewriting completes');
|
|
42
|
+
});
|
|
34
43
|
(0, node_test_1.default)('production renderer build has a loadable entry document and assets', () => {
|
|
35
44
|
const rendererDir = (0, node_path_1.join)(rootDir, 'dist', 'renderer');
|
|
36
45
|
const indexPath = (0, node_path_1.join)(rendererDir, 'index.html');
|
|
@@ -42,6 +42,37 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
42
42
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
|
+
(0, node_test_1.default)('runtime project migration makes workspace registry authoritative and preserves identity across rename', async () => {
|
|
46
|
+
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'workspace-project-migration-'));
|
|
47
|
+
try {
|
|
48
|
+
const runtime = (0, bootstrap_js_1.bootstrapLocalCoreRuntime)({ userDataPath, enableKnowledge: false, log: () => { } });
|
|
49
|
+
const controller = new local_core_controller_js_1.LocalCoreController(userDataPath, runtime);
|
|
50
|
+
await controller.saveRuntimeConfig({
|
|
51
|
+
projects: [{
|
|
52
|
+
name: 'Workspace A',
|
|
53
|
+
agent: { type: 'pi', options: { work_dir: '/tmp/workspace-a' } },
|
|
54
|
+
platforms: [],
|
|
55
|
+
}],
|
|
56
|
+
});
|
|
57
|
+
const first = await controller.readRuntimeConfig();
|
|
58
|
+
const workspaceId = first.config.projects?.[0]?.workspace_id;
|
|
59
|
+
strict_1.default.ok(workspaceId);
|
|
60
|
+
strict_1.default.equal(controller.store.getWorkspaceRegistryEntry(workspaceId)?.displayName, 'Workspace A');
|
|
61
|
+
strict_1.default.equal(controller.store.readRuntimeConfig().config.projects, undefined);
|
|
62
|
+
await controller.saveRuntimeConfig({
|
|
63
|
+
...first.config,
|
|
64
|
+
projects: [{ ...first.config.projects[0], name: 'Workspace B' }],
|
|
65
|
+
});
|
|
66
|
+
const renamed = await controller.readRuntimeConfig();
|
|
67
|
+
strict_1.default.equal(renamed.config.projects?.[0]?.workspace_id, workspaceId);
|
|
68
|
+
strict_1.default.equal(controller.store.getWorkspaceRegistryEntry(workspaceId)?.displayName, 'Workspace B');
|
|
69
|
+
strict_1.default.equal((await controller.workspaceRouter.listWorkspaces())[0]?.id, workspaceId);
|
|
70
|
+
await controller.close();
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
74
|
+
}
|
|
75
|
+
});
|
|
45
76
|
(0, node_test_1.default)('model providers persist independently from workspace config', () => {
|
|
46
77
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'model-provider-store-'));
|
|
47
78
|
try {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const inbound_authorization_js_1 = require("../../services/local-ai-core/src/channel/shared/inbound-authorization.js");
|
|
9
|
+
function createStore() {
|
|
10
|
+
const authorizedUsers = [];
|
|
11
|
+
const pairings = [];
|
|
12
|
+
return {
|
|
13
|
+
authorizedUsers,
|
|
14
|
+
pairings,
|
|
15
|
+
store: {
|
|
16
|
+
expirePendingPairings() { },
|
|
17
|
+
getAuthorizedUser(workspaceId, platformUserId, platform) {
|
|
18
|
+
return authorizedUsers.find((row) => row.workspace_id === workspaceId &&
|
|
19
|
+
row.platform_user_id === platformUserId &&
|
|
20
|
+
row.platform === platform);
|
|
21
|
+
},
|
|
22
|
+
createAuthorizedUser(input) {
|
|
23
|
+
authorizedUsers.push(input);
|
|
24
|
+
},
|
|
25
|
+
listPendingPairings() {
|
|
26
|
+
return pairings;
|
|
27
|
+
},
|
|
28
|
+
createPairingRequest(input) {
|
|
29
|
+
pairings.push(input);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const identity = {
|
|
35
|
+
workspaceId: 'workspace-1',
|
|
36
|
+
platformKey: 'lark:default',
|
|
37
|
+
platformUserId: 'user-1',
|
|
38
|
+
chatId: 'chat-1',
|
|
39
|
+
displayName: 'User One',
|
|
40
|
+
};
|
|
41
|
+
(0, node_test_1.default)('shared inbound authorization auto-approves and returns the stored user', () => {
|
|
42
|
+
const fixture = createStore();
|
|
43
|
+
let changes = 0;
|
|
44
|
+
const result = (0, inbound_authorization_js_1.resolveInboundChannelAuthorization)({
|
|
45
|
+
store: fixture.store,
|
|
46
|
+
identity,
|
|
47
|
+
autoApprove: true,
|
|
48
|
+
authorizedUserIdPrefix: 'lark-user',
|
|
49
|
+
generatePairingCode: () => '123456',
|
|
50
|
+
onStateChanged: () => { changes += 1; },
|
|
51
|
+
});
|
|
52
|
+
strict_1.default.equal(result.status, 'authorized');
|
|
53
|
+
strict_1.default.equal(fixture.authorizedUsers.length, 1);
|
|
54
|
+
strict_1.default.equal(changes, 1);
|
|
55
|
+
});
|
|
56
|
+
(0, node_test_1.default)('shared inbound authorization reuses an existing pending pairing', () => {
|
|
57
|
+
const fixture = createStore();
|
|
58
|
+
fixture.pairings.push({
|
|
59
|
+
code: '654321',
|
|
60
|
+
workspace_id: 'workspace-1',
|
|
61
|
+
platform: 'lark:default',
|
|
62
|
+
platform_user_id: 'user-1',
|
|
63
|
+
chat_id: 'chat-1',
|
|
64
|
+
status: 'pending',
|
|
65
|
+
});
|
|
66
|
+
let generated = 0;
|
|
67
|
+
const result = (0, inbound_authorization_js_1.resolveInboundChannelAuthorization)({
|
|
68
|
+
store: fixture.store,
|
|
69
|
+
identity,
|
|
70
|
+
autoApprove: false,
|
|
71
|
+
authorizedUserIdPrefix: 'lark-user',
|
|
72
|
+
generatePairingCode: () => {
|
|
73
|
+
generated += 1;
|
|
74
|
+
return '123456';
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
strict_1.default.deepEqual(result, { status: 'pending', pairingCode: '654321' });
|
|
78
|
+
strict_1.default.equal(generated, 0);
|
|
79
|
+
strict_1.default.equal(fixture.pairings.length, 1);
|
|
80
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const gateway_utils_js_1 = require("../../services/local-ai-core/src/channel/lark/gateway-utils.js");
|
|
9
|
+
(0, node_test_1.default)('lark gateway attachment utilities preserve content summaries and mime detection', () => {
|
|
10
|
+
strict_1.default.equal((0, gateway_utils_js_1.summarizeLarkInboundContentParts)([{ type: 'file', fileName: 'report.pdf' }]), '[File: report.pdf]');
|
|
11
|
+
strict_1.default.equal((0, gateway_utils_js_1.extractLarkHeaderMimeType)({ 'Content-Type': 'image/png; charset=binary' }), 'image/png');
|
|
12
|
+
strict_1.default.equal((0, gateway_utils_js_1.sniffLarkImageExtension)(Buffer.from([0x89, 0x50, 0x4e, 0x47])), 'png');
|
|
13
|
+
});
|
|
@@ -1265,7 +1265,7 @@ function findLarkPostMdText(content) {
|
|
|
1265
1265
|
});
|
|
1266
1266
|
strict_1.default.equal(sentMessages.length, 1);
|
|
1267
1267
|
strict_1.default.equal(sentMessages[0]?.threadId, 'thread-1');
|
|
1268
|
-
strict_1.default.
|
|
1268
|
+
strict_1.default.equal(sentMessages[0]?.content?.displayText, '[Image]');
|
|
1269
1269
|
strict_1.default.deepEqual(sentMessages[0]?.content?.contentParts?.map((part) => part.type), ['text', 'image']);
|
|
1270
1270
|
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.mimeType, 'image/png');
|
|
1271
1271
|
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.data, pngBytes.toString('base64'));
|
|
@@ -1366,7 +1366,7 @@ function findLarkPostMdText(content) {
|
|
|
1366
1366
|
});
|
|
1367
1367
|
strict_1.default.equal(sentMessages.length, 1);
|
|
1368
1368
|
strict_1.default.equal(sentMessages[0]?.threadId, 'thread-1');
|
|
1369
|
-
strict_1.default.
|
|
1369
|
+
strict_1.default.equal(sentMessages[0]?.content?.displayText, '[File: report.pdf]');
|
|
1370
1370
|
strict_1.default.deepEqual(sentMessages[0]?.content?.contentParts?.map((part) => part.type), ['text', 'file']);
|
|
1371
1371
|
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.mimeType, 'application/pdf');
|
|
1372
1372
|
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.data, undefined);
|
|
@@ -1494,7 +1494,7 @@ function findLarkPostMdText(content) {
|
|
|
1494
1494
|
});
|
|
1495
1495
|
strict_1.default.equal(sentMessages.length, 1);
|
|
1496
1496
|
strict_1.default.equal(sentMessages[0]?.threadId, 'thread-1');
|
|
1497
|
-
strict_1.default.
|
|
1497
|
+
strict_1.default.equal(sentMessages[0]?.content, 'ask @张三 to review');
|
|
1498
1498
|
});
|
|
1499
1499
|
(0, node_test_1.default)('lark group text messages ignore non-mentioned bot messages by default', async () => {
|
|
1500
1500
|
const sentMessages = [];
|
|
@@ -1620,7 +1620,7 @@ function findLarkPostMdText(content) {
|
|
|
1620
1620
|
});
|
|
1621
1621
|
strict_1.default.equal(sentMessages.length, 1);
|
|
1622
1622
|
strict_1.default.equal(sentMessages[0]?.threadId, 'thread-1');
|
|
1623
|
-
strict_1.default.
|
|
1623
|
+
strict_1.default.equal(sentMessages[0]?.content, '1. hi\n2. hello');
|
|
1624
1624
|
});
|
|
1625
1625
|
(0, node_test_1.default)('lark inbound messages create a chat binding when an authorized user has an old direct thread', async () => {
|
|
1626
1626
|
const bindings = [];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const runtime_state_js_1 = require("../../services/local-ai-core/src/channel/weixin/runtime-state.js");
|
|
9
|
+
(0, node_test_1.default)('weixin turn state keeps thought, tool progress, and final reply ordered', () => {
|
|
10
|
+
const turn = (0, runtime_state_js_1.createWeixinTurnState)('workspace:thread');
|
|
11
|
+
(0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, { type: 'typing_start', sessionKey: turn.sessionKey });
|
|
12
|
+
(0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, { type: 'update_message', sessionKey: turn.sessionKey, bridgeKind: 'thought', content: 'Inspecting' });
|
|
13
|
+
(0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, { type: 'reply', sessionKey: turn.sessionKey, bridgeKind: 'tool', content: 'Search - running' });
|
|
14
|
+
const finalEvent = { type: 'reply', sessionKey: turn.sessionKey, bridgeKind: 'assistant', content: 'Done' };
|
|
15
|
+
(0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, finalEvent);
|
|
16
|
+
const rendered = (0, runtime_state_js_1.renderWeixinTurnText)(turn);
|
|
17
|
+
strict_1.default.match(rendered, /Inspecting/);
|
|
18
|
+
strict_1.default.match(rendered, /Done/);
|
|
19
|
+
strict_1.default.equal((0, runtime_state_js_1.isTerminalWeixinBridgeMessage)(finalEvent, rendered), true);
|
|
20
|
+
});
|
|
21
|
+
(0, node_test_1.default)('weixin permission events remain terminal and render fallback actions', () => {
|
|
22
|
+
const turn = (0, runtime_state_js_1.createWeixinTurnState)('workspace:thread');
|
|
23
|
+
const event = {
|
|
24
|
+
type: 'buttons',
|
|
25
|
+
sessionKey: turn.sessionKey,
|
|
26
|
+
buttonRows: [[{ text: 'Allow', data: 'allow' }]],
|
|
27
|
+
};
|
|
28
|
+
(0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, event);
|
|
29
|
+
const rendered = (0, runtime_state_js_1.renderWeixinTurnText)(turn);
|
|
30
|
+
strict_1.default.match(rendered, /allow all/);
|
|
31
|
+
strict_1.default.equal((0, runtime_state_js_1.isTerminalWeixinBridgeMessage)(event, rendered), true);
|
|
32
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const text_utils_js_1 = require("../../services/local-ai-core/src/channel/weixin/text-utils.js");
|
|
9
|
+
(0, node_test_1.default)('weixin text utilities preserve utf8 boundaries and decode simple html', () => {
|
|
10
|
+
strict_1.default.equal((0, text_utils_js_1.stripWeixinHtml)('<p>A&B</p>'), 'A&B');
|
|
11
|
+
const chunks = (0, text_utils_js_1.splitTextByUtf8Bytes)('你好世界', 6);
|
|
12
|
+
strict_1.default.deepEqual(chunks, ['你好', '世界']);
|
|
13
|
+
strict_1.default.ok(chunks.every((chunk) => (0, text_utils_js_1.utf8ByteLength)(chunk) <= 6));
|
|
14
|
+
strict_1.default.ok((0, text_utils_js_1.utf8ByteLength)((0, text_utils_js_1.truncateTextByUtf8Bytes)('很长的内容'.repeat(20), 80)) <= 80);
|
|
15
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kafca/agentdock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.57",
|
|
4
4
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist-electron/electron/main.js",
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
"dev": "node scripts/dev.mjs",
|
|
27
27
|
"dev:web": "pnpm exec vite --host 127.0.0.1 --port 5173",
|
|
28
28
|
"dev:core": "pnpm build:electron && node scripts/launch-core.mjs",
|
|
29
|
-
"build": "vite build && node scripts/write-electron-package.mjs && tsc -p tsconfig.electron.json",
|
|
29
|
+
"build": "vite build && node scripts/write-electron-package.mjs && tsc -p tsconfig.electron.json && tsc-alias -p tsconfig.electron.json",
|
|
30
30
|
"build:npm": "VITE_LOCAL_AI_CORE_BASE=/api/local/v1 pnpm build",
|
|
31
31
|
"build:web": "vite build",
|
|
32
32
|
"build:renderer": "vite build",
|
|
33
|
-
"build:electron": "node scripts/write-electron-package.mjs && tsc -p tsconfig.electron.json",
|
|
33
|
+
"build:electron": "node scripts/write-electron-package.mjs && tsc -p tsconfig.electron.json && tsc-alias -p tsconfig.electron.json",
|
|
34
34
|
"build:core": "pnpm build:electron",
|
|
35
|
-
"
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
+
"test": "pnpm typecheck && pnpm build:renderer && pnpm build:electron && node --test dist-electron/tests/electron/*.test.js dist-electron/tests/contracts/*.test.js dist-electron/tests/integration/*.test.js dist-electron/packages/knowledge-api/test/*.test.js dist-electron/src/pages/Threads/thread-chat-permission.test.js",
|
|
36
37
|
"e2e:smoke": "pnpm build && node scripts/e2e-smoke.mjs",
|
|
37
38
|
"e2e:compose": "node scripts/e2e-compose.mjs",
|
|
38
39
|
"dist:mac": "pnpm build && electron-builder --mac dmg zip --arm64",
|
|
@@ -45,6 +46,9 @@
|
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"@agentclientprotocol/claude-agent-acp": "^0.30.0",
|
|
49
|
+
"@cc/core-sdk": "workspace:*",
|
|
50
|
+
"@cc/plugin-sdk": "workspace:*",
|
|
51
|
+
"@cc/superai-contracts": "workspace:*",
|
|
48
52
|
"@iarna/toml": "^2.2.5",
|
|
49
53
|
"@larksuiteoapi/node-sdk": "^1.58.0",
|
|
50
54
|
"@mariozechner/pi-coding-agent": "^0.72.1",
|
|
@@ -78,6 +82,7 @@
|
|
|
78
82
|
"electron-builder": "^26.8.1",
|
|
79
83
|
"postcss": "^8.5.3",
|
|
80
84
|
"tailwindcss": "^3.4.17",
|
|
85
|
+
"tsc-alias": "^1.8.17",
|
|
81
86
|
"typescript": "~5.8.3",
|
|
82
87
|
"vite": "^6.3.2"
|
|
83
88
|
},
|