@frmwrkd/snag-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.
- package/LICENSE +19 -0
- package/README.md +187 -0
- package/dist/client.d.ts +544 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1074 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/resources.d.ts +19 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +281 -0
- package/dist/resources.js.map +1 -0
- package/dist/tokens.d.ts +69 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +90 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tools.d.ts +115 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +868 -0
- package/dist/tools.js.map +1 -0
- package/package.json +44 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
import type { Plan, RepoMap, SnagConfig, Task, TaskStatus } from '@frmwrkd/snag-core';
|
|
2
|
+
export declare const DAEMON_HOST = "127.0.0.1";
|
|
3
|
+
/** doc 02 §7.3 — the probe range, inclusive at both ends. */
|
|
4
|
+
export declare const DAEMON_PORT_START = 7654;
|
|
5
|
+
export declare const DAEMON_PORT_END = 7664;
|
|
6
|
+
/** `.snag/` — the contract directory (doc 02 §6.1). */
|
|
7
|
+
export declare const SNAG_DIR = ".snag";
|
|
8
|
+
/**
|
|
9
|
+
* The command that starts snagd, for whoever is running *this* build.
|
|
10
|
+
*
|
|
11
|
+
* `snagd` is not published, so `npx snagd` cannot start it today. Until it is, the MCP
|
|
12
|
+
* server runs from a Snag checkout (`scripts/install-claude-code.mjs`), and
|
|
13
|
+
* the daemon's build sits beside it at `apps/daemon/dist/cli.js` — so when that
|
|
14
|
+
* file exists, name it. `npx snagd` remains the answer for a published install.
|
|
15
|
+
*/
|
|
16
|
+
export declare function snagdCommand(moduleUrl?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The daemon could not be reached at all. The message is written to be read by
|
|
19
|
+
* an agent: it names the command that fixes it and the files that work without
|
|
20
|
+
* it.
|
|
21
|
+
*/
|
|
22
|
+
export declare class DaemonUnavailableError extends Error {
|
|
23
|
+
readonly root: string;
|
|
24
|
+
/** The underlying failure (`fetch failed`, a timeout), kept so it can be re-thrown against the project root. */
|
|
25
|
+
readonly detail: string | undefined;
|
|
26
|
+
constructor(root: string, detail?: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A snagd answered — for a different checkout.
|
|
30
|
+
*
|
|
31
|
+
* Reported instead of "snagd is not running", which is false and sends the
|
|
32
|
+
* agent to start a second daemon that then fights the first for the port
|
|
33
|
+
* range. A subclass of `DaemonUnavailableError` because it means the same thing
|
|
34
|
+
* to every caller: there is no daemon *for this project* to write through.
|
|
35
|
+
*/
|
|
36
|
+
export declare class DaemonRootMismatchError extends DaemonUnavailableError {
|
|
37
|
+
/** The port the other daemon answered on, or `null` if the URL had none. */
|
|
38
|
+
readonly port: number | null;
|
|
39
|
+
/** The root that daemon serves, exactly as its `/health` reported it. */
|
|
40
|
+
readonly daemonRoot: string;
|
|
41
|
+
constructor(root: string, daemonRoot: string, baseUrl: string);
|
|
42
|
+
}
|
|
43
|
+
/** The daemon answered, and said no. `code` is its machine-readable error id. */
|
|
44
|
+
export declare class DaemonRequestError extends Error {
|
|
45
|
+
readonly status: number;
|
|
46
|
+
readonly code: string;
|
|
47
|
+
constructor(status: number, code: string, message: string);
|
|
48
|
+
}
|
|
49
|
+
export interface FetchResponseLike {
|
|
50
|
+
readonly ok: boolean;
|
|
51
|
+
readonly status: number;
|
|
52
|
+
text(): Promise<string>;
|
|
53
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
54
|
+
readonly headers: {
|
|
55
|
+
get(name: string): string | null;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export interface FetchInitLike {
|
|
59
|
+
method?: string;
|
|
60
|
+
headers?: Record<string, string>;
|
|
61
|
+
body?: string;
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Structurally the slice of `fetch` this module uses. Declared rather than
|
|
66
|
+
* imported so tests can inject a fake without pulling in DOM lib types.
|
|
67
|
+
*/
|
|
68
|
+
export type FetchLike = (url: string, init?: FetchInitLike) => Promise<FetchResponseLike>;
|
|
69
|
+
/**
|
|
70
|
+
* Whether two paths name the same directory.
|
|
71
|
+
*
|
|
72
|
+
* `path.resolve` on both, case-folded on win32 — NTFS is case-insensitive, and
|
|
73
|
+
* `git rev-parse --show-toplevel` (which is where snagd's `root` comes from)
|
|
74
|
+
* and `process.cwd()` do not agree on drive-letter case. The realpath
|
|
75
|
+
* comparison is the fallback for symlinked temp directories (macOS `/var` →
|
|
76
|
+
* `/private/var`) and 8.3 short names.
|
|
77
|
+
*/
|
|
78
|
+
export declare function samePath(a: string, b: string): boolean;
|
|
79
|
+
/** Runs `git <args>` in `cwd` and resolves its stdout. Injected by tests. */
|
|
80
|
+
export type GitRunner = (args: readonly string[], cwd: string) => Promise<string>;
|
|
81
|
+
/** `git` from `PATH`, bounded by `GIT_TIMEOUT_MS`. Rejects when git is missing. */
|
|
82
|
+
export declare const runGit: GitRunner;
|
|
83
|
+
/** The absolute git common dir for `dir`, or `null` when there is none to be had. */
|
|
84
|
+
export type GitCommonDirLookup = (dir: string) => Promise<string | null>;
|
|
85
|
+
/**
|
|
86
|
+
* `git rev-parse --git-common-dir`, resolved against `dir` and cached.
|
|
87
|
+
*
|
|
88
|
+
* The common dir is what a linked worktree shares with the checkout it was
|
|
89
|
+
* added from (`git worktree add`), so two roots with the same common dir are
|
|
90
|
+
* one repository and one queue. git prints it relative to the cwd in a main
|
|
91
|
+
* checkout (`.git`) and absolute in a linked worktree, hence the resolve.
|
|
92
|
+
* `--path-format=absolute` would save that, but needs git 2.31.
|
|
93
|
+
*
|
|
94
|
+
* Only answers are cached. A failure — git not installed, not a repository, a
|
|
95
|
+
* timeout — returns `null`, which only ever means "not proven to be the same
|
|
96
|
+
* repository", and is asked again next time: `git init` can happen mid-session.
|
|
97
|
+
*/
|
|
98
|
+
export declare function createGitCommonDirLookup(run?: GitRunner): GitCommonDirLookup;
|
|
99
|
+
/** The process-wide lookup, so the cache outlives any one discovery. */
|
|
100
|
+
export declare const defaultGitCommonDir: GitCommonDirLookup;
|
|
101
|
+
/** Whether `a` and `b` are checkouts of one repository (same git common dir). */
|
|
102
|
+
export declare function sameRepository(a: string, b: string, lookup?: GitCommonDirLookup): Promise<boolean>;
|
|
103
|
+
/**
|
|
104
|
+
* Walk up from `startDir` looking for a directory containing `.snag/`.
|
|
105
|
+
*
|
|
106
|
+
* Claude Code spawns a stdio MCP server with the project directory as its cwd,
|
|
107
|
+
* so this normally hits on the first try. Walking up covers the case where the
|
|
108
|
+
* server is spawned from a subdirectory of the repo.
|
|
109
|
+
*
|
|
110
|
+
* **`~/.snag` is not a project.** It is snagd's token directory (doc 02 §7.1),
|
|
111
|
+
* so every directory under the user's home has a `.snag/` somewhere above it.
|
|
112
|
+
* Without this skip, an MCP server started in an app that has never run snagd
|
|
113
|
+
* adopts the home directory as its root, and every read and write goes to the
|
|
114
|
+
* wrong place with no error at all.
|
|
115
|
+
*/
|
|
116
|
+
export declare function findProjectRoot(startDir?: string, home?: string | null): string | null;
|
|
117
|
+
/** `~/.snag/token`, or `null` on first run before `snagd` has generated one. */
|
|
118
|
+
export declare function readToken(home?: string): string | null;
|
|
119
|
+
/** `.snag/.port` — the port `snagd` actually bound (doc 02 §7.3). */
|
|
120
|
+
export declare function readPortFile(root: string): number | null;
|
|
121
|
+
/**
|
|
122
|
+
* Three outcomes, deliberately not two.
|
|
123
|
+
*
|
|
124
|
+
* `missing` and `invalid` mean opposite things to an agent: the first says
|
|
125
|
+
* "there is no work", the second says "the work is unreadable and someone must
|
|
126
|
+
* look". Folding them into `null` is what let a wholly broken backlog report
|
|
127
|
+
* itself as an empty queue.
|
|
128
|
+
*/
|
|
129
|
+
export type PlanReadResult = {
|
|
130
|
+
state: 'ok';
|
|
131
|
+
plan: Plan;
|
|
132
|
+
} | {
|
|
133
|
+
state: 'missing';
|
|
134
|
+
} | {
|
|
135
|
+
state: 'invalid';
|
|
136
|
+
issues: string[];
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* The `.snag/` half of the contract. Pure reads — nothing here ever writes,
|
|
140
|
+
* because the daemon owns the directory and watches it.
|
|
141
|
+
*/
|
|
142
|
+
export declare class FileStore {
|
|
143
|
+
readonly root: string;
|
|
144
|
+
constructor(root: string);
|
|
145
|
+
get dir(): string;
|
|
146
|
+
/** Absolute path for a repo-relative path, or `null` if it escapes the root. */
|
|
147
|
+
resolveInsideRoot(relative: string): string | null;
|
|
148
|
+
private readJson;
|
|
149
|
+
/** `.snag/config.json`. Falls back to `defaultConfig()` — it is committed, but optional. */
|
|
150
|
+
readConfig(): SnagConfig;
|
|
151
|
+
/**
|
|
152
|
+
* `.snag/plan.json`, distinguishing "no plan yet" from "the plan is broken".
|
|
153
|
+
*
|
|
154
|
+
* Collapsing both to `null` is how 53 unreadable tasks came out of `snag_list`
|
|
155
|
+
* as "the queue is clear" — an agent was told there was no work when in fact
|
|
156
|
+
* the work could not be read. A file that exists and fails validation must
|
|
157
|
+
* never be reported as absence.
|
|
158
|
+
*/
|
|
159
|
+
readPlanResult(): PlanReadResult;
|
|
160
|
+
/** `.snag/plan.json`, or `null` when there is no *usable* plan. */
|
|
161
|
+
readPlan(): Plan | null;
|
|
162
|
+
/** `.snag/map.json`, or `null` when the repo map has not been built. */
|
|
163
|
+
readMap(): RepoMap | null;
|
|
164
|
+
/**
|
|
165
|
+
* Tasks from `.snag/plan.json`. This is the offline fallback for
|
|
166
|
+
* `snag_list`/`snag_get`: `plan.tasks` is plain JSON validated by
|
|
167
|
+
* `TaskSchema`, so no YAML parser is needed to read the queue without the
|
|
168
|
+
* daemon. Statuses here are a snapshot and may lag the index.
|
|
169
|
+
*/
|
|
170
|
+
tasks(): Task[];
|
|
171
|
+
/**
|
|
172
|
+
* Why the offline task list is empty, when it is empty. `null` means it is
|
|
173
|
+
* not empty, or is legitimately so.
|
|
174
|
+
*
|
|
175
|
+
* `tasks()` has to keep returning `Task[]` — every caller expects an array —
|
|
176
|
+
* so the reason travels alongside it rather than inside it.
|
|
177
|
+
*/
|
|
178
|
+
emptyTasksReason(): string | null;
|
|
179
|
+
/**
|
|
180
|
+
* The task's markdown file, repo-relative, or `null` if it is not on disk.
|
|
181
|
+
* The name is derived by `taskFileName` from `@frmwrkd/snag-core`, which is the same
|
|
182
|
+
* function the daemon's writer uses, so the two cannot drift.
|
|
183
|
+
*/
|
|
184
|
+
taskMarkdownPath(task: Pick<Task, 'id' | 'title'>): string | null;
|
|
185
|
+
readTextFile(relative: string): string | null;
|
|
186
|
+
readBytes(relative: string): Buffer | null;
|
|
187
|
+
}
|
|
188
|
+
export interface DaemonClientOptions {
|
|
189
|
+
baseUrl: string;
|
|
190
|
+
token: string | null;
|
|
191
|
+
fetchImpl?: FetchLike;
|
|
192
|
+
timeoutMs?: number;
|
|
193
|
+
}
|
|
194
|
+
export interface HealthPayload {
|
|
195
|
+
name?: string;
|
|
196
|
+
version?: string;
|
|
197
|
+
root?: string;
|
|
198
|
+
captures?: number;
|
|
199
|
+
open_captures?: number;
|
|
200
|
+
tasks?: number;
|
|
201
|
+
anchor_coverage?: number;
|
|
202
|
+
ok?: boolean;
|
|
203
|
+
}
|
|
204
|
+
export interface TaskListQuery {
|
|
205
|
+
status?: TaskStatus;
|
|
206
|
+
wave?: number;
|
|
207
|
+
severity?: string;
|
|
208
|
+
limit?: number;
|
|
209
|
+
}
|
|
210
|
+
export declare class DaemonClient {
|
|
211
|
+
readonly baseUrl: string;
|
|
212
|
+
readonly token: string | null;
|
|
213
|
+
private readonly fetchImpl;
|
|
214
|
+
private readonly timeoutMs;
|
|
215
|
+
constructor(options: DaemonClientOptions);
|
|
216
|
+
private headers;
|
|
217
|
+
raw(method: string, pathname: string, body?: unknown, timeoutMs?: number): Promise<FetchResponseLike>;
|
|
218
|
+
/**
|
|
219
|
+
* A JSON request. Throws `DaemonRequestError` on a non-2xx, preserving the
|
|
220
|
+
* daemon's own `error` code and `message` — those messages are written to be
|
|
221
|
+
* actionable (`verify_only`, `illegal_transition`, …) and paraphrasing them
|
|
222
|
+
* would throw away the only explanation the agent gets.
|
|
223
|
+
*/
|
|
224
|
+
request<T>(method: string, pathname: string, body?: unknown): Promise<T>;
|
|
225
|
+
health(): Promise<HealthPayload>;
|
|
226
|
+
listTasks(query?: TaskListQuery): Promise<Task[]>;
|
|
227
|
+
getTask(id: string): Promise<{
|
|
228
|
+
task: Task;
|
|
229
|
+
file: string | null;
|
|
230
|
+
} | null>;
|
|
231
|
+
/**
|
|
232
|
+
* `POST /git/commit` — snagd stages the named files and commits them.
|
|
233
|
+
*
|
|
234
|
+
* The daemon does it, not this server: it owns the project root and
|
|
235
|
+
* `.snag/config.json`'s `git` block, and one implementation means the rails
|
|
236
|
+
* (named paths only, never a push, never a protected branch) cannot differ
|
|
237
|
+
* between an MCP call and the commit at the end of a headless run.
|
|
238
|
+
*/
|
|
239
|
+
commit(body: {
|
|
240
|
+
task?: string;
|
|
241
|
+
files?: string[];
|
|
242
|
+
message?: string;
|
|
243
|
+
}): Promise<CommitAnswer>;
|
|
244
|
+
setStatus(id: string, status: TaskStatus): Promise<Task>;
|
|
245
|
+
plan(): Promise<Plan | null>;
|
|
246
|
+
map(): Promise<RepoMap | null>;
|
|
247
|
+
/**
|
|
248
|
+
* `POST /verify/:taskId` with `dry_run: true` — the daemon's preflight and
|
|
249
|
+
* nothing else. It starts no run and changes no status, so it can be asked
|
|
250
|
+
* *before* `snag_resolve` moves the task: a task that Verify can never judge
|
|
251
|
+
* must not be parked in `verifying`, where nothing will ever move it again.
|
|
252
|
+
*
|
|
253
|
+
* The refusals are the daemon's own, verbatim: 404 `not_found`, 409
|
|
254
|
+
* `verify_disabled`, 409 `no_capture_url`, 503 `verify_unavailable`.
|
|
255
|
+
*/
|
|
256
|
+
verifyPreflight(taskId: string): Promise<VerifyPreflightResult>;
|
|
257
|
+
/**
|
|
258
|
+
* `GET /verify/:taskId` — whether a run is in flight, and how the last one
|
|
259
|
+
* ended. The daemon keeps only the last report per task, in memory, so
|
|
260
|
+
* `last: null` after a snagd restart means "not since it started", not
|
|
261
|
+
* "never". `null` when the daemon has no such task, or no such route.
|
|
262
|
+
*/
|
|
263
|
+
verifyStatus(taskId: string): Promise<VerifyStatus | null>;
|
|
264
|
+
/**
|
|
265
|
+
* `POST /verify/:taskId` (doc 02 §7.1 / §10). Returns a result rather than
|
|
266
|
+
* throwing when the daemon refuses: a task that reached `verifying` but could
|
|
267
|
+
* not queue a run is a partial success, and reporting it as a total failure
|
|
268
|
+
* would make the agent retry a transition that already happened.
|
|
269
|
+
*
|
|
270
|
+
* The daemon answers **202 `{ queued, task_uid, already_running }`** and runs
|
|
271
|
+
* the loop in the background — Verify drives a real Chrome tab, which takes
|
|
272
|
+
* far longer than this client's timeout, so waiting on it here would turn
|
|
273
|
+
* every resolve into a timeout. `wait: true` is never sent.
|
|
274
|
+
*
|
|
275
|
+
* **503 `verify_unavailable`** means no extension is attached. The daemon's
|
|
276
|
+
* message says exactly how to fix that, so it is passed through verbatim.
|
|
277
|
+
*
|
|
278
|
+
* `DaemonUnavailableError` propagates: the caller owns the connection cache
|
|
279
|
+
* and has to forget a daemon that stopped answering.
|
|
280
|
+
*/
|
|
281
|
+
queueVerify(taskId: string, body: {
|
|
282
|
+
commit?: string;
|
|
283
|
+
note?: string;
|
|
284
|
+
}): Promise<VerifyQueueResult>;
|
|
285
|
+
}
|
|
286
|
+
/** What `queueVerify` learned. `code` is the daemon's refusal id, when it refused. */
|
|
287
|
+
export interface VerifyQueueResult {
|
|
288
|
+
queued: boolean;
|
|
289
|
+
detail: string;
|
|
290
|
+
code?: string;
|
|
291
|
+
/** A run for this task was already in flight; the daemon did not start a second. */
|
|
292
|
+
already_running?: boolean;
|
|
293
|
+
}
|
|
294
|
+
/** What the preflight said. `code`/`message` are the daemon's refusal, verbatim. */
|
|
295
|
+
export type VerifyPreflightResult = {
|
|
296
|
+
ok: true;
|
|
297
|
+
} | {
|
|
298
|
+
ok: false;
|
|
299
|
+
status: number;
|
|
300
|
+
code: string;
|
|
301
|
+
message: string;
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* `GET /verify/:taskId`, projected to what an agent acts on. `outcome` and
|
|
305
|
+
* `reason` come from the last report, verbatim; all three are `null` when no
|
|
306
|
+
* run has settled since snagd started.
|
|
307
|
+
*/
|
|
308
|
+
export interface VerifyStatus {
|
|
309
|
+
running: boolean;
|
|
310
|
+
outcome: string | null;
|
|
311
|
+
reason: string | null;
|
|
312
|
+
last_at: string | null;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* doc 02 §10 as it runs today. No pixel comparison happens yet, so this must
|
|
316
|
+
* not claim one: a capture with no console error gives Verify nothing to judge
|
|
317
|
+
* by, and the task goes to `needs_review` rather than to `resolved`.
|
|
318
|
+
*/
|
|
319
|
+
export declare const VERIFY_QUEUED_DETAIL: string;
|
|
320
|
+
export interface ConnectOptions {
|
|
321
|
+
root: string;
|
|
322
|
+
token?: string | null;
|
|
323
|
+
fetchImpl?: FetchLike;
|
|
324
|
+
/** Overrides discovery entirely. Used by tests and by `SNAG_DAEMON_URL`. */
|
|
325
|
+
baseUrl?: string;
|
|
326
|
+
portRange?: {
|
|
327
|
+
start: number;
|
|
328
|
+
end: number;
|
|
329
|
+
};
|
|
330
|
+
/** How to tell a worktree of this repository from another project. */
|
|
331
|
+
gitCommonDir?: GitCommonDirLookup;
|
|
332
|
+
}
|
|
333
|
+
/** Whether a `/health` answer is a snagd for `root`, and if not, why not. */
|
|
334
|
+
export type DaemonIdentity = {
|
|
335
|
+
ok: true;
|
|
336
|
+
} | {
|
|
337
|
+
ok: false;
|
|
338
|
+
reason: 'not_snagd';
|
|
339
|
+
} | {
|
|
340
|
+
ok: false;
|
|
341
|
+
reason: 'other_root';
|
|
342
|
+
daemonRoot: string;
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* The identity rule, shared by discovery and by the re-check before a write.
|
|
346
|
+
*
|
|
347
|
+
* `root` absent means a daemon too old to say; that is not evidence of a
|
|
348
|
+
* mismatch. A different root is accepted only when git says both are
|
|
349
|
+
* checkouts of one repository — see "Which snagd" above.
|
|
350
|
+
*/
|
|
351
|
+
export declare function daemonIdentity(health: HealthPayload, root: string, lookup?: GitCommonDirLookup): Promise<DaemonIdentity>;
|
|
352
|
+
/**
|
|
353
|
+
* Find the daemon: `.snag/.port` first, then a bounded probe of 7654–7664.
|
|
354
|
+
*
|
|
355
|
+
* `GET /health` is unauthenticated by design (doc 02 §7.1) and reports
|
|
356
|
+
* `name: 'snagd'`, which is what tells us a stray service on 7655 is not the
|
|
357
|
+
* daemon — the appendix is explicit that the probe must be able to make that
|
|
358
|
+
* distinction.
|
|
359
|
+
*
|
|
360
|
+
* A daemon serving exactly this root wins outright. Failing that, the first
|
|
361
|
+
* daemon serving another worktree of the same repository is taken. Failing
|
|
362
|
+
* that, if any snagd answered for a different project this **throws**
|
|
363
|
+
* `DaemonRootMismatchError` naming it, and resolves `null` only when no snagd
|
|
364
|
+
* answered at all.
|
|
365
|
+
*/
|
|
366
|
+
export declare function connectToDaemon(options: ConnectOptions): Promise<DaemonClient | null>;
|
|
367
|
+
export type SourceLabel = 'daemon' | 'files';
|
|
368
|
+
export interface TaskQuery {
|
|
369
|
+
status?: TaskStatus;
|
|
370
|
+
wave?: number;
|
|
371
|
+
limit?: number;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Everything the five tools and four resources need. An interface so the tests
|
|
375
|
+
* can drive the handlers with a fake, and so the disk fallback is a swap rather
|
|
376
|
+
* than a branch inside every handler.
|
|
377
|
+
*/
|
|
378
|
+
/** What `POST /git/commit` answers — snagd's own words, passed through. */
|
|
379
|
+
export interface CommitAnswer {
|
|
380
|
+
ok: boolean;
|
|
381
|
+
code: string;
|
|
382
|
+
message: string;
|
|
383
|
+
files: string[];
|
|
384
|
+
sha?: string;
|
|
385
|
+
branch?: string;
|
|
386
|
+
commit_message?: string;
|
|
387
|
+
}
|
|
388
|
+
export interface SnagBackend {
|
|
389
|
+
readonly root: string;
|
|
390
|
+
readonly files: FileStore;
|
|
391
|
+
config(): SnagConfig;
|
|
392
|
+
listTasks(query: TaskQuery): Promise<{
|
|
393
|
+
tasks: Task[];
|
|
394
|
+
source: SourceLabel;
|
|
395
|
+
}>;
|
|
396
|
+
getTask(id: string): Promise<{
|
|
397
|
+
task: Task;
|
|
398
|
+
file: string | null;
|
|
399
|
+
source: SourceLabel;
|
|
400
|
+
} | null>;
|
|
401
|
+
/** Throws `DaemonUnavailableError` when `snagd` is not running. */
|
|
402
|
+
setStatus(id: string, status: TaskStatus): Promise<Task>;
|
|
403
|
+
/** The daemon's verify preflight (`dry_run`). Throws `DaemonUnavailableError` like a write. */
|
|
404
|
+
verifyPreflight(taskId: string): Promise<VerifyPreflightResult>;
|
|
405
|
+
/** `GET /verify/:taskId`; `null` without a daemon, or when it has nothing to say. Never throws for that. */
|
|
406
|
+
verifyStatus(taskId: string): Promise<VerifyStatus | null>;
|
|
407
|
+
queueVerify(taskId: string, body: {
|
|
408
|
+
commit?: string;
|
|
409
|
+
note?: string;
|
|
410
|
+
}): Promise<VerifyQueueResult>;
|
|
411
|
+
/** `POST /git/commit`. Throws `DaemonUnavailableError`: only snagd can commit. */
|
|
412
|
+
commit(body: {
|
|
413
|
+
task?: string;
|
|
414
|
+
files?: string[];
|
|
415
|
+
message?: string;
|
|
416
|
+
}): Promise<CommitAnswer>;
|
|
417
|
+
plan(): Promise<{
|
|
418
|
+
plan: Plan | null;
|
|
419
|
+
source: SourceLabel;
|
|
420
|
+
}>;
|
|
421
|
+
map(): Promise<{
|
|
422
|
+
map: RepoMap | null;
|
|
423
|
+
source: SourceLabel;
|
|
424
|
+
}>;
|
|
425
|
+
health(): Promise<HealthPayload | null>;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* The real backend: daemon when it answers, `.snag/` when it does not.
|
|
429
|
+
*
|
|
430
|
+
* The daemon handle is resolved once, lazily, and re-resolved after a failure
|
|
431
|
+
* so a daemon started mid-session is picked up without restarting the MCP
|
|
432
|
+
* server (Claude Code keeps a stdio server alive for the whole session).
|
|
433
|
+
*/
|
|
434
|
+
/**
|
|
435
|
+
* How long a failed discovery is remembered before probing again.
|
|
436
|
+
*
|
|
437
|
+
* Without this, every tool call in a burst re-probes all eleven ports. The
|
|
438
|
+
* probe is cheap on a healthy machine (a closed loopback port refuses
|
|
439
|
+
* immediately) but not free, and a black-holed port costs the full timeout
|
|
440
|
+
* each time. Two seconds is long enough to cover one agent turn and short
|
|
441
|
+
* enough that a daemon started mid-session is picked up almost at once —
|
|
442
|
+
* Claude Code keeps a stdio server alive for the whole session, so
|
|
443
|
+
* "restart the MCP server" must never be the fix for "I started snagd".
|
|
444
|
+
*/
|
|
445
|
+
export declare const DAEMON_RETRY_AFTER_MS = 2000;
|
|
446
|
+
export declare class SnagClient implements SnagBackend {
|
|
447
|
+
readonly root: string;
|
|
448
|
+
readonly files: FileStore;
|
|
449
|
+
private readonly connect;
|
|
450
|
+
private daemonPromise;
|
|
451
|
+
/** The handle `daemonPromise` last resolved to, so a stale failure can be told apart. */
|
|
452
|
+
private connected;
|
|
453
|
+
/**
|
|
454
|
+
* `-Infinity`, not `0`: "no failure yet" must never look like "failed at time
|
|
455
|
+
* zero", or the very first call is swallowed by the backoff window.
|
|
456
|
+
*/
|
|
457
|
+
private lastFailureAt;
|
|
458
|
+
private cachedConfig;
|
|
459
|
+
private readonly now;
|
|
460
|
+
private readonly gitCommonDir;
|
|
461
|
+
/**
|
|
462
|
+
* The snagd the last discovery skipped because it serves another project.
|
|
463
|
+
* Kept through the backoff window, so every write in it can say where the
|
|
464
|
+
* daemon actually is instead of claiming there is none.
|
|
465
|
+
*/
|
|
466
|
+
private mismatch;
|
|
467
|
+
constructor(root: string, connect?: () => Promise<DaemonClient | null>, now?: () => number, gitCommonDir?: GitCommonDirLookup);
|
|
468
|
+
/** `null` when the daemon is unreachable. Never throws. */
|
|
469
|
+
daemon(): Promise<DaemonClient | null>;
|
|
470
|
+
/**
|
|
471
|
+
* Drop the cached handle after the daemon stopped answering.
|
|
472
|
+
*
|
|
473
|
+
* A handle that resolved once used to be kept for the life of the MCP
|
|
474
|
+
* server, so a snagd that was stopped and restarted — which picks the first
|
|
475
|
+
* free port and may not get the old one back — was never found again: every
|
|
476
|
+
* call went to the dead port and fell back to files. Forgetting it makes the
|
|
477
|
+
* next call re-probe, after the same backoff window a failed probe gets.
|
|
478
|
+
*
|
|
479
|
+
* `stale` is the handle that failed. Claude Code can run tool calls in
|
|
480
|
+
* parallel, so a failure on a handle another call has already replaced must
|
|
481
|
+
* not throw away the replacement.
|
|
482
|
+
*
|
|
483
|
+
* `backoff: false` is for a handle that answered but is no longer ours: the
|
|
484
|
+
* port is alive, so waiting out the window would only delay finding where
|
|
485
|
+
* our snagd went. The next call re-probes at once.
|
|
486
|
+
*/
|
|
487
|
+
private forgetDaemon;
|
|
488
|
+
/**
|
|
489
|
+
* The daemon, or a thrown `DaemonUnavailableError` — the root-mismatch
|
|
490
|
+
* subclass when the only snagd that answered serves another project.
|
|
491
|
+
*/
|
|
492
|
+
private requireDaemon;
|
|
493
|
+
/**
|
|
494
|
+
* The daemon for a write, with its identity asked again first.
|
|
495
|
+
*
|
|
496
|
+
* The handle is cached for the life of the MCP server, and a snagd that
|
|
497
|
+
* restarted binds the first free port — which another project's snagd may
|
|
498
|
+
* since have taken. That daemon answers `PATCH /tasks/SNAG-3` perfectly well,
|
|
499
|
+
* for its own SNAG-3. Reads tolerate the risk (they are labelled and cheap to
|
|
500
|
+
* repeat); a status change does not, so `/health` is asked before every one,
|
|
501
|
+
* and a handle that now answers for another root is dropped and discovery
|
|
502
|
+
* runs again on the spot.
|
|
503
|
+
*/
|
|
504
|
+
private writableDaemon;
|
|
505
|
+
/**
|
|
506
|
+
* Forget the daemon if `error` says it is gone, and return the error to throw.
|
|
507
|
+
* The request-level error names the base URL where the project root belongs,
|
|
508
|
+
* so it is rebuilt against the root — its message tells the agent where to
|
|
509
|
+
* start snagd.
|
|
510
|
+
*/
|
|
511
|
+
private unavailable;
|
|
512
|
+
config(): SnagConfig;
|
|
513
|
+
listTasks(query: TaskQuery): Promise<{
|
|
514
|
+
tasks: Task[];
|
|
515
|
+
source: SourceLabel;
|
|
516
|
+
}>;
|
|
517
|
+
getTask(id: string): Promise<{
|
|
518
|
+
task: Task;
|
|
519
|
+
file: string | null;
|
|
520
|
+
source: SourceLabel;
|
|
521
|
+
} | null>;
|
|
522
|
+
commit(body: {
|
|
523
|
+
task?: string;
|
|
524
|
+
files?: string[];
|
|
525
|
+
message?: string;
|
|
526
|
+
}): Promise<CommitAnswer>;
|
|
527
|
+
setStatus(id: string, status: TaskStatus): Promise<Task>;
|
|
528
|
+
verifyPreflight(taskId: string): Promise<VerifyPreflightResult>;
|
|
529
|
+
verifyStatus(taskId: string): Promise<VerifyStatus | null>;
|
|
530
|
+
queueVerify(taskId: string, body: {
|
|
531
|
+
commit?: string;
|
|
532
|
+
note?: string;
|
|
533
|
+
}): Promise<VerifyQueueResult>;
|
|
534
|
+
plan(): Promise<{
|
|
535
|
+
plan: Plan | null;
|
|
536
|
+
source: SourceLabel;
|
|
537
|
+
}>;
|
|
538
|
+
map(): Promise<{
|
|
539
|
+
map: RepoMap | null;
|
|
540
|
+
source: SourceLabel;
|
|
541
|
+
}>;
|
|
542
|
+
health(): Promise<HealthPayload | null>;
|
|
543
|
+
}
|
|
544
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|