@adhd/backlog 0.1.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -44
- package/README.md +332 -81
- package/api.d.ts +146 -0
- package/cli.d.ts +45 -18
- package/env.d.ts +23 -3
- package/envelope.d.ts +163 -0
- package/index.d.ts +11 -10
- package/index.js +531 -173
- package/index.mjs +29814 -15647
- package/install-skill.d.ts +23 -0
- package/package.json +50 -15
- package/query/card.d.ts +31 -0
- package/query/get.d.ts +11 -0
- package/query/index.d.ts +67 -0
- package/query/markdown.d.ts +11 -0
- package/query/query.d.ts +131 -0
- package/query/resolve.d.ts +123 -0
- package/query/types.d.ts +450 -0
- package/query/views/registry.d.ts +43 -0
- package/query/views/semantic.d.ts +101 -0
- package/query/views/stats.d.ts +109 -0
- package/search-shortcut.d.ts +79 -0
- package/serve.d.ts +18 -0
- package/server.d.ts +139 -4
- package/skill/SKILL.md +619 -138
- package/store/graph-backlog-store.d.ts +80 -17
- package/store/immediate-retry.d.ts +24 -13
- package/store/type-policy.d.ts +4 -0
- package/store/vocabulary-guard.d.ts +52 -0
- package/version-info.d.ts +15 -0
- package/write/audit.d.ts +36 -0
- package/write/bootstrap.d.ts +123 -0
- package/write/catalog.d.ts +351 -0
- package/write/claim-lease.d.ts +21 -0
- package/write/claim.d.ts +80 -0
- package/write/create-issue.d.ts +250 -0
- package/write/delete.d.ts +39 -0
- package/write/embed-drain.d.ts +68 -0
- package/write/embedding-observer.d.ts +80 -0
- package/write/errors.d.ts +303 -0
- package/write/issue-status.d.ts +10 -0
- package/write/move.d.ts +70 -0
- package/write/relate.d.ts +52 -0
- package/write/transition.d.ts +60 -0
- package/write/tx.d.ts +344 -0
- package/write/update.d.ts +81 -0
- package/client.d.ts +0 -169
- package/markdown.d.ts +0 -75
- package/migration-admin.d.ts +0 -26
- package/model.d.ts +0 -437
- package/store/audit-log.d.ts +0 -16
- package/store/claim.d.ts +0 -24
- package/store/crud.d.ts +0 -62
- package/store/ids.d.ts +0 -24
- package/store/lifecycle.d.ts +0 -36
- package/store/mapping.d.ts +0 -101
- package/store/mutate-metadata.d.ts +0 -8
- package/store/query.d.ts +0 -68
- package/store/repo-migration.d.ts +0 -51
- package/store/serve-lock.d.ts +0 -42
- package/store/structure.d.ts +0 -66
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { IQueryStoreHandle } from '../query.js';
|
|
2
|
+
import { IIssueFilter } from '../types.js';
|
|
3
|
+
|
|
4
|
+
export interface IPriorityMatrixRow {
|
|
5
|
+
priority: string;
|
|
6
|
+
priorityUid: string;
|
|
7
|
+
/** `priority.meta.metadata.rank` (`nextPriorityRankTx`, §2) — lower is more urgent. Absent only for a malformed pre-existing row with no numeric rank; the count itself is still real. */
|
|
8
|
+
rank?: number;
|
|
9
|
+
count: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IPriorityMatrixResult {
|
|
12
|
+
/** Sorted by `rank` ascending (a missing rank sorts last), mirroring `query.ts`'s own `sortByPriorityRank` convention. */
|
|
13
|
+
rows: IPriorityMatrixRow[];
|
|
14
|
+
/** In-scope issues carrying no live `has_priority` edge at all — never silently folded into a phantom priority row, never silently dropped from the total. */
|
|
15
|
+
unassigned: number;
|
|
16
|
+
/** The status scope actually applied. `'open'` when `filter?.status` was omitted (BUG-023's fix) — echoed here so a caller can never mistake a default-scoped result for an all-status one. */
|
|
17
|
+
statusScope: NonNullable<IIssueFilter['status']>;
|
|
18
|
+
}
|
|
19
|
+
export interface IPriorityMatrixInput {
|
|
20
|
+
/** `project`/`component`/`kind`/`status` only (§6.5 rule 3's edge-scoped dimensions, restricted to what a priority breakdown composes with) — any other key throws. */
|
|
21
|
+
filter?: IIssueFilter;
|
|
22
|
+
}
|
|
23
|
+
/** SPEC.md §5's status-aware priority matrix (BUG-023). */
|
|
24
|
+
export declare function priorityMatrix(handle: IQueryStoreHandle, input?: IPriorityMatrixInput): Promise<IPriorityMatrixResult>;
|
|
25
|
+
export interface IPartOfRollupInput {
|
|
26
|
+
/** The root issue's `uid` (§6.1). Throws `IssueNotFoundError` if it does not resolve to a live issue. */
|
|
27
|
+
uid: string;
|
|
28
|
+
}
|
|
29
|
+
export interface IPartOfRollupResult {
|
|
30
|
+
uid: string;
|
|
31
|
+
/** Every TRANSITIVE descendant via `part_of` (issue → issue, `n:1`, §3) — not just direct children. Counted exactly once each, regardless of chain depth. */
|
|
32
|
+
childrenTotal: number;
|
|
33
|
+
childrenOpen: number;
|
|
34
|
+
childrenClosed: number;
|
|
35
|
+
/** `uid`s of the still-open descendants — the actionable half, mirroring the `IIssueRef`-shaped convention `card.ts`'s `blockers`/`related` already use. */
|
|
36
|
+
childrenOpenUids: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SPEC.md §5's `part_of` + derived two-axis rollup (FEAT-005), realized as
|
|
40
|
+
* ONE axis here — children-open/closed over the FULL transitive subtree
|
|
41
|
+
* (the second axis, "does THIS item carry its own closing evidence," is a
|
|
42
|
+
* `get`/card-assembly concern over the root's own citations, out of scope
|
|
43
|
+
* for a rollup over its CHILDREN).
|
|
44
|
+
*
|
|
45
|
+
* Uses `getSubgraph(rootId, {rel:'part_of', direction:'in', depth:-1})` —
|
|
46
|
+
* the unbounded walk (verified: `getNeighbors`'s `depth` is a row BUDGET,
|
|
47
|
+
* not a depth bound, per `@adhd/sox-graph-store`'s own dist comment; only
|
|
48
|
+
* `getSubgraph`'s `-1` sentinel gives a genuine unbounded multi-level walk)
|
|
49
|
+
* with its own internal visited set, so a grandchild (or deeper) reached
|
|
50
|
+
* through exactly one path is collected into the SAME node set as a direct
|
|
51
|
+
* child — counted once, never re-added by also summing each child's own
|
|
52
|
+
* subtree size on top of a direct-children count. `getSubgraph` does NOT
|
|
53
|
+
* filter node liveness (documented on the library's own `getSubgraphIterative`:
|
|
54
|
+
* "an invalidated node behind a live edge IS part of the subgraph") — a
|
|
55
|
+
* soft-deleted descendant is explicitly filtered back out below, since a
|
|
56
|
+
* deleted issue is neither open work nor closed work, it is gone.
|
|
57
|
+
*/
|
|
58
|
+
export declare function partOfRollup(handle: IQueryStoreHandle, input: IPartOfRollupInput): Promise<IPartOfRollupResult>;
|
|
59
|
+
export interface IOpenCurveInput {
|
|
60
|
+
/** `project`/`component`/`kind` only — `status` is rejected (`InvalidArgumentError`): this view computes openness itself, per sampled instant, so a caller-given status filter would silently conflict with that computation rather than compose with it. */
|
|
61
|
+
filter?: IIssueFilter;
|
|
62
|
+
/** ISO-8601 instants to sample, in the given order. Must be non-empty; each is parsed via `Date.parse` and normalized to a full ISO string for lexical comparison against stored `at` timestamps — an unparsable entry throws by name rather than silently producing `NaN`-derived output. */
|
|
63
|
+
at: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
export interface IOpenCurvePoint {
|
|
66
|
+
at: string;
|
|
67
|
+
/** In-scope issues that EXISTED at this instant (`NodeFilter.validAt`: `t_created <= at` and `t_invalid` is null or after `at`) — exact, never reconstructed. */
|
|
68
|
+
existed: number;
|
|
69
|
+
/** Of `existed`, the count whose RECONSTRUCTED status was non-terminal at this instant (never the issue's CURRENT status) — see {@link reconstructStatusAt}. */
|
|
70
|
+
open: number;
|
|
71
|
+
/** `existed - open`. */
|
|
72
|
+
closed: number;
|
|
73
|
+
}
|
|
74
|
+
export interface IOpenCurveResult {
|
|
75
|
+
points: readonly IOpenCurvePoint[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* SPEC.md §5's `validAt`-driven cumulative-open curve.
|
|
79
|
+
*
|
|
80
|
+
* **Cost is bounded by the sampled-instant count and the size of the
|
|
81
|
+
* `has_status`/`audits` relations, never by (instants × existing-issue
|
|
82
|
+
* count).** The obvious shape — for each sampled instant, fetch the issues
|
|
83
|
+
* that existed then, per issue, fetch its current-status edge, its
|
|
84
|
+
* current-status node, and its full audit trail — is up to four sequential
|
|
85
|
+
* round trips PER ISSUE PER INSTANT. Ten sampled instants over a 5,000-issue
|
|
86
|
+
* store cost on the order of 200,000 serialized queries under that shape,
|
|
87
|
+
* even though nothing about "how open was the store on these ten dates"
|
|
88
|
+
* scales with store size on its own — it should scale with the number of
|
|
89
|
+
* dates the caller asked about. Worse, an issue's CURRENT status and full
|
|
90
|
+
* audit trail don't depend on `at` at all (`reconstructStatusAt` only reads
|
|
91
|
+
* them; it never asks the backend anything itself), so the naive per-instant
|
|
92
|
+
* loop was refetching the exact same unchanging per-issue data once per
|
|
93
|
+
* instant for nothing.
|
|
94
|
+
*
|
|
95
|
+
* Instead, both relations are fetched ONCE, before the instant loop, and
|
|
96
|
+
* grouped in memory — the same shape `query.ts`'s `queryReady` already uses
|
|
97
|
+
* for `blocks`/`has_status`: `getEdges({rel:'has_status'})` and
|
|
98
|
+
* `getEdges({rel:'audits'})` each take the WHOLE relation in a single call
|
|
99
|
+
* (there is no batch-by-many-`src` primitive — `getEdges` accepts only one
|
|
100
|
+
* `src`/`dst` at a time, which is exactly why fetching the whole relation
|
|
101
|
+
* once is the right move), plus one `getNodesByIds` each to resolve the
|
|
102
|
+
* status/audit-entry nodes those edges point at — see
|
|
103
|
+
* {@link resolveCurrentStatusAndAuditTrails}. That's four queries total for
|
|
104
|
+
* this cost, however many issues or instants are involved; the only
|
|
105
|
+
* per-instant cost left is the one `queryNodes({validAt})` call SPEC.md's own
|
|
106
|
+
* existence check requires. Total round trips: `4 + M` for `M` sampled
|
|
107
|
+
* instants — independent of N, the number of issues in the store.
|
|
108
|
+
*/
|
|
109
|
+
export declare function openCurve(handle: IQueryStoreHandle, input: IOpenCurveInput): Promise<IOpenCurveResult>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* search-shortcut.ts — `backlog search "<text>" [flags]`, a pure ARGV
|
|
3
|
+
* TRANSLATION onto the mounted `query` operation.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a translation and not a seventh operation
|
|
6
|
+
*
|
|
7
|
+
* The apigen mount-surface spec §3 fixes the apigen mount surface at exactly six verbs
|
|
8
|
+
* (`get, query, create, update, relate, admin`) — `index.ts`'s own comment
|
|
9
|
+
* above those exports says "these, and only these". Adding a `search` export
|
|
10
|
+
* to `client.ts` would widen that surface for every transport (CLI, HTTP,
|
|
11
|
+
* MCP) to buy CLI ergonomics, which is the wrong trade. So `search` never
|
|
12
|
+
* becomes an operation: `runBacklogCli` rewrites its argv into
|
|
13
|
+
* `['query', '--input', '<json>']` and hands it to the SAME
|
|
14
|
+
* `@adhd/apigen-plugin-cli-output` dispatch every other command goes
|
|
15
|
+
* through. Store lifecycle, signal cleanup, `exitCodeForEnvelope` mapping and
|
|
16
|
+
* output shape are therefore reused unchanged rather than reimplemented —
|
|
17
|
+
* this module is a pure function over `string[]` and opens nothing.
|
|
18
|
+
*
|
|
19
|
+
* ## Why the positional compiles to `text`, not `filter.semantic`
|
|
20
|
+
*
|
|
21
|
+
* `IIssueQueryInput.text` is already specified as "the natural-language
|
|
22
|
+
* query; also the CLI positional form" (§2.1b) — this shortcut is the CLI
|
|
23
|
+
* form that field was written for. `resolveTextInput` (query/query.ts, called
|
|
24
|
+
* once from `queryIssues`) routes the whole string into `filter.semantic`
|
|
25
|
+
* when the vector space is readable and into `filter.grep` when it is NOT
|
|
26
|
+
* (RAG-SPEC §3.1 / BUG-045), and picks `sort: "relevance"` or `"textMatch"`
|
|
27
|
+
* to match. Compiling the positional straight to `filter.semantic` instead
|
|
28
|
+
* would hard-fail on an unconfigured or unbackfilled store, throwing away a
|
|
29
|
+
* working keyword answer — and would ALSO need this module to hardcode a
|
|
30
|
+
* `sort` default that `resolveTextInput` already derives correctly. Neither
|
|
31
|
+
* divergence is worth owning here.
|
|
32
|
+
*
|
|
33
|
+
* For the same reason there is no `fields` default: the `text` path's own
|
|
34
|
+
* projection is already the compact `uid/kind/title/status/priority`
|
|
35
|
+
* list (`DEFAULT_ISSUE_CARD_FIELDS`, query/types.ts), so a default invented
|
|
36
|
+
* here could only make it worse. `--fields` overrides it (add `_score` to
|
|
37
|
+
* see the ranking scores).
|
|
38
|
+
*
|
|
39
|
+
* ## Error parity
|
|
40
|
+
*
|
|
41
|
+
* The flags below are hand-parsed, not schema-derived, so every rejection
|
|
42
|
+
* mirrors `@adhd/apigen-plugin-cli-output`'s `parseArgs`/validate-Layer
|
|
43
|
+
* wording byte-for-byte: `Unknown option: --X. Available: …` (a REAL list, never a placebo),
|
|
44
|
+
* `Missing value for --X`, `Unexpected positional argument: "X"`. The caller
|
|
45
|
+
* prints them as `{"code":"invalid_argument","message":…}` on stderr with
|
|
46
|
+
* `process.exitCode = 2` (`CLI_EXIT_CODE['invalid_argument']`).
|
|
47
|
+
*
|
|
48
|
+
* DEBT-BACKLOG-001 (the backlog CLI's bespoke argv parsing diverging from the
|
|
49
|
+
* apigen-mounted surface) is enlarged by this file, deliberately and with the
|
|
50
|
+
* parity discipline above; see that item.
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* The complete, REAL flag vocabulary — the `Available:` list an unknown-option
|
|
54
|
+
* rejection prints. Derived from the four arrays above rather than
|
|
55
|
+
* hand-maintained, so a flag can never be accepted but unlisted (or listed
|
|
56
|
+
* but unaccepted).
|
|
57
|
+
*/
|
|
58
|
+
export declare const SEARCH_FLAGS: readonly string[];
|
|
59
|
+
export declare const SEARCH_HELP: string;
|
|
60
|
+
/** A rendered `--help`, a rejection, or the rewritten argv to dispatch. */
|
|
61
|
+
export type SearchShortcutOutcome = {
|
|
62
|
+
kind: 'help';
|
|
63
|
+
text: string;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'error';
|
|
66
|
+
message: string;
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'argv';
|
|
69
|
+
argv: string[];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Translates `search`'s tokens (everything AFTER the `search` word) into the
|
|
73
|
+
* `['query', '--input', '<json>']` argv the apigen command table dispatches.
|
|
74
|
+
*
|
|
75
|
+
* Pure: reads no config, opens no store, touches no globals — so the caller
|
|
76
|
+
* can reject a bad invocation before any of `runBacklogCli`'s store lifecycle
|
|
77
|
+
* has started, and so every branch here is unit-testable on its own.
|
|
78
|
+
*/
|
|
79
|
+
export declare function buildSearchArgv(rest: readonly string[]): SearchShortcutOutcome;
|
package/serve.d.ts
CHANGED
|
@@ -5,7 +5,25 @@ export interface RunServeCommandOpts {
|
|
|
5
5
|
/** Test-only override — see `buildBacklogEnv`'s `BuildBacklogEnvOptions`. */
|
|
6
6
|
adhdRoot?: string;
|
|
7
7
|
cwd?: string;
|
|
8
|
+
/** Explicit-parameter-first namespace override — see
|
|
9
|
+
* `BuildBacklogEnvOptions.namespace`'s doc comment. `--namespace sandbox
|
|
10
|
+
* serve` (cli.ts) sets this to `'sandbox'`, along with minting a fresh
|
|
11
|
+
* `adhdRoot` and writing D8's sandbox `config.yaml`. */
|
|
12
|
+
namespace?: string;
|
|
8
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* BUG-033: `backlog serve --help` used to throw a plain `Error` from
|
|
16
|
+
* `parseArgs` (unknown-argument), which `runServeCommand` neither caught nor
|
|
17
|
+
* short-circuited — the error propagated all the way to `index.ts`'s
|
|
18
|
+
* bin-entry guard, which prints `err.stack` unconditionally, so a completely
|
|
19
|
+
* ordinary "show me the help" request rendered as ten frames of minified
|
|
20
|
+
* dist. Mirrors `install.ts`'s established `--help` + `BacklogUsageError` +
|
|
21
|
+
* `failUsage` pattern exactly: `--help`/`-h` anywhere in argv short-circuits
|
|
22
|
+
* BEFORE parsing, and every argument-parsing failure is a `BacklogUsageError`
|
|
23
|
+
* (never a bare `Error`) so `runServeCommand` can catch it and hand it to
|
|
24
|
+
* `failUsage` instead of letting it reach the bin guard's stack-trace path.
|
|
25
|
+
*/
|
|
26
|
+
export declare const SERVE_HELP_TEXT = "backlog serve [--transport mcp|http|both] [--port N] [--host H]\n\nStarts the long-lived backlog server (MCP and/or HTTP), matching one of the\nprocess's own configured transports to the way an agent host or a script\nexpects to reach it.\n\n --transport <name> mcp | http | both (default: mcp)\n --port <N> HTTP listen port (default: 3300; ignored for mcp-only)\n --host <name> HTTP listen host (default: 127.0.0.1; ignored for mcp-only)\n\nExamples:\n backlog serve\n backlog serve --transport http --port 3300\n backlog serve --transport both --host 0.0.0.0\n";
|
|
9
27
|
/** Runs until the process receives SIGTERM/SIGINT (the normal way a host
|
|
10
28
|
* process manager — or `.mcp.json`'s own stdio transport lifecycle — stops
|
|
11
29
|
* a long-lived MCP/HTTP server), then resolves cleanly. */
|
package/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BacklogCtx } from './
|
|
2
|
-
import {
|
|
1
|
+
import { BacklogCtx } from './api.js';
|
|
2
|
+
import { HttpVerb } from '@adhd/apigen-engine-naming';
|
|
3
|
+
import { composeSchemas, Operation, Plugin, Logger, OutputPlugin, RunInput } from '@adhd/apigen-core-client';
|
|
3
4
|
import { Scope } from '@adhd/environment-base-spec';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -37,6 +38,117 @@ export declare function requireRun(plugin: OutputPlugin): (input: RunInput) => P
|
|
|
37
38
|
* `undefined` and the real pino default logger is used, unchanged.
|
|
38
39
|
*/
|
|
39
40
|
export declare function testSilentLogger(): Logger | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* SPEC.md §6.6's "host-command carve-out" — the commands that are
|
|
43
|
+
* deliberately NOT part of the mounted data surface, pinned as a value so the
|
|
44
|
+
* refusal is enforceable rather than prose.
|
|
45
|
+
*
|
|
46
|
+
* `install`/`install-skill` are pure filesystem/config operations that must
|
|
47
|
+
* never open the store (cli.ts:243-256 special-cases them BEFORE the apigen
|
|
48
|
+
* command table is ever built — that is what closes
|
|
49
|
+
* DEBT-BACKLOG-CLI-EAGER-STORE-OPEN-001), and `serve` is a long-lived
|
|
50
|
+
* listener launcher with a completely different lifecycle (cli.ts:262-265).
|
|
51
|
+
* Neither is a data op, so neither may ever appear as an apigen operation on
|
|
52
|
+
* ANY of the four mounts.
|
|
53
|
+
*
|
|
54
|
+
* `assertHostCarveOut` turns §6.6's negative assertion ("`install`/`serve` are
|
|
55
|
+
* NOT among the mounted verbs") into a mount-time invariant: a future refactor that
|
|
56
|
+
* accidentally exports a host command from the mounted client module fails at
|
|
57
|
+
* `buildBacklogApigenPackage()` — in every transport at once — instead of
|
|
58
|
+
* silently shipping a `backlog_serve` MCP tool that would open a second
|
|
59
|
+
* concurrent writer against the store via a completely different lifecycle
|
|
60
|
+
* path than the one `startBacklogServer` itself expects.
|
|
61
|
+
*/
|
|
62
|
+
export declare const BACKLOG_HOST_COMMANDS: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* SPEC.md §6.7 — the data verbs the whole surface consolidates onto:
|
|
65
|
+
* the nine issue verbs plus `lookup`, §3a's registry CRUD verbs, and the
|
|
66
|
+
* three §5 stats/rollup reads (`priority-matrix`/`part-of-rollup`/
|
|
67
|
+
* `open-curve`), mounted as `backlog_<verb>`. Pinned here, next to the
|
|
68
|
+
* carve-out it is the complement of, because it is the ONE list four separate
|
|
69
|
+
* surfaces are
|
|
70
|
+
* checked against: the three apigen mounts derive their names from the
|
|
71
|
+
* operation descriptors via `describeMountedSurface`, and `cli.ts`'s argv
|
|
72
|
+
* parser — which is deliberately NOT an apigen mount, because apigen's
|
|
73
|
+
* `parseArgs` cannot express the §2.1b positional form, projects `string[]`
|
|
74
|
+
* as a JSON-valued flag where §7.3 wants comma-separated, and only sets
|
|
75
|
+
* `process.exitCode` on a thrown `ApiError` (so an `ok:false` envelope would
|
|
76
|
+
* exit 0, contradicting `BACKLOG_EXIT_CODE`) — has to be checked against this list rather than
|
|
77
|
+
* derived from the mount.
|
|
78
|
+
*
|
|
79
|
+
* That asymmetry is exactly how a split brain starts, and this repo already
|
|
80
|
+
* has one open as BUG-BACKLOG-MCP-CLI-SPLIT-BRAIN-001. `server.verbs.spec.ts`
|
|
81
|
+
* asserts BOTH sides against this constant so a verb added to one surface and
|
|
82
|
+
* forgotten on the other fails a test instead of shipping.
|
|
83
|
+
*
|
|
84
|
+
* Order is the SPEC.md §4/§6 declaration order, not alphabetical; compare as sets.
|
|
85
|
+
*/
|
|
86
|
+
export declare const BACKLOG_VERBS: readonly string[];
|
|
87
|
+
/**
|
|
88
|
+
* One mounted operation, projected to all four transports backlog serves.
|
|
89
|
+
*
|
|
90
|
+
* Every field here is computed by `@adhd/apigen-engine-naming`'s `project()`
|
|
91
|
+
* — the SAME function `apigen-plugin-api-fastify` (`run.ts:214-215` via
|
|
92
|
+
* `routeFor`), `apigen-plugin-mcp` (tool registration), `apigen-plugin-cli-output`
|
|
93
|
+
* (command table) and `@adhd/apigen-codegen-openapi`'s `toOpenApi`
|
|
94
|
+
* (`to-openapi.ts:131` → `paths[route]`) each call independently. That shared
|
|
95
|
+
* projector is *why* the four surfaces agree: there is one operation
|
|
96
|
+
* descriptor list and one naming function, never a per-transport definition
|
|
97
|
+
* and never a hand-maintained OpenAPI document.
|
|
98
|
+
*/
|
|
99
|
+
export interface IMountedOperationSurface {
|
|
100
|
+
/** Canonical apigen operation id (e.g. `backlog/get-item`). */
|
|
101
|
+
id: string;
|
|
102
|
+
/** CLI command as a human types it, e.g. `backlog get-item`. */
|
|
103
|
+
cliCommand: string;
|
|
104
|
+
/** CLI command segments, e.g. `['backlog','get-item']`. */
|
|
105
|
+
cliPath: string[];
|
|
106
|
+
/** MCP tool name as a host loads it, e.g. `backlog_get_item`. */
|
|
107
|
+
mcpTool: string;
|
|
108
|
+
/** HTTP verb the fastify mount registers. */
|
|
109
|
+
httpVerb: HttpVerb;
|
|
110
|
+
/** HTTP route the fastify mount registers AND the OpenAPI `paths` key. */
|
|
111
|
+
httpRoute: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Projects the extracted operation descriptors onto the four transports
|
|
115
|
+
* backlog mounts, returning the single expected surface.
|
|
116
|
+
*
|
|
117
|
+
* This is the mechanical statement of SPEC.md §6.7: *one* operation
|
|
118
|
+
* definition serves CLI, MCP, REST and OpenAPI. A test (or an operator) can
|
|
119
|
+
* call this once and compare it against what each live transport actually
|
|
120
|
+
* advertises; a divergence means some transport grew its own definition,
|
|
121
|
+
* which is precisely what §6.7 forbids.
|
|
122
|
+
*
|
|
123
|
+
* Only `kind: 'action'` operations are mounted — the same filter
|
|
124
|
+
* `buildBacklogApigenPackage` applies when it builds `generated.schemas`, so
|
|
125
|
+
* this never claims a surface the package does not actually compose.
|
|
126
|
+
*
|
|
127
|
+
* @param operations the descriptor list returned by `buildBacklogApigenPackage`
|
|
128
|
+
* @returns one entry per mounted operation, sorted by canonical id for stable
|
|
129
|
+
* comparison
|
|
130
|
+
*/
|
|
131
|
+
export declare function describeMountedSurface(operations: readonly Operation[]): IMountedOperationSurface[];
|
|
132
|
+
/**
|
|
133
|
+
* Derives the FULL set of MCP tool names the real `serve --transport mcp`
|
|
134
|
+
* process advertises — every mounted `client.ts` verb (via
|
|
135
|
+
* `describeMountedSurface`'s `mcpTool`, itself `project(op).mcp.name`) PLUS
|
|
136
|
+
* every tool a mount plugin (currently just `apigen-plugin-batch`'s
|
|
137
|
+
* `batch_action`) contributes, using the exact same `project(op).mcp.name`
|
|
138
|
+
* derivation `cli.ts`'s `resolveMountNamespaces` uses for the CLI's own
|
|
139
|
+
* top-level segments.
|
|
140
|
+
*
|
|
141
|
+
* Exists so a test can assert against a LIVE-derived tool set instead of a
|
|
142
|
+
* hardcoded literal array/count — a hardcoded `['backlog_get', …]` (or a bare
|
|
143
|
+
* `.length === 7`) silently stops meaning anything the moment a `client.ts`
|
|
144
|
+
* export is added, renamed, or removed, and would then either falsely fail
|
|
145
|
+
* (a legitimate, intended surface change) or — worse — falsely pass (typo'd
|
|
146
|
+
* to match the wrong new count) with no signal that the assertion itself
|
|
147
|
+
* needs updating. Deriving it here, from the same `operations`/`usePlugins`
|
|
148
|
+
* every transport is actually built from, means the assertion tracks the
|
|
149
|
+
* shipped surface automatically.
|
|
150
|
+
*/
|
|
151
|
+
export declare function resolveExpectedMcpToolNames(operations: readonly Operation[], usePlugins?: readonly Plugin[]): string[];
|
|
40
152
|
export interface StartOpts {
|
|
41
153
|
transport: 'http' | 'mcp' | 'both';
|
|
42
154
|
port?: number;
|
|
@@ -46,6 +158,9 @@ export interface StartOpts {
|
|
|
46
158
|
adhdRoot?: string;
|
|
47
159
|
cwd?: string;
|
|
48
160
|
signal: AbortSignal;
|
|
161
|
+
/** Explicit-parameter-first namespace override — see
|
|
162
|
+
* `BuildBacklogEnvOptions.namespace`'s doc comment. */
|
|
163
|
+
namespace?: string;
|
|
49
164
|
}
|
|
50
165
|
/**
|
|
51
166
|
* Builds the composed, apigen-ready package descriptor for `client.ts`'s
|
|
@@ -56,18 +171,38 @@ export interface StartOpts {
|
|
|
56
171
|
* when a dispatched command actually reaches the real function, which never
|
|
57
172
|
* happens for `--help`/no-args/an unknown command. This is what closes
|
|
58
173
|
* DEBT-BACKLOG-CLI-EAGER-STORE-OPEN-001: `operations`/`schemas` below are
|
|
59
|
-
* computed purely from the built `
|
|
174
|
+
* computed purely from the built `api.d.ts` (via `extractApiOperations`)
|
|
60
175
|
* and never touch `ctx` at all, so a lazy caller can defer opening the real
|
|
61
176
|
* backing store until a command that actually needs it is dispatched.
|
|
177
|
+
*
|
|
178
|
+
* @param opts.adhdRoot/instanceId BUG-BACKLOG-SANDBOX-IRCACHE-001 — forwarded
|
|
179
|
+
* verbatim to `extractApiOperations`/the IR-cache plugin, so a caller
|
|
180
|
+
* already isolating its real store via `adhdRoot` (`--namespace sandbox`, or any
|
|
181
|
+
* other test-isolation caller of `buildBacklogEnv`) gets the extract-stage
|
|
182
|
+
* IR cache isolated the SAME way, instead of it silently falling through
|
|
183
|
+
* to the real machine `HOME`. Optional and additive — every existing call
|
|
184
|
+
* site that omits it keeps its prior (real-`HOME`, shared-cache) behavior
|
|
185
|
+
* exactly.
|
|
62
186
|
*/
|
|
63
|
-
export declare function buildBacklogApigenPackage(ctx: BacklogCtx | (() => BacklogCtx | Promise<BacklogCtx>)
|
|
187
|
+
export declare function buildBacklogApigenPackage(ctx: BacklogCtx | (() => BacklogCtx | Promise<BacklogCtx>), opts?: {
|
|
188
|
+
adhdRoot?: string;
|
|
189
|
+
instanceId?: string;
|
|
190
|
+
}): Promise<{
|
|
64
191
|
pkg: {
|
|
65
192
|
id: string;
|
|
193
|
+
version: string;
|
|
66
194
|
schemas: ReturnType<typeof composeSchemas>;
|
|
67
195
|
importPath: string;
|
|
68
196
|
fns: Record<string, (...args: unknown[]) => unknown>;
|
|
69
197
|
createClient: () => Promise<BacklogCtx>;
|
|
70
198
|
};
|
|
199
|
+
/**
|
|
200
|
+
* §6.7: the four-transport projection of `operations`, computed once here
|
|
201
|
+
* so CLI, MCP, REST and OpenAPI are provably reading ONE definition. Callers
|
|
202
|
+
* that need to know "what is mounted" must read this rather than
|
|
203
|
+
* re-deriving names per transport.
|
|
204
|
+
*/
|
|
205
|
+
surface: IMountedOperationSurface[];
|
|
71
206
|
operations: Operation[];
|
|
72
207
|
}>;
|
|
73
208
|
/**
|