@kafca/agentdock 0.1.55 → 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.
Files changed (185) hide show
  1. package/README.md +14 -0
  2. package/dist/renderer/assets/{Badge-Bg_nNvBL.js → Badge-CDTbmw1h.js} +1 -1
  3. package/dist/renderer/assets/Card-DayUo35w.js +1 -0
  4. package/dist/renderer/assets/Config-ByGMQuzR.js +21 -0
  5. package/dist/renderer/assets/CronList-XqHdVlgu.js +1 -0
  6. package/dist/renderer/assets/Dashboard-CZj-oANw.js +41 -0
  7. package/dist/renderer/assets/{EmptyState-C60g3RMj.js → EmptyState-EFMkOjZO.js} +1 -1
  8. package/dist/renderer/assets/HighlightedMarkdown-DyvF3DHK.js +12 -0
  9. package/dist/renderer/assets/Input-DxoWVc9d.js +1 -0
  10. package/dist/renderer/assets/{KnowledgeDetail-CC5C7JYe.js → KnowledgeDetail-CbUb2tG7.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-3rlvxgWf.js → KnowledgeHome-BWV1gz4f.js} +3 -3
  12. package/dist/renderer/assets/Logs-DqnanQTc.js +6 -0
  13. package/dist/renderer/assets/{Modal-BQUW9LSf.js → Modal-yY7TzR0x.js} +3 -3
  14. package/dist/renderer/assets/MonitorList-CIjGQkFs.js +1 -0
  15. package/dist/renderer/assets/Page-vwHNUdoj.js +1 -0
  16. package/dist/renderer/assets/{Select-CfRkos3z.js → Select-CmbK36pN.js} +2 -2
  17. package/dist/renderer/assets/ThreadChat-4OceMgM4.js +86 -0
  18. package/dist/renderer/assets/Workspace-DplPJOjJ.js +19 -0
  19. package/dist/renderer/assets/{arrow-left-D1DbXrLA.js → arrow-left-C8HfBt2K.js} +1 -1
  20. package/dist/renderer/assets/{book-open-BxC1z1C1.js → book-open-BCdZWncQ.js} +1 -1
  21. package/dist/renderer/assets/channels-hgO3cAIx.js +6 -0
  22. package/dist/renderer/assets/chevron-down-BPk77tqY.js +11 -0
  23. package/dist/renderer/assets/index-BIKL3fTP.css +11 -0
  24. package/dist/renderer/assets/index-BlA4xPdd.js +41 -0
  25. package/dist/renderer/assets/index-wYpjqVqC.js +167 -0
  26. package/dist/renderer/assets/knowledge-7pl06KuH.js +1 -0
  27. package/dist/renderer/assets/{pencil-X44UaxwR.js → pencil-CB1SWZ9A.js} +1 -1
  28. package/dist/renderer/assets/{play-ujo-De38.js → play-BvsoXUrM.js} +1 -1
  29. package/dist/renderer/assets/{plus-BHgVdG_A.js → plus-CokBDnaL.js} +1 -1
  30. package/dist/renderer/assets/{save-Cz6giKrE.js → save-D-w4kATO.js} +1 -1
  31. package/dist/renderer/assets/{search-DKWvTqi5.js → search-Cnsn6i4Q.js} +1 -1
  32. package/dist/renderer/assets/{shield-check-V82O8AC1.js → shield-check-Cjja2Gh6.js} +1 -1
  33. package/dist/renderer/assets/threads-BCm6j4eI.js +1 -0
  34. package/dist/renderer/assets/{trash-2-_Fgwk8mc.js → trash-2-CIxz9qYY.js} +1 -1
  35. package/dist/renderer/index.html +2 -2
  36. package/dist-electron/packages/contracts/src/automation.js +2 -0
  37. package/dist-electron/packages/contracts/src/channels.js +2 -0
  38. package/dist-electron/packages/contracts/src/knowledge.js +2 -0
  39. package/dist-electron/packages/contracts/src/local-core.js +15 -0
  40. package/dist-electron/packages/contracts/src/runtime.js +2 -0
  41. package/dist-electron/packages/contracts/src/scheduler.js +2 -0
  42. package/dist-electron/packages/contracts/src/threads.js +2 -0
  43. package/dist-electron/packages/core-sdk/src/automation.js +32 -0
  44. package/dist-electron/packages/core-sdk/src/channels.js +121 -0
  45. package/dist-electron/packages/core-sdk/src/client.js +455 -0
  46. package/dist-electron/packages/core-sdk/src/index.js +43 -607
  47. package/dist-electron/packages/core-sdk/src/knowledge.js +85 -0
  48. package/dist-electron/packages/core-sdk/src/request.js +22 -0
  49. package/dist-electron/packages/core-sdk/src/runtime.js +214 -0
  50. package/dist-electron/packages/core-sdk/src/scheduler.js +32 -0
  51. package/dist-electron/packages/core-sdk/src/threads.js +67 -0
  52. package/dist-electron/packages/plugin-sdk/src/agents.js +2 -0
  53. package/dist-electron/packages/plugin-sdk/src/automation.js +2 -0
  54. package/dist-electron/packages/plugin-sdk/src/channels.js +2 -0
  55. package/dist-electron/packages/plugin-sdk/src/index.js +21 -0
  56. package/dist-electron/packages/plugin-sdk/src/knowledge.js +2 -0
  57. package/dist-electron/packages/plugin-sdk/src/runtime.js +2 -0
  58. package/dist-electron/packages/plugin-sdk/src/scheduler.js +2 -0
  59. package/dist-electron/packages/plugin-sdk/src/threads.js +2 -0
  60. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +6 -9
  61. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +2 -2
  62. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +3 -3
  63. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +5 -5
  64. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +12 -12
  65. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +2 -2
  66. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +11 -11
  67. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +3 -3
  68. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +7 -7
  69. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +2 -2
  70. package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +3 -3
  71. package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +3 -3
  72. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +2 -2
  73. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +4 -4
  74. package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +2 -2
  75. package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +2 -2
  76. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +3 -3
  77. package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +1 -1
  78. package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +4 -4
  79. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +33 -18
  80. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -2
  81. package/dist-electron/services/local-ai-core/src/channel/lark/gateway-utils.js +91 -0
  82. package/dist-electron/services/local-ai-core/src/channel/lark/inbound-handler.js +180 -0
  83. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +52 -456
  84. package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +124 -0
  85. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-attachment-store.js +93 -0
  86. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
  87. package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
  88. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
  89. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
  90. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +98 -483
  91. package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +156 -0
  92. package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +100 -0
  93. package/dist-electron/services/local-ai-core/src/cli/lac.js +6 -6
  94. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
  95. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
  96. package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +33 -5
  97. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
  98. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
  99. package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
  100. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
  101. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
  102. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
  103. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
  104. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
  105. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
  106. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
  107. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
  108. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
  109. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
  110. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
  111. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
  112. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
  113. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
  114. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
  115. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
  116. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
  117. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
  118. package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
  119. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
  120. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
  121. package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
  122. package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
  123. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
  124. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
  125. package/dist-electron/shared/desktop.js +1 -64
  126. package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
  127. package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
  128. package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
  129. package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
  130. package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
  131. package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
  132. package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
  133. package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
  134. package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
  135. package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
  136. package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
  137. package/dist-electron/tests/electron/core-client.test.js +284 -0
  138. package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
  139. package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
  140. package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
  141. package/dist-electron/tests/integration/channel-inbound-attachment-store.test.js +117 -0
  142. package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
  143. package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
  144. package/dist-electron/tests/integration/lark-gateway.test.js +58 -4
  145. package/dist-electron/tests/integration/local-core-errors.test.js +41 -0
  146. package/dist-electron/tests/integration/weixin-gateway.test.js +36 -0
  147. package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
  148. package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
  149. package/package.json +9 -4
  150. package/dist/renderer/assets/Chat-BJveQQKu.js +0 -2
  151. package/dist/renderer/assets/ChatMarkdown-Bqn2HJ6f.js +0 -45
  152. package/dist/renderer/assets/Config-CMtZDRAE.js +0 -21
  153. package/dist/renderer/assets/CronList-C-ILB_Ae.js +0 -1
  154. package/dist/renderer/assets/Dashboard-CsKBSQIe.js +0 -26
  155. package/dist/renderer/assets/Logs-CktemGN0.js +0 -1
  156. package/dist/renderer/assets/MonitorList-B0hxjuOZ.js +0 -1
  157. package/dist/renderer/assets/Page-DL_Nv2i5.js +0 -1
  158. package/dist/renderer/assets/ProjectDetail-Djr9-MyT.js +0 -11
  159. package/dist/renderer/assets/ProjectList-BKl4eW7q.js +0 -1
  160. package/dist/renderer/assets/SessionChat-Dxv8D5DW.js +0 -1
  161. package/dist/renderer/assets/SessionList-BJ2GjXvR.js +0 -1
  162. package/dist/renderer/assets/ThreadChat-CAsIl9qf.js +0 -28
  163. package/dist/renderer/assets/Workspace-CaUhiGBX.js +0 -19
  164. package/dist/renderer/assets/bot-Fw3IzhJA.js +0 -6
  165. package/dist/renderer/assets/check-5zCTgp3A.js +0 -6
  166. package/dist/renderer/assets/chevron-down-N3PxTNxH.js +0 -6
  167. package/dist/renderer/assets/circle-C_chUflo.js +0 -6
  168. package/dist/renderer/assets/desktop-DkQTZNhe.js +0 -1
  169. package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
  170. package/dist/renderer/assets/funnel-B8ZAv6I7.js +0 -6
  171. package/dist/renderer/assets/heart-M9A3E4Ed.js +0 -6
  172. package/dist/renderer/assets/index-Bwv855ID.js +0 -41
  173. package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
  174. package/dist/renderer/assets/index-DJ8w4e0l.js +0 -182
  175. package/dist/renderer/assets/projects-DB1FLZ3A.js +0 -1
  176. package/dist/renderer/assets/server-BsuHcYl4.js +0 -11
  177. package/dist/renderer/assets/session-utils-DnAWL3eo.js +0 -6
  178. package/dist/renderer/assets/sessions-DptxO_BE.js +0 -1
  179. package/dist/renderer/assets/user-DQKTaUcR.js +0 -6
  180. package/dist/renderer/assets/wifi-off-vjH-MD2w.js +0 -11
  181. package/dist-electron/src/api/client.js +0 -73
  182. package/dist-electron/src/api/sessions.js +0 -21
  183. package/dist-electron/src/lib/session-utils.js +0 -51
  184. package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
  185. package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.upsertSessionGroup = exports.ASSISTANT_REPLY_TIMEOUT_MS = void 0;
4
+ exports.chatControllerActionForTaskState = chatControllerActionForTaskState;
5
+ exports.taskStateFromControllerStatus = taskStateFromControllerStatus;
4
6
  exports.isInternalProgressBridgeKind = isInternalProgressBridgeKind;
5
7
  exports.isAwaitingInputBridgeStatus = isAwaitingInputBridgeStatus;
6
8
  exports.findStreamingPreviewMessage = findStreamingPreviewMessage;
@@ -9,10 +11,7 @@ exports.shouldAcceptLiveBridgeEvent = shouldAcceptLiveBridgeEvent;
9
11
  exports.settlePreviewMessages = settlePreviewMessages;
10
12
  exports.finalizeTurnMessageKinds = finalizeTurnMessageKinds;
11
13
  exports.extractVisibleMessageContent = extractVisibleMessageContent;
12
- exports.sessionMatchesDesktop = sessionMatchesDesktop;
13
- exports.toMessages = toMessages;
14
14
  exports.toMessagesFromThread = toMessagesFromThread;
15
- exports.toChatThreadSummary = toChatThreadSummary;
16
15
  exports.toCoreChatThreadSummary = toCoreChatThreadSummary;
17
16
  exports.sortChatThreadsByLiveAndUpdated = sortChatThreadsByLiveAndUpdated;
18
17
  exports.chatThreadMatchesSearch = chatThreadMatchesSearch;
@@ -28,9 +27,49 @@ exports.formatTaskHint = formatTaskHint;
28
27
  exports.isTaskRunningState = isTaskRunningState;
29
28
  exports.isTaskInputLocked = isTaskInputLocked;
30
29
  exports.canStreamingPromoteTaskState = canStreamingPromoteTaskState;
31
- const desktop_1 = require("../../../shared/desktop");
32
- const session_utils_1 = require("../../lib/session-utils");
30
+ const chat_event_gate_1 = require("../../components/chat/chat-event-gate");
31
+ const superai_contracts_1 = require("../../../packages/contracts/src/index.js");
33
32
  exports.ASSISTANT_REPLY_TIMEOUT_MS = 90000;
33
+ // Threads drives the shared chat controller through these mappers instead of the
34
+ // reducer's `transition` escape hatch so its task state stays inside ChatTaskState
35
+ // and the reducer's named-action guards remain meaningful.
36
+ function chatControllerActionForTaskState(next) {
37
+ switch (next) {
38
+ case 'idle':
39
+ return { type: 'settled' };
40
+ case 'running':
41
+ return { type: 'stream_started' };
42
+ case 'awaiting_input':
43
+ return { type: 'input_requested' };
44
+ case 'awaiting_permission':
45
+ return { type: 'permission_requested' };
46
+ case 'permission_submitted':
47
+ return { type: 'permission_submitted' };
48
+ case 'stopping':
49
+ return { type: 'stop_started' };
50
+ case 'error':
51
+ return { type: 'failed' };
52
+ }
53
+ }
54
+ function taskStateFromControllerStatus(status) {
55
+ switch (status) {
56
+ case 'idle':
57
+ case 'running':
58
+ case 'awaiting_input':
59
+ case 'awaiting_permission':
60
+ case 'permission_submitted':
61
+ case 'error':
62
+ case 'stopping':
63
+ return status;
64
+ case 'failed':
65
+ case 'timed_out':
66
+ return 'error';
67
+ default:
68
+ // sending/waiting/polling/activating are Session/Web-only statuses the
69
+ // Threads surface never holds; map them defensively to 'running'.
70
+ return 'running';
71
+ }
72
+ }
34
73
  function isInternalProgressBridgeKind(bridgeKind) {
35
74
  return bridgeKind === 'thought' ||
36
75
  bridgeKind === 'plan' ||
@@ -64,23 +103,10 @@ function shouldReplacePreviewWithReply(message, replyContent, replyCtx, replyBri
64
103
  message.bridgeKind === 'assistant'));
65
104
  }
66
105
  function shouldAcceptLiveBridgeEvent(input) {
67
- const replyCtx = String(input.event.replyCtx || '').trim();
68
- if (!replyCtx) {
69
- return true;
70
- }
71
- const activeRunId = String(input.activeRunId || '').trim();
72
- const pendingTurn = input.pendingTurn;
73
- if (pendingTurn && pendingTurn.sessionKey === input.event.sessionKey) {
74
- const pendingRunId = String(pendingTurn.runId || '').trim();
75
- if (pendingRunId) {
76
- return replyCtx === pendingRunId;
77
- }
78
- const supersededRunId = String(pendingTurn.supersededRunId || '').trim();
79
- if (supersededRunId && replyCtx === supersededRunId) {
80
- return false;
81
- }
82
- }
83
- return !activeRunId || replyCtx === activeRunId;
106
+ return (0, chat_event_gate_1.shouldAcceptRunScopedEvent)(input.event, {
107
+ activeRunId: input.activeRunId,
108
+ pendingTurn: input.pendingTurn,
109
+ });
84
110
  }
85
111
  function settlePreviewMessages(messages, turnKey) {
86
112
  let changed = false;
@@ -130,19 +156,6 @@ function extractVisibleMessageContent(content) {
130
156
  }
131
157
  return match[1] || '';
132
158
  }
133
- function sessionMatchesDesktop(session) {
134
- return session.platform === 'desktop' || session.session_key.startsWith('desktop:');
135
- }
136
- function toMessages(history) {
137
- return history.map((message, index) => ({
138
- id: `${index}-${message.timestamp || message.role}`,
139
- role: message.role === 'user' ? 'user' : message.role === 'system' ? 'system' : 'assistant',
140
- content: message.role === 'user' ? extractVisibleMessageContent(message.content) : message.content,
141
- kind: message.kind === 'progress' ? 'progress' : 'final',
142
- order: index,
143
- timestamp: message.timestamp,
144
- }));
145
- }
146
159
  function toMessagesFromThread(history) {
147
160
  return history.map((message, index) => ({
148
161
  id: message.id || `${index}-${message.timestamp || message.role}`,
@@ -160,20 +173,6 @@ function toMessagesFromThread(history) {
160
173
  timestamp: message.timestamp,
161
174
  }));
162
175
  }
163
- function toChatThreadSummary(project, session) {
164
- return {
165
- id: session.id,
166
- project,
167
- name: (0, session_utils_1.sessionLabel)(session),
168
- live: session.live,
169
- createdAt: session.created_at,
170
- updatedAt: session.updated_at,
171
- excerpt: extractVisibleMessageContent(session.last_message?.content || ''),
172
- agentType: session.agent_type,
173
- agentMode: undefined,
174
- bridgeSessionKey: session.session_key,
175
- };
176
- }
177
176
  function toCoreChatThreadSummary(thread) {
178
177
  return {
179
178
  id: thread.id,
@@ -261,7 +260,7 @@ function normalizeBridgeActionRows(input) {
261
260
  return [];
262
261
  }
263
262
  return row
264
- .map((button) => (0, desktop_1.normalizeDesktopBridgeButtonOption)(button))
263
+ .map((button) => (0, superai_contracts_1.normalizeDesktopBridgeButtonOption)(button))
265
264
  .filter((button) => Boolean(button));
266
265
  })
267
266
  .filter((row) => row.length > 0);
@@ -281,7 +280,7 @@ function upsertThreadInGroup(groups, project, thread) {
281
280
  return upsertThreadGroup(groups, project, nextSessions);
282
281
  }
283
282
  function isPermissionActionRow(rows) {
284
- return rows.some((row) => row.some((action) => (0, desktop_1.isPermissionButtonOption)(action)));
283
+ return rows.some((row) => row.some((action) => (0, superai_contracts_1.isPermissionButtonOption)(action)));
285
284
  }
286
285
  function formatTaskHint(taskState, typing) {
287
286
  if (taskState === 'stopping') {
@@ -0,0 +1,21 @@
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 node_test_1 = __importDefault(require("node:test"));
7
+ const strict_1 = __importDefault(require("node:assert/strict"));
8
+ const agent_message_policy_js_1 = require("../../services/local-ai-core/src/thread/agent-message-policy.js");
9
+ (0, node_test_1.default)('agent message policy is owned by Local Core and includes selected knowledge context', () => {
10
+ const message = (0, agent_message_policy_js_1.composeAgentMessage)('Summarize the design', [
11
+ { id: 'kb-1', name: 'Architecture notes' },
12
+ ]);
13
+ strict_1.default.match(message, /\[Scheduler Tools\]/);
14
+ strict_1.default.match(message, /\[Monitor Tools\]/);
15
+ strict_1.default.match(message, /\[Channel Tools\]/);
16
+ strict_1.default.match(message, /id: kb-1 \| name: Architecture notes/);
17
+ strict_1.default.match(message, /\[User Message\]\nSummarize the design\n\[\/User Message\]/);
18
+ });
19
+ (0, node_test_1.default)('agent message policy leaves slash commands untouched', () => {
20
+ strict_1.default.equal((0, agent_message_policy_js_1.composeAgentMessage)('/agent use pi'), '/agent use pi');
21
+ });
@@ -39,33 +39,6 @@ function readSourceFiles(scope) {
39
39
  content: (0, node_fs_1.readFileSync)(path, 'utf8'),
40
40
  }));
41
41
  }
42
- const rendererPackageSourceImportAllowlist = new Set([
43
- 'src/api/cron.ts',
44
- 'src/api/desktop.ts',
45
- 'src/api/knowledge.ts',
46
- 'src/api/monitors.ts',
47
- 'src/api/runtime-bootstrap.ts',
48
- 'src/app/runtime.ts',
49
- 'src/pages/Automation/MonitorList.tsx',
50
- 'src/pages/Cron/CronList.tsx',
51
- 'src/pages/Dashboard.tsx',
52
- 'src/pages/Knowledge/KnowledgeDetail.tsx',
53
- 'src/pages/Knowledge/KnowledgeHome.tsx',
54
- 'src/pages/System/Config.tsx',
55
- 'src/pages/Threads/thread-chat-action-types.ts',
56
- 'src/pages/Threads/thread-chat-model.ts',
57
- 'src/pages/Threads/thread-chat-page-state.ts',
58
- 'src/pages/Threads/thread-chat-permission.test.ts',
59
- 'src/pages/Threads/thread-chat-permission.ts',
60
- 'src/pages/Threads/useThreadChatActions.ts',
61
- 'src/pages/Threads/useThreadChatController.ts',
62
- 'src/pages/Threads/useThreadChatConversationState.ts',
63
- 'src/pages/Threads/useThreadChatSendingActions.ts',
64
- 'src/pages/Threads/useThreadChatSessionBrowser.ts',
65
- 'src/pages/Threads/ThreadChatComposer.tsx',
66
- 'src/pages/Threads/useThreadChatThreadActions.ts',
67
- 'src/types/window.d.ts',
68
- ]);
69
42
  (0, node_test_1.default)('state ownership docs identify Local AI Core owners for durable chat and channel state', () => {
70
43
  const content = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, 'docs', 'architecture', 'state-ownership.md'), 'utf8');
71
44
  for (const state of [
@@ -111,12 +84,13 @@ const rendererPackageSourceImportAllowlist = new Set([
111
84
  strict_1.default.match(permissionSource, /export type PendingPermissionRequest = ThreadPendingPermissionRequest;/, 'renderer pending permission state must alias the shared thread permission contract');
112
85
  strict_1.default.doesNotMatch(permissionSource, /type PermissionTaskState\s*=/, 'permission helpers must not carry a second task-state union');
113
86
  });
114
- (0, node_test_1.default)('renderer does not add new direct imports of package source internals', () => {
115
- const offenders = readSourceFiles('src')
116
- .filter(({ content }) => /from ['"][^'"]*packages\/(?:contracts|core-sdk|plugin-sdk)\/src/.test(content))
117
- .map(({ relativePath }) => relativePath)
118
- .filter((relativePath) => !rendererPackageSourceImportAllowlist.has(relativePath));
119
- strict_1.default.deepEqual(offenders, [], 'renderer code should import package APIs through stable public entrypoints; add migrations instead of new packages/*/src imports');
87
+ (0, node_test_1.default)('production code imports workspace packages through public package names', () => {
88
+ const offenders = ['src', 'services', 'packages']
89
+ .flatMap(readSourceFiles)
90
+ .filter(({ relativePath }) => !relativePath.startsWith('packages/contracts/src/'))
91
+ .filter(({ content }) => /(?:packages\/(?:contracts|core-sdk|plugin-sdk|knowledge-api)|(?:contracts|core-sdk|plugin-sdk))\/src/.test(content))
92
+ .map(({ relativePath }) => relativePath);
93
+ strict_1.default.deepEqual(offenders, [], 'production code must import workspace dependencies through @cc/* public entrypoints');
120
94
  });
121
95
  (0, node_test_1.default)('renderer does not import Electron or Local AI Core internals', () => {
122
96
  const offenders = readSourceFiles('src')
@@ -137,4 +111,53 @@ const rendererPackageSourceImportAllowlist = new Set([
137
111
  const packageJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, packagePath), 'utf8'));
138
112
  strict_1.default.equal(packageJson.exports?.['.'], './src/index.ts', `${packagePath} must expose its public source entrypoint for workspace consumers`);
139
113
  }
114
+ const contracts = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, 'packages/contracts/package.json'), 'utf8'));
115
+ const domains = ['runtime', 'threads', 'channels', 'scheduler', 'automation', 'knowledge'];
116
+ for (const domain of domains) {
117
+ strict_1.default.ok(contracts.exports?.[`./${domain}`], `contracts must expose the ${domain} domain entrypoint`);
118
+ }
119
+ for (const packageName of ['contracts', 'core-sdk', 'plugin-sdk']) {
120
+ const packageJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, `packages/${packageName}/package.json`), 'utf8'));
121
+ for (const domain of domains) {
122
+ strict_1.default.equal(packageJson.exports?.[`./${domain}`], `./src/${domain}.ts`, `${packageName} must expose the ${domain} domain through its dedicated entrypoint`);
123
+ }
124
+ }
125
+ });
126
+ (0, node_test_1.default)('core sdk domain entrypoints do not re-export the top-level sdk', () => {
127
+ for (const domain of ['runtime', 'threads', 'channels', 'scheduler', 'automation', 'knowledge']) {
128
+ const source = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, `packages/core-sdk/src/${domain}.ts`), 'utf8');
129
+ strict_1.default.doesNotMatch(source, /(?:from|import\s*\()\s*['"]\.\/index\.js['"]/, `core-sdk/${domain} must own its implementation without depending on the aggregate entrypoint`);
130
+ strict_1.default.match(source, /coreRequest|coreClient/, `core-sdk/${domain} must own executable domain behavior`);
131
+ }
132
+ });
133
+ (0, node_test_1.default)('package domain modules do not depend on aggregate entrypoints', () => {
134
+ for (const packageName of ['contracts', 'core-sdk', 'plugin-sdk']) {
135
+ for (const domain of ['runtime', 'threads', 'channels', 'scheduler', 'automation', 'knowledge']) {
136
+ const source = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, `packages/${packageName}/src/${domain}.ts`), 'utf8');
137
+ strict_1.default.doesNotMatch(source, /(?:from|import\s*\()\s*['"]\.\/index(?:\.js)?['"]/, `${packageName}/${domain} must not reach back through its aggregate entrypoint`);
138
+ }
139
+ }
140
+ });
141
+ (0, node_test_1.default)('desktop contracts are consumed through the contracts package outside their owner', () => {
142
+ const offenders = ['src', 'services', 'packages']
143
+ .flatMap(readSourceFiles)
144
+ .filter(({ relativePath }) => !relativePath.startsWith('packages/contracts/src/'))
145
+ .filter(({ content }) => /shared\/desktop/.test(content))
146
+ .map(({ relativePath }) => relativePath);
147
+ strict_1.default.deepEqual(offenders, [], 'business code must consume shared desktop contracts through @cc/superai-contracts');
148
+ });
149
+ (0, node_test_1.default)('renderer does not branch features through the retired runtime provider string', () => {
150
+ const offenders = readSourceFiles('src')
151
+ .filter(({ content }) => /RuntimeProvider|getRuntimeProvider|runtimeProvider\s*(?:===|!==)/.test(content))
152
+ .map(({ relativePath }) => relativePath);
153
+ strict_1.default.deepEqual(offenders, [], 'renderer features must use capabilities or the Local Core contract directly');
154
+ });
155
+ (0, node_test_1.default)('chat syntax highlighting stays behind a lazy code-block boundary', () => {
156
+ const markdown = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, 'src/components/chat/ChatMarkdown.tsx'), 'utf8');
157
+ const highlighted = (0, node_fs_1.readFileSync)((0, node_path_1.join)(rootDir, 'src/components/chat/HighlightedMarkdown.tsx'), 'utf8');
158
+ strict_1.default.doesNotMatch(markdown, /from ['"]rehype-highlight['"]/, 'base chat markdown must not eagerly load highlighting');
159
+ strict_1.default.match(markdown, /lazy\(\(\) =>\s*import\('\.\/HighlightedMarkdown'\)/, 'highlighting must use a lazy chunk');
160
+ for (const language of ['typescript', 'javascript', 'json', 'bash', 'python', 'xml', 'css', 'sql', 'yaml']) {
161
+ strict_1.default.match(highlighted, new RegExp(`highlight\\.js/lib/languages/${language}`), `${language} must remain in the supported subset`);
162
+ }
140
163
  });
@@ -0,0 +1,114 @@
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 chat_event_gate_js_1 = require("../../src/components/chat/chat-event-gate.js");
9
+ (0, node_test_1.default)('chat event gate rejects duplicate bridge events', () => {
10
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
11
+ const event = {
12
+ type: 'update_message',
13
+ sessionKey: 'workspace:thread-1',
14
+ replyCtx: 'run-1',
15
+ previewHandle: 'preview-1',
16
+ content: 'working',
17
+ };
18
+ strict_1.default.equal(gate.acceptBridgeEvent(event, { activeRunId: 'run-1' }), true);
19
+ strict_1.default.equal(gate.acceptBridgeEvent(event, { activeRunId: 'run-1' }), false);
20
+ });
21
+ (0, node_test_1.default)('chat event gate rejects late streaming updates after a turn settles', () => {
22
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
23
+ const context = { activeRunId: 'run-1' };
24
+ strict_1.default.equal(gate.acceptBridgeEvent({
25
+ type: 'typing_stop',
26
+ sessionKey: 'workspace:thread-1',
27
+ replyCtx: 'run-1',
28
+ }, context), true);
29
+ strict_1.default.equal(gate.acceptBridgeEvent({
30
+ type: 'update_message',
31
+ sessionKey: 'workspace:thread-1',
32
+ replyCtx: 'run-1',
33
+ content: 'late preview',
34
+ }, context), false);
35
+ });
36
+ (0, node_test_1.default)('chat event gate rejects events from a superseded run', () => {
37
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
38
+ strict_1.default.equal(gate.acceptBridgeEvent({
39
+ type: 'reply',
40
+ sessionKey: 'workspace:thread-1',
41
+ replyCtx: 'run-old',
42
+ content: 'late answer',
43
+ }, {
44
+ activeRunId: 'run-old',
45
+ pendingTurn: {
46
+ sessionKey: 'workspace:thread-1',
47
+ supersededRunId: 'run-old',
48
+ },
49
+ }), false);
50
+ });
51
+ (0, node_test_1.default)('chat event gate deduplicates core refresh events while allowing changed payloads', () => {
52
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
53
+ const first = {
54
+ type: 'message.updated',
55
+ threadId: 'thread-1',
56
+ message: { id: 'message-1', content: 'one' },
57
+ };
58
+ const second = {
59
+ ...first,
60
+ message: { id: 'message-1', content: 'two' },
61
+ };
62
+ strict_1.default.equal(gate.acceptCoreEvent(first), true);
63
+ strict_1.default.equal(gate.acceptCoreEvent(first), false);
64
+ strict_1.default.equal(gate.acceptCoreEvent(second), true);
65
+ });
66
+ (0, node_test_1.default)('chat event gate rejects late Core stream updates after the run settles', () => {
67
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
68
+ const terminal = {
69
+ type: 'stream.updated',
70
+ stream: {
71
+ type: 'typing_stop',
72
+ sessionKey: 'workspace:thread-1',
73
+ replyCtx: 'run-1',
74
+ },
75
+ };
76
+ const lateUpdate = {
77
+ type: 'presence.updated',
78
+ live: true,
79
+ stream: {
80
+ type: 'update_message',
81
+ sessionKey: 'workspace:thread-1',
82
+ replyCtx: 'run-1',
83
+ content: 'late preview',
84
+ },
85
+ };
86
+ strict_1.default.equal(gate.acceptCoreEvent(terminal), true);
87
+ strict_1.default.equal(gate.acceptCoreEvent(lateUpdate), false);
88
+ strict_1.default.equal(gate.acceptCoreEvent({
89
+ type: 'stream.updated',
90
+ stream: {
91
+ type: 'reply',
92
+ sessionKey: 'workspace:thread-1',
93
+ replyCtx: 'run-1',
94
+ content: 'late final',
95
+ },
96
+ }), false);
97
+ });
98
+ (0, node_test_1.default)('chat event gate rejects late running state after a Core run completes', () => {
99
+ const gate = (0, chat_event_gate_js_1.createChatEventGate)();
100
+ const run = {
101
+ id: 'run-1',
102
+ threadId: 'thread-1',
103
+ startedAt: '',
104
+ updatedAt: '',
105
+ };
106
+ strict_1.default.equal(gate.acceptCoreEvent({
107
+ type: 'run.updated',
108
+ run: { ...run, status: 'completed' },
109
+ }), true);
110
+ strict_1.default.equal(gate.acceptCoreEvent({
111
+ type: 'run.updated',
112
+ run: { ...run, status: 'running' },
113
+ }), false);
114
+ });
@@ -0,0 +1,16 @@
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 markdown_code_block_js_1 = require("../../src/components/chat/markdown-code-block.js");
9
+ (0, node_test_1.default)('markdown code block detection covers fenced and indented code blocks', () => {
10
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)('```ts\nconst value = 1;\n```'), true);
11
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)('~~~python\nprint("hi")\n~~~'), true);
12
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)(' ````ts\nconst value = 1;\n`````'), true);
13
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)('```ts\nconst unfinished = true;'), true);
14
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)('Paragraph\n\n pnpm test'), true);
15
+ strict_1.default.equal((0, markdown_code_block_js_1.hasMarkdownCodeBlock)('Use `inline code` only'), false);
16
+ });
@@ -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 thread_chat_model_js_1 = require("../../src/pages/Threads/thread-chat-model.js");
9
+ (0, node_test_1.default)('chatControllerActionForTaskState maps each chat task state to a named controller action', () => {
10
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('idle'), { type: 'settled' });
11
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('running'), { type: 'stream_started' });
12
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('awaiting_input'), { type: 'input_requested' });
13
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('awaiting_permission'), { type: 'permission_requested' });
14
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('permission_submitted'), { type: 'permission_submitted' });
15
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('stopping'), { type: 'stop_started' });
16
+ strict_1.default.deepEqual((0, thread_chat_model_js_1.chatControllerActionForTaskState)('error'), { type: 'failed' });
17
+ });
18
+ (0, node_test_1.default)('taskStateFromControllerStatus narrows the controller status without a cast', () => {
19
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('idle'), 'idle');
20
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('running'), 'running');
21
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('awaiting_input'), 'awaiting_input');
22
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('error'), 'error');
23
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('stopping'), 'stopping');
24
+ // Terminal controller statuses Threads never dispatches map back to 'error'.
25
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('failed'), 'error');
26
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('timed_out'), 'error');
27
+ // Session/Web-only statuses map defensively to 'running'.
28
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('sending'), 'running');
29
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('waiting'), 'running');
30
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('polling'), 'running');
31
+ strict_1.default.equal((0, thread_chat_model_js_1.taskStateFromControllerStatus)('activating'), 'running');
32
+ });
@@ -0,0 +1,23 @@
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 node_test_1 = __importDefault(require("node:test"));
7
+ const strict_1 = __importDefault(require("node:assert/strict"));
8
+ const workspace_model_js_1 = require("../../src/pages/Desktop/workspace-model.js");
9
+ (0, node_test_1.default)('desktop workspace operations keep using stable identity after a display-name change', () => {
10
+ strict_1.default.equal((0, workspace_model_js_1.desktopProjectWorkspaceId)({
11
+ workspace_id: 'workspace-stable',
12
+ name: 'Renamed workspace',
13
+ agent: { type: 'pi' },
14
+ platforms: [],
15
+ }), 'workspace-stable');
16
+ });
17
+ (0, node_test_1.default)('desktop workspace identity falls back to legacy project names', () => {
18
+ strict_1.default.equal((0, workspace_model_js_1.desktopProjectWorkspaceId)({
19
+ name: 'Legacy workspace',
20
+ agent: { type: 'pi' },
21
+ platforms: [],
22
+ }), 'Legacy workspace');
23
+ });