@geminilight/mindos 0.6.29 → 0.6.30

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 (71) hide show
  1. package/README.md +10 -4
  2. package/app/app/api/acp/config/route.ts +82 -0
  3. package/app/app/api/acp/detect/route.ts +71 -48
  4. package/app/app/api/acp/install/route.ts +51 -0
  5. package/app/app/api/acp/session/route.ts +141 -11
  6. package/app/app/api/ask/route.ts +116 -13
  7. package/app/app/api/workflows/route.ts +156 -0
  8. package/app/app/page.tsx +7 -2
  9. package/app/components/ActivityBar.tsx +12 -4
  10. package/app/components/AskModal.tsx +4 -1
  11. package/app/components/FileTree.tsx +21 -10
  12. package/app/components/HomeContent.tsx +1 -0
  13. package/app/components/Panel.tsx +1 -0
  14. package/app/components/RightAskPanel.tsx +5 -1
  15. package/app/components/SidebarLayout.tsx +6 -0
  16. package/app/components/agents/AgentDetailContent.tsx +263 -47
  17. package/app/components/agents/AgentsContentPage.tsx +11 -0
  18. package/app/components/agents/AgentsPanelA2aTab.tsx +285 -46
  19. package/app/components/agents/AgentsPanelSessionsTab.tsx +166 -0
  20. package/app/components/agents/agents-content-model.ts +2 -2
  21. package/app/components/ask/AgentSelectorCapsule.tsx +218 -0
  22. package/app/components/ask/AskContent.tsx +197 -239
  23. package/app/components/ask/FileChip.tsx +82 -17
  24. package/app/components/ask/MentionPopover.tsx +21 -3
  25. package/app/components/ask/MessageList.tsx +30 -9
  26. package/app/components/ask/SlashCommandPopover.tsx +21 -3
  27. package/app/components/panels/AgentsPanel.tsx +1 -0
  28. package/app/components/panels/AgentsPanelHubNav.tsx +9 -2
  29. package/app/components/panels/WorkflowsPanel.tsx +206 -0
  30. package/app/components/renderers/workflow-yaml/StepEditor.tsx +157 -0
  31. package/app/components/renderers/workflow-yaml/WorkflowEditor.tsx +201 -0
  32. package/app/components/renderers/workflow-yaml/WorkflowRunner.tsx +226 -0
  33. package/app/components/renderers/workflow-yaml/WorkflowYamlRenderer.tsx +126 -0
  34. package/app/components/renderers/workflow-yaml/execution.ts +177 -0
  35. package/app/components/renderers/workflow-yaml/index.ts +6 -0
  36. package/app/components/renderers/workflow-yaml/manifest.ts +21 -0
  37. package/app/components/renderers/workflow-yaml/parser.ts +172 -0
  38. package/app/components/renderers/workflow-yaml/selectors.tsx +522 -0
  39. package/app/components/renderers/workflow-yaml/serializer.ts +56 -0
  40. package/app/components/renderers/workflow-yaml/types.ts +46 -0
  41. package/app/hooks/useAcpConfig.ts +96 -0
  42. package/app/hooks/useAcpDetection.ts +69 -14
  43. package/app/hooks/useAcpRegistry.ts +46 -11
  44. package/app/hooks/useAskModal.ts +12 -5
  45. package/app/hooks/useAskPanel.ts +8 -5
  46. package/app/hooks/useAskSession.ts +19 -2
  47. package/app/hooks/useImageUpload.ts +152 -0
  48. package/app/lib/acp/acp-tools.ts +3 -1
  49. package/app/lib/acp/agent-descriptors.ts +274 -0
  50. package/app/lib/acp/bridge.ts +6 -0
  51. package/app/lib/acp/index.ts +20 -4
  52. package/app/lib/acp/registry.ts +74 -7
  53. package/app/lib/acp/session.ts +481 -28
  54. package/app/lib/acp/subprocess.ts +307 -21
  55. package/app/lib/acp/types.ts +158 -20
  56. package/app/lib/agent/model.ts +18 -3
  57. package/app/lib/agent/to-agent-messages.ts +25 -2
  58. package/app/lib/i18n/modules/knowledge.ts +4 -0
  59. package/app/lib/i18n/modules/navigation.ts +2 -0
  60. package/app/lib/i18n/modules/panels.ts +146 -2
  61. package/app/lib/pi-integration/skills.ts +21 -6
  62. package/app/lib/renderers/index.ts +2 -2
  63. package/app/lib/settings.ts +10 -0
  64. package/app/lib/types.ts +12 -1
  65. package/app/next-env.d.ts +1 -1
  66. package/app/package.json +3 -1
  67. package/package.json +1 -1
  68. package/templates/en/.mindos/workflows/Sprint Release.flow.yaml +130 -0
  69. package/templates/zh/.mindos/workflows//345/221/250/350/277/255/344/273/243/346/243/200/346/237/245.flow.yaml +84 -0
  70. package/app/components/renderers/workflow/WorkflowRenderer.tsx +0 -409
  71. package/app/components/renderers/workflow/manifest.ts +0 -14
@@ -13,13 +13,36 @@
13
13
  * - Orphaned tool calls (running/pending from interrupted streams): supply empty result
14
14
  * - Reasoning parts: filtered out (display-only, not sent back to LLM)
15
15
  */
16
- import type { Message as FrontendMessage, ToolCallPart as FrontendToolCallPart } from '@/lib/types';
16
+ import type { Message as FrontendMessage, ToolCallPart as FrontendToolCallPart, ImagePart } from '@/lib/types';
17
17
  import type { AgentMessage } from '@mariozechner/pi-agent-core';
18
18
  import type { UserMessage, AssistantMessage, ToolResultMessage } from '@mariozechner/pi-ai';
19
19
 
20
20
  // Re-export for convenience
21
21
  export type { AgentMessage } from '@mariozechner/pi-agent-core';
22
22
 
23
+ /** Build multimodal content array for user messages with images */
24
+ function buildUserContent(text: string, images?: ImagePart[]): string | any[] {
25
+ // Filter out stripped images (empty data from persisted sessions)
26
+ const validImages = images?.filter(img => img.data);
27
+ if (!validImages || validImages.length === 0) return text;
28
+
29
+ // Multimodal content: images first, then text
30
+ // Use pi-ai ImageContent format: { type: 'image', data: base64, mimeType }
31
+ // The SDK converts this to the provider-specific format (Anthropic/OpenAI) internally
32
+ const parts: any[] = [];
33
+ for (const img of validImages) {
34
+ parts.push({
35
+ type: 'image',
36
+ data: img.data,
37
+ mimeType: img.mimeType,
38
+ });
39
+ }
40
+ if (text) {
41
+ parts.push({ type: 'text', text });
42
+ }
43
+ return parts;
44
+ }
45
+
23
46
  export function toAgentMessages(messages: FrontendMessage[]): AgentMessage[] {
24
47
  const result: AgentMessage[] = [];
25
48
 
@@ -29,7 +52,7 @@ export function toAgentMessages(messages: FrontendMessage[]): AgentMessage[] {
29
52
  if (msg.role === 'user') {
30
53
  result.push({
31
54
  role: 'user',
32
- content: msg.content,
55
+ content: buildUserContent(msg.content, msg.images),
33
56
  timestamp,
34
57
  } satisfies UserMessage as AgentMessage);
35
58
  continue;
@@ -39,11 +39,13 @@ export const knowledgeEn = {
39
39
  'agent-inspector': 'Agent Inspector',
40
40
  'config-panel': 'Config Panel',
41
41
  'todo': 'TODO Board',
42
+ 'workflow-yaml': 'Workflows',
42
43
  } as Record<string, string>,
43
44
  toolDesc: {
44
45
  'agent-inspector': 'View agent tool-call logs and audit trail',
45
46
  'config-panel': 'Edit and manage global configuration',
46
47
  'todo': 'Manage tasks as an interactive kanban board',
48
+ 'workflow-yaml': 'Execute step-by-step workflows with AI assistance',
47
49
  } as Record<string, string>,
48
50
  plugins: 'Extensions',
49
51
  changeHistory: 'Change History',
@@ -251,11 +253,13 @@ export const knowledgeZh = {
251
253
  'agent-inspector': '审计面板',
252
254
  'config-panel': '配置面板',
253
255
  'todo': '待办面板',
256
+ 'workflow-yaml': '工作流',
254
257
  } as Record<string, string>,
255
258
  toolDesc: {
256
259
  'agent-inspector': '查看 Agent 操作日志与调用轨迹',
257
260
  'config-panel': '编辑和管理全局配置项',
258
261
  'todo': '以看板形式管理待办事项',
262
+ 'workflow-yaml': '执行多步骤工作流,AI 辅助执行',
259
263
  } as Record<string, string>,
260
264
  plugins: '扩展',
261
265
  changeHistory: '变更历史',
@@ -11,6 +11,7 @@ export const navigationEn = {
11
11
  agents: 'Agents',
12
12
  echo: 'Echo',
13
13
  discover: 'Discover',
14
+ workflows: 'Flows',
14
15
  history: 'History',
15
16
  help: 'Help',
16
17
  syncLabel: 'Sync',
@@ -86,6 +87,7 @@ export const navigationZh = {
86
87
  agents: '智能体',
87
88
  echo: '回响',
88
89
  discover: '探索',
90
+ workflows: '流程',
89
91
  history: '历史',
90
92
  help: '帮助',
91
93
  syncLabel: '同步',
@@ -40,6 +40,7 @@ export const panelsEn = {
40
40
  navMcp: 'MCP',
41
41
  navSkills: 'Skills',
42
42
  navNetwork: 'Network',
43
+ navSessions: 'Sessions',
43
44
  // A2A tab
44
45
  a2aTabTitle: 'Remote Agents',
45
46
  a2aTabEmpty: 'No remote agents',
@@ -90,11 +91,33 @@ export const panelsEn = {
90
91
  acpComingSoon: 'Coming soon \u2014 use Ask AI to invoke',
91
92
  acpReady: 'Ready',
92
93
  acpNotInstalled: 'Not Installed',
93
- acpScan: 'Scan Local',
94
+ acpScan: 'Re-scan',
94
95
  acpInstallHint: (cmd: string) => `Install with: ${cmd}`,
96
+ acpInstall: 'Install',
97
+ acpInstalling: 'Installing…',
95
98
  acpLoading: 'Loading ACP registry\u2026',
96
99
  acpLoadFailed: 'Failed to load ACP registry.',
97
100
  acpRetry: 'Retry',
101
+ acpQuickReview: 'Review code',
102
+ acpQuickFix: 'Fix bugs',
103
+ acpQuickExplain: 'Explain repo',
104
+ acpUseWith: (name: string) => `Use ${name} to `,
105
+ acpDefaultAgent: 'MindOS Agent',
106
+ acpSelectAgent: 'Select Agent',
107
+ acpChangeAgent: 'Change agent',
108
+ acpConfigToggle: 'Configure',
109
+ acpConfigCommand: 'Command',
110
+ acpConfigArgs: 'Args',
111
+ acpConfigEnv: 'Env',
112
+ acpConfigEnvAdd: 'Add env var',
113
+ acpConfigSource: 'Source',
114
+ acpConfigSourceBuiltin: 'built-in',
115
+ acpConfigSourceRegistry: 'registry',
116
+ acpConfigSourceUser: 'custom',
117
+ acpConfigReset: 'Reset',
118
+ acpConfigSave: 'Save',
119
+ acpConfigSaved: 'Saved',
120
+ acpConfigPath: 'Path',
98
121
  networkEmptyTitle: 'Connect to the agent ecosystem',
99
122
  networkEmptyDesc: 'Discover remote agents or browse coding agents from the ACP registry.',
100
123
  networkDiscoverBtn: 'Discover Agent',
@@ -139,6 +162,22 @@ export const panelsEn = {
139
162
  viewAll: 'View all use cases',
140
163
  tryIt: 'Try',
141
164
  },
165
+ workflows: {
166
+ title: 'Flows',
167
+ empty: 'No flows yet',
168
+ emptyDesc: 'Create your first flow to automate multi-step tasks with AI.',
169
+ newWorkflow: 'New Flow',
170
+ nSteps: (n: number) => `${n} step${n === 1 ? '' : 's'}`,
171
+ parseError: 'Parse error',
172
+ name: 'Name',
173
+ namePlaceholder: 'My Flow',
174
+ template: 'Template',
175
+ templateBlank: 'Blank',
176
+ create: 'Create',
177
+ cancel: 'Cancel',
178
+ creating: 'Creating...',
179
+ exists: 'A workflow with this name already exists',
180
+ },
142
181
  },
143
182
  echoPages: {
144
183
  parent: 'Echo',
@@ -211,6 +250,7 @@ export const panelsEn = {
211
250
  navMcp: 'MCP',
212
251
  navSkills: 'Skills',
213
252
  navNetwork: 'Network',
253
+ navSessions: 'Sessions',
214
254
  a2aTabTitle: 'Remote Agents',
215
255
  a2aTabEmptyHint: 'Discover agents to enable cross-agent delegation.',
216
256
  backToOverview: 'Back to Agents',
@@ -518,6 +558,38 @@ export const panelsEn = {
518
558
  mcpReconnectAll: 'Reconnect all',
519
559
  mcpReconnectAllRunning: 'Reconnecting...',
520
560
  mcpReconnectAllDone: (ok: number, failed: number) => `Reconnected ${ok}${failed > 0 ? `, failed ${failed}` : ''}.`,
561
+ // ─── Runtime & Diagnostics ───
562
+ runtimeDiagTitle: 'Runtime & Diagnostics',
563
+ runtimePing: 'Ping',
564
+ runtimePinging: 'Pinging...',
565
+ runtimePingOk: (ms: number) => `Reachable (${ms}ms)`,
566
+ runtimePingFail: 'Unreachable',
567
+ runtimeUptime: 'Uptime',
568
+ runtimePid: 'Process',
569
+ runtimeMemory: 'Memory',
570
+ runtimeVersion: 'Version',
571
+ runtimeStartedAt: 'Started',
572
+ runtimeNoData: 'No runtime data available.',
573
+ // ─── Environment & Permissions ───
574
+ envPermTitle: 'Environment & Permissions',
575
+ envVars: 'Environment variables',
576
+ envVarsCount: (n: number) => `${n} configured`,
577
+ envVarsEmpty: 'No custom environment variables.',
578
+ envScope: 'Scope',
579
+ envReadOnly: 'Read-only access',
580
+ envWriteAccess: 'Write access',
581
+ envFileAccess: 'File access',
582
+ envNetworkAccess: 'Network access',
583
+ envAllowed: 'Allowed',
584
+ envRestricted: 'Restricted',
585
+ // ─── Activity & Usage ───
586
+ activityTitle: 'Activity & Usage',
587
+ activityTotal: 'Total invocations',
588
+ activityLast7d: 'Last 7 days',
589
+ activityLastInvocation: 'Last invocation',
590
+ activityTokensUsed: 'Tokens used',
591
+ activityAvgLatency: 'Avg latency',
592
+ activityNoData: 'No activity recorded yet.',
521
593
  },
522
594
  detailSubtitle: '',
523
595
  detailNotFound: 'Agent not found — it may have been removed or renamed.',
@@ -565,6 +637,7 @@ export const panelsZh = {
565
637
  navMcp: 'MCP',
566
638
  navSkills: '技能',
567
639
  navNetwork: '网络',
640
+ navSessions: '会话',
568
641
  // A2A tab
569
642
  a2aTabTitle: '远程 Agent',
570
643
  a2aTabEmpty: '无远程 Agent',
@@ -615,11 +688,33 @@ export const panelsZh = {
615
688
  acpComingSoon: '即将上线 — 当前可通过 Ask AI 调用',
616
689
  acpReady: '就绪',
617
690
  acpNotInstalled: '未安装',
618
- acpScan: '扫描本地',
691
+ acpScan: '重新扫描',
619
692
  acpInstallHint: (cmd: string) => `安装命令: ${cmd}`,
693
+ acpInstall: '安装',
694
+ acpInstalling: '安装中…',
620
695
  acpLoading: '加载 ACP 注册表中…',
621
696
  acpLoadFailed: '加载 ACP 注册表失败。',
622
697
  acpRetry: '重试',
698
+ acpQuickReview: '代码审查',
699
+ acpQuickFix: '修复Bug',
700
+ acpQuickExplain: '解释项目',
701
+ acpUseWith: (name: string) => `使用 ${name} `,
702
+ acpDefaultAgent: 'MindOS Agent',
703
+ acpSelectAgent: '选择 Agent',
704
+ acpChangeAgent: '切换 Agent',
705
+ acpConfigToggle: '配置',
706
+ acpConfigCommand: '命令',
707
+ acpConfigArgs: '参数',
708
+ acpConfigEnv: '环境变量',
709
+ acpConfigEnvAdd: '添加环境变量',
710
+ acpConfigSource: '来源',
711
+ acpConfigSourceBuiltin: '内置',
712
+ acpConfigSourceRegistry: '注册表',
713
+ acpConfigSourceUser: '自定义',
714
+ acpConfigReset: '重置',
715
+ acpConfigSave: '保存',
716
+ acpConfigSaved: '已保存',
717
+ acpConfigPath: '路径',
623
718
  networkEmptyTitle: '连接智能体生态',
624
719
  networkEmptyDesc: '发现远程 Agent 或浏览 ACP 注册表中的编程智能体。',
625
720
  networkDiscoverBtn: '发现 Agent',
@@ -664,6 +759,22 @@ export const panelsZh = {
664
759
  viewAll: '查看所有使用案例',
665
760
  tryIt: '试试',
666
761
  },
762
+ workflows: {
763
+ title: '流程',
764
+ empty: '还没有流程',
765
+ emptyDesc: '创建第一个流程,用 AI 自动化多步骤任务。',
766
+ newWorkflow: '新建流程',
767
+ nSteps: (n: number) => `${n} 个步骤`,
768
+ parseError: '解析错误',
769
+ name: '名称',
770
+ namePlaceholder: '我的流程',
771
+ template: '模板',
772
+ templateBlank: '空白',
773
+ create: '创建',
774
+ cancel: '取消',
775
+ creating: '创建中...',
776
+ exists: '已存在同名流程',
777
+ },
667
778
  },
668
779
  echoPages: {
669
780
  parent: '回响',
@@ -736,6 +847,7 @@ export const panelsZh = {
736
847
  navMcp: 'MCP',
737
848
  navSkills: 'Skills',
738
849
  navNetwork: '网络',
850
+ navSessions: '会话',
739
851
  a2aTabTitle: '远程 Agent',
740
852
  a2aTabEmptyHint: '发现远程 Agent 以启用跨 Agent 委派。',
741
853
  backToOverview: '返回 Agents',
@@ -1043,6 +1155,38 @@ export const panelsZh = {
1043
1155
  mcpReconnectAll: '全部重连',
1044
1156
  mcpReconnectAllRunning: '正在重连...',
1045
1157
  mcpReconnectAllDone: (ok: number, failed: number) => `已重连 ${ok}${failed > 0 ? `,失败 ${failed}` : ''}。`,
1158
+ // ─── 运行与诊断 ───
1159
+ runtimeDiagTitle: '运行与诊断',
1160
+ runtimePing: '连通测试',
1161
+ runtimePinging: '测试中...',
1162
+ runtimePingOk: (ms: number) => `可达 (${ms}ms)`,
1163
+ runtimePingFail: '不可达',
1164
+ runtimeUptime: '运行时长',
1165
+ runtimePid: '进程',
1166
+ runtimeMemory: '内存',
1167
+ runtimeVersion: '版本',
1168
+ runtimeStartedAt: '启动于',
1169
+ runtimeNoData: '暂无运行数据。',
1170
+ // ─── 环境与权限 ───
1171
+ envPermTitle: '环境与权限',
1172
+ envVars: '环境变量',
1173
+ envVarsCount: (n: number) => `已配置 ${n} 个`,
1174
+ envVarsEmpty: '暂无自定义环境变量。',
1175
+ envScope: '作用域',
1176
+ envReadOnly: '只读访问',
1177
+ envWriteAccess: '写入访问',
1178
+ envFileAccess: '文件访问',
1179
+ envNetworkAccess: '网络访问',
1180
+ envAllowed: '允许',
1181
+ envRestricted: '受限',
1182
+ // ─── 活动与用量 ───
1183
+ activityTitle: '活动与用量',
1184
+ activityTotal: '总调用次数',
1185
+ activityLast7d: '近 7 天',
1186
+ activityLastInvocation: '最近调用',
1187
+ activityTokensUsed: '消耗 Tokens',
1188
+ activityAvgLatency: '平均延迟',
1189
+ activityNoData: '暂无活动记录。',
1046
1190
  },
1047
1191
  detailSubtitle: '',
1048
1192
  detailNotFound: '未找到该 Agent,可能已移除或重命名。',
@@ -23,15 +23,30 @@ export function parseSkillMd(content: string): { name: string; description: stri
23
23
  if (!match) return { name: '', description: '' };
24
24
  const yaml = match[1];
25
25
  const nameMatch = yaml.match(/^name:\s*(.+)/m);
26
- const descMatch = yaml.match(/^description:\s*>?\s*\n?([\s\S]*?)(?=\n\w|\n---)/m);
27
- const name = nameMatch ? nameMatch[1].trim() : '';
26
+
27
+ // Try to match block scalar (description: >) first
28
+ // Captures all indented lines until next non-indented line or EOF
28
29
  let description = '';
29
- if (descMatch) {
30
- description = descMatch[1].trim().split('\n').map((l) => l.trim()).join(' ').slice(0, 200);
30
+ const blockMatch = yaml.match(/^description:\s*>?\s*\n((?:\s+.+\n?)*)/m);
31
+ if (blockMatch && blockMatch[1].trim()) {
32
+ // Block scalar: join indented lines, dedent, preserve structure
33
+ description = blockMatch[1]
34
+ .split('\n')
35
+ .map(line => line.replace(/^\s+/, '')) // Remove leading spaces
36
+ .filter(line => line.trim()) // Remove empty lines
37
+ .join(' ')
38
+ .slice(0, 200);
31
39
  } else {
32
- const simpleDesc = yaml.match(/^description:\s*(.+)/m);
33
- if (simpleDesc) description = simpleDesc[1].trim().slice(0, 200);
40
+ // Fallback to single-line description
41
+ const simpleMatch = yaml.match(/^description:\s*(.+)/m);
42
+ if (simpleMatch) {
43
+ const val = simpleMatch[1].trim();
44
+ // Skip the ">" character if it's there (fallback from block scalar)
45
+ description = val === '>' ? '' : val.slice(0, 200);
46
+ }
34
47
  }
48
+
49
+ const name = nameMatch ? nameMatch[1].trim() : '';
35
50
  return { name, description };
36
51
  }
37
52
 
@@ -10,11 +10,11 @@ import { manifest as csv } from '@/components/renderers/csv/manifest';
10
10
  import { manifest as summary } from '@/components/renderers/summary/manifest';
11
11
  import { manifest as timeline } from '@/components/renderers/timeline/manifest';
12
12
  import { manifest as todo } from '@/components/renderers/todo/manifest';
13
- import { manifest as workflow } from '@/components/renderers/workflow/manifest';
13
+ import { manifest as workflowYaml } from '@/components/renderers/workflow-yaml/manifest';
14
14
  import { manifest as graph } from '@/components/renderers/graph/manifest';
15
15
 
16
16
  const manifests = [
17
- agentInspector, backlinks, config, csv, summary, timeline, todo, workflow, graph,
17
+ agentInspector, backlinks, config, csv, summary, timeline, todo, workflowYaml, graph,
18
18
  ];
19
19
 
20
20
  for (const m of manifests) {
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
+ import { parseAcpAgentOverrides } from './acp/agent-descriptors';
4
5
 
5
6
  const SETTINGS_PATH = path.join(os.homedir(), '.mindos', 'config.json');
6
7
 
@@ -49,6 +50,8 @@ export interface ServerSettings {
49
50
  setupPending?: boolean; // true → / redirects to /setup
50
51
  disabledSkills?: string[];
51
52
  guideState?: GuideState;
53
+ /** Per-agent ACP overrides (command, args, env, enabled). Keyed by agent ID. */
54
+ acpAgents?: Record<string, import('./acp/agent-descriptors').AcpAgentOverride>;
52
55
  }
53
56
 
54
57
  const DEFAULTS: ServerSettings = {
@@ -133,6 +136,11 @@ function parseAgent(raw: unknown): AgentConfig | undefined {
133
136
  return Object.keys(result).length > 0 ? result : undefined;
134
137
  }
135
138
 
139
+ /** Parse acpAgents config field, delegates to agent-descriptors.ts */
140
+ function parseAcpAgentsField(raw: unknown): Record<string, import('./acp/agent-descriptors').AcpAgentOverride> | undefined {
141
+ return parseAcpAgentOverrides(raw);
142
+ }
143
+
136
144
  /** Parse guideState from unknown input */
137
145
  function parseGuideState(raw: unknown): GuideState | undefined {
138
146
  if (!raw || typeof raw !== 'object') return undefined;
@@ -159,6 +167,7 @@ export function readSettings(): ServerSettings {
159
167
  return {
160
168
  ai: migrateAi(parsed),
161
169
  agent: parseAgent(parsed.agent),
170
+ acpAgents: parseAcpAgentsField(parsed.acpAgents),
162
171
  mindRoot: (parsed.mindRoot ?? parsed.sopRoot ?? DEFAULTS.mindRoot) as string,
163
172
  webPassword: typeof parsed.webPassword === 'string' ? parsed.webPassword : undefined,
164
173
  authToken: typeof parsed.authToken === 'string' ? parsed.authToken : undefined,
@@ -189,6 +198,7 @@ export function writeSettings(settings: ServerSettings): void {
189
198
  if (settings.startMode !== undefined) merged.startMode = settings.startMode;
190
199
  if (settings.disabledSkills !== undefined) merged.disabledSkills = settings.disabledSkills;
191
200
  if (settings.guideState !== undefined) merged.guideState = settings.guideState;
201
+ if (settings.acpAgents !== undefined) merged.acpAgents = settings.acpAgents;
192
202
  // setupPending: false/undefined → remove the field (cleanup); true → set it
193
203
  if ('setupPending' in settings) {
194
204
  if (settings.setupPending) merged.setupPending = true;
package/app/lib/types.ts CHANGED
@@ -32,7 +32,16 @@ export interface ReasoningPart {
32
32
  text: string;
33
33
  }
34
34
 
35
- export type MessagePart = TextPart | ToolCallPart | ReasoningPart;
35
+ export type ImageMimeType = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp';
36
+
37
+ export interface ImagePart {
38
+ type: 'image';
39
+ /** Base64-encoded image data (no data: prefix) */
40
+ data: string;
41
+ mimeType: ImageMimeType;
42
+ }
43
+
44
+ export type MessagePart = TextPart | ToolCallPart | ReasoningPart | ImagePart;
36
45
 
37
46
  export interface Message {
38
47
  role: 'user' | 'assistant';
@@ -41,6 +50,8 @@ export interface Message {
41
50
  timestamp?: number;
42
51
  /** Structured parts for assistant messages (tool calls + text segments) */
43
52
  parts?: MessagePart[];
53
+ /** Images attached to this message (user messages only) */
54
+ images?: ImagePart[];
44
55
  /** Skill name used for this user message (rendered as a capsule in the UI) */
45
56
  skillName?: string;
46
57
  }
package/app/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
3
+ import "./.next/dev/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
package/app/package.json CHANGED
@@ -39,9 +39,10 @@
39
39
  "extend": "^3.0.2",
40
40
  "fuse.js": "^7.1.0",
41
41
  "github-slugger": "^2.0.0",
42
+ "js-yaml": "^4.1.1",
42
43
  "lucide-react": "^0.577.0",
43
- "nanoid": "^5.1.0",
44
44
  "mcporter": "^0.7.3",
45
+ "nanoid": "^5.1.0",
45
46
  "next": "16.1.6",
46
47
  "papaparse": "^5.5.3",
47
48
  "pdfjs-dist": "^4.10.38",
@@ -61,6 +62,7 @@
61
62
  },
62
63
  "devDependencies": {
63
64
  "@tailwindcss/postcss": "^4",
65
+ "@types/js-yaml": "^4.0.9",
64
66
  "@types/node": "^20",
65
67
  "@types/papaparse": "^5.5.2",
66
68
  "@types/react": "^19",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.6.29",
3
+ "version": "0.6.30",
4
4
  "description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
5
5
  "keywords": [
6
6
  "mindos",
@@ -0,0 +1,130 @@
1
+ title: Sprint Release Workflow
2
+ description: Weekly sprint release process with multi-agent collaboration and comprehensive QA
3
+
4
+ # Global configuration - skills available across all steps
5
+ skills:
6
+ - software-architecture
7
+ - code-review-quality
8
+ - document-release
9
+
10
+ # Global tools guidance (advisory - LLM auto-selects based on context)
11
+ tools:
12
+ - git
13
+ - npm
14
+ - github
15
+
16
+ # Workflow steps - executed sequentially
17
+ steps:
18
+ # Step 1: Run comprehensive test suite
19
+ - id: run_tests
20
+ name: Run tests
21
+ description: Execute full test suite and report results with coverage metrics
22
+ agent: cursor
23
+ prompt: |
24
+ Execute the full test suite for this project.
25
+
26
+ Provide:
27
+ 1. Total tests run, passed, failed
28
+ 2. Coverage report (lines/branches/functions)
29
+ 3. Any critical failures with recommendations
30
+ 4. Time taken
31
+
32
+ If failures exist, list the top 3 most critical with suggested fixes.
33
+ timeout: 120
34
+
35
+ # Step 2: Code review with dedicated AI agent
36
+ - id: code_review
37
+ name: Code review
38
+ description: Comprehensive code review using software architecture principles
39
+ agent: claude-code
40
+ skill: code-review-quality
41
+ prompt: |
42
+ Review the recent code changes using the code-review-quality standard.
43
+
44
+ Evaluate:
45
+ 1. Correctness - error handling, edge cases
46
+ 2. Security - authentication, input validation, secrets
47
+ 3. Performance - N+1 queries, caching, complexity
48
+ 4. Maintainability - naming, tests, documentation
49
+ 5. Architecture - follows project patterns, no anti-patterns
50
+
51
+ Provide a rating (e.g., 8.5/10) and key recommendations.
52
+ timeout: 120
53
+
54
+ # Step 3: Automated security scan (no agent - use LLM with tools)
55
+ - id: security_check
56
+ name: Security scan
57
+ description: Run security analysis and dependency checks
58
+ tools:
59
+ - npm
60
+ - github
61
+ prompt: |
62
+ Perform security checks on this project:
63
+
64
+ 1. Check for known vulnerabilities in npm dependencies
65
+ 2. Review recent dependency changes
66
+ 3. Check for hardcoded secrets or credentials
67
+ 4. Evaluate access control and authentication mechanisms
68
+ 5. Assess error handling for information leaks
69
+
70
+ Report severity and recommended fixes.
71
+ timeout: 60
72
+
73
+ # Step 4: Update documentation using document-release skill
74
+ - id: update_docs
75
+ name: Update documentation
76
+ description: Sync CHANGELOG, README, and API docs with shipped changes
77
+ skill: document-release
78
+ prompt: |
79
+ Update project documentation based on the shipped changes:
80
+
81
+ 1. Update CHANGELOG.md following semantic versioning
82
+ 2. Update README.md if features or APIs changed
83
+ 3. Update API documentation if endpoints changed
84
+ 4. Verify all documentation links are valid
85
+ 5. Check code examples match current implementation
86
+
87
+ Provide a summary of all documentation updates made.
88
+ timeout: 60
89
+
90
+ # Step 5: Final checklist before release
91
+ - id: pre_release_check
92
+ name: Pre-release verification
93
+ description: Final comprehensive verification before shipping
94
+ agent: mindos
95
+ prompt: |
96
+ Perform final pre-release verification:
97
+
98
+ Checklist:
99
+ ☐ All tests passing
100
+ ☐ Code review completed and issues resolved
101
+ ☐ Security scan passed or risks accepted
102
+ ☐ Documentation updated and links valid
103
+ ☐ Version bumped correctly (semver)
104
+ ☐ Git tags and commits clean
105
+ ☐ No uncommitted changes
106
+ ☐ Changelog entry present
107
+ ☐ Dependencies updated and locked
108
+ ☐ Performance benchmarks acceptable
109
+
110
+ Confirm release readiness or list any blockers.
111
+ timeout: 60
112
+
113
+ # Step 6: Create release tag and prepare release notes
114
+ - id: create_release
115
+ name: Create release
116
+ description: Tag release and prepare release notes for publishing
117
+ tools:
118
+ - git
119
+ - npm
120
+ prompt: |
121
+ Prepare the project for release:
122
+
123
+ 1. Confirm version in package.json matches intended release
124
+ 2. Create git tag for this version (vX.Y.Z)
125
+ 3. Generate release notes from CHANGELOG.md
126
+ 4. Prepare npm release command (do not execute yet)
127
+ 5. List all deliverables included in this release
128
+
129
+ Provide step-by-step commands for final publishing.
130
+ timeout: 60