@pmelab/gtd 64.1.1 → 64.2.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 (43) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +27 -14
  3. package/dist/chunks/{flows-B7ZRCe-B.mjs → flows-dnIE_qbe.mjs} +7 -13
  4. package/dist/chunks/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-D8jQpDG7.mjs} +1 -2
  5. package/dist/chunks/{steering-Cem5i6Xl.mjs → steering-DEh_MS40.mjs} +181 -187
  6. package/dist/chunks/{testkit-DfWZQCWQ.mjs → testkit-BwCH8ky6.mjs} +412 -512
  7. package/dist/chunks/{wire-CPNSm_9N.mjs → wire-CaPJ9Tme.mjs} +12 -24
  8. package/dist/flows.mjs +1 -2
  9. package/dist/gtd.bundle.mjs +1010 -1785
  10. package/dist/gtd.core.mjs +191 -182
  11. package/dist/steering.mjs +1 -2
  12. package/dist/testkit/gherkin.mjs +3 -5
  13. package/dist/testkit.mjs +2 -2
  14. package/dist/web/main.css +1 -1
  15. package/dist/web/main.js +438 -413
  16. package/dist/wire.mjs +1 -2
  17. package/dist/workflow-kit.mjs +6 -10
  18. package/package.json +19 -32
  19. package/src/cli/Cli.test.ts +1 -0
  20. package/src/cli/Cli.ts +16 -1
  21. package/src/cli/Program.ts +6 -0
  22. package/src/cli/ToolCommands.ts +1 -0
  23. package/src/edge/Edge.test.ts +23 -1
  24. package/src/edge/Edge.ts +23 -1
  25. package/src/edge/index.ts +1 -0
  26. package/src/emit/GitScript.test.ts +1 -1
  27. package/src/flows/runtime.test.ts +1 -1
  28. package/src/platform/Git.ts +33 -10
  29. package/src/replay/Replay.test.ts +21 -7
  30. package/src/steering/Blocks.test.ts +3 -1
  31. package/src/steering/Blocks.ts +14 -6
  32. package/src/steering/SteeringFormat.ts +9 -1
  33. package/src/steering/freeform.test.ts +51 -1
  34. package/src/steering/freeform.ts +38 -0
  35. package/src/steering/qa.test.ts +3 -3
  36. package/src/steering/qa.ts +1 -1
  37. package/src/steering/review.test.ts +26 -1
  38. package/src/step/LandStep.ts +1 -1
  39. package/src/twins/FakeGitOperations.ts +2 -0
  40. package/src/twins/GitTiers.ts +27 -2
  41. package/src/twins/InMemRepo.ts +5 -0
  42. package/src/wire/BeatPlain.ts +3 -3
  43. package/src/wire/Select.ts +1 -1
@@ -1,13 +1,12 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- //#region src/steering/SteeringFormat.ts
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
2
+ // src/steering/SteeringFormat.ts
3
3
  /** `file:line:col: message` — the shape editors and grep already jump on. Stored 0-based, printed 1-based. A finding with a `line` but no `range`, or none at all, degrades to the shorter forms. */
4
4
  const formatFinding = (file, finding) => {
5
5
  if (finding.line === void 0) return finding.message;
6
6
  const col = finding.range !== void 0 ? `:${finding.range.start.character + 1}` : "";
7
7
  return `${file}:${finding.line + 1}${col}: ${finding.message}`;
8
8
  };
9
- //#endregion
10
- //#region node_modules/mdast-util-to-string/lib/index.js
9
+ // node_modules/mdast-util-to-string/lib/index.js
11
10
  /**
12
11
  * @typedef {import('mdast').Nodes} Nodes
13
12
  *
@@ -88,8 +87,7 @@ function all(values, includeImageAlt, includeHtml) {
88
87
  function node(value) {
89
88
  return Boolean(value && typeof value === "object");
90
89
  }
91
- //#endregion
92
- //#region node_modules/character-entities/index.js
90
+ // node_modules/character-entities/index.js
93
91
  /**
94
92
  * Map of named character references.
95
93
  *
@@ -2222,8 +2220,7 @@ const characterEntities = {
2222
2220
  zwj: "‍",
2223
2221
  zwnj: "‌"
2224
2222
  };
2225
- //#endregion
2226
- //#region node_modules/decode-named-character-reference/index.js
2223
+ // node_modules/decode-named-character-reference/index.js
2227
2224
  const own$1 = {}.hasOwnProperty;
2228
2225
  /**
2229
2226
  * Decode a single character reference (without the `&` or `;`).
@@ -2239,8 +2236,7 @@ const own$1 = {}.hasOwnProperty;
2239
2236
  function decodeNamedCharacterReference(value) {
2240
2237
  return own$1.call(characterEntities, value) ? characterEntities[value] : false;
2241
2238
  }
2242
- //#endregion
2243
- //#region node_modules/micromark-util-chunked/index.js
2239
+ // node_modules/micromark-util-chunked/index.js
2244
2240
  /**
2245
2241
  * Like `Array#splice`, but smarter for giant arrays.
2246
2242
  *
@@ -2309,8 +2305,7 @@ function push(list, items) {
2309
2305
  }
2310
2306
  return items;
2311
2307
  }
2312
- //#endregion
2313
- //#region node_modules/micromark-util-combine-extensions/index.js
2308
+ // node_modules/micromark-util-combine-extensions/index.js
2314
2309
  /**
2315
2310
  * @import {
2316
2311
  * Extension,
@@ -2380,8 +2375,7 @@ function constructs(existing, list) {
2380
2375
  while (++index < list.length) (list[index].add === "after" ? existing : before).push(list[index]);
2381
2376
  splice(existing, 0, 0, before);
2382
2377
  }
2383
- //#endregion
2384
- //#region node_modules/micromark-util-decode-numeric-character-reference/index.js
2378
+ // node_modules/micromark-util-decode-numeric-character-reference/index.js
2385
2379
  /**
2386
2380
  * Turn the number (in string form as either hexa- or plain decimal) coming from
2387
2381
  * a numeric character reference into a character.
@@ -2401,8 +2395,7 @@ function decodeNumericCharacterReference(value, base) {
2401
2395
  if (code < 9 || code === 11 || code > 13 && code < 32 || code > 126 && code < 160 || code > 55295 && code < 57344 || code > 64975 && code < 65008 || (code & 65535) === 65535 || (code & 65535) === 65534 || code > 1114111) return "�";
2402
2396
  return String.fromCodePoint(code);
2403
2397
  }
2404
- //#endregion
2405
- //#region node_modules/micromark-util-normalize-identifier/index.js
2398
+ // node_modules/micromark-util-normalize-identifier/index.js
2406
2399
  /**
2407
2400
  * Normalize an identifier (as found in references, definitions).
2408
2401
  *
@@ -2425,8 +2418,7 @@ function decodeNumericCharacterReference(value, base) {
2425
2418
  function normalizeIdentifier(value) {
2426
2419
  return value.replace(/[\t\n\r ]+/g, " ").replace(/^ | $/g, "").toLowerCase().toUpperCase();
2427
2420
  }
2428
- //#endregion
2429
- //#region node_modules/micromark-util-character/index.js
2421
+ // node_modules/micromark-util-character/index.js
2430
2422
  /**
2431
2423
  * @import {Code} from 'micromark-util-types'
2432
2424
  */
@@ -2653,8 +2645,7 @@ function regexCheck(regex) {
2653
2645
  return code !== null && code > -1 && regex.test(String.fromCharCode(code));
2654
2646
  }
2655
2647
  }
2656
- //#endregion
2657
- //#region node_modules/micromark-factory-space/index.js
2648
+ // node_modules/micromark-factory-space/index.js
2658
2649
  /**
2659
2650
  * @import {Effects, State, TokenType} from 'micromark-util-types'
2660
2651
  */
@@ -2712,8 +2703,7 @@ function factorySpace(effects, ok, type, max) {
2712
2703
  return ok(code);
2713
2704
  }
2714
2705
  }
2715
- //#endregion
2716
- //#region node_modules/micromark/lib/initialize/content.js
2706
+ // node_modules/micromark/lib/initialize/content.js
2717
2707
  /**
2718
2708
  * @import {
2719
2709
  * InitialConstruct,
@@ -2779,8 +2769,7 @@ function initializeContent(effects) {
2779
2769
  return data;
2780
2770
  }
2781
2771
  }
2782
- //#endregion
2783
- //#region node_modules/micromark/lib/initialize/document.js
2772
+ // node_modules/micromark/lib/initialize/document.js
2784
2773
  /**
2785
2774
  * @import {
2786
2775
  * Construct,
@@ -2995,8 +2984,7 @@ function initializeDocument(effects) {
2995
2984
  function tokenizeContainer(effects, ok, nok) {
2996
2985
  return factorySpace(effects, effects.attempt(this.parser.constructs.document, ok, nok), "linePrefix", this.parser.constructs.disable.null.includes("codeIndented") ? void 0 : 4);
2997
2986
  }
2998
- //#endregion
2999
- //#region node_modules/micromark-util-classify-character/index.js
2987
+ // node_modules/micromark-util-classify-character/index.js
3000
2988
  /**
3001
2989
  * @import {Code} from 'micromark-util-types'
3002
2990
  */
@@ -3018,8 +3006,7 @@ function classifyCharacter(code) {
3018
3006
  if (code === null || markdownLineEndingOrSpace(code) || unicodeWhitespace(code)) return 1;
3019
3007
  if (unicodePunctuation(code)) return 2;
3020
3008
  }
3021
- //#endregion
3022
- //#region node_modules/micromark-util-resolve-all/index.js
3009
+ // node_modules/micromark-util-resolve-all/index.js
3023
3010
  /**
3024
3011
  * @import {Event, Resolver, TokenizeContext} from 'micromark-util-types'
3025
3012
  */
@@ -3048,8 +3035,7 @@ function resolveAll(constructs, events, context) {
3048
3035
  }
3049
3036
  return events;
3050
3037
  }
3051
- //#endregion
3052
- //#region node_modules/micromark-core-commonmark/lib/attention.js
3038
+ // node_modules/micromark-core-commonmark/lib/attention.js
3053
3039
  /**
3054
3040
  * @import {
3055
3041
  * Code,
@@ -3268,8 +3254,7 @@ function movePoint(point, offset) {
3268
3254
  point.offset += offset;
3269
3255
  point._bufferIndex += offset;
3270
3256
  }
3271
- //#endregion
3272
- //#region node_modules/micromark-core-commonmark/lib/autolink.js
3257
+ // node_modules/micromark-core-commonmark/lib/autolink.js
3273
3258
  /**
3274
3259
  * @import {
3275
3260
  * Construct,
@@ -3479,8 +3464,7 @@ function tokenizeAutolink(effects, ok, nok) {
3479
3464
  return nok(code);
3480
3465
  }
3481
3466
  }
3482
- //#endregion
3483
- //#region node_modules/micromark-core-commonmark/lib/blank-line.js
3467
+ // node_modules/micromark-core-commonmark/lib/blank-line.js
3484
3468
  /**
3485
3469
  * @import {
3486
3470
  * Construct,
@@ -3536,8 +3520,7 @@ function tokenizeBlankLine(effects, ok, nok) {
3536
3520
  return code === null || markdownLineEnding(code) ? ok(code) : nok(code);
3537
3521
  }
3538
3522
  }
3539
- //#endregion
3540
- //#region node_modules/micromark-core-commonmark/lib/block-quote.js
3523
+ // node_modules/micromark-core-commonmark/lib/block-quote.js
3541
3524
  /**
3542
3525
  * @import {
3543
3526
  * Construct,
@@ -3663,8 +3646,7 @@ function tokenizeBlockQuoteContinuation(effects, ok, nok) {
3663
3646
  function exit(effects) {
3664
3647
  effects.exit("blockQuote");
3665
3648
  }
3666
- //#endregion
3667
- //#region node_modules/micromark-core-commonmark/lib/character-escape.js
3649
+ // node_modules/micromark-core-commonmark/lib/character-escape.js
3668
3650
  /**
3669
3651
  * @import {
3670
3652
  * Construct,
@@ -3723,8 +3705,7 @@ function tokenizeCharacterEscape(effects, ok, nok) {
3723
3705
  return nok(code);
3724
3706
  }
3725
3707
  }
3726
- //#endregion
3727
- //#region node_modules/micromark-core-commonmark/lib/character-reference.js
3708
+ // node_modules/micromark-core-commonmark/lib/character-reference.js
3728
3709
  /**
3729
3710
  * @import {
3730
3711
  * Code,
@@ -3861,8 +3842,7 @@ function tokenizeCharacterReference(effects, ok, nok) {
3861
3842
  return nok(code);
3862
3843
  }
3863
3844
  }
3864
- //#endregion
3865
- //#region node_modules/micromark-core-commonmark/lib/code-fenced.js
3845
+ // node_modules/micromark-core-commonmark/lib/code-fenced.js
3866
3846
  /**
3867
3847
  * @import {
3868
3848
  * Code,
@@ -4276,8 +4256,7 @@ function tokenizeNonLazyContinuation(effects, ok, nok) {
4276
4256
  return self.parser.lazy[self.now().line] ? nok(code) : ok(code);
4277
4257
  }
4278
4258
  }
4279
- //#endregion
4280
- //#region node_modules/micromark-core-commonmark/lib/code-indented.js
4259
+ // node_modules/micromark-core-commonmark/lib/code-indented.js
4281
4260
  /**
4282
4261
  * @import {
4283
4262
  * Construct,
@@ -4420,8 +4399,7 @@ function tokenizeFurtherStart(effects, ok, nok) {
4420
4399
  return tail && tail[1].type === "linePrefix" && tail[2].sliceSerialize(tail[1], true).length >= 4 ? ok(code) : markdownLineEnding(code) ? furtherStart(code) : nok(code);
4421
4400
  }
4422
4401
  }
4423
- //#endregion
4424
- //#region node_modules/micromark-core-commonmark/lib/code-text.js
4402
+ // node_modules/micromark-core-commonmark/lib/code-text.js
4425
4403
  /**
4426
4404
  * @import {
4427
4405
  * Construct,
@@ -4605,8 +4583,7 @@ function tokenizeCodeText(effects, ok, nok) {
4605
4583
  return data(code);
4606
4584
  }
4607
4585
  }
4608
- //#endregion
4609
- //#region node_modules/micromark-util-subtokenize/lib/splice-buffer.js
4586
+ // node_modules/micromark-util-subtokenize/lib/splice-buffer.js
4610
4587
  /**
4611
4588
  * Some of the internal operations of micromark do lots of editing
4612
4589
  * operations on very large arrays. This runs into problems with two
@@ -4835,8 +4812,7 @@ function chunkedPush(list, right) {
4835
4812
  chunkStart += 1e4;
4836
4813
  }
4837
4814
  }
4838
- //#endregion
4839
- //#region node_modules/micromark-util-subtokenize/index.js
4815
+ // node_modules/micromark-util-subtokenize/index.js
4840
4816
  /**
4841
4817
  * @import {Chunk, Event, Token} from 'micromark-util-types'
4842
4818
  */
@@ -4990,8 +4966,7 @@ function subcontent(events, eventIndex) {
4990
4966
  }
4991
4967
  return gaps;
4992
4968
  }
4993
- //#endregion
4994
- //#region node_modules/micromark-core-commonmark/lib/content.js
4969
+ // node_modules/micromark-core-commonmark/lib/content.js
4995
4970
  /**
4996
4971
  * @import {
4997
4972
  * Construct,
@@ -5123,8 +5098,7 @@ function tokenizeContinuation(effects, ok, nok) {
5123
5098
  return effects.interrupt(self.parser.constructs.flow, nok, ok)(code);
5124
5099
  }
5125
5100
  }
5126
- //#endregion
5127
- //#region node_modules/micromark-factory-destination/index.js
5101
+ // node_modules/micromark-factory-destination/index.js
5128
5102
  /**
5129
5103
  * @import {Effects, State, TokenType} from 'micromark-util-types'
5130
5104
  */
@@ -5307,8 +5281,7 @@ function factoryDestination(effects, ok, nok, type, literalType, literalMarkerTy
5307
5281
  return raw(code);
5308
5282
  }
5309
5283
  }
5310
- //#endregion
5311
- //#region node_modules/micromark-factory-label/index.js
5284
+ // node_modules/micromark-factory-label/index.js
5312
5285
  /**
5313
5286
  * @import {
5314
5287
  * Effects,
@@ -5383,7 +5356,9 @@ function factoryLabel(effects, ok, nok, type, markerType, stringType) {
5383
5356
  * @type {State}
5384
5357
  */
5385
5358
  function atBreak(code) {
5386
- if (size > 999 || code === null || code === 91 || code === 93 && !seen || code === 94 && !size && "_hiddenFootnoteSupport" in self.parser.constructs) return nok(code);
5359
+ if (size > 999 || code === null || code === 91 || code === 93 && !seen ||
5360
+ /* c8 ignore next 3 */
5361
+ code === 94 && !size && "_hiddenFootnoteSupport" in self.parser.constructs) return nok(code);
5387
5362
  if (code === 93) {
5388
5363
  effects.exit(stringType);
5389
5364
  effects.enter(markerType);
@@ -5439,8 +5414,7 @@ function factoryLabel(effects, ok, nok, type, markerType, stringType) {
5439
5414
  return labelInside(code);
5440
5415
  }
5441
5416
  }
5442
- //#endregion
5443
- //#region node_modules/micromark-factory-title/index.js
5417
+ // node_modules/micromark-factory-title/index.js
5444
5418
  /**
5445
5419
  * @import {
5446
5420
  * Code,
@@ -5584,8 +5558,7 @@ function factoryTitle(effects, ok, nok, type, markerType, stringType) {
5584
5558
  return inside(code);
5585
5559
  }
5586
5560
  }
5587
- //#endregion
5588
- //#region node_modules/micromark-factory-whitespace/index.js
5561
+ // node_modules/micromark-factory-whitespace/index.js
5589
5562
  /**
5590
5563
  * @import {Effects, State} from 'micromark-util-types'
5591
5564
  */
@@ -5624,8 +5597,7 @@ function factoryWhitespace(effects, ok) {
5624
5597
  return ok(code);
5625
5598
  }
5626
5599
  }
5627
- //#endregion
5628
- //#region node_modules/micromark-core-commonmark/lib/definition.js
5600
+ // node_modules/micromark-core-commonmark/lib/definition.js
5629
5601
  /**
5630
5602
  * @import {
5631
5603
  * Construct,
@@ -5839,8 +5811,7 @@ function tokenizeTitleBefore(effects, ok, nok) {
5839
5811
  return code === null || markdownLineEnding(code) ? ok(code) : nok(code);
5840
5812
  }
5841
5813
  }
5842
- //#endregion
5843
- //#region node_modules/micromark-core-commonmark/lib/hard-break-escape.js
5814
+ // node_modules/micromark-core-commonmark/lib/hard-break-escape.js
5844
5815
  /**
5845
5816
  * @import {
5846
5817
  * Construct,
@@ -5896,8 +5867,7 @@ function tokenizeHardBreakEscape(effects, ok, nok) {
5896
5867
  return nok(code);
5897
5868
  }
5898
5869
  }
5899
- //#endregion
5900
- //#region node_modules/micromark-core-commonmark/lib/heading-atx.js
5870
+ // node_modules/micromark-core-commonmark/lib/heading-atx.js
5901
5871
  /**
5902
5872
  * @import {
5903
5873
  * Construct,
@@ -6081,8 +6051,7 @@ function tokenizeHeadingAtx(effects, ok, nok) {
6081
6051
  return data;
6082
6052
  }
6083
6053
  }
6084
- //#endregion
6085
- //#region node_modules/micromark-util-html-tag-name/index.js
6054
+ // node_modules/micromark-util-html-tag-name/index.js
6086
6055
  /**
6087
6056
  * List of lowercase HTML “block” tag names.
6088
6057
  *
@@ -6180,8 +6149,7 @@ const htmlRawNames = [
6180
6149
  "style",
6181
6150
  "textarea"
6182
6151
  ];
6183
- //#endregion
6184
- //#region node_modules/micromark-core-commonmark/lib/html-flow.js
6152
+ // node_modules/micromark-core-commonmark/lib/html-flow.js
6185
6153
  /**
6186
6154
  * @import {
6187
6155
  * Code,
@@ -6953,8 +6921,7 @@ function tokenizeBlankLineBefore(effects, ok, nok) {
6953
6921
  return effects.attempt(blankLine, ok, nok);
6954
6922
  }
6955
6923
  }
6956
- //#endregion
6957
- //#region node_modules/micromark-core-commonmark/lib/html-text.js
6924
+ // node_modules/micromark-core-commonmark/lib/html-text.js
6958
6925
  /**
6959
6926
  * @import {
6960
6927
  * Code,
@@ -7567,8 +7534,7 @@ function tokenizeHtmlText(effects, ok, nok) {
7567
7534
  return returnState(code);
7568
7535
  }
7569
7536
  }
7570
- //#endregion
7571
- //#region node_modules/micromark-core-commonmark/lib/label-end.js
7537
+ // node_modules/micromark-core-commonmark/lib/label-end.js
7572
7538
  /**
7573
7539
  * @import {
7574
7540
  * Construct,
@@ -8037,8 +8003,7 @@ function tokenizeReferenceCollapsed(effects, ok, nok) {
8037
8003
  return nok(code);
8038
8004
  }
8039
8005
  }
8040
- //#endregion
8041
- //#region node_modules/micromark-core-commonmark/lib/label-start-image.js
8006
+ // node_modules/micromark-core-commonmark/lib/label-start-image.js
8042
8007
  /**
8043
8008
  * @import {
8044
8009
  * Construct,
@@ -8130,8 +8095,7 @@ function tokenizeLabelStartImage(effects, ok, nok) {
8130
8095
  return code === 94 && "_hiddenFootnoteSupport" in self.parser.constructs ? nok(code) : ok(code);
8131
8096
  }
8132
8097
  }
8133
- //#endregion
8134
- //#region node_modules/micromark-core-commonmark/lib/label-start-link.js
8098
+ // node_modules/micromark-core-commonmark/lib/label-start-link.js
8135
8099
  /**
8136
8100
  * @import {
8137
8101
  * Construct,
@@ -8178,8 +8142,7 @@ function tokenizeLabelStartLink(effects, ok, nok) {
8178
8142
  return code === 94 && "_hiddenFootnoteSupport" in self.parser.constructs ? nok(code) : ok(code);
8179
8143
  }
8180
8144
  }
8181
- //#endregion
8182
- //#region node_modules/micromark-core-commonmark/lib/line-ending.js
8145
+ // node_modules/micromark-core-commonmark/lib/line-ending.js
8183
8146
  /**
8184
8147
  * @import {
8185
8148
  * Construct,
@@ -8208,8 +8171,7 @@ function tokenizeLineEnding(effects, ok) {
8208
8171
  return factorySpace(effects, ok, "linePrefix");
8209
8172
  }
8210
8173
  }
8211
- //#endregion
8212
- //#region node_modules/micromark-core-commonmark/lib/thematic-break.js
8174
+ // node_modules/micromark-core-commonmark/lib/thematic-break.js
8213
8175
  /**
8214
8176
  * @import {
8215
8177
  * Code,
@@ -8303,8 +8265,7 @@ function tokenizeThematicBreak(effects, ok, nok) {
8303
8265
  return markdownSpace(code) ? factorySpace(effects, atBreak, "whitespace")(code) : atBreak(code);
8304
8266
  }
8305
8267
  }
8306
- //#endregion
8307
- //#region node_modules/micromark-core-commonmark/lib/list.js
8268
+ // node_modules/micromark-core-commonmark/lib/list.js
8308
8269
  /**
8309
8270
  * @import {
8310
8271
  * Code,
@@ -8475,8 +8436,7 @@ function tokenizeListItemPrefixWhitespace(effects, ok, nok) {
8475
8436
  return !markdownSpace(code) && tail && tail[1].type === "listItemPrefixWhitespace" ? ok(code) : nok(code);
8476
8437
  }
8477
8438
  }
8478
- //#endregion
8479
- //#region node_modules/micromark-core-commonmark/lib/setext-underline.js
8439
+ // node_modules/micromark-core-commonmark/lib/setext-underline.js
8480
8440
  /**
8481
8441
  * @import {
8482
8442
  * Code,
@@ -8627,8 +8587,7 @@ function tokenizeSetextUnderline(effects, ok, nok) {
8627
8587
  return nok(code);
8628
8588
  }
8629
8589
  }
8630
- //#endregion
8631
- //#region node_modules/micromark/lib/initialize/flow.js
8590
+ // node_modules/micromark/lib/initialize/flow.js
8632
8591
  /**
8633
8592
  * @import {
8634
8593
  * InitialConstruct,
@@ -8674,8 +8633,7 @@ function initializeFlow(effects) {
8674
8633
  return initial;
8675
8634
  }
8676
8635
  }
8677
- //#endregion
8678
- //#region node_modules/micromark/lib/initialize/text.js
8636
+ // node_modules/micromark/lib/initialize/text.js
8679
8637
  /**
8680
8638
  * @import {
8681
8639
  * Code,
@@ -8851,8 +8809,7 @@ function resolveAllLineSuffixes(events, context) {
8851
8809
  }
8852
8810
  return events;
8853
8811
  }
8854
- //#endregion
8855
- //#region node_modules/micromark/lib/constructs.js
8812
+ // node_modules/micromark/lib/constructs.js
8856
8813
  /**
8857
8814
  * @import {Extension} from 'micromark-util-types'
8858
8815
  */
@@ -8929,8 +8886,7 @@ const insideSpan = { null: [attention, resolver] };
8929
8886
  const attentionMarkers = { null: [42, 95] };
8930
8887
  /** @satisfies {Extension['disable']} */
8931
8888
  const disable = { null: [] };
8932
- //#endregion
8933
- //#region node_modules/micromark/lib/create-tokenizer.js
8889
+ // node_modules/micromark/lib/create-tokenizer.js
8934
8890
  /**
8935
8891
  * @import {
8936
8892
  * Chunk,
@@ -9398,8 +9354,7 @@ function serializeChunks(chunks, expandTabs) {
9398
9354
  }
9399
9355
  return result.join("");
9400
9356
  }
9401
- //#endregion
9402
- //#region node_modules/micromark/lib/parse.js
9357
+ // node_modules/micromark/lib/parse.js
9403
9358
  /**
9404
9359
  * @import {
9405
9360
  * Create,
@@ -9442,8 +9397,7 @@ function parse$1(options) {
9442
9397
  }
9443
9398
  }
9444
9399
  }
9445
- //#endregion
9446
- //#region node_modules/micromark/lib/postprocess.js
9400
+ // node_modules/micromark/lib/postprocess.js
9447
9401
  /**
9448
9402
  * @import {Event} from 'micromark-util-types'
9449
9403
  */
@@ -9457,8 +9411,7 @@ function postprocess(events) {
9457
9411
  while (!subtokenize(events));
9458
9412
  return events;
9459
9413
  }
9460
- //#endregion
9461
- //#region node_modules/micromark/lib/preprocess.js
9414
+ // node_modules/micromark/lib/preprocess.js
9462
9415
  /**
9463
9416
  * @import {Chunk, Code, Encoding, Value} from 'micromark-util-types'
9464
9417
  */
@@ -9558,8 +9511,7 @@ function preprocess() {
9558
9511
  return chunks;
9559
9512
  }
9560
9513
  }
9561
- //#endregion
9562
- //#region node_modules/micromark-util-decode-string/index.js
9514
+ // node_modules/micromark-util-decode-string/index.js
9563
9515
  const characterEscapeOrReference = /\\([!-/:-@[-`{-~])|&(#(?:\d{1,7}|x[\da-f]{1,6})|[\da-z]{1,31});/gi;
9564
9516
  /**
9565
9517
  * Decode markdown strings (which occur in places such as fenced code info
@@ -9595,8 +9547,7 @@ function decode($0, $1, $2) {
9595
9547
  }
9596
9548
  return decodeNamedCharacterReference($2) || $0;
9597
9549
  }
9598
- //#endregion
9599
- //#region node_modules/unist-util-stringify-position/lib/index.js
9550
+ // node_modules/unist-util-stringify-position/lib/index.js
9600
9551
  /**
9601
9552
  * @typedef {import('unist').Node} Node
9602
9553
  * @typedef {import('unist').Point} Point
@@ -9659,8 +9610,7 @@ function position(pos) {
9659
9610
  function index(value) {
9660
9611
  return value && typeof value === "number" ? value : 1;
9661
9612
  }
9662
- //#endregion
9663
- //#region node_modules/mdast-util-from-markdown/lib/index.js
9613
+ // node_modules/mdast-util-from-markdown/lib/index.js
9664
9614
  /**
9665
9615
  * @import {
9666
9616
  * Break,
@@ -9875,8 +9825,10 @@ function compiler(options) {
9875
9825
  /** @type {Array<number>} */
9876
9826
  const listStack = [];
9877
9827
  let index = -1;
9878
- while (++index < events.length) if (events[index][1].type === "listOrdered" || events[index][1].type === "listUnordered") if (events[index][0] === "enter") listStack.push(index);
9879
- else index = prepareList(events, listStack.pop(), index);
9828
+ while (++index < events.length) if (events[index][1].type === "listOrdered" || events[index][1].type === "listUnordered") {
9829
+ if (events[index][0] === "enter") listStack.push(index);
9830
+ else index = prepareList(events, listStack.pop(), index);
9831
+ }
9880
9832
  index = -1;
9881
9833
  while (++index < events.length) {
9882
9834
  const handler = config[events[index][0]];
@@ -10066,8 +10018,10 @@ function compiler(options) {
10066
10018
  start: token.start,
10067
10019
  end: token.end
10068
10020
  }) + "): it’s not open");
10069
- else if (open[0].type !== token.type) if (onExitError) onExitError.call(this, token, open[0]);
10070
- else (open[1] || defaultOnError).call(this, token, open[0]);
10021
+ else if (open[0].type !== token.type) {
10022
+ if (onExitError) onExitError.call(this, token, open[0]);
10023
+ else (open[1] || defaultOnError).call(this, token, open[0]);
10024
+ }
10071
10025
  node.position.end = point(token.end);
10072
10026
  }
10073
10027
  /**
@@ -10625,8 +10579,7 @@ function defaultOnError(left, right) {
10625
10579
  end: right.end
10626
10580
  }) + ") is still open");
10627
10581
  }
10628
- //#endregion
10629
- //#region node_modules/ccount/index.js
10582
+ // node_modules/ccount/index.js
10630
10583
  /**
10631
10584
  * Count how often a character (or substring) is used in a string.
10632
10585
  *
@@ -10648,14 +10601,12 @@ function ccount(value, character) {
10648
10601
  }
10649
10602
  return count;
10650
10603
  }
10651
- //#endregion
10652
- //#region node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp/index.js
10604
+ // node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp/index.js
10653
10605
  function escapeStringRegexp(string) {
10654
10606
  if (typeof string !== "string") throw new TypeError("Expected a string");
10655
10607
  return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
10656
10608
  }
10657
- //#endregion
10658
- //#region node_modules/unist-util-is/lib/index.js
10609
+ // node_modules/unist-util-is/lib/index.js
10659
10610
  /**
10660
10611
  * Generate an assertion from a test.
10661
10612
  *
@@ -10768,8 +10719,7 @@ function ok() {
10768
10719
  function looksLikeANode(value) {
10769
10720
  return value !== null && typeof value === "object" && "type" in value;
10770
10721
  }
10771
- //#endregion
10772
- //#region node_modules/unist-util-visit-parents/lib/color.node.js
10722
+ // node_modules/unist-util-visit-parents/lib/color.node.js
10773
10723
  /**
10774
10724
  * @param {string} d
10775
10725
  * @returns {string}
@@ -10777,8 +10727,7 @@ function looksLikeANode(value) {
10777
10727
  function color(d) {
10778
10728
  return "\x1B[33m" + d + "\x1B[39m";
10779
10729
  }
10780
- //#endregion
10781
- //#region node_modules/unist-util-visit-parents/lib/index.js
10730
+ // node_modules/unist-util-visit-parents/lib/index.js
10782
10731
  /**
10783
10732
  * @import {Node as UnistNode, Parent as UnistParent} from 'unist'
10784
10733
  */
@@ -11098,8 +11047,7 @@ function toResult(value) {
11098
11047
  if (typeof value === "number") return [true, value];
11099
11048
  return value === null || value === void 0 ? empty : [value];
11100
11049
  }
11101
- //#endregion
11102
- //#region node_modules/mdast-util-find-and-replace/lib/index.js
11050
+ // node_modules/mdast-util-find-and-replace/lib/index.js
11103
11051
  /**
11104
11052
  * @import {Nodes, Parents, PhrasingContent, Root, Text} from 'mdast'
11105
11053
  * @import {BuildVisitor, Test, VisitorResult} from 'unist-util-visit-parents'
@@ -11293,8 +11241,7 @@ function toFunction(replace) {
11293
11241
  return replace;
11294
11242
  };
11295
11243
  }
11296
- //#endregion
11297
- //#region node_modules/mdast-util-gfm-autolink-literal/lib/index.js
11244
+ // node_modules/mdast-util-gfm-autolink-literal/lib/index.js
11298
11245
  /**
11299
11246
  * @import {RegExpMatchObject, ReplaceFunction} from 'mdast-util-find-and-replace'
11300
11247
  * @import {CompileContext, Extension as FromMarkdownExtension, Handle as FromMarkdownHandle, Transform as FromMarkdownTransform} from 'mdast-util-from-markdown'
@@ -11473,8 +11420,7 @@ function previous(match, email) {
11473
11420
  const code = match.input.charCodeAt(match.index - 1);
11474
11421
  return (match.index === 0 || unicodeWhitespace(code) || unicodePunctuation(code)) && (!email || code !== 47);
11475
11422
  }
11476
- //#endregion
11477
- //#region node_modules/mdast-util-gfm-footnote/lib/index.js
11423
+ // node_modules/mdast-util-gfm-footnote/lib/index.js
11478
11424
  /**
11479
11425
  * @import {
11480
11426
  * CompileContext,
@@ -11608,8 +11554,7 @@ function gfmFootnoteFromMarkdown() {
11608
11554
  }
11609
11555
  };
11610
11556
  }
11611
- //#endregion
11612
- //#region node_modules/mdast-util-gfm-strikethrough/lib/index.js
11557
+ // node_modules/mdast-util-gfm-strikethrough/lib/index.js
11613
11558
  handleDelete.attention = attentionDelete;
11614
11559
  handleDelete.peek = peekDelete;
11615
11560
  /**
@@ -11689,8 +11634,7 @@ function attentionDelete() {
11689
11634
  function peekDelete() {
11690
11635
  return "~";
11691
11636
  }
11692
- //#endregion
11693
- //#region node_modules/mdast-util-gfm-task-list-item/lib/index.js
11637
+ // node_modules/mdast-util-gfm-task-list-item/lib/index.js
11694
11638
  /**
11695
11639
  * @typedef {import('mdast').ListItem} ListItem
11696
11640
  * @typedef {import('mdast').Paragraph} Paragraph
@@ -11758,8 +11702,7 @@ function exitParagraphWithTaskListItem(token) {
11758
11702
  }
11759
11703
  this.exit(token);
11760
11704
  }
11761
- //#endregion
11762
- //#region node_modules/micromark-extension-gfm-autolink-literal/lib/syntax.js
11705
+ // node_modules/micromark-extension-gfm-autolink-literal/lib/syntax.js
11763
11706
  /**
11764
11707
  * @import {Code, ConstructRecord, Event, Extension, Previous, State, TokenizeContext, Tokenizer} from 'micromark-util-types'
11765
11708
  */
@@ -12459,8 +12402,7 @@ function previousUnbalanced(events) {
12459
12402
  if (events.length > 0 && !result) events[events.length - 1][1]._gfmAutolinkLiteralWalkedInto = true;
12460
12403
  return result;
12461
12404
  }
12462
- //#endregion
12463
- //#region node_modules/micromark-extension-gfm-footnote/lib/syntax.js
12405
+ // node_modules/micromark-extension-gfm-footnote/lib/syntax.js
12464
12406
  /**
12465
12407
  * @import {Event, Exiter, Extension, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types'
12466
12408
  */
@@ -12878,8 +12820,7 @@ function tokenizeIndent(effects, ok, nok) {
12878
12820
  return tail && tail[1].type === "gfmFootnoteDefinitionIndent" && tail[2].sliceSerialize(tail[1], true).length === 4 ? ok(code) : nok(code);
12879
12821
  }
12880
12822
  }
12881
- //#endregion
12882
- //#region node_modules/micromark-extension-gfm-strikethrough/lib/syntax.js
12823
+ // node_modules/micromark-extension-gfm-strikethrough/lib/syntax.js
12883
12824
  /**
12884
12825
  * @import {Options} from 'micromark-extension-gfm-strikethrough'
12885
12826
  * @import {Event, Extension, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types'
@@ -13019,8 +12960,7 @@ function gfmStrikethrough(options) {
13019
12960
  }
13020
12961
  }
13021
12962
  }
13022
- //#endregion
13023
- //#region node_modules/micromark-extension-gfm-task-list-item/lib/syntax.js
12963
+ // node_modules/micromark-extension-gfm-task-list-item/lib/syntax.js
13024
12964
  /**
13025
12965
  * @import {Extension, State, TokenizeContext, Tokenizer} from 'micromark-util-types'
13026
12966
  */
@@ -13138,8 +13078,7 @@ function spaceThenNonSpace(effects, ok, nok) {
13138
13078
  return code === null ? nok(code) : ok(code);
13139
13079
  }
13140
13080
  }
13141
- //#endregion
13142
- //#region src/steering/MarkdownTree.ts
13081
+ // src/steering/MarkdownTree.ts
13143
13082
  /**
13144
13083
  * How many times `parseMarkdown` has actually run `fromMarkdown` (memo hits
13145
13084
  * excluded) — the only way "one parse per document" is assertable, since
@@ -13339,12 +13278,10 @@ const headingSectionBodies = (content, depth = 2) => {
13339
13278
  const headingSections = (content, depth = 2) => {
13340
13279
  return parseMarkdown(content).children.filter((node) => node.type === "heading" && node.depth === depth).map((heading) => headingText$1(content, heading));
13341
13280
  };
13342
- //#endregion
13343
- //#region src/steering/Eol.ts
13281
+ // src/steering/Eol.ts
13344
13282
  /** The document's own newline style, so a splice into a CRLF file never introduces a bare `\n`. */
13345
13283
  const eolOf = (content) => content.includes("\r\n") ? "\r\n" : "\n";
13346
- //#endregion
13347
- //#region src/steering/Threads.ts
13284
+ // src/steering/Threads.ts
13348
13285
  const PREFIX_RE$1 = /^(H|A):\s*/;
13349
13286
  const lineOf$1 = (node, which) => toLspPosition(node.position[which]).line;
13350
13287
  /** The item's own blocks joined — never the item node's span, which can run past its last line into the next bullet's marker. */
@@ -13430,8 +13367,7 @@ const collectThreads = (content, tree, markers) => {
13430
13367
  findings
13431
13368
  };
13432
13369
  };
13433
- //#endregion
13434
- //#region src/steering/Footnotes.ts
13370
+ // src/steering/Footnotes.ts
13435
13371
  /** The footnote-addition action's title — the ONE shared literal `qa`/`review` offer it under and `src/lsp/Lsp.ts` matches to compute the reveal position. A drifted copy in any one place silently breaks the cursor jump without failing a single test, so this constant is the only place the string is spelled. */
13436
13372
  const FOOTNOTE_ACTION_TITLE = "gtd: add a footnote";
13437
13373
  /** The thread-reply action's title — shared with `src/lsp/Lsp.ts` for the same reason as `FOOTNOTE_ACTION_TITLE`. */
@@ -13918,8 +13854,7 @@ const threadReplyActions = (content, position) => {
13918
13854
  }]
13919
13855
  }];
13920
13856
  };
13921
- //#endregion
13922
- //#region src/steering/Inline.ts
13857
+ // src/steering/Inline.ts
13923
13858
  /**
13924
13859
  * A `link`'s `href`/an `image`'s `src` passes only when it carries NO scheme
13925
13860
  * at all (relative, `./src/x.ts#42`, a bare fragment) or a scheme matching
@@ -14084,8 +14019,7 @@ const joinInlineRuns = (runs) => {
14084
14019
  });
14085
14020
  return result;
14086
14021
  };
14087
- //#endregion
14088
- //#region src/steering/Blocks.ts
14022
+ // src/steering/Blocks.ts
14089
14023
  /** A footnote marker as plain text, stripped out of every extracted title below. */
14090
14024
  const MARKER_TEXT_RE$1 = /\[\^([^\s\]]+)\]/g;
14091
14025
  const stripMarkerText$1 = (text) => text.replace(MARKER_TEXT_RE$1, "");
@@ -14161,17 +14095,22 @@ const nodeInline = (content, node, options) => {
14161
14095
  }] : [];
14162
14096
  };
14163
14097
  /** One list item as a `BlockListItem`, recursing into a nested `list` child (there is at most one, CommonMark's own shape) as its own `items`. */
14164
- const blockListItemOf = (content, item) => {
14165
- const items = item.children.filter((c) => c.type === "list").flatMap((list) => blockListItemsOf(content, list.children));
14098
+ const blockListItemOf = (content, item, noteAt) => {
14099
+ const items = item.children.filter((c) => c.type === "list").flatMap((list) => blockListItemsOf(content, list.children, noteAt));
14100
+ const line = item.position === void 0 ? void 0 : toLspPosition(item.position.start).line;
14166
14101
  return {
14167
14102
  text: listItemText(content, item),
14168
14103
  inline: listItemInline(content, item),
14169
14104
  ...item.checked === true || item.checked === false ? { checked: item.checked } : {},
14170
- ...items.length > 0 ? { items } : {}
14105
+ ...items.length > 0 ? { items } : {},
14106
+ ...line === void 0 ? {} : {
14107
+ line,
14108
+ ...noteAt(line)
14109
+ }
14171
14110
  };
14172
14111
  };
14173
14112
  /** Every item of a `list` node's own `children`, as `BlockListItem`s, in document order. */
14174
- const blockListItemsOf = (content, items) => items.map((item) => blockListItemOf(content, item));
14113
+ const blockListItemsOf = (content, items, noteAt) => items.map((item) => blockListItemOf(content, item, noteAt));
14175
14114
  /** The `title` an empty fenced code block (a `` ``` ``/`` ``` `` pair with nothing between them) falls back to — its real body is `""`, and every node still carries a non-empty title. */
14176
14115
  const EMPTY_CODE_BLOCK_TITLE = "(empty code block)";
14177
14116
  /** A `list`'s children with `options.skipListItem` removed. Filtering, never dropping the whole node: `qa`'s option items share a list with ordinary body bullets. */
@@ -14198,7 +14137,7 @@ const blockTitle = (content, node, options) => {
14198
14137
  * renders via `title` alone. `code`'s `text` is `node.value` VERBATIM,
14199
14138
  * leading whitespace intact, unlike every other kind's collapsed `title`.
14200
14139
  */
14201
- const blockOf = (content, node, options) => {
14140
+ const blockOf = (content, node, noteAt, options) => {
14202
14141
  switch (node.type) {
14203
14142
  case "heading": return {
14204
14143
  kind: "heading",
@@ -14208,7 +14147,7 @@ const blockOf = (content, node, options) => {
14208
14147
  case "list": return {
14209
14148
  kind: "list",
14210
14149
  ordered: node.ordered === true,
14211
- items: blockListItemsOf(content, visibleListItems(node, options))
14150
+ items: blockListItemsOf(content, visibleListItems(node, options), noteAt)
14212
14151
  };
14213
14152
  case "code": return {
14214
14153
  kind: "code",
@@ -14253,7 +14192,7 @@ const blockNodesOfRun = (content, nodes, options) => {
14253
14192
  const noteAt = noteLookup(content, options?.footnotes);
14254
14193
  return visibleNodes(content, nodes, options).map((node) => {
14255
14194
  const startLine = toLspPosition(node.position.start).line;
14256
- const block = blockOf(content, node, options);
14195
+ const block = blockOf(content, node, noteAt, options);
14257
14196
  return {
14258
14197
  title: blockTitle(content, node, options),
14259
14198
  anchor: {
@@ -14277,10 +14216,10 @@ const blockNodesOf = (content, tree, options) => blockNodesOfRun(content, tree.c
14277
14216
  * compact-row rule (R2) applies `Inline.ts#collapseImages` to the result.
14278
14217
  */
14279
14218
  const blockRunInline = (content, nodes, options) => {
14280
- return joinInlineRuns(visibleNodes(content, nodes, options).map((node) => nodeInline(content, node, options)));
14219
+ const filtered = visibleNodes(content, nodes, options);
14220
+ return joinInlineRuns(filtered.map((node) => nodeInline(content, node, options)));
14281
14221
  };
14282
- //#endregion
14283
- //#region src/steering/findings.ts
14222
+ // src/steering/findings.ts
14284
14223
  /** The `# ` heading the findings a judge called noise sit under. */
14285
14224
  const NOISE_HEADING = "Dropped as noise";
14286
14225
  /** The label of the one box under each finding. */
@@ -14523,8 +14462,7 @@ Why the judge dropped it.
14523
14462
  clearTicks: (content) => content,
14524
14463
  openThreads: openThreadsOf
14525
14464
  };
14526
- //#endregion
14527
- //#region src/steering/qa.ts
14465
+ // src/steering/qa.ts
14528
14466
  /**
14529
14467
  * A marker as plain text. Local to this module because `headingText`/
14530
14468
  * `optionText` extract text that is NOT a full node's tree span, which
@@ -14699,7 +14637,8 @@ const optionText = (content, item) => {
14699
14637
  */
14700
14638
  const optionBodyNodes = (content, item, footnotes) => {
14701
14639
  const labelParagraph = item.children.find((c) => c.type === "paragraph");
14702
- return blockNodesOfRun(content, item.children.filter((c) => c !== labelParagraph), { footnotes });
14640
+ const rest = item.children.filter((c) => c !== labelParagraph);
14641
+ return blockNodesOfRun(content, rest, { footnotes });
14703
14642
  };
14704
14643
  /** Extracts the checkbox options from a question block's body, in document order. */
14705
14644
  const parseOptions = (content, body, footnotes) => {
@@ -14977,7 +14916,8 @@ const unansweredQuestions$1 = (content) => parseOpenQuestions(content).questions
14977
14916
  * than by `indexOf("[")`, which text containing its own `[` would mislead.
14978
14917
  */
14979
14918
  const toggleCheckbox = (content, line) => {
14980
- const item = taskItems(parseMarkdown(content)).find((it) => toLspPosition(it.position.start).line === line);
14919
+ const tree = parseMarkdown(content);
14920
+ const item = taskItems(tree).find((it) => toLspPosition(it.position.start).line === line);
14981
14921
  if (!item?.position) return void 0;
14982
14922
  const startOffset = item.position.start.offset;
14983
14923
  const boundOffset = optionContentOffset(item) ?? item.position.end.offset;
@@ -15104,7 +15044,7 @@ const replaceOptionTextEdit = (content, item, text) => {
15104
15044
  * Collapses a typed answer to the single-line shape a list-item label must
15105
15045
  * be. A raw textarea value's interior newlines would break `.gtd/`'s oxfmt
15106
15046
  * fixed point the moment they are spliced onto a `- [x] ` line, and every
15107
- * steering file — server-written ones included — is covered by `format:check`.
15047
+ * steering file — server-written ones included — is covered by the `check` task.
15108
15048
  */
15109
15049
  /**
15110
15050
  * Empty normalizes to `FREE_TEXT_PLACEHOLDER`, never `""`: an empty label
@@ -15132,7 +15072,8 @@ const questionsApply = (content, anchor, opts) => {
15132
15072
  const checked = opts.checked ?? true;
15133
15073
  const edits = setOptionCheckedEdits(content, question, option, checked);
15134
15074
  if (opts.text !== void 0) {
15135
- const item = taskItems(parseMarkdown(content)).find((it) => toLspPosition(it.position.start).line === option.sourceLine);
15075
+ const tree = parseMarkdown(content);
15076
+ const item = taskItems(tree).find((it) => toLspPosition(it.position.start).line === option.sourceLine);
15136
15077
  const textEdit = item ? replaceOptionTextEdit(content, item, normalizeFreeTextAnswer(opts.text)) : void 0;
15137
15078
  if (textEdit) edits.push(textEdit);
15138
15079
  }
@@ -15327,8 +15268,7 @@ const qaDescriptor = {
15327
15268
  unansweredQuestions: unansweredQuestions$1,
15328
15269
  openThreads: openThreadsOf
15329
15270
  };
15330
- //#endregion
15331
- //#region src/steering/review.ts
15271
+ // src/steering/review.ts
15332
15272
  const ANSWER_LEAD = "Tick exactly one:";
15333
15273
  const ANSWER_FIX = "fix as suggested";
15334
15274
  const ANSWER_WONT_FIX = "won't fix";
@@ -15478,7 +15418,7 @@ const stripLeadingSeparatorInline = (nodes) => {
15478
15418
  /** `paragraph`'s own inline content strictly AFTER raw source offset `afterOffset` — the structural counterpart of `restOfParagraph`'s string slice: keeps every child entirely past the cut, trims the one child that straddles it (only when it's plain `text`; a straddling non-text child is dropped, the one edge case a token followed immediately by styled text hits), and trims the result's own leading whitespace. `undefined`/`[]` for anything that isn't a real `paragraph`. */
15479
15419
  const trailingParagraphInline = (content, paragraph, afterOffset) => {
15480
15420
  if (paragraph.type !== "paragraph") return [];
15481
- const projected = projectInline(paragraph.children.flatMap((child) => {
15421
+ const kept = paragraph.children.flatMap((child) => {
15482
15422
  const start = child.position?.start.offset;
15483
15423
  const end = child.position?.end.offset;
15484
15424
  if (start === void 0 || end === void 0 || end <= afterOffset) return [];
@@ -15488,7 +15428,8 @@ const trailingParagraphInline = (content, paragraph, afterOffset) => {
15488
15428
  ...child,
15489
15429
  value: child.value.slice(afterOffset - start)
15490
15430
  }];
15491
- }), definitionsOf(content));
15431
+ });
15432
+ const projected = projectInline(kept, definitionsOf(content));
15492
15433
  const first = projected[0];
15493
15434
  if (first === void 0 || first.kind !== "text") return projected;
15494
15435
  return [{
@@ -15499,7 +15440,8 @@ const trailingParagraphInline = (content, paragraph, afterOffset) => {
15499
15440
  /** `note`'s own inline counterpart, mirroring `hunkNote` structurally: `paragraph`'s own trailing inline content (past the pointer token) first, then every further sibling block's own `nodeInline`-equivalent projection, joined and image-collapsed (R2). `tokenEndOffset` is the raw source offset right after the pointer token itself. */
15500
15441
  const hunkNoteInline = (content, item, paragraph, tokenEndOffset) => {
15501
15442
  const otherChildren = item.children.filter((c) => c !== paragraph && c.type !== "list" && c.type !== "footnoteDefinition");
15502
- return collapseImages(joinInlineRuns([stripLeadingSeparatorInline(trailingParagraphInline(content, paragraph, tokenEndOffset)), ...otherChildren.map((c) => stripLeadingSeparatorInline(blockRunInline(content, [c])))]));
15443
+ const runs = [stripLeadingSeparatorInline(trailingParagraphInline(content, paragraph, tokenEndOffset)), ...otherChildren.map((c) => stripLeadingSeparatorInline(blockRunInline(content, [c])))];
15444
+ return collapseImages(joinInlineRuns(runs));
15503
15445
  };
15504
15446
  /** The last line of a hunk's OWN span — every non-`list` child's own end line, at most — excluding a nested hunk's span entirely, so a parent's span never swallows it (for "add a footnote" placement, or for matching which hunk a cursor sits on). */
15505
15447
  const hunkOwnEndLine = (item, sourceLine) => {
@@ -15848,7 +15790,8 @@ const reviewClearTicks = (content) => {
15848
15790
  };
15849
15791
  /** Flips the `[ ]`/`[x]` box of the hunk pointer task item starting at `line`, preserving path/note text exactly. `undefined` when `line` isn't a real task item's own start line, or its content isn't a valid hunk pointer. */
15850
15792
  const toggleFilePointer = (content, line) => {
15851
- const item = taskItems(parseMarkdown(content)).find((it) => toLspPosition(it.position.start).line === line);
15793
+ const tree = parseMarkdown(content);
15794
+ const item = taskItems(tree).find((it) => toLspPosition(it.position.start).line === line);
15852
15795
  if (!item?.position) return void 0;
15853
15796
  const paragraph = item.children.find((c) => c.type === "paragraph");
15854
15797
  const firstWord = paragraph ? sourceText(content, paragraph).split(/\s+/)[0] : void 0;
@@ -16451,8 +16394,7 @@ const reviewSections = (content) => splitChunks(parseMarkdown(content), content)
16451
16394
  section: s.section,
16452
16395
  line: s.headingLine
16453
16396
  }));
16454
- //#endregion
16455
- //#region src/steering/Edits.ts
16397
+ // src/steering/Edits.ts
16456
16398
  /** Splices `edits` into `content`, sorted last-to-first so an earlier range's offset is never invalidated by a later edit. Positions are 0-based line/character over `\n`-split lines. */
16457
16399
  const applySteeringEdits = (content, edits) => {
16458
16400
  const lines = content.split("\n");
@@ -16466,8 +16408,7 @@ const applySteeringEdits = (content, edits) => {
16466
16408
  for (const edit of sorted) result = result.slice(0, toOffset(edit.range.start)) + edit.newText + result.slice(toOffset(edit.range.end));
16467
16409
  return result;
16468
16410
  };
16469
- //#endregion
16470
- //#region src/steering/freeform.ts
16411
+ // src/steering/freeform.ts
16471
16412
  const FREE_FORM_SAMPLE = `Sample plan. Add a thing.
16472
16413
 
16473
16414
  ## Notes
@@ -16545,6 +16486,58 @@ const appendEdit = (content, text) => {
16545
16486
  const newText = trimmed.length > 0 ? `${trimmed}${eol}${eol}${normalizedText}${eol}` : `${normalizedText}${eol}`;
16546
16487
  return wholeDocumentEdit(content, newText);
16547
16488
  };
16489
+ /** Every task-list item with its sibling task items (direct children of one list only). */
16490
+ const taskGroups = (node, out) => {
16491
+ const n = node;
16492
+ if (n.type === "list") out.push(n.children.filter((i) => i.checked === true || i.checked === false));
16493
+ for (const c of n.children ?? []) taskGroups(c, out);
16494
+ };
16495
+ /** The box sits on the first child's line, which is not the marker line when a bare `-` precedes it. */
16496
+ const boxEdit = (lines, item, newText) => {
16497
+ const line = toLspPosition((item.children[0]?.position ?? item.position).start).line;
16498
+ const m = /\[( |x|X)\]/.exec(lines[line] ?? "");
16499
+ if (!m) return void 0;
16500
+ const c = m.index + 1;
16501
+ return {
16502
+ range: {
16503
+ start: {
16504
+ line,
16505
+ character: c
16506
+ },
16507
+ end: {
16508
+ line,
16509
+ character: c + 1
16510
+ }
16511
+ },
16512
+ newText
16513
+ };
16514
+ };
16515
+ /** Pick-one tick: sets the box on `line` and unticks its ticked siblings, in one edit set. Ticking an already-ticked box is an empty edit set. */
16516
+ const tickEdits = (content, line) => {
16517
+ const lines = content.split("\n");
16518
+ const groups = [];
16519
+ taskGroups(parseMarkdown(content), groups);
16520
+ const startLine = (i) => toLspPosition(i.position.start).line;
16521
+ const group = groups.find((g) => g.some((i) => startLine(i) === line));
16522
+ if (!group) return {
16523
+ ok: false,
16524
+ reason: "anchor-not-found"
16525
+ };
16526
+ const target = group.find((i) => startLine(i) === line);
16527
+ if (target.checked === true) return {
16528
+ ok: true,
16529
+ edits: []
16530
+ };
16531
+ const edits = group.filter((i) => i === target || i.checked === true).map((i) => boxEdit(lines, i, i === target ? "x" : " "));
16532
+ if (edits.some((e) => e === void 0)) return {
16533
+ ok: false,
16534
+ reason: "anchor-not-found"
16535
+ };
16536
+ return {
16537
+ ok: true,
16538
+ edits
16539
+ };
16540
+ };
16548
16541
  /**
16549
16542
  * Free-form's `apply`: only a `paragraph` anchor resolves (the only kind
16550
16543
  * `view` ever reports), and it only ever APPENDS, at or past the document's
@@ -16559,6 +16552,11 @@ const freeFormApply = (content, anchor, opts) => {
16559
16552
  ok: false,
16560
16553
  reason: "anchor-not-found"
16561
16554
  };
16555
+ if (opts.checked === true) return tickEdits(content, anchor.line);
16556
+ if (opts.checked === false) return {
16557
+ ok: false,
16558
+ reason: "pick-never-clears"
16559
+ };
16562
16560
  const text = opts.text ?? "";
16563
16561
  const tree = parseMarkdown(content);
16564
16562
  const lastLineIndex = content.split(/\r?\n/).length - 1;
@@ -16577,7 +16575,8 @@ const freeFormApply = (content, anchor, opts) => {
16577
16575
  };
16578
16576
  /** Free-form's `view`: every top-level block, in document order — no format-specific structure (no questions, no chunks) to project beyond the shared block walk. */
16579
16577
  const freeFormView = (content) => {
16580
- return { nodes: blockNodesOf(content, parseMarkdown(content)) };
16578
+ const tree = parseMarkdown(content);
16579
+ return { nodes: blockNodesOf(content, tree) };
16581
16580
  };
16582
16581
  /**
16583
16582
  * The free-form `SteeringFormat`: no structure to validate, outline, or
@@ -16599,8 +16598,7 @@ const freeFormFormat = {
16599
16598
  apply: freeFormApply,
16600
16599
  clearTicks: (content) => content
16601
16600
  };
16602
- //#endregion
16603
- //#region src/steering/Declared.ts
16601
+ // src/steering/Declared.ts
16604
16602
  const FENCE_RE = /^( *)(`{3,}|~{3,})/;
16605
16603
  const HEADING_RE = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?(?:[ \t]+#+)?[ \t]*$/;
16606
16604
  const ITEM_RE = /^( *)([-*+]|\d{1,9}[.)])(?:[ \t]+(.*))?$/;
@@ -17019,8 +17017,7 @@ const formatFromSpec = (spec) => {
17019
17017
  if (kind === "section") return sectionFormat(rest);
17020
17018
  throw new Error(`not a declared format spec: ${JSON.stringify(kind)}`);
17021
17019
  };
17022
- //#endregion
17023
- //#region src/steering/registry.ts
17020
+ // src/steering/registry.ts
17024
17021
  /** The built-in registry: mode name → its format, in registry order. The single place the built-in formats are wired into names — everything else in this module dispatches over a resolved `SteeringFormat`, never a mode-name string. */
17025
17022
  const REGISTRY = /* @__PURE__ */ new Map([
17026
17023
  ["qa", qaDescriptor],
@@ -17045,8 +17042,7 @@ const steeringFormatFor = (mode) => REGISTRY.get(mode);
17045
17042
  const unansweredQuestions = (format, content) => format.unansweredQuestions?.(content) ?? [];
17046
17043
  /** Every OPEN thread — last entry is the agent's — as `{ name, line, firstMe }` (0-based line). `[]` for a format with no thread concept. */
17047
17044
  const openThreads = (format, content) => format.openThreads?.(content) ?? [];
17048
- //#endregion
17049
- //#region src/steering/reads.ts
17045
+ // src/steering/reads.ts
17050
17046
  /** The top-level `## ` heading texts of markdown `text`. */
17051
17047
  const sections = (text) => headingSections(text);
17052
17048
  /** The top-level `## ` sections of markdown `text`, each with its own markdown, its heading line included. */
@@ -17066,8 +17062,7 @@ const threads = (text) => {
17066
17062
  faults: findings.filter((f) => f.message.startsWith(`Footnote thread "[^${t.name}]": `)).map((f) => f.message)
17067
17063
  }));
17068
17064
  };
17069
- //#endregion
17070
- //#region src/steering/CodeThreads.ts
17065
+ // src/steering/CodeThreads.ts
17071
17066
  const TOKENS = [
17072
17067
  "//",
17073
17068
  "#",
@@ -17246,5 +17241,4 @@ const stripCodeThreads = (path, text) => {
17246
17241
  for (const run of runsOf(lines.map((l) => l.replace(/\r$/, "")), tokens).filter(isThreadRun)) for (let i = run.start; i <= run.end; i++) drop.add(i);
17247
17242
  return lines.filter((_, i) => !drop.has(i)).join("\n");
17248
17243
  };
17249
- //#endregion
17250
17244
  export { findingEntries as A, reviewRisks as C, isAnswered as D, FREE_TEXT_PLACEHOLDER as E, headingSectionBodies as F, formatFinding as I, parseFootnotes as M, parseThreads as N, FIX_BOX as O, parseThreadsWithFindings as P, reviewNotes as S, unansweredNotes as T, ANSWER_LEAD as _, sections as a, reviewChunks as b, openThreads as c, formatFromSpec as d, listFormat as f, ANSWER_FIX as g, applySteeringEdits as h, sectionBodies as i, openThreadFindings as j, NOISE_HEADING as k, steeringFormatFor as l, freeFormFormat as m, stripCodeThreads as n, threads as o, sectionFormat as p, openQuestions as r, BUILT_IN_MODE_NAMES as s, parseCodeThreads as t, unansweredQuestions as u, ANSWER_WONT_FIX as v, reviewSections as w, reviewDecisions as x, REVIEW_SECTIONS as y };