@goodandready/dsh-goal 0.2.2 → 0.2.4

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.
@@ -1,276 +1,242 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { GoalState, detectLanguage } from './goal-engine.js';
3
-
4
- export const USAGE_EN = 'Usage: /goal [<goal>|clear|pause|resume]';
5
- export const USAGE_ZH = '用法: /goal [<目标描述>|clear|pause|resume]';
6
- export const USAGE_RU = 'Использование: /goal [<цель>|clear|pause|resume]';
7
- export const USAGE = USAGE_EN;
8
-
9
- /**
10
- * Парсинг строки ввода для команды /goal
11
- * @param {string} rawInput
12
- * @returns {{ action: string, text?: string }}
13
- */
14
- export function parseGoalInput(rawInput = '') {
15
- const input = String(rawInput || '').trim();
16
- if (!input) {
17
- return { action: 'show' };
18
- }
19
-
20
- const lower = input.toLowerCase();
21
- if (lower === 'clear') return { action: 'clear' };
22
- if (lower === 'pause') return { action: 'pause' };
23
- if (lower === 'resume') return { action: 'resume' };
24
-
25
- return { action: 'start', text: input };
26
- }
27
-
28
- /**
29
- * Создание валидного identified сообщения пользователя для отправки агенту через followup
30
- * @param {string} text
31
- * @returns {Object}
32
- */
33
- export function createGoalUserMessage(text) {
34
- return {
35
- id: randomUUID(),
36
- role: 'user',
37
- content: [{ type: 'text', text }],
38
- source: { kind: 'user' },
39
- };
40
- }
41
-
42
- /**
43
- * Формирование стартового промпта с жестким требованием составить план работ
44
- * @param {string} goalText
45
- * @param {string} [explicitLang]
46
- * @returns {string}
47
- */
48
- export function formatGoalStartPrompt(goalText, explicitLang) {
49
- const lang = explicitLang || detectLanguage(goalText);
50
- if (lang === 'zh') {
51
- return `🎯 目标模式已激活 (Goal Mode): "${goalText}"\n\n` +
52
- `自主执行契约:\n` +
53
- `1. 第一步必选动作:在开展任何工作或回复之前,你的第一个动作必须是调用 goal_set_milestones 工具,提交包含 3-7 个具体连续步骤的工作计划。用户将在界面中实时查看此计划。\n` +
54
- `2. 第二步:计划确立后开始执行任务。在开始每个步骤前,通过 goal_update_progress(milestone_id, "in_progress") 标记其为进行中。\n` +
55
- `3. 第三步:完成某一步骤后,通过 goal_update_progress(milestone_id, "completed", "阶段简要成果") 标记为已完成。\n` +
56
- `4. 第四步:当所有里程碑全部完成后,调用 goal_finish(summary) 工具并附带详尽的最终成果总结。`;
57
- }
58
- if (lang === 'ru') {
59
- return `🎯 Активирован режим цели (Goal Mode): "${goalText}"\n\n` +
60
- `СТРОГИЙ КОНТРАКТ АВТОНОМНОГО РЕЖИМА:\n` +
61
- `1. ОБЯЗАТЕЛЬНЫЙ ШАГ №1: Твоим ПЕРВЫМ действием ДО выполнения любой другой работы или ответа должен быть вызов инструмента goal_set_milestones с массивом из 3-7 конкретных, последовательных пунктов плана работ. Пользователь видит этот план в интерфейсе в реальном времени.\n` +
62
- `2. ШАГ №2: После установки плана переходи к выполнению шагов. Перед началом работы над каждым шагом отметь его статус как in_progress через goal_update_progress(milestone_id, "in_progress").\n` +
63
- `3. ШАГ №3: После успешного завершения шага отметь его статус как completed через goal_update_progress(milestone_id, "completed", "краткие итоги шага").\n` +
64
- `4. ШАГ №4: Когда все пункты плана выполнены, вызови инструмент goal_finish(summary) с подробным резюме достигнутых результатов.`;
65
- }
66
-
67
- return `🎯 Goal Mode activated: "${goalText}"\n\n` +
68
- `STRICT AUTONOMOUS CONTRACT:\n` +
69
- `1. MANDATORY STEP 1: Your FIRST action BEFORE doing any other work or reply MUST be calling tool goal_set_milestones with an array of 3-7 concrete, sequential milestones. The user sees this plan in real time.\n` +
70
- `2. STEP 2: After establishing the plan, proceed to execute milestones. Before starting each milestone, mark it as in_progress via goal_update_progress(milestone_id, "in_progress").\n` +
71
- `3. STEP 3: Upon completing a milestone, mark it as completed via goal_update_progress(milestone_id, "completed", "brief milestone outcome").\n` +
72
- `4. STEP 4: When all milestones are completed, call tool goal_finish(summary) with a comprehensive summary of achieved results.`;
73
- }
74
-
75
- /**
76
- * Форматирование текстового ответа для UI и постановка/управление задачей агента
77
- * @param {import('./goal-engine.js').GoalEngine} engine
78
- * @param {{ action: string, text?: string }} parsed
79
- * @param {Object} [config]
80
- * @param {Object} [agent]
81
- * @param {string} [sessionId='default']
82
- * @returns {{ kind: 'success' | 'error', text: string }}
83
- */
84
- export function executeGoalSlashCommand(engine, parsed, config = {}, agent = null, sessionId = 'default') {
85
- const sid = sessionId || 'default';
86
- const snap = engine.getSnapshot(sid);
87
-
88
- const lang = (parsed.text ? detectLanguage(parsed.text) : (snap.lang || (snap.title ? detectLanguage(snap.title) : 'en'))) || 'en';
89
- const isZh = lang === 'zh';
90
- const isRu = lang === 'ru';
91
- const usage = isZh ? USAGE_ZH : (isRu ? USAGE_RU : USAGE_EN);
92
-
93
- switch (parsed.action) {
94
- case 'show': {
95
- if (!snap.hasActiveGoal) {
96
- return {
97
- kind: 'success',
98
- text: isZh
99
- ? `🎯 目标模式 (Goal Mode): 当前未设置目标。\n${usage}`
100
- : (isRu
101
- ? `🎯 Режим цели (Goal Mode): цель не установлена.\n${usage}`
102
- : `🎯 Goal Mode: no active goal set.\n${usage}`),
103
- };
104
- }
105
-
106
- const milestonesInfo = snap.milestones.length > 0
107
- ? (isZh ? `\n工作计划:\n` : (isRu ? `\nПлан работ:\n` : `\nWork plan:\n`)) + snap.milestones.map((m, i) => ` ${i + 1}. [${m.status}] ${m.title}`).join('\n')
108
- : '';
109
-
110
- const etaText = snap.formattedETA ? ` (ETA: ${snap.formattedETA})` : '';
111
- const tokensInfo = (snap.tokensUsage && snap.tokensUsage.totalTokens > 0)
112
- ? (isZh
113
- ? `\nToken: ${snap.tokensUsage.totalTokens.toLocaleString()} (输入: ${snap.tokensUsage.promptTokens.toLocaleString()}, 输出: ${snap.tokensUsage.completionTokens.toLocaleString()})`
114
- : (isRu
115
- ? `\nТокены: ${snap.tokensUsage.totalTokens.toLocaleString()} (in: ${snap.tokensUsage.promptTokens.toLocaleString()}, out: ${snap.tokensUsage.completionTokens.toLocaleString()})`
116
- : `\nTokens: ${snap.tokensUsage.totalTokens.toLocaleString()} (in: ${snap.tokensUsage.promptTokens.toLocaleString()}, out: ${snap.tokensUsage.completionTokens.toLocaleString()})`))
117
- : '';
118
-
119
- return {
120
- kind: 'success',
121
- text: isZh
122
- ? `🎯 目标: "${snap.title}"\n` +
123
- `状态: ${snap.state}\n` +
124
- `耗时: ${snap.formattedElapsed}${etaText}\n` +
125
- `迭代轮次: ${snap.iterationsCount}/${snap.maxIterations}` +
126
- tokensInfo +
127
- milestonesInfo +
128
- `\n\n快捷指令: /goal pause, /goal resume, /goal clear, /goal <新目标>`
129
- : (isRu
130
- ? `🎯 Цель: «${snap.title}»\n` +
131
- `Статус: ${snap.state}\n` +
132
- `Время: ${snap.formattedElapsed}${etaText}\n` +
133
- `Итераций: ${snap.iterationsCount}/${snap.maxIterations}` +
134
- tokensInfo +
135
- milestonesInfo +
136
- `\n\nКоманды: /goal pause, /goal resume, /goal clear, /goal <новая цель>`
137
- : `🎯 Goal: "${snap.title}"\n` +
138
- `Status: ${snap.state}\n` +
139
- `Duration: ${snap.formattedElapsed}${etaText}\n` +
140
- `Iterations: ${snap.iterationsCount}/${snap.maxIterations}` +
141
- tokensInfo +
142
- milestonesInfo +
143
- `\n\nCommands: /goal pause, /goal resume, /goal clear, /goal <new goal>`),
144
- };
145
- }
146
-
147
- case 'clear': {
148
- if (!snap.hasActiveGoal) {
149
- return {
150
- kind: 'success',
151
- text: isZh ? '当前未设置目标。' : (isRu ? 'Цель не была установлена.' : 'No active goal set.'),
152
- };
153
- }
154
- engine.clear(sid);
155
- if (agent && typeof agent.cancel === 'function') {
156
- try {
157
- agent.cancel({ kind: 'user', reason: 'Goal cleared by user' });
158
- } catch (err) {
159
- console.warn('[dsh-goal] Failed to cancel agent on clear:', err);
160
- }
161
- }
162
- return {
163
- kind: 'success',
164
- text: isZh ? '🎯 目标已清除。' : (isRu ? '🎯 Цель сброшена.' : '🎯 Goal cleared.'),
165
- };
166
- }
167
-
168
- case 'pause': {
169
- if (!snap.hasActiveGoal) {
170
- return {
171
- kind: 'error',
172
- text: isZh
173
- ? `无法暂停:未设置活动目标。\n${usage}`
174
- : (isRu
175
- ? `Нельзя приостановить: активная цель отсутствует.\n${usage}`
176
- : `Cannot pause: no active goal.\n${usage}`),
177
- };
178
- }
179
- if (snap.state === GoalState.PAUSED) {
180
- return {
181
- kind: 'success',
182
- text: isZh ? '⏸ 目标当前已处于暂停状态。' : (isRu ? '⏸ Цель уже на паузе.' : '⏸ Goal is already paused.'),
183
- };
184
- }
185
- engine.pause(isZh ? '用户命令暂停 (/goal pause)' : (isRu ? 'Пауза по команде пользователя (/goal pause)' : 'Paused by user command (/goal pause)'), sid);
186
- if (agent && typeof agent.cancel === 'function') {
187
- try {
188
- agent.cancel({ kind: 'user', reason: 'Goal paused by user' });
189
- } catch (err) {
190
- console.warn('[dsh-goal] Failed to cancel agent on pause:', err);
191
- }
192
- }
193
- return {
194
- kind: 'success',
195
- text: isZh
196
- ? `⏸ 目标已暂停: "${snap.title}"。智能体已停止,使用 /goal resume ▶️ 按钮继续。`
197
- : (isRu
198
- ? `⏸ Цель приостановлена: «${snap.title}». Работа агента остановлена. Используйте /goal resume или кнопку ▶️ для продолжения.`
199
- : `⏸ Goal paused: "${snap.title}". Agent stopped. Use /goal resume or ▶️ button to continue.`),
200
- };
201
- }
202
-
203
- case 'resume': {
204
- if (!snap.hasActiveGoal) {
205
- return {
206
- kind: 'error',
207
- text: isZh
208
- ? `无法恢复:未设置活动目标。\n${usage}`
209
- : (isRu
210
- ? `Нельзя возобновить: активная цель отсутствует.\n${usage}`
211
- : `Cannot resume: no active goal.\n${usage}`),
212
- };
213
- }
214
- if (snap.state === GoalState.RUNNING) {
215
- return {
216
- kind: 'success',
217
- text: isZh ? '▶️ 目标已在运行中。' : (isRu ? '▶️ Цель уже выполняется.' : '▶️ Goal is already running.'),
218
- };
219
- }
220
- engine.resume(sid);
221
- if (agent && typeof agent.followup === 'function') {
222
- try {
223
- const resumePrompt = isZh
224
- ? `▶️ 用户已恢复目标运行。请继续推进工作计划中尚未完成的步骤。通过 goal_update_progress 实时更新进度。`
225
- : (isRu
226
- ? `▶️ Цель возобновлена пользователем. Продолжай выполнение плана работ с того места, где остановился. Отмечай шаги через goal_update_progress.`
227
- : `▶️ Goal resumed by user. Continue executing the work plan from where you stopped. Update steps via goal_update_progress.`);
228
- agent.followup(createGoalUserMessage(resumePrompt));
229
- } catch (err) {
230
- console.warn('[dsh-goal] Failed to followup agent on resume:', err);
231
- }
232
- }
233
- return {
234
- kind: 'success',
235
- text: isZh
236
- ? `▶️ 目标已恢复: "${snap.title}"。智能体继续工作中。`
237
- : (isRu
238
- ? `▶️ Цель возобновлена: «${snap.title}». Агент продолжает работу.`
239
- : `▶️ Goal resumed: "${snap.title}". Agent continues working.`),
240
- };
241
- }
242
-
243
- case 'start': {
244
- const maxIterations = config.maxIterations ?? snap.maxIterations ?? 25;
245
- const cwd = config.cwd;
246
- const newSnap = engine.startGoal(parsed.text, { maxIterations, lang, cwd }, sid);
247
-
248
- if (agent && typeof agent.followup === 'function') {
249
- try {
250
- const userMsg = createGoalUserMessage(formatGoalStartPrompt(parsed.text, lang));
251
- agent.followup(userMsg);
252
- } catch (err) {
253
- console.warn('[dsh-goal] Failed to dispatch goal to agent followup:', err);
254
- }
255
- }
256
-
257
- return {
258
- kind: 'success',
259
- text: isZh
260
- ? `🎯 目标已激活: "${newSnap.title}" (上限 ${newSnap.maxIterations} 轮迭代)。\n` +
261
- `暂停: /goal pause | 清除: /goal clear`
262
- : (isRu
263
- ? `🎯 Активирована цель: «${newSnap.title}» (макс. ${newSnap.maxIterations} итераций).\n` +
264
- `Для паузы: /goal pause | Для сброса: /goal clear`
265
- : `🎯 Goal activated: "${newSnap.title}" (max ${newSnap.maxIterations} iterations).\n` +
266
- `To pause: /goal pause | To clear: /goal clear`),
267
- };
268
- }
269
-
270
- default:
271
- return {
272
- kind: 'error',
273
- text: isZh ? `未知指令。${usage}` : (isRu ? `Неизвестная команда. ${usage}` : `Unknown command. ${usage}`),
274
- };
275
- }
276
- }
1
+ import { randomUUID } from 'node:crypto';
2
+ import { GoalState, detectLanguage } from './goal-engine.js';
3
+
4
+ export const USAGE_EN = 'Usage: /goal [<goal>|clear|pause|resume]';
5
+ export const USAGE_ZH = '用法: /goal [<目标描述>|clear|pause|resume]';
6
+
7
+ /**
8
+ * Parse input string for /goal command
9
+ * @param {string} rawInput
10
+ * @returns {{ action: string, text?: string }}
11
+ */
12
+ export function parseGoalInput(rawInput = '') {
13
+ const input = String(rawInput || '').trim();
14
+ if (!input) {
15
+ return { action: 'show' };
16
+ }
17
+
18
+ const lower = input.toLowerCase();
19
+ if (lower === 'clear') return { action: 'clear' };
20
+ if (lower === 'pause') return { action: 'pause' };
21
+ if (lower === 'resume') return { action: 'resume' };
22
+
23
+ return { action: 'start', text: input };
24
+ }
25
+
26
+ /**
27
+ * Create a valid identified user message for agent followup
28
+ * @param {string} text
29
+ * @returns {Object}
30
+ */
31
+ export function createGoalUserMessage(text) {
32
+ return {
33
+ id: randomUUID(),
34
+ role: 'user',
35
+ content: [{ type: 'text', text }],
36
+ source: { kind: 'user' },
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Format goal start prompt with mandatory milestone contract
42
+ * @param {string} goalText
43
+ * @param {string} [explicitLang]
44
+ * @returns {string}
45
+ */
46
+ export function formatGoalStartPrompt(goalText, explicitLang) {
47
+ const lang = explicitLang || detectLanguage(goalText);
48
+ if (lang === 'zh') {
49
+ return `🎯 目标模式已激活 (Goal Mode): "${goalText}"\n\n` +
50
+ `自主执行契约:\n` +
51
+ `1. 第一步必选动作:在开展任何工作或回复之前,你的第一个动作必须是调用 goal_set_milestones 工具,提交包含 3-7 个具体连续步骤的工作计划。用户将在界面中实时查看此计划。\n` +
52
+ `2. 第二步:计划确立后开始执行任务。在开始每个步骤前,通过 goal_update_progress(milestone_id, "in_progress") 标记其为进行中。\n` +
53
+ `3. 第三步:完成某一步骤后,通过 goal_update_progress(milestone_id, "completed", "阶段简要成果") 标记为已完成。\n` +
54
+ `4. 第四步:当所有里程碑全部完成后,调用 goal_finish(summary) 工具并附带详尽的最终成果总结。`;
55
+ }
56
+
57
+ return `🎯 Goal Mode activated: "${goalText}"\n\n` +
58
+ `STRICT AUTONOMOUS CONTRACT:\n` +
59
+ `1. MANDATORY STEP 1: Your FIRST action BEFORE doing any other work or reply MUST be calling tool goal_set_milestones with an array of 3-7 concrete, sequential milestones. The user sees this plan in real time.\n` +
60
+ `2. STEP 2: After establishing the plan, proceed to execute milestones. Before starting each milestone, mark it as in_progress via goal_update_progress(milestone_id, "in_progress").\n` +
61
+ `3. STEP 3: Upon completing a milestone, mark it as completed via goal_update_progress(milestone_id, "completed", "brief milestone outcome").\n` +
62
+ `4. STEP 4: When all milestones are completed, call tool goal_finish(summary) with a comprehensive summary of achieved results.`;
63
+ }
64
+
65
+ /**
66
+ * Format response for UI and manage agent task execution
67
+ * @param {import('./goal-engine.js').GoalEngine} engine
68
+ * @param {{ action: string, text?: string }} parsed
69
+ * @param {Object} [config]
70
+ * @param {Object} [agent]
71
+ * @param {string} [sessionId='default']
72
+ * @returns {{ kind: string, text: string }}
73
+ */
74
+ export function executeGoalSlashCommand(engine, parsed, config = {}, agent = null, sessionId = 'default') {
75
+ const sid = sessionId || 'default';
76
+ const snap = engine.getGoalSnapshot(sid);
77
+ const lang = snap.lang || (parsed.text ? detectLanguage(parsed.text) : 'en');
78
+ const isZh = lang === 'zh';
79
+ const usage = isZh ? USAGE_ZH : USAGE_EN;
80
+
81
+ switch (parsed.action) {
82
+ case 'show': {
83
+ if (!snap.hasActiveGoal) {
84
+ return {
85
+ kind: 'success',
86
+ text: isZh ? `目标模式: 当前未设置活动目标。\n${usage}` : `Goal Mode: no active goal set.\n${usage}`,
87
+ };
88
+ }
89
+
90
+ const milestonesInfo = snap.milestones && snap.milestones.length > 0
91
+ ? `\n\n${isZh ? '工作计划' : 'Work Plan'}:\n` +
92
+ snap.milestones
93
+ .map((m, i) => ` ${i + 1}. [${m.status.toUpperCase()}] ${m.title}${m.notes ? ` (${m.notes})` : ''}`)
94
+ .join('\n')
95
+ : '';
96
+
97
+ const etaText = snap.formattedETA ? ` (ETA: ${snap.formattedETA})` : '';
98
+ const tokensInfo = (snap.tokensUsage && snap.tokensUsage.totalTokens > 0)
99
+ ? (isZh
100
+ ? `\nToken: ${snap.tokensUsage.totalTokens.toLocaleString()} (输入: ${snap.tokensUsage.promptTokens.toLocaleString()}, 输出: ${snap.tokensUsage.completionTokens.toLocaleString()})`
101
+ : `\nTokens: ${snap.tokensUsage.totalTokens.toLocaleString()} (in: ${snap.tokensUsage.promptTokens.toLocaleString()}, out: ${snap.tokensUsage.completionTokens.toLocaleString()})`)
102
+ : '';
103
+
104
+ return {
105
+ kind: 'success',
106
+ text: isZh
107
+ ? `🎯 目标: "${snap.title}"\n` +
108
+ `状态: ${snap.state}\n` +
109
+ `耗时: ${snap.formattedElapsed}${etaText}\n` +
110
+ `迭代轮次: ${snap.iterationsCount}/${snap.maxIterations}` +
111
+ tokensInfo +
112
+ milestonesInfo +
113
+ `\n\n快捷指令: /goal pause, /goal resume, /goal clear, /goal <新目标>`
114
+ : `🎯 Goal: "${snap.title}"\n` +
115
+ `Status: ${snap.state}\n` +
116
+ `Duration: ${snap.formattedElapsed}${etaText}\n` +
117
+ `Iterations: ${snap.iterationsCount}/${snap.maxIterations}` +
118
+ tokensInfo +
119
+ milestonesInfo +
120
+ `\n\nCommands: /goal pause, /goal resume, /goal clear, /goal <new goal>`,
121
+ };
122
+ }
123
+
124
+ case 'clear': {
125
+ if (!snap.hasActiveGoal) {
126
+ return {
127
+ kind: 'success',
128
+ text: isZh ? '当前未设置目标。' : 'No active goal set.',
129
+ };
130
+ }
131
+ engine.clear(sid);
132
+ if (agent && typeof agent.cancel === 'function') {
133
+ try {
134
+ agent.cancel({ kind: 'user', reason: 'Goal cleared by user' });
135
+ } catch (err) {
136
+ // agent cancellation error handled defensively
137
+ }
138
+ }
139
+ return {
140
+ kind: 'success',
141
+ text: isZh ? '🎯 目标已清除。' : '🎯 Goal cleared.',
142
+ };
143
+ }
144
+
145
+ case 'pause': {
146
+ if (!snap.hasActiveGoal) {
147
+ return {
148
+ kind: 'error',
149
+ text: isZh
150
+ ? `无法暂停:未设置活动目标。\n${usage}`
151
+ : `Cannot pause: no active goal.\n${usage}`,
152
+ };
153
+ }
154
+ if (snap.state === GoalState.PAUSED) {
155
+ return {
156
+ kind: 'success',
157
+ text: isZh ? '⏸ 目标当前已处于暂停状态。' : 'Goal is already paused.',
158
+ };
159
+ }
160
+ engine.pause(isZh ? '用户命令暂停 (/goal pause)' : 'Paused by user command (/goal pause)', sid);
161
+ if (agent && typeof agent.cancel === 'function') {
162
+ try {
163
+ agent.cancel({ kind: 'user', reason: 'Goal paused by user' });
164
+ } catch (err) {
165
+ // agent cancellation error handled defensively
166
+ }
167
+ }
168
+ return {
169
+ kind: 'success',
170
+ text: isZh
171
+ ? `⏸ 目标已暂停: "${snap.title}"。智能体已停止,使用 /goal resume 或 ▶️ 按钮继续。`
172
+ : `⏸ Goal paused: "${snap.title}". Agent stopped. Use /goal resume or ▶️ button to continue.`,
173
+ };
174
+ }
175
+
176
+ case 'resume': {
177
+ if (!snap.hasActiveGoal) {
178
+ return {
179
+ kind: 'error',
180
+ text: isZh
181
+ ? `无法恢复:未设置活动目标。\n${usage}`
182
+ : `Cannot resume: no active goal.\n${usage}`,
183
+ };
184
+ }
185
+ if (snap.state === GoalState.RUNNING) {
186
+ return {
187
+ kind: 'success',
188
+ text: isZh ? '▶️ 目标已在运行中。' : '▶️ Goal is already running.',
189
+ };
190
+ }
191
+ engine.resume(sid);
192
+ if (agent && typeof agent.followup === 'function') {
193
+ try {
194
+ const resumePrompt = isZh
195
+ ? `▶️ 用户已恢复目标运行。请继续推进工作计划中尚未完成的步骤。通过 goal_update_progress 实时更新进度。`
196
+ : `▶️ Goal resumed by user. Continue executing the work plan from where you stopped. Update steps via goal_update_progress.`;
197
+ agent.followup(createGoalUserMessage(resumePrompt));
198
+ } catch (err) {
199
+ // agent followup error handled defensively
200
+ }
201
+ }
202
+ return {
203
+ kind: 'success',
204
+ text: isZh
205
+ ? `▶️ 目标已恢复: "${snap.title}"。智能体继续工作中。`
206
+ : `▶️ Goal resumed: "${snap.title}". Agent continues working.`,
207
+ };
208
+ }
209
+
210
+ case 'start': {
211
+ const goalLang = detectLanguage(parsed.text);
212
+ const isZhStart = goalLang === 'zh';
213
+ const maxIterations = config.maxIterations ?? snap.maxIterations ?? 25;
214
+ const cwd = config.cwd;
215
+ const newSnap = engine.startGoal(parsed.text, { maxIterations, lang: goalLang, cwd }, sid);
216
+
217
+ if (agent && typeof agent.followup === 'function') {
218
+ try {
219
+ const userMsg = createGoalUserMessage(formatGoalStartPrompt(parsed.text, goalLang));
220
+ agent.followup(userMsg);
221
+ } catch (err) {
222
+ // agent dispatch error handled defensively
223
+ }
224
+ }
225
+
226
+ return {
227
+ kind: 'success',
228
+ text: isZhStart
229
+ ? `🎯 目标已激活: "${newSnap.title}" (上限 ${newSnap.maxIterations} 轮迭代)。\n` +
230
+ `暂停: /goal pause | 清除: /goal clear`
231
+ : `🎯 Goal activated: "${newSnap.title}" (max ${newSnap.maxIterations} iterations).\n` +
232
+ `To pause: /goal pause | To clear: /goal clear`,
233
+ };
234
+ }
235
+
236
+ default:
237
+ return {
238
+ kind: 'error',
239
+ text: isZh ? `未知指令。${usage}` : `Unknown command. ${usage}`,
240
+ };
241
+ }
242
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Prompt generation for DSH Goal Mode
3
+ */
4
+ export function buildStatePromptInjection(snapshot, pendingNudge) {
5
+ const lang = snapshot.lang || 'en';
6
+ const hasMilestones = snapshot.milestones && snapshot.milestones.length > 0;
7
+ const etaText = snapshot.formattedETA ? ` (ETA: ${snapshot.formattedETA})` : '';
8
+
9
+ let nudgeText = '';
10
+ if (pendingNudge) {
11
+ if (lang === 'zh') {
12
+ nudgeText = `\n\n🚨 用户紧急补充说明 / 调整方向:\n"${pendingNudge}"\n你必须根据此说明调整近期的具体执行步骤!\n`;
13
+ } else {
14
+ nudgeText = `\n\n🚨 URGENT USER CLARIFICATION / STEERING:\n"${pendingNudge}"\nYou must adjust your immediate actions according to this guidance!\n`;
15
+ }
16
+ }
17
+
18
+ if (lang === 'zh') {
19
+ const milestonesText = hasMilestones
20
+ ? snapshot.milestones
21
+ .map((m, i) => ` ${i + 1}. [${m.status.toUpperCase()}] ${m.title}${m.notes ? ` (${m.notes})` : ''}`)
22
+ .join('\n')
23
+ : ' (工作计划尚未建立 — 请立即调用 goal_set_milestones 设定初始里程碑!)';
24
+
25
+ return (
26
+ nudgeText +
27
+ `\n\n[DSH GOAL MODE ACTIVE]\n` +
28
+ `目标: "${snapshot.title}"\n` +
29
+ `运行时间: ${snapshot.formattedElapsed}${etaText} | 迭代轮次: ${snapshot.iterationsCount}/${snapshot.maxIterations}\n` +
30
+ `工作计划:\n` +
31
+ `${milestonesText}\n\n` +
32
+ `Goal Mode 执行契约 (必须严格遵循):\n` +
33
+ `1. ${hasMilestones ? '按部就班推进当前进行中的里程碑。' : '第一步核心指令: 立即调用 goal_set_milestones 制定 3-7 个具体里程碑。在完成此工具调用前严禁执行其他操作!'}\n` +
34
+ `2. 推进里程碑时,必须通过 goal_update_progress 工具更新状态(开始前标为 in_progress,完成后标为 completed 并附简要说明)。\n` +
35
+ `3. 当所有里程碑全部完成后,调用 goal_finish 工具提交详细成果总结。`
36
+ );
37
+ }
38
+
39
+ const milestonesText = hasMilestones
40
+ ? snapshot.milestones
41
+ .map((m, i) => ` ${i + 1}. [${m.status.toUpperCase()}] ${m.title}${m.notes ? ` (${m.notes})` : ''}`)
42
+ .join('\n')
43
+ : ' (Work plan is not yet established — call goal_set_milestones immediately with initial steps!)';
44
+
45
+ return (
46
+ nudgeText +
47
+ `\n\n[DSH GOAL MODE ACTIVE]\n` +
48
+ `Goal: "${snapshot.title}"\n` +
49
+ `Elapsed Time: ${snapshot.formattedElapsed}${etaText} | Iteration: ${snapshot.iterationsCount}/${snapshot.maxIterations}\n` +
50
+ `Work Plan:\n` +
51
+ `${milestonesText}\n\n` +
52
+ `Goal Mode Instructions (MANDATORY TO FOLLOW):\n` +
53
+ `1. ${hasMilestones ? 'Execute the current active milestone from the work plan.' : 'YOUR FIRST STEP: Immediately call tool goal_set_milestones with the list of milestones (3-7 concrete steps). You must not execute work or finish turn without calling goal_set_milestones!'}\n` +
54
+ `2. As each milestone progresses, update its status via tool goal_update_progress (status: "in_progress" before starting, status: "completed" upon completion with brief notes).\n` +
55
+ `3. When all milestones are completed, call tool goal_finish with a detailed summary of achieved results.`
56
+ );
57
+ }