alchemylab 1.0.5 → 1.0.7

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.
@@ -89,12 +89,33 @@ function extractToolEventInfo(toolName, input, resultText, sessionId) {
89
89
  const isDocumentOps = toolName.includes('document_operations');
90
90
  const isQueryHistory = toolName.includes('query_history');
91
91
  if (isRequestOps && resultText) {
92
+ const toolArgs = input?.args || input?.input || {};
93
+ const operation = toolArgs.operation;
92
94
  const requestId = extractRequestId(resultText);
95
+ // Debug: log what we see for request ops to diagnose hook firing
96
+ try {
97
+ const fs = require('fs'), path = require('path');
98
+ const debugPath = path.join(process.env.ALCHEMY_PROJECT_PATH || process.cwd(), '.alchemy_lab', 'hook-debug.log');
99
+ const inputKeys = Object.keys(input || {}).join(',');
100
+ const inputInputKeys = Object.keys(input?.input || {}).join(',');
101
+ fs.appendFileSync(debugPath, `[${new Date().toISOString()}] request_ops: tool=${toolName} op=${operation} reqId=${requestId} inputKeys=[${inputKeys}] input.inputKeys=[${inputInputKeys}] input.input.op=${input?.input?.operation} input.operation=${input?.operation} result=${resultText?.substring(0, 80)}\n`);
102
+ }
103
+ catch { }
93
104
  if (requestId) {
94
- events.push({
95
- eventType: 'request_completed',
96
- variables: { ...baseVars, requestId },
97
- });
105
+ if (operation === 'merge' || operation === 'finalize') {
106
+ // Actual merge to main
107
+ events.push({
108
+ eventType: 'request_completed',
109
+ variables: { ...baseVars, requestId },
110
+ });
111
+ }
112
+ else if (operation === 'complete') {
113
+ // Phase 1 — work done, ready for merge
114
+ events.push({
115
+ eventType: 'request_ready_for_merge',
116
+ variables: { ...baseVars, requestId },
117
+ });
118
+ }
98
119
  }
99
120
  }
100
121
  else if (isTaskOps && resultText) {
@@ -114,7 +135,16 @@ function extractToolEventInfo(toolName, input, resultText, sessionId) {
114
135
  });
115
136
  }
116
137
  else if (isReplaceInFiles) {
117
- const operations = input?.input?.operations || [];
138
+ const replaceArgs = input?.args || input?.input || {};
139
+ let operations = replaceArgs.operations || [];
140
+ if (typeof operations === 'string') {
141
+ try {
142
+ operations = JSON.parse(operations);
143
+ }
144
+ catch {
145
+ operations = [];
146
+ }
147
+ }
118
148
  const paths = operations.map((op) => op.path || op.documentId).filter(Boolean);
119
149
  events.push({
120
150
  eventType: 'replace_in_files',
@@ -124,8 +154,8 @@ function extractToolEventInfo(toolName, input, resultText, sessionId) {
124
154
  else if (isQuickEdit) {
125
155
  const vars = {
126
156
  ...baseVars,
127
- path: input?.input?.operationArgs?.path || '',
128
- title: input?.input?.title || '',
157
+ path: (input?.args || input?.input)?.operationArgs?.path || '',
158
+ title: (input?.args || input?.input)?.title || '',
129
159
  };
130
160
  const qeRequestMatch = resultText?.match(/\*\*Request:\*\*\s*(req\d+)/i);
131
161
  if (qeRequestMatch)
@@ -140,7 +170,15 @@ function extractToolEventInfo(toolName, input, resultText, sessionId) {
140
170
  }
141
171
  }
142
172
  else if (isReadFiles) {
143
- const pathsInput = input?.input?.paths || [];
173
+ let pathsInput = (input?.args || input?.input)?.paths || [];
174
+ if (typeof pathsInput === 'string') {
175
+ try {
176
+ pathsInput = JSON.parse(pathsInput);
177
+ }
178
+ catch {
179
+ pathsInput = [];
180
+ }
181
+ }
144
182
  const paths = pathsInput.map((p) => p.path || p.documentId).filter(Boolean);
145
183
  events.push({
146
184
  eventType: 'read_files',
@@ -152,15 +190,24 @@ function extractToolEventInfo(toolName, input, resultText, sessionId) {
152
190
  eventType: 'search',
153
191
  variables: {
154
192
  ...baseVars,
155
- query: input?.input?.needle || '',
156
- directory: input?.input?.directory || '',
157
- fileExtension: input?.input?.options?.fileExtension || '*',
193
+ query: (input?.args || input?.input)?.needle || '',
194
+ directory: (input?.args || input?.input)?.directory || '',
195
+ fileExtension: (input?.args || input?.input)?.options?.fileExtension || '*',
158
196
  },
159
197
  });
160
198
  }
161
199
  else if (isManageFiles) {
162
- const operations = input?.input?.operations || [];
163
- const opTypes = operations.map((op) => op.operationType).filter(Boolean);
200
+ const manageArgs = input?.args || input?.input || {};
201
+ let manageOps = manageArgs.operations || [];
202
+ if (typeof manageOps === 'string') {
203
+ try {
204
+ manageOps = JSON.parse(manageOps);
205
+ }
206
+ catch {
207
+ manageOps = [];
208
+ }
209
+ }
210
+ const opTypes = manageOps.map((op) => op.operationType).filter(Boolean);
164
211
  events.push({
165
212
  eventType: 'manage_files',
166
213
  variables: { ...baseVars, operationTypes: [...new Set(opTypes)].join(', ') },
@@ -227,7 +274,7 @@ exports.default = async ({ directory }) => {
227
274
  if (!toolName)
228
275
  return;
229
276
  const sessionId = input?.sessionID || '';
230
- const inputText = JSON.stringify(input?.input || {}).substring(0, 1000);
277
+ const inputText = JSON.stringify(input?.args || input?.input || {}).substring(0, 1000);
231
278
  postHookEvent('tool_executed', sessionId, {
232
279
  tool: toolName,
233
280
  toolName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemylab",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "private": false,
5
5
  "description": "AlchemyLab - agentic coding IDEm",
6
6
  "author": "Testfire Software",