frontier-mcp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/dist/driver-registry.d.ts +15 -0
- package/dist/driver-registry.d.ts.map +1 -0
- package/dist/driver-registry.js +19 -0
- package/dist/driver-registry.js.map +1 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +57 -38
- package/dist/server.js.map +1 -1
- package/dist/storage/driver.d.ts +41 -8
- package/dist/storage/driver.d.ts.map +1 -1
- package/dist/storage/driver.js.map +1 -1
- package/dist/storage/markdown/create.d.ts +5 -5
- package/dist/storage/markdown/create.d.ts.map +1 -1
- package/dist/storage/markdown/create.js +17 -17
- package/dist/storage/markdown/create.js.map +1 -1
- package/dist/storage/markdown/driver.d.ts +35 -1
- package/dist/storage/markdown/driver.d.ts.map +1 -1
- package/dist/storage/markdown/driver.js +155 -84
- package/dist/storage/markdown/driver.js.map +1 -1
- package/dist/storage/markdown/migrate.d.ts +4 -4
- package/dist/storage/markdown/migrate.d.ts.map +1 -1
- package/dist/storage/markdown/migrate.js +1 -1
- package/dist/storage/markdown/migrate.js.map +1 -1
- package/dist/storage/markdown/ticket.d.ts +16 -5
- package/dist/storage/markdown/ticket.d.ts.map +1 -1
- package/dist/storage/markdown/ticket.js +19 -7
- package/dist/storage/markdown/ticket.js.map +1 -1
- package/dist/storage/markdown/watcher.d.ts +33 -0
- package/dist/storage/markdown/watcher.d.ts.map +1 -0
- package/dist/storage/markdown/watcher.js +142 -0
- package/dist/storage/markdown/watcher.js.map +1 -0
- package/dist/tools/create-tickets.d.ts +4 -4
- package/dist/tools/create-tickets.d.ts.map +1 -1
- package/dist/tools/create-tickets.js.map +1 -1
- package/dist/tools/list-efforts.d.ts.map +1 -1
- package/dist/tools/list-efforts.js +2 -1
- package/dist/tools/list-efforts.js.map +1 -1
- package/dist/tools/update-ticket.d.ts +3 -3
- package/dist/tools/update-ticket.d.ts.map +1 -1
- package/dist/tools/update-ticket.js.map +1 -1
- package/dist/tools/workspace-line.d.ts +18 -0
- package/dist/tools/workspace-line.d.ts.map +1 -0
- package/dist/tools/workspace-line.js +22 -0
- package/dist/tools/workspace-line.js.map +1 -0
- package/dist/workspace.d.ts +5 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +42 -5
- package/dist/workspace.js.map +1 -1
- package/docs/agents/issue-tracker.md +14 -2
- package/package.json +1 -1
- package/dist/workspace-index.d.ts +0 -39
- package/dist/workspace-index.d.ts.map +0 -1
- package/dist/workspace-index.js +0 -83
- package/dist/workspace-index.js.map +0 -1
- package/dist/workspace-watcher.d.ts +0 -24
- package/dist/workspace-watcher.d.ts.map +0 -1
- package/dist/workspace-watcher.js +0 -87
- package/dist/workspace-watcher.js.map +0 -1
package/README.md
CHANGED
|
@@ -36,8 +36,9 @@ Restart your editor after saving.
|
|
|
36
36
|
## First use in a repository
|
|
37
37
|
|
|
38
38
|
1. Open the repository in your editor. FrontierMCP resolves the workspace from the session working
|
|
39
|
-
directory — walking upward to the nearest `.scratch
|
|
40
|
-
only setup step.
|
|
39
|
+
directory — walking upward to the nearest `.scratch/`, or `.git` in either form — so opening the
|
|
40
|
+
project is the only setup step. A git worktree is its own workspace: it carries `.git` as a file,
|
|
41
|
+
and it is served instead of the repository it was made from.
|
|
41
42
|
2. Read the tracker configuration document once: fetch MCP resource `frontier://tracker-doc`, or read
|
|
42
43
|
[`docs/agents/issue-tracker.md`](docs/agents/issue-tracker.md) in a repo that vendors it.
|
|
43
44
|
3. Call `list_efforts` to see whether `.scratch/` exists yet.
|
|
@@ -53,6 +54,10 @@ Optional, per call or per session:
|
|
|
53
54
|
- Pass `root` on any tool call to read another directory.
|
|
54
55
|
- Set `FRONTIER_ROOT` in the server environment for a non-standard layout.
|
|
55
56
|
|
|
57
|
+
The working directory is the one your client launched the server in, and it is fixed for the session.
|
|
58
|
+
Moving to another worktree mid-session does not retarget it — use `root`, `FRONTIER_ROOT`, or restart
|
|
59
|
+
the server.
|
|
60
|
+
|
|
56
61
|
## Tools
|
|
57
62
|
|
|
58
63
|
Eight tools: `list_efforts`, `get_board`, `get_tickets`, `create_tickets`, `update_ticket`,
|
|
@@ -82,7 +87,7 @@ to avoid.
|
|
|
82
87
|
new build — pins stay manual on purpose.
|
|
83
88
|
|
|
84
89
|
The workflow is dispatchable from any branch but refuses to run off `master`: release-it commits,
|
|
85
|
-
tags and pushes
|
|
90
|
+
tags and pushes as part of the run, so a release from a feature branch would rewrite that branch.
|
|
86
91
|
|
|
87
92
|
Local dry-run (no tag, no publish). It needs a clean working tree and an upstream branch, so commit
|
|
88
93
|
first:
|
|
@@ -96,8 +101,8 @@ npmjs.com, so there is no `NPM_TOKEN` to rotate.
|
|
|
96
101
|
|
|
97
102
|
Before changing `.release-it.json` or the workflow, read the release-it bullet in
|
|
98
103
|
[AGENTS.md](./AGENTS.md) Work Guidance. Several settings there look removable and are not — the
|
|
99
|
-
absent `registry-url`, `npm.skipChecks`, and the pnpm 10 pin each exist for a
|
|
100
|
-
place so it cannot drift.
|
|
104
|
+
absent `registry-url`, `npm.skipChecks`, `npm.publishArgs`, and the pnpm 10 pin each exist for a
|
|
105
|
+
reason recorded in one place so it cannot drift.
|
|
101
106
|
|
|
102
107
|
## License
|
|
103
108
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StorageDriver } from './storage/driver.ts';
|
|
2
|
+
/**
|
|
3
|
+
* One driver per resolved workspace. A call carrying an explicit `root` reads a
|
|
4
|
+
* different workspace from the session's own, and each keeps its own driver —
|
|
5
|
+
* and so its own cache, its own watcher, and its own write queue.
|
|
6
|
+
*
|
|
7
|
+
* This is a lookup, not a layer: it hands back the driver itself, and no read
|
|
8
|
+
* or write passes through it.
|
|
9
|
+
*/
|
|
10
|
+
export interface DriverRegistry {
|
|
11
|
+
forWorkspace(root: string): StorageDriver;
|
|
12
|
+
closeAll(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createDriverRegistry(createDriver: (root: string) => StorageDriver): DriverRegistry;
|
|
15
|
+
//# sourceMappingURL=driver-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver-registry.d.ts","sourceRoot":"","sources":["../src/driver-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IAC1C,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,GAC5C,cAAc,CAiBhB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function createDriverRegistry(createDriver) {
|
|
2
|
+
const drivers = new Map();
|
|
3
|
+
return {
|
|
4
|
+
forWorkspace(root) {
|
|
5
|
+
let driver = drivers.get(root);
|
|
6
|
+
if (driver === undefined) {
|
|
7
|
+
driver = createDriver(root);
|
|
8
|
+
drivers.set(root, driver);
|
|
9
|
+
}
|
|
10
|
+
return driver;
|
|
11
|
+
},
|
|
12
|
+
closeAll() {
|
|
13
|
+
for (const driver of drivers.values())
|
|
14
|
+
driver.close();
|
|
15
|
+
drivers.clear();
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=driver-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver-registry.js","sourceRoot":"","sources":["../src/driver-registry.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,oBAAoB,CAClC,YAA6C;IAE7C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEjD,OAAO;QACL,YAAY,CAAC,IAAI;YACf,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5B,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,QAAQ;YACN,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE;gBAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YACtD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -11,18 +11,22 @@ export interface CreateServerOptions {
|
|
|
11
11
|
* so a SQLite driver can be swapped in without touching the tool layer.
|
|
12
12
|
*/
|
|
13
13
|
readonly createDriver?: (root: string) => StorageDriver;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Debounce filesystem watcher events in the default markdown driver. Tests
|
|
16
|
+
* may shorten it, or push it past the test to pin what a read actually read.
|
|
17
|
+
* Ignored when `createDriver` is supplied — a driver constructs its own.
|
|
18
|
+
*/
|
|
15
19
|
readonly watcherDebounceMs?: number;
|
|
16
20
|
}
|
|
17
21
|
export interface FrontierMCP {
|
|
18
22
|
readonly server: McpServer;
|
|
19
23
|
/**
|
|
20
|
-
*
|
|
24
|
+
* Warm the driver for the session's own workspace. Calls resolve their own
|
|
21
25
|
* workspace anyway, so a failure here is not fatal — it only forfeits the
|
|
22
26
|
* warm start.
|
|
23
27
|
*/
|
|
24
28
|
warmUp(): Promise<void>;
|
|
25
|
-
/**
|
|
29
|
+
/** Close every open driver and the transport. */
|
|
26
30
|
close(): Promise<void>;
|
|
27
31
|
}
|
|
28
32
|
export declare function createFrontierMCP(options?: CreateServerOptions): FrontierMCP;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AAyC5E,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACzD;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,CAAC;IACxD;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B;;;;OAIG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,iDAAiD;IACjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAOD,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,mBAAwB,GAAG,WAAW,CAoShF"}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { frontierOf } from './frontier.js';
|
|
3
|
-
import {
|
|
3
|
+
import { createDriverRegistry } from './driver-registry.js';
|
|
4
4
|
import { createMarkdownDriver } from './storage/markdown/driver.js';
|
|
5
5
|
import { NoSuchMap, RevisionMismatch } from './storage/driver.js';
|
|
6
6
|
import { createTicketsDescription, createTicketsInputSchema, planBatch, renderCreated, } from './tools/create-tickets.js';
|
|
@@ -10,6 +10,7 @@ import { getTicketsDescription, getTicketsInputSchema, renderTickets, } from './
|
|
|
10
10
|
import { listEffortsDescription, listEffortsInputSchema, renderEfforts, } from './tools/list-efforts.js';
|
|
11
11
|
import { migrateEffortDescription, migrateEffortInputSchema, renderMigration, } from './tools/migrate-effort.js';
|
|
12
12
|
import { renderSpec, specDescription, specInputSchema } from './tools/spec.js';
|
|
13
|
+
import { withWorkspace } from './tools/workspace-line.js';
|
|
13
14
|
import { editFor, renderUpdate, updateTicketDescription, updateTicketInputSchema, } from './tools/update-ticket.js';
|
|
14
15
|
import { readTrackerDoc, TRACKER_DOC_URI } from './tracker-doc.js';
|
|
15
16
|
import { resolveWorkspace } from './workspace.js';
|
|
@@ -24,7 +25,10 @@ export function createFrontierMCP(options = {}) {
|
|
|
24
25
|
cwd: options.cwd ?? process.cwd(),
|
|
25
26
|
env: options.env ?? process.env,
|
|
26
27
|
};
|
|
27
|
-
const registry =
|
|
28
|
+
const registry = createDriverRegistry(options.createDriver ??
|
|
29
|
+
(root => createMarkdownDriver(root, options.watcherDebounceMs === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { watcherDebounceMs: options.watcherDebounceMs })));
|
|
28
32
|
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
29
33
|
server.registerResource('tracker-doc', TRACKER_DOC_URI, {
|
|
30
34
|
title: 'Issue tracker configuration',
|
|
@@ -40,8 +44,8 @@ export function createFrontierMCP(options = {}) {
|
|
|
40
44
|
annotations: { readOnlyHint: true },
|
|
41
45
|
}, async ({ root }) => {
|
|
42
46
|
const workspace = resolveWorkspace(root, context);
|
|
43
|
-
const
|
|
44
|
-
const [efforts, tickets] = await Promise.all([
|
|
47
|
+
const driver = registry.forWorkspace(workspace);
|
|
48
|
+
const [efforts, tickets] = await Promise.all([driver.listEfforts(), driver.listTickets()]);
|
|
45
49
|
return {
|
|
46
50
|
content: [{ type: 'text', text: renderEfforts(workspace, efforts, frontierOf(tickets)) }],
|
|
47
51
|
};
|
|
@@ -53,8 +57,8 @@ export function createFrontierMCP(options = {}) {
|
|
|
53
57
|
annotations: { readOnlyHint: true },
|
|
54
58
|
}, async ({ effort: slug, root }) => {
|
|
55
59
|
const workspace = resolveWorkspace(root, context);
|
|
56
|
-
const
|
|
57
|
-
const [efforts, tickets] = await Promise.all([
|
|
60
|
+
const driver = registry.forWorkspace(workspace);
|
|
61
|
+
const [efforts, tickets] = await Promise.all([driver.listEfforts(), driver.listTickets()]);
|
|
58
62
|
const effort = efforts.find(candidate => candidate.slug === slug);
|
|
59
63
|
if (effort === undefined) {
|
|
60
64
|
throw new Error(`No Effort '${slug}' in ${workspace}. Known: ${efforts.map(e => e.slug).join(', ') || '(none)'}`);
|
|
@@ -68,16 +72,8 @@ export function createFrontierMCP(options = {}) {
|
|
|
68
72
|
annotations: { readOnlyHint: true },
|
|
69
73
|
}, async ({ ids, root }) => {
|
|
70
74
|
const workspace = resolveWorkspace(root, context);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
content: [
|
|
75
|
-
{
|
|
76
|
-
type: 'text',
|
|
77
|
-
text: renderTickets(ids, tickets.filter(ticket => wanted.has(ticket.handle) || (ticket.id !== undefined && wanted.has(ticket.id)))),
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
};
|
|
75
|
+
const found = await registry.forWorkspace(workspace).readTickets(ids);
|
|
76
|
+
return { content: [{ type: 'text', text: renderTickets(ids, found) }] };
|
|
81
77
|
});
|
|
82
78
|
server.registerTool('create_tickets', {
|
|
83
79
|
title: 'Create Tickets',
|
|
@@ -86,17 +82,19 @@ export function createFrontierMCP(options = {}) {
|
|
|
86
82
|
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
87
83
|
}, async ({ effort, create, tickets, root }) => {
|
|
88
84
|
const workspace = resolveWorkspace(root, context);
|
|
89
|
-
const
|
|
85
|
+
const driver = registry.forWorkspace(workspace);
|
|
90
86
|
// Every reference resolves before anything is written, so a refusal —
|
|
91
87
|
// an unknown key, a cycle — leaves the workspace exactly as it was. The
|
|
92
88
|
// one rule that needs real ids runs under the driver's reservations,
|
|
93
89
|
// still before any file lands.
|
|
94
|
-
const { drafts, validate } = planBatch(tickets, await
|
|
95
|
-
const created = await
|
|
90
|
+
const { drafts, validate } = planBatch(tickets, await driver.listTickets());
|
|
91
|
+
const created = await driver.createTickets(effort, drafts, {
|
|
96
92
|
createEffort: create === true,
|
|
97
93
|
validate,
|
|
98
94
|
});
|
|
99
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: 'text', text: withWorkspace(workspace, renderCreated(effort, created)) }],
|
|
97
|
+
};
|
|
100
98
|
});
|
|
101
99
|
server.registerTool('update_ticket', {
|
|
102
100
|
title: 'Update Ticket',
|
|
@@ -105,8 +103,8 @@ export function createFrontierMCP(options = {}) {
|
|
|
105
103
|
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
106
104
|
}, async ({ id, claim, resolve, drop, status, triage, blocked_by, comment, tick, root }) => {
|
|
107
105
|
const workspace = resolveWorkspace(root, context);
|
|
108
|
-
const
|
|
109
|
-
const tickets = await
|
|
106
|
+
const driver = registry.forWorkspace(workspace);
|
|
107
|
+
const tickets = await driver.listTickets();
|
|
110
108
|
const request = { claim, resolve, drop, status, triage, blocked_by, comment, tick };
|
|
111
109
|
const find = (from) => {
|
|
112
110
|
const ticket = from.find(entry => entry.id === id || entry.handle === id);
|
|
@@ -117,7 +115,7 @@ export function createFrontierMCP(options = {}) {
|
|
|
117
115
|
const ticket = find(tickets);
|
|
118
116
|
let written;
|
|
119
117
|
try {
|
|
120
|
-
written = await
|
|
118
|
+
written = await driver.updateTicket(ticket.handle, editFor(ticket, tickets, request, now()), ticket.revision);
|
|
121
119
|
}
|
|
122
120
|
catch (error) {
|
|
123
121
|
if (!(error instanceof RevisionMismatch))
|
|
@@ -127,12 +125,17 @@ export function createFrontierMCP(options = {}) {
|
|
|
127
125
|
// claimed by agent-3" is the useful message. The write is never
|
|
128
126
|
// retried — a mismatch may equally be somebody's hand edit, and
|
|
129
127
|
// overwriting that is exactly what the check exists to prevent.
|
|
130
|
-
const fresh = await
|
|
128
|
+
const fresh = await driver.listTickets();
|
|
131
129
|
editFor(find(fresh), fresh, request, now());
|
|
132
130
|
throw error;
|
|
133
131
|
}
|
|
134
132
|
return {
|
|
135
|
-
content: [
|
|
133
|
+
content: [
|
|
134
|
+
{
|
|
135
|
+
type: 'text',
|
|
136
|
+
text: withWorkspace(workspace, renderUpdate(written.ticket, written.warnings)),
|
|
137
|
+
},
|
|
138
|
+
],
|
|
136
139
|
};
|
|
137
140
|
});
|
|
138
141
|
server.registerTool('edit_map', {
|
|
@@ -142,29 +145,34 @@ export function createFrontierMCP(options = {}) {
|
|
|
142
145
|
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
143
146
|
}, async ({ effort, create, destination, notes, add_fog, graduate_fog, rule_out, expected_revision, root, }) => {
|
|
144
147
|
const workspace = resolveWorkspace(root, context);
|
|
145
|
-
const
|
|
148
|
+
const driver = registry.forWorkspace(workspace);
|
|
146
149
|
const edit = mapEditFor({ destination, notes, add_fog, graduate_fog, rule_out });
|
|
147
150
|
const mutating = Object.keys(edit).length > 0;
|
|
148
151
|
// create alone is for starting a missing Effort/Map — not a flag to send
|
|
149
152
|
// on every call. With no section fields, an existing Map is a plain read
|
|
150
153
|
// (no expected_revision); only a missing Map takes the write path.
|
|
151
154
|
let document;
|
|
155
|
+
let wrote = mutating;
|
|
152
156
|
if (!mutating) {
|
|
153
157
|
try {
|
|
154
|
-
document = await
|
|
158
|
+
document = await driver.readMap(effort);
|
|
155
159
|
}
|
|
156
160
|
catch (error) {
|
|
157
161
|
if (!(create === true && error instanceof NoSuchMap))
|
|
158
162
|
throw error;
|
|
159
|
-
document = await
|
|
163
|
+
document = await driver.editMap(effort, edit, undefined, { createEffort: true });
|
|
164
|
+
wrote = true;
|
|
160
165
|
}
|
|
161
166
|
}
|
|
162
167
|
else {
|
|
163
|
-
document = await
|
|
168
|
+
document = await driver.editMap(effort, edit, expected_revision, {
|
|
164
169
|
createEffort: create === true,
|
|
165
170
|
});
|
|
166
171
|
}
|
|
167
|
-
|
|
172
|
+
const rendered = renderMap(effort, document);
|
|
173
|
+
return {
|
|
174
|
+
content: [{ type: 'text', text: wrote ? withWorkspace(workspace, rendered) : rendered }],
|
|
175
|
+
};
|
|
168
176
|
});
|
|
169
177
|
server.registerTool('spec', {
|
|
170
178
|
title: 'Spec',
|
|
@@ -173,13 +181,17 @@ export function createFrontierMCP(options = {}) {
|
|
|
173
181
|
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
174
182
|
}, async ({ effort, create, content, expected_revision, root }) => {
|
|
175
183
|
const workspace = resolveWorkspace(root, context);
|
|
176
|
-
const
|
|
184
|
+
const driver = registry.forWorkspace(workspace);
|
|
177
185
|
const document = content === undefined
|
|
178
|
-
? await
|
|
179
|
-
: await
|
|
186
|
+
? await driver.readSpec(effort)
|
|
187
|
+
: await driver.putSpec(effort, content, expected_revision, {
|
|
180
188
|
createEffort: create === true,
|
|
181
189
|
});
|
|
182
|
-
|
|
190
|
+
const wrote = content !== undefined;
|
|
191
|
+
const rendered = renderSpec(effort, document);
|
|
192
|
+
return {
|
|
193
|
+
content: [{ type: 'text', text: wrote ? withWorkspace(workspace, rendered) : rendered }],
|
|
194
|
+
};
|
|
183
195
|
});
|
|
184
196
|
server.registerTool('migrate_effort', {
|
|
185
197
|
title: 'Migrate Effort',
|
|
@@ -188,18 +200,25 @@ export function createFrontierMCP(options = {}) {
|
|
|
188
200
|
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
189
201
|
}, async ({ effort, preview, rename, root }) => {
|
|
190
202
|
const workspace = resolveWorkspace(root, context);
|
|
191
|
-
const
|
|
192
|
-
const report = await
|
|
203
|
+
const driver = registry.forWorkspace(workspace);
|
|
204
|
+
const report = await driver.migrateEffort(effort, {
|
|
193
205
|
preview: preview === true,
|
|
194
206
|
rename: rename === true,
|
|
195
207
|
});
|
|
196
|
-
|
|
208
|
+
// A preview writes nothing, and neither does a run that finds nothing to
|
|
209
|
+
// normalize — an Effort already in schema reports no changes and leaves
|
|
210
|
+
// every file alone. Both are reads, whatever the flag said.
|
|
211
|
+
const wrote = preview !== true && report.changes.length > 0;
|
|
212
|
+
const rendered = renderMigration(report);
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: 'text', text: wrote ? withWorkspace(workspace, rendered) : rendered }],
|
|
215
|
+
};
|
|
197
216
|
});
|
|
198
217
|
return {
|
|
199
218
|
server,
|
|
200
219
|
async warmUp() {
|
|
201
220
|
const workspace = resolveWorkspace(undefined, context);
|
|
202
|
-
await registry.forWorkspace(workspace).
|
|
221
|
+
await registry.forWorkspace(workspace).listEfforts();
|
|
203
222
|
},
|
|
204
223
|
async close() {
|
|
205
224
|
registry.closeAll();
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/driver.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Effort, MapDocument, MapEdit, MigrateOptions, MigrationReport, SpecDocument, Ticket, TicketDraft, TicketEdit } from '../domain.ts';
|
|
1
|
+
import type { Effort, MapDocument, MapEdit, MigrateOptions, MigrationReport, SpecDocument, Ticket, TicketDraft, TicketEdit, TicketSummary } from '../domain.ts';
|
|
2
2
|
export type { MapDocument, MapEdit, MigrateOptions, MigrationReport, SpecDocument, TicketDraft, TicketEdit, };
|
|
3
3
|
export interface CreateOptions {
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ export interface CreateOptions {
|
|
|
20
20
|
* seam can see that coming, because nothing above the seam knows what the
|
|
21
21
|
* next id will be.
|
|
22
22
|
*/
|
|
23
|
-
readonly validate?: (ids: readonly string[], tickets: readonly
|
|
23
|
+
readonly validate?: (ids: readonly string[], tickets: readonly TicketSummary[]) => void;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Whether a Header-doc write may start an Effort that does not yet exist.
|
|
@@ -38,6 +38,15 @@ export interface HeaderDocOptions {
|
|
|
38
38
|
* markdown driver takes a directory, a SQLite driver would take a connection),
|
|
39
39
|
* so no method ever takes or returns a location. The planned SQLite driver, and
|
|
40
40
|
* the `md <-> db` conversion either side of it, are only writable if this holds.
|
|
41
|
+
*
|
|
42
|
+
* A driver is the workspace *cached and live*, not a bare set of queries.
|
|
43
|
+
* Whether to hold a scan, when it goes stale, and how it hears that another
|
|
44
|
+
* process wrote are all answers about one physical model — the markdown driver
|
|
45
|
+
* caches a full walk and watches a directory; a SQLite driver would query and
|
|
46
|
+
* let its own page cache do the work. A layer above the seam deciding any of
|
|
47
|
+
* this for both of them is one model's policy wearing a generic interface, so
|
|
48
|
+
* there is no such layer. Callers see none of it: every method answers as
|
|
49
|
+
* though it had just read.
|
|
41
50
|
*/
|
|
42
51
|
export interface StorageDriver {
|
|
43
52
|
/**
|
|
@@ -46,11 +55,24 @@ export interface StorageDriver {
|
|
|
46
55
|
*/
|
|
47
56
|
listEfforts(): Promise<readonly Effort[]>;
|
|
48
57
|
/**
|
|
49
|
-
* Every Ticket in the workspace, ordered by Effort then by
|
|
50
|
-
* resolve repo-wide, so callers that need one Effort filter
|
|
51
|
-
* asking for a subset — at these volumes the whole set is the
|
|
58
|
+
* Every Ticket in the workspace without its body, ordered by Effort then by
|
|
59
|
+
* sort order. Ids resolve repo-wide, so callers that need one Effort filter
|
|
60
|
+
* this rather than asking for a subset — at these volumes the whole set is the
|
|
61
|
+
* cheap answer, and it stays cheap only because no body rides along.
|
|
62
|
+
*/
|
|
63
|
+
listTickets(): Promise<readonly TicketSummary[]>;
|
|
64
|
+
/**
|
|
65
|
+
* The named Tickets with their bodies, addressed by id or by the
|
|
66
|
+
* `<effort>#<order>` handle an id-less Legacy Ticket answers to. A name the
|
|
67
|
+
* workspace does not hold is simply absent: which names were asked for is the
|
|
68
|
+
* caller's knowledge, not the driver's.
|
|
69
|
+
*
|
|
70
|
+
* Separate from {@link listTickets} because a body is the one field almost
|
|
71
|
+
* nothing reads — Boards, the Frontier and Edge resolution all work from
|
|
72
|
+
* summary fields — so bodies are fetched for the few Tickets being worked
|
|
73
|
+
* rather than carried by every read of the workspace.
|
|
52
74
|
*/
|
|
53
|
-
|
|
75
|
+
readTickets(handles: readonly string[]): Promise<readonly Ticket[]>;
|
|
54
76
|
/**
|
|
55
77
|
* Apply an edit to one Ticket and return it as written.
|
|
56
78
|
*
|
|
@@ -76,7 +98,7 @@ export interface StorageDriver {
|
|
|
76
98
|
* Ids are unique across the whole workspace, and stay unique when two sessions
|
|
77
99
|
* in separate processes create at the same instant.
|
|
78
100
|
*/
|
|
79
|
-
createTickets(effort: string, drafts: readonly TicketDraft[], options: CreateOptions): Promise<readonly
|
|
101
|
+
createTickets(effort: string, drafts: readonly TicketDraft[], options: CreateOptions): Promise<readonly TicketSummary[]>;
|
|
80
102
|
/**
|
|
81
103
|
* The Map's typed sections for one Effort. Decisions-so-far is not here — it
|
|
82
104
|
* is derived from Tickets and never read from the file.
|
|
@@ -98,10 +120,21 @@ export interface StorageDriver {
|
|
|
98
120
|
* nothing. Unrecognized files in the Effort directory are ignored.
|
|
99
121
|
*/
|
|
100
122
|
migrateEffort(effort: string, options: MigrateOptions): Promise<MigrationReport>;
|
|
123
|
+
/**
|
|
124
|
+
* Release whatever this driver holds open to stay live — the markdown
|
|
125
|
+
* driver's filesystem watcher, a connection for a driver that has one. Reads
|
|
126
|
+
* and writes are not expected after it, and a driver that holds nothing may
|
|
127
|
+
* do nothing.
|
|
128
|
+
*
|
|
129
|
+
* Synchronous, because closing is: an `FSWatcher` closes synchronously and so
|
|
130
|
+
* does `node:sqlite`. Widening it to a promise the day a driver needs one is
|
|
131
|
+
* a change to this line and to the one caller that closes them all.
|
|
132
|
+
*/
|
|
133
|
+
close(): void;
|
|
101
134
|
}
|
|
102
135
|
/** A Ticket write, plus any non-fatal warnings that rode along. */
|
|
103
136
|
export interface TicketWriteResult {
|
|
104
|
-
readonly ticket:
|
|
137
|
+
readonly ticket: TicketSummary;
|
|
105
138
|
readonly warnings: readonly string[];
|
|
106
139
|
}
|
|
107
140
|
/** Thrown when the stored Ticket moved on since the caller read it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/storage/driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,WAAW,EACX,OAAO,EACP,cAAc,EACd,eAAe,EACf,YAAY,EACZ,MAAM,EACN,WAAW,EACX,UAAU,
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/storage/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/storage/driver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/storage/driver.ts"],"names":[],"mappings":"AAgMA,uEAAuE;AACvE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,MAAc;QACxB,KAAK,CACH,GAAG,MAAM,iFAAiF,CAC3F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,MAAc;QACxB,KAAK,CAAC,cAAc,MAAM,sBAAsB,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,sFAAsF;AACtF,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,IAAY;QACtB,KAAK,CAAC,cAAc,IAAI,+CAA+C,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,qEAAqE;AACrE,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,IAAY;QACtB,KAAK,CAAC,sBAAsB,IAAI,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,IAAY;QACtB,KAAK,CAAC,uBAAuB,IAAI,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,qEAAqE;AACrE,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,KAAa;QACvB,KAAK,CAAC,0BAA0B,KAAK,4BAA4B,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TicketDraft, TicketSummary } from '../../domain.ts';
|
|
2
2
|
/** Every Ticket in the workspace, re-read rather than served from any cache. */
|
|
3
|
-
export type Rescan = () => Promise<readonly
|
|
3
|
+
export type Rescan = () => Promise<readonly TicketSummary[]>;
|
|
4
4
|
export interface CreateRequest {
|
|
5
5
|
/** Where the id guards live: one namespace for the whole workspace. */
|
|
6
|
-
readonly
|
|
6
|
+
readonly storage: string;
|
|
7
7
|
readonly effort: string;
|
|
8
8
|
/** The Effort's directory, and the directory its Tickets go in. Both owned by the driver. */
|
|
9
9
|
readonly dir: string;
|
|
@@ -15,7 +15,7 @@ export interface CreateRequest {
|
|
|
15
15
|
* The last check, run with the reserved ids and the workspace as it looks
|
|
16
16
|
* under the guards. Throwing abandons the batch before anything is written.
|
|
17
17
|
*/
|
|
18
|
-
readonly validate: (ids: readonly string[], tickets: readonly
|
|
18
|
+
readonly validate: (ids: readonly string[], tickets: readonly TicketSummary[]) => void;
|
|
19
19
|
/** Whether the Effort's directory has to be made, and unmade if nothing lands. */
|
|
20
20
|
readonly createEffort: boolean;
|
|
21
21
|
}
|
|
@@ -41,7 +41,7 @@ export declare function createTicketFiles(request: CreateRequest): Promise<reado
|
|
|
41
41
|
* Hold exclusive id guards for `count` fresh ids, run `use`, then release.
|
|
42
42
|
* Migration mints through this so a parallel create_tickets cannot collide.
|
|
43
43
|
*/
|
|
44
|
-
export declare function withIdReservations<T>(
|
|
44
|
+
export declare function withIdReservations<T>(storage: string, count: number, rescan: Rescan, use: (ids: readonly string[]) => Promise<T>): Promise<T>;
|
|
45
45
|
/**
|
|
46
46
|
* The next `count` minted ids from a scan, without taking guards. Preview uses
|
|
47
47
|
* this so a dry run never leaves `.frontier-id-*.guard` files behind.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/storage/markdown/create.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/storage/markdown/create.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAyBlE,gFAAgF;AAChF,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IACxC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS,aAAa,EAAE,KAAK,IAAI,CAAC;IACvF,kFAAkF;IAClF,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CA4B1F;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAC1C,OAAO,CAAC,CAAC,CAAC,CASZ;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAWzF;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/E"}
|