abelworkflow 0.9.2 → 1.0.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 (134) hide show
  1. package/README.md +54 -182
  2. package/bin/abelworkflow.mjs +5 -3
  3. package/extensions/pi-gpt-responses-compat/index.ts +1 -1
  4. package/lib/cli/args.mjs +76 -0
  5. package/lib/cli/main.mjs +385 -0
  6. package/lib/cli/prompts.mjs +106 -0
  7. package/lib/config/dotenv.mjs +102 -0
  8. package/lib/config/jsonc.mjs +80 -0
  9. package/lib/config/store.mjs +310 -0
  10. package/lib/config/toml.mjs +638 -0
  11. package/lib/installer/assets.mjs +324 -0
  12. package/lib/installer/install.mjs +153 -0
  13. package/lib/installer/links.mjs +427 -0
  14. package/lib/installer/state.mjs +163 -0
  15. package/lib/paths.mjs +99 -0
  16. package/lib/providers/claude.mjs +197 -0
  17. package/lib/providers/codex.mjs +433 -0
  18. package/lib/providers/pi.mjs +577 -0
  19. package/lib/providers/skills.mjs +105 -0
  20. package/lib/templates/codex/agents/default.toml +7 -0
  21. package/lib/templates/codex/agents/explorer.toml +7 -0
  22. package/lib/templates/codex/agents/planner.toml +7 -0
  23. package/lib/templates/codex/agents/reviewer.toml +7 -0
  24. package/lib/templates/codex/agents/worker.toml +7 -0
  25. package/lib/templates/codex/config-base.toml +11 -3
  26. package/lib/templates/workflow/AGENTS.md +50 -0
  27. package/lib/templates/workflow/commands/abel-design.md +175 -0
  28. package/{commands → lib/templates/workflow/commands}/abel-diagnose.md +5 -5
  29. package/lib/templates/workflow/commands/abel-implement.md +170 -0
  30. package/{commands → lib/templates/workflow/commands}/abel-init.md +3 -5
  31. package/{.gitignore → lib/templates/workflow/gitignore.template} +0 -2
  32. package/lib/tools/cli-installer.mjs +277 -0
  33. package/package.json +37 -10
  34. package/skills/context7-auto-research/SKILL.md +5 -5
  35. package/skills/context7-auto-research/{context7-api.js → context7-api.cjs} +5 -8
  36. package/skills/dev-browser/SKILL.md +53 -33
  37. package/skills/dev-browser/dist/scripts/start.d.ts +2 -0
  38. package/skills/dev-browser/dist/scripts/start.d.ts.map +1 -0
  39. package/skills/dev-browser/dist/scripts/start.js +118 -0
  40. package/skills/dev-browser/dist/scripts/start.js.map +1 -0
  41. package/skills/dev-browser/dist/src/client.d.ts +93 -0
  42. package/skills/dev-browser/dist/src/client.d.ts.map +1 -0
  43. package/skills/dev-browser/dist/src/client.js +310 -0
  44. package/skills/dev-browser/dist/src/client.js.map +1 -0
  45. package/skills/dev-browser/dist/src/entrypoint.d.ts +29 -0
  46. package/skills/dev-browser/dist/src/entrypoint.d.ts.map +1 -0
  47. package/skills/dev-browser/dist/src/entrypoint.js +106 -0
  48. package/skills/dev-browser/dist/src/entrypoint.js.map +1 -0
  49. package/skills/dev-browser/dist/src/index.d.ts +4 -0
  50. package/skills/dev-browser/dist/src/index.d.ts.map +1 -0
  51. package/skills/dev-browser/dist/src/index.js +2 -0
  52. package/skills/dev-browser/dist/src/index.js.map +1 -0
  53. package/skills/dev-browser/dist/src/page-api.d.ts +25 -0
  54. package/skills/dev-browser/dist/src/page-api.d.ts.map +1 -0
  55. package/skills/dev-browser/dist/src/page-api.js +104 -0
  56. package/skills/dev-browser/dist/src/page-api.js.map +1 -0
  57. package/skills/dev-browser/dist/src/relay.d.ts +27 -0
  58. package/skills/dev-browser/dist/src/relay.d.ts.map +1 -0
  59. package/skills/dev-browser/dist/src/relay.js +521 -0
  60. package/skills/dev-browser/dist/src/relay.js.map +1 -0
  61. package/skills/dev-browser/dist/src/runtime.d.ts +45 -0
  62. package/skills/dev-browser/dist/src/runtime.d.ts.map +1 -0
  63. package/skills/dev-browser/dist/src/runtime.js +54 -0
  64. package/skills/dev-browser/dist/src/runtime.js.map +1 -0
  65. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +23 -0
  66. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts.map +1 -0
  67. package/skills/dev-browser/{src/snapshot/browser-script.ts → dist/src/snapshot/browser-script.js} +21 -30
  68. package/skills/dev-browser/dist/src/snapshot/browser-script.js.map +1 -0
  69. package/skills/dev-browser/dist/src/snapshot/index.d.ts +14 -0
  70. package/skills/dev-browser/dist/src/snapshot/index.d.ts.map +1 -0
  71. package/skills/dev-browser/{src/snapshot/index.ts → dist/src/snapshot/index.js} +2 -2
  72. package/skills/dev-browser/dist/src/snapshot/index.js.map +1 -0
  73. package/skills/dev-browser/dist/src/snapshot/inject.d.ts +13 -0
  74. package/skills/dev-browser/dist/src/snapshot/inject.d.ts.map +1 -0
  75. package/skills/dev-browser/{src/snapshot/inject.ts → dist/src/snapshot/inject.js} +2 -2
  76. package/skills/dev-browser/dist/src/snapshot/inject.js.map +1 -0
  77. package/skills/dev-browser/dist/src/standalone.d.ts +32 -0
  78. package/skills/dev-browser/dist/src/standalone.d.ts.map +1 -0
  79. package/skills/dev-browser/dist/src/standalone.js +174 -0
  80. package/skills/dev-browser/dist/src/standalone.js.map +1 -0
  81. package/skills/dev-browser/dist/src/startup.d.ts +55 -0
  82. package/skills/dev-browser/dist/src/startup.d.ts.map +1 -0
  83. package/skills/dev-browser/dist/src/startup.js +81 -0
  84. package/skills/dev-browser/dist/src/startup.js.map +1 -0
  85. package/skills/dev-browser/dist/src/target-registry.d.ts +29 -0
  86. package/skills/dev-browser/dist/src/target-registry.d.ts.map +1 -0
  87. package/skills/dev-browser/dist/src/target-registry.js +135 -0
  88. package/skills/dev-browser/dist/src/target-registry.js.map +1 -0
  89. package/skills/dev-browser/dist/src/types.d.ts +27 -0
  90. package/skills/dev-browser/dist/src/types.d.ts.map +1 -0
  91. package/skills/dev-browser/dist/src/types.js +2 -0
  92. package/skills/dev-browser/dist/src/types.js.map +1 -0
  93. package/skills/dev-browser/package-lock.json +67 -1510
  94. package/skills/dev-browser/package.json +18 -14
  95. package/skills/dev-browser/references/scraping.md +94 -105
  96. package/skills/grok-search/.env.example +3 -3
  97. package/skills/grok-search/SKILL.md +1 -1
  98. package/skills/grok-search/defaults.json +3 -0
  99. package/skills/grok-search/gitignore.template +4 -0
  100. package/skills/grok-search/scripts/_dotenv.py +5 -1
  101. package/skills/grok-search/scripts/groksearch_cli.py +15 -33
  102. package/skills/prompt-enhancer/SKILL.md +2 -27
  103. package/skills/prompt-enhancer/TEMPLATE.md +0 -4
  104. package/.skill-lock.json +0 -29
  105. package/AGENTS.md +0 -45
  106. package/commands/abel-implement.md +0 -157
  107. package/commands/abel-plan.md +0 -88
  108. package/commands/abel-research.md +0 -126
  109. package/lib/cli/logic.mjs +0 -213
  110. package/lib/cli.mjs +0 -3016
  111. package/skills/confidence-check/SKILL.md +0 -34
  112. package/skills/confidence-check/confidence.ts +0 -276
  113. package/skills/dev-browser/bun.lock +0 -460
  114. package/skills/dev-browser/scripts/start.ts +0 -280
  115. package/skills/dev-browser/src/client.ts +0 -474
  116. package/skills/dev-browser/src/entrypoint.ts +0 -157
  117. package/skills/dev-browser/src/index.ts +0 -289
  118. package/skills/dev-browser/src/relay.ts +0 -731
  119. package/skills/dev-browser/src/runtime.test.ts +0 -60
  120. package/skills/dev-browser/src/runtime.ts +0 -171
  121. package/skills/dev-browser/src/startup.test.ts +0 -95
  122. package/skills/dev-browser/src/startup.ts +0 -153
  123. package/skills/dev-browser/src/types.ts +0 -35
  124. package/skills/dev-browser/tsconfig.json +0 -36
  125. package/skills/dev-browser/vitest.config.ts +0 -12
  126. package/skills/prompt-enhancer/.env.example +0 -12
  127. package/skills/prompt-enhancer/ADVANCED.md +0 -103
  128. package/skills/prompt-enhancer/requirements.txt +0 -2
  129. package/skills/prompt-enhancer/scripts/_dotenv.py +0 -28
  130. package/skills/prompt-enhancer/scripts/enhance.py +0 -191
  131. package/skills/prompt-enhancer/scripts/prompt_enhancer_entry.py +0 -253
  132. package/skills/sequential-think/SKILL.md +0 -198
  133. package/skills/sequential-think/scripts/.env.example +0 -5
  134. package/skills/sequential-think/scripts/sequential_think_cli.py +0 -253
@@ -0,0 +1,638 @@
1
+ import { parse as validateToml } from "smol-toml";
2
+
3
+ function detectLineEnding(content) {
4
+ return content.includes("\r\n") ? "\r\n" : "\n";
5
+ }
6
+
7
+ function updateTopLevelTomlField(content, field, value) {
8
+ const lineEnding = detectLineEnding(content);
9
+ if (value === null) {
10
+ return removeTopLevelTomlField(content, field);
11
+ }
12
+
13
+ const document = parseTomlDocument(content);
14
+ const entry = findTomlAssignment(document.assignments, field, null);
15
+ const nextLine = `${field} = ${JSON.stringify(value)}`;
16
+
17
+ if (entry) {
18
+ return `${content.slice(0, entry.start)}${entry.indent}${nextLine}${content.slice(entry.end)}`;
19
+ }
20
+
21
+ const topLevel = content.slice(0, document.topLevelEnd);
22
+ const rest = content.slice(document.topLevelEnd);
23
+ let nextTopLevel = topLevel.trimEnd()
24
+ ? `${topLevel.trimEnd()}${lineEnding}${nextLine}`
25
+ : nextLine;
26
+ if (rest && nextTopLevel) {
27
+ nextTopLevel = `${nextTopLevel}${lineEnding}${lineEnding}`;
28
+ }
29
+ return `${nextTopLevel}${rest}`;
30
+ }
31
+
32
+ function removeTopLevelTomlField(content, field) {
33
+ const document = parseTomlDocument(content);
34
+ const entry = findTomlAssignment(document.assignments, field, null);
35
+ if (!entry) {
36
+ return content;
37
+ }
38
+ return `${content.slice(0, entry.start)}${content.slice(entry.lineEnd)}`;
39
+ }
40
+
41
+ function removeTomlSection(content, sectionName) {
42
+ const section = findTomlSection(parseTomlDocument(content), sectionName);
43
+ if (!section) {
44
+ return content;
45
+ }
46
+ return `${content.slice(0, section.start)}${content.slice(section.end)}`;
47
+ }
48
+
49
+ function buildTomlSection(sectionName, values, lineEnding = "\n") {
50
+ const lines = [`[${sectionName}]`];
51
+ for (const [key, value] of Object.entries(values)) {
52
+ if (value === undefined || value === null || value === "") {
53
+ continue;
54
+ }
55
+ if (typeof value === "string") {
56
+ lines.push(`${key} = ${JSON.stringify(value)}`);
57
+ } else if (typeof value === "boolean") {
58
+ lines.push(`${key} = ${value ? "true" : "false"}`);
59
+ } else {
60
+ lines.push(`${key} = ${String(value)}`);
61
+ }
62
+ }
63
+ return `${lines.join(lineEnding)}${lineEnding}`;
64
+ }
65
+
66
+ function formatTomlValue(value) {
67
+ if (typeof value === "string") {
68
+ return JSON.stringify(value);
69
+ }
70
+ if (typeof value === "boolean") {
71
+ return value ? "true" : "false";
72
+ }
73
+ return String(value);
74
+ }
75
+
76
+ function formatTomlKeySegment(value) {
77
+ const segment = String(value);
78
+ return /^[A-Za-z0-9_-]+$/u.test(segment) ? segment : JSON.stringify(segment);
79
+ }
80
+
81
+ function getTomlLines(content) {
82
+ const lines = [];
83
+ for (let start = 0; start < content.length;) {
84
+ const newline = content.indexOf("\n", start);
85
+ if (newline === -1) {
86
+ lines.push({
87
+ contentEnd: content.length,
88
+ end: content.length,
89
+ start,
90
+ text: content.slice(start)
91
+ });
92
+ break;
93
+ }
94
+
95
+ const contentEnd = content[newline - 1] === "\r" ? newline - 1 : newline;
96
+ lines.push({
97
+ contentEnd,
98
+ end: newline + 1,
99
+ start,
100
+ text: content.slice(start, contentEnd)
101
+ });
102
+ start = newline + 1;
103
+ }
104
+ return lines;
105
+ }
106
+
107
+ function skipTomlWhitespace(line, index) {
108
+ while (line[index] === " " || line[index] === "\t") {
109
+ index += 1;
110
+ }
111
+ return index;
112
+ }
113
+
114
+ function readTomlBasicEscape(text, index) {
115
+ const escaped = text[index + 1];
116
+ const simple = {
117
+ '"': '"',
118
+ "\\": "\\",
119
+ b: "\b",
120
+ e: "\u001b",
121
+ f: "\f",
122
+ n: "\n",
123
+ r: "\r",
124
+ t: "\t"
125
+ };
126
+ if (escaped in simple) {
127
+ return { index: index + 2, value: simple[escaped] };
128
+ }
129
+
130
+ const length = { U: 8, u: 4, x: 2 }[escaped];
131
+ const hex = length ? text.slice(index + 2, index + 2 + length) : "";
132
+ if (!length || hex.length !== length || !/^[0-9A-Fa-f]+$/u.test(hex)) {
133
+ return null;
134
+ }
135
+ const codePoint = Number.parseInt(hex, 16);
136
+ if (codePoint > 0x10ffff || (codePoint >= 0xd800 && codePoint <= 0xdfff)) {
137
+ return null;
138
+ }
139
+ return { index: index + 2 + length, value: String.fromCodePoint(codePoint) };
140
+ }
141
+
142
+ function parseTomlSimpleKey(text, index) {
143
+ const quote = text[index];
144
+ if (quote === `"` || quote === `'`) {
145
+ let value = "";
146
+ for (index += 1; index < text.length;) {
147
+ if (text[index] === quote) {
148
+ return { index: index + 1, value };
149
+ }
150
+ if (quote === `"` && text[index] === "\\") {
151
+ const escape = readTomlBasicEscape(text, index);
152
+ if (!escape) return null;
153
+ value += escape.value;
154
+ index = escape.index;
155
+ } else {
156
+ value += text[index];
157
+ index += 1;
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+
163
+ const start = index;
164
+ while (index < text.length && /[A-Za-z0-9_-]/u.test(text[index])) {
165
+ index += 1;
166
+ }
167
+ return index === start ? null : { index, value: text.slice(start, index) };
168
+ }
169
+
170
+ function parseTomlKeyPath(text, index = 0) {
171
+ const path = [];
172
+ while (true) {
173
+ index = skipTomlWhitespace(text, index);
174
+ const key = parseTomlSimpleKey(text, index);
175
+ if (!key) return null;
176
+ path.push(key.value);
177
+ index = skipTomlWhitespace(text, key.index);
178
+ if (text[index] !== ".") {
179
+ return { index, path };
180
+ }
181
+ index += 1;
182
+ }
183
+ }
184
+
185
+ function parseTomlHeader(text) {
186
+ let index = skipTomlWhitespace(text, 0);
187
+ const arrayTable = text.startsWith("[[", index);
188
+ if (!arrayTable && text[index] !== "[") return null;
189
+ index += arrayTable ? 2 : 1;
190
+
191
+ const key = parseTomlKeyPath(text, index);
192
+ if (!key) return null;
193
+ index = skipTomlWhitespace(text, key.index);
194
+ const close = arrayTable ? "]]" : "]";
195
+ if (!text.startsWith(close, index)) return null;
196
+ index = skipTomlWhitespace(text, index + close.length);
197
+ if (index !== text.length && text[index] !== "#") return null;
198
+ return { arrayTable, path: key.path };
199
+ }
200
+
201
+ function parseTomlAssignmentHead(text) {
202
+ const keyStart = skipTomlWhitespace(text, 0);
203
+ if (text[keyStart] === "#") return null;
204
+ const key = parseTomlKeyPath(text, keyStart);
205
+ if (!key) return null;
206
+ let index = skipTomlWhitespace(text, key.index);
207
+ if (text[index] !== "=") return null;
208
+ index = skipTomlWhitespace(text, index + 1);
209
+ return {
210
+ indent: text.slice(0, keyStart),
211
+ path: key.path,
212
+ valueIndex: index
213
+ };
214
+ }
215
+
216
+ function closeTomlMultilineString(text, state, index, quote) {
217
+ let end = index + 3;
218
+ while (text[end] === quote) {
219
+ end += 1;
220
+ }
221
+ if (end - index <= 5) {
222
+ state.mode = "normal";
223
+ }
224
+ return end;
225
+ }
226
+
227
+ function scanTomlValueLine(text, start, state) {
228
+ let valueEnd = text.length;
229
+ for (let index = start; index < text.length;) {
230
+ if (state.mode === "multiline-basic") {
231
+ if (text[index] === "\\") {
232
+ index += 2;
233
+ } else if (text.startsWith(`"""`, index)) {
234
+ index = closeTomlMultilineString(text, state, index, `"`);
235
+ } else {
236
+ index += 1;
237
+ }
238
+ continue;
239
+ }
240
+
241
+ if (state.mode === "multiline-literal") {
242
+ if (text.startsWith(`'''`, index)) {
243
+ index = closeTomlMultilineString(text, state, index, `'`);
244
+ } else {
245
+ index += 1;
246
+ }
247
+ continue;
248
+ }
249
+
250
+ if (state.mode === "basic") {
251
+ if (text[index] === "\\") {
252
+ index += 2;
253
+ } else if (text[index] === `"`) {
254
+ state.mode = "normal";
255
+ index += 1;
256
+ } else {
257
+ index += 1;
258
+ }
259
+ continue;
260
+ }
261
+
262
+ if (state.mode === "literal") {
263
+ if (text[index] === `'`) {
264
+ state.mode = "normal";
265
+ }
266
+ index += 1;
267
+ continue;
268
+ }
269
+
270
+ if (text[index] === "#") {
271
+ valueEnd = index;
272
+ break;
273
+ }
274
+ if (text.startsWith(`"""`, index)) {
275
+ state.mode = "multiline-basic";
276
+ index += 3;
277
+ continue;
278
+ }
279
+ if (text.startsWith(`'''`, index)) {
280
+ state.mode = "multiline-literal";
281
+ index += 3;
282
+ continue;
283
+ }
284
+ if (text[index] === `"`) {
285
+ state.mode = "basic";
286
+ } else if (text[index] === `'`) {
287
+ state.mode = "literal";
288
+ } else if (text[index] === "[") {
289
+ state.arrayDepth += 1;
290
+ } else if (text[index] === "]" && state.arrayDepth > 0) {
291
+ state.arrayDepth -= 1;
292
+ } else if (text[index] === "{") {
293
+ state.inlineTableDepth += 1;
294
+ } else if (text[index] === "}" && state.inlineTableDepth > 0) {
295
+ state.inlineTableDepth -= 1;
296
+ }
297
+ index += 1;
298
+ }
299
+ while (valueEnd > start && (text[valueEnd - 1] === " " || text[valueEnd - 1] === "\t")) {
300
+ valueEnd -= 1;
301
+ }
302
+ return {
303
+ complete: state.mode === "normal" && state.arrayDepth === 0 && state.inlineTableDepth === 0,
304
+ invalid: state.mode === "basic" || state.mode === "literal",
305
+ valueEnd
306
+ };
307
+ }
308
+
309
+ function parseTomlDocument(content) {
310
+ try {
311
+ validateToml(content, { integersAsBigInt: true });
312
+ } catch (error) {
313
+ const message = error instanceof Error ? error.message.split(/\r?\n/u, 1)[0] : "Invalid TOML document";
314
+ throw new SyntaxError(message, { cause: error });
315
+ }
316
+
317
+ const assignments = [];
318
+ const lines = getTomlLines(content);
319
+ const sections = [];
320
+ let currentSection = null;
321
+
322
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
323
+ const line = lines[lineIndex];
324
+ const header = parseTomlHeader(line.text);
325
+ if (header) {
326
+ if (currentSection) currentSection.end = line.start;
327
+ currentSection = {
328
+ ...header,
329
+ end: content.length,
330
+ start: line.start
331
+ };
332
+ sections.push(currentSection);
333
+ continue;
334
+ }
335
+
336
+ const head = parseTomlAssignmentHead(line.text);
337
+ if (!head) continue;
338
+ const state = { arrayDepth: 0, inlineTableDepth: 0, mode: "normal" };
339
+ let endLineIndex = lineIndex;
340
+ let scan;
341
+ for (; endLineIndex < lines.length; endLineIndex += 1) {
342
+ const valueLine = lines[endLineIndex];
343
+ scan = scanTomlValueLine(
344
+ valueLine.text,
345
+ endLineIndex === lineIndex ? head.valueIndex : 0,
346
+ state
347
+ );
348
+ if (scan.invalid) {
349
+ throw new SyntaxError(`Incomplete TOML string at offset ${valueLine.start}`);
350
+ }
351
+ if (scan.complete) break;
352
+ }
353
+ if (!scan?.complete) {
354
+ throw new SyntaxError(`Incomplete TOML assignment at offset ${line.start}`);
355
+ }
356
+ if (endLineIndex >= lines.length) endLineIndex = lines.length - 1;
357
+ const endLine = lines[endLineIndex];
358
+ assignments.push({
359
+ end: endLine.contentEnd,
360
+ indent: head.indent,
361
+ lineEnd: endLine.end,
362
+ path: head.path,
363
+ section: currentSection,
364
+ start: line.start,
365
+ valueEnd: endLine.start + scan.valueEnd,
366
+ valueStart: line.start + head.valueIndex
367
+ });
368
+ lineIndex = endLineIndex;
369
+ }
370
+
371
+ return {
372
+ assignments,
373
+ sections,
374
+ topLevelEnd: sections[0]?.start ?? content.length
375
+ };
376
+ }
377
+
378
+ function sameTomlPath(left, right) {
379
+ return left.length === right.length && left.every((part, index) => part === right[index]);
380
+ }
381
+
382
+ function parseTomlRequestedPath(value) {
383
+ const parsed = parseTomlKeyPath(value);
384
+ return parsed && skipTomlWhitespace(value, parsed.index) === value.length ? parsed.path : null;
385
+ }
386
+
387
+ function findTomlSection(document, sectionName) {
388
+ const path = parseTomlRequestedPath(sectionName);
389
+ return path
390
+ ? document.sections.find((section) => !section.arrayTable && sameTomlPath(section.path, path))
391
+ : null;
392
+ }
393
+
394
+ function findTomlAssignment(assignments, field, section) {
395
+ return assignments.find((entry) => (
396
+ entry.section === section
397
+ && entry.path.length === 1
398
+ && entry.path[0] === field
399
+ ));
400
+ }
401
+
402
+ function splitTopLevelTomlContent(content) {
403
+ const { topLevelEnd } = parseTomlDocument(content);
404
+ return {
405
+ topLevel: topLevelEnd === -1 ? content : content.slice(0, topLevelEnd),
406
+ rest: topLevelEnd === -1 ? "" : content.slice(topLevelEnd)
407
+ };
408
+ }
409
+
410
+ function extractTopLevelTomlEntries(content) {
411
+ const document = parseTomlDocument(content);
412
+ return document.assignments
413
+ .filter(({ path, section }) => section === null && path.length === 1)
414
+ .map((entry) => ({
415
+ field: entry.path[0],
416
+ raw: content.slice(entry.start, entry.end)
417
+ }));
418
+ }
419
+
420
+ function mergeMissingTopLevelTomlEntries(content, entries) {
421
+ if (!entries.length) {
422
+ return content;
423
+ }
424
+
425
+ const lineEnding = detectLineEnding(content);
426
+ const document = parseTomlDocument(content);
427
+ const topLevel = content.slice(0, document.topLevelEnd);
428
+ const rest = content.slice(document.topLevelEnd);
429
+ const existingFields = new Set(
430
+ document.assignments
431
+ .filter(({ path, section }) => section === null && path.length === 1)
432
+ .map(({ path }) => path[0])
433
+ );
434
+ const missingEntries = entries.filter(({ field }) => !existingFields.has(field));
435
+ if (!missingEntries.length) {
436
+ return content;
437
+ }
438
+
439
+ let nextTopLevel = topLevel.trimEnd();
440
+ for (const entry of missingEntries) {
441
+ nextTopLevel = nextTopLevel
442
+ ? `${nextTopLevel}${lineEnding}${entry.raw}`
443
+ : entry.raw;
444
+ }
445
+
446
+ nextTopLevel = nextTopLevel.trimEnd();
447
+ if (rest && nextTopLevel) {
448
+ nextTopLevel = `${nextTopLevel}${lineEnding}${lineEnding}`;
449
+ }
450
+ return `${nextTopLevel}${rest}`;
451
+ }
452
+
453
+ function applyTomlEdits(content, edits) {
454
+ let nextContent = content;
455
+ for (const { end, start, text } of edits.sort((left, right) => right.start - left.start)) {
456
+ nextContent = `${nextContent.slice(0, start)}${text}${nextContent.slice(end)}`;
457
+ }
458
+ return nextContent;
459
+ }
460
+
461
+ function updateTomlSectionFields(content, sectionName, values) {
462
+ const lineEnding = detectLineEnding(content);
463
+ const document = parseTomlDocument(content);
464
+ const section = findTomlSection(document, sectionName);
465
+
466
+ if (!section) {
467
+ const nextSection = buildTomlSection(sectionName, values, lineEnding).trimEnd();
468
+ return content.trimEnd()
469
+ ? `${content.trimEnd()}${lineEnding}${lineEnding}${nextSection}${lineEnding}`
470
+ : `${nextSection}${lineEnding}`;
471
+ }
472
+
473
+ const remaining = new Map(
474
+ Object.entries(values).filter(([, value]) => value !== undefined && value !== null && value !== "")
475
+ );
476
+ const managedFields = new Set(remaining.keys());
477
+ const seenFields = new Set();
478
+ const edits = [];
479
+
480
+ for (const entry of document.assignments) {
481
+ if (
482
+ entry.section !== section
483
+ || entry.path.length !== 1
484
+ || !managedFields.has(entry.path[0])
485
+ ) continue;
486
+ const field = entry.path[0];
487
+ if (seenFields.has(field)) {
488
+ edits.push({ end: entry.lineEnd, start: entry.start, text: "" });
489
+ } else {
490
+ edits.push({
491
+ end: entry.end,
492
+ start: entry.start,
493
+ text: `${entry.indent}${field} = ${formatTomlValue(remaining.get(field))}`
494
+ });
495
+ seenFields.add(field);
496
+ remaining.delete(field);
497
+ }
498
+ }
499
+
500
+ if (remaining.size) {
501
+ const leading = section.end > 0 && content[section.end - 1] !== "\n" ? lineEnding : "";
502
+ const lines = [...remaining].map(([field, value]) => `${field} = ${formatTomlValue(value)}`);
503
+ edits.push({
504
+ end: section.end,
505
+ start: section.end,
506
+ text: `${leading}${lines.join(lineEnding)}${lineEnding}`
507
+ });
508
+ }
509
+ return applyTomlEdits(content, edits);
510
+ }
511
+
512
+ function parseTomlBasicString(value) {
513
+ if (value[0] !== `"` || value.startsWith(`"""`)) return null;
514
+ let parsed = "";
515
+ for (let index = 1; index < value.length;) {
516
+ if (value[index] === `"`) {
517
+ return index === value.length - 1 ? parsed : null;
518
+ }
519
+ if (value[index] === "\\") {
520
+ const escape = readTomlBasicEscape(value, index);
521
+ if (!escape) return null;
522
+ parsed += escape.value;
523
+ index = escape.index;
524
+ } else {
525
+ parsed += value[index];
526
+ index += 1;
527
+ }
528
+ }
529
+ return null;
530
+ }
531
+
532
+ function parseTomlMultilineString(value, quote) {
533
+ const delimiter = quote.repeat(3);
534
+ if (!value.startsWith(delimiter)) return null;
535
+ let content = value.slice(3).replace(/\r\n/gu, "\n");
536
+ if (content.startsWith("\n")) content = content.slice(1);
537
+
538
+ let parsed = "";
539
+ for (let index = 0; index < content.length;) {
540
+ if (content.startsWith(delimiter, index)) {
541
+ let end = index + 3;
542
+ while (content[end] === quote) end += 1;
543
+ const quoteCount = end - index;
544
+ return quoteCount <= 5 && end === content.length
545
+ ? `${parsed}${quote.repeat(quoteCount - 3)}`
546
+ : null;
547
+ }
548
+
549
+ if (quote === `'` || content[index] !== "\\") {
550
+ parsed += content[index];
551
+ index += 1;
552
+ continue;
553
+ }
554
+
555
+ let continuation = index + 1;
556
+ while (content[continuation] === " " || content[continuation] === "\t") {
557
+ continuation += 1;
558
+ }
559
+ if (content[continuation] === "\n") {
560
+ index = continuation + 1;
561
+ while (content[index] === " " || content[index] === "\t" || content[index] === "\n") {
562
+ index += 1;
563
+ }
564
+ continue;
565
+ }
566
+
567
+ const escape = readTomlBasicEscape(content, index);
568
+ if (!escape) return null;
569
+ parsed += escape.value;
570
+ index = escape.index;
571
+ }
572
+ return parsed;
573
+ }
574
+
575
+ function parseTomlScalar(rawValue) {
576
+ const multilineBasic = parseTomlMultilineString(rawValue, `"`);
577
+ if (multilineBasic !== null) return { parsed: true, value: multilineBasic };
578
+ const multilineLiteral = parseTomlMultilineString(rawValue, `'`);
579
+ if (multilineLiteral !== null) return { parsed: true, value: multilineLiteral };
580
+ const value = rawValue.trim();
581
+ const basicString = parseTomlBasicString(value);
582
+ if (basicString !== null) return { parsed: true, value: basicString };
583
+ if (/^'[^']*'$/u.test(value)) return { parsed: true, value: value.slice(1, -1) };
584
+ if (value === "true" || value === "false") {
585
+ return { parsed: true, value: value === "true" };
586
+ }
587
+ if (/^-?\d+(?:\.\d+)?$/u.test(value)) {
588
+ return { parsed: true, value: Number(value) };
589
+ }
590
+ return { parsed: false, value: undefined };
591
+ }
592
+
593
+ function readTopLevelTomlString(content, field) {
594
+ const document = parseTomlDocument(content);
595
+ const entry = findTomlAssignment(document.assignments, field, null);
596
+ if (!entry) return "";
597
+ const value = parseTomlScalar(content.slice(entry.valueStart, entry.valueEnd));
598
+ return value.parsed && typeof value.value === "string" ? value.value : "";
599
+ }
600
+
601
+ function parseTomlSection(content, sectionName) {
602
+ const document = parseTomlDocument(content);
603
+ const section = findTomlSection(document, sectionName);
604
+ if (!section) return {};
605
+ const values = {};
606
+ for (const entry of document.assignments) {
607
+ if (entry.section !== section || entry.path.length !== 1) continue;
608
+ const value = parseTomlScalar(content.slice(entry.valueStart, entry.valueEnd));
609
+ if (value.parsed) values[entry.path[0]] = value.value;
610
+ }
611
+ return values;
612
+ }
613
+
614
+ function getTomlSectionFieldNames(content, sectionName) {
615
+ const document = parseTomlDocument(content);
616
+ const section = findTomlSection(document, sectionName);
617
+ if (!section) return [];
618
+ return document.assignments
619
+ .filter((entry) => entry.section === section && entry.path.length === 1)
620
+ .map((entry) => entry.path[0]);
621
+ }
622
+
623
+
624
+ export {
625
+ buildTomlSection,
626
+ detectLineEnding,
627
+ extractTopLevelTomlEntries,
628
+ formatTomlKeySegment,
629
+ getTomlSectionFieldNames,
630
+ mergeMissingTopLevelTomlEntries,
631
+ parseTomlSection,
632
+ readTopLevelTomlString,
633
+ removeTomlSection,
634
+ removeTopLevelTomlField,
635
+ splitTopLevelTomlContent,
636
+ updateTomlSectionFields,
637
+ updateTopLevelTomlField
638
+ };