@stringsync/splates 0.0.0-stage → 0.0.45

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 (251) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -2
  3. package/acp-extensions.d.ts +82 -0
  4. package/add.d.ts +53 -0
  5. package/adherence.d.ts +49 -0
  6. package/age.d.ts +2 -0
  7. package/agent-connection.d.ts +171 -0
  8. package/agent-errors.d.ts +2 -0
  9. package/agent-process.d.ts +65 -0
  10. package/agent-stream.d.ts +91 -0
  11. package/agents.d.ts +15 -0
  12. package/artifact-room.d.ts +47 -0
  13. package/artifact-viewers.d.ts +6 -0
  14. package/artifact.d.ts +30 -0
  15. package/artifacts.d.ts +161 -0
  16. package/asked.d.ts +146 -0
  17. package/asked.js +7 -0
  18. package/assumed.d.ts +34 -0
  19. package/attach.d.ts +30 -0
  20. package/attachments.d.ts +43 -0
  21. package/baselines.d.ts +55 -0
  22. package/claim.d.ts +17 -0
  23. package/cloudflare-api.d.ts +25 -0
  24. package/cloudflare-error.d.ts +5 -0
  25. package/cloudflared-tunnel-provider.d.ts +27 -0
  26. package/codex-limits.d.ts +19 -0
  27. package/compaction.d.ts +17 -0
  28. package/config-source.d.ts +13 -0
  29. package/config.d.ts +98 -0
  30. package/config.js +7 -0
  31. package/conversation-archive.d.ts +6 -0
  32. package/conversation-background.d.ts +21 -0
  33. package/conversation-choice.d.ts +4 -0
  34. package/conversation-files.d.ts +51 -0
  35. package/conversation-given.d.ts +8 -0
  36. package/conversation-host.d.ts +102 -0
  37. package/conversation-listing.d.ts +15 -0
  38. package/conversation-log.d.ts +301 -0
  39. package/conversation-messages.d.ts +18 -0
  40. package/conversation-name.d.ts +28 -0
  41. package/conversation-options.d.ts +73 -0
  42. package/conversation-reference.d.ts +2 -0
  43. package/conversation-state.d.ts +472 -0
  44. package/conversation-turns.d.ts +115 -0
  45. package/conversation.d.ts +209 -0
  46. package/conversations.d.ts +140 -0
  47. package/coordinator-state.d.ts +28 -0
  48. package/creds.d.ts +123 -0
  49. package/darwin-temperature.d.ts +7 -0
  50. package/decided.d.ts +18 -0
  51. package/demo.d.ts +29 -0
  52. package/dev/api.d.ts +209 -0
  53. package/dev/assets.d.ts +24 -0
  54. package/dev/conversation-address.d.ts +47 -0
  55. package/dev/conversation-feed.d.ts +166 -0
  56. package/dev/live-stream.d.ts +29 -0
  57. package/dev/worker.d.ts +33 -0
  58. package/dev-access.d.ts +61 -0
  59. package/dev-artifacts.d.ts +22 -0
  60. package/dev-budgets.d.ts +18 -0
  61. package/dev-conversation-events.d.ts +39 -0
  62. package/dev-conversation-routes.d.ts +90 -0
  63. package/dev-creds.d.ts +17 -0
  64. package/dev-dictation-connection.d.ts +18 -0
  65. package/dev-dictation.d.ts +17 -0
  66. package/dev-http.d.ts +76 -0
  67. package/dev-open.d.ts +15 -0
  68. package/dev-options.d.ts +133 -0
  69. package/dev-outcomes.d.ts +21 -0
  70. package/dev-pages.d.ts +16 -0
  71. package/dev-picker.d.ts +57 -0
  72. package/dev-port-socket.d.ts +26 -0
  73. package/dev-ports.d.ts +11 -0
  74. package/dev-project-watch.d.ts +44 -0
  75. package/dev-project.d.ts +168 -0
  76. package/dev-push.d.ts +59 -0
  77. package/dev-restart.d.ts +141 -0
  78. package/dev-servers.d.ts +30 -0
  79. package/dev-setup-native.d.ts +23 -0
  80. package/dev-setup-opencode.d.ts +29 -0
  81. package/dev-setup.d.ts +16 -0
  82. package/dev-shell.d.ts +70 -0
  83. package/dev-slot.d.ts +28 -0
  84. package/dev-sockets.d.ts +13 -0
  85. package/dev-task-ports.d.ts +73 -0
  86. package/dev-tasks.d.ts +20 -0
  87. package/dev-terminal-connection.d.ts +19 -0
  88. package/dev-terminal.d.ts +42 -0
  89. package/dev-todos.d.ts +35 -0
  90. package/dev-transcriber.d.ts +15 -0
  91. package/dev-tunnel.d.ts +38 -0
  92. package/dev-versions.d.ts +53 -0
  93. package/dev-workers.d.ts +55 -0
  94. package/dev.d.ts +24 -0
  95. package/diff.d.ts +29 -0
  96. package/dispatched.d.ts +16 -0
  97. package/editors.d.ts +22 -0
  98. package/escalate.d.ts +27 -0
  99. package/events.d.ts +311 -0
  100. package/everywhere.d.ts +41 -0
  101. package/exhibit.d.ts +21 -0
  102. package/exit.d.ts +54 -0
  103. package/fact-todos.d.ts +18 -0
  104. package/fake-agent.d.ts +107 -0
  105. package/fake-agent.js +284 -0
  106. package/finding-facts.d.ts +38 -0
  107. package/findings.d.ts +84 -0
  108. package/fold.d.ts +43 -0
  109. package/follow.d.ts +41 -0
  110. package/format.d.ts +68 -0
  111. package/git.d.ts +112 -0
  112. package/handed-out.d.ts +79 -0
  113. package/handoff.d.ts +23 -0
  114. package/heavy-run.d.ts +12 -0
  115. package/heavy.d.ts +28 -0
  116. package/heavy.js +16 -0
  117. package/held.d.ts +22 -0
  118. package/index-0tfvy823.js +272 -0
  119. package/index-43pq33n4.js +157 -0
  120. package/index-4776671w.js +698 -0
  121. package/index-d4hjrzaq.js +464 -0
  122. package/index-gcfq7awr.js +740 -0
  123. package/index-k73tsw5g.js +101 -0
  124. package/index-kaa44k7q.js +59 -0
  125. package/index-vcv9m93e.js +1265 -0
  126. package/index-xmfmy729.js +249 -0
  127. package/index.d.ts +2 -0
  128. package/index.js +26928 -0
  129. package/init.d.ts +28 -0
  130. package/journal.d.ts +57 -0
  131. package/landed.d.ts +14 -0
  132. package/lane-todos.d.ts +44 -0
  133. package/lane.d.ts +55 -0
  134. package/lanes-from-tags.d.ts +17 -0
  135. package/lanes.d.ts +96 -0
  136. package/legacy-names.d.ts +70 -0
  137. package/legacy-ps.d.ts +31 -0
  138. package/limits.d.ts +32 -0
  139. package/list.d.ts +18 -0
  140. package/load-config.d.ts +44 -0
  141. package/log.d.ts +14 -0
  142. package/machine.d.ts +42 -0
  143. package/merge.d.ts +35 -0
  144. package/migrate-config.d.ts +31 -0
  145. package/models.d.ts +24 -0
  146. package/needs.d.ts +115 -0
  147. package/notices.d.ts +39 -0
  148. package/offered.d.ts +39 -0
  149. package/opencode-usage.d.ts +37 -0
  150. package/outcomes.d.ts +114 -0
  151. package/package.json +74 -5
  152. package/path.d.ts +13 -0
  153. package/plan.d.ts +236 -0
  154. package/port-forward.d.ts +22 -0
  155. package/port-pipe.d.ts +36 -0
  156. package/ports-list.d.ts +19 -0
  157. package/probe-runtime.d.ts +5 -0
  158. package/probe-runtime.js +13 -0
  159. package/project-reaches.d.ts +23 -0
  160. package/projects.d.ts +136 -0
  161. package/prompts.d.ts +128 -0
  162. package/pty.d.ts +39 -0
  163. package/pulse.d.ts +8 -0
  164. package/recommend.d.ts +31 -0
  165. package/release.d.ts +41 -0
  166. package/remote-process.d.ts +26 -0
  167. package/remote-pty.d.ts +29 -0
  168. package/remote-worker.d.ts +77 -0
  169. package/remove.d.ts +31 -0
  170. package/repository.d.ts +91 -0
  171. package/retry.d.ts +34 -0
  172. package/roster.d.ts +63 -0
  173. package/saved-ports-host.d.ts +25 -0
  174. package/saved-tunnel.d.ts +44 -0
  175. package/server-worker-socket.d.ts +21 -0
  176. package/setup-areas.d.ts +7 -0
  177. package/setup-opencode-model-error.d.ts +3 -0
  178. package/setup-opencode-models.d.ts +54 -0
  179. package/setup-opencode-recipe.d.ts +26 -0
  180. package/setup-opencode.d.ts +46 -0
  181. package/setup.d.ts +102 -0
  182. package/shared-browser.d.ts +50 -0
  183. package/shell.d.ts +17 -0
  184. package/show.d.ts +106 -0
  185. package/skill-checks.d.ts +73 -0
  186. package/skill-checks.js +10 -0
  187. package/skills.d.ts +16 -0
  188. package/slot-tunnel.d.ts +27 -0
  189. package/slots.d.ts +135 -0
  190. package/snapshot.d.ts +75 -0
  191. package/splates-artifact.d.ts +3 -0
  192. package/splates-creds.d.ts +3 -0
  193. package/splates-dev.d.ts +22 -0
  194. package/splates-flags.d.ts +34 -0
  195. package/splates-lane.d.ts +3 -0
  196. package/splates-projects.d.ts +3 -0
  197. package/splates-setup.d.ts +17 -0
  198. package/splates-slots.d.ts +3 -0
  199. package/splates-todo.d.ts +3 -0
  200. package/splates-tunnel.d.ts +3 -0
  201. package/splates-worker.d.ts +3 -0
  202. package/splates.d.ts +28 -0
  203. package/stats.d.ts +186 -0
  204. package/supervise.d.ts +50 -0
  205. package/system-changes.d.ts +67 -0
  206. package/system.d.ts +28 -0
  207. package/systems.d.ts +119 -0
  208. package/systems.js +21 -0
  209. package/table.d.ts +5 -0
  210. package/task-log.d.ts +35 -0
  211. package/task-ports.d.ts +25 -0
  212. package/tell.d.ts +47 -0
  213. package/todo-edit.d.ts +60 -0
  214. package/todo-file.d.ts +6 -0
  215. package/todo-lanes.d.ts +82 -0
  216. package/todo-list.d.ts +26 -0
  217. package/todo-take.d.ts +27 -0
  218. package/todo.d.ts +146 -0
  219. package/todos.d.ts +157 -0
  220. package/tool-calls.d.ts +18 -0
  221. package/tunnel-provider.d.ts +37 -0
  222. package/tunnel-provider.js +0 -0
  223. package/tunnel-remove.d.ts +28 -0
  224. package/tunnel-setup.d.ts +104 -0
  225. package/unix-worker-listener.d.ts +23 -0
  226. package/unix-worker-socket.d.ts +30 -0
  227. package/update.d.ts +29 -0
  228. package/update.js +10 -0
  229. package/vocabulary.d.ts +9 -0
  230. package/wait.d.ts +36 -0
  231. package/watch.d.ts +46 -0
  232. package/watched.d.ts +43 -0
  233. package/websocket-worker-socket.d.ts +18 -0
  234. package/worker-call-host.d.ts +51 -0
  235. package/worker-channel.d.ts +83 -0
  236. package/worker-connection.d.ts +24 -0
  237. package/worker-daemon.d.ts +64 -0
  238. package/worker-git.d.ts +18 -0
  239. package/worker-list.d.ts +49 -0
  240. package/worker-machine.d.ts +34 -0
  241. package/worker-port-host.d.ts +21 -0
  242. package/worker-process-host.d.ts +29 -0
  243. package/worker-protocol.d.ts +104 -0
  244. package/worker-pty-host.d.ts +34 -0
  245. package/worker-registry.d.ts +68 -0
  246. package/worker-replay.d.ts +25 -0
  247. package/worker-run.d.ts +20 -0
  248. package/worker-session.d.ts +189 -0
  249. package/worker-socket.d.ts +15 -0
  250. package/worktree-service.d.ts +113 -0
  251. package/worktree.d.ts +232 -0
@@ -0,0 +1,740 @@
1
+ import {
2
+ LEGACY_PLAN_FILE
3
+ } from "./index-k73tsw5g.js";
4
+
5
+ // exhibit.ts
6
+ var EXHIBIT = /^### 🖼️?[ \t]+(.+?)[ \t]*$/;
7
+ function exhibitTitle(line) {
8
+ return EXHIBIT.exec(line)?.[1] ?? null;
9
+ }
10
+
11
+ // plan.ts
12
+ import { Markdown } from "webappwiz/md";
13
+ var PLAN_FILE = "SPLATES.md";
14
+
15
+ class Plans {
16
+ fs;
17
+ constructor(fs) {
18
+ this.fs = fs;
19
+ }
20
+ read(tree) {
21
+ return this.fs.read(`${tree}/${PLAN_FILE}`).catch(() => this.fs.read(`${tree}/${LEGACY_PLAN_FILE}`)).catch(() => null);
22
+ }
23
+ async exclude(gitDir) {
24
+ const info = `${gitDir}/info`;
25
+ const excluded = await this.fs.read(`${info}/exclude`).catch(() => "");
26
+ if (!excluded.split(`
27
+ `).includes(PLAN_FILE)) {
28
+ await this.fs.mkdir(info);
29
+ await this.fs.write(`${info}/exclude`, `${excluded.trimEnd()}
30
+ ${PLAN_FILE}
31
+ `.trimStart());
32
+ }
33
+ }
34
+ }
35
+ var STUB_STEP = "fill in Goal and list the steps here as `- [ ]` items";
36
+ var SECTIONS = ["Goal", "Done", "Next", "Notes", "Assumptions", "Blocked"];
37
+ var REQUIRED = ["Goal", "Next"];
38
+ var UNCHECKED = /^[ \t]*- \[ \]/m;
39
+ var QUESTION = /^[ \t]*- \[[ xX]\] [Qq]?\d+\./m;
40
+ function goalLine(text) {
41
+ const md = Markdown.parse(text);
42
+ if (!md.has("Goal")) {
43
+ return null;
44
+ }
45
+ const line = md.section("Goal").body.split(`
46
+ `).find((line) => line.trim() !== "");
47
+ return line === undefined ? null : line.trim();
48
+ }
49
+ function goalOf(text) {
50
+ const md = Markdown.parse(text);
51
+ return md.has("Goal") ? md.section("Goal").body.trim() : "";
52
+ }
53
+ var ITEM = /^[ \t]*- \[([ xX])\] [Qq]?(\d+)\.[ \t]*(.*)$/;
54
+ var ARROW = " → ";
55
+ var FOLLOW_UP = /^[ \t]+→[ \t]+(.*)$/;
56
+ var CHOICE = /^([ \t]+)- (?:\(([a-z])\)|\[([a-z])\]|([a-z])\.)[ \t]+(.+?)[ \t]*$/;
57
+ var CHOSEN = /[ \t]*\(chosen\)$/i;
58
+ var SIZES = ["small", "medium", "large"];
59
+ var SIZE = /^\(([a-z]+)\)[ \t]+/;
60
+ function sized(text) {
61
+ const size = SIZE.exec(text);
62
+ return size === null ? { text, size: null } : { text: text.slice(size[0].length), size: size[1] };
63
+ }
64
+ function questions(text) {
65
+ return items(sectionLines(text, "Blocked"));
66
+ }
67
+ function assumptions(text) {
68
+ return items(sectionLines(text, "Assumptions"));
69
+ }
70
+ function items(lines) {
71
+ const found = [];
72
+ let last;
73
+ for (const { line } of lines) {
74
+ const asked = question(line);
75
+ if (asked !== null) {
76
+ last = { asked, body: [] };
77
+ found.push(last);
78
+ continue;
79
+ }
80
+ if (line.trim() !== "" && !/^[ \t]/.test(line)) {
81
+ last = undefined;
82
+ }
83
+ if (last === undefined) {
84
+ continue;
85
+ }
86
+ const followUp = FOLLOW_UP.exec(line);
87
+ if (followUp !== null) {
88
+ last.asked.followUps.push((followUp[1] ?? "").trim());
89
+ } else if (!offers(last.asked, line)) {
90
+ last.body.push(line);
91
+ }
92
+ }
93
+ return found.map(({ asked, body }) => settled(asked, body));
94
+ }
95
+ var INDENTS = new WeakMap;
96
+ function offers(asked, line) {
97
+ const choice = CHOICE.exec(line);
98
+ if (choice === null) {
99
+ const last = asked.choices.at(-1);
100
+ const indent = /^[ \t]*/.exec(line)?.[0].length ?? 0;
101
+ if (last === undefined || line.trim() === "" || indent <= (INDENTS.get(last) ?? indent)) {
102
+ return false;
103
+ }
104
+ last.body = last.body === "" ? line : `${last.body}
105
+ ${line}`;
106
+ return true;
107
+ }
108
+ const [, indent = "", one, any, order, text = ""] = choice;
109
+ const offered = {
110
+ key: one ?? any ?? order ?? "",
111
+ text: text.replace(CHOSEN, ""),
112
+ body: "",
113
+ why: "",
114
+ chosen: CHOSEN.test(text)
115
+ };
116
+ INDENTS.set(offered, indent.length);
117
+ asked.choices.push(offered);
118
+ asked.pick ??= one !== undefined ? "one" : any !== undefined ? "any" : "order";
119
+ return true;
120
+ }
121
+ function settled(asked, body) {
122
+ asked.body = dedent(body);
123
+ for (const choice of asked.choices) {
124
+ Object.assign(choice, reasoned(dedent(choice.body.split(`
125
+ `))));
126
+ }
127
+ return asked;
128
+ }
129
+ var WHY = /^why:[ \t]*(.*)$/i;
130
+ function reasoned(body) {
131
+ const lines = body.split(`
132
+ `);
133
+ const at = lines.findIndex((line) => WHY.test(line));
134
+ if (at === -1) {
135
+ return { body, why: "" };
136
+ }
137
+ return {
138
+ body: dedent(lines.filter((_, index) => index !== at)),
139
+ why: (WHY.exec(lines[at] ?? "")?.[1] ?? "").trim()
140
+ };
141
+ }
142
+ function dedent(lines) {
143
+ const indents = lines.filter((line) => line.trim() !== "").map((line) => /^[ \t]*/.exec(line)?.[0].length ?? 0);
144
+ const cut = indents.length === 0 ? 0 : Math.min(...indents);
145
+ return lines.map((line) => line.slice(cut).trimEnd()).join(`
146
+ `).replace(/^\n+|\s+$/g, "");
147
+ }
148
+ function picks(text) {
149
+ const asked = questions(text);
150
+ const met = asked.map(metPick).filter((each) => each !== null);
151
+ return {
152
+ asked: asked.length,
153
+ picked: met.length,
154
+ overturned: met.filter((each) => each === "overturned").length,
155
+ amended: met.filter((each) => each === "amended").length
156
+ };
157
+ }
158
+ function metPick(asked) {
159
+ const chosen = asked.choices.find((choice) => choice.chosen);
160
+ const reply = asked.reply ?? "";
161
+ const [lead, wrapped, bare] = /^(?:- )?(?:\(([a-z])\)|([a-z])(?=[.,]|$))/i.exec(reply) ?? [];
162
+ const key = wrapped ?? bare;
163
+ if (chosen === undefined || key === undefined || asked.pick !== "one") {
164
+ return null;
165
+ }
166
+ if (key.toLowerCase() !== chosen.key) {
167
+ return "overturned";
168
+ }
169
+ return /[a-z0-9]/i.test(reply.slice(lead?.length ?? 0)) || asked.followUps.length > 0 ? "amended" : "kept";
170
+ }
171
+ function decisions(text) {
172
+ const each = (item, how, ended) => ({
173
+ number: item.number,
174
+ text: item.text,
175
+ size: item.size,
176
+ how,
177
+ ended
178
+ });
179
+ return [
180
+ ...assumptions(text).map((item) => each(item, "assumed", "kept")),
181
+ ...questions(text).map((item) => CHALLENGED.test(item.reply ?? "") ? each(item, "assumed", "challenged") : each(item, "asked", metPick(item)))
182
+ ].sort((one, other) => Number(one.number) - Number(other.number));
183
+ }
184
+ var CHALLENGED = /^challenged\b/i;
185
+ function assumptionCounts(text) {
186
+ const challenged = questions(text).filter((each) => CHALLENGED.test(each.reply ?? "")).length;
187
+ return { made: assumptions(text).length + challenged, challenged };
188
+ }
189
+ var STEP = /^[ \t]*- \[ \][ \t]*(.*)$/;
190
+ function unfinished(text) {
191
+ const md = Markdown.parse(text);
192
+ const next = md.has("Next") ? md.section("Next").body.split(`
193
+ `) : [];
194
+ return {
195
+ questions: questions(text).filter((asked) => !asked.done).map((asked) => asked.number),
196
+ steps: next.flatMap((line) => {
197
+ const step = STEP.exec(line)?.[1];
198
+ return step === undefined ? [] : [step.trim()];
199
+ })
200
+ };
201
+ }
202
+ function ready({ questions, steps }) {
203
+ return questions.length === 0 && steps.length === 0;
204
+ }
205
+ function whatIsLeft({ questions, steps }) {
206
+ return [
207
+ questions.length > 0 ? `questions ${questions.join(", ")} unchecked under ## Blocked` : "",
208
+ steps.length > 0 ? `${steps.length} step${steps.length === 1 ? "" : "s"} unchecked under ## Next` : ""
209
+ ].filter(Boolean).join(" and ");
210
+ }
211
+ function question(line) {
212
+ const item = ITEM.exec(line);
213
+ if (item === null) {
214
+ return null;
215
+ }
216
+ const [, check = " ", number = "", rest = ""] = item;
217
+ const arrow = rest.indexOf(ARROW);
218
+ const { text, size } = sized((arrow === -1 ? rest : rest.slice(0, arrow)).trim());
219
+ return {
220
+ number,
221
+ done: check !== " ",
222
+ text,
223
+ size,
224
+ body: "",
225
+ reply: arrow === -1 ? null : rest.slice(arrow + ARROW.length).trim(),
226
+ followUps: [],
227
+ choices: [],
228
+ pick: null
229
+ };
230
+ }
231
+ function sectionLines(text, name) {
232
+ const { sections } = Markdown.parse(text);
233
+ const at = sections.findIndex((section) => section.heading.toLowerCase() === name.toLowerCase());
234
+ const blocked = sections[at];
235
+ if (blocked === undefined) {
236
+ return [];
237
+ }
238
+ const lines = text.split(`
239
+ `);
240
+ const end = sections.slice(at + 1).find((later) => later.level <= blocked.level)?.line ?? lines.length + 1;
241
+ return lines.slice(blocked.line, end - 1).map((line, offset) => ({ index: blocked.line + offset, line }));
242
+ }
243
+ function checkPlan(text, { task, escalated = false, review = false }) {
244
+ const md = Markdown.parse(text);
245
+ const problems = [];
246
+ const section = (name) => md.has(name) ? md.section(name).body : null;
247
+ if (md.title !== task) {
248
+ problems.push(md.title === null ? `no title: the first line should be "# ${task}"` : `title is "# ${md.title}", should be "# ${task}"`);
249
+ }
250
+ for (const name of REQUIRED) {
251
+ if (!md.has(name)) {
252
+ problems.push(`no ## ${name} section`);
253
+ }
254
+ }
255
+ if (section("Goal") === "") {
256
+ problems.push("## Goal is empty: say in a line or two what done means");
257
+ }
258
+ const done = section("Done");
259
+ if (done !== null && UNCHECKED.test(done)) {
260
+ problems.push("## Done has a `- [ ]` item: it belongs under ## Next");
261
+ }
262
+ const blocked = section("Blocked");
263
+ if (escalated && !review && blocked === null) {
264
+ problems.push("escalated with no ## Blocked section: add `- [ ] 1.` items for what the reviewer must do");
265
+ }
266
+ if (blocked !== null && !QUESTION.test(blocked)) {
267
+ problems.push("## Blocked lists nothing: add `- [ ] 1.` items for what the reviewer must do");
268
+ }
269
+ const open = questions(text).filter((asked) => !asked.done && asked.reply === null);
270
+ if (!escalated && open.length > 0) {
271
+ const numbers = open.map((asked) => asked.number).join(", ");
272
+ problems.push(`## Blocked has open questions ${numbers}: ask the reviewer before merging`);
273
+ }
274
+ for (const assumed of assumptions(text)) {
275
+ if (!assumed.choices.some((choice) => choice.chosen)) {
276
+ problems.push(`## Assumptions item ${assumed.number} marks no choice \`(chosen)\`: offer what else it could have been, and mark the one taken`);
277
+ }
278
+ }
279
+ const numbers = [...questions(text), ...assumptions(text)].map((item) => item.number);
280
+ const twice = [
281
+ ...new Set(numbers.filter((each, at) => numbers.indexOf(each) !== at))
282
+ ];
283
+ if (twice.length > 0) {
284
+ problems.push(`${twice.join(", ")} numbered twice across ## Assumptions and ## Blocked: a challenged assumption moves to ## Blocked rather than being copied, and new items continue from the highest`);
285
+ }
286
+ const known = SECTIONS.map((section) => section.toLowerCase());
287
+ for (const section of md.sections) {
288
+ if (section.level === 2 && !known.includes(section.heading.toLowerCase())) {
289
+ problems.push(`unexpected section "## ${section.heading}" (line ${section.line}): keep to ${SECTIONS.join(", ")}`);
290
+ }
291
+ }
292
+ return problems;
293
+ }
294
+
295
+ // assumed.ts
296
+ var ASSUMED = /^- Assumed (\d+):[ \t]+(.+?)[ \t]*$/;
297
+ var HEADING = /^#{1,3}[ \t]/;
298
+ var FENCE = /^[ \t]*(```|~~~)/;
299
+ function isAssumed(line) {
300
+ return ASSUMED.test(line);
301
+ }
302
+ function assumedAt(lines, start) {
303
+ const assumed = [];
304
+ let end = start;
305
+ let exhibit;
306
+ for (let i = start;i < lines.length; i += 1) {
307
+ const line = lines[i];
308
+ const title = exhibitTitle(line);
309
+ if (title !== null) {
310
+ const shown = shownEnd(lines, i + 1);
311
+ if (!ASSUMED.test(lines[shown] ?? "")) {
312
+ break;
313
+ }
314
+ exhibit = { title, body: trimmed(lines.slice(i + 1, shown)) };
315
+ i = shown - 1;
316
+ continue;
317
+ }
318
+ const said = ASSUMED.exec(line);
319
+ if (said !== null) {
320
+ assumed.push({
321
+ number: said[1],
322
+ text: said[2],
323
+ ...exhibit === undefined ? {} : { exhibit }
324
+ });
325
+ end = i + 1;
326
+ } else if (line.trim() !== "") {
327
+ break;
328
+ } else {
329
+ exhibit = undefined;
330
+ }
331
+ }
332
+ return assumed.length === 0 ? null : { assumed, end };
333
+ }
334
+ function shownEnd(lines, start) {
335
+ let fenced = false;
336
+ for (let i = start;i < lines.length; i += 1) {
337
+ const line = lines[i];
338
+ if (FENCE.test(line)) {
339
+ fenced = !fenced;
340
+ } else if (!fenced && (HEADING.test(line) || ASSUMED.test(line))) {
341
+ return i;
342
+ }
343
+ }
344
+ return lines.length;
345
+ }
346
+ function trimmed(lines) {
347
+ return lines.join(`
348
+ `).replace(/^\n+|\s+$/g, "");
349
+ }
350
+
351
+ // demo.ts
352
+ var DEMO = /^### 🎬 Demo(?::[ \t]*(.*?))?[ \t]*$/;
353
+ var STEP2 = /^(\d+)\.[ \t]+(.+)$/;
354
+ function demoAt(lines, start, until) {
355
+ const title = DEMO.exec(lines[start]);
356
+ if (title === null) {
357
+ return null;
358
+ }
359
+ const first = lines.findIndex((line, at) => at > start && at < until && STEP2.exec(line)?.[1] === "1");
360
+ const steps = [];
361
+ let end = first === -1 ? until : first;
362
+ if (first !== -1) {
363
+ let body = [];
364
+ for (let i = first;i < lines.length; i += 1) {
365
+ const line = lines[i];
366
+ const item = STEP2.exec(line);
367
+ if (item !== null && item[1] === String(steps.length + 1)) {
368
+ body = [];
369
+ steps.push({
370
+ number: item[1],
371
+ action: (item[2] ?? "").trim(),
372
+ expect: ""
373
+ });
374
+ end = i + 1;
375
+ continue;
376
+ }
377
+ if (line.trim() === "") {
378
+ continue;
379
+ }
380
+ if (!/^[ \t]/.test(line)) {
381
+ break;
382
+ }
383
+ body.push(...lines.slice(end, i).map(() => ""), line);
384
+ steps.at(-1).expect = dedented(body);
385
+ end = i + 1;
386
+ }
387
+ }
388
+ return {
389
+ demo: {
390
+ title: title[1] || null,
391
+ intro: trimmed2(lines.slice(start + 1, first === -1 ? until : first)),
392
+ steps
393
+ },
394
+ end
395
+ };
396
+ }
397
+ function isDemoTitle(line) {
398
+ return DEMO.test(line);
399
+ }
400
+ function dedented(lines) {
401
+ const indent = Math.min(...lines.filter((line) => line.trim() !== "").map((line) => /^[ \t]*/.exec(line)?.[0].length ?? 0));
402
+ return trimmed2(lines.map((line) => line.slice(indent)));
403
+ }
404
+ function trimmed2(lines) {
405
+ return lines.join(`
406
+ `).replace(/^\n+|\s+$/g, "");
407
+ }
408
+
409
+ // asked.ts
410
+ function stretches2(text) {
411
+ const lines = text.split(`
412
+ `);
413
+ const found = [];
414
+ let from = 0;
415
+ let fenced = false;
416
+ for (let i = 0;i < lines.length; i += 1) {
417
+ const line = lines[i];
418
+ if (FENCE2.test(line)) {
419
+ fenced = !fenced;
420
+ continue;
421
+ }
422
+ if (fenced) {
423
+ continue;
424
+ }
425
+ const title = REVIEW.exec(line);
426
+ const end = lines.findIndex((each, at) => at > i && each.trim() === REVIEW_END);
427
+ if (title !== null && end !== -1) {
428
+ found.push(...prose(lines.slice(from, i)));
429
+ found.push({
430
+ type: "review",
431
+ review: {
432
+ task: title[1],
433
+ base: title[2],
434
+ ...reviewOf(lines.slice(i + 1, end))
435
+ }
436
+ });
437
+ from = end + 1;
438
+ i = end;
439
+ continue;
440
+ }
441
+ const proposed = PROPOSED.exec(line);
442
+ if (proposed !== null) {
443
+ const end = endAt(lines, i + 1);
444
+ found.push(...prose(lines.slice(from, i)));
445
+ found.push({
446
+ type: "proposal",
447
+ proposal: {
448
+ subject: proposed[1],
449
+ body: trimmed3(lines.slice(i + 1, end))
450
+ }
451
+ });
452
+ from = end;
453
+ i = end - 1;
454
+ continue;
455
+ }
456
+ const demo = demoHere(lines, i);
457
+ if (demo !== null) {
458
+ found.push(...prose(lines.slice(from, i)));
459
+ found.push({ type: "demo", demo: demo.demo });
460
+ from = demo.end;
461
+ i = demo.end - 1;
462
+ continue;
463
+ }
464
+ const assumed = assumedAt(lines, i);
465
+ if (assumed !== null) {
466
+ found.push(...prose(lines.slice(from, i)));
467
+ found.push({ type: "assumed", assumed: assumed.assumed });
468
+ from = assumed.end;
469
+ i = assumed.end - 1;
470
+ continue;
471
+ }
472
+ const kept = keptAt(lines, i);
473
+ if (kept !== null) {
474
+ found.push(...prose(lines.slice(from, i)));
475
+ found.push(kept.stretch);
476
+ from = kept.end;
477
+ i = kept.end - 1;
478
+ continue;
479
+ }
480
+ if (ITEM2.exec(line)?.[1] !== "1") {
481
+ continue;
482
+ }
483
+ const list = listAt(lines, i);
484
+ if (list === null) {
485
+ continue;
486
+ }
487
+ found.push(...prose(lines.slice(from, i)));
488
+ found.push({ type: "questions", questions: list.questions });
489
+ from = list.end;
490
+ i = list.end - 1;
491
+ }
492
+ found.push(...prose(lines.slice(from)));
493
+ return found;
494
+ }
495
+ var ASKS = /\?(?:[ \t]+\([^()]*\))?$/;
496
+ var ASKS_THEN = /^(.*?\?(?:[ \t]+\([^()]*\))?)[ \t]+(\S.*)$/;
497
+ var MERGED = /^## ✅ Merged (\S+) onto (\S+)[ \t]*$/;
498
+ var ENDED = /^## (?:(🛑) Removed|⚠\uFE0F? Escalated) (\S+?)(?::[ \t]*(.*?))?[ \t]*$/;
499
+ var FINISHED = /^## 🏁 Finished lanes? (.*?)[ \t]*$/;
500
+ var WAITING = /^## ⏸\uFE0F? Waiting lanes? (.*?)(?::[ \t]*(.*?))?[ \t]*$/;
501
+ var WORKING = /^## ⏳ Working lanes? (.*?)(?::[ \t]*(.*?))?[ \t]*$/;
502
+ var WORKING_TASK = /^## ⏳ Working (\S+?)(?::[ \t]*(.*?))?[ \t]*$/;
503
+ var HANDED = /^## 🤝 Handed off (\S+) to (.+?)(?::[ \t]*(.*?))?[ \t]*$/;
504
+ var STARTED = /^## 🌱 Started lanes? (.*?)[ \t]*$/;
505
+ var PROPOSAL = /^### 📝 (.+?) \[#(\d+)\][ \t]*$/;
506
+ var HEADING2 = /^#{1,3}[ \t]/;
507
+ var REVIEW = /^## 🔍 Ready to merge (\S+) onto (\S+)[ \t]*$/;
508
+ var REVIEW_END = 'Reply "merge", or say what to change.';
509
+ var PROPOSED = /^## 💡 Proposed (.+?)[ \t]*$/;
510
+ var CHECKS = /^Checks:[ \t]*(.*)$/;
511
+ var FAILED = /^Failed:[ \t]*(.*)$/;
512
+ var ITEM2 = /^(\d+)\.[ \t]+(.+)$/;
513
+ var FENCE2 = /^[ \t]*(```|~~~)/;
514
+ function keptAt(lines, start) {
515
+ const line = lines[start];
516
+ const merged = MERGED.exec(line);
517
+ const ended = ENDED.exec(line);
518
+ const finished = FINISHED.exec(line);
519
+ const waiting = WAITING.exec(line);
520
+ const working = WORKING.exec(line);
521
+ const workingTask = working === null ? WORKING_TASK.exec(line) : null;
522
+ const handed = HANDED.exec(line);
523
+ const started = STARTED.exec(line);
524
+ const proposed = PROPOSAL.exec(line);
525
+ if (merged === null && ended === null && finished === null && waiting === null && working === null && workingTask === null && handed === null && started === null && proposed === null) {
526
+ return null;
527
+ }
528
+ const end = proposed !== null ? paragraphEnd(lines, start + 1, endAt(lines, start + 1)) : endAt(lines, start + 1);
529
+ const body = lines.slice(start + 1, end).join(`
530
+ `).replace(/^\n+|\s+$/g, "");
531
+ if (started !== null) {
532
+ return {
533
+ stretch: {
534
+ type: "start",
535
+ start: { lanes: lanesOf(started[1]), goal: body }
536
+ },
537
+ end
538
+ };
539
+ }
540
+ if (proposed !== null) {
541
+ return {
542
+ stretch: {
543
+ type: "todo",
544
+ todo: {
545
+ id: Number(proposed[2]),
546
+ subject: proposed[1],
547
+ body
548
+ }
549
+ },
550
+ end
551
+ };
552
+ }
553
+ const source = lines.slice(start, end).join(`
554
+ `).replace(/\s+$/, "");
555
+ const report = finished !== null ? {
556
+ ending: "finished",
557
+ lanes: lanesOf(finished[1]),
558
+ reason: null,
559
+ body,
560
+ source
561
+ } : waiting !== null || working !== null ? {
562
+ ending: waiting !== null ? "waiting" : "working",
563
+ lanes: lanesOf((waiting ?? working)?.[1]),
564
+ reason: (waiting ?? working)?.[2] || null,
565
+ body,
566
+ source
567
+ } : merged !== null ? {
568
+ ending: "merged",
569
+ task: merged[1],
570
+ base: merged[2],
571
+ to: null,
572
+ reason: null,
573
+ body,
574
+ source
575
+ } : workingTask !== null ? {
576
+ ending: "working",
577
+ task: workingTask[1],
578
+ base: null,
579
+ to: null,
580
+ reason: workingTask[2] || null,
581
+ body,
582
+ source
583
+ } : handed !== null ? {
584
+ ending: "handed",
585
+ task: handed[1],
586
+ base: null,
587
+ to: handed[2],
588
+ reason: handed[3] || null,
589
+ body,
590
+ source
591
+ } : {
592
+ ending: ended?.[1] === undefined ? "escalated" : "removed",
593
+ task: ended?.[2],
594
+ base: null,
595
+ to: null,
596
+ reason: ended?.[3] || null,
597
+ body,
598
+ source
599
+ };
600
+ return { stretch: { type: "report", report }, end };
601
+ }
602
+ function lanesOf(listed) {
603
+ return listed.split(",").map((lane) => lane.trim()).filter((lane) => lane !== "");
604
+ }
605
+ function reviewOf(lines) {
606
+ const { body, demo } = withDemo(lines);
607
+ let rest = body.split(`
608
+ `);
609
+ const named = (line) => {
610
+ const at = rest.findIndex((said) => line.test(said));
611
+ if (at === -1) {
612
+ return [];
613
+ }
614
+ const found = Array.from(rest[at].matchAll(/`([^`]+)`/g), (code) => code[1]);
615
+ rest = rest.toSpliced(at, rest[at + 1]?.trim() === "" ? 2 : 1);
616
+ return found;
617
+ };
618
+ const checks = named(CHECKS);
619
+ const failed = named(FAILED);
620
+ const gap = rest.findIndex((line) => line.trim() === "");
621
+ return {
622
+ summary: trimmed3(gap === -1 ? rest : rest.slice(0, gap)),
623
+ demo,
624
+ checks,
625
+ failed,
626
+ details: gap === -1 ? "" : trimmed3(rest.slice(gap))
627
+ };
628
+ }
629
+ function withDemo(lines) {
630
+ const at = lines.findIndex((_, index) => demoHere(lines, index) !== null);
631
+ const found = at === -1 ? null : demoHere(lines, at);
632
+ if (found === null) {
633
+ return { body: trimmed3(lines), demo: null };
634
+ }
635
+ return {
636
+ body: trimmed3([...lines.slice(0, at), ...lines.slice(found.end)]),
637
+ demo: found.demo
638
+ };
639
+ }
640
+ function demoHere(lines, start) {
641
+ return isDemoTitle(lines[start]) ? demoAt(lines, start, endAt(lines, start + 1)) : null;
642
+ }
643
+ function trimmed3(lines) {
644
+ return lines.join(`
645
+ `).replace(/^\n+|\s+$/g, "");
646
+ }
647
+ function paragraphEnd(lines, start, end) {
648
+ let begun = false;
649
+ let fenced = false;
650
+ for (let i = start;i < end; i += 1) {
651
+ const line = lines[i];
652
+ if (FENCE2.test(line)) {
653
+ fenced = !fenced;
654
+ }
655
+ if (line.trim() !== "") {
656
+ begun = true;
657
+ } else if (begun && !fenced) {
658
+ return i;
659
+ }
660
+ }
661
+ return end;
662
+ }
663
+ function endAt(lines, start) {
664
+ let fenced = false;
665
+ for (let i = start;i < lines.length; i += 1) {
666
+ const line = lines[i];
667
+ if (FENCE2.test(line)) {
668
+ fenced = !fenced;
669
+ continue;
670
+ }
671
+ if (!fenced && (HEADING2.test(line) || isAssumed(line) || ITEM2.exec(line)?.[1] === "1" && listAt(lines, i) !== null)) {
672
+ return i;
673
+ }
674
+ }
675
+ return lines.length;
676
+ }
677
+ function listAt(lines, start) {
678
+ const items = [];
679
+ let end = start;
680
+ for (let i = start;i < lines.length; i += 1) {
681
+ const line = lines[i];
682
+ const item = ITEM2.exec(line);
683
+ if (item !== null && item[1] === String(items.length + 1)) {
684
+ items.push({ asked: question2(item[1], item[2] ?? ""), body: [] });
685
+ end = i + 1;
686
+ continue;
687
+ }
688
+ if (line.trim() === "") {
689
+ continue;
690
+ }
691
+ if (!/^[ \t]/.test(line)) {
692
+ break;
693
+ }
694
+ const last = items.at(-1);
695
+ last.body.push(...lines.slice(end, i).map(() => ""));
696
+ if (!offers(last.asked, line)) {
697
+ last.body.push(line);
698
+ }
699
+ end = i + 1;
700
+ }
701
+ if (!items.every(asks)) {
702
+ return null;
703
+ }
704
+ return {
705
+ questions: items.map(({ asked, body }) => settled(asked, body)),
706
+ end
707
+ };
708
+ }
709
+ function asks({ asked, body }) {
710
+ if (ASKS.test(asked.text)) {
711
+ return true;
712
+ }
713
+ const then = ASKS_THEN.exec(asked.text);
714
+ if (then !== null) {
715
+ asked.text = then[1];
716
+ const indent = /^[ \t]*/.exec(body.find((line) => line.trim()) ?? "");
717
+ body.unshift(`${indent?.[0] ?? ""}${then[2]}`);
718
+ return true;
719
+ }
720
+ return asked.choices.length > 0;
721
+ }
722
+ function question2(number, line) {
723
+ return {
724
+ number,
725
+ done: false,
726
+ ...sized(line.trim()),
727
+ body: "",
728
+ reply: null,
729
+ followUps: [],
730
+ choices: [],
731
+ pick: null
732
+ };
733
+ }
734
+ function prose(lines) {
735
+ const text = lines.join(`
736
+ `).replace(/^\n+|\s+$/g, "");
737
+ return text === "" ? [] : [{ type: "text", text }];
738
+ }
739
+
740
+ export { PLAN_FILE, Plans, STUB_STEP, goalLine, goalOf, SIZES, questions, picks, decisions, assumptionCounts, unfinished, ready, whatIsLeft, checkPlan, stretches2 };