@hunterzhu/pulse-cli 0.1.5 → 0.1.6

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.
@@ -77,6 +77,18 @@ export function App({ hostOptions, conversationId: initialConversationId, initia
77
77
  },
78
78
  onExit: () => exit(),
79
79
  onQuit: () => exit(),
80
+ onCancel: async () => {
81
+ if (!isRunning) {
82
+ addAssistantMessage({
83
+ id: `cancel-${Date.now()}`,
84
+ role: 'system',
85
+ text: '当前没有正在运行的任务。',
86
+ createdAt: new Date().toISOString(),
87
+ });
88
+ return;
89
+ }
90
+ await cancelRun();
91
+ },
80
92
  onConfig: () => {
81
93
  addAssistantMessage({
82
94
  id: `config-${Date.now()}`,
@@ -347,6 +359,6 @@ export function App({ hostOptions, conversationId: initialConversationId, initia
347
359
  const cwd = conversation.summary.cwd;
348
360
  const title = conversation.summary.title;
349
361
  const modelName = hostOptions.provider?.defaultModel || hostOptions.provider?.provider || 'default';
350
- return (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsx(Header, { title: title, cwd: cwd, model: modelName, approvalMode: hostOptions.approvalMode ?? 'ask' }), messages.length === 0 && !isRunning && (_jsx(Welcome, { cwd: cwd, model: modelName, version: version })), messages.length > 0 && (_jsx(MessageList, { messages: messages, showThinking: showThinking, verbosity: verbosity })), isRunning && !approvalRequest && (_jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: currentStep || '正在思考与执行...' }) })), runError && (_jsx(Box, { marginY: 1, children: _jsxs(Text, { color: "red", children: ["\u9519\u8BEF: ", runError] }) })), conversationError && (_jsx(Box, { marginY: 1, children: _jsxs(Text, { color: "red", children: ["\u4F1A\u8BDD\u6D88\u606F\u52A0\u8F7D\u5931\u8D25: ", conversationError] }) })), approvalRequest && (_jsx(ApprovalPrompt, { request: approvalRequest, onApprove: () => void approveAction(approvalRequest.effectId, true), onDeny: (reason) => void approveAction(approvalRequest.effectId, false, reason) })), _jsx(Box, { marginTop: 1, children: _jsx(InputArea, { onSubmit: (txt) => void handleSubmit(txt), disabled: isRunning || !!approvalRequest, placeholder: isRunning ? '正在处理中...' : '输入消息或 /help...' }) })] }));
362
+ return (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsx(Header, { title: title, cwd: cwd, model: modelName, approvalMode: hostOptions.approvalMode ?? 'ask' }), messages.length === 0 && !isRunning && (_jsx(Welcome, { cwd: cwd, model: modelName, version: version })), messages.length > 0 && (_jsx(MessageList, { messages: messages, showThinking: showThinking, verbosity: verbosity })), isRunning && !approvalRequest && (_jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: currentStep || '正在思考与执行...' }) })), runError && (_jsx(Box, { marginY: 1, children: _jsxs(Text, { color: "red", children: ["\u9519\u8BEF: ", runError] }) })), conversationError && (_jsx(Box, { marginY: 1, children: _jsxs(Text, { color: "red", children: ["\u4F1A\u8BDD\u6D88\u606F\u52A0\u8F7D\u5931\u8D25: ", conversationError] }) })), approvalRequest && (_jsx(ApprovalPrompt, { request: approvalRequest, onApprove: () => void approveAction(approvalRequest.effectId, true), onDeny: (reason) => void approveAction(approvalRequest.effectId, false, reason) })), _jsx(Box, { marginTop: 1, children: _jsx(InputArea, { onSubmit: (txt) => void handleSubmit(txt), disabled: false, placeholder: isRunning ? '运行中也可以输入;/cancel 可取消当前运行...' : '输入消息或 /help...' }) })] }));
351
363
  }
352
364
  export default App;
@@ -10,6 +10,7 @@ const COMMANDS = [
10
10
  { name: '/tools', desc: '列出可用工具' },
11
11
  { name: '/artifacts', desc: '查看当前产物列表' },
12
12
  { name: '/exit, /quit', desc: '退出 CLI' },
13
+ { name: '/cancel, /stop', desc: '取消当前运行并保留会话' },
13
14
  ],
14
15
  },
15
16
  {
@@ -1,5 +1,6 @@
1
1
  import type { LocalHost } from '@hunterzhu/pulse-server';
2
2
  import type { ApprovalRequest, DisplayMessage } from '../types.js';
3
+ export declare function describeFactStatus(data: unknown): string;
3
4
  export declare function useRun({ host, conversationId, addAssistantMessage, }: {
4
5
  host: LocalHost | null;
5
6
  conversationId: string | null;
@@ -4,6 +4,37 @@ function toolStatus(value) {
4
4
  return value;
5
5
  return 'running';
6
6
  }
7
+ export function describeFactStatus(data) {
8
+ if (typeof data === 'string') {
9
+ if (data === 'human.input.received')
10
+ return '已收到你的输入,正在安排处理...';
11
+ if (data === 'human.input.dispatched')
12
+ return '已安排优先处理你的输入...';
13
+ if (data === 'human.input.deferred')
14
+ return '输入已记录,将在当前副作用安全收尾后处理...';
15
+ return data;
16
+ }
17
+ if (!data || typeof data !== 'object' || Array.isArray(data))
18
+ return '正在执行...';
19
+ const payload = data;
20
+ const decision = payload.decision ?? payload.action;
21
+ if (typeof payload.inputId === 'string' && decision === undefined) {
22
+ return '已收到你的输入,调度器正在决定如何处理...';
23
+ }
24
+ if (decision === 'spawn')
25
+ return '已启动优先交互任务,正在处理你的输入...';
26
+ if (decision === 'respond')
27
+ return '已收到回复,正在继续当前任务...';
28
+ if (decision === 'steer')
29
+ return '正在根据你的输入调整当前任务...';
30
+ if (decision === 'cancel')
31
+ return '正在按你的输入取消相关任务...';
32
+ if (decision === 'defer')
33
+ return '输入已记录,等待安全时机处理...';
34
+ if (typeof payload.reason === 'string')
35
+ return `输入处理暂缓:${payload.reason}`;
36
+ return '正在执行...';
37
+ }
7
38
  export function useRun({ host, conversationId, addAssistantMessage, }) {
8
39
  const [isRunning, setIsRunning] = useState(false);
9
40
  const [currentStep, setCurrentStep] = useState(null);
@@ -84,12 +115,7 @@ export function useRun({ host, conversationId, addAssistantMessage, }) {
84
115
  break;
85
116
  }
86
117
  case 'fact':
87
- if (typeof event.data === 'string') {
88
- setCurrentStep(event.data);
89
- }
90
- else if (event.data && typeof event.data === 'object') {
91
- setCurrentStep('正在执行...');
92
- }
118
+ setCurrentStep(describeFactStatus(event.data));
93
119
  break;
94
120
  case 'error':
95
121
  setError(String(event.data ?? '发生未知错误'));
@@ -111,8 +137,19 @@ export function useRun({ host, conversationId, addAssistantMessage, }) {
111
137
  runRef.current = null;
112
138
  }, []);
113
139
  const sendMessage = useCallback(async (text) => {
114
- if (!host || !conversationId || runRef.current)
140
+ if (!host || !conversationId)
115
141
  return;
142
+ if (runRef.current) {
143
+ try {
144
+ await runRef.current.submitHumanInput(text);
145
+ setError(null);
146
+ setCurrentStep('已接收输入,调度器正在决定如何处理...');
147
+ }
148
+ catch (e) {
149
+ setError(e instanceof Error ? e.message : String(e));
150
+ }
151
+ return;
152
+ }
116
153
  setIsRunning(true);
117
154
  setError(null);
118
155
  setCurrentStep('思考中...');
@@ -6,6 +6,7 @@ export interface SlashCommandDependencies {
6
6
  onArtifacts?: () => void | Promise<void>;
7
7
  onExit?: () => void | Promise<void>;
8
8
  onQuit?: () => void | Promise<void>;
9
+ onCancel?: () => void | Promise<void>;
9
10
  onNew?: () => void | Promise<void>;
10
11
  onSessions?: () => void | Promise<void>;
11
12
  onDelete?: (args: string) => void | Promise<void>;
@@ -7,6 +7,7 @@ export function useSlashCommands(deps) {
7
7
  { name: '/artifacts', description: '查看当前产物', execute: async () => deps.onArtifacts?.() },
8
8
  { name: '/exit', description: '退出程序', execute: async () => deps.onExit?.() },
9
9
  { name: '/quit', aliases: ['/q'], description: '退出程序', execute: async () => deps.onQuit?.() },
10
+ { name: '/cancel', aliases: ['/stop'], description: '取消当前运行(保留会话)', execute: async () => deps.onCancel?.() },
10
11
  { name: '/new', description: '开启新会话', execute: async () => deps.onNew?.() },
11
12
  { name: '/sessions', description: '查看所有会话', execute: async () => deps.onSessions?.() },
12
13
  { name: '/delete', description: '删除会话 [id]', execute: async (args) => deps.onDelete?.(args) },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hunterzhu/pulse-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/zhuhengtan/Pulse"
@@ -19,7 +19,7 @@
19
19
  "build": "tsc -p tsconfig.json"
20
20
  },
21
21
  "dependencies": {
22
- "@hunterzhu/pulse-server": "0.1.5",
22
+ "@hunterzhu/pulse-server": "0.1.6",
23
23
  "ink": "^7.1.1",
24
24
  "react": "^19.0.0",
25
25
  "ink-spinner": "^5.0.0",