@spzxg/cli-ui 0.6.2 → 0.6.5

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 (131) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +137 -11
  3. package/dist/cli-ui-embed-BmLN2Jjg.js +43290 -0
  4. package/dist/{cli-ui-index-BY5i3wId.js → cli-ui-index-D4qfPHMd.js} +2 -2
  5. package/dist/{cli-ui-jszip.min-BZsUwI-s.js → cli-ui-jszip.min-DC9898pC.js} +1 -1
  6. package/dist/{cli-ui-jszip.min-m01fexHW.js → cli-ui-jszip.min-DpEl0G1z.js} +2 -2
  7. package/dist/{cli-ui-xlsx-CpWicJLT.js → cli-ui-xlsx-zs7oEtPj.js} +1 -1
  8. package/dist/cli-ui.css +32 -1
  9. package/dist/cli-ui.js +1 -1
  10. package/package.json +14 -8
  11. package/src/board/BrowserPane.tsx +160 -74
  12. package/src/board/ChangesPane.tsx +2 -2
  13. package/src/board/CliBoard.tsx +79 -50
  14. package/src/board/FileViewer.tsx +32 -22
  15. package/src/board/FilesPane.tsx +32 -15
  16. package/src/board/PanelControls.tsx +28 -0
  17. package/src/board/blocks.tsx +5 -5
  18. package/src/board/context.ts +65 -0
  19. package/src/board/fileOps.ts +26 -3
  20. package/src/board/fileWatch.ts +88 -0
  21. package/src/board/folderDownload.ts +30 -14
  22. package/src/board/panels.ts +33 -0
  23. package/src/board/textLoad.ts +2 -2
  24. package/src/board/workspace.ts +38 -9
  25. package/src/chat/CliChat.tsx +73 -30
  26. package/src/chat/Composer.tsx +41 -41
  27. package/src/chat/RunControls.tsx +99 -0
  28. package/src/chat/configuration.ts +15 -0
  29. package/src/chat/draft.ts +41 -0
  30. package/src/chat/export.ts +2 -2
  31. package/src/components.tsx +13 -0
  32. package/src/core/blocks.ts +2 -2
  33. package/src/core/callbacks.ts +8 -0
  34. package/src/core/client.ts +8 -6
  35. package/src/core/conversation.ts +3 -3
  36. package/src/core/id.ts +15 -0
  37. package/src/core/identity.ts +33 -0
  38. package/src/core/provider.tsx +24 -14
  39. package/src/core/store.ts +83 -26
  40. package/src/core/types.ts +34 -0
  41. package/src/elements.tsx +135 -29
  42. package/src/embed.ts +6 -8
  43. package/src/index.ts +24 -17
  44. package/src/layout/CliSplit.tsx +1 -1
  45. package/src/msglist/CliMsgList.tsx +10 -10
  46. package/src/operator/branchFlow.ts +35 -0
  47. package/src/operator/index.ts +9 -0
  48. package/src/operator/liveStream.ts +1 -0
  49. package/src/operator/node/AgentConnect.tsx +624 -0
  50. package/src/operator/node/AppearancePanel.tsx +35 -0
  51. package/src/operator/node/BranchHistory.tsx +67 -0
  52. package/src/operator/node/BranchNavigator.tsx +36 -0
  53. package/src/operator/node/BrowserPane.tsx +128 -0
  54. package/src/operator/node/BrowserPopup.tsx +22 -0
  55. package/src/operator/node/Chat.tsx +517 -0
  56. package/src/operator/node/CommandPalette.tsx +213 -0
  57. package/src/operator/node/Composer.tsx +287 -0
  58. package/src/operator/node/InsightsView.tsx +831 -0
  59. package/src/operator/node/Layout.tsx +190 -0
  60. package/src/operator/node/Markdown.tsx +61 -0
  61. package/src/operator/node/Modal.tsx +179 -0
  62. package/src/operator/node/NeedsYouMenu.tsx +54 -0
  63. package/src/operator/node/OnboardingWizard.tsx +250 -0
  64. package/src/operator/node/Orchestrator.tsx +634 -0
  65. package/src/operator/node/ProjectLanding.tsx +86 -0
  66. package/src/operator/node/ProjectsColumn.tsx +137 -0
  67. package/src/operator/node/ProviderAuth.tsx +561 -0
  68. package/src/operator/node/RunControls.tsx +2 -0
  69. package/src/operator/node/RunSwitch.tsx +113 -0
  70. package/src/operator/node/Services.tsx +245 -0
  71. package/src/operator/node/SessionRail.tsx +260 -0
  72. package/src/operator/node/SessionView.tsx +288 -0
  73. package/src/operator/node/SettingsView.tsx +690 -0
  74. package/src/operator/node/TaskBoard.tsx +352 -0
  75. package/src/operator/node/TaskChanges.tsx +530 -0
  76. package/src/operator/node/TaskHero.tsx +50 -0
  77. package/src/operator/node/TasksColumn.tsx +200 -0
  78. package/src/operator/node/Terminal.tsx +143 -0
  79. package/src/operator/node/Transcript.tsx +463 -0
  80. package/src/operator/node/ViewFile.tsx +79 -0
  81. package/src/operator/node/Welcome.tsx +101 -0
  82. package/src/operator/node/WorktreePrune.tsx +333 -0
  83. package/src/operator/node/agents.ts +58 -0
  84. package/src/operator/node/api.ts +40 -0
  85. package/src/operator/node/boardBackend.ts +80 -0
  86. package/src/operator/node/boardEvents.ts +22 -0
  87. package/src/operator/node/boardInteraction.ts +15 -0
  88. package/src/operator/node/boardState.ts +57 -0
  89. package/src/operator/node/boardWorkspace.ts +12 -0
  90. package/src/operator/node/branchFlow.ts +1 -0
  91. package/src/operator/node/composerDraft.ts +52 -0
  92. package/src/operator/node/fileLinks.ts +81 -0
  93. package/src/operator/node/format.ts +290 -0
  94. package/src/operator/node/github.tsx +234 -0
  95. package/src/operator/node/icons.tsx +88 -0
  96. package/src/operator/node/liveStream.ts +270 -0
  97. package/src/operator/node/modals.tsx +720 -0
  98. package/src/operator/node/navHistory.ts +70 -0
  99. package/src/operator/node/persist.ts +26 -0
  100. package/src/operator/node/protocol/agents/optIn.ts +9 -0
  101. package/src/operator/node/protocol/agents/types.ts +394 -0
  102. package/src/operator/node/protocol/approvalFailure.ts +77 -0
  103. package/src/operator/node/protocol/authFailure.ts +66 -0
  104. package/src/operator/node/protocol/customModels.ts +23 -0
  105. package/src/operator/node/protocol/events.ts +13 -0
  106. package/src/operator/node/protocol/features.ts +70 -0
  107. package/src/operator/node/protocol/internalUsage.ts +1 -0
  108. package/src/operator/node/protocol/promptLimits.ts +52 -0
  109. package/src/operator/node/protocol/storageRetention.ts +13 -0
  110. package/src/operator/node/protocol/types.ts +332 -0
  111. package/src/operator/node/protocol/usageLimit.ts +72 -0
  112. package/src/operator/node/shared.tsx +89 -0
  113. package/src/operator/node/transcriptModel.ts +129 -0
  114. package/src/operator/node/types.ts +296 -0
  115. package/src/operator/node/useGlobalEvents.ts +97 -0
  116. package/src/operator/node/useOrchestrator.ts +696 -0
  117. package/src/operator/node/usePrefs.ts +114 -0
  118. package/src/operator/node/useRecaps.ts +91 -0
  119. package/src/operator/node/useTaskStream.ts +279 -0
  120. package/src/operator.base.css +1798 -0
  121. package/src/operator.css +186 -16
  122. package/src/styles.css +20 -0
  123. package/src/ui/Markdown.tsx +7 -2
  124. package/src/ui/Popover.tsx +77 -0
  125. package/src/ui/TextBlock.tsx +3 -3
  126. package/src/ui/Transcript.tsx +10 -8
  127. package/src/ui/fileLinks.ts +6 -0
  128. package/src/ui/format.ts +1 -1
  129. package/src/ui/shared.tsx +1 -1
  130. package/src/ui/transcriptModel.ts +2 -2
  131. package/dist/cli-ui-embed-6IJ_jRVh.js +0 -41223
@@ -0,0 +1,250 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useState } from "react";
4
+ import { Icon } from "./icons";
5
+ import { jget, jsend } from "./api";
6
+ import { AgentConnect } from "./AgentConnect";
7
+ import type { AgentInfoT, AgentsResponseT, ClaudeVerifyT, OnboardingT, OnbStep } from "./types";
8
+
9
+ // The first-run wizard, trimmed to the two irreducible auth steps: connect a
10
+ // coding agent, then verify it responds. "An agent" — not Claude specifically:
11
+ // every registered driver (Claude Code, Codex, …) is offered via the same
12
+ // generic AgentConnect card the Settings surface uses, and connecting ANY of
13
+ // them satisfies the step, so a Codex-only first run completes cleanly (the
14
+ // server adopts the connected agent as the default on finish — lib/onboarding).
15
+ // Claude stays the recommended tab. Everything else — creating a real project —
16
+ // is deferred until after the built-in "Welcome" tutorial. State persists
17
+ // server-side (lib/onboarding) so abandoning mid-way resumes at the right step;
18
+ // it's re-runnable from Settings and skippable for power users.
19
+
20
+ const STEPS: { id: OnbStep; label: string; icon: () => React.ReactNode }[] = [
21
+ { id: "connect", label: "连接智能体", icon: Icon.bolt },
22
+ { id: "verify", label: "验证", icon: Icon.check },
23
+ ];
24
+
25
+ export function OnboardingWizard({
26
+ initial,
27
+ onFinish,
28
+ }: {
29
+ initial: OnboardingT;
30
+ onFinish: () => void;
31
+ }) {
32
+ // Older/persisted states may resume on a step that no longer exists ("project"
33
+ // / "notifications"); collapse anything that isn't "verify" back to "connect".
34
+ const [step, setStep] = useState<OnbStep>(initial.step === "verify" ? "verify" : "connect");
35
+ const [bundle, setBundle] = useState<AgentsResponseT | null>(null);
36
+ // The agent connected during THIS wizard run — the one the Verify step tests.
37
+ // On resume (nothing connected this run) fall back to any connected agent.
38
+ const [justConnected, setJustConnected] = useState<string | null>(null);
39
+ const idx = STEPS.findIndex((s) => s.id === step);
40
+
41
+ const load = useCallback(() => {
42
+ jget<AgentsResponseT>("/api/agents").then(setBundle).catch(() => {});
43
+ }, []);
44
+ useEffect(() => { load(); }, [load]);
45
+
46
+ const connected = (bundle?.agents ?? []).filter((a) => a.connected);
47
+
48
+ // While nothing is connected yet, keep re-checking: a login can settle
49
+ // server-side after a missed onConnected (e.g. the connect card was remounted
50
+ // mid-login), and without this the Continue button stays locked until a reload.
51
+ useEffect(() => {
52
+ if (step !== "connect" || connected.length > 0) return;
53
+ const t = setInterval(load, 3_000);
54
+ return () => clearInterval(t);
55
+ }, [step, connected.length, load]);
56
+ const verifyAgent =
57
+ (justConnected && connected.find((a) => a.id === justConnected)) || connected[0] || null;
58
+
59
+ // Persist the resume point whenever the step changes (fire-and-forget).
60
+ const goto = useCallback((s: OnbStep) => {
61
+ setStep(s);
62
+ jsend("/api/onboarding", "PATCH", { step: s }).catch(() => {});
63
+ }, []);
64
+
65
+ const finish = useCallback(() => {
66
+ jsend("/api/onboarding", "POST").catch(() => {});
67
+ onFinish();
68
+ }, [onFinish]);
69
+
70
+ return (
71
+ <div className="wiz-scrim">
72
+ <div className="wiz">
73
+ <div className="wiz-rail">
74
+ <div className="wiz-brand"><span className="glyph">{Icon.bolt()}</span> Operator</div>
75
+ <div className="wiz-rail-sub">来完成初始设置吧</div>
76
+ <div className="wiz-steps">
77
+ {STEPS.map((s, i) => (
78
+ <div key={s.id} className={`wiz-stepitem${i === idx ? " active" : ""}${i < idx ? " done" : ""}`}>
79
+ <span className="wiz-stepnum">{i < idx ? Icon.check() : s.icon()}</span>
80
+ <span className="wiz-steplabel">{s.label}</span>
81
+ </div>
82
+ ))}
83
+ </div>
84
+ <span style={{ flex: 1 }} />
85
+ <button className="btn btn-ghost btn-sm wiz-skip" onClick={finish} title="跳过设置 —— 之后可在「设置」中重新运行">
86
+ 跳过设置
87
+ </button>
88
+ </div>
89
+
90
+ <div className="wiz-main">
91
+ {step === "connect" && (
92
+ <ConnectStep
93
+ bundle={bundle}
94
+ done={connected.length > 0}
95
+ onConnected={(id) => { setJustConnected(id); load(); }}
96
+ onContinue={() => goto("verify")}
97
+ />
98
+ )}
99
+ {step === "verify" && (
100
+ <VerifyStep agent={verifyAgent} onBack={() => goto("connect")} onFinish={finish} />
101
+ )}
102
+ </div>
103
+ </div>
104
+ </div>
105
+ );
106
+ }
107
+
108
+ // ---------- step shell ----------
109
+
110
+ function StepHead({ n, title, sub }: { n: number; title: string; sub: React.ReactNode }) {
111
+ return (
112
+ <div className="wiz-head">
113
+ <div className="wiz-step-tag">第 {n} 步,共 {STEPS.length} 步</div>
114
+ <div className="wiz-title">{title}</div>
115
+ <div className="wiz-sub">{sub}</div>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ // ---------- Step 1: Connect an agent ----------
121
+
122
+ // One tab per registered driver, each rendering the same generic AgentConnect
123
+ // card (subscription sign-in + API-key path) the Settings surface uses — so
124
+ // agent #3 shows up here with zero wizard edits. Connecting any ONE agent
125
+ // unlocks Continue; the rest can be added later from Settings → Agents.
126
+ function ConnectStep({
127
+ bundle,
128
+ done,
129
+ onConnected,
130
+ onContinue,
131
+ }: {
132
+ bundle: AgentsResponseT | null;
133
+ done: boolean;
134
+ onConnected: (agentId: string) => void;
135
+ onContinue: () => void;
136
+ }) {
137
+ const agents = bundle?.agents ?? [];
138
+ const recommended = bundle?.default ?? "claude";
139
+ const [selected, setSelected] = useState<string | null>(null);
140
+ const current: AgentInfoT | undefined =
141
+ agents.find((a) => a.id === (selected ?? recommended)) ?? agents[0];
142
+
143
+ return (
144
+ <>
145
+ <StepHead
146
+ n={1}
147
+ title="连接一个编程智能体"
148
+ sub="Operator 以你的身份运行编程智能体。用你已有的账号登录即可 —— 现在连接一个,其余的随时可以在「设置」里添加。"
149
+ />
150
+ <div className="wiz-body">
151
+ <div className="hlp" style={{ margin: "0 0 18px", maxWidth: 620 }}>
152
+ Operator 会用已连接的智能体执行一些小型辅助任务,包括自动生成项目回顾,以及你请求的会话摘要。这些都可以随时在「设置 → 后台任务」中控制。
153
+ </div>
154
+ {!bundle && <div className="wiz-verify"><span className="wiz-spin" /> <span>正在加载智能体…</span></div>}
155
+ {agents.length > 1 && (
156
+ <div className="seg" style={{ maxWidth: 460, marginBottom: 20 }}>
157
+ {agents.map((a) => (
158
+ <button key={a.id} className={current?.id === a.id ? "on" : ""} onClick={() => setSelected(a.id)}>
159
+ {a.connected ? Icon.check() : Icon.bolt()} {a.label}
160
+ {a.id === recommended ? " · 推荐" : ""}
161
+ </button>
162
+ ))}
163
+ </div>
164
+ )}
165
+ {current && (
166
+ <AgentConnect key={current.id} agent={current} onConnected={() => onConnected(current.id)} />
167
+ )}
168
+ </div>
169
+ <div className="wiz-foot">
170
+ <span className="spacer" />
171
+ <button className="btn btn-accent" disabled={!done} onClick={onContinue}>
172
+ 继续 {Icon.chevRight()}
173
+ </button>
174
+ </div>
175
+ </>
176
+ );
177
+ }
178
+
179
+ // ---------- Step 2: Verify ----------
180
+
181
+ function VerifyStep({
182
+ agent,
183
+ onBack,
184
+ onFinish,
185
+ }: {
186
+ agent: AgentInfoT | null;
187
+ onBack: () => void;
188
+ onFinish: () => void;
189
+ }) {
190
+ const [state, setState] = useState<"running" | "ok" | "fail">("running");
191
+ const [result, setResult] = useState<ClaudeVerifyT | null>(null);
192
+ const label = agent?.label ?? "你的智能体";
193
+
194
+ const run = useCallback(() => {
195
+ if (!agent) return;
196
+ setState("running");
197
+ setResult(null);
198
+ jsend<ClaudeVerifyT>(`/api/agents/${agent.id}/verify`, "POST")
199
+ .then((r) => { setResult(r); setState(r.connected ? "ok" : "fail"); })
200
+ .catch((e) => { setResult({ connected: false, email: null, plan: null, method: null, error: e instanceof Error ? e.message : String(e) }); setState("fail"); });
201
+ }, [agent]);
202
+
203
+ useEffect(() => { run(); }, [run]);
204
+
205
+ return (
206
+ <>
207
+ <StepHead
208
+ n={2}
209
+ title="验证连接"
210
+ sub={`正在运行一次测试轮次,确认 ${label} 能正常响应。接下来会进入一个 2 分钟的教程,带你走完整个流程。`}
211
+ />
212
+ <div className="wiz-body">
213
+ {(!agent || state === "running") && (
214
+ <div className="wiz-verify"><span className="wiz-spin" /> <span>正在测试你的 {label} 连接…</span></div>
215
+ )}
216
+ {agent && state === "ok" && (
217
+ <div className="wiz-connected">
218
+ <span className="wiz-ok">{Icon.check()}</span>
219
+ <div>
220
+ <div className="wiz-ok-t">
221
+ 已连接{result?.email ? <>,账号 <strong>{result.email}</strong></> : ""}{result?.plan ? `(${result.plan})` : ""}
222
+ </div>
223
+ <div className="hlp" style={{ margin: "3px 0 0" }}>测试轮次已完成 —— 你的会话可以开始运行了。</div>
224
+ </div>
225
+ </div>
226
+ )}
227
+ {agent && state === "fail" && (
228
+ <div className="field" style={{ maxWidth: 600 }}>
229
+ <div className="wiz-fail">
230
+ <span className="wiz-failic">{Icon.x()}</span>
231
+ <div>
232
+ <div className="wiz-ok-t">无法连接 {label}</div>
233
+ <div className="hlp" style={{ margin: "4px 0 0" }}>{result?.error ?? "未知错误"}</div>
234
+ </div>
235
+ </div>
236
+ <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
237
+ <button className="btn btn-accent" onClick={run}>{Icon.restore()} 重试</button>
238
+ <button className="btn btn-line" onClick={onBack}>{Icon.chevRight({ style: { transform: "rotate(180deg)" } })} 返回连接步骤</button>
239
+ </div>
240
+ </div>
241
+ )}
242
+ </div>
243
+ <div className="wiz-foot">
244
+ <button className="btn btn-ghost" onClick={onBack}>上一步</button>
245
+ <span className="spacer" />
246
+ <button className="btn btn-accent" disabled={state !== "ok"} onClick={onFinish}>开始教程 {Icon.chevRight()}</button>
247
+ </div>
248
+ </>
249
+ );
250
+ }