bingocode 1.1.183 → 1.1.184

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.
@@ -0,0 +1,34 @@
1
+ {
2
+ "tasks": [
3
+ {
4
+ "id": "274f11cf",
5
+ "cron": "0 9 * * *",
6
+ "prompt": "test prompt",
7
+ "createdAt": 1782997215925,
8
+ "recurring": true,
9
+ "name": "test-name",
10
+ "description": "test description",
11
+ "folder": "/test/folder",
12
+ "model": "claude-opus-4-7",
13
+ "permissionMode": "ask",
14
+ "worktree": false,
15
+ "frequency": "daily",
16
+ "scheduledTime": "09:00"
17
+ },
18
+ {
19
+ "id": "1c4152a1",
20
+ "cron": "0 9 * * *",
21
+ "prompt": "test prompt",
22
+ "createdAt": 1782998699654,
23
+ "recurring": true,
24
+ "name": "test-name",
25
+ "description": "test description",
26
+ "folder": "/test/folder",
27
+ "model": "claude-opus-4-7",
28
+ "permissionMode": "ask",
29
+ "worktree": false,
30
+ "frequency": "daily",
31
+ "scheduledTime": "09:00"
32
+ }
33
+ ]
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bingocode",
3
- "version": "1.1.183",
3
+ "version": "1.1.184",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -1793,38 +1793,86 @@ export function setPromptId(id: string | null): void {
1793
1793
  // /goal session state accessors
1794
1794
  // ============================================================================
1795
1795
 
1796
+ // ============================================================================
1797
+ // /goal session state accessors (DEPRECATED — use goalStore.ts instead)
1798
+ // ============================================================================
1799
+ // These accessors are kept for backwards compatibility with existing code.
1800
+ // They delegate to the new GoalStore in src/utils/goalStore.ts.
1801
+ // New code should import from goalStore.ts directly.
1802
+ // TODO: remove after all consumers are migrated.
1803
+
1804
+ import { getGoalState as _getGoalState } from '../utils/goalStore.js'
1805
+
1796
1806
  export function getGoalCondition(): string | null {
1797
- return STATE.goalCondition
1807
+ try {
1808
+ return _getGoalState().userGoal?.text ?? _getGoalState().operationalGoal?.text ?? null
1809
+ } catch {
1810
+ return STATE.goalCondition // fallback to old field during migration
1811
+ }
1798
1812
  }
1799
1813
 
1800
1814
  export function setGoalCondition(condition: string | null): void {
1801
- STATE.goalCondition = condition
1802
- STATE.goalIterationCount = 0
1815
+ if (condition) {
1816
+ try {
1817
+ // Delegate to new store for structured goal management
1818
+ const { setUserGoal: _setUserGoal, setOperationalGoal: _setOperationalGoal } = require('../utils/goalStore.js')
1819
+ _setUserGoal(condition)
1820
+ _setOperationalGoal(condition)
1821
+ } catch {
1822
+ STATE.goalCondition = condition // fallback
1823
+ STATE.goalIterationCount = 0
1824
+ }
1825
+ } else {
1826
+ STATE.goalCondition = null
1827
+ STATE.goalIterationCount = 0
1828
+ }
1803
1829
  }
1804
1830
 
1805
1831
  export function getGoalIterationCount(): number {
1806
- return STATE.goalIterationCount
1832
+ try {
1833
+ return _getGoalState().metrics.iterationCount
1834
+ } catch {
1835
+ return STATE.goalIterationCount
1836
+ }
1807
1837
  }
1808
1838
 
1809
1839
  export function incrementGoalIterationCount(): void {
1810
- STATE.goalIterationCount++
1840
+ try {
1841
+ const { incrementIteration } = require('../utils/goalStore.js')
1842
+ incrementIteration()
1843
+ } catch {
1844
+ STATE.goalIterationCount++
1845
+ }
1811
1846
  }
1812
1847
 
1813
1848
  export function getGoalMaxIterations(): number {
1814
- return STATE.goalMaxIterations
1849
+ try {
1850
+ return _getGoalState().metrics.maxIterations
1851
+ } catch {
1852
+ return STATE.goalMaxIterations
1853
+ }
1815
1854
  }
1816
1855
 
1817
- // Goal evaluator history accessors
1856
+ // Goal evaluator history accessors (DEPRECATED — use goalStore.ts)
1818
1857
  export function getGoalEvalHistory() {
1819
- return STATE.goalEvalHistory
1858
+ try {
1859
+ return _getGoalState().metrics.evalHistory
1860
+ } catch {
1861
+ return STATE.goalEvalHistory
1862
+ }
1820
1863
  }
1821
1864
 
1822
1865
  export function updateGoalEvalHistory(lastGap: string | null): void {
1823
- if (lastGap === STATE.goalEvalHistory.lastGap) {
1824
- STATE.goalEvalHistory.consecutiveSameGapCount++
1825
- } else {
1826
- STATE.goalEvalHistory.lastGap = lastGap
1827
- STATE.goalEvalHistory.consecutiveSameGapCount = 1
1866
+ try {
1867
+ const { recordEvalGap: _recordEvalGap } = require('../utils/goalStore.js')
1868
+ _recordEvalGap(lastGap)
1869
+ } catch {
1870
+ if (lastGap === STATE.goalEvalHistory.lastGap) {
1871
+ STATE.goalEvalHistory.consecutiveSameGapCount++
1872
+ } else {
1873
+ STATE.goalEvalHistory.lastGap = lastGap
1874
+ STATE.goalEvalHistory.consecutiveSameGapCount = 1
1875
+ }
1828
1876
  }
1829
1877
  }
1830
1878
 
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Goal Auto-Updater Hook — bridges agent tool execution with goal state.
3
+ *
4
+ * Monitors PostToolUse events and automatically updates goal state in real-time.
5
+ * This replaces the manual "output EVAL blocks" approach with automatic state
6
+ * tracking based on what the agent actually does.
7
+ *
8
+ * Integration point: called in REPL.tsx after each tool execution completes.
9
+ * Uses the GoalStore to update state, which triggers re-renders in any
10
+ * subscribed components via the signal pattern.
11
+ */
12
+
13
+ import type { ToolResult, SubGoalStatus } from '../types/goal.js'
14
+ import { getGoalState, addArtifact, updateSubGoalStatus, recalculateProgress } from '../utils/goalStore.js'
15
+ import { asSubGoalId } from '../utils/goalHelpers.js'
16
+ import { assessDrift } from '../utils/goalDrift.js'
17
+ import type { DriftAssessment, SubGoal } from '../types/goal.js'
18
+
19
+ /**
20
+ * Classify a tool execution result into a goal-relevant action category.
21
+ * Returns null if the tool is not relevant to goal progress tracking.
22
+ */
23
+ function classifyToolAction(
24
+ toolName: string,
25
+ toolInput: Record<string, unknown>,
26
+ toolOutput: string,
27
+ success: boolean,
28
+ ): ToolAction | null {
29
+ // Read-only tools (query) → informational, not state-changing
30
+ if (isReadTool(toolName)) return null
31
+
32
+ // Write tools (create/modify)
33
+ if (isCreateTool(toolName)) {
34
+ const filePath = extractFilePath(toolInput)
35
+ return {
36
+ type: 'create',
37
+ filePath,
38
+ subGoalId: inferSubGoal(toolName, filePath),
39
+ description: `Created ${filePath}`,
40
+ }
41
+ }
42
+
43
+ // Build tools (verify)
44
+ if (isVerifyTool(toolName)) {
45
+ return {
46
+ type: 'verify',
47
+ filePath: extractFilePath(toolInput),
48
+ subGoalId: inferSubGoal(toolName, extractFilePath(toolInput)),
49
+ description: `Verified with ${toolName}`,
50
+ }
51
+ }
52
+
53
+ // Default: generic mutation
54
+ return {
55
+ type: 'modify',
56
+ filePath: extractFilePath(toolInput),
57
+ subGoalId: inferSubGoal(toolName, extractFilePath(toolInput)),
58
+ description: `Modified via ${toolName}`,
59
+ }
60
+ }
61
+
62
+ type ToolAction = {
63
+ type: 'create' | 'modify' | 'verify'
64
+ filePath: string
65
+ subGoalId: string
66
+ description: string
67
+ }
68
+
69
+ /** Update goal state after a tool execution. Called from REPL.tsx after
70
+ * each PostToolUse event. Also performs drift assessment to detect
71
+ * when agent behavior starts deviating from target goals. */
72
+ export function useGoalAutoUpdater(
73
+ toolResult: ToolResult,
74
+ ): void {
75
+ const state = getGoalState()
76
+ if (!state.activeGoalId) return
77
+ if (!state.operationalGoal) return
78
+
79
+ const action = classifyToolAction(
80
+ toolResult.toolName,
81
+ toolResult.toolInput,
82
+ toolResult.toolOutput,
83
+ toolResult.success,
84
+ )
85
+
86
+ if (!action) return
87
+
88
+ // Phase 1: Update goal state based on action type
89
+ switch (action.type) {
90
+ case 'create':
91
+ addArtifact(action.filePath)
92
+ break
93
+ case 'modify':
94
+ addArtifact(action.filePath)
95
+ break
96
+ case 'verify':
97
+ updateSubGoalStatus(action.subGoalId, 'active')
98
+ break
99
+ }
100
+
101
+ // Phase 2: Recalculate progress after state mutation
102
+ recalculateProgress()
103
+
104
+ // Phase 3: Assess drift (after state update, before next turn)
105
+ const currentSubGoal = state.dag.nodes.get(action.subGoalId)
106
+ if (currentSubGoal) {
107
+ const drift = assessDrift(
108
+ action.description ?? `${toolResult.toolName}: ${toolResult.toolOutput.slice(0, 100)}`,
109
+ currentSubGoal,
110
+ state.operationalGoal.text,
111
+ )
112
+
113
+ // Log drift warnings for debugging — future: escalate to enqueue()
114
+ if (drift.warnings.length > 0) {
115
+ const highWarnings = drift.warnings.filter(w => w.severity === 'high')
116
+ if (highWarnings.length > 0) {
117
+ // Drift is severe — agent should replan
118
+ // TODO: wire into enqueue() for user-visible warning
119
+ console.warn(`[GoalDrift] ${drift.warnings.length} warning(s): score ${drift.consistencyScore}%, trend ${drift.trend}`)
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ // ============================================================================
126
+ // Helpers
127
+ // ============================================================================
128
+
129
+ /** Check if a tool is read-only (doesn't modify state). */
130
+ function isReadTool(toolName: string): boolean {
131
+ const readTools = new Set([
132
+ 'Read',
133
+ 'Glob',
134
+ 'Grep',
135
+ 'LS',
136
+ 'WebSearch',
137
+ 'WebFetch',
138
+ 'TaskOutput',
139
+ 'TaskStatus',
140
+ ])
141
+ return readTools.has(toolName)
142
+ }
143
+
144
+ /** Check if a tool creates new files. */
145
+ function isCreateTool(toolName: string): boolean {
146
+ const createTools = new Set([
147
+ 'Write',
148
+ 'Edit', // can create or modify, but classified as create for new files
149
+ 'NotebookEdit',
150
+ ])
151
+ return createTools.has(toolName)
152
+ }
153
+
154
+ /** Check if a tool verifies existing work (tests, builds). */
155
+ function isVerifyTool(toolName: string): boolean {
156
+ const verifyTools = new Set([
157
+ 'Bash', // often used for test/build commands
158
+ ])
159
+ return verifyTools.has(toolName)
160
+ }
161
+
162
+ /** Extract file path from tool input. Handles different tool input shapes. */
163
+ function extractFilePath(input: Record<string, unknown>): string {
164
+ if (typeof input.file_path === 'string') return input.file_path
165
+ if (typeof input.path === 'string') return input.path
166
+ if (typeof input.notebook_path === 'string') return input.notebook_path
167
+ return ''
168
+ }
169
+
170
+ /** Infer which sub-goal this tool action likely belongs to.
171
+ * Uses file path heuristics to match against known sub-goals. */
172
+ function inferSubGoal(toolName: string, filePath: string): string {
173
+ // For now, use a simple heuristic — match by file path pattern
174
+ // This will be enhanced in Phase 6 with actual DAG integration
175
+ if (!filePath) return 'unknown'
176
+
177
+ // Strip the path and use the filename as a sub-goal identifier
178
+ // In practice, the real mapping will come from the DAG's SubGoal nodes
179
+ const fileName = filePath.split('/').pop()?.split('\\').pop() ?? filePath
180
+ return `task-${fileName}`
181
+ }
182
+
183
+ // ============================================================================
184
+ // Re-export for convenience
185
+ // ============================================================================
186
+
187
+ export { getGoalState as useGoalStore }
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Goal evaluator hook — post-turn goal assessment.
3
+ *
4
+ * Fires after each turn completes (triggered by lastQueryCompletionTime change).
5
+ * Evaluates progress toward active goal using env-aware evaluator v2.
6
+ */
7
+
1
8
  import { useEffect, useRef } from 'react'
2
9
  import type { MutableRefObject } from 'react'
3
10
  import type { MessageType } from '../components/messages.js'
@@ -10,6 +17,7 @@ import {
10
17
  getGoalEvalHistory,
11
18
  updateGoalEvalHistory,
12
19
  } from '../bootstrap/state.js'
20
+ import { getGoalState, recalculateProgress } from '../utils/goalStore.js'
13
21
  import { enqueue } from '../utils/messageQueueManager.js'
14
22
  import { evaluateGoal } from '../utils/goalEvaluator.js'
15
23
 
@@ -20,16 +28,15 @@ type UseGoalEvaluatorParams = {
20
28
  }
21
29
 
22
30
  /**
23
- * React hook that fires an independent goal evaluator after each turn.
24
- *
25
- * Triggered by lastQueryCompletionTime changing (set in REPL.tsx after
26
- * queryGuard.end() succeeds). Uses messagesRef (not React state) to avoid
27
- * batching issues — the ref is synchronously updated via Zustand pattern
28
- * before React re-renders.
31
+ * React hook fires after each turn. Triggered by lastQueryCompletionTime.
32
+ * Uses messagesRef (sync ref, not React state) to avoid batching issues.
29
33
  *
30
- * On goal not satisfied: enqueues a continuation message with priority 'now'
31
- * so useQueueProcessor picks it up immediately for the next turn.
32
- * On goal satisfied or max iterations reached: clears the goal condition.
34
+ * Flow:
35
+ * 1. Check max iterations reached if so, stop
36
+ * 2. Call env-aware evaluator v2 (rule engine + Haiku + main model)
37
+ * 3. On satisfied → clear goal, enqueue success message
38
+ * 4. On repeated gap (3x) → circuit breaker, clear goal
39
+ * 5. On not satisfied → enqueue continuation message
33
40
  */
34
41
  export function useGoalEvaluator({
35
42
  lastQueryCompletionTime,
@@ -55,6 +62,7 @@ export function useGoalEvaluator({
55
62
  const iterCount = getGoalIterationCount()
56
63
  const maxIter = getGoalMaxIterations()
57
64
 
65
+ // Max iterations check
58
66
  if (iterCount >= maxIter) {
59
67
  setGoalCondition(null)
60
68
  enqueue({
@@ -65,17 +73,24 @@ export function useGoalEvaluator({
65
73
  return
66
74
  }
67
75
 
68
- // Read snapshot BEFORE await to avoid stale data
76
+ // Get current goal state + sub-goal from store
69
77
  const messages = messagesRef.current
70
- const result = await evaluateGoal(condition, messages)
78
+ const goalState = getGoalState()
79
+ const currentSubGoal = goalState.immediateGoal
80
+ ? goalState.dag.nodes.get(goalState.immediateGoal.subGoalId)
81
+ : undefined
82
+
83
+ // Run environment-aware evaluation
84
+ const result = await evaluateGoal(condition, messages, currentSubGoal)
71
85
 
72
- // Race protection: user may have called /goal clear during the await
86
+ // Race: user may have cleared goal during await
73
87
  if (getGoalCondition() !== condition) return
74
88
 
75
89
  incrementGoalIterationCount()
76
90
  updateGoalEvalHistory(result.gap)
91
+ recalculateProgress()
77
92
 
78
- // Check for repeated gaps - implement circuit breaker
93
+ // Circuit breaker: 3 consecutive same gap
79
94
  const evalHistory = getGoalEvalHistory()
80
95
  const isRepeatedGap = evalHistory.consecutiveSameGapCount >= 3 && result.gap !== null
81
96
 
@@ -87,10 +102,9 @@ export function useGoalEvaluator({
87
102
  priority: 'now',
88
103
  })
89
104
  } else if (isRepeatedGap) {
90
- // Circuit breaker: stop after 3 repeated gaps
91
105
  setGoalCondition(null)
92
106
  enqueue({
93
- value: `⚠️ Goal evaluator stopped after detecting the same gap "${result.gap}" 3 times in a row. Please adjust your approach or output EVAL blocks in the correct format.`,
107
+ value: `⚠️ Goal evaluator stopped same gap "${result.gap}" 3x. Adjust approach or output EVAL blocks.`,
94
108
  mode: 'task-notification',
95
109
  priority: 'now',
96
110
  })
@@ -108,6 +122,5 @@ export function useGoalEvaluator({
108
122
  evaluating.current = false
109
123
  }
110
124
  })()
111
- // messages intentionally excluded from deps — read via ref to avoid batching issues
112
125
  }, [lastQueryCompletionTime, isQueryActive])
113
126
  }
package/src/query.ts CHANGED
@@ -110,6 +110,8 @@ import {
110
110
  } from './bootstrap/state.js'
111
111
  import { createBudgetTracker, checkTokenBudget } from './query/tokenBudget.js'
112
112
  import { count } from './utils/array.js'
113
+ import { convertSDKToolResults } from './utils/goalHelpers.js'
114
+ import { useGoalAutoUpdater } from './hooks/useGoalAutoUpdater.js'
113
115
 
114
116
  /* eslint-disable @typescript-eslint/no-require-imports */
115
117
  const snipModule = feature('HISTORY_SNIP')
@@ -1408,6 +1410,25 @@ async function* queryLoop(
1408
1410
  }
1409
1411
  queryCheckpoint('query_tool_execution_end')
1410
1412
 
1413
+ // === Goal system auto-update: PostToolUse hook ===
1414
+ // Update goal state based on actual tool execution results.
1415
+ // This replaces the old "output EVAL blocks" approach — now we track
1416
+ // progress automatically from what the agent actually does.
1417
+ if (toolUseBlocks.length > 0) {
1418
+ try {
1419
+ const goalResults = convertSDKToolResults(
1420
+ toolUseBlocks as ReadonlyArray<{ id: string; name: string; input: Record<string, unknown> }>,
1421
+ toolResults as ReadonlyArray<{ type: string; message: { content: { type: string; text?: string; tool_use_id?: string; content?: string }[] } }>,
1422
+ )
1423
+ for (const result of goalResults) {
1424
+ useGoalAutoUpdater(result)
1425
+ }
1426
+ } catch (err) {
1427
+ // Goal auto-update is non-critical — don't block the main loop
1428
+ logError('goal_auto_update_error', err instanceof Error ? err.message : String(err))
1429
+ }
1430
+ }
1431
+
1411
1432
  // Generate tool use summary after tool batch completes — passed to next recursive call
1412
1433
  let nextPendingToolUseSummary:
1413
1434
  | Promise<ToolUseSummaryMessage | null>
@@ -1,27 +1,30 @@
1
- import {
2
- getGoalCondition,
3
- getGoalMaxIterations,
4
- setGoalCondition,
5
- } from '../../bootstrap/state.js'
1
+ /**
2
+ * Goal command — CLI entry point for Goal Management system.
3
+ *
4
+ * 4-layer architecture: User Goal → Operational Goal → Sub Goals → Immediate Goal.
5
+ * Orchestrates creation, status queries, and management commands.
6
+ */
7
+
8
+ import { getGoalState, setUserGoal, setOperationalGoal, clearState } from '../../utils/goalStore.js'
6
9
  import { registerBundledSkill } from '../bundledSkills.js'
7
10
 
8
- const USAGE = `Usage: /goal <condition>
11
+ const USAGE = `Usage: /goal <create | clear | cancel>
9
12
 
10
- Set a session goal. The agent will keep working until the condition is met.
13
+ Set a session goal. Agent will work autonomously until goal met.
11
14
 
12
15
  Examples:
13
- /goal all tests pass
14
- /goal login flow handles empty email without crash
15
- /goal PR is ready for review with passing CI
16
+ /goal create all tests pass
17
+ /goal create login flow handles empty email without crash
18
+ /goal create PR ready for review with passing CI
16
19
 
17
- To cancel: /goal clear`
20
+ To cancel: /goal clear or /goal cancel`
18
21
 
19
22
  export function registerGoalSkill(): void {
20
23
  registerBundledSkill({
21
24
  name: 'goal',
22
25
  description:
23
- 'Set a session-level goal condition and loop until met. Use when user says "/goal <condition>" or wants autonomous execution until a specific outcome is reached.',
24
- argumentHint: '<condition | clear>',
26
+ 'Manage task goals with hierarchical decomposition and progress tracking.',
27
+ argumentHint: '<create | clear | cancel>',
25
28
  userInvocable: true,
26
29
  async getPromptForCommand(args) {
27
30
  const trimmed = args.trim()
@@ -30,48 +33,54 @@ export function registerGoalSkill(): void {
30
33
  return [{ type: 'text', text: USAGE }]
31
34
  }
32
35
 
33
- if (['clear', 'stop', 'cancel'].includes(trimmed)) {
34
- const current = getGoalCondition()
35
- if (current) {
36
- setGoalCondition(null)
36
+ // --- Cancel / Clear ---
37
+ if (['clear', 'stop', 'cancel'].includes(trimmed.toLowerCase())) {
38
+ const state = getGoalState()
39
+ if (state.activeGoalId) {
40
+ const userText = state.userGoal?.text ?? '(unknown)'
41
+ clearState()
37
42
  return [
38
43
  {
39
44
  type: 'text',
40
- text: `Goal cancelled: "${current}". Tell the user their goal has been cancelled.`,
45
+ text: `Goal cancelled: "${userText}". Goal state cleared from memory and disk.`,
41
46
  },
42
47
  ]
43
48
  }
44
49
  return [
45
50
  {
46
51
  type: 'text',
47
- text: 'No active goal to cancel. Tell the user there is no active goal.',
52
+ text: 'No active goal. Use `/goal create <text>` to start.',
48
53
  },
49
54
  ]
50
55
  }
51
56
 
52
- setGoalCondition(trimmed)
53
- const maxIter = getGoalMaxIterations()
57
+ // --- Create ---
58
+ setUserGoal(trimmed)
59
+ setOperationalGoal(trimmed)
60
+ const state = getGoalState()
61
+ const maxIter = state.metrics.maxIterations
54
62
 
55
63
  return [
56
64
  {
57
65
  type: 'text',
58
66
  text: `# /goal activated
59
67
 
60
- Goal condition: "${trimmed}"
61
-
62
- This goal is now registered for this session. After each turn, an independent evaluator (Haiku 4.5, a weak model) will check whether the goal is satisfied. Maximum ${maxIter} iterations.
68
+ **Goal**: "${trimmed}"
69
+ **Architecture**: User Goal → Operational Goal → DAG Sub Goals → Immediate Action
70
+ **Max iterations**: ${maxIter}
63
71
 
64
- CRITICAL: The evaluator reads ONLY your text output. It cannot see code changes, tool results, or file contents — only the plain text you write.
72
+ The evaluator now uses **environment-aware assessment** (3 tiers):
73
+ Level 1: Rule engine — checks file existence, test output, compile status
74
+ Level 2: Haiku 4.5 — semantic interpretation of evidence
75
+ Level 3: Main model — final verification (ambiguous cases only)
65
76
 
66
- At each turn toward the goal, output a short evaluation block like:
67
- EVAL: [metric1]: [value] / [target] → ✓ or
77
+ EVAL blocks still welcome for agent self-reporting, but no longer required.
78
+ Format: \`EVAL: metric: value / target → ✓ or ✗\`
68
79
 
69
- This block is the ONLY signal the evaluator can reliably process. Make it short,
70
- unambiguous, and quantitative. Do NOT expect the evaluator to infer success from narrative discussion.
71
- Note: The EVAL block can appear anywhere in your text response (not just in quote blocks).
80
+ Tell user: Goal set. Agent works autonomously until "${trimmed}" achieved (max ${maxIter} turns).
81
+ Send \`/goal clear\` to cancel.
72
82
 
73
- Tell the user: Goal set you will work autonomously until "${trimmed}" is achieved (max ${maxIter} turns). Send \`/goal clear\` to cancel.
74
- Now begin: assess current state and take the first concrete action toward the goal.`,
83
+ Now: assess current state, take first concrete action toward goal.`,
75
84
  },
76
85
  ]
77
86
  },