@geminilight/mindos 0.6.30 → 0.6.31
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_zh.md +10 -4
- package/app/app/api/ask/route.ts +12 -7
- package/app/app/api/export/route.ts +105 -0
- package/app/app/globals.css +2 -2
- package/app/app/trash/page.tsx +7 -0
- package/app/app/view/[...path]/ViewPageClient.tsx +234 -2
- package/app/components/ExportModal.tsx +220 -0
- package/app/components/FileTree.tsx +22 -2
- package/app/components/HomeContent.tsx +91 -20
- package/app/components/MarkdownView.tsx +45 -10
- package/app/components/Sidebar.tsx +10 -1
- package/app/components/TrashPageClient.tsx +263 -0
- package/app/components/ask/ToolCallBlock.tsx +102 -18
- package/app/components/changes/ChangesContentPage.tsx +58 -14
- package/app/components/explore/ExploreContent.tsx +4 -7
- package/app/components/explore/UseCaseCard.tsx +18 -1
- package/app/components/explore/use-cases.generated.ts +76 -0
- package/app/components/explore/use-cases.yaml +185 -0
- package/app/components/panels/DiscoverPanel.tsx +1 -1
- package/app/components/renderers/workflow-yaml/StepEditor.tsx +98 -91
- package/app/components/renderers/workflow-yaml/WorkflowEditor.tsx +82 -72
- package/app/components/renderers/workflow-yaml/WorkflowRunner.tsx +163 -120
- package/app/components/renderers/workflow-yaml/WorkflowYamlRenderer.tsx +61 -61
- package/app/components/renderers/workflow-yaml/execution.ts +64 -12
- package/app/components/renderers/workflow-yaml/selectors.tsx +64 -12
- package/app/components/settings/AiTab.tsx +191 -174
- package/app/components/settings/AppearanceTab.tsx +168 -77
- package/app/components/settings/KnowledgeTab.tsx +131 -136
- package/app/components/settings/McpTab.tsx +11 -11
- package/app/components/settings/Primitives.tsx +60 -0
- package/app/components/settings/SettingsContent.tsx +15 -8
- package/app/components/settings/SyncTab.tsx +12 -12
- package/app/components/settings/UninstallTab.tsx +8 -18
- package/app/components/settings/UpdateTab.tsx +82 -82
- package/app/components/settings/types.ts +17 -8
- package/app/lib/acp/session.ts +12 -3
- package/app/lib/actions.ts +57 -3
- package/app/lib/agent/stream-consumer.ts +18 -0
- package/app/lib/agent/tools.ts +56 -9
- package/app/lib/core/export.ts +116 -0
- package/app/lib/core/trash.ts +241 -0
- package/app/lib/fs.ts +47 -0
- package/app/lib/hooks/usePinnedFiles.ts +90 -0
- package/app/lib/i18n/generated/explore-i18n.generated.ts +138 -0
- package/app/lib/i18n/index.ts +3 -0
- package/app/lib/i18n/modules/knowledge.ts +120 -6
- package/app/lib/i18n/modules/onboarding.ts +2 -134
- package/app/lib/i18n/modules/settings.ts +12 -0
- package/app/package.json +8 -2
- package/app/scripts/generate-explore.ts +145 -0
- package/package.json +1 -1
- package/app/components/explore/use-cases.ts +0 -58
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// ⚠️ AUTO-GENERATED — DO NOT EDIT. Source: components/explore/use-cases.yaml
|
|
2
|
+
// Run `npm run generate` to regenerate.
|
|
3
|
+
|
|
4
|
+
/** Capability axis — maps to product pillars */
|
|
5
|
+
export type UseCaseCategory = 'knowledge-management' | 'memory-sync' | 'auto-execute' | 'experience-evolution' | 'human-insights' | 'audit-control';
|
|
6
|
+
|
|
7
|
+
/** Scenario axis — maps to user journey phase */
|
|
8
|
+
export type UseCaseScenario = 'first-day' | 'daily' | 'project' | 'advanced';
|
|
9
|
+
|
|
10
|
+
export interface UseCase {
|
|
11
|
+
id: string;
|
|
12
|
+
icon: string;
|
|
13
|
+
image?: string;
|
|
14
|
+
category: UseCaseCategory;
|
|
15
|
+
scenario: UseCaseScenario;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const useCases: UseCase[] = [
|
|
19
|
+
{
|
|
20
|
+
"id": "c1",
|
|
21
|
+
"icon": "👤",
|
|
22
|
+
"category": "memory-sync",
|
|
23
|
+
"scenario": "first-day"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "c2",
|
|
27
|
+
"icon": "📥",
|
|
28
|
+
"category": "knowledge-management",
|
|
29
|
+
"scenario": "daily"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "c3",
|
|
33
|
+
"icon": "🔄",
|
|
34
|
+
"category": "memory-sync",
|
|
35
|
+
"scenario": "project"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "c4",
|
|
39
|
+
"icon": "🔁",
|
|
40
|
+
"category": "experience-evolution",
|
|
41
|
+
"scenario": "daily"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "c5",
|
|
45
|
+
"icon": "💡",
|
|
46
|
+
"category": "auto-execute",
|
|
47
|
+
"scenario": "daily"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "c6",
|
|
51
|
+
"icon": "🚀",
|
|
52
|
+
"category": "auto-execute",
|
|
53
|
+
"scenario": "project"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "c7",
|
|
57
|
+
"icon": "🔍",
|
|
58
|
+
"category": "knowledge-management",
|
|
59
|
+
"scenario": "project"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "c8",
|
|
63
|
+
"icon": "🤝",
|
|
64
|
+
"category": "human-insights",
|
|
65
|
+
"scenario": "daily"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "c9",
|
|
69
|
+
"icon": "🛡️",
|
|
70
|
+
"category": "audit-control",
|
|
71
|
+
"scenario": "advanced"
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
export const categories: UseCaseCategory[] = ["knowledge-management","memory-sync","auto-execute","experience-evolution","human-insights","audit-control"];
|
|
76
|
+
export const scenarios: UseCaseScenario[] = ["first-day","daily","project","advanced"];
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# MindOS Explore — Use Case Definitions (Single Source of Truth)
|
|
2
|
+
#
|
|
3
|
+
# To add a new use case: just append a new entry below.
|
|
4
|
+
# Run `npm run generate` to regenerate use-cases.ts + i18n.
|
|
5
|
+
#
|
|
6
|
+
# Fields:
|
|
7
|
+
# id: Unique identifier (e.g. c10)
|
|
8
|
+
# icon: Emoji fallback when no image is available
|
|
9
|
+
# image: (optional) Custom image path under /explore/. Omit to use /explore/{id}.png
|
|
10
|
+
# category: One of: knowledge-management | memory-sync | auto-execute | experience-evolution | human-insights | audit-control
|
|
11
|
+
# scenario: One of: first-day | daily | project | advanced
|
|
12
|
+
# zh/en: Bilingual text — title, desc, prompt
|
|
13
|
+
|
|
14
|
+
# ── Category & Scenario labels (used by filter UI) ──
|
|
15
|
+
meta:
|
|
16
|
+
categories:
|
|
17
|
+
knowledge-management:
|
|
18
|
+
en: Knowledge Management
|
|
19
|
+
zh: 知识管理
|
|
20
|
+
memory-sync:
|
|
21
|
+
en: Memory Sync
|
|
22
|
+
zh: 记忆同步
|
|
23
|
+
auto-execute:
|
|
24
|
+
en: Auto Execute
|
|
25
|
+
zh: 自动执行
|
|
26
|
+
experience-evolution:
|
|
27
|
+
en: Experience Evolution
|
|
28
|
+
zh: 经验进化
|
|
29
|
+
human-insights:
|
|
30
|
+
en: Human Insights
|
|
31
|
+
zh: 人类洞察
|
|
32
|
+
audit-control:
|
|
33
|
+
en: Audit & Control
|
|
34
|
+
zh: 审计纠错
|
|
35
|
+
scenarios:
|
|
36
|
+
first-day:
|
|
37
|
+
en: First Day
|
|
38
|
+
zh: 初次使用
|
|
39
|
+
daily:
|
|
40
|
+
en: Daily Work
|
|
41
|
+
zh: 日常工作
|
|
42
|
+
project:
|
|
43
|
+
en: Project Work
|
|
44
|
+
zh: 项目协作
|
|
45
|
+
advanced:
|
|
46
|
+
en: Advanced
|
|
47
|
+
zh: 高级
|
|
48
|
+
ui:
|
|
49
|
+
title:
|
|
50
|
+
en: Explore Use Cases
|
|
51
|
+
zh: 探索使用场景
|
|
52
|
+
subtitle:
|
|
53
|
+
en: "Discover what you can do with MindOS \u2014 pick a scenario and try it now."
|
|
54
|
+
zh: "发现 MindOS 能帮你做什么 \u2014 选一个场景,立即体验。"
|
|
55
|
+
tryIt:
|
|
56
|
+
en: Try it
|
|
57
|
+
zh: 试一试
|
|
58
|
+
all:
|
|
59
|
+
en: All
|
|
60
|
+
zh: 全部
|
|
61
|
+
byCapability:
|
|
62
|
+
en: By Capability
|
|
63
|
+
zh: 按能力
|
|
64
|
+
byScenario:
|
|
65
|
+
en: By Scenario
|
|
66
|
+
zh: 按场景
|
|
67
|
+
|
|
68
|
+
# ── Use Cases ──
|
|
69
|
+
cases:
|
|
70
|
+
- id: c1
|
|
71
|
+
icon: "\U0001F464"
|
|
72
|
+
category: memory-sync
|
|
73
|
+
scenario: first-day
|
|
74
|
+
en:
|
|
75
|
+
title: Inject Your Identity
|
|
76
|
+
desc: "Tell all AI agents who you are \u2014 preferences, tech stack, communication style \u2014 in one shot."
|
|
77
|
+
prompt: "Here's my resume, read it and organize my info into MindOS."
|
|
78
|
+
zh:
|
|
79
|
+
title: 注入身份
|
|
80
|
+
desc: "让所有 AI Agent 一次认识你 \u2014 偏好、技术栈、沟通风格。"
|
|
81
|
+
prompt: 这是我的简历,读一下,把我的信息整理到 MindOS 里。
|
|
82
|
+
|
|
83
|
+
- id: c2
|
|
84
|
+
icon: "\U0001F4E5"
|
|
85
|
+
category: knowledge-management
|
|
86
|
+
scenario: daily
|
|
87
|
+
en:
|
|
88
|
+
title: Save Information
|
|
89
|
+
desc: Archive articles, meeting notes, or web pages into your knowledge base with one prompt.
|
|
90
|
+
prompt: Help me save the key points from this article into MindOS.
|
|
91
|
+
zh:
|
|
92
|
+
title: 注入信息
|
|
93
|
+
desc: 一句话归档文章、会议纪要或网页到知识库,全局可搜。
|
|
94
|
+
prompt: 帮我把这篇文章的要点整理到 MindOS 里。
|
|
95
|
+
|
|
96
|
+
- id: c3
|
|
97
|
+
icon: "\U0001F504"
|
|
98
|
+
category: memory-sync
|
|
99
|
+
scenario: project
|
|
100
|
+
en:
|
|
101
|
+
title: Cross-Agent Handoff
|
|
102
|
+
desc: "Start a plan in MindOS, continue coding in Claude Code, refine in Cursor \u2014 zero context loss."
|
|
103
|
+
prompt: Help me start coding based on the plan in MindOS.
|
|
104
|
+
zh:
|
|
105
|
+
title: 跨 Agent 切换
|
|
106
|
+
desc: "在 MindOS 写方案,在 Claude Code 写代码,在 Cursor 优化 \u2014 零重复。"
|
|
107
|
+
prompt: 帮我按 MindOS 里的 XXX 方案开始写代码。
|
|
108
|
+
|
|
109
|
+
- id: c4
|
|
110
|
+
icon: "\U0001F501"
|
|
111
|
+
category: experience-evolution
|
|
112
|
+
scenario: daily
|
|
113
|
+
en:
|
|
114
|
+
title: "Experience \u2192 SOP"
|
|
115
|
+
desc: Turn hard-won debugging sessions into reusable workflows that prevent future mistakes.
|
|
116
|
+
prompt: Help me distill this conversation into a reusable workflow in MindOS.
|
|
117
|
+
zh:
|
|
118
|
+
title: "经验\u2192SOP"
|
|
119
|
+
desc: 把踩坑经验沉淀为可复用的工作流,下次 3 分钟搞定。
|
|
120
|
+
prompt: 帮我把这次对话的经验沉淀到 MindOS,形成可复用的工作流。
|
|
121
|
+
|
|
122
|
+
- id: c5
|
|
123
|
+
icon: "\U0001F4A1"
|
|
124
|
+
category: auto-execute
|
|
125
|
+
scenario: daily
|
|
126
|
+
en:
|
|
127
|
+
title: Capture Ideas on the Go
|
|
128
|
+
desc: "Jot down an inspiration on your phone \u2014 MindOS archives, decomposes, and assigns to agents."
|
|
129
|
+
prompt: Help me organize this idea into MindOS and break it into actionable sub-tasks.
|
|
130
|
+
zh:
|
|
131
|
+
title: 手机记灵感
|
|
132
|
+
desc: 随手记下灵感,MindOS 自动归档、拆任务、多 Agent 接力执行。
|
|
133
|
+
prompt: 帮我把这个想法整理到 MindOS,拆解成可执行的子任务。
|
|
134
|
+
|
|
135
|
+
- id: c6
|
|
136
|
+
icon: "\U0001F680"
|
|
137
|
+
category: auto-execute
|
|
138
|
+
scenario: project
|
|
139
|
+
en:
|
|
140
|
+
title: Project Cold Start
|
|
141
|
+
desc: "Spin up a new project in 4 minutes \u2014 your profile and SOPs guide the scaffolding automatically."
|
|
142
|
+
prompt: Help me start a new project following the Startup SOP in MindOS.
|
|
143
|
+
zh:
|
|
144
|
+
title: 项目冷启动
|
|
145
|
+
desc: "4 分钟搭建新项目 \u2014 Profile 和 SOP 自动引导脚手架。"
|
|
146
|
+
prompt: 帮我按 MindOS 里的 Startup SOP 启动一个新项目。
|
|
147
|
+
|
|
148
|
+
- id: c7
|
|
149
|
+
icon: "\U0001F50D"
|
|
150
|
+
category: knowledge-management
|
|
151
|
+
scenario: project
|
|
152
|
+
en:
|
|
153
|
+
title: Research & Archive
|
|
154
|
+
desc: Let agents research competitors or topics for you, then file structured results in your KB.
|
|
155
|
+
prompt: "Help me research X, Y, Z products and save results to the MindOS product library."
|
|
156
|
+
zh:
|
|
157
|
+
title: 调研入库
|
|
158
|
+
desc: 让 Agent 替你跑腿调研竞品或话题,结果结构化入库。
|
|
159
|
+
prompt: 帮我调研 X、Y、Z 这几个产品,结果写入 MindOS 产品库。
|
|
160
|
+
|
|
161
|
+
- id: c8
|
|
162
|
+
icon: "\U0001F91D"
|
|
163
|
+
category: human-insights
|
|
164
|
+
scenario: daily
|
|
165
|
+
en:
|
|
166
|
+
title: Network Management
|
|
167
|
+
desc: "Log conversations with contacts, auto-generate follow-up TODOs, and keep full context."
|
|
168
|
+
prompt: "I met with someone today \u2014 update MindOS Connections and create follow-up TODOs."
|
|
169
|
+
zh:
|
|
170
|
+
title: 人脉管理
|
|
171
|
+
desc: 记录对话、自动生成跟进待办,每个联系人都有完整上下文。
|
|
172
|
+
prompt: 我今天和 XXX 聊了这些内容,帮我更新到 MindOS 并生成跟进待办。
|
|
173
|
+
|
|
174
|
+
- id: c9
|
|
175
|
+
icon: "\U0001F6E1\uFE0F"
|
|
176
|
+
category: audit-control
|
|
177
|
+
scenario: advanced
|
|
178
|
+
en:
|
|
179
|
+
title: Audit & Correct
|
|
180
|
+
desc: "Review what agents know about you, fix mistakes in one place, and all agents update instantly."
|
|
181
|
+
prompt: Check my MindOS Profile for accuracy and correct any errors.
|
|
182
|
+
zh:
|
|
183
|
+
title: 审计纠偏
|
|
184
|
+
desc: 审查 Agent 记了什么,一处修正,全局生效。
|
|
185
|
+
prompt: 帮我检查 MindOS Profile 里的技术栈偏好是否正确,有错误帮我修正。
|
|
@@ -6,7 +6,7 @@ import { Lightbulb, Blocks, Zap, LayoutTemplate, User, Download, RefreshCw, Repe
|
|
|
6
6
|
import PanelHeader from './PanelHeader';
|
|
7
7
|
import { PanelNavRow, ComingSoonBadge } from './PanelNavRow';
|
|
8
8
|
import { useLocale } from '@/lib/LocaleContext';
|
|
9
|
-
import { useCases } from '@/components/explore/use-cases';
|
|
9
|
+
import { useCases } from '@/components/explore/use-cases.generated';
|
|
10
10
|
import { openAskModal } from '@/hooks/useAskModal';
|
|
11
11
|
import { getPluginRenderers, isRendererEnabled, setRendererEnabled, loadDisabledState } from '@/lib/renderers/registry';
|
|
12
12
|
import { Toggle } from '../settings/Primitives';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { ChevronDown, ChevronUp, Trash2 } from 'lucide-react';
|
|
4
|
+
import { ChevronDown, ChevronUp, Trash2, Settings2 } from 'lucide-react';
|
|
5
5
|
import { AgentSelector, ModelSelector, SkillsSelector, ContextSelector } from './selectors';
|
|
6
6
|
import type { WorkflowStep } from './types';
|
|
7
7
|
|
|
@@ -15,142 +15,149 @@ interface StepEditorProps {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export default function StepEditor({ step, index, onChange, onDelete, onMoveUp, onMoveDown }: StepEditorProps) {
|
|
18
|
-
// Auto-expand if step has no prompt (newly created)
|
|
19
18
|
const [expanded, setExpanded] = useState(!step.prompt);
|
|
19
|
+
const [showConfig, setShowConfig] = useState(false);
|
|
20
20
|
|
|
21
21
|
const update = (patch: Partial<WorkflowStep>) => onChange({ ...step, ...patch });
|
|
22
|
-
|
|
23
|
-
// Merge legacy single skill into skills array for display
|
|
24
22
|
const allSkills = step.skills?.length ? step.skills : (step.skill ? [step.skill] : []);
|
|
23
|
+
const hasConfig = !!(step.agent || step.model || allSkills.length || step.context?.length || step.description || step.timeout);
|
|
25
24
|
|
|
26
|
-
// Collapsed
|
|
25
|
+
// ── Collapsed ──
|
|
27
26
|
if (!expanded) {
|
|
28
27
|
return (
|
|
29
|
-
<div className="group flex items-
|
|
28
|
+
<div className="group flex items-start gap-2 px-3 py-2 rounded-lg hover:bg-muted/40 transition-colors cursor-pointer -ml-1"
|
|
30
29
|
onClick={() => setExpanded(true)}>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
<div className="min-w-0 flex-1">
|
|
31
|
+
<span className={`text-sm leading-tight block ${step.name ? 'text-foreground font-medium' : 'text-muted-foreground/50 italic'}`}>
|
|
32
|
+
{step.name || 'Untitled step'}
|
|
33
|
+
</span>
|
|
34
|
+
{/* Config summary pills */}
|
|
35
|
+
{hasConfig && (
|
|
36
|
+
<div className="flex items-center gap-1 mt-1 flex-wrap">
|
|
37
|
+
{step.agent && <span className="text-2xs px-1.5 py-0.5 rounded-full bg-muted text-muted-foreground">{step.agent}</span>}
|
|
38
|
+
{allSkills.slice(0, 2).map(s => (
|
|
39
|
+
<span key={s} className="text-2xs px-1.5 py-0.5 rounded-full bg-[var(--amber)]/8 text-[var(--amber)]">{s}</span>
|
|
40
|
+
))}
|
|
41
|
+
{allSkills.length > 2 && <span className="text-2xs text-muted-foreground/50">+{allSkills.length - 2}</span>}
|
|
42
|
+
{step.context?.length ? <span className="text-2xs text-muted-foreground/50">{step.context.length} files</span> : null}
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
{/* Prompt preview */}
|
|
46
|
+
{step.prompt && (
|
|
47
|
+
<p className="text-2xs text-muted-foreground/50 mt-1 line-clamp-1 leading-relaxed">{step.prompt}</p>
|
|
41
48
|
)}
|
|
42
|
-
{step.agent && <span className="text-2xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground">🤖 {step.agent}</span>}
|
|
43
|
-
{step.agent && step.model && <span className="text-2xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground">🧠 {step.model}</span>}
|
|
44
|
-
{step.context?.length ? <span className="text-2xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground">📎 {step.context.length}</span> : null}
|
|
45
49
|
</div>
|
|
46
|
-
<ChevronDown size={12} className="text-muted-foreground/
|
|
50
|
+
<ChevronDown size={12} className="text-muted-foreground/30 mt-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
47
51
|
</div>
|
|
48
52
|
);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
// Expanded
|
|
55
|
+
// ── Expanded ──
|
|
52
56
|
return (
|
|
53
|
-
<div className="rounded-
|
|
57
|
+
<div className="rounded-lg border border-[var(--amber)]/20 bg-card overflow-hidden shadow-sm">
|
|
54
58
|
{/* Header */}
|
|
55
|
-
<div className="flex items-center gap-2 px-3
|
|
56
|
-
<span className=
|
|
57
|
-
<span className={`text-xs font-medium flex-1 truncate ${step.name ? 'text-foreground' : 'text-muted-foreground italic'}`}>
|
|
59
|
+
<div className="flex items-center gap-2 px-3 py-2 bg-muted/20">
|
|
60
|
+
<span className={`text-xs font-medium flex-1 truncate ${step.name ? 'text-foreground' : 'text-muted-foreground/50 italic'}`}>
|
|
58
61
|
{step.name || 'Untitled step'}
|
|
59
62
|
</span>
|
|
60
63
|
<div className="flex items-center gap-0.5">
|
|
61
64
|
{onMoveUp && (
|
|
62
|
-
<button onClick={onMoveUp} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title="Move up">
|
|
63
|
-
<ChevronUp size={
|
|
65
|
+
<button onClick={onMoveUp} className="p-1 rounded hover:bg-muted text-muted-foreground/50 hover:text-foreground transition-colors" title="Move up">
|
|
66
|
+
<ChevronUp size={12} />
|
|
64
67
|
</button>
|
|
65
68
|
)}
|
|
66
69
|
{onMoveDown && (
|
|
67
|
-
<button onClick={onMoveDown} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title="Move down">
|
|
68
|
-
<ChevronDown size={
|
|
70
|
+
<button onClick={onMoveDown} className="p-1 rounded hover:bg-muted text-muted-foreground/50 hover:text-foreground transition-colors" title="Move down">
|
|
71
|
+
<ChevronDown size={12} />
|
|
69
72
|
</button>
|
|
70
73
|
)}
|
|
71
|
-
<button onClick={onDelete} className="p-1 rounded hover:bg-[var(--error)]/10 text-muted-foreground hover:text-[var(--error)] transition-colors" title="Delete
|
|
72
|
-
<Trash2 size={
|
|
74
|
+
<button onClick={onDelete} className="p-1 rounded hover:bg-[var(--error)]/10 text-muted-foreground/50 hover:text-[var(--error)] transition-colors" title="Delete">
|
|
75
|
+
<Trash2 size={11} />
|
|
73
76
|
</button>
|
|
74
|
-
<button onClick={() => setExpanded(false)} className="p-1 rounded hover:bg-muted text-muted-foreground transition-colors" title="Collapse">
|
|
75
|
-
<ChevronUp size={
|
|
77
|
+
<button onClick={() => setExpanded(false)} className="p-1 rounded hover:bg-muted text-muted-foreground/50 transition-colors" title="Collapse">
|
|
78
|
+
<ChevronUp size={12} />
|
|
76
79
|
</button>
|
|
77
80
|
</div>
|
|
78
81
|
</div>
|
|
79
82
|
|
|
80
|
-
{/*
|
|
81
|
-
<div className="px-3
|
|
82
|
-
{/*
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
className="w-full px-2.5 py-1.5 text-sm rounded-md border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
83
|
+
{/* Body */}
|
|
84
|
+
<div className="px-3 py-3 space-y-3">
|
|
85
|
+
{/* Name — inline style, not a labeled field */}
|
|
86
|
+
<input type="text" value={step.name} onChange={e => update({ name: e.target.value })}
|
|
87
|
+
placeholder="Step name..."
|
|
88
|
+
autoFocus={!step.name}
|
|
89
|
+
className="w-full text-sm font-medium bg-transparent text-foreground placeholder:text-muted-foreground/30 focus:outline-none border-none p-0"
|
|
90
|
+
/>
|
|
91
91
|
|
|
92
|
-
{/* Prompt */}
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
className="w-full px-2.5 py-1.5 text-sm rounded-md border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring resize-y leading-relaxed"
|
|
99
|
-
/>
|
|
100
|
-
</div>
|
|
92
|
+
{/* Prompt — the main content */}
|
|
93
|
+
<textarea value={step.prompt} onChange={e => update({ prompt: e.target.value })}
|
|
94
|
+
placeholder="What should the AI do?"
|
|
95
|
+
rows={3}
|
|
96
|
+
className="w-full px-3 py-2.5 text-sm rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground/40 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring resize-y leading-relaxed"
|
|
97
|
+
/>
|
|
101
98
|
|
|
102
|
-
{/* Agent
|
|
103
|
-
<div className={`grid ${step.agent ? 'grid-cols-2' : 'grid-cols-1'} gap-
|
|
99
|
+
{/* Agent selector — always visible, it's important */}
|
|
100
|
+
<div className={`grid ${step.agent ? 'grid-cols-2' : 'grid-cols-1'} gap-2`}>
|
|
104
101
|
<div>
|
|
105
|
-
<label className="block text-2xs
|
|
102
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Agent</label>
|
|
106
103
|
<AgentSelector value={step.agent} onChange={agent => update({ agent, model: agent ? step.model : undefined })} />
|
|
107
104
|
</div>
|
|
108
105
|
{step.agent && (
|
|
109
106
|
<div>
|
|
110
|
-
<label className="block text-2xs
|
|
107
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Model</label>
|
|
111
108
|
<ModelSelector value={step.model} onChange={model => update({ model })} />
|
|
112
109
|
</div>
|
|
113
110
|
)}
|
|
114
111
|
</div>
|
|
115
112
|
|
|
116
|
-
{/*
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
{/* Config toggle — progressive disclosure for skills, context, timeout */}
|
|
114
|
+
<button
|
|
115
|
+
onClick={() => setShowConfig(v => !v)}
|
|
116
|
+
className={`flex items-center gap-1.5 text-2xs transition-colors ${
|
|
117
|
+
showConfig || hasConfig ? 'text-muted-foreground' : 'text-muted-foreground/40 hover:text-muted-foreground'
|
|
118
|
+
}`}
|
|
119
|
+
>
|
|
120
|
+
<Settings2 size={11} />
|
|
121
|
+
{showConfig ? 'Less options' : 'More options'}
|
|
122
|
+
{!showConfig && hasConfig && <span className="w-1.5 h-1.5 rounded-full bg-[var(--amber)]" />}
|
|
123
|
+
</button>
|
|
124
124
|
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
</div>
|
|
125
|
+
{showConfig && (
|
|
126
|
+
<div className="space-y-3 pt-1">
|
|
127
|
+
{/* Skills */}
|
|
128
|
+
<div>
|
|
129
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Skills</label>
|
|
130
|
+
<SkillsSelector value={allSkills} onChange={skills => update({ skills, skill: undefined })} />
|
|
131
|
+
</div>
|
|
133
132
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
133
|
+
{/* Context files */}
|
|
134
|
+
<div>
|
|
135
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Context files</label>
|
|
136
|
+
<ContextSelector value={step.context ?? []} onChange={context => update({ context: context.length ? context : undefined })} />
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
{/* Description + Timeout */}
|
|
140
|
+
<div className="grid grid-cols-[1fr,auto] gap-3">
|
|
141
|
+
<div>
|
|
142
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Description</label>
|
|
143
|
+
<input type="text" value={step.description || ''} onChange={e => update({ description: e.target.value || undefined })}
|
|
144
|
+
placeholder="Optional note..."
|
|
145
|
+
className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background text-foreground placeholder:text-muted-foreground/30 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
<div>
|
|
149
|
+
<label className="block text-2xs text-muted-foreground/60 mb-1">Timeout</label>
|
|
150
|
+
<div className="flex items-center gap-1">
|
|
151
|
+
<input type="number" min={0} value={step.timeout || ''} onChange={e => update({ timeout: e.target.value ? Number(e.target.value) : undefined })}
|
|
152
|
+
placeholder="120"
|
|
153
|
+
className="w-16 px-2 py-1.5 text-xs rounded-md border border-border bg-background text-foreground placeholder:text-muted-foreground/30 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
154
|
+
/>
|
|
155
|
+
<span className="text-2xs text-muted-foreground/40">s</span>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
151
158
|
</div>
|
|
152
159
|
</div>
|
|
153
|
-
|
|
160
|
+
)}
|
|
154
161
|
</div>
|
|
155
162
|
</div>
|
|
156
163
|
);
|