frontier-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +104 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +10 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/domain.d.ts +230 -0
  7. package/dist/domain.d.ts.map +1 -0
  8. package/dist/domain.js +23 -0
  9. package/dist/domain.js.map +1 -0
  10. package/dist/edges.d.ts +35 -0
  11. package/dist/edges.d.ts.map +1 -0
  12. package/dist/edges.js +61 -0
  13. package/dist/edges.js.map +1 -0
  14. package/dist/frontier.d.ts +12 -0
  15. package/dist/frontier.d.ts.map +1 -0
  16. package/dist/frontier.js +34 -0
  17. package/dist/frontier.js.map +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/server.d.ts +29 -0
  23. package/dist/server.d.ts.map +1 -0
  24. package/dist/server.js +210 -0
  25. package/dist/server.js.map +1 -0
  26. package/dist/storage/driver.d.ts +131 -0
  27. package/dist/storage/driver.d.ts.map +1 -0
  28. package/dist/storage/driver.js +43 -0
  29. package/dist/storage/driver.js.map +1 -0
  30. package/dist/storage/markdown/create.d.ts +52 -0
  31. package/dist/storage/markdown/create.d.ts.map +1 -0
  32. package/dist/storage/markdown/create.js +298 -0
  33. package/dist/storage/markdown/create.js.map +1 -0
  34. package/dist/storage/markdown/driver.d.ts +7 -0
  35. package/dist/storage/markdown/driver.d.ts.map +1 -0
  36. package/dist/storage/markdown/driver.js +492 -0
  37. package/dist/storage/markdown/driver.js.map +1 -0
  38. package/dist/storage/markdown/frontmatter.d.ts +17 -0
  39. package/dist/storage/markdown/frontmatter.d.ts.map +1 -0
  40. package/dist/storage/markdown/frontmatter.js +36 -0
  41. package/dist/storage/markdown/frontmatter.js.map +1 -0
  42. package/dist/storage/markdown/header-doc.d.ts +56 -0
  43. package/dist/storage/markdown/header-doc.d.ts.map +1 -0
  44. package/dist/storage/markdown/header-doc.js +287 -0
  45. package/dist/storage/markdown/header-doc.js.map +1 -0
  46. package/dist/storage/markdown/legacy.d.ts +16 -0
  47. package/dist/storage/markdown/legacy.d.ts.map +1 -0
  48. package/dist/storage/markdown/legacy.js +152 -0
  49. package/dist/storage/markdown/legacy.js.map +1 -0
  50. package/dist/storage/markdown/migrate.d.ts +27 -0
  51. package/dist/storage/markdown/migrate.d.ts.map +1 -0
  52. package/dist/storage/markdown/migrate.js +158 -0
  53. package/dist/storage/markdown/migrate.js.map +1 -0
  54. package/dist/storage/markdown/serialize.d.ts +37 -0
  55. package/dist/storage/markdown/serialize.d.ts.map +1 -0
  56. package/dist/storage/markdown/serialize.js +321 -0
  57. package/dist/storage/markdown/serialize.js.map +1 -0
  58. package/dist/storage/markdown/ticket.d.ts +12 -0
  59. package/dist/storage/markdown/ticket.d.ts.map +1 -0
  60. package/dist/storage/markdown/ticket.js +97 -0
  61. package/dist/storage/markdown/ticket.js.map +1 -0
  62. package/dist/storage/markdown/write.d.ts +42 -0
  63. package/dist/storage/markdown/write.d.ts.map +1 -0
  64. package/dist/storage/markdown/write.js +134 -0
  65. package/dist/storage/markdown/write.js.map +1 -0
  66. package/dist/tools/create-tickets.d.ts +63 -0
  67. package/dist/tools/create-tickets.d.ts.map +1 -0
  68. package/dist/tools/create-tickets.js +161 -0
  69. package/dist/tools/create-tickets.js.map +1 -0
  70. package/dist/tools/edit-map.d.ts +29 -0
  71. package/dist/tools/edit-map.d.ts.map +1 -0
  72. package/dist/tools/edit-map.js +81 -0
  73. package/dist/tools/edit-map.js.map +1 -0
  74. package/dist/tools/get-board.d.ts +29 -0
  75. package/dist/tools/get-board.d.ts.map +1 -0
  76. package/dist/tools/get-board.js +190 -0
  77. package/dist/tools/get-board.js.map +1 -0
  78. package/dist/tools/get-tickets.d.ts +14 -0
  79. package/dist/tools/get-tickets.d.ts.map +1 -0
  80. package/dist/tools/get-tickets.js +56 -0
  81. package/dist/tools/get-tickets.js.map +1 -0
  82. package/dist/tools/list-efforts.d.ts +16 -0
  83. package/dist/tools/list-efforts.d.ts.map +1 -0
  84. package/dist/tools/list-efforts.js +38 -0
  85. package/dist/tools/list-efforts.js.map +1 -0
  86. package/dist/tools/migrate-effort.d.ts +11 -0
  87. package/dist/tools/migrate-effort.d.ts.map +1 -0
  88. package/dist/tools/migrate-effort.js +54 -0
  89. package/dist/tools/migrate-effort.js.map +1 -0
  90. package/dist/tools/spec.d.ts +12 -0
  91. package/dist/tools/spec.d.ts.map +1 -0
  92. package/dist/tools/spec.js +27 -0
  93. package/dist/tools/spec.js.map +1 -0
  94. package/dist/tools/update-ticket.d.ts +62 -0
  95. package/dist/tools/update-ticket.d.ts.map +1 -0
  96. package/dist/tools/update-ticket.js +164 -0
  97. package/dist/tools/update-ticket.js.map +1 -0
  98. package/dist/tracker-doc.d.ts +10 -0
  99. package/dist/tracker-doc.d.ts.map +1 -0
  100. package/dist/tracker-doc.js +16 -0
  101. package/dist/tracker-doc.js.map +1 -0
  102. package/dist/workspace-index.d.ts +39 -0
  103. package/dist/workspace-index.d.ts.map +1 -0
  104. package/dist/workspace-index.js +83 -0
  105. package/dist/workspace-index.js.map +1 -0
  106. package/dist/workspace-watcher.d.ts +24 -0
  107. package/dist/workspace-watcher.d.ts.map +1 -0
  108. package/dist/workspace-watcher.js +87 -0
  109. package/dist/workspace-watcher.js.map +1 -0
  110. package/dist/workspace.d.ts +23 -0
  111. package/dist/workspace.d.ts.map +1 -0
  112. package/dist/workspace.js +70 -0
  113. package/dist/workspace.js.map +1 -0
  114. package/docs/agents/issue-tracker.md +141 -0
  115. package/package.json +56 -0
@@ -0,0 +1,298 @@
1
+ import { mkdir, rename, rmdir, unlink, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { MINTED_ID } from '../../domain.js';
4
+ import { resolveDraftEdges } from '../../edges.js';
5
+ import { serializeNew } from './serialize.js';
6
+ import { stage, unstage } from './write.js';
7
+ /**
8
+ * How many times the batch will re-scan and start over when a parallel session
9
+ * lands an id between our scan and our guard. Each retry needs a real collision,
10
+ * so more than a couple means something other than contention.
11
+ */
12
+ const MAX_ATTEMPTS = 8;
13
+ /**
14
+ * A ceiling on how far a single batch will walk looking for free ids. Reached
15
+ * only when a workspace has collected a guard per candidate from crashed
16
+ * sessions, which is a broken state rather than a busy one.
17
+ */
18
+ const CANDIDATE_HEADROOM = 1000;
19
+ /**
20
+ * Create every Ticket in the batch, or none, and return the filenames written in
21
+ * the order asked for.
22
+ *
23
+ * Ids are `max + 1` over the whole workspace — derived, so there is no counter
24
+ * file to drift — and made safe against a parallel session by an exclusive
25
+ * create: `open(..., 'wx')` on a guard named for the candidate id, bumping to the
26
+ * next candidate on collision. The filesystem provides the mutual exclusion.
27
+ *
28
+ * The guard alone is not compare-and-set. A session that scanned before ours and
29
+ * finished writing after would hand us an id it has already used, so the batch
30
+ * re-scans *while holding every guard* and starts over if any candidate has
31
+ * turned up on disk. That is what makes the invariant hold: a file carrying id X
32
+ * is only ever written while X's guard is held, and the guard is only kept when a
33
+ * scan taken after acquiring it shows X unused — so two sessions can never both
34
+ * write X. See ADR 0005.
35
+ */
36
+ export async function createTicketFiles(request) {
37
+ const { scratch, effort, dir, issues, drafts, rescan, validate, createEffort } = request;
38
+ const { reservations, tickets } = await reserve(scratch, drafts.length, rescan);
39
+ try {
40
+ const ids = reservations.map(entry => entry.id);
41
+ // The last rule that can only be checked now: the ids are real, and nothing
42
+ // has been written or even created, so a refusal leaves no trace at all.
43
+ validate(ids, tickets);
44
+ const files = filesFor(effort, drafts, ids, tickets);
45
+ // After validation, so a refused batch never leaves an empty Effort behind —
46
+ // a bare issues/ directory is enough to make one show up in list_efforts.
47
+ await mkdir(issues, { recursive: true });
48
+ try {
49
+ await writeAll(issues, files);
50
+ }
51
+ catch (error) {
52
+ if (createEffort)
53
+ await discardEffort(dir, issues);
54
+ throw error;
55
+ }
56
+ return files.map(file => file.filename);
57
+ }
58
+ finally {
59
+ // Released only once every file is on disk. A guard held across the write is
60
+ // the whole guarantee; releasing early would reopen the window it closes.
61
+ await release(reservations);
62
+ }
63
+ }
64
+ /**
65
+ * Hold exclusive id guards for `count` fresh ids, run `use`, then release.
66
+ * Migration mints through this so a parallel create_tickets cannot collide.
67
+ */
68
+ export async function withIdReservations(scratch, count, rescan, use) {
69
+ if (count === 0)
70
+ return use([]);
71
+ const { reservations } = await reserve(scratch, count, rescan);
72
+ try {
73
+ return await use(reservations.map(entry => entry.id));
74
+ }
75
+ finally {
76
+ await release(reservations);
77
+ }
78
+ }
79
+ /**
80
+ * The next `count` minted ids from a scan, without taking guards. Preview uses
81
+ * this so a dry run never leaves `.frontier-id-*.guard` files behind.
82
+ */
83
+ export function peekMintedIds(used, count) {
84
+ const ids = [];
85
+ let candidate = highestMinted(used) + 1;
86
+ while (ids.length < count) {
87
+ const id = `T${String(candidate)}`;
88
+ if (!used.has(id))
89
+ ids.push(id);
90
+ candidate += 1;
91
+ }
92
+ return ids;
93
+ }
94
+ /** The cosmetic filename convention: `<NN>-T<n>-<slug>.md`. */
95
+ export function ticketFilename(order, id, title) {
96
+ return `${pad(order)}-${id}-${slugify(title)}.md`;
97
+ }
98
+ /**
99
+ * Remove an Effort this call made and then failed to fill. `rmdir` rather than a
100
+ * recursive delete: it fails with ENOTEMPTY on a directory holding anything,
101
+ * which is exactly right if a concurrent session has already put something
102
+ * there. Never a recursive `rm` — this runs on a failure path, where being wrong
103
+ * about which directory it is would destroy somebody's work.
104
+ */
105
+ async function discardEffort(dir, issues) {
106
+ await rmdir(issues).catch(() => { });
107
+ await rmdir(dir).catch(() => { });
108
+ }
109
+ /**
110
+ * Turn the drafts into files. Temporary keys resolve here, against the ids the
111
+ * batch just reserved — the same resolution the cycle check validated, so the
112
+ * graph that was approved is the graph that gets written.
113
+ */
114
+ function filesFor(effort, drafts, ids, tickets) {
115
+ const resolve = resolveDraftEdges(drafts, ids);
116
+ const firstOrder = nextOrder(tickets, effort);
117
+ return drafts.map((draft, index) => {
118
+ const id = ids[index];
119
+ if (id === undefined)
120
+ throw new Error('Reserved fewer ids than there are Tickets to create.');
121
+ const contents = serializeNew({
122
+ id,
123
+ title: draft.title,
124
+ kind: draft.kind,
125
+ type: draft.type,
126
+ status: 'open',
127
+ triage: draft.triage,
128
+ blockedBy: draft.blockedBy.map(resolve),
129
+ }, draft.body);
130
+ return { filename: ticketFilename(firstOrder + index, id, draft.title), contents };
131
+ });
132
+ }
133
+ /**
134
+ * Stage every file beside its target, then rename them all into place. Both
135
+ * phases settle in full before the next begins, because a `Promise.all` that
136
+ * rejects on the first failure leaves its siblings running — and a rename
137
+ * landing after the cleanup ran is the orphan this is trying to prevent.
138
+ *
139
+ * Splitting the phases is what makes "all or none" true of the batch rather than
140
+ * only of each file. Everything that can fail — a full disk, a bad path — fails
141
+ * in the staging phase, where nothing is visible yet. By the time the renames
142
+ * start, every file exists in the directory it is going into, and a rename
143
+ * within one directory is atomic and essentially cannot fail.
144
+ */
145
+ async function writeAll(issues, files) {
146
+ const staged = await Promise.allSettled(files.map(async (file) => ({
147
+ temporary: await stage(join(issues, file.filename), file.contents),
148
+ target: join(issues, file.filename),
149
+ })));
150
+ const ready = staged.filter(entry => entry.status === 'fulfilled').map(entry => entry.value);
151
+ const failed = staged.find(entry => entry.status === 'rejected');
152
+ if (failed !== undefined) {
153
+ await Promise.allSettled(ready.map(entry => unstage(entry.temporary)));
154
+ throw failed.reason;
155
+ }
156
+ const renamed = await Promise.allSettled(ready.map(async (entry) => {
157
+ // Two batches racing on one Effort can pick the same sort order, which is
158
+ // cosmetic — the id beside it still differs, so the names cannot actually
159
+ // collide. This is the assertion of that rather than a case with a path to
160
+ // it: a target that exists would be a Ticket this write was about to
161
+ // destroy.
162
+ await rename(entry.temporary, entry.target);
163
+ return entry.target;
164
+ }));
165
+ const landed = renamed.filter(entry => entry.status === 'fulfilled').map(entry => entry.value);
166
+ const lost = renamed.find(entry => entry.status === 'rejected');
167
+ if (lost !== undefined) {
168
+ await Promise.allSettled([
169
+ ...landed.map(path => unlink(path).catch(() => { })),
170
+ ...ready.map(entry => unstage(entry.temporary)),
171
+ ]);
172
+ throw lost.reason;
173
+ }
174
+ }
175
+ async function reserve(scratch, count, rescan, attempt = 1) {
176
+ const used = idsOf(await rescan());
177
+ const reservations = await claim(scratch, used, count, highestMinted(used) + 1, []);
178
+ let settled;
179
+ try {
180
+ settled = await rescan();
181
+ }
182
+ catch (error) {
183
+ await release(reservations);
184
+ throw error;
185
+ }
186
+ const taken = idsOf(settled);
187
+ const redundant = reservations.filter(entry => taken.has(entry.id));
188
+ if (redundant.length === 0)
189
+ return { reservations, tickets: settled };
190
+ await release(reservations);
191
+ if (attempt >= MAX_ATTEMPTS) {
192
+ throw new Error(`Could not reserve ${String(count)} Ticket ids after ${String(MAX_ATTEMPTS)} attempts — ` +
193
+ 'another session is creating Tickets continuously. Retry in a moment.');
194
+ }
195
+ return reserve(scratch, count, rescan, attempt + 1);
196
+ }
197
+ function release(reservations) {
198
+ return Promise.allSettled(reservations.map(entry => unlink(entry.guard).catch(() => { })));
199
+ }
200
+ /**
201
+ * Walk candidates, taking a guard on each. Recursive rather than a loop because
202
+ * each attempt depends on the one before it, and a bumped candidate is the
203
+ * normal case rather than an error.
204
+ */
205
+ async function claim(scratch, used, count, candidate, taken) {
206
+ if (taken.length === count)
207
+ return taken;
208
+ if (candidate > highestMinted(used) + CANDIDATE_HEADROOM + count) {
209
+ await release(taken);
210
+ throw new Error(`No free Ticket id within ${String(CANDIDATE_HEADROOM)} of the highest in use. ` +
211
+ 'Sweep the abandoned .frontier-id-*.guard files under .scratch/.');
212
+ }
213
+ const id = `T${String(candidate)}`;
214
+ if (used.has(id))
215
+ return claim(scratch, used, count, candidate + 1, taken);
216
+ const guard = guardFor(scratch, id);
217
+ // A guard we cannot take belongs to a session that is still allocating. Bump
218
+ // rather than wait: an id may be skipped, never reused.
219
+ if (!(await hold(guard)))
220
+ return claim(scratch, used, count, candidate + 1, taken);
221
+ return claim(scratch, used, count, candidate + 1, [...taken, { id, guard }]);
222
+ }
223
+ /**
224
+ * Take a guard, or report that somebody else has it.
225
+ *
226
+ * A guard is **never** broken, only bumped past, and that is the whole of the
227
+ * concurrency story here. Every scheme for reclaiming one — an age threshold, a
228
+ * liveness check on the pid inside it — has the same shape: read the guard,
229
+ * decide it is abandoned, then remove it. The decision goes stale between those
230
+ * two steps, and a session that removes a guard another session has just taken
231
+ * hands both of them the same id. That is the exact defect this file exists to
232
+ * prevent, so it is not reintroduced to tidy up after crashes.
233
+ *
234
+ * The cost is a guard left by a crashed session, which makes one id number
235
+ * unusable. Ids are promised never to be *reused*, never to run without gaps, so
236
+ * a skipped number costs nothing; the file is hidden, one line, and names the
237
+ * process that left it. {@link CANDIDATE_HEADROOM} bounds how many can pile up
238
+ * before allocation says so and points at them.
239
+ */
240
+ async function hold(guard) {
241
+ try {
242
+ await writeFile(guard, `${String(process.pid)}\n`, { flag: 'wx' });
243
+ return true;
244
+ }
245
+ catch (error) {
246
+ if (error?.code !== 'EEXIST')
247
+ throw error;
248
+ return false;
249
+ }
250
+ }
251
+ /**
252
+ * Beside the Efforts rather than inside one, because the counter is repo-global:
253
+ * two sessions creating into different Efforts must still collide here. Hidden
254
+ * and not `.md`, so no scan mistakes it for a Ticket, and `.scratch/` yields it
255
+ * no Effort because it is not a directory.
256
+ */
257
+ function guardFor(scratch, id) {
258
+ return join(scratch, `.frontier-id-${id}.guard`);
259
+ }
260
+ function idsOf(tickets) {
261
+ return new Set(tickets.map(entry => entry.id).filter(id => id !== undefined));
262
+ }
263
+ /**
264
+ * The counter, derived. Ids preserved verbatim through migration need not look
265
+ * like `T<n>` at all; those still occupy their name but contribute no number.
266
+ */
267
+ function highestMinted(used) {
268
+ let highest = 0;
269
+ for (const id of used) {
270
+ const digits = MINTED_ID.exec(id)?.[1];
271
+ if (digits !== undefined)
272
+ highest = Math.max(highest, Number(digits));
273
+ }
274
+ return highest;
275
+ }
276
+ /** `NN` is sort order within the Effort and nothing else, so it simply continues. */
277
+ function nextOrder(tickets, effort) {
278
+ const orders = tickets.filter(entry => entry.effort === effort).map(entry => entry.order);
279
+ return orders.length === 0 ? 1 : Math.max(...orders) + 1;
280
+ }
281
+ function pad(order) {
282
+ return String(order).padStart(2, '0');
283
+ }
284
+ /**
285
+ * The cosmetic half of a filename. It exists so a directory listing reads, and
286
+ * carries no identity — the id beside it does, and the frontmatter is the
287
+ * authority over both.
288
+ */
289
+ function slugify(title) {
290
+ const slug = title
291
+ .toLowerCase()
292
+ .replace(/[^a-z0-9]+/g, '-')
293
+ .replace(/^-+|-+$/g, '')
294
+ .slice(0, 48)
295
+ .replace(/-+$/, '');
296
+ return slug === '' ? 'ticket' : slug;
297
+ }
298
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/storage/markdown/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { StorageDriver } from '../driver.ts';
2
+ /**
3
+ * The markdown driver — the only driver in v1. Bound to `root`, the resolved
4
+ * workspace, so that no path crosses the {@link StorageDriver} interface.
5
+ */
6
+ export declare function createMarkdownDriver(root: string): StorageDriver;
7
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/storage/markdown/driver.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,cAAc,CAAC;AAsCtB;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAsFhE"}