flight-rules 0.15.2 → 0.15.3

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.
@@ -123,28 +123,29 @@ async function runClaudeWithPrompt(promptContent, verbose) {
123
123
  ], {
124
124
  stdio: ['pipe', 'pipe', 'pipe'],
125
125
  });
126
- let output = '';
126
+ let reassembledText = ''; // Plain text reassembled from stream-json fragments
127
+ let resultText = ''; // Full text from the final result event (fallback)
127
128
  let errorOutput = '';
128
129
  let lineBuffer = ''; // Buffer for incomplete JSON lines
129
130
  let needsTimestamp = true; // Track whether next text output needs a timestamp
130
131
  claude.stdout?.on('data', (data) => {
131
132
  const text = data.toString();
132
- output += text;
133
- if (verbose) {
134
- // Prepend any buffered partial line from previous chunk
135
- const fullText = lineBuffer + text;
136
- const lines = fullText.split('\n');
137
- // Last element might be incomplete - save it for next chunk
138
- lineBuffer = lines.pop() || '';
139
- for (const line of lines) {
140
- if (!line.trim())
141
- continue;
142
- try {
143
- const parsed = JSON.parse(line);
144
- // Handle different message types in stream-json format
145
- if (parsed.type === 'assistant' && parsed.message?.content) {
146
- for (const block of parsed.message.content) {
147
- if (block.type === 'text' && block.text) {
133
+ // Parse stream-json lines to reassemble plain text output
134
+ const fullText = lineBuffer + text;
135
+ const lines = fullText.split('\n');
136
+ // Last element might be incomplete - save it for next chunk
137
+ lineBuffer = lines.pop() || '';
138
+ for (const line of lines) {
139
+ if (!line.trim())
140
+ continue;
141
+ try {
142
+ const parsed = JSON.parse(line);
143
+ // Handle different message types in stream-json format
144
+ if (parsed.type === 'assistant' && parsed.message?.content) {
145
+ for (const block of parsed.message.content) {
146
+ if (block.type === 'text' && block.text) {
147
+ reassembledText += block.text;
148
+ if (verbose) {
148
149
  if (needsTimestamp) {
149
150
  process.stdout.write(`${formatTimestamp()} `);
150
151
  needsTimestamp = false;
@@ -153,23 +154,31 @@ async function runClaudeWithPrompt(promptContent, verbose) {
153
154
  }
154
155
  }
155
156
  }
156
- else if (parsed.type === 'content_block_delta' && parsed.delta?.text) {
157
+ }
158
+ else if (parsed.type === 'content_block_delta' && parsed.delta?.text) {
159
+ reassembledText += parsed.delta.text;
160
+ if (verbose) {
157
161
  if (needsTimestamp) {
158
162
  process.stdout.write(`${formatTimestamp()} `);
159
163
  needsTimestamp = false;
160
164
  }
161
165
  process.stdout.write(parsed.delta.text);
162
166
  }
163
- else if (parsed.type === 'content_block_stop') {
167
+ }
168
+ else if (parsed.type === 'content_block_stop') {
169
+ if (verbose) {
164
170
  // Add newline + blank line after each content block ends
165
171
  process.stdout.write('\n\n');
166
172
  needsTimestamp = true;
167
173
  }
168
174
  }
169
- catch {
170
- // Not valid JSON, skip
175
+ else if (parsed.type === 'result' && typeof parsed.result === 'string') {
176
+ resultText = parsed.result;
171
177
  }
172
178
  }
179
+ catch {
180
+ // Not valid JSON, skip
181
+ }
173
182
  }
174
183
  });
175
184
  claude.stderr?.on('data', (data) => {
@@ -180,6 +189,30 @@ async function runClaudeWithPrompt(promptContent, verbose) {
180
189
  }
181
190
  });
182
191
  claude.on('close', (code) => {
192
+ // Flush any remaining data in lineBuffer
193
+ if (lineBuffer.trim()) {
194
+ try {
195
+ const parsed = JSON.parse(lineBuffer);
196
+ if (parsed.type === 'assistant' && parsed.message?.content) {
197
+ for (const block of parsed.message.content) {
198
+ if (block.type === 'text' && block.text) {
199
+ reassembledText += block.text;
200
+ }
201
+ }
202
+ }
203
+ else if (parsed.type === 'content_block_delta' && parsed.delta?.text) {
204
+ reassembledText += parsed.delta.text;
205
+ }
206
+ else if (parsed.type === 'result' && typeof parsed.result === 'string') {
207
+ resultText = parsed.result;
208
+ }
209
+ }
210
+ catch {
211
+ // Not valid JSON, skip
212
+ }
213
+ }
214
+ // Prefer reassembled streaming text; fall back to result event text
215
+ const output = reassembledText || resultText;
183
216
  resolve({ output, exitCode: code ?? 0 });
184
217
  });
185
218
  claude.on('error', (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flight-rules",
3
- "version": "0.15.2",
3
+ "version": "0.15.3",
4
4
  "description": "An opinionated framework for AI-assisted software development",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/payload/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Flight Rules – Agent Guidelines
2
2
 
3
- flight_rules_version: 0.15.2
3
+ flight_rules_version: 0.15.3
4
4
 
5
5
  This file defines how agents (Claude Code, Cursor, etc.) should work on software projects using the Flight Rules system.
6
6
 
@@ -1,20 +1,25 @@
1
1
  # Flight Rules Discovery Agent
2
2
 
3
- You are a discovery agent for Flight Rules. Your ONLY job is to scan implementation docs and report which task groups have incomplete tasks. Do NOT implement anything.
3
+ You are a discovery agent for Flight Rules. Your ONLY job is to scan implementation docs and report which task groups have **incomplete** (not-yet-done) tasks. Do NOT implement anything.
4
4
 
5
5
  ## Instructions
6
6
 
7
7
  1. Read `docs/implementation/overview.md` to understand the area/task-group structure
8
8
  2. Scan each Area directory in `docs/implementation/`
9
- 3. For each Task Group file (.md), check every task's status
10
- 4. Report all task groups that contain any task with status other than ✅ Complete (i.e., 🔵 Planned, 🟡 In Progress, or ⏸️ Blocked)
9
+ 3. For each Task Group file (.md), check every task's `**Status**:` field
10
+ 4. A task is **incomplete** if its status is 🔵 Planned, 🟡 In Progress, or ⏸️ Blocked
11
+ 5. A task is **complete** only if its status is ✅ Complete
12
+ 6. Report all task groups that contain any incomplete task
11
13
 
12
14
  ## Response Format
13
15
 
14
- Respond with a pipe-delimited report inside `<ralph-discovery>` tags. Use EXACTLY this format:
16
+ Output ONLY the `<ralph-discovery>` block below. No commentary, no summary, no interpretation before or after the tags. Your entire response must be the block and nothing else.
17
+
18
+ When incomplete tasks exist (the common case), use this format:
15
19
 
16
20
  ```
17
21
  <ralph-discovery>
22
+ INCOMPLETE|{totalIncompleteTaskCount}
18
23
  TASK_GROUP|{id}|{title}|{filePath}|{areaDir}
19
24
  TASK|{taskId}|{taskTitle}|{status}
20
25
  TASK|{taskId}|{taskTitle}|{status}
@@ -23,16 +28,17 @@ TASK|{taskId}|{taskTitle}|{status}
23
28
  </ralph-discovery>
24
29
  ```
25
30
 
26
- - Each `TASK_GROUP` line is followed by its `TASK` lines (only incomplete tasks)
31
+ - First line is `INCOMPLETE|{N}` where N = total number of incomplete tasks across all task groups
32
+ - Each `TASK_GROUP` line is followed by its incomplete `TASK` lines
27
33
  - `{id}` = task group ID as written in the file (e.g., "1.1", "2.3")
28
34
  - `{title}` = task group title
29
35
  - `{filePath}` = relative path from project root to the task group file
30
36
  - `{areaDir}` = area directory name (e.g., "1-project-setup", "2-cli-core")
31
37
  - `{taskId}` = individual task ID (e.g., "1.1.1", "2.3.2")
32
38
  - `{taskTitle}` = individual task title
33
- - `{status}` = one of: planned, in_progress, blocked
39
+ - `{status}` = one of: `planned`, `in_progress`, `blocked` — all three mean the task is NOT done
34
40
 
35
- If ALL tasks in ALL task groups are ✅ Complete, respond with:
41
+ Only if every single task in every single task group has ✅ Complete status (this is rare during active development), respond with:
36
42
 
37
43
  ```
38
44
  <ralph-discovery>
@@ -40,11 +46,21 @@ ALL_COMPLETE
40
46
  </ralph-discovery>
41
47
  ```
42
48
 
49
+ ## Field Reference
50
+
51
+ | Status in doc | Meaning | Output value |
52
+ |---|---|---|
53
+ | 🔵 Planned | Not started, work remains | `planned` |
54
+ | 🟡 In Progress | Started but not finished | `in_progress` |
55
+ | ⏸️ Blocked | Cannot proceed, work remains | `blocked` |
56
+ | ✅ Complete | Done, do NOT include in output | (omit) |
57
+
43
58
  ## Rules
44
59
 
45
60
  - Do NOT implement or modify any code
46
61
  - Do NOT create or modify any files
47
62
  - Do NOT run any scripts or quality checks
48
63
  - ONLY read implementation files and report status
49
- - Always include the `<ralph-discovery>` tags in your response
50
- - List task groups in the order they should be worked on (by area number, then task group number)
64
+ - Your response must contain ONLY the `<ralph-discovery>` block no other text
65
+ - List task groups in order by area number, then task group number
66
+ - Never output `ALL_COMPLETE` if any task has a status of planned, in_progress, or blocked