@khaentertainment/grok-swarm 1.3.4 → 1.3.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.
package/dist/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.4
1
+ 1.3.6
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khaentertainment/grok-swarm",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Multi-agent intelligence powered by Grok 4.20 via OpenRouter. Give any AI coding agent access to a 4-agent swarm with ~2M token context.",
5
5
  "keywords": [
6
6
  "grok",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khaentertainment/grok-swarm",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Multi-agent intelligence powered by Grok 4.20 via OpenRouter. Give any AI coding agent access to a 4-agent swarm with ~2M token context.",
5
5
  "keywords": [
6
6
  "grok",
@@ -31,6 +31,7 @@ from bridge.grok_bridge import (
31
31
  get_api_key,
32
32
  read_files,
33
33
  strip_pgp_blocks,
34
+ parse_and_write_files,
34
35
  MODE_PROMPTS,
35
36
  AGENT_COUNTS,
36
37
  )
@@ -57,13 +58,28 @@ log = logging.getLogger("grok-mcp")
57
58
  # ---------------------------------------------------------------------------
58
59
 
59
60
  SERVER_NAME = "grok-swarm"
60
- SERVER_VERSION = "1.3.4"
61
+ SERVER_VERSION = "1.3.6"
61
62
  PROTOCOL_VERSION = "2024-11-05"
62
63
 
63
64
  # ---------------------------------------------------------------------------
64
65
  # Tool definitions (JSON Schema format for MCP, NOT OpenAI format)
65
66
  # ---------------------------------------------------------------------------
66
67
 
68
+ # JSON Schema fragments parsed at import time so defaults use lowercase JSON
69
+ # true/false rather than Python True/False literals.
70
+ _WRITE_FILES_SCHEMA = json.loads(
71
+ '{"type": "boolean", "default": false, '
72
+ '"description": "Whether to parse and write code blocks from the response to disk."}'
73
+ )
74
+ _OUTPUT_DIR_SCHEMA = json.loads(
75
+ '{"type": "string", "default": "./grok-output/", '
76
+ '"description": "Output directory for write_files mode."}'
77
+ )
78
+ _BOOL_FALSE_SCHEMA = json.loads(
79
+ '{"type": "boolean", "default": false, '
80
+ '"description": "Whether to actually write changes (default: dry-run preview)."}'
81
+ )
82
+
67
83
  TOOLS = [
68
84
  {
69
85
  "name": "grok_query",
@@ -105,6 +121,8 @@ TOOLS = [
105
121
  "default": 120,
106
122
  "description": "API timeout in seconds.",
107
123
  },
124
+ "write_files": _WRITE_FILES_SCHEMA,
125
+ "output_dir": _OUTPUT_DIR_SCHEMA,
108
126
  },
109
127
  "required": ["prompt"],
110
128
  },
@@ -140,6 +158,16 @@ TOOLS = [
140
158
  "items": {"type": "string"},
141
159
  "description": "File paths to include as initial context.",
142
160
  },
161
+ "write_files": {
162
+ "type": "boolean",
163
+ "default": False,
164
+ "description": "Accepted for API consistency; applies only to grok_session_continue.",
165
+ },
166
+ "output_dir": {
167
+ "type": "string",
168
+ "default": "./grok-output/",
169
+ "description": "Accepted for API consistency; applies only to grok_session_continue.",
170
+ },
143
171
  },
144
172
  "required": [],
145
173
  },
@@ -166,6 +194,8 @@ TOOLS = [
166
194
  "items": {"type": "string"},
167
195
  "description": "Additional file paths to add as context.",
168
196
  },
197
+ "write_files": _WRITE_FILES_SCHEMA,
198
+ "output_dir": _OUTPUT_DIR_SCHEMA,
169
199
  },
170
200
  "required": ["session_id", "message"],
171
201
  },
@@ -189,11 +219,7 @@ TOOLS = [
189
219
  "default": ".",
190
220
  "description": "Target directory or file to operate on.",
191
221
  },
192
- "apply": {
193
- "type": "boolean",
194
- "default": False,
195
- "description": "Whether to actually write changes (default: dry-run preview).",
196
- },
222
+ "apply": _BOOL_FALSE_SCHEMA,
197
223
  "max_iterations": {
198
224
  "type": "integer",
199
225
  "default": 5,
@@ -222,6 +248,8 @@ def _handle_grok_query(params):
222
248
  system = params.get("system")
223
249
  thinking = params.get("thinking", "low")
224
250
  timeout = params.get("timeout", 120)
251
+ write_files = params.get("write_files", False)
252
+ output_dir = params.get("output_dir", "./grok-output/")
225
253
 
226
254
  if mode == "orchestrate" and not system:
227
255
  return _error_content("orchestrate mode requires the 'system' parameter")
@@ -255,7 +283,19 @@ def _handle_grok_query(params):
255
283
  return _error_content("Empty response from Grok API")
256
284
 
257
285
  content = response.choices[0].message.content or ""
258
- return _text_content(strip_pgp_blocks(content))
286
+ cleaned = strip_pgp_blocks(content)
287
+
288
+ if write_files:
289
+ try:
290
+ written = parse_and_write_files(cleaned, output_dir)
291
+ except (OSError, IOError) as exc:
292
+ log.error("Failed to write files: %s", exc)
293
+ return _error_content(f"Failed to write files: {exc}")
294
+ if written:
295
+ paths = ", ".join(p for p, _ in written)
296
+ return _text_content(f"{len(written)} file(s) written to {output_dir}: {paths}")
297
+ # Fall back to printing the response text if no files were written
298
+ return _text_content(cleaned)
259
299
 
260
300
 
261
301
  def _handle_grok_session_start(params):
@@ -266,6 +306,8 @@ def _handle_grok_session_start(params):
266
306
  system = params.get("system")
267
307
  thinking = params.get("thinking", "low")
268
308
  files = params.get("files", [])
309
+ # write_files and output_dir params are accepted for API consistency
310
+ # but apply to grok_session_continue, not the session start itself
269
311
 
270
312
  # Read initial file context
271
313
  file_context = ""
@@ -296,6 +338,8 @@ def _handle_grok_session_continue(params):
296
338
  session_id = params["session_id"]
297
339
  message = params["message"]
298
340
  files = params.get("files", [])
341
+ write_files = params.get("write_files", False)
342
+ output_dir = params.get("output_dir", "./grok-output/")
299
343
 
300
344
  session = session_mod.get_session(session_id)
301
345
  if session is None:
@@ -312,7 +356,17 @@ def _handle_grok_session_continue(params):
312
356
  log.error("Session %s error: %s", session_id, exc)
313
357
  return _error_content(f"Grok API error: {exc}")
314
358
 
315
- return _text_content(strip_pgp_blocks(response))
359
+ cleaned = strip_pgp_blocks(response)
360
+ if write_files:
361
+ try:
362
+ written = parse_and_write_files(cleaned, output_dir)
363
+ except (OSError, IOError) as exc:
364
+ log.error("Failed to write files to %s: %s", output_dir, exc)
365
+ return _error_content(f"Failed to write files: {exc}")
366
+ if written:
367
+ paths = ", ".join(p for p, _ in written)
368
+ return _text_content(f"{len(written)} file(s) written to {output_dir}: {paths}")
369
+ return _text_content(cleaned)
316
370
 
317
371
 
318
372
  def _handle_grok_agent(params):