nightralph 0.0.33 → 0.0.34

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/meta.json CHANGED
@@ -142,7 +142,7 @@
142
142
  "format": "esm"
143
143
  },
144
144
  "src/orchestrator.ts": {
145
- "bytes": 61636,
145
+ "bytes": 65884,
146
146
  "imports": [
147
147
  {
148
148
  "path": "node:child_process",
@@ -305,7 +305,7 @@
305
305
  "imports": [],
306
306
  "exports": [],
307
307
  "inputs": {},
308
- "bytes": 170396
308
+ "bytes": 176450
309
309
  },
310
310
  "dist/index.js": {
311
311
  "imports": [
@@ -468,7 +468,7 @@
468
468
  "bytesInOutput": 4265
469
469
  },
470
470
  "src/orchestrator.ts": {
471
- "bytesInOutput": 43047
471
+ "bytesInOutput": 45245
472
472
  },
473
473
  "src/worktree.ts": {
474
474
  "bytesInOutput": 3788
@@ -489,7 +489,7 @@
489
489
  "bytesInOutput": 1937
490
490
  }
491
491
  },
492
- "bytes": 79590
492
+ "bytes": 81788
493
493
  }
494
494
  }
495
495
  }
@@ -111,30 +111,110 @@ function findReadyTickets(tickets) {
111
111
  });
112
112
  }
113
113
  __name(findReadyTickets, "findReadyTickets");
114
- const COMPLETED_RE = /^\[x\]\s+(.+)$/i;
114
+ const COMPLETED_RE = /^\s*[-*+]?\s*\[x\]\s+(.+)$/i;
115
115
  const TOOL_USE_RE = /^\[[\w.]+\]/;
116
+ const CHECKBOX_RE = /^(\s*[-*+] )\[( |x|X)\]( .*)$/;
117
+ const UNCHECKED_BOX_RE = /^(\s*[-*+] )\[( )\]/;
118
+ function normalizeItemText(s) {
119
+ return s.replace(/\s+/g, " ").trim().toLowerCase();
120
+ }
121
+ __name(normalizeItemText, "normalizeItemText");
122
+ function stripCheckboxPrefix(s) {
123
+ return s.replace(/^\s*[-*+]?\s*\[[ xX]\]\s+/, "");
124
+ }
125
+ __name(stripCheckboxPrefix, "stripCheckboxPrefix");
126
+ function parseChecklistItems(lines) {
127
+ const items = [];
128
+ let inFence = false;
129
+ let i = 0;
130
+ while (i < lines.length) {
131
+ if (/^\s*```/.test(lines[i])) {
132
+ inFence = !inFence;
133
+ i++;
134
+ continue;
135
+ }
136
+ if (inFence) {
137
+ i++;
138
+ continue;
139
+ }
140
+ const m = lines[i].match(CHECKBOX_RE);
141
+ if (!m) {
142
+ i++;
143
+ continue;
144
+ }
145
+ const start = i;
146
+ let text = m[3];
147
+ i++;
148
+ while (i < lines.length && /^\s+\S/.test(lines[i]) && !CHECKBOX_RE.test(lines[i])) {
149
+ text += " " + lines[i].trim();
150
+ i++;
151
+ }
152
+ items.push({
153
+ start,
154
+ text: normalizeItemText(text)
155
+ });
156
+ }
157
+ return items;
158
+ }
159
+ __name(parseChecklistItems, "parseChecklistItems");
116
160
  function checkItems(ticket, completedItems) {
117
161
  if (completedItems.length === 0) return;
118
- let body = ticket.body;
119
- for (const item of completedItems) {
120
- const escaped = item.replace(
121
- /[.*+?^${}()|[\]\\]/g,
122
- "\\$&"
123
- );
124
- body = body.replace(
125
- new RegExp(
126
- `- \\[ \\] ${escaped}`,
127
- "i"
128
- ),
129
- `- [x] ${item}`
162
+ let body;
163
+ try {
164
+ body = readFileSync(ticket.filepath, "utf8");
165
+ } catch {
166
+ body = ticket.body;
167
+ }
168
+ const wanted = new Set(
169
+ completedItems.map(
170
+ (item) => normalizeItemText(stripCheckboxPrefix(item))
171
+ )
172
+ );
173
+ const lines = body.split("\n");
174
+ let changed = false;
175
+ for (const item of parseChecklistItems(lines)) {
176
+ if (!wanted.has(item.text)) continue;
177
+ const flipped = lines[item.start].replace(
178
+ UNCHECKED_BOX_RE,
179
+ "$1[x]"
130
180
  );
181
+ if (flipped !== lines[item.start]) {
182
+ lines[item.start] = flipped;
183
+ changed = true;
184
+ }
131
185
  }
186
+ if (!changed) return;
187
+ body = lines.join("\n");
132
188
  writeFileSync(ticket.filepath, body);
133
189
  ticket.body = body;
134
190
  }
135
191
  __name(checkItems, "checkItems");
192
+ function checkAllItems(body) {
193
+ const lines = body.split("\n");
194
+ let inFence = false;
195
+ for (let i = 0; i < lines.length; i++) {
196
+ if (/^\s*```/.test(lines[i])) {
197
+ inFence = !inFence;
198
+ continue;
199
+ }
200
+ if (inFence) continue;
201
+ lines[i] = lines[i].replace(
202
+ UNCHECKED_BOX_RE,
203
+ "$1[x]"
204
+ );
205
+ }
206
+ return lines.join("\n");
207
+ }
208
+ __name(checkAllItems, "checkAllItems");
136
209
  function markDone(ticket) {
137
- const updated = ticket.body.replace(
210
+ let body;
211
+ try {
212
+ body = readFileSync(ticket.filepath, "utf8");
213
+ } catch {
214
+ body = ticket.body;
215
+ }
216
+ body = checkAllItems(body);
217
+ const updated = body.replace(
138
218
  /\*\*Status:\*\*\s*.+/i,
139
219
  "**Status:** done"
140
220
  );
@@ -549,9 +629,16 @@ function spawnAgent(opts) {
549
629
  proc.stdout.pipe(logStream);
550
630
  const piFormatter = isPi ? createPiStreamFormatter() : null;
551
631
  const completedItems = [];
632
+ const seenItems = /* @__PURE__ */ new Set();
552
633
  function collectCompleted(text) {
553
- const match = text.match(COMPLETED_RE);
554
- if (match) completedItems.push(match[1]);
634
+ for (const line of text.split("\n")) {
635
+ const match = line.match(COMPLETED_RE);
636
+ if (!match) continue;
637
+ const item = match[1].trim();
638
+ if (!item || seenItems.has(item)) continue;
639
+ seenItems.add(item);
640
+ completedItems.push(item);
641
+ }
555
642
  }
556
643
  __name(collectCompleted, "collectCompleted");
557
644
  const rl = createInterface({ input: proc.stdout });