tldr-experts 0.3.0 → 0.4.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 (36) hide show
  1. package/CHANGELOG.md +1957 -0
  2. package/README.md +99 -12
  3. package/dist/hooks/answer-capture.js +21 -12
  4. package/dist/hooks/budget-gate.js +95 -11
  5. package/dist/hooks/{chunk-0bt6yb2q.js → chunk-39zh2e44.js} +10 -1
  6. package/dist/hooks/chunk-4cp363kv.js +1766 -0
  7. package/dist/hooks/{chunk-t8tdv11p.js → chunk-7y2dq0pj.js} +1 -1
  8. package/dist/hooks/chunk-9zsqxr6y.js +213 -0
  9. package/dist/hooks/{chunk-a8p2rc94.js → chunk-b8kxzna2.js} +1 -1
  10. package/dist/hooks/{chunk-j234zf0t.js → chunk-c6t5nx0r.js} +37 -166
  11. package/dist/hooks/{chunk-g395gk7e.js → chunk-m3mewgnw.js} +36 -17
  12. package/dist/hooks/chunk-phmdk72a.js +164 -0
  13. package/dist/hooks/chunk-rpcxsqh3.js +199 -0
  14. package/dist/hooks/{chunk-azctppjh.js → chunk-rz541e2b.js} +7 -1
  15. package/dist/hooks/{chunk-y0jdr3et.js → chunk-s1c5h7yx.js} +71 -29
  16. package/dist/hooks/{chunk-p274ckxv.js → chunk-sq44k6g2.js} +155 -12
  17. package/dist/hooks/{chunk-x98qs959.js → chunk-t1ywrfr4.js} +35 -42
  18. package/dist/hooks/{chunk-1zwcxd3f.js → chunk-tzzwddct.js} +1 -1
  19. package/dist/hooks/claim-sources.js +31 -23
  20. package/dist/hooks/dod-gate.js +12 -37
  21. package/dist/hooks/no-reask.js +9 -9
  22. package/dist/hooks/session-start.js +176 -422
  23. package/dist/hooks/statusline.js +14 -11
  24. package/dist/tldrx.js +22798 -12309
  25. package/package.json +3 -1
  26. package/plugin/.claude-plugin/plugin.json +1 -1
  27. package/plugin/skills/tldrx/SKILL.md +16 -3
  28. package/stages/build/stage.md +5 -0
  29. package/stages/build/stage.yml +2 -1
  30. package/stages/plan/stage.md +11 -0
  31. package/templates/budget.yml +5 -0
  32. package/templates/epic.md +5 -3
  33. package/dist/hooks/chunk-ae6bkfs5.js +0 -0
  34. package/dist/hooks/chunk-kw4tffzf.js +0 -139
  35. package/dist/hooks/chunk-sdjnnmzz.js +0 -497
  36. package/dist/hooks/chunk-t56k6146.js +0 -14
@@ -7284,6 +7284,93 @@ var runtime = onBun ? bunRuntime : nodeRuntime;
7284
7284
  function parseYaml(text) {
7285
7285
  return runtime.parseYaml(text);
7286
7286
  }
7287
+ function parseYamlRepairing(text) {
7288
+ try {
7289
+ return { doc: parseYaml(text), repaired: false };
7290
+ } catch (original) {
7291
+ const mended = rejoinBrokenQuotedScalars(text);
7292
+ if (mended === null)
7293
+ throw original;
7294
+ try {
7295
+ return { doc: parseYaml(mended), repaired: true };
7296
+ } catch {
7297
+ throw original;
7298
+ }
7299
+ }
7300
+ }
7301
+ function rejoinBrokenQuotedScalars(text) {
7302
+ const out = [];
7303
+ let changed = false;
7304
+ let inDouble = false;
7305
+ let inSingle = false;
7306
+ for (let i = 0;i < text.length; i++) {
7307
+ const ch = text[i];
7308
+ if (inDouble) {
7309
+ if (ch === "\\") {
7310
+ out.push(ch, text[i + 1] ?? "");
7311
+ i++;
7312
+ continue;
7313
+ }
7314
+ if (ch === '"') {
7315
+ inDouble = false;
7316
+ out.push(ch);
7317
+ continue;
7318
+ }
7319
+ const escaped = CONTROL_ESCAPES[ch];
7320
+ if (escaped !== undefined) {
7321
+ out.push(escaped);
7322
+ changed = true;
7323
+ continue;
7324
+ }
7325
+ out.push(ch);
7326
+ continue;
7327
+ }
7328
+ if (inSingle) {
7329
+ if (ch === "'") {
7330
+ if (text[i + 1] === "'") {
7331
+ out.push(ch, ch);
7332
+ i++;
7333
+ } else {
7334
+ inSingle = false;
7335
+ out.push(ch);
7336
+ }
7337
+ continue;
7338
+ }
7339
+ out.push(ch);
7340
+ continue;
7341
+ }
7342
+ if (ch === '"')
7343
+ inDouble = true;
7344
+ else if (ch === "'")
7345
+ inSingle = true;
7346
+ else if (ch === "#" && (i === 0 || text[i - 1] === " " || text[i - 1] === `
7347
+ `)) {
7348
+ const end = text.indexOf(`
7349
+ `, i);
7350
+ const stop = end === -1 ? text.length : end;
7351
+ out.push(text.slice(i, stop));
7352
+ i = stop - 1;
7353
+ continue;
7354
+ }
7355
+ out.push(ch);
7356
+ }
7357
+ if (inDouble)
7358
+ return null;
7359
+ return changed ? out.join("") : null;
7360
+ }
7361
+ var CONTROL_ESCAPES = {
7362
+ "\n": "\\n",
7363
+ "\r": "\\r",
7364
+ "\v": "\\v",
7365
+ "\f": "\\f",
7366
+ "\x00": "\\0",
7367
+ "\x07": "\\a",
7368
+ "\b": "\\b",
7369
+ "\x1B": "\\e",
7370
+ "…": "\\N",
7371
+ "\u2028": "\\L",
7372
+ "\u2029": "\\P"
7373
+ };
7287
7374
 
7288
7375
  // src/core/paths.ts
7289
7376
  import { dirname as dirname2, join } from "node:path";
@@ -7313,10 +7400,15 @@ var TEMPLATES_DIR = join(FRAMEWORK_ROOT, "templates");
7313
7400
  var PLUGIN_DIR = join(FRAMEWORK_ROOT, "plugin");
7314
7401
  var PROJECT_FRAMEWORK_DIR = ".tldrx";
7315
7402
  var PROJECT_WORK_DIR = "tldrx-work";
7403
+ var PROJECT_WORKTREES_DIR = "worktrees";
7404
+ var EPIC_WORKTREE_PREFIX = "_epic-";
7405
+ function isEpicWorktreeOf(name, runId) {
7406
+ return name.startsWith(`${EPIC_WORKTREE_PREFIX}${runId}-`);
7407
+ }
7316
7408
 
7317
7409
  // src/hooks/lib/workspace.ts
7318
7410
  import { existsSync as existsSync2, readdirSync, readFileSync, statSync as statSync2 } from "node:fs";
7319
- import { dirname as dirname3, isAbsolute, join as join2, resolve, sep } from "node:path";
7411
+ import { basename, dirname as dirname3, isAbsolute, join as join2, resolve, sep } from "node:path";
7320
7412
  function locateWork(filePath) {
7321
7413
  if (filePath === "")
7322
7414
  return null;
@@ -7348,10 +7440,32 @@ function findWorkspaceRoot(start) {
7348
7440
  return null;
7349
7441
  }
7350
7442
  var FALLBACK_DEFAULT_BRANCH = "main";
7443
+ function commandRolesOf(doc) {
7444
+ const out = new Map;
7445
+ const list = doc?.repos;
7446
+ if (!Array.isArray(list))
7447
+ return out;
7448
+ for (const entry of list) {
7449
+ if (typeof entry?.name !== "string")
7450
+ continue;
7451
+ const roles = new Map;
7452
+ const cmds = entry.commands;
7453
+ if (cmds !== null && typeof cmds === "object") {
7454
+ for (const [role, value] of Object.entries(cmds)) {
7455
+ if (typeof value !== "string" || value.trim() === "")
7456
+ continue;
7457
+ roles.set(role, value);
7458
+ }
7459
+ }
7460
+ out.set(entry.name, roles);
7461
+ }
7462
+ return out;
7463
+ }
7351
7464
  function loadWorkspace(root) {
7352
7465
  const repos = new Map;
7353
7466
  const commands = new Set;
7354
7467
  const repoCommands = new Map;
7468
+ const commandRoles = new Map;
7355
7469
  const defaultBranches = new Map;
7356
7470
  let seedTriageThresholdTokens = null;
7357
7471
  const empty = () => ({
@@ -7359,6 +7473,7 @@ function loadWorkspace(root) {
7359
7473
  repos,
7360
7474
  commands,
7361
7475
  repoCommands,
7476
+ commandRoles,
7362
7477
  defaultBranches,
7363
7478
  seedTriageThresholdTokens
7364
7479
  });
@@ -7381,23 +7496,21 @@ function loadWorkspace(root) {
7381
7496
  const list = doc?.repos;
7382
7497
  if (!Array.isArray(list))
7383
7498
  return empty();
7499
+ const declared = commandRolesOf(doc);
7384
7500
  for (const entry of list) {
7385
7501
  if (typeof entry?.name !== "string")
7386
7502
  continue;
7387
7503
  repos.set(entry.name, typeof entry.path === "string" ? entry.path : ".");
7388
7504
  defaultBranches.set(entry.name, typeof entry.default_branch === "string" && entry.default_branch !== "" ? entry.default_branch : FALLBACK_DEFAULT_BRANCH);
7389
7505
  const own = [];
7390
- const cmds = entry.commands;
7391
- if (cmds !== null && typeof cmds === "object") {
7392
- for (const value of Object.values(cmds)) {
7393
- if (typeof value !== "string" || value.trim() === "")
7394
- continue;
7395
- commands.add(value);
7396
- if (!own.includes(value))
7397
- own.push(value);
7398
- }
7506
+ const roles = declared.get(entry.name) ?? new Map;
7507
+ for (const value of roles.values()) {
7508
+ commands.add(value);
7509
+ if (!own.includes(value))
7510
+ own.push(value);
7399
7511
  }
7400
7512
  repoCommands.set(entry.name, own);
7513
+ commandRoles.set(entry.name, roles);
7401
7514
  }
7402
7515
  return empty();
7403
7516
  }
@@ -7406,9 +7519,39 @@ function toSrcContext(workspace, runDir) {
7406
7519
  root: workspace.root,
7407
7520
  repos: workspace.repos,
7408
7521
  commands: workspace.commands,
7409
- runDir: runDir ?? null
7522
+ runDir: runDir ?? null,
7523
+ epicWorktrees: epicWorktreesOf(workspace, runDir ?? null)
7410
7524
  };
7411
7525
  }
7526
+ function epicWorktreesOf(workspace, runDir) {
7527
+ if (runDir === null || runDir === "")
7528
+ return [];
7529
+ const runId = basename(runDir);
7530
+ if (runId === "")
7531
+ return [];
7532
+ const trees = [];
7533
+ for (const repo of workspace.repos.keys()) {
7534
+ const dir = join2(workspace.root, PROJECT_FRAMEWORK_DIR, PROJECT_WORKTREES_DIR, repo);
7535
+ if (!existsSync2(dir))
7536
+ continue;
7537
+ let entries;
7538
+ try {
7539
+ entries = readdirSync(dir);
7540
+ } catch {
7541
+ continue;
7542
+ }
7543
+ for (const name of entries.slice().sort()) {
7544
+ if (!isEpicWorktreeOf(name, runId))
7545
+ continue;
7546
+ const abs = join2(dir, name);
7547
+ try {
7548
+ if (statSync2(abs).isDirectory())
7549
+ trees.push({ repo, dir: abs });
7550
+ } catch {}
7551
+ }
7552
+ }
7553
+ return trees;
7554
+ }
7412
7555
  function repoPath(workspace, name) {
7413
7556
  const rel = workspace.repos.get(name);
7414
7557
  return rel === undefined ? null : join2(workspace.root, rel);
@@ -7432,4 +7575,4 @@ function listRunDirs(root) {
7432
7575
  return dirs.sort().reverse();
7433
7576
  }
7434
7577
 
7435
- export { runtime, parseYaml, STAGES_DIR, TEMPLATES_DIR, PROJECT_FRAMEWORK_DIR, PROJECT_WORK_DIR, locateWork, findWorkspaceRoot, loadWorkspace, toSrcContext, repoPath, factsPath, stageYamlPath, listRunDirs };
7578
+ export { runtime, parseYaml, parseYamlRepairing, STAGES_DIR, TEMPLATES_DIR, PROJECT_FRAMEWORK_DIR, PROJECT_WORK_DIR, locateWork, findWorkspaceRoot, loadWorkspace, toSrcContext, repoPath, factsPath, stageYamlPath, listRunDirs };
@@ -1,11 +1,20 @@
1
1
  import {
2
2
  emitFactsYaml,
3
3
  withWorkspaceLock,
4
- workspaceRootOfFactsPath
5
- } from "./chunk-j234zf0t.js";
4
+ workspaceRootOfFactsPath,
5
+ writeAtomic
6
+ } from "./chunk-c6t5nx0r.js";
6
7
  import {
8
+ FACT_CONFIDENCES,
9
+ FACT_KINDS,
10
+ MAX_FACTS,
11
+ MAX_FACT_CHARS,
12
+ factNumber,
13
+ formatFactId,
14
+ isLive,
15
+ isRetired,
7
16
  noteDeprecations
8
- } from "./chunk-t56k6146.js";
17
+ } from "./chunk-rpcxsqh3.js";
9
18
  import {
10
19
  asDocument,
11
20
  isRecord,
@@ -15,29 +24,13 @@ import {
15
24
  requireString,
16
25
  requireVersion,
17
26
  result
18
- } from "./chunk-0bt6yb2q.js";
27
+ } from "./chunk-39zh2e44.js";
19
28
  import {
20
29
  parseYaml
21
- } from "./chunk-p274ckxv.js";
30
+ } from "./chunk-sq44k6g2.js";
22
31
 
23
32
  // src/core/facts/FactsStore.ts
24
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
25
- import { dirname } from "node:path";
26
-
27
- // src/core/facts/Fact.ts
28
- var FACT_KINDS = ["answer", "observed", "derived"];
29
- var FACT_CONFIDENCES = ["measured", "inferred", "stated"];
30
- var MAX_FACTS = 5000;
31
- var MAX_FACT_CHARS = 300;
32
- function isRetired(fact) {
33
- return fact.retired !== null && fact.retired.at !== null;
34
- }
35
- function factNumber(id) {
36
- return Number.parseInt(id.slice(1), 10);
37
- }
38
- function formatFactId(n) {
39
- return `F${String(n).padStart(3, "0")}`;
40
- }
33
+ import { existsSync, readFileSync } from "node:fs";
41
34
 
42
35
  // src/core/facts/validateFactsFile.ts
43
36
  var ID_RE = /^F\d{3,6}$/;
@@ -94,6 +87,9 @@ function validateFactsFile(input) {
94
87
  } else if (row.source !== undefined) {
95
88
  issues.push({ path: `${path}.source`, message: "expected a mapping" });
96
89
  }
90
+ if (row.truncated !== undefined && typeof row.truncated !== "boolean") {
91
+ issues.push({ path: `${path}.truncated`, message: "expected true, false or absent" });
92
+ }
97
93
  const superseded = typeof row.superseded_by === "string";
98
94
  const retired = isRecord(row.retired) && row.retired.at !== null && row.retired.at !== undefined;
99
95
  if (superseded && retired) {
@@ -158,7 +154,7 @@ function findDuplicate(question, area, facts, threshold = DEFAULT_JACCARD_THRESH
158
154
  for (const fact of facts) {
159
155
  if (fact.area !== area)
160
156
  continue;
161
- if (isRetired(fact))
157
+ if (!isLive(fact))
162
158
  continue;
163
159
  const score = jaccard(asked, tokenize(fact.fact));
164
160
  if (score < threshold)
@@ -204,7 +200,7 @@ class FactsStore {
204
200
  return this.rows;
205
201
  }
206
202
  get active() {
207
- return this.rows.filter((f) => !isRetired(f));
203
+ return this.rows.filter(isLive);
208
204
  }
209
205
  get(id) {
210
206
  return this.rows.find((f) => f.id === id);
@@ -214,9 +210,10 @@ class FactsStore {
214
210
  return formatFactId(highest + 1);
215
211
  }
216
212
  append(input) {
213
+ const cut = input.fact.length > MAX_FACT_CHARS;
217
214
  const fact = {
218
215
  id: this.nextId(),
219
- fact: input.fact.length > MAX_FACT_CHARS ? `${input.fact.slice(0, MAX_FACT_CHARS - 1)}…` : input.fact,
216
+ fact: cut ? `${input.fact.slice(0, MAX_FACT_CHARS - 1)}…` : input.fact,
220
217
  area: input.area,
221
218
  repos: [...input.repos],
222
219
  kind: input.kind,
@@ -224,11 +221,21 @@ class FactsStore {
224
221
  source: { ...input.source },
225
222
  supersedes: input.supersedes ?? null,
226
223
  superseded_by: null,
227
- retired: input.retired ?? null
224
+ retired: input.retired ?? null,
225
+ ...cut || input.truncated === true ? { truncated: true } : {}
228
226
  };
229
227
  this.rows.push(fact);
230
228
  return fact;
231
229
  }
230
+ headOf(id) {
231
+ let fact = this.get(id);
232
+ for (let step = 0;fact !== undefined && fact.superseded_by !== null; step++) {
233
+ if (step >= this.rows.length)
234
+ return;
235
+ fact = this.get(fact.superseded_by);
236
+ }
237
+ return fact;
238
+ }
232
239
  supersede(oldId, input) {
233
240
  const index = this.rows.findIndex((f) => f.id === oldId);
234
241
  if (index === -1)
@@ -272,7 +279,7 @@ class FactsStore {
272
279
  throw new Error(`refusing to write an invalid facts.yml: ${first?.path ?? ""} ${first?.message ?? ""}`);
273
280
  }
274
281
  withWorkspaceLock(workspaceRootOfFactsPath(path), () => {
275
- writeFactsAtomic(path, text);
282
+ writeAtomic(path, text);
276
283
  });
277
284
  }
278
285
  static update(path, fn) {
@@ -284,19 +291,5 @@ class FactsStore {
284
291
  });
285
292
  }
286
293
  }
287
- function writeFactsAtomic(path, text) {
288
- const temp = `${path}.tmp-${String(process.pid)}`;
289
- mkdirSync(dirname(path), { recursive: true });
290
- try {
291
- writeFileSync(temp, text, "utf8");
292
- renameSync(temp, path);
293
- } catch (error) {
294
- try {
295
- if (existsSync(temp))
296
- rmSync(temp, { force: true });
297
- } catch {}
298
- throw error;
299
- }
300
- }
301
294
 
302
- export { MAX_FACT_CHARS, FactsStore };
295
+ export { FactsStore };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseHookInput,
3
3
  readStdin
4
- } from "./chunk-a8p2rc94.js";
4
+ } from "./chunk-b8kxzna2.js";
5
5
 
6
6
  // src/hooks/lib/decide.ts
7
7
  function deny(reason) {
@@ -1,17 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  wouldBeContent
4
- } from "./chunk-t8tdv11p.js";
4
+ } from "./chunk-7y2dq0pj.js";
5
5
  import {
6
6
  claimSourcesDeny,
7
7
  claimSourcesEmptySectionDeny,
8
8
  claimSourcesMalformedDeny,
9
9
  claimSourcesUnresolvedDeny
10
10
  } from "./chunk-9gb21660.js";
11
- import {
12
- isHandoff,
13
- validateHandoff
14
- } from "./chunk-kw4tffzf.js";
15
11
  import {
16
12
  allow,
17
13
  deny,
@@ -20,14 +16,19 @@ import {
20
16
  postContext,
21
17
  readPayload,
22
18
  runHook
23
- } from "./chunk-1zwcxd3f.js";
24
- import"./chunk-a8p2rc94.js";
25
- import"./chunk-g395gk7e.js";
19
+ } from "./chunk-tzzwddct.js";
20
+ import"./chunk-b8kxzna2.js";
21
+ import {
22
+ isHandoff,
23
+ validateCitations,
24
+ validateHandoff
25
+ } from "./chunk-9zsqxr6y.js";
26
+ import"./chunk-m3mewgnw.js";
26
27
  import {
27
28
  loadWorkspace,
28
29
  locateWork,
29
30
  toSrcContext
30
- } from "./chunk-p274ckxv.js";
31
+ } from "./chunk-sq44k6g2.js";
31
32
 
32
33
  // src/hooks/claim-sources.ts
33
34
  await runHook("claim-sources", async () => {
@@ -43,24 +44,31 @@ await runHook("claim-sources", async () => {
43
44
  const wouldBe = wouldBeContent(payload, filePath);
44
45
  if (wouldBe.kind !== "content")
45
46
  return;
46
- const looksLikeHandoff = filePath.endsWith("handoff.md") || isHandoff(wouldBe.text);
47
- if (!looksLikeHandoff)
48
- return;
49
47
  const workspace = loadWorkspace(location.root);
50
- const report = validateHandoff(wouldBe.text, toSrcContext(workspace, location.runDir));
51
- if (report.ok)
52
- return;
48
+ const srcCtx = toSrcContext(workspace, location.runDir);
53
49
  const relPath = `tldrx-work/${location.run}/${location.relative}`;
54
50
  const parts = [];
55
- if (report.unsourced.length > 0)
56
- parts.push(claimSourcesDeny(relPath, report.unsourced));
57
- if (report.malformed.length > 0)
58
- parts.push(claimSourcesMalformedDeny(relPath, report.malformed));
59
- if (report.emptySections.length > 0) {
60
- parts.push(claimSourcesEmptySectionDeny(relPath, [...report.emptySections]));
51
+ const looksLikeHandoff = filePath.endsWith("handoff.md") || isHandoff(wouldBe.text);
52
+ if (looksLikeHandoff) {
53
+ const report = validateHandoff(wouldBe.text, srcCtx);
54
+ if (report.ok)
55
+ return;
56
+ if (report.unsourced.length > 0)
57
+ parts.push(claimSourcesDeny(relPath, report.unsourced));
58
+ if (report.malformed.length > 0)
59
+ parts.push(claimSourcesMalformedDeny(relPath, report.malformed));
60
+ if (report.emptySections.length > 0) {
61
+ parts.push(claimSourcesEmptySectionDeny(relPath, [...report.emptySections]));
62
+ }
63
+ if (report.unresolved.length > 0)
64
+ parts.push(claimSourcesUnresolvedDeny(relPath, report.unresolved));
65
+ } else {
66
+ const report = validateCitations(wouldBe.text, srcCtx);
67
+ if (report.malformed.length > 0)
68
+ parts.push(claimSourcesMalformedDeny(relPath, report.malformed));
69
+ if (report.unresolved.length > 0)
70
+ parts.push(claimSourcesUnresolvedDeny(relPath, report.unresolved));
61
71
  }
62
- if (report.unresolved.length > 0)
63
- parts.push(claimSourcesUnresolvedDeny(relPath, report.unresolved));
64
72
  if (parts.length === 0)
65
73
  return;
66
74
  const message = parts.join(`
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  wouldBeContent
4
- } from "./chunk-t8tdv11p.js";
4
+ } from "./chunk-7y2dq0pj.js";
5
5
  import {
6
6
  dodGateDeny,
7
7
  dodGateInternalErrorDeny,
@@ -15,54 +15,29 @@ import {
15
15
  filePathOf,
16
16
  isWriteOrEdit,
17
17
  readPayload
18
- } from "./chunk-1zwcxd3f.js";
19
- import"./chunk-a8p2rc94.js";
20
- import"./chunk-ae6bkfs5.js";
21
- import"./chunk-0bt6yb2q.js";
18
+ } from "./chunk-tzzwddct.js";
19
+ import"./chunk-b8kxzna2.js";
20
+ import {
21
+ parseDodBlock
22
+ } from "./chunk-phmdk72a.js";
23
+ import"./chunk-39zh2e44.js";
22
24
  import {
23
25
  loadWorkspace,
24
26
  locateWork,
25
27
  repoPath,
26
28
  runtime
27
- } from "./chunk-p274ckxv.js";
29
+ } from "./chunk-sq44k6g2.js";
28
30
 
29
31
  // src/hooks/dod-gate.ts
30
32
  import { basename, join } from "node:path";
31
33
  import { existsSync } from "node:fs";
32
34
 
33
- // src/core/schemas/story.ts
34
- var FENCE_OPEN_RE = /^\s*```+\s*dod\s*$/i;
35
- var FENCE_CLOSE_RE = /^\s*```+\s*$/;
36
- function parseDodBlock(text) {
37
- const commands = [];
38
- let present = false;
39
- let inside = false;
40
- for (const line of text.split(`
41
- `)) {
42
- if (inside) {
43
- if (FENCE_CLOSE_RE.test(line)) {
44
- inside = false;
45
- continue;
46
- }
47
- const command = line.trim();
48
- if (command !== "" && !command.startsWith("#"))
49
- commands.push(command);
50
- continue;
51
- }
52
- if (FENCE_OPEN_RE.test(line)) {
53
- present = true;
54
- inside = true;
55
- }
56
- }
57
- return { present, commands };
58
- }
59
-
60
35
  // src/hooks/lib/story.ts
61
36
  var DONE_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?status(?:\*\*)?\s*:\s*["'`]?done["'`]?\.?\s*$/i;
62
37
  var REPO_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?repo(?:\*\*)?\s*:\s*["'`]?([A-Za-z0-9._-]{1,64})["'`]?\s*$/i;
63
38
  var TIMEOUT_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?timeout_s(?:\*\*)?\s*:\s*(\d{1,6})\s*$/i;
64
- var FENCE_OPEN_RE2 = /^\s*```+\s*dod\s*$/i;
65
- var FENCE_CLOSE_RE2 = /^\s*```+\s*$/;
39
+ var FENCE_OPEN_RE = /^\s*```+\s*dod\s*$/i;
40
+ var FENCE_CLOSE_RE = /^\s*```+\s*$/;
66
41
  function readStory(text) {
67
42
  const lines = text.split(`
68
43
  `);
@@ -73,11 +48,11 @@ function readStory(text) {
73
48
  let inDod = false;
74
49
  for (const line of lines) {
75
50
  if (inDod) {
76
- if (FENCE_CLOSE_RE2.test(line))
51
+ if (FENCE_CLOSE_RE.test(line))
77
52
  inDod = false;
78
53
  continue;
79
54
  }
80
- if (FENCE_OPEN_RE2.test(line)) {
55
+ if (FENCE_OPEN_RE.test(line)) {
81
56
  inDod = true;
82
57
  continue;
83
58
  }
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  wouldBeContent
4
- } from "./chunk-t8tdv11p.js";
4
+ } from "./chunk-7y2dq0pj.js";
5
5
  import {
6
6
  noReAskDeny
7
7
  } from "./chunk-9gb21660.js";
8
8
  import {
9
9
  FactsStore
10
- } from "./chunk-x98qs959.js";
10
+ } from "./chunk-t1ywrfr4.js";
11
11
  import {
12
12
  allow,
13
13
  deny,
@@ -15,19 +15,19 @@ import {
15
15
  isWriteOrEdit,
16
16
  readPayload,
17
17
  runHook
18
- } from "./chunk-1zwcxd3f.js";
19
- import"./chunk-a8p2rc94.js";
18
+ } from "./chunk-tzzwddct.js";
19
+ import"./chunk-b8kxzna2.js";
20
+ import"./chunk-c6t5nx0r.js";
20
21
  import {
21
22
  openBlocks,
22
23
  parseQuestions
23
- } from "./chunk-j234zf0t.js";
24
- import"./chunk-t56k6146.js";
25
- import"./chunk-g395gk7e.js";
26
- import"./chunk-0bt6yb2q.js";
24
+ } from "./chunk-rpcxsqh3.js";
25
+ import"./chunk-m3mewgnw.js";
26
+ import"./chunk-39zh2e44.js";
27
27
  import {
28
28
  factsPath,
29
29
  locateWork
30
- } from "./chunk-p274ckxv.js";
30
+ } from "./chunk-sq44k6g2.js";
31
31
 
32
32
  // src/hooks/no-reask.ts
33
33
  import { existsSync, readFileSync } from "node:fs";