@zachjxyz/moxie 0.4.2 → 0.4.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.
package/bin/moxie CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  set -euo pipefail
18
18
 
19
- MOXIE_VERSION="0.4.2"
19
+ MOXIE_VERSION="0.4.4"
20
20
  # Resolve symlinks (npm installs bin as a symlink)
21
21
  _self="$0"
22
22
  while [ -L "$_self" ]; do
@@ -47,6 +47,14 @@ function toolWriteFile(args) {
47
47
  return `Written ${args.content.length} bytes to ${args.path}`;
48
48
  }
49
49
 
50
+ function toolAppendFile(args) {
51
+ const filepath = resolve(CWD, args.path);
52
+ mkdirSync(dirname(filepath), { recursive: true });
53
+ const existing = existsSync(filepath) ? readFileSync(filepath, 'utf8') : '';
54
+ writeFileSync(filepath, existing + args.content, 'utf8');
55
+ return `Appended ${args.content.length} bytes to ${args.path} (total: ${existing.length + args.content.length} bytes)`;
56
+ }
57
+
50
58
  function toolEditFile(args) {
51
59
  const filepath = resolve(CWD, args.path);
52
60
  if (!existsSync(filepath)) return `Error: File not found: ${args.path}`;
@@ -157,6 +165,7 @@ function executeTool(name, args) {
157
165
  switch (name) {
158
166
  case 'read_file': return toolReadFile(args);
159
167
  case 'write_file': return toolWriteFile(args);
168
+ case 'append_file': return toolAppendFile(args);
160
169
  case 'edit_file': return toolEditFile(args);
161
170
  case 'run_command': return toolRunCommand(args);
162
171
  case 'list_directory': return toolListDirectory(args);
@@ -203,6 +212,21 @@ const TOOL_DEFINITIONS = [
203
212
  },
204
213
  },
205
214
  },
215
+ {
216
+ type: 'function',
217
+ function: {
218
+ name: 'append_file',
219
+ description: 'Append content to a file. Creates the file if it does not exist. Use this to write large documents incrementally — one section at a time.',
220
+ parameters: {
221
+ type: 'object',
222
+ properties: {
223
+ path: { type: 'string', description: 'File path relative to project root' },
224
+ content: { type: 'string', description: 'Content to append' },
225
+ },
226
+ required: ['path', 'content'],
227
+ },
228
+ },
229
+ },
206
230
  {
207
231
  type: 'function',
208
232
  function: {
@@ -286,13 +310,21 @@ const TOOL_DEFINITIONS = [
286
310
 
287
311
  const SYSTEM_PROMPT = `You are a coding agent working in the directory: ${CWD}
288
312
 
289
- You have access to tools for reading, writing, and editing files, running shell commands, listing directories, and searching code. Use these tools to accomplish the task given to you.
313
+ You have access to tools for reading, writing, editing, and appending to files, running shell commands, listing directories, and searching code. Use these tools to accomplish the task given to you.
290
314
 
291
315
  Rules:
292
316
  - Always use tools to read files before modifying them.
293
317
  - Use tools to verify your work (e.g., read a file after editing to confirm the change).
294
318
  - When editing files, provide enough surrounding context in old_string to make the match unique.
295
- - Be thorough and complete the task fully.`;
319
+ - Be thorough and complete the task fully.
320
+
321
+ IMPORTANT — Writing large documents:
322
+ When writing reports, RFCs, audits, plans, or any document longer than ~100 lines, you MUST
323
+ write incrementally using append_file rather than a single write_file call. Write one section
324
+ at a time — e.g., first the header, then section 1, then section 2, etc. Each append_file call
325
+ should contain at most one section (~50-150 lines). This prevents connection timeouts on long
326
+ generations. Start with write_file for the first section (to create/overwrite), then use
327
+ append_file for all subsequent sections.`;
296
328
 
297
329
  // ---- SSE streaming API client ----
298
330
 
package/lib/phases.sh CHANGED
@@ -1487,11 +1487,27 @@ cmd_status() {
1487
1487
  echo "Context: $ctx_count document(s) in .moxie/context/"
1488
1488
  fi
1489
1489
 
1490
- # Quick agent health check
1490
+ # Quick agent health check (includes persisted degradation)
1491
+ local deg_file="$MOXIE_DIR/degraded.json"
1491
1492
  local agent_health=""
1492
1493
  local all_healthy=1
1494
+ local any_degraded=0
1493
1495
  for name in "${AGENT_NAMES[@]}"; do
1494
- if _is_gateway_agent "$name"; then
1496
+ # Check if agent is degraded (persisted across phases)
1497
+ local is_deg=0
1498
+ if [ -f "$deg_file" ]; then
1499
+ is_deg=$(python3 -c "
1500
+ import json
1501
+ with open('$deg_file') as f:
1502
+ d = json.load(f)
1503
+ print('1' if d.get('$name', False) else '0')
1504
+ " 2>/dev/null)
1505
+ fi
1506
+
1507
+ if [ "$is_deg" = "1" ]; then
1508
+ agent_health="$agent_health $name[DEGRADED]"
1509
+ any_degraded=1
1510
+ elif _is_gateway_agent "$name"; then
1495
1511
  if command -v node &>/dev/null && gateway_has_key "vercel-ai-gateway"; then
1496
1512
  agent_health="$agent_health $name[ok]"
1497
1513
  else
@@ -1515,6 +1531,9 @@ cmd_status() {
1515
1531
  if [ "$all_healthy" = "0" ]; then
1516
1532
  echo " (some agents missing — run 'moxie doctor' for details)"
1517
1533
  fi
1534
+ if [ "$any_degraded" = "1" ]; then
1535
+ echo " (degraded agents are skipped — rm .moxie/degraded.json to reset)"
1536
+ fi
1518
1537
  echo ""
1519
1538
 
1520
1539
  for phase in "${PHASES[@]}"; do
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zachjxyz/moxie",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Run multiple AI coding agents through spec-driven phases with quorum convergence. Supports CLI agents (Claude, Codex, Qwen, Aider, Goose, Amp, Cline, Roo) and Vercel AI Gateway models.",
5
5
  "bin": {
6
6
  "moxie": "bin/moxie"