make-it-done 0.1.0

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.
Files changed (42) hide show
  1. package/README.md +263 -0
  2. package/agents/.gitkeep +0 -0
  3. package/agents/mid-debugger.md +88 -0
  4. package/agents/mid-executor.md +69 -0
  5. package/agents/mid-planner.md +97 -0
  6. package/agents/mid-researcher.md +101 -0
  7. package/agents/mid-verifier.md +92 -0
  8. package/bin/install.js +122 -0
  9. package/commands/mid/.gitkeep +0 -0
  10. package/commands/mid/debug.md +19 -0
  11. package/commands/mid/do.md +24 -0
  12. package/commands/mid/help.md +77 -0
  13. package/commands/mid/init.md +18 -0
  14. package/commands/mid/next.md +18 -0
  15. package/commands/mid/plan.md +21 -0
  16. package/commands/mid/quick.md +24 -0
  17. package/commands/mid/report.md +16 -0
  18. package/commands/mid/status.md +16 -0
  19. package/commands/mid/verify.md +19 -0
  20. package/makeitdone/bin/mid-tools.cjs +2048 -0
  21. package/makeitdone/steps/agent-contracts.md +184 -0
  22. package/makeitdone/steps/anti-patterns.md +291 -0
  23. package/makeitdone/steps/context-budget.md +157 -0
  24. package/makeitdone/steps/init-gate.md +42 -0
  25. package/makeitdone/steps/model-route.md +70 -0
  26. package/makeitdone/steps/state-read.md +56 -0
  27. package/makeitdone/templates/plan.md +94 -0
  28. package/makeitdone/templates/project.md +62 -0
  29. package/makeitdone/templates/requirements.md +97 -0
  30. package/makeitdone/templates/roadmap.md +111 -0
  31. package/makeitdone/templates/state.md +28 -0
  32. package/makeitdone/templates/summary.md +58 -0
  33. package/makeitdone/workflows/debug.md +135 -0
  34. package/makeitdone/workflows/execute.md +218 -0
  35. package/makeitdone/workflows/init.md +113 -0
  36. package/makeitdone/workflows/next.md +114 -0
  37. package/makeitdone/workflows/plan.md +231 -0
  38. package/makeitdone/workflows/quick.md +151 -0
  39. package/makeitdone/workflows/report.md +138 -0
  40. package/makeitdone/workflows/status.md +135 -0
  41. package/makeitdone/workflows/verify.md +177 -0
  42. package/package.json +50 -0
@@ -0,0 +1,2048 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/commands/toon.ts
5
+ var import_fs = require("fs");
6
+
7
+ // node_modules/@toon-format/toon/dist/index.mjs
8
+ var LIST_ITEM_MARKER = "-";
9
+ var LIST_ITEM_PREFIX = "- ";
10
+ var COMMA = ",";
11
+ var COLON = ":";
12
+ var SPACE = " ";
13
+ var PIPE = "|";
14
+ var DOT = ".";
15
+ var OPEN_BRACKET = "[";
16
+ var CLOSE_BRACKET = "]";
17
+ var OPEN_BRACE = "{";
18
+ var CLOSE_BRACE = "}";
19
+ var NULL_LITERAL = "null";
20
+ var TRUE_LITERAL = "true";
21
+ var FALSE_LITERAL = "false";
22
+ var BACKSLASH = "\\";
23
+ var DOUBLE_QUOTE = '"';
24
+ var NEWLINE = "\n";
25
+ var CARRIAGE_RETURN = "\r";
26
+ var TAB = " ";
27
+ var DELIMITERS = {
28
+ comma: COMMA,
29
+ tab: TAB,
30
+ pipe: PIPE
31
+ };
32
+ var DEFAULT_DELIMITER = DELIMITERS.comma;
33
+ function escapeString(value) {
34
+ return value.replace(/\\/g, `${BACKSLASH}${BACKSLASH}`).replace(/"/g, `${BACKSLASH}${DOUBLE_QUOTE}`).replace(/\n/g, `${BACKSLASH}n`).replace(/\r/g, `${BACKSLASH}r`).replace(/\t/g, `${BACKSLASH}t`);
35
+ }
36
+ function unescapeString(value) {
37
+ let unescaped = "";
38
+ let i = 0;
39
+ while (i < value.length) {
40
+ if (value[i] === BACKSLASH) {
41
+ if (i + 1 >= value.length)
42
+ throw new SyntaxError("Invalid escape sequence: backslash at end of string");
43
+ const next = value[i + 1];
44
+ if (next === "n") {
45
+ unescaped += NEWLINE;
46
+ i += 2;
47
+ continue;
48
+ }
49
+ if (next === "t") {
50
+ unescaped += TAB;
51
+ i += 2;
52
+ continue;
53
+ }
54
+ if (next === "r") {
55
+ unescaped += CARRIAGE_RETURN;
56
+ i += 2;
57
+ continue;
58
+ }
59
+ if (next === BACKSLASH) {
60
+ unescaped += BACKSLASH;
61
+ i += 2;
62
+ continue;
63
+ }
64
+ if (next === DOUBLE_QUOTE) {
65
+ unescaped += DOUBLE_QUOTE;
66
+ i += 2;
67
+ continue;
68
+ }
69
+ throw new SyntaxError(`Invalid escape sequence: \\${next}`);
70
+ }
71
+ unescaped += value[i];
72
+ i++;
73
+ }
74
+ return unescaped;
75
+ }
76
+ function findClosingQuote(content, start) {
77
+ let i = start + 1;
78
+ while (i < content.length) {
79
+ if (content[i] === BACKSLASH && i + 1 < content.length) {
80
+ i += 2;
81
+ continue;
82
+ }
83
+ if (content[i] === DOUBLE_QUOTE)
84
+ return i;
85
+ i++;
86
+ }
87
+ return -1;
88
+ }
89
+ function findUnquotedChar(content, char, start = 0) {
90
+ let inQuotes = false;
91
+ let i = start;
92
+ while (i < content.length) {
93
+ if (content[i] === BACKSLASH && i + 1 < content.length && inQuotes) {
94
+ i += 2;
95
+ continue;
96
+ }
97
+ if (content[i] === DOUBLE_QUOTE) {
98
+ inQuotes = !inQuotes;
99
+ i++;
100
+ continue;
101
+ }
102
+ if (content[i] === char && !inQuotes)
103
+ return i;
104
+ i++;
105
+ }
106
+ return -1;
107
+ }
108
+ function isBooleanOrNullLiteral(token) {
109
+ return token === TRUE_LITERAL || token === FALSE_LITERAL || token === NULL_LITERAL;
110
+ }
111
+ function isNumericLiteral(token) {
112
+ if (!token)
113
+ return false;
114
+ if (token.length > 1 && token[0] === "0" && token[1] !== ".")
115
+ return false;
116
+ const numericValue = Number(token);
117
+ return !Number.isNaN(numericValue) && Number.isFinite(numericValue);
118
+ }
119
+ function parseArrayHeaderLine(content, defaultDelimiter) {
120
+ const trimmedToken = content.trimStart();
121
+ let bracketStart = -1;
122
+ if (trimmedToken.startsWith(DOUBLE_QUOTE)) {
123
+ const closingQuoteIndex = findClosingQuote(trimmedToken, 0);
124
+ if (closingQuoteIndex === -1)
125
+ return;
126
+ if (!trimmedToken.slice(closingQuoteIndex + 1).startsWith(OPEN_BRACKET))
127
+ return;
128
+ const keyEndIndex = content.length - trimmedToken.length + closingQuoteIndex + 1;
129
+ bracketStart = content.indexOf(OPEN_BRACKET, keyEndIndex);
130
+ } else
131
+ bracketStart = content.indexOf(OPEN_BRACKET);
132
+ if (bracketStart === -1)
133
+ return;
134
+ const bracketEnd = content.indexOf(CLOSE_BRACKET, bracketStart);
135
+ if (bracketEnd === -1)
136
+ return;
137
+ let colonIndex = bracketEnd + 1;
138
+ let braceEnd = colonIndex;
139
+ const braceStart = content.indexOf(OPEN_BRACE, bracketEnd);
140
+ if (braceStart !== -1 && braceStart < content.indexOf(COLON, bracketEnd)) {
141
+ const foundBraceEnd = content.indexOf(CLOSE_BRACE, braceStart);
142
+ if (foundBraceEnd !== -1)
143
+ braceEnd = foundBraceEnd + 1;
144
+ }
145
+ colonIndex = content.indexOf(COLON, Math.max(bracketEnd, braceEnd));
146
+ if (colonIndex === -1)
147
+ return;
148
+ let key;
149
+ if (bracketStart > 0) {
150
+ const rawKey = content.slice(0, bracketStart).trim();
151
+ key = rawKey.startsWith(DOUBLE_QUOTE) ? parseStringLiteral(rawKey) : rawKey;
152
+ }
153
+ const afterColon = content.slice(colonIndex + 1).trim();
154
+ const bracketContent = content.slice(bracketStart + 1, bracketEnd);
155
+ let parsedBracket;
156
+ try {
157
+ parsedBracket = parseBracketSegment(bracketContent, defaultDelimiter);
158
+ } catch {
159
+ return;
160
+ }
161
+ const { length, delimiter } = parsedBracket;
162
+ let fields;
163
+ if (braceStart !== -1 && braceStart < colonIndex) {
164
+ const foundBraceEnd = content.indexOf(CLOSE_BRACE, braceStart);
165
+ if (foundBraceEnd !== -1 && foundBraceEnd < colonIndex)
166
+ fields = parseDelimitedValues(content.slice(braceStart + 1, foundBraceEnd), delimiter).map((field) => parseStringLiteral(field.trim()));
167
+ }
168
+ return {
169
+ header: {
170
+ key,
171
+ length,
172
+ delimiter,
173
+ fields
174
+ },
175
+ inlineValues: afterColon || void 0
176
+ };
177
+ }
178
+ function parseBracketSegment(seg, defaultDelimiter) {
179
+ let content = seg;
180
+ let delimiter = defaultDelimiter;
181
+ if (content.endsWith(TAB)) {
182
+ delimiter = DELIMITERS.tab;
183
+ content = content.slice(0, -1);
184
+ } else if (content.endsWith(PIPE)) {
185
+ delimiter = DELIMITERS.pipe;
186
+ content = content.slice(0, -1);
187
+ }
188
+ const length = Number.parseInt(content, 10);
189
+ if (Number.isNaN(length))
190
+ throw new TypeError(`Invalid array length: ${seg}`);
191
+ return {
192
+ length,
193
+ delimiter
194
+ };
195
+ }
196
+ function parseDelimitedValues(input, delimiter) {
197
+ const values = [];
198
+ let valueBuffer = "";
199
+ let inQuotes = false;
200
+ let i = 0;
201
+ while (i < input.length) {
202
+ const char = input[i];
203
+ if (char === BACKSLASH && i + 1 < input.length && inQuotes) {
204
+ valueBuffer += char + input[i + 1];
205
+ i += 2;
206
+ continue;
207
+ }
208
+ if (char === DOUBLE_QUOTE) {
209
+ inQuotes = !inQuotes;
210
+ valueBuffer += char;
211
+ i++;
212
+ continue;
213
+ }
214
+ if (char === delimiter && !inQuotes) {
215
+ values.push(valueBuffer.trim());
216
+ valueBuffer = "";
217
+ i++;
218
+ continue;
219
+ }
220
+ valueBuffer += char;
221
+ i++;
222
+ }
223
+ if (valueBuffer || values.length > 0)
224
+ values.push(valueBuffer.trim());
225
+ return values;
226
+ }
227
+ function mapRowValuesToPrimitives(values) {
228
+ return values.map((v) => parsePrimitiveToken(v));
229
+ }
230
+ function parsePrimitiveToken(token) {
231
+ const trimmedToken = token.trim();
232
+ if (!trimmedToken)
233
+ return "";
234
+ if (trimmedToken.startsWith(DOUBLE_QUOTE))
235
+ return parseStringLiteral(trimmedToken);
236
+ if (isBooleanOrNullLiteral(trimmedToken)) {
237
+ if (trimmedToken === TRUE_LITERAL)
238
+ return true;
239
+ if (trimmedToken === FALSE_LITERAL)
240
+ return false;
241
+ if (trimmedToken === NULL_LITERAL)
242
+ return null;
243
+ }
244
+ if (isNumericLiteral(trimmedToken)) {
245
+ const parsedNumber = Number.parseFloat(trimmedToken);
246
+ return Object.is(parsedNumber, -0) ? 0 : parsedNumber;
247
+ }
248
+ return trimmedToken;
249
+ }
250
+ function parseStringLiteral(token) {
251
+ const trimmedToken = token.trim();
252
+ if (trimmedToken.startsWith(DOUBLE_QUOTE)) {
253
+ const closingQuoteIndex = findClosingQuote(trimmedToken, 0);
254
+ if (closingQuoteIndex === -1)
255
+ throw new SyntaxError("Unterminated string: missing closing quote");
256
+ if (closingQuoteIndex !== trimmedToken.length - 1)
257
+ throw new SyntaxError("Unexpected characters after closing quote");
258
+ return unescapeString(trimmedToken.slice(1, closingQuoteIndex));
259
+ }
260
+ return trimmedToken;
261
+ }
262
+ function parseUnquotedKey(content, start) {
263
+ let parsePosition = start;
264
+ while (parsePosition < content.length && content[parsePosition] !== COLON)
265
+ parsePosition++;
266
+ if (parsePosition >= content.length || content[parsePosition] !== COLON)
267
+ throw new SyntaxError("Missing colon after key");
268
+ const key = content.slice(start, parsePosition).trim();
269
+ parsePosition++;
270
+ return {
271
+ key,
272
+ end: parsePosition
273
+ };
274
+ }
275
+ function parseQuotedKey(content, start) {
276
+ const closingQuoteIndex = findClosingQuote(content, start);
277
+ if (closingQuoteIndex === -1)
278
+ throw new SyntaxError("Unterminated quoted key");
279
+ const key = unescapeString(content.slice(start + 1, closingQuoteIndex));
280
+ let parsePosition = closingQuoteIndex + 1;
281
+ if (parsePosition >= content.length || content[parsePosition] !== COLON)
282
+ throw new SyntaxError("Missing colon after key");
283
+ parsePosition++;
284
+ return {
285
+ key,
286
+ end: parsePosition
287
+ };
288
+ }
289
+ function parseKeyToken(content, start) {
290
+ const isQuoted = content[start] === DOUBLE_QUOTE;
291
+ return {
292
+ ...isQuoted ? parseQuotedKey(content, start) : parseUnquotedKey(content, start),
293
+ isQuoted
294
+ };
295
+ }
296
+ function isArrayHeaderContent(content) {
297
+ return content.trim().startsWith(OPEN_BRACKET) && findUnquotedChar(content, COLON) !== -1;
298
+ }
299
+ function isKeyValueContent(content) {
300
+ return findUnquotedChar(content, COLON) !== -1;
301
+ }
302
+ function createScanState() {
303
+ return {
304
+ lineNumber: 0,
305
+ blankLines: []
306
+ };
307
+ }
308
+ function parseLineIncremental(raw, state, indentSize, strict) {
309
+ state.lineNumber++;
310
+ const lineNumber = state.lineNumber;
311
+ let indent = 0;
312
+ while (indent < raw.length && raw[indent] === SPACE)
313
+ indent++;
314
+ const content = raw.slice(indent);
315
+ if (!content.trim()) {
316
+ const depth$1 = computeDepthFromIndent(indent, indentSize);
317
+ state.blankLines.push({
318
+ lineNumber,
319
+ indent,
320
+ depth: depth$1
321
+ });
322
+ return;
323
+ }
324
+ const depth = computeDepthFromIndent(indent, indentSize);
325
+ if (strict) {
326
+ let whitespaceEndIndex = 0;
327
+ while (whitespaceEndIndex < raw.length && (raw[whitespaceEndIndex] === SPACE || raw[whitespaceEndIndex] === TAB))
328
+ whitespaceEndIndex++;
329
+ if (raw.slice(0, whitespaceEndIndex).includes(TAB))
330
+ throw new SyntaxError(`Line ${lineNumber}: Tabs are not allowed in indentation in strict mode`);
331
+ if (indent > 0 && indent % indentSize !== 0)
332
+ throw new SyntaxError(`Line ${lineNumber}: Indentation must be exact multiple of ${indentSize}, but found ${indent} spaces`);
333
+ }
334
+ return {
335
+ raw,
336
+ indent,
337
+ content,
338
+ depth,
339
+ lineNumber
340
+ };
341
+ }
342
+ function* parseLinesSync(source, indentSize, strict, state) {
343
+ for (const raw of source) {
344
+ const parsedLine = parseLineIncremental(raw, state, indentSize, strict);
345
+ if (parsedLine !== void 0)
346
+ yield parsedLine;
347
+ }
348
+ }
349
+ function computeDepthFromIndent(indentSpaces, indentSize) {
350
+ return Math.floor(indentSpaces / indentSize);
351
+ }
352
+ function assertExpectedCount(actual, expected, itemType, options) {
353
+ if (options.strict && actual !== expected)
354
+ throw new RangeError(`Expected ${expected} ${itemType}, but got ${actual}`);
355
+ }
356
+ function validateNoExtraListItems(nextLine, itemDepth, expectedCount) {
357
+ if (nextLine?.depth === itemDepth && nextLine.content.startsWith(LIST_ITEM_PREFIX))
358
+ throw new RangeError(`Expected ${expectedCount} list array items, but found more`);
359
+ }
360
+ function validateNoExtraTabularRows(nextLine, rowDepth, header) {
361
+ if (nextLine?.depth === rowDepth && !nextLine.content.startsWith(LIST_ITEM_PREFIX) && isDataRow(nextLine.content, header.delimiter))
362
+ throw new RangeError(`Expected ${header.length} tabular rows, but found more`);
363
+ }
364
+ function validateNoBlankLinesInRange(startLine, endLine, blankLines, strict, context) {
365
+ if (!strict)
366
+ return;
367
+ const firstBlank = blankLines.find((blank) => blank.lineNumber > startLine && blank.lineNumber < endLine);
368
+ if (firstBlank)
369
+ throw new SyntaxError(`Line ${firstBlank.lineNumber}: Blank lines inside ${context} are not allowed in strict mode`);
370
+ }
371
+ function isDataRow(content, delimiter) {
372
+ const colonPos = content.indexOf(COLON);
373
+ const delimiterPos = content.indexOf(delimiter);
374
+ if (colonPos === -1)
375
+ return true;
376
+ if (delimiterPos !== -1 && delimiterPos < colonPos)
377
+ return true;
378
+ return false;
379
+ }
380
+ var StreamingLineCursor = class {
381
+ buffer = [];
382
+ generator;
383
+ done = false;
384
+ lastLine;
385
+ scanState;
386
+ constructor(generator, scanState) {
387
+ this.generator = generator;
388
+ this.scanState = scanState;
389
+ }
390
+ getBlankLines() {
391
+ return this.scanState.blankLines;
392
+ }
393
+ async peek() {
394
+ if (this.buffer.length > 0)
395
+ return this.buffer[0];
396
+ if (this.done)
397
+ return;
398
+ const result = await this.generator.next();
399
+ if (result.done) {
400
+ this.done = true;
401
+ return;
402
+ }
403
+ this.buffer.push(result.value);
404
+ return result.value;
405
+ }
406
+ async next() {
407
+ const line = await this.peek();
408
+ if (line !== void 0) {
409
+ this.buffer.shift();
410
+ this.lastLine = line;
411
+ }
412
+ return line;
413
+ }
414
+ async advance() {
415
+ await this.next();
416
+ }
417
+ current() {
418
+ return this.lastLine;
419
+ }
420
+ async atEnd() {
421
+ return await this.peek() === void 0;
422
+ }
423
+ peekSync() {
424
+ if (this.buffer.length > 0)
425
+ return this.buffer[0];
426
+ if (this.done)
427
+ return;
428
+ const result = this.generator.next();
429
+ if (result.done) {
430
+ this.done = true;
431
+ return;
432
+ }
433
+ this.buffer.push(result.value);
434
+ return result.value;
435
+ }
436
+ nextSync() {
437
+ const line = this.peekSync();
438
+ if (line !== void 0) {
439
+ this.buffer.shift();
440
+ this.lastLine = line;
441
+ }
442
+ return line;
443
+ }
444
+ advanceSync() {
445
+ this.nextSync();
446
+ }
447
+ atEndSync() {
448
+ return this.peekSync() === void 0;
449
+ }
450
+ };
451
+ function* decodeStreamSync$1(source, options) {
452
+ if (options?.expandPaths !== void 0)
453
+ throw new Error("expandPaths is not supported in streaming decode");
454
+ const resolvedOptions = {
455
+ indent: options?.indent ?? 2,
456
+ strict: options?.strict ?? true
457
+ };
458
+ const scanState = createScanState();
459
+ const cursor = new StreamingLineCursor(parseLinesSync(source, resolvedOptions.indent, resolvedOptions.strict, scanState), scanState);
460
+ const first = cursor.peekSync();
461
+ if (!first) {
462
+ yield { type: "startObject" };
463
+ yield { type: "endObject" };
464
+ return;
465
+ }
466
+ if (isArrayHeaderContent(first.content)) {
467
+ const headerInfo = parseArrayHeaderLine(first.content, DEFAULT_DELIMITER);
468
+ if (headerInfo) {
469
+ cursor.advanceSync();
470
+ yield* decodeArrayFromHeaderSync(headerInfo.header, headerInfo.inlineValues, cursor, 0, resolvedOptions);
471
+ return;
472
+ }
473
+ }
474
+ cursor.advanceSync();
475
+ if (!!cursor.atEndSync() && !isKeyValueLineSync(first)) {
476
+ yield {
477
+ type: "primitive",
478
+ value: parsePrimitiveToken(first.content.trim())
479
+ };
480
+ return;
481
+ }
482
+ yield { type: "startObject" };
483
+ yield* decodeKeyValueSync(first.content, cursor, 0, resolvedOptions);
484
+ while (!cursor.atEndSync()) {
485
+ const line = cursor.peekSync();
486
+ if (!line || line.depth !== 0)
487
+ break;
488
+ cursor.advanceSync();
489
+ yield* decodeKeyValueSync(line.content, cursor, 0, resolvedOptions);
490
+ }
491
+ yield { type: "endObject" };
492
+ }
493
+ function* decodeKeyValueSync(content, cursor, baseDepth, options) {
494
+ const arrayHeader = parseArrayHeaderLine(content, DEFAULT_DELIMITER);
495
+ if (arrayHeader && arrayHeader.header.key) {
496
+ yield {
497
+ type: "key",
498
+ key: arrayHeader.header.key
499
+ };
500
+ yield* decodeArrayFromHeaderSync(arrayHeader.header, arrayHeader.inlineValues, cursor, baseDepth, options);
501
+ return;
502
+ }
503
+ const { key, isQuoted } = parseKeyToken(content, 0);
504
+ const colonIndex = content.indexOf(COLON, key.length);
505
+ const rest = colonIndex >= 0 ? content.slice(colonIndex + 1).trim() : "";
506
+ yield isQuoted ? {
507
+ type: "key",
508
+ key,
509
+ wasQuoted: true
510
+ } : {
511
+ type: "key",
512
+ key
513
+ };
514
+ if (!rest) {
515
+ const nextLine = cursor.peekSync();
516
+ if (nextLine && nextLine.depth > baseDepth) {
517
+ yield { type: "startObject" };
518
+ yield* decodeObjectFieldsSync(cursor, baseDepth + 1, options);
519
+ yield { type: "endObject" };
520
+ return;
521
+ }
522
+ yield { type: "startObject" };
523
+ yield { type: "endObject" };
524
+ return;
525
+ }
526
+ yield {
527
+ type: "primitive",
528
+ value: parsePrimitiveToken(rest)
529
+ };
530
+ }
531
+ function* decodeObjectFieldsSync(cursor, baseDepth, options) {
532
+ let computedDepth;
533
+ while (!cursor.atEndSync()) {
534
+ const line = cursor.peekSync();
535
+ if (!line || line.depth < baseDepth)
536
+ break;
537
+ if (computedDepth === void 0 && line.depth >= baseDepth)
538
+ computedDepth = line.depth;
539
+ if (line.depth === computedDepth) {
540
+ cursor.advanceSync();
541
+ yield* decodeKeyValueSync(line.content, cursor, computedDepth, options);
542
+ } else
543
+ break;
544
+ }
545
+ }
546
+ function* decodeArrayFromHeaderSync(header, inlineValues, cursor, baseDepth, options) {
547
+ yield {
548
+ type: "startArray",
549
+ length: header.length
550
+ };
551
+ if (inlineValues) {
552
+ yield* decodeInlinePrimitiveArraySync(header, inlineValues, options);
553
+ yield { type: "endArray" };
554
+ return;
555
+ }
556
+ if (header.fields && header.fields.length > 0) {
557
+ yield* decodeTabularArraySync(header, cursor, baseDepth, options);
558
+ yield { type: "endArray" };
559
+ return;
560
+ }
561
+ yield* decodeListArraySync(header, cursor, baseDepth, options);
562
+ yield { type: "endArray" };
563
+ }
564
+ function* decodeInlinePrimitiveArraySync(header, inlineValues, options) {
565
+ if (!inlineValues.trim()) {
566
+ assertExpectedCount(0, header.length, "inline array items", options);
567
+ return;
568
+ }
569
+ const primitives = mapRowValuesToPrimitives(parseDelimitedValues(inlineValues, header.delimiter));
570
+ assertExpectedCount(primitives.length, header.length, "inline array items", options);
571
+ for (const primitive of primitives)
572
+ yield {
573
+ type: "primitive",
574
+ value: primitive
575
+ };
576
+ }
577
+ function* decodeTabularArraySync(header, cursor, baseDepth, options) {
578
+ const rowDepth = baseDepth + 1;
579
+ let rowCount = 0;
580
+ let startLine;
581
+ let endLine;
582
+ while (!cursor.atEndSync() && rowCount < header.length) {
583
+ const line = cursor.peekSync();
584
+ if (!line || line.depth < rowDepth)
585
+ break;
586
+ if (line.depth === rowDepth) {
587
+ if (startLine === void 0)
588
+ startLine = line.lineNumber;
589
+ endLine = line.lineNumber;
590
+ cursor.advanceSync();
591
+ const values = parseDelimitedValues(line.content, header.delimiter);
592
+ assertExpectedCount(values.length, header.fields.length, "tabular row values", options);
593
+ const primitives = mapRowValuesToPrimitives(values);
594
+ yield* yieldObjectFromFields(header.fields, primitives);
595
+ rowCount++;
596
+ } else
597
+ break;
598
+ }
599
+ assertExpectedCount(rowCount, header.length, "tabular rows", options);
600
+ if (options.strict && startLine !== void 0 && endLine !== void 0)
601
+ validateNoBlankLinesInRange(startLine, endLine, cursor.getBlankLines(), options.strict, "tabular array");
602
+ if (options.strict)
603
+ validateNoExtraTabularRows(cursor.peekSync(), rowDepth, header);
604
+ }
605
+ function* decodeListArraySync(header, cursor, baseDepth, options) {
606
+ const itemDepth = baseDepth + 1;
607
+ let itemCount = 0;
608
+ let startLine;
609
+ let endLine;
610
+ while (!cursor.atEndSync() && itemCount < header.length) {
611
+ const line = cursor.peekSync();
612
+ if (!line || line.depth < itemDepth)
613
+ break;
614
+ const isListItem = line.content.startsWith(LIST_ITEM_PREFIX) || line.content === LIST_ITEM_MARKER;
615
+ if (line.depth === itemDepth && isListItem) {
616
+ if (startLine === void 0)
617
+ startLine = line.lineNumber;
618
+ endLine = line.lineNumber;
619
+ yield* decodeListItemSync(cursor, itemDepth, options);
620
+ const currentLine = cursor.current();
621
+ if (currentLine)
622
+ endLine = currentLine.lineNumber;
623
+ itemCount++;
624
+ } else
625
+ break;
626
+ }
627
+ assertExpectedCount(itemCount, header.length, "list array items", options);
628
+ if (options.strict && startLine !== void 0 && endLine !== void 0)
629
+ validateNoBlankLinesInRange(startLine, endLine, cursor.getBlankLines(), options.strict, "list array");
630
+ if (options.strict)
631
+ validateNoExtraListItems(cursor.peekSync(), itemDepth, header.length);
632
+ }
633
+ function* decodeListItemSync(cursor, baseDepth, options) {
634
+ const line = cursor.nextSync();
635
+ if (!line)
636
+ throw new ReferenceError("Expected list item");
637
+ let afterHyphen;
638
+ if (line.content === LIST_ITEM_MARKER) {
639
+ const followDepth = baseDepth + 1;
640
+ const nextLine = cursor.peekSync();
641
+ if (!nextLine || nextLine.depth < followDepth) {
642
+ yield { type: "startObject" };
643
+ yield { type: "endObject" };
644
+ return;
645
+ }
646
+ if (nextLine.depth === followDepth && !nextLine.content.startsWith(LIST_ITEM_PREFIX)) {
647
+ yield { type: "startObject" };
648
+ while (!cursor.atEndSync()) {
649
+ const fieldLine = cursor.peekSync();
650
+ if (!fieldLine || fieldLine.depth < followDepth)
651
+ break;
652
+ if (fieldLine.depth === followDepth && !fieldLine.content.startsWith(LIST_ITEM_PREFIX)) {
653
+ cursor.advanceSync();
654
+ yield* decodeKeyValueSync(fieldLine.content, cursor, followDepth, options);
655
+ } else
656
+ break;
657
+ }
658
+ yield { type: "endObject" };
659
+ return;
660
+ } else {
661
+ yield { type: "startObject" };
662
+ yield { type: "endObject" };
663
+ return;
664
+ }
665
+ } else if (line.content.startsWith(LIST_ITEM_PREFIX))
666
+ afterHyphen = line.content.slice(LIST_ITEM_PREFIX.length);
667
+ else
668
+ throw new SyntaxError(`Expected list item to start with "${LIST_ITEM_PREFIX}"`);
669
+ if (!afterHyphen.trim()) {
670
+ yield { type: "startObject" };
671
+ yield { type: "endObject" };
672
+ return;
673
+ }
674
+ if (isArrayHeaderContent(afterHyphen)) {
675
+ const arrayHeader = parseArrayHeaderLine(afterHyphen, DEFAULT_DELIMITER);
676
+ if (arrayHeader) {
677
+ yield* decodeArrayFromHeaderSync(arrayHeader.header, arrayHeader.inlineValues, cursor, baseDepth, options);
678
+ return;
679
+ }
680
+ }
681
+ const headerInfo = parseArrayHeaderLine(afterHyphen, DEFAULT_DELIMITER);
682
+ if (headerInfo && headerInfo.header.key && headerInfo.header.fields) {
683
+ const header = headerInfo.header;
684
+ yield { type: "startObject" };
685
+ yield {
686
+ type: "key",
687
+ key: header.key
688
+ };
689
+ yield* decodeArrayFromHeaderSync(header, headerInfo.inlineValues, cursor, baseDepth + 1, options);
690
+ const followDepth = baseDepth + 1;
691
+ while (!cursor.atEndSync()) {
692
+ const nextLine = cursor.peekSync();
693
+ if (!nextLine || nextLine.depth < followDepth)
694
+ break;
695
+ if (nextLine.depth === followDepth && !nextLine.content.startsWith(LIST_ITEM_PREFIX)) {
696
+ cursor.advanceSync();
697
+ yield* decodeKeyValueSync(nextLine.content, cursor, followDepth, options);
698
+ } else
699
+ break;
700
+ }
701
+ yield { type: "endObject" };
702
+ return;
703
+ }
704
+ if (isKeyValueContent(afterHyphen)) {
705
+ yield { type: "startObject" };
706
+ yield* decodeKeyValueSync(afterHyphen, cursor, baseDepth + 1, options);
707
+ const followDepth = baseDepth + 1;
708
+ while (!cursor.atEndSync()) {
709
+ const nextLine = cursor.peekSync();
710
+ if (!nextLine || nextLine.depth < followDepth)
711
+ break;
712
+ if (nextLine.depth === followDepth && !nextLine.content.startsWith(LIST_ITEM_PREFIX)) {
713
+ cursor.advanceSync();
714
+ yield* decodeKeyValueSync(nextLine.content, cursor, followDepth, options);
715
+ } else
716
+ break;
717
+ }
718
+ yield { type: "endObject" };
719
+ return;
720
+ }
721
+ yield {
722
+ type: "primitive",
723
+ value: parsePrimitiveToken(afterHyphen)
724
+ };
725
+ }
726
+ function isKeyValueLineSync(line) {
727
+ const content = line.content;
728
+ if (content.startsWith('"')) {
729
+ const closingQuoteIndex = findClosingQuote(content, 0);
730
+ if (closingQuoteIndex === -1)
731
+ return false;
732
+ return content.slice(closingQuoteIndex + 1).includes(COLON);
733
+ } else
734
+ return content.includes(COLON);
735
+ }
736
+ function* yieldObjectFromFields(fields, primitives) {
737
+ yield { type: "startObject" };
738
+ for (let i = 0; i < fields.length; i++) {
739
+ yield {
740
+ type: "key",
741
+ key: fields[i]
742
+ };
743
+ yield {
744
+ type: "primitive",
745
+ value: primitives[i]
746
+ };
747
+ }
748
+ yield { type: "endObject" };
749
+ }
750
+ function normalizeValue(value) {
751
+ if (value === null)
752
+ return null;
753
+ if (typeof value === "object" && value !== null && "toJSON" in value && typeof value.toJSON === "function") {
754
+ const next = value.toJSON();
755
+ if (next !== value)
756
+ return normalizeValue(next);
757
+ }
758
+ if (typeof value === "string" || typeof value === "boolean")
759
+ return value;
760
+ if (typeof value === "number") {
761
+ if (Object.is(value, -0))
762
+ return 0;
763
+ if (!Number.isFinite(value))
764
+ return null;
765
+ return value;
766
+ }
767
+ if (typeof value === "bigint") {
768
+ if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER)
769
+ return Number(value);
770
+ return value.toString();
771
+ }
772
+ if (value instanceof Date)
773
+ return value.toISOString();
774
+ if (Array.isArray(value))
775
+ return value.map(normalizeValue);
776
+ if (value instanceof Set)
777
+ return Array.from(value).map(normalizeValue);
778
+ if (value instanceof Map)
779
+ return Object.fromEntries(Array.from(value, ([k, v]) => [String(k), normalizeValue(v)]));
780
+ if (isPlainObject(value)) {
781
+ const normalized = {};
782
+ for (const key in value)
783
+ if (Object.prototype.hasOwnProperty.call(value, key))
784
+ normalized[key] = normalizeValue(value[key]);
785
+ return normalized;
786
+ }
787
+ return null;
788
+ }
789
+ function isJsonPrimitive(value) {
790
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
791
+ }
792
+ function isJsonArray(value) {
793
+ return Array.isArray(value);
794
+ }
795
+ function isJsonObject(value) {
796
+ return value !== null && typeof value === "object" && !Array.isArray(value);
797
+ }
798
+ function isEmptyObject(value) {
799
+ return Object.keys(value).length === 0;
800
+ }
801
+ function isPlainObject(value) {
802
+ if (value === null || typeof value !== "object")
803
+ return false;
804
+ const prototype = Object.getPrototypeOf(value);
805
+ return prototype === null || prototype === Object.prototype;
806
+ }
807
+ function isArrayOfPrimitives(value) {
808
+ return value.length === 0 || value.every((item) => isJsonPrimitive(item));
809
+ }
810
+ function isArrayOfArrays(value) {
811
+ return value.length === 0 || value.every((item) => isJsonArray(item));
812
+ }
813
+ function isArrayOfObjects(value) {
814
+ return value.length === 0 || value.every((item) => isJsonObject(item));
815
+ }
816
+ function isValidUnquotedKey(key) {
817
+ return /^[A-Z_][\w.]*$/i.test(key);
818
+ }
819
+ function isIdentifierSegment(key) {
820
+ return /^[A-Z_]\w*$/i.test(key);
821
+ }
822
+ function isSafeUnquoted(value, delimiter = DEFAULT_DELIMITER) {
823
+ if (!value)
824
+ return false;
825
+ if (value !== value.trim())
826
+ return false;
827
+ if (isBooleanOrNullLiteral(value) || isNumericLike(value))
828
+ return false;
829
+ if (value.includes(":"))
830
+ return false;
831
+ if (value.includes('"') || value.includes("\\"))
832
+ return false;
833
+ if (/[[\]{}]/.test(value))
834
+ return false;
835
+ if (/[\n\r\t]/.test(value))
836
+ return false;
837
+ if (value.includes(delimiter))
838
+ return false;
839
+ if (value.startsWith(LIST_ITEM_MARKER))
840
+ return false;
841
+ return true;
842
+ }
843
+ function isNumericLike(value) {
844
+ return /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value) || /^0\d+$/.test(value);
845
+ }
846
+ var QUOTED_KEY_MARKER = Symbol("quotedKey");
847
+ function expandPathsSafe(value, strict) {
848
+ if (Array.isArray(value))
849
+ return value.map((item) => expandPathsSafe(item, strict));
850
+ if (isJsonObject(value)) {
851
+ const expandedObject = {};
852
+ const quotedKeys = value[QUOTED_KEY_MARKER];
853
+ for (const [key, keyValue] of Object.entries(value)) {
854
+ const isQuoted = quotedKeys?.has(key);
855
+ if (key.includes(DOT) && !isQuoted) {
856
+ const segments = key.split(DOT);
857
+ if (segments.every((seg) => isIdentifierSegment(seg))) {
858
+ insertPathSafe(expandedObject, segments, expandPathsSafe(keyValue, strict), strict);
859
+ continue;
860
+ }
861
+ }
862
+ const expandedValue = expandPathsSafe(keyValue, strict);
863
+ if (key in expandedObject) {
864
+ const conflictingValue = expandedObject[key];
865
+ if (canMerge(conflictingValue, expandedValue))
866
+ mergeObjects(conflictingValue, expandedValue, strict);
867
+ else {
868
+ if (strict)
869
+ throw new TypeError(`Path expansion conflict at key "${key}": cannot merge ${typeof conflictingValue} with ${typeof expandedValue}`);
870
+ expandedObject[key] = expandedValue;
871
+ }
872
+ } else
873
+ expandedObject[key] = expandedValue;
874
+ }
875
+ return expandedObject;
876
+ }
877
+ return value;
878
+ }
879
+ function insertPathSafe(target, segments, value, strict) {
880
+ let currentNode = target;
881
+ for (let i = 0; i < segments.length - 1; i++) {
882
+ const currentSegment = segments[i];
883
+ const segmentValue = currentNode[currentSegment];
884
+ if (segmentValue === void 0) {
885
+ const newObj = {};
886
+ currentNode[currentSegment] = newObj;
887
+ currentNode = newObj;
888
+ } else if (isJsonObject(segmentValue))
889
+ currentNode = segmentValue;
890
+ else {
891
+ if (strict)
892
+ throw new TypeError(`Path expansion conflict at segment "${currentSegment}": expected object but found ${typeof segmentValue}`);
893
+ const newObj = {};
894
+ currentNode[currentSegment] = newObj;
895
+ currentNode = newObj;
896
+ }
897
+ }
898
+ const lastSeg = segments[segments.length - 1];
899
+ const destinationValue = currentNode[lastSeg];
900
+ if (destinationValue === void 0)
901
+ currentNode[lastSeg] = value;
902
+ else if (canMerge(destinationValue, value))
903
+ mergeObjects(destinationValue, value, strict);
904
+ else {
905
+ if (strict)
906
+ throw new TypeError(`Path expansion conflict at key "${lastSeg}": cannot merge ${typeof destinationValue} with ${typeof value}`);
907
+ currentNode[lastSeg] = value;
908
+ }
909
+ }
910
+ function mergeObjects(target, source, strict) {
911
+ for (const [key, sourceValue] of Object.entries(source)) {
912
+ const targetValue = target[key];
913
+ if (targetValue === void 0)
914
+ target[key] = sourceValue;
915
+ else if (canMerge(targetValue, sourceValue))
916
+ mergeObjects(targetValue, sourceValue, strict);
917
+ else {
918
+ if (strict)
919
+ throw new TypeError(`Path expansion conflict at key "${key}": cannot merge ${typeof targetValue} with ${typeof sourceValue}`);
920
+ target[key] = sourceValue;
921
+ }
922
+ }
923
+ }
924
+ function canMerge(a, b) {
925
+ return isJsonObject(a) && isJsonObject(b);
926
+ }
927
+ function buildValueFromEvents(events) {
928
+ const state = {
929
+ stack: [],
930
+ root: void 0
931
+ };
932
+ for (const event of events)
933
+ applyEvent(state, event);
934
+ return finalizeState(state);
935
+ }
936
+ function applyEvent(state, event) {
937
+ const { stack } = state;
938
+ switch (event.type) {
939
+ case "startObject": {
940
+ const obj = {};
941
+ const quotedKeys = /* @__PURE__ */ new Set();
942
+ if (stack.length === 0)
943
+ stack.push({
944
+ type: "object",
945
+ obj,
946
+ quotedKeys
947
+ });
948
+ else {
949
+ const parent = stack[stack.length - 1];
950
+ if (parent.type === "object") {
951
+ if (parent.currentKey === void 0)
952
+ throw new Error("Object startObject event without preceding key");
953
+ parent.obj[parent.currentKey] = obj;
954
+ parent.currentKey = void 0;
955
+ } else if (parent.type === "array")
956
+ parent.arr.push(obj);
957
+ stack.push({
958
+ type: "object",
959
+ obj,
960
+ quotedKeys
961
+ });
962
+ }
963
+ break;
964
+ }
965
+ case "endObject": {
966
+ if (stack.length === 0)
967
+ throw new Error("Unexpected endObject event");
968
+ const context = stack.pop();
969
+ if (context.type !== "object")
970
+ throw new Error("Mismatched endObject event");
971
+ if (context.quotedKeys.size > 0)
972
+ Object.defineProperty(context.obj, QUOTED_KEY_MARKER, {
973
+ value: context.quotedKeys,
974
+ enumerable: false,
975
+ writable: false,
976
+ configurable: false
977
+ });
978
+ if (stack.length === 0)
979
+ state.root = context.obj;
980
+ break;
981
+ }
982
+ case "startArray": {
983
+ const arr = [];
984
+ if (stack.length === 0)
985
+ stack.push({
986
+ type: "array",
987
+ arr
988
+ });
989
+ else {
990
+ const parent = stack[stack.length - 1];
991
+ if (parent.type === "object") {
992
+ if (parent.currentKey === void 0)
993
+ throw new Error("Array startArray event without preceding key");
994
+ parent.obj[parent.currentKey] = arr;
995
+ parent.currentKey = void 0;
996
+ } else if (parent.type === "array")
997
+ parent.arr.push(arr);
998
+ stack.push({
999
+ type: "array",
1000
+ arr
1001
+ });
1002
+ }
1003
+ break;
1004
+ }
1005
+ case "endArray": {
1006
+ if (stack.length === 0)
1007
+ throw new Error("Unexpected endArray event");
1008
+ const context = stack.pop();
1009
+ if (context.type !== "array")
1010
+ throw new Error("Mismatched endArray event");
1011
+ if (stack.length === 0)
1012
+ state.root = context.arr;
1013
+ break;
1014
+ }
1015
+ case "key": {
1016
+ if (stack.length === 0)
1017
+ throw new Error("Key event outside of object context");
1018
+ const parent = stack[stack.length - 1];
1019
+ if (parent.type !== "object")
1020
+ throw new Error("Key event in non-object context");
1021
+ parent.currentKey = event.key;
1022
+ if (event.wasQuoted)
1023
+ parent.quotedKeys.add(event.key);
1024
+ break;
1025
+ }
1026
+ case "primitive":
1027
+ if (stack.length === 0)
1028
+ state.root = event.value;
1029
+ else {
1030
+ const parent = stack[stack.length - 1];
1031
+ if (parent.type === "object") {
1032
+ if (parent.currentKey === void 0)
1033
+ throw new Error("Primitive event without preceding key in object");
1034
+ parent.obj[parent.currentKey] = event.value;
1035
+ parent.currentKey = void 0;
1036
+ } else if (parent.type === "array")
1037
+ parent.arr.push(event.value);
1038
+ }
1039
+ break;
1040
+ }
1041
+ }
1042
+ function finalizeState(state) {
1043
+ if (state.stack.length !== 0)
1044
+ throw new Error("Incomplete event stream: stack not empty at end");
1045
+ if (state.root === void 0)
1046
+ throw new Error("No root value built from events");
1047
+ return state.root;
1048
+ }
1049
+ function tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, flattenDepth) {
1050
+ if (options.keyFolding !== "safe")
1051
+ return;
1052
+ if (!isJsonObject(value))
1053
+ return;
1054
+ const { segments, tail, leafValue } = collectSingleKeyChain(key, value, flattenDepth ?? options.flattenDepth);
1055
+ if (segments.length < 2)
1056
+ return;
1057
+ if (!segments.every((seg) => isIdentifierSegment(seg)))
1058
+ return;
1059
+ const foldedKey = buildFoldedKey(segments);
1060
+ const absolutePath = pathPrefix ? `${pathPrefix}${DOT}${foldedKey}` : foldedKey;
1061
+ if (siblings.includes(foldedKey))
1062
+ return;
1063
+ if (rootLiteralKeys && rootLiteralKeys.has(absolutePath))
1064
+ return;
1065
+ return {
1066
+ foldedKey,
1067
+ remainder: tail,
1068
+ leafValue,
1069
+ segmentCount: segments.length
1070
+ };
1071
+ }
1072
+ function collectSingleKeyChain(startKey, startValue, maxDepth) {
1073
+ const segments = [startKey];
1074
+ let currentValue = startValue;
1075
+ while (segments.length < maxDepth) {
1076
+ if (!isJsonObject(currentValue))
1077
+ break;
1078
+ const keys = Object.keys(currentValue);
1079
+ if (keys.length !== 1)
1080
+ break;
1081
+ const nextKey = keys[0];
1082
+ const nextValue = currentValue[nextKey];
1083
+ segments.push(nextKey);
1084
+ currentValue = nextValue;
1085
+ }
1086
+ if (!isJsonObject(currentValue) || isEmptyObject(currentValue))
1087
+ return {
1088
+ segments,
1089
+ tail: void 0,
1090
+ leafValue: currentValue
1091
+ };
1092
+ return {
1093
+ segments,
1094
+ tail: currentValue,
1095
+ leafValue: currentValue
1096
+ };
1097
+ }
1098
+ function buildFoldedKey(segments) {
1099
+ return segments.join(DOT);
1100
+ }
1101
+ function encodePrimitive(value, delimiter) {
1102
+ if (value === null)
1103
+ return NULL_LITERAL;
1104
+ if (typeof value === "boolean")
1105
+ return String(value);
1106
+ if (typeof value === "number")
1107
+ return String(value);
1108
+ return encodeStringLiteral(value, delimiter);
1109
+ }
1110
+ function encodeStringLiteral(value, delimiter = DEFAULT_DELIMITER) {
1111
+ if (isSafeUnquoted(value, delimiter))
1112
+ return value;
1113
+ return `${DOUBLE_QUOTE}${escapeString(value)}${DOUBLE_QUOTE}`;
1114
+ }
1115
+ function encodeKey(key) {
1116
+ if (isValidUnquotedKey(key))
1117
+ return key;
1118
+ return `${DOUBLE_QUOTE}${escapeString(key)}${DOUBLE_QUOTE}`;
1119
+ }
1120
+ function encodeAndJoinPrimitives(values, delimiter = DEFAULT_DELIMITER) {
1121
+ return values.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
1122
+ }
1123
+ function formatHeader(length, options) {
1124
+ const key = options?.key;
1125
+ const fields = options?.fields;
1126
+ const delimiter = options?.delimiter ?? COMMA;
1127
+ let header = "";
1128
+ if (key)
1129
+ header += encodeKey(key);
1130
+ header += `[${length}${delimiter !== DEFAULT_DELIMITER ? delimiter : ""}]`;
1131
+ if (fields) {
1132
+ const quotedFields = fields.map((f) => encodeKey(f));
1133
+ header += `{${quotedFields.join(delimiter)}}`;
1134
+ }
1135
+ header += ":";
1136
+ return header;
1137
+ }
1138
+ function* encodeJsonValue(value, options, depth) {
1139
+ if (isJsonPrimitive(value)) {
1140
+ const encodedPrimitive = encodePrimitive(value, options.delimiter);
1141
+ if (encodedPrimitive !== "")
1142
+ yield encodedPrimitive;
1143
+ return;
1144
+ }
1145
+ if (isJsonArray(value))
1146
+ yield* encodeArrayLines(void 0, value, depth, options);
1147
+ else if (isJsonObject(value))
1148
+ yield* encodeObjectLines(value, depth, options);
1149
+ }
1150
+ function* encodeObjectLines(value, depth, options, rootLiteralKeys, pathPrefix, remainingDepth) {
1151
+ const keys = Object.keys(value);
1152
+ if (depth === 0 && !rootLiteralKeys)
1153
+ rootLiteralKeys = new Set(keys.filter((k) => k.includes(".")));
1154
+ const effectiveFlattenDepth = remainingDepth ?? options.flattenDepth;
1155
+ for (const [key, val] of Object.entries(value))
1156
+ yield* encodeKeyValuePairLines(key, val, depth, options, keys, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
1157
+ }
1158
+ function* encodeKeyValuePairLines(key, value, depth, options, siblings, rootLiteralKeys, pathPrefix, flattenDepth) {
1159
+ const currentPath = pathPrefix ? `${pathPrefix}${DOT}${key}` : key;
1160
+ const effectiveFlattenDepth = flattenDepth ?? options.flattenDepth;
1161
+ if (options.keyFolding === "safe" && siblings) {
1162
+ const foldResult = tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
1163
+ if (foldResult) {
1164
+ const { foldedKey, remainder, leafValue, segmentCount } = foldResult;
1165
+ const encodedFoldedKey = encodeKey(foldedKey);
1166
+ if (remainder === void 0) {
1167
+ if (isJsonPrimitive(leafValue)) {
1168
+ yield indentedLine(depth, `${encodedFoldedKey}: ${encodePrimitive(leafValue, options.delimiter)}`, options.indent);
1169
+ return;
1170
+ } else if (isJsonArray(leafValue)) {
1171
+ yield* encodeArrayLines(foldedKey, leafValue, depth, options);
1172
+ return;
1173
+ } else if (isJsonObject(leafValue) && isEmptyObject(leafValue)) {
1174
+ yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
1175
+ return;
1176
+ }
1177
+ }
1178
+ if (isJsonObject(remainder)) {
1179
+ yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
1180
+ const remainingDepth = effectiveFlattenDepth - segmentCount;
1181
+ const foldedPath = pathPrefix ? `${pathPrefix}${DOT}${foldedKey}` : foldedKey;
1182
+ yield* encodeObjectLines(remainder, depth + 1, options, rootLiteralKeys, foldedPath, remainingDepth);
1183
+ return;
1184
+ }
1185
+ }
1186
+ }
1187
+ const encodedKey = encodeKey(key);
1188
+ if (isJsonPrimitive(value))
1189
+ yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value, options.delimiter)}`, options.indent);
1190
+ else if (isJsonArray(value))
1191
+ yield* encodeArrayLines(key, value, depth, options);
1192
+ else if (isJsonObject(value)) {
1193
+ yield indentedLine(depth, `${encodedKey}:`, options.indent);
1194
+ if (!isEmptyObject(value))
1195
+ yield* encodeObjectLines(value, depth + 1, options, rootLiteralKeys, currentPath, effectiveFlattenDepth);
1196
+ }
1197
+ }
1198
+ function* encodeArrayLines(key, value, depth, options) {
1199
+ if (value.length === 0) {
1200
+ yield indentedLine(depth, formatHeader(0, {
1201
+ key,
1202
+ delimiter: options.delimiter
1203
+ }), options.indent);
1204
+ return;
1205
+ }
1206
+ if (isArrayOfPrimitives(value)) {
1207
+ yield indentedLine(depth, encodeInlineArrayLine(value, options.delimiter, key), options.indent);
1208
+ return;
1209
+ }
1210
+ if (isArrayOfArrays(value)) {
1211
+ if (value.every((arr) => isArrayOfPrimitives(arr))) {
1212
+ yield* encodeArrayOfArraysAsListItemsLines(key, value, depth, options);
1213
+ return;
1214
+ }
1215
+ }
1216
+ if (isArrayOfObjects(value)) {
1217
+ const header = extractTabularHeader(value);
1218
+ if (header)
1219
+ yield* encodeArrayOfObjectsAsTabularLines(key, value, header, depth, options);
1220
+ else
1221
+ yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
1222
+ return;
1223
+ }
1224
+ yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
1225
+ }
1226
+ function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
1227
+ yield indentedLine(depth, formatHeader(values.length, {
1228
+ key: prefix,
1229
+ delimiter: options.delimiter
1230
+ }), options.indent);
1231
+ for (const arr of values)
1232
+ if (isArrayOfPrimitives(arr)) {
1233
+ const arrayLine = encodeInlineArrayLine(arr, options.delimiter);
1234
+ yield indentedListItem(depth + 1, arrayLine, options.indent);
1235
+ }
1236
+ }
1237
+ function encodeInlineArrayLine(values, delimiter, prefix) {
1238
+ const header = formatHeader(values.length, {
1239
+ key: prefix,
1240
+ delimiter
1241
+ });
1242
+ const joinedValue = encodeAndJoinPrimitives(values, delimiter);
1243
+ if (values.length === 0)
1244
+ return header;
1245
+ return `${header} ${joinedValue}`;
1246
+ }
1247
+ function* encodeArrayOfObjectsAsTabularLines(prefix, rows, header, depth, options) {
1248
+ yield indentedLine(depth, formatHeader(rows.length, {
1249
+ key: prefix,
1250
+ fields: header,
1251
+ delimiter: options.delimiter
1252
+ }), options.indent);
1253
+ yield* writeTabularRowsLines(rows, header, depth + 1, options);
1254
+ }
1255
+ function extractTabularHeader(rows) {
1256
+ if (rows.length === 0)
1257
+ return;
1258
+ const firstRow = rows[0];
1259
+ const firstKeys = Object.keys(firstRow);
1260
+ if (firstKeys.length === 0)
1261
+ return;
1262
+ if (isTabularArray(rows, firstKeys))
1263
+ return firstKeys;
1264
+ }
1265
+ function isTabularArray(rows, header) {
1266
+ for (const row of rows) {
1267
+ if (Object.keys(row).length !== header.length)
1268
+ return false;
1269
+ for (const key of header) {
1270
+ if (!(key in row))
1271
+ return false;
1272
+ if (!isJsonPrimitive(row[key]))
1273
+ return false;
1274
+ }
1275
+ }
1276
+ return true;
1277
+ }
1278
+ function* writeTabularRowsLines(rows, header, depth, options) {
1279
+ for (const row of rows)
1280
+ yield indentedLine(depth, encodeAndJoinPrimitives(header.map((key) => row[key]), options.delimiter), options.indent);
1281
+ }
1282
+ function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) {
1283
+ yield indentedLine(depth, formatHeader(items.length, {
1284
+ key: prefix,
1285
+ delimiter: options.delimiter
1286
+ }), options.indent);
1287
+ for (const item of items)
1288
+ yield* encodeListItemValueLines(item, depth + 1, options);
1289
+ }
1290
+ function* encodeObjectAsListItemLines(obj, depth, options) {
1291
+ if (isEmptyObject(obj)) {
1292
+ yield indentedLine(depth, LIST_ITEM_MARKER, options.indent);
1293
+ return;
1294
+ }
1295
+ const entries = Object.entries(obj);
1296
+ const [firstKey, firstValue] = entries[0];
1297
+ const restEntries = entries.slice(1);
1298
+ if (isJsonArray(firstValue) && isArrayOfObjects(firstValue)) {
1299
+ const header = extractTabularHeader(firstValue);
1300
+ if (header) {
1301
+ yield indentedListItem(depth, formatHeader(firstValue.length, {
1302
+ key: firstKey,
1303
+ fields: header,
1304
+ delimiter: options.delimiter
1305
+ }), options.indent);
1306
+ yield* writeTabularRowsLines(firstValue, header, depth + 2, options);
1307
+ if (restEntries.length > 0)
1308
+ yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
1309
+ return;
1310
+ }
1311
+ }
1312
+ const encodedKey = encodeKey(firstKey);
1313
+ if (isJsonPrimitive(firstValue))
1314
+ yield indentedListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`, options.indent);
1315
+ else if (isJsonArray(firstValue))
1316
+ if (firstValue.length === 0)
1317
+ yield indentedListItem(depth, `${encodedKey}${formatHeader(0, { delimiter: options.delimiter })}`, options.indent);
1318
+ else if (isArrayOfPrimitives(firstValue))
1319
+ yield indentedListItem(depth, `${encodedKey}${encodeInlineArrayLine(firstValue, options.delimiter)}`, options.indent);
1320
+ else {
1321
+ yield indentedListItem(depth, `${encodedKey}${formatHeader(firstValue.length, { delimiter: options.delimiter })}`, options.indent);
1322
+ for (const item of firstValue)
1323
+ yield* encodeListItemValueLines(item, depth + 2, options);
1324
+ }
1325
+ else if (isJsonObject(firstValue)) {
1326
+ yield indentedListItem(depth, `${encodedKey}:`, options.indent);
1327
+ if (!isEmptyObject(firstValue))
1328
+ yield* encodeObjectLines(firstValue, depth + 2, options);
1329
+ }
1330
+ if (restEntries.length > 0)
1331
+ yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
1332
+ }
1333
+ function* encodeListItemValueLines(value, depth, options) {
1334
+ if (isJsonPrimitive(value))
1335
+ yield indentedListItem(depth, encodePrimitive(value, options.delimiter), options.indent);
1336
+ else if (isJsonArray(value))
1337
+ if (isArrayOfPrimitives(value))
1338
+ yield indentedListItem(depth, encodeInlineArrayLine(value, options.delimiter), options.indent);
1339
+ else {
1340
+ yield indentedListItem(depth, formatHeader(value.length, { delimiter: options.delimiter }), options.indent);
1341
+ for (const item of value)
1342
+ yield* encodeListItemValueLines(item, depth + 1, options);
1343
+ }
1344
+ else if (isJsonObject(value))
1345
+ yield* encodeObjectAsListItemLines(value, depth, options);
1346
+ }
1347
+ function indentedLine(depth, content, indentSize) {
1348
+ return " ".repeat(indentSize * depth) + content;
1349
+ }
1350
+ function indentedListItem(depth, content, indentSize) {
1351
+ return indentedLine(depth, LIST_ITEM_PREFIX + content, indentSize);
1352
+ }
1353
+ function applyReplacer(root, replacer) {
1354
+ const replacedRoot = replacer("", root, []);
1355
+ if (replacedRoot === void 0)
1356
+ return transformChildren(root, replacer, []);
1357
+ return transformChildren(normalizeValue(replacedRoot), replacer, []);
1358
+ }
1359
+ function transformChildren(value, replacer, path) {
1360
+ if (isJsonObject(value))
1361
+ return transformObject(value, replacer, path);
1362
+ if (isJsonArray(value))
1363
+ return transformArray(value, replacer, path);
1364
+ return value;
1365
+ }
1366
+ function transformObject(obj, replacer, path) {
1367
+ const result = {};
1368
+ for (const [key, value] of Object.entries(obj)) {
1369
+ const childPath = [...path, key];
1370
+ const replacedValue = replacer(key, value, childPath);
1371
+ if (replacedValue === void 0)
1372
+ continue;
1373
+ result[key] = transformChildren(normalizeValue(replacedValue), replacer, childPath);
1374
+ }
1375
+ return result;
1376
+ }
1377
+ function transformArray(arr, replacer, path) {
1378
+ const result = [];
1379
+ for (let i = 0; i < arr.length; i++) {
1380
+ const value = arr[i];
1381
+ const childPath = [...path, i];
1382
+ const replacedValue = replacer(String(i), value, childPath);
1383
+ if (replacedValue === void 0)
1384
+ continue;
1385
+ const normalizedValue = normalizeValue(replacedValue);
1386
+ result.push(transformChildren(normalizedValue, replacer, childPath));
1387
+ }
1388
+ return result;
1389
+ }
1390
+ function encode(input, options) {
1391
+ return Array.from(encodeLines(input, options)).join("\n");
1392
+ }
1393
+ function decode(input, options) {
1394
+ return decodeFromLines(input.split("\n"), options);
1395
+ }
1396
+ function encodeLines(input, options) {
1397
+ const normalizedValue = normalizeValue(input);
1398
+ const resolvedOptions = resolveOptions(options);
1399
+ return encodeJsonValue(resolvedOptions.replacer ? applyReplacer(normalizedValue, resolvedOptions.replacer) : normalizedValue, resolvedOptions, 0);
1400
+ }
1401
+ function decodeFromLines(lines, options) {
1402
+ const resolvedOptions = resolveDecodeOptions(options);
1403
+ const decodedValue = buildValueFromEvents(decodeStreamSync$1(lines, {
1404
+ indent: resolvedOptions.indent,
1405
+ strict: resolvedOptions.strict
1406
+ }));
1407
+ if (resolvedOptions.expandPaths === "safe")
1408
+ return expandPathsSafe(decodedValue, resolvedOptions.strict);
1409
+ return decodedValue;
1410
+ }
1411
+ function resolveOptions(options) {
1412
+ return {
1413
+ indent: options?.indent ?? 2,
1414
+ delimiter: options?.delimiter ?? DEFAULT_DELIMITER,
1415
+ keyFolding: options?.keyFolding ?? "off",
1416
+ flattenDepth: options?.flattenDepth ?? Number.POSITIVE_INFINITY,
1417
+ replacer: options?.replacer
1418
+ };
1419
+ }
1420
+ function resolveDecodeOptions(options) {
1421
+ return {
1422
+ indent: options?.indent ?? 2,
1423
+ strict: options?.strict ?? true,
1424
+ expandPaths: options?.expandPaths ?? "off"
1425
+ };
1426
+ }
1427
+
1428
+ // src/commands/toon.ts
1429
+ async function toonEncode(args2) {
1430
+ const file = args2[0];
1431
+ if (!file || file === "--help" || file === "-h") {
1432
+ console.error(`USAGE: mid-tools toon <file|->`);
1433
+ process.exit(1);
1434
+ }
1435
+ let input;
1436
+ if (file === "-") {
1437
+ input = await readStdin();
1438
+ } else {
1439
+ input = (0, import_fs.readFileSync)(file, "utf-8");
1440
+ }
1441
+ const isToon = input.trim().split("\n")[0]?.includes(":") && !input.startsWith("{") && !input.startsWith("[");
1442
+ try {
1443
+ if (isToon) {
1444
+ const decoded = decode(input);
1445
+ console.log(JSON.stringify(decoded, null, 2));
1446
+ } else {
1447
+ const parsed = JSON.parse(input);
1448
+ const encoded = encode(parsed, {
1449
+ indent: 2
1450
+ });
1451
+ console.log(encoded);
1452
+ }
1453
+ } catch (error) {
1454
+ if (error instanceof SyntaxError) {
1455
+ console.error(`Parse error: ${error.message}`);
1456
+ } else if (error instanceof Error) {
1457
+ console.error(`Error: ${error.message}`);
1458
+ }
1459
+ process.exit(1);
1460
+ }
1461
+ }
1462
+ async function readStdin() {
1463
+ return new Promise((resolve3, reject) => {
1464
+ let data = "";
1465
+ process.stdin.setEncoding("utf8");
1466
+ process.stdin.on("readable", () => {
1467
+ let chunk;
1468
+ while ((chunk = process.stdin.read()) !== null) {
1469
+ data += chunk;
1470
+ }
1471
+ });
1472
+ process.stdin.on("end", () => {
1473
+ resolve3(data);
1474
+ });
1475
+ process.stdin.on("error", reject);
1476
+ });
1477
+ }
1478
+
1479
+ // src/commands/state.ts
1480
+ var import_fs3 = require("fs");
1481
+
1482
+ // src/utils.ts
1483
+ var import_fs2 = require("fs");
1484
+ var import_path = require("path");
1485
+ var import_process = require("process");
1486
+ function getPlanningDir() {
1487
+ const local = (0, import_path.resolve)((0, import_process.cwd)(), ".planning");
1488
+ if ((0, import_fs2.existsSync)(local)) {
1489
+ return local;
1490
+ }
1491
+ return local;
1492
+ }
1493
+ function getConfigPath() {
1494
+ return (0, import_path.resolve)(getPlanningDir(), "config.json");
1495
+ }
1496
+ function getStateFile() {
1497
+ return (0, import_path.resolve)(getPlanningDir(), "STATE.md");
1498
+ }
1499
+ function getRoadmapFile() {
1500
+ return (0, import_path.resolve)(getPlanningDir(), "ROADMAP.md");
1501
+ }
1502
+ function readJSON(path) {
1503
+ if (!(0, import_fs2.existsSync)(path)) {
1504
+ return {};
1505
+ }
1506
+ try {
1507
+ return JSON.parse((0, import_fs2.readFileSync)(path, "utf-8"));
1508
+ } catch {
1509
+ return {};
1510
+ }
1511
+ }
1512
+ function extractFrontmatter(content) {
1513
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
1514
+ if (!match) {
1515
+ return {};
1516
+ }
1517
+ const fm = {};
1518
+ const lines = match[1].split("\n");
1519
+ for (const line of lines) {
1520
+ const colonIndex = line.indexOf(":");
1521
+ if (colonIndex === -1)
1522
+ continue;
1523
+ const key = line.substring(0, colonIndex).trim();
1524
+ const value = line.substring(colonIndex + 1).trim();
1525
+ if (value === "true") {
1526
+ fm[key] = true;
1527
+ } else if (value === "false") {
1528
+ fm[key] = false;
1529
+ } else if (value === "null" || value === "") {
1530
+ fm[key] = null;
1531
+ } else if (/^\d+$/.test(value)) {
1532
+ fm[key] = parseInt(value, 10);
1533
+ } else if (/^\d+\.\d+$/.test(value)) {
1534
+ fm[key] = parseFloat(value);
1535
+ } else if (value.startsWith("[") && value.endsWith("]")) {
1536
+ try {
1537
+ fm[key] = JSON.parse(value);
1538
+ } catch {
1539
+ fm[key] = value;
1540
+ }
1541
+ } else {
1542
+ fm[key] = value.replace(/^["']|["']$/g, "");
1543
+ }
1544
+ }
1545
+ return fm;
1546
+ }
1547
+ function getContextWindow() {
1548
+ try {
1549
+ const config = readJSON(getConfigPath());
1550
+ return config.context_window || 2e5;
1551
+ } catch {
1552
+ return 2e5;
1553
+ }
1554
+ }
1555
+ function getModelProfile() {
1556
+ try {
1557
+ const config = readJSON(getConfigPath());
1558
+ return config.model_profile || "balanced";
1559
+ } catch {
1560
+ return "balanced";
1561
+ }
1562
+ }
1563
+
1564
+ // src/commands/state.ts
1565
+ function stateCommand(args2) {
1566
+ const subcommand = args2[0];
1567
+ switch (subcommand) {
1568
+ case "get":
1569
+ stateGet();
1570
+ break;
1571
+ case "set":
1572
+ stateSet(args2[1], args2.slice(2).join(" "));
1573
+ break;
1574
+ case "advance":
1575
+ stateAdvance(args2[1]);
1576
+ break;
1577
+ default:
1578
+ console.error(`Unknown state command: ${subcommand}`);
1579
+ console.error(`Usage: mid-tools state <get|set|advance>`);
1580
+ process.exit(1);
1581
+ }
1582
+ }
1583
+ function stateGet() {
1584
+ const stateFile = getStateFile();
1585
+ if (!(0, import_fs3.existsSync)(stateFile)) {
1586
+ console.log(`phase_number: 0
1587
+ status: uninitialized`);
1588
+ return;
1589
+ }
1590
+ const content = (0, import_fs3.readFileSync)(stateFile, "utf-8");
1591
+ const fm = extractFrontmatter(content);
1592
+ const toon = encode(fm, { keyFolding: "safe", indent: 2 });
1593
+ console.log(toon);
1594
+ }
1595
+ function stateSet(key, value) {
1596
+ const stateFile = getStateFile();
1597
+ const planningDir = getPlanningDir();
1598
+ if (!(0, import_fs3.existsSync)(planningDir)) {
1599
+ (0, import_fs3.mkdirSync)(planningDir, { recursive: true });
1600
+ }
1601
+ let content = "";
1602
+ let fm = {};
1603
+ if ((0, import_fs3.existsSync)(stateFile)) {
1604
+ content = (0, import_fs3.readFileSync)(stateFile, "utf-8");
1605
+ fm = extractFrontmatter(content);
1606
+ const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
1607
+ content = match ? match[1] : "";
1608
+ }
1609
+ let parsedValue = value;
1610
+ if (value === "true")
1611
+ parsedValue = true;
1612
+ else if (value === "false")
1613
+ parsedValue = false;
1614
+ else if (value === "null")
1615
+ parsedValue = null;
1616
+ else if (/^\d+$/.test(value))
1617
+ parsedValue = parseInt(value, 10);
1618
+ else if (/^\d+\.\d+$/.test(value))
1619
+ parsedValue = parseFloat(value);
1620
+ else if ((value.startsWith("[") || value.startsWith("{")) && value.endsWith("]") || value.endsWith("}")) {
1621
+ try {
1622
+ parsedValue = JSON.parse(value);
1623
+ } catch {
1624
+ }
1625
+ }
1626
+ fm[key] = parsedValue;
1627
+ const fmLines = Object.entries(fm).map(([k, v]) => {
1628
+ if (typeof v === "string") {
1629
+ return `${k}: ${v}`;
1630
+ } else if (v === null) {
1631
+ return `${k}:`;
1632
+ } else if (typeof v === "object") {
1633
+ return `${k}: ${JSON.stringify(v)}`;
1634
+ } else {
1635
+ return `${k}: ${String(v)}`;
1636
+ }
1637
+ });
1638
+ const newContent = `---
1639
+ ${fmLines.join("\n")}
1640
+ ---
1641
+ ${content}`;
1642
+ (0, import_fs3.writeFileSync)(stateFile, newContent, "utf-8");
1643
+ }
1644
+ function stateAdvance(phase) {
1645
+ const stateFile = getStateFile();
1646
+ if (!(0, import_fs3.existsSync)(stateFile)) {
1647
+ console.error(`STATE.md not found at ${stateFile}`);
1648
+ process.exit(1);
1649
+ }
1650
+ stateSet("last_completed_phase", phase);
1651
+ console.log(`Advanced to phase: ${phase}`);
1652
+ }
1653
+
1654
+ // src/commands/frontmatter.ts
1655
+ var import_fs4 = require("fs");
1656
+ function frontmatterCommand(args2) {
1657
+ const subcommand = args2[0];
1658
+ switch (subcommand) {
1659
+ case "get":
1660
+ frontmatterGet(args2.slice(1));
1661
+ break;
1662
+ case "list":
1663
+ frontmatterList(args2[1]);
1664
+ break;
1665
+ default:
1666
+ console.error(`Unknown frontmatter command: ${subcommand}`);
1667
+ console.error(`Usage: mid-tools fm <get|list>`);
1668
+ process.exit(1);
1669
+ }
1670
+ }
1671
+ function frontmatterGet(args2) {
1672
+ const file = args2[0];
1673
+ let field = null;
1674
+ for (let i = 0; i < args2.length; i++) {
1675
+ if (args2[i] === "--field" && i + 1 < args2.length) {
1676
+ field = args2[i + 1];
1677
+ break;
1678
+ }
1679
+ }
1680
+ if (!file) {
1681
+ console.error(`Usage: mid-tools fm get <file> --field <fieldname>`);
1682
+ process.exit(1);
1683
+ }
1684
+ if (!(0, import_fs4.existsSync)(file)) {
1685
+ console.error(`File not found: ${file}`);
1686
+ process.exit(1);
1687
+ }
1688
+ const content = (0, import_fs4.readFileSync)(file, "utf-8");
1689
+ const fm = extractFrontmatter(content);
1690
+ if (!field) {
1691
+ console.error(`Usage: mid-tools fm get <file> --field <fieldname>`);
1692
+ process.exit(1);
1693
+ }
1694
+ const value = fm[field];
1695
+ if (value === void 0) {
1696
+ console.log(``);
1697
+ } else if (typeof value === "object") {
1698
+ console.log(JSON.stringify(value));
1699
+ } else {
1700
+ console.log(String(value));
1701
+ }
1702
+ }
1703
+ function frontmatterList(file) {
1704
+ if (!file) {
1705
+ console.error(`Usage: mid-tools fm list <file>`);
1706
+ process.exit(1);
1707
+ }
1708
+ if (!(0, import_fs4.existsSync)(file)) {
1709
+ console.error(`File not found: ${file}`);
1710
+ process.exit(1);
1711
+ }
1712
+ const content = (0, import_fs4.readFileSync)(file, "utf-8");
1713
+ const fm = extractFrontmatter(content);
1714
+ const toon = encode(fm, { keyFolding: "safe", indent: 2 });
1715
+ console.log(toon);
1716
+ }
1717
+
1718
+ // src/commands/roadmap.ts
1719
+ var import_fs5 = require("fs");
1720
+ function roadmapCommand(args2) {
1721
+ const subcommand = args2[0];
1722
+ switch (subcommand) {
1723
+ case "phases":
1724
+ roadmapPhases();
1725
+ break;
1726
+ case "current":
1727
+ roadmapCurrent();
1728
+ break;
1729
+ case "phase":
1730
+ roadmapPhase(args2[1]);
1731
+ break;
1732
+ default:
1733
+ console.error(`Unknown roadmap command: ${subcommand}`);
1734
+ console.error(`Usage: mid-tools roadmap <phases|current|phase>`);
1735
+ process.exit(1);
1736
+ }
1737
+ }
1738
+ function roadmapPhases() {
1739
+ const roadmapFile = getRoadmapFile();
1740
+ if (!(0, import_fs5.existsSync)(roadmapFile)) {
1741
+ console.log(`phases[0]:`);
1742
+ return;
1743
+ }
1744
+ const content = (0, import_fs5.readFileSync)(roadmapFile, "utf-8");
1745
+ const phases = extractPhases(content);
1746
+ const toon = encode({ phases }, { keyFolding: "safe", indent: 2 });
1747
+ console.log(toon);
1748
+ }
1749
+ function roadmapCurrent() {
1750
+ const roadmapFile = getRoadmapFile();
1751
+ if (!(0, import_fs5.existsSync)(roadmapFile)) {
1752
+ console.log(`phase_number: 0
1753
+ phase_name: ""
1754
+ status: pending`);
1755
+ return;
1756
+ }
1757
+ const content = (0, import_fs5.readFileSync)(roadmapFile, "utf-8");
1758
+ const phases = extractPhases(content);
1759
+ const currentPhase = phases.find((p) => p.status !== "complete") || phases[0];
1760
+ const toon = encode(currentPhase || {}, { keyFolding: "safe", indent: 2 });
1761
+ console.log(toon);
1762
+ }
1763
+ function roadmapPhase(phaseNumber) {
1764
+ if (!phaseNumber) {
1765
+ console.error(`Usage: mid-tools roadmap phase <number>`);
1766
+ process.exit(1);
1767
+ }
1768
+ const roadmapFile = getRoadmapFile();
1769
+ if (!(0, import_fs5.existsSync)(roadmapFile)) {
1770
+ console.error(`ROADMAP.md not found at ${roadmapFile}`);
1771
+ process.exit(1);
1772
+ }
1773
+ const content = (0, import_fs5.readFileSync)(roadmapFile, "utf-8");
1774
+ const phases = extractPhases(content);
1775
+ const num = parseInt(phaseNumber, 10);
1776
+ const phase = phases.find((p) => p.number === num);
1777
+ if (!phase) {
1778
+ console.error(`Phase ${num} not found`);
1779
+ process.exit(1);
1780
+ }
1781
+ const toon = encode(phase, { keyFolding: "safe", indent: 2 });
1782
+ console.log(toon);
1783
+ }
1784
+ function extractPhases(content) {
1785
+ const phases = [];
1786
+ const lines = content.split("\n");
1787
+ let phaseNumber = 0;
1788
+ let phaseName = "";
1789
+ let phaseStatus = "pending";
1790
+ for (const line of lines) {
1791
+ const phaseMatch = line.match(/^##\s+(\d+)\s*-\s*([^[\]]+)\s*\[([^\]]+)\]?/);
1792
+ if (phaseMatch) {
1793
+ if (phaseName) {
1794
+ phases.push({
1795
+ number: phaseNumber,
1796
+ name: phaseName,
1797
+ status: phaseStatus
1798
+ });
1799
+ }
1800
+ phaseNumber = parseInt(phaseMatch[1], 10);
1801
+ phaseName = phaseMatch[2].trim();
1802
+ phaseStatus = phaseMatch[3]?.toLowerCase() || "pending";
1803
+ }
1804
+ }
1805
+ if (phaseName) {
1806
+ phases.push({
1807
+ number: phaseNumber,
1808
+ name: phaseName,
1809
+ status: phaseStatus
1810
+ });
1811
+ }
1812
+ return phases;
1813
+ }
1814
+
1815
+ // src/commands/config.ts
1816
+ var import_fs6 = require("fs");
1817
+ function configCommand(args2) {
1818
+ const subcommand = args2[0];
1819
+ switch (subcommand) {
1820
+ case "get":
1821
+ configGet(args2[1]);
1822
+ break;
1823
+ case "set":
1824
+ configSet(args2[1], args2.slice(2).join(" "));
1825
+ break;
1826
+ default:
1827
+ console.error(`Unknown config command: ${subcommand}`);
1828
+ console.error(`Usage: mid-tools config <get|set>`);
1829
+ process.exit(1);
1830
+ }
1831
+ }
1832
+ function configGet(key) {
1833
+ if (!key) {
1834
+ console.error(`Usage: mid-tools config get <key>`);
1835
+ process.exit(1);
1836
+ }
1837
+ const config = readJSON(getConfigPath());
1838
+ const value = config[key];
1839
+ if (value === void 0) {
1840
+ console.log(``);
1841
+ } else if (typeof value === "object") {
1842
+ console.log(JSON.stringify(value));
1843
+ } else {
1844
+ console.log(String(value));
1845
+ }
1846
+ }
1847
+ function configSet(key, value) {
1848
+ if (!key) {
1849
+ console.error(`Usage: mid-tools config set <key> <value>`);
1850
+ process.exit(1);
1851
+ }
1852
+ const configPath = getConfigPath();
1853
+ const planningDir = getPlanningDir();
1854
+ if (!(0, import_fs6.existsSync)(planningDir)) {
1855
+ (0, import_fs6.mkdirSync)(planningDir, { recursive: true });
1856
+ }
1857
+ const config = readJSON(configPath);
1858
+ let parsedValue = value;
1859
+ if (value === "true")
1860
+ parsedValue = true;
1861
+ else if (value === "false")
1862
+ parsedValue = false;
1863
+ else if (value === "null")
1864
+ parsedValue = null;
1865
+ else if (/^\d+$/.test(value))
1866
+ parsedValue = parseInt(value, 10);
1867
+ else if (/^\d+\.\d+$/.test(value))
1868
+ parsedValue = parseFloat(value);
1869
+ else if ((value.startsWith("[") || value.startsWith("{")) && (value.endsWith("]") || value.endsWith("}"))) {
1870
+ try {
1871
+ parsedValue = JSON.parse(value);
1872
+ } catch {
1873
+ }
1874
+ }
1875
+ config[key] = parsedValue;
1876
+ (0, import_fs6.writeFileSync)(configPath, JSON.stringify(config, null, 2), "utf-8");
1877
+ }
1878
+
1879
+ // src/commands/init.ts
1880
+ var import_fs7 = require("fs");
1881
+ var import_path2 = require("path");
1882
+ async function initCommand(args2) {
1883
+ const workflow = args2[0];
1884
+ const phaseArg = args2[1];
1885
+ if (!workflow) {
1886
+ console.error(`Usage: mid-tools init <workflow> [phase]`);
1887
+ process.exit(1);
1888
+ }
1889
+ const payload = getInitPayload(workflow, phaseArg);
1890
+ const toon = encode(payload, { keyFolding: "safe", indent: 2 });
1891
+ console.log(toon);
1892
+ }
1893
+ function getInitPayload(workflow, phaseArg) {
1894
+ const planningDir = getPlanningDir();
1895
+ const contextWindow = getContextWindow();
1896
+ const modelProfile = getModelProfile();
1897
+ let phaseNumber = 1;
1898
+ if (phaseArg) {
1899
+ phaseNumber = parseInt(phaseArg, 10) || 1;
1900
+ }
1901
+ const phaseName = `Phase ${phaseNumber}`;
1902
+ const phaseDir = (0, import_path2.resolve)(planningDir, `phases`, `0${phaseNumber}`);
1903
+ const branchName = `phase-${phaseNumber}`;
1904
+ const { executor, verifier } = routeModels(modelProfile);
1905
+ const { plans, incompletePlans } = getPlanList(phaseDir);
1906
+ const parallelization = incompletePlans.length > 1;
1907
+ return {
1908
+ workflow,
1909
+ phase_number: phaseNumber,
1910
+ phase_name: phaseName,
1911
+ phase_dir: phaseDir,
1912
+ plans,
1913
+ incomplete_plans: incompletePlans,
1914
+ branch_name: branchName,
1915
+ parallelization,
1916
+ executor_model: executor,
1917
+ verifier_model: verifier,
1918
+ context_window: contextWindow,
1919
+ model_profile: modelProfile
1920
+ };
1921
+ }
1922
+ function routeModels(profile) {
1923
+ switch (profile) {
1924
+ case "budget":
1925
+ return { executor: "claude-haiku-4-5", verifier: "claude-haiku-4-5" };
1926
+ case "balanced":
1927
+ return { executor: "claude-sonnet-4-6", verifier: "claude-haiku-4-5" };
1928
+ case "quality":
1929
+ return { executor: "claude-opus-4-6", verifier: "claude-sonnet-4-6" };
1930
+ default:
1931
+ return { executor: "claude-sonnet-4-6", verifier: "claude-haiku-4-5" };
1932
+ }
1933
+ }
1934
+ function getPlanList(phaseDir) {
1935
+ const plans = [];
1936
+ const incompletePlans = [];
1937
+ if (!(0, import_fs7.existsSync)(phaseDir)) {
1938
+ return { plans, incompletePlans };
1939
+ }
1940
+ const fs = require("fs");
1941
+ try {
1942
+ const files = fs.readdirSync(phaseDir);
1943
+ const planFiles = files.filter((f) => f.match(/^\d+-\d+-PLAN\.md$/));
1944
+ for (const file of planFiles) {
1945
+ plans.push(file);
1946
+ const summaryFile = file.replace("PLAN", "SUMMARY");
1947
+ if (!files.includes(summaryFile)) {
1948
+ incompletePlans.push(file);
1949
+ }
1950
+ }
1951
+ } catch {
1952
+ }
1953
+ return { plans, incompletePlans };
1954
+ }
1955
+
1956
+ // src/index.ts
1957
+ var args = process.argv.slice(2);
1958
+ async function main() {
1959
+ if (args.length === 0) {
1960
+ printHelp();
1961
+ process.exit(0);
1962
+ }
1963
+ const command = args[0];
1964
+ const commandArgs = args.slice(1);
1965
+ try {
1966
+ switch (command) {
1967
+ case "toon":
1968
+ await toonEncode(commandArgs);
1969
+ break;
1970
+ case "init":
1971
+ await initCommand(commandArgs);
1972
+ break;
1973
+ case "state":
1974
+ stateCommand(commandArgs);
1975
+ break;
1976
+ case "fm":
1977
+ case "frontmatter":
1978
+ frontmatterCommand(commandArgs);
1979
+ break;
1980
+ case "roadmap":
1981
+ roadmapCommand(commandArgs);
1982
+ break;
1983
+ case "config":
1984
+ configCommand(commandArgs);
1985
+ break;
1986
+ case "help":
1987
+ case "--help":
1988
+ case "-h":
1989
+ printHelp();
1990
+ break;
1991
+ default:
1992
+ console.error(`Unknown command: ${command}`);
1993
+ printHelp();
1994
+ process.exit(1);
1995
+ }
1996
+ } catch (error) {
1997
+ if (error instanceof Error) {
1998
+ console.error(`Error: ${error.message}`);
1999
+ } else {
2000
+ console.error(`Unknown error: ${error}`);
2001
+ }
2002
+ process.exit(1);
2003
+ }
2004
+ }
2005
+ function printHelp() {
2006
+ console.log(`
2007
+ makeitdone tools \u2014 token-optimized utility for Claude Code orchestration
2008
+
2009
+ USAGE:
2010
+ mid-tools <command> [options]
2011
+
2012
+ COMMANDS:
2013
+ toon <file|-> Convert JSON to TOON or vice versa
2014
+ Use '-' for stdin
2015
+
2016
+ init <workflow> [phase] Get workflow initialization payload (returns TOON)
2017
+
2018
+ state <subcommand> STATE.md operations
2019
+ get Read STATE.md as TOON
2020
+ set <key> <value> Atomic field update
2021
+ advance <phase> Mark phase as complete
2022
+
2023
+ fm|frontmatter <subcommand> YAML frontmatter operations
2024
+ get <file> --field <f> Extract single frontmatter field
2025
+ list <file> List all frontmatter fields (TOON)
2026
+
2027
+ roadmap <subcommand> ROADMAP.md queries
2028
+ phases List all phases (TOON)
2029
+ current Current active phase (TOON)
2030
+ phase <n> Get phase details by number (TOON)
2031
+
2032
+ config <subcommand> .planning/config.json
2033
+ get <key> Read config value
2034
+ set <key> <value> Write config value
2035
+
2036
+ help Show this help
2037
+
2038
+ EXAMPLES:
2039
+ node mid-tools.cjs toon data.json
2040
+ node mid-tools.cjs init execute 1
2041
+ node mid-tools.cjs state get
2042
+ node mid-tools.cjs roadmap phases
2043
+ `);
2044
+ }
2045
+ main().catch((err) => {
2046
+ console.error(err);
2047
+ process.exit(1);
2048
+ });