@hatchway/cli 0.50.85 → 0.51.1

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/dist/index.js CHANGED
@@ -4440,18 +4440,11 @@ function createNativeClaudeQuery(modelId = DEFAULT_CLAUDE_MODEL_ID, abortControl
4440
4440
  // Enable SDK debug logging for skill discovery diagnostics
4441
4441
  ...(process.env.DEBUG_SKILLS === '1' ? { DEBUG_CLAUDE_AGENT_SDK: '1' } : {}),
4442
4442
  },
4443
- // Use preset tools from Claude Code
4443
+ // Use preset tools from Claude Code. The preset's task tracking is now the
4444
+ // built-in Task* tools (TodoWrite is deferred and not reliably loadable);
4445
+ // the runner translates Task* tool calls into TodoWrite-shaped progress
4446
+ // events the UI renders (see translateTaskToolsToTodos).
4444
4447
  tools: { type: 'preset', preset: 'claude_code' },
4445
- // The claude_code preset now ships built-in task tools (TaskCreate/Update/
4446
- // List) AND defers TodoWrite behind tool search. The agent reached for the
4447
- // task tools (which the Hatchway UI doesn't render) and, when those were
4448
- // disallowed, couldn't even find TodoWrite (3 failed ToolSearches) → no
4449
- // checklist, stuck "analyzing". Fix: SURFACE TodoWrite as a non-deferred,
4450
- // always-available tool (allowedTools is additive, not restrictive) AND
4451
- // disallow the task tools — so the agent reliably uses TodoWrite, which the
4452
- // UI renders and the todo-workflow skill mandates.
4453
- allowedTools: ['TodoWrite'],
4454
- disallowedTools: ['TaskCreate', 'TaskUpdate', 'TaskList'],
4455
4448
  // Pass abort controller for cancellation support
4456
4449
  // NOTE: There is a known bug in the Claude Agent SDK where AbortController
4457
4450
  // signals are not fully respected. When abort() is called, the SDK may
@@ -7878,6 +7871,8 @@ let transformerState = {
7878
7871
  messageStarted: false,
7879
7872
  commandMetadata: new Map(),
7880
7873
  toolNames: new Map(),
7874
+ taskTodos: new Map(),
7875
+ pendingTaskCreates: new Map(),
7881
7876
  };
7882
7877
  function resetTransformerState() {
7883
7878
  transformerState = {
@@ -7885,11 +7880,22 @@ function resetTransformerState() {
7885
7880
  messageStarted: false,
7886
7881
  commandMetadata: new Map(),
7887
7882
  toolNames: new Map(),
7883
+ taskTodos: new Map(),
7884
+ pendingTaskCreates: new Map(),
7888
7885
  };
7889
7886
  }
7890
7887
  function setExpectedCwd(cwd) {
7891
7888
  transformerState.expectedCwd = cwd;
7892
7889
  }
7890
+ /** Build a synthetic TodoWrite event from the accumulated Task* state. */
7891
+ function buildTaskTodoEvent() {
7892
+ return {
7893
+ type: 'tool-input-available',
7894
+ toolCallId: `task-todo-${Date.now()}-${Math.random().toString(16).slice(2)}`,
7895
+ toolName: 'TodoWrite',
7896
+ input: { todos: Array.from(transformerState.taskTodos.values()) },
7897
+ };
7898
+ }
7893
7899
  /**
7894
7900
  * Path violation detection - warns about absolute paths
7895
7901
  */
@@ -8096,6 +8102,26 @@ function transformAgentMessageToSSE(agentMessage) {
8096
8102
  toolName: block.name,
8097
8103
  input: block.input,
8098
8104
  });
8105
+ // Bridge Task* tools -> TodoWrite checklist the UI renders.
8106
+ if (block.name === 'TaskCreate') {
8107
+ const ti = block.input;
8108
+ const subject = ti?.subject || ti?.description || 'Task';
8109
+ // Resolve the task id from this call's result (see tool_result below).
8110
+ transformerState.pendingTaskCreates.set(block.id, subject);
8111
+ }
8112
+ else if (block.name === 'TaskUpdate') {
8113
+ const ti = block.input;
8114
+ const taskId = ti?.taskId ? String(ti.taskId) : undefined;
8115
+ if (taskId && transformerState.taskTodos.has(taskId)) {
8116
+ if (ti?.status === 'deleted') {
8117
+ transformerState.taskTodos.delete(taskId);
8118
+ }
8119
+ else if (ti?.status === 'pending' || ti?.status === 'in_progress' || ti?.status === 'completed') {
8120
+ transformerState.taskTodos.get(taskId).status = ti.status;
8121
+ }
8122
+ events.push(buildTaskTodoEvent());
8123
+ }
8124
+ }
8099
8125
  if (block.name === 'command_execution') {
8100
8126
  const command = typeof block.input?.command === 'string'
8101
8127
  ? block.input.command
@@ -8127,6 +8153,25 @@ function transformAgentMessageToSSE(agentMessage) {
8127
8153
  else if (typeof output !== 'string') {
8128
8154
  output = JSON.stringify(output);
8129
8155
  }
8156
+ // Bridge a TaskCreate result -> add the task to the TodoWrite checklist.
8157
+ // The result carries { task: { id, subject } }; pair it with the subject
8158
+ // captured from the tool_use call so TaskUpdate (by id) can update it.
8159
+ if (transformerState.pendingTaskCreates.has(toolId)) {
8160
+ const subject = transformerState.pendingTaskCreates.get(toolId);
8161
+ transformerState.pendingTaskCreates.delete(toolId);
8162
+ let taskId;
8163
+ try {
8164
+ const parsed = typeof output === 'string' ? JSON.parse(output) : output;
8165
+ taskId = parsed?.task?.id ? String(parsed.task.id) : undefined;
8166
+ }
8167
+ catch {
8168
+ // result wasn't JSON; skip — task just won't appear in the checklist
8169
+ }
8170
+ if (taskId) {
8171
+ transformerState.taskTodos.set(taskId, { content: subject, status: 'pending', activeForm: subject });
8172
+ events.push(buildTaskTodoEvent());
8173
+ }
8174
+ }
8130
8175
  // Process TodoWrite markers in command outputs
8131
8176
  if (typeof output === 'string' && output.includes('TODO_WRITE')) {
8132
8177
  const regex = /TODO_WRITE\s*:\s*(\{[\s\S]*?\})(?=$|\n)/g;