@adhd/backlog 0.1.9 → 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 +80 -47
- 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 +30039 -15879
- 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/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 -174
- 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
package/query/types.d.ts
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* types.ts — the read/query-layer's own shared types (SPEC.md §5, §5a, §6.1, §6.5).
|
|
3
|
+
*
|
|
4
|
+
* These are the TYPESCRIPT shapes for the `get`/`query` verbs (§6.3.1, §6.5)
|
|
5
|
+
* and the §3a registry read views. They intentionally mirror SPEC.md's own
|
|
6
|
+
* `IIssue*`/`IProject*` interfaces field-for-field — this file is the single
|
|
7
|
+
* place those interfaces are declared for the read layer; `get.ts`/`query.ts`/
|
|
8
|
+
* `registry.ts` all import from here rather than re-declaring their own
|
|
9
|
+
* copies, and the six sibling write verbs (`update`/`transition`/`claim`/
|
|
10
|
+
* `relate`/`move`/`delete`) should import {@link IIssueCard} /
|
|
11
|
+
* {@link IIssueField} from here too, rather than re-declaring a third copy
|
|
12
|
+
* alongside `create-issue.ts`'s own `IIssueCard` (see this module's own
|
|
13
|
+
* top-level doc comment in `index.ts` for the reconciliation note).
|
|
14
|
+
*/
|
|
15
|
+
/** Identity is the global `uid` (SPEC.md §6.1) — a single scalar, never a composite key. */
|
|
16
|
+
export type IssueUid = string;
|
|
17
|
+
/**
|
|
18
|
+
* The closed field vocabulary a `get`/`query` caller may request (SPEC.md
|
|
19
|
+
* §6.5). `assertKnownFields` (this module's {@link assertKnownIssueFields})
|
|
20
|
+
* rejects any name outside this union with a `BacklogValidationError` naming
|
|
21
|
+
* it — never a silent drop.
|
|
22
|
+
*
|
|
23
|
+
* `plain` fields are cheap: each is either a column on the `issue` node
|
|
24
|
+
* itself or a scalar living in `issue.meta.metadata` (`assignee`, `closedAt`,
|
|
25
|
+
* `gitContext` — SPEC.md §6.5's own reclassification of `closedAt` as
|
|
26
|
+
* `plain`, since it is read in the SAME single-row fetch as `assignee`, not a
|
|
27
|
+
* second query; `gitContext` is the item-level disclosure-contract git
|
|
28
|
+
* context, a sibling of `assignee` in the same metadata blob).
|
|
29
|
+
*
|
|
30
|
+
* `pseudo` fields are opt-in only: each costs a genuine extra read (an edge
|
|
31
|
+
* traversal to another node kind, or only exists on a `searchRanked`
|
|
32
|
+
* response) and is therefore NEVER included in the default card.
|
|
33
|
+
*/
|
|
34
|
+
export type IIssuePlainField = 'uid' | 'title' | 'kind' | 'status' | 'priority' | 'project' | 'component' | 'createdAt' | 'updatedAt' | 'assignee' | 'author' | 'closedAt' | 'gitContext';
|
|
35
|
+
export type IIssuePseudoField = 'body' | 'citations' | 'notes' | 'auditTrail' | 'blockers' | 'related' | '_score' | '_vector';
|
|
36
|
+
export type IIssueField = IIssuePlainField | IIssuePseudoField;
|
|
37
|
+
export declare const ISSUE_PLAIN_FIELDS: readonly IIssuePlainField[];
|
|
38
|
+
export declare const ISSUE_PSEUDO_FIELDS: readonly IIssuePseudoField[];
|
|
39
|
+
export declare function isKnownIssueField(name: string): name is IIssueField;
|
|
40
|
+
/** SPEC.md §6.5: "Default (`fields` omitted): the exact five-field terse card established by `DEFAULT_CARD_FIELDS`." */
|
|
41
|
+
export declare const DEFAULT_ISSUE_CARD_FIELDS: readonly IIssuePlainField[];
|
|
42
|
+
/** A citation, projected for read (mirrors the write layer's `ICitationInput` shape plus the server-computed `sha`). */
|
|
43
|
+
export interface IIssueCitation {
|
|
44
|
+
uid: string;
|
|
45
|
+
file: string;
|
|
46
|
+
lines?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Free-text prose for this citation (the write layer's `ICitationInput.context`).
|
|
49
|
+
* NOT the item's disclosure-contract git context — that is ITEM-level
|
|
50
|
+
* provenance and lives on {@link IIssueCard.gitContext}, a sibling of
|
|
51
|
+
* `assignee`, rendered once at the head of the `Citations:` block. This
|
|
52
|
+
* per-citation `context` is never rendered by `markdown.ts` and cannot carry
|
|
53
|
+
* the git context.
|
|
54
|
+
*/
|
|
55
|
+
context?: string;
|
|
56
|
+
symbol?: string;
|
|
57
|
+
sha: string;
|
|
58
|
+
at: string;
|
|
59
|
+
}
|
|
60
|
+
export interface IIssueNote {
|
|
61
|
+
uid: string;
|
|
62
|
+
author: string;
|
|
63
|
+
text: string;
|
|
64
|
+
at: string;
|
|
65
|
+
}
|
|
66
|
+
export interface IIssueAuditEntry {
|
|
67
|
+
uid: string;
|
|
68
|
+
actor: string;
|
|
69
|
+
action: string;
|
|
70
|
+
from?: string;
|
|
71
|
+
to?: string;
|
|
72
|
+
note?: string;
|
|
73
|
+
sha: string;
|
|
74
|
+
at: string;
|
|
75
|
+
}
|
|
76
|
+
/** A minimal cross-reference to another issue — used by the `blockers`/`related` pseudo-fields. */
|
|
77
|
+
export interface IIssueRef {
|
|
78
|
+
uid: string;
|
|
79
|
+
title: string;
|
|
80
|
+
status: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The projected issue card (SPEC.md §6.5's `IIssueCard`). Every field is
|
|
84
|
+
* OPTIONAL here because the shape is fields-projected: a caller that asked
|
|
85
|
+
* for `['uid','title']` gets a card with only those two keys populated.
|
|
86
|
+
* `uid` is always present regardless of the requested `fields` — an issue
|
|
87
|
+
* card with no addressable identity is never a useful response.
|
|
88
|
+
*/
|
|
89
|
+
export interface IIssueCard {
|
|
90
|
+
uid: string;
|
|
91
|
+
title?: string;
|
|
92
|
+
kind?: string;
|
|
93
|
+
status?: string;
|
|
94
|
+
priority?: string;
|
|
95
|
+
project?: string;
|
|
96
|
+
component?: string;
|
|
97
|
+
createdAt?: string;
|
|
98
|
+
updatedAt?: string;
|
|
99
|
+
assignee?: string;
|
|
100
|
+
author?: string;
|
|
101
|
+
closedAt?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The item-level disclosure-contract git context (repo `AGENTS.md`'s
|
|
104
|
+
* "Cite what you read": the FIRST element of a `Citations:` block is
|
|
105
|
+
* `<active git context>`). A plain field — a sibling of `assignee` in
|
|
106
|
+
* `issue.meta.metadata`, read in the same single-row fetch. Rendered once at
|
|
107
|
+
* the head of the `Citations:` block by `markdown.ts`; never per-citation.
|
|
108
|
+
* Absent on every issue filed before the field existed, and on any issue
|
|
109
|
+
* whose `create`/`transition` supplied no `gitContext`.
|
|
110
|
+
*/
|
|
111
|
+
gitContext?: string;
|
|
112
|
+
body?: string;
|
|
113
|
+
citations?: IIssueCitation[];
|
|
114
|
+
notes?: IIssueNote[];
|
|
115
|
+
auditTrail?: IIssueAuditEntry[];
|
|
116
|
+
blockers?: IIssueRef[];
|
|
117
|
+
related?: IIssueRef[];
|
|
118
|
+
_score?: number;
|
|
119
|
+
_vector?: number[];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* `get`'s uid-addressed shape (SPEC.md §6.3.1/§6.5/AC-13) — the implementation
|
|
123
|
+
* layer's {@link getIssue} (`get.ts`) takes exactly this, never the mounted
|
|
124
|
+
* union below. Named `...ByUidInput` (rather than reusing the bare
|
|
125
|
+
* `IIssueGetInput` name) because the MOUNTED `get` verb (`api.ts`) also
|
|
126
|
+
* accepts the registry-detail shape (§3a/AC-11) — see {@link IIssueGetInput}.
|
|
127
|
+
*/
|
|
128
|
+
export interface IIssueGetByUidInput {
|
|
129
|
+
uid: IssueUid;
|
|
130
|
+
fields?: readonly IIssueField[];
|
|
131
|
+
}
|
|
132
|
+
/** SPEC.md §6.5's `IIssueFilter`. */
|
|
133
|
+
export interface IIssueFilter {
|
|
134
|
+
/** uid or name (SPEC.md §6.1). */
|
|
135
|
+
project?: string;
|
|
136
|
+
/** uid or name, scoped within `project`. */
|
|
137
|
+
component?: string;
|
|
138
|
+
kind?: string | string[];
|
|
139
|
+
status?: string | string[] | 'open' | 'closed' | 'all';
|
|
140
|
+
priority?: string | string[];
|
|
141
|
+
assignee?: string;
|
|
142
|
+
claimedBy?: string;
|
|
143
|
+
/** Resolves via `authored_by` edge traversal — uid or name. */
|
|
144
|
+
author?: string;
|
|
145
|
+
/** FTS keyword, title+body — keyword-only, never hybrid. */
|
|
146
|
+
grep?: string;
|
|
147
|
+
/** Routes to `searchRanked` (§5a) — composes with `grep`, neither swallows the other. */
|
|
148
|
+
semantic?: string;
|
|
149
|
+
/** Item-anchored similarity/traversal seed (§6.1) — uid of the reference item. */
|
|
150
|
+
anchor?: string;
|
|
151
|
+
/**
|
|
152
|
+
* uid or name of the parent `issue` this one is filed under via the `part_of`
|
|
153
|
+
* edge (SPEC.md §1052/§1471: a plan is itself an `issue` row, not a
|
|
154
|
+
* dedicated node kind — attaching an item to it is
|
|
155
|
+
* `relate(childUid, planUid, 'part_of', 'add')`). Resolves candidate issues
|
|
156
|
+
* by the incoming `part_of` edge into the resolved plan node, exactly like
|
|
157
|
+
* the `project`/`component` edge-scoped filters.
|
|
158
|
+
*/
|
|
159
|
+
plan?: string;
|
|
160
|
+
/** `component.meta.path` (repo-relative package path, SPEC.md §3) — exact match against every live `component` row, unioned across matches. Distinct from `component`, which takes a uid/name rather than a filesystem path. */
|
|
161
|
+
projectPath?: string;
|
|
162
|
+
closedAt?: {
|
|
163
|
+
since?: string;
|
|
164
|
+
until?: string;
|
|
165
|
+
};
|
|
166
|
+
createdAt?: {
|
|
167
|
+
since?: string;
|
|
168
|
+
until?: string;
|
|
169
|
+
};
|
|
170
|
+
updatedAt?: {
|
|
171
|
+
since?: string;
|
|
172
|
+
until?: string;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export type IIssueSort = 'priority' | 'updated' | 'created' | 'relevance' | 'textMatch';
|
|
176
|
+
export type IIssueSortDirection = 'asc' | 'desc';
|
|
177
|
+
/**
|
|
178
|
+
* `projects`/`components`/`locations` (SPEC.md §3a/§8 AC-9) are the registry
|
|
179
|
+
* LIST views — every live `project`/`component`/`location` row, optionally
|
|
180
|
+
* narrowed by `filter.project` (and, for `locations`, `filter.component`) —
|
|
181
|
+
* routed to `views/registry.ts`'s `listProjects`/`listComponents`/
|
|
182
|
+
* `listLocations`, distinct from the issue-search views above (§6.1:
|
|
183
|
+
* "conflating the two would be wrong").
|
|
184
|
+
*/
|
|
185
|
+
export type IIssueView = 'list' | 'ready' | 'graph' | 'order' | 'stale' | 'similar' | 'overlap' | 'projects' | 'components' | 'locations';
|
|
186
|
+
export type IIssueQueryFormat = 'json' | 'markdown';
|
|
187
|
+
/** SPEC.md §5, §6.1's `axis` — the grouping dimension for `overlapUids` (§6.2). */
|
|
188
|
+
export type IOverlapAxis = 'file' | 'project' | 'component' | 'author';
|
|
189
|
+
export interface IIssueQueryInput {
|
|
190
|
+
/**
|
|
191
|
+
* The natural-language query — routed by `queryIssues` to `filter.semantic`
|
|
192
|
+
* when the vector space can return ranked results, or to `filter.grep`
|
|
193
|
+
* otherwise. Mutually exclusive with setting `filter.semantic` or
|
|
194
|
+
* `filter.grep` yourself; pick one or the other, never both.
|
|
195
|
+
*/
|
|
196
|
+
text?: string;
|
|
197
|
+
filter?: IIssueFilter;
|
|
198
|
+
fields?: readonly IIssueField[];
|
|
199
|
+
sort?: IIssueSort;
|
|
200
|
+
direction?: IIssueSortDirection;
|
|
201
|
+
/** default 50, max 1000 (`MAX_QUERY_LIMIT`). */
|
|
202
|
+
limit?: number;
|
|
203
|
+
/** offset-based paging; mutually exclusive with `after`. */
|
|
204
|
+
offset?: number;
|
|
205
|
+
/** opaque keyset cursor from a prior page's `nextCursor`. */
|
|
206
|
+
after?: string;
|
|
207
|
+
view?: IIssueView;
|
|
208
|
+
/**
|
|
209
|
+
* default `'json'`. `'markdown'` is only supported for the four item-list
|
|
210
|
+
* views (`list`/`ready`/`stale`/`similar`) — see {@link IIssueMarkdownResult}
|
|
211
|
+
* — and rejects with `InvalidArgumentError('format', ...)` for any other
|
|
212
|
+
* view (`graph`/`order`/`overlap`/`projects`/`components`/`locations`),
|
|
213
|
+
* which return a shape DATA_MODEL.md §8's markdown projection has no rule
|
|
214
|
+
* for.
|
|
215
|
+
*/
|
|
216
|
+
format?: IIssueQueryFormat;
|
|
217
|
+
/** `view:'overlap'` only (§6.2) — the axis to group `overlapUids` by. */
|
|
218
|
+
overlapAxis?: IOverlapAxis;
|
|
219
|
+
/** `view:'overlap'` only (§6.2) — the set of `uid`s to group by `overlapAxis`. */
|
|
220
|
+
overlapUids?: readonly string[];
|
|
221
|
+
/** `view:'stale'` only — minutes since `claimedAt`; falls back to `project_policy.claim_stale_after_min` (default 30) when omitted. */
|
|
222
|
+
staleAfterMin?: number;
|
|
223
|
+
}
|
|
224
|
+
export declare const MAX_QUERY_LIMIT = 1000;
|
|
225
|
+
export declare const DEFAULT_QUERY_LIMIT = 50;
|
|
226
|
+
export interface IIssuePage {
|
|
227
|
+
items: IIssueCard[];
|
|
228
|
+
/** Pass back as `after` for the next page; absent ⇒ no more pages. */
|
|
229
|
+
nextCursor?: string;
|
|
230
|
+
hasMore: boolean;
|
|
231
|
+
}
|
|
232
|
+
/** SPEC.md §5's `DependencyGraph`, using this system's edge vocabulary (§6.2: `blocks`, not `DEPENDS_ON`). */
|
|
233
|
+
export interface IDependencyGraph {
|
|
234
|
+
nodes: Array<{
|
|
235
|
+
uid: string;
|
|
236
|
+
title: string;
|
|
237
|
+
status: string;
|
|
238
|
+
}>;
|
|
239
|
+
edges: Array<{
|
|
240
|
+
from: string;
|
|
241
|
+
to: string;
|
|
242
|
+
rel: 'blocks' | 'relates_to' | 'part_of';
|
|
243
|
+
}>;
|
|
244
|
+
}
|
|
245
|
+
export type ITopoOrderResult = {
|
|
246
|
+
ok: true;
|
|
247
|
+
order: string[];
|
|
248
|
+
} | {
|
|
249
|
+
ok: false;
|
|
250
|
+
cycle: string[];
|
|
251
|
+
};
|
|
252
|
+
/** `view:'overlap'`'s output shape (§6.2) — one entry per distinct axis value shared by ≥1 of the input `uids`. */
|
|
253
|
+
export interface IOverlapGroup {
|
|
254
|
+
axisValue: string;
|
|
255
|
+
uids: string[];
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* `view:'list'`'s result — {@link IIssuePage} plus the discriminator.
|
|
259
|
+
*
|
|
260
|
+
* Declared as an interface rather than written inline as
|
|
261
|
+
* `({ view: 'list' } & IIssuePage)`. That distinction is load-bearing, not
|
|
262
|
+
* stylistic: the schema extractor that derives every mount's response shape
|
|
263
|
+
* cannot express a TypeScript intersection, and emitted a bare `{}` for that
|
|
264
|
+
* branch. The runtime encodes each response against the derived schema, so
|
|
265
|
+
* with `{}` in the union the list branch was projected onto a sibling member
|
|
266
|
+
* — and `hasMore` and `nextCursor` were silently dropped from every CLI, MCP
|
|
267
|
+
* and HTTP response, which made paging unreachable for every consumer while
|
|
268
|
+
* the in-process return value looked correct. An `extends` clause extracts
|
|
269
|
+
* into a complete object schema, so the wire shape matches the type.
|
|
270
|
+
*/
|
|
271
|
+
export interface IIssueListResult extends IIssuePage {
|
|
272
|
+
view: 'list';
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* `format:'markdown'`'s result shape (SPEC.md §6.5/§6.6, DATA_MODEL.md §8) —
|
|
276
|
+
* returned instead of the matching JSON-shaped member above for any of the
|
|
277
|
+
* four item-list views (`list`/`ready`/`stale`/`similar`; the only views whose
|
|
278
|
+
* result is an `IIssueCard[]` DATA_MODEL.md §8's markdown projection can
|
|
279
|
+
* render). `markdown` is the SAME page a `format:'json'` call would have
|
|
280
|
+
* returned, re-serialized (`query/markdown.ts`'s `renderIssueCardsMarkdown`)
|
|
281
|
+
* — never a second query path.
|
|
282
|
+
*/
|
|
283
|
+
export interface IIssueMarkdownResult {
|
|
284
|
+
view: 'list' | 'ready' | 'stale' | 'similar';
|
|
285
|
+
format: 'markdown';
|
|
286
|
+
markdown: string;
|
|
287
|
+
}
|
|
288
|
+
/** The one discriminated result shape `query` (§6.3, §5) returns — the `view` field selects which of the following members is populated. */
|
|
289
|
+
export type IIssueQueryResult = IIssueListResult | {
|
|
290
|
+
view: 'ready';
|
|
291
|
+
items: IIssueCard[];
|
|
292
|
+
} | {
|
|
293
|
+
view: 'graph';
|
|
294
|
+
graph: IDependencyGraph;
|
|
295
|
+
} | {
|
|
296
|
+
view: 'order';
|
|
297
|
+
order: ITopoOrderResult;
|
|
298
|
+
} | {
|
|
299
|
+
view: 'stale';
|
|
300
|
+
items: IIssueCard[];
|
|
301
|
+
} | {
|
|
302
|
+
view: 'similar';
|
|
303
|
+
items: IIssueCard[];
|
|
304
|
+
} | {
|
|
305
|
+
view: 'overlap';
|
|
306
|
+
groups: IOverlapGroup[];
|
|
307
|
+
} | {
|
|
308
|
+
view: 'projects';
|
|
309
|
+
items: IProjectSummary[];
|
|
310
|
+
} | {
|
|
311
|
+
view: 'components';
|
|
312
|
+
items: IComponentSummary[];
|
|
313
|
+
} | {
|
|
314
|
+
view: 'locations';
|
|
315
|
+
items: ILocationSummary[];
|
|
316
|
+
} | IIssueMarkdownResult;
|
|
317
|
+
export interface IProjectSummary {
|
|
318
|
+
uid: string;
|
|
319
|
+
name: string;
|
|
320
|
+
path?: string;
|
|
321
|
+
repoUrl?: string;
|
|
322
|
+
monorepo?: boolean;
|
|
323
|
+
description?: string;
|
|
324
|
+
}
|
|
325
|
+
export interface IComponentSummary {
|
|
326
|
+
uid: string;
|
|
327
|
+
name: string;
|
|
328
|
+
projectUid: string;
|
|
329
|
+
path?: string;
|
|
330
|
+
description?: string;
|
|
331
|
+
}
|
|
332
|
+
export type ILocationType = 'path' | 'url' | 'tool';
|
|
333
|
+
export interface ILocationSummary {
|
|
334
|
+
uid: string;
|
|
335
|
+
locType: ILocationType;
|
|
336
|
+
value: string;
|
|
337
|
+
componentUid: string;
|
|
338
|
+
}
|
|
339
|
+
export interface IProjectDetail extends IProjectSummary {
|
|
340
|
+
components: Array<{
|
|
341
|
+
name: string;
|
|
342
|
+
path?: string;
|
|
343
|
+
}>;
|
|
344
|
+
locations: Array<{
|
|
345
|
+
locType: ILocationType;
|
|
346
|
+
value: string;
|
|
347
|
+
}>;
|
|
348
|
+
}
|
|
349
|
+
export interface IComponentDetail extends IComponentSummary {
|
|
350
|
+
project: {
|
|
351
|
+
name: string;
|
|
352
|
+
path?: string;
|
|
353
|
+
repoUrl?: string;
|
|
354
|
+
};
|
|
355
|
+
locations: Array<{
|
|
356
|
+
locType: ILocationType;
|
|
357
|
+
value: string;
|
|
358
|
+
}>;
|
|
359
|
+
}
|
|
360
|
+
export interface ILocationDetail extends ILocationSummary {
|
|
361
|
+
component: {
|
|
362
|
+
name: string;
|
|
363
|
+
path?: string;
|
|
364
|
+
};
|
|
365
|
+
project: {
|
|
366
|
+
name: string;
|
|
367
|
+
path?: string;
|
|
368
|
+
repoUrl?: string;
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
export interface IRegistryQueryFilter {
|
|
372
|
+
project?: string;
|
|
373
|
+
component?: string;
|
|
374
|
+
}
|
|
375
|
+
export interface ILookupResult {
|
|
376
|
+
project: {
|
|
377
|
+
uid: string;
|
|
378
|
+
name: string;
|
|
379
|
+
path?: string;
|
|
380
|
+
repoUrl?: string;
|
|
381
|
+
};
|
|
382
|
+
component?: {
|
|
383
|
+
uid: string;
|
|
384
|
+
name: string;
|
|
385
|
+
path?: string;
|
|
386
|
+
};
|
|
387
|
+
location?: {
|
|
388
|
+
uid: string;
|
|
389
|
+
locType: ILocationType;
|
|
390
|
+
value: string;
|
|
391
|
+
};
|
|
392
|
+
/** Present when only a partial (project-level, or path-prefix) match was found — never a silent null (§3a). */
|
|
393
|
+
hint?: string;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* `get`'s registry-detail shape (SPEC.md §3a/§8 AC-11) — `get --input
|
|
397
|
+
* '{"registry":"project"|"component"|"location","name":...}'`, routed to
|
|
398
|
+
* `views/registry.ts`'s `getRegistryDetail`. `filter` is honoured ONLY for
|
|
399
|
+
* `registry:'component'` (SPEC.md §6.1's project-scoping rule — `name` alone
|
|
400
|
+
* is ambiguous across projects, e.g. every project's reserved `(root)`
|
|
401
|
+
* component shares the same name, §8 AC-23) and is ignored for `project`/
|
|
402
|
+
* `location` (a location has no independent name at all — it is always
|
|
403
|
+
* resolved by uid, §3a).
|
|
404
|
+
*/
|
|
405
|
+
export interface IIssueGetRegistryInput {
|
|
406
|
+
registry: 'project' | 'component' | 'location';
|
|
407
|
+
name: string;
|
|
408
|
+
filter?: IRegistryQueryFilter;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* The MOUNTED `get` verb's input (`api.ts`) — either the uid-addressed issue
|
|
412
|
+
* card ({@link IIssueGetByUidInput}, SPEC.md §6.3.1/AC-13, UNCHANGED) or the
|
|
413
|
+
* registry-detail lookup ({@link IIssueGetRegistryInput}, §3a/AC-11). The two
|
|
414
|
+
* shapes are structurally disjoint (`uid` vs. `registry`+`name`), which is
|
|
415
|
+
* what lets `api.ts`'s `get` narrow on `'registry' in input` and is also what
|
|
416
|
+
* keeps apigen's undiscriminated-union structural encoder
|
|
417
|
+
* (`pickUnionBranch`/`scoreUnionBranch`, `@adhd/apigen-base-logical`) from
|
|
418
|
+
* ever conflating the two: each branch's OWN required-key set immediately
|
|
419
|
+
* disqualifies the other (a uid-input has no `registry`/`name`; a
|
|
420
|
+
* registry-input has no `uid`).
|
|
421
|
+
*/
|
|
422
|
+
export type IIssueGetInput = IIssueGetByUidInput | IIssueGetRegistryInput;
|
|
423
|
+
/**
|
|
424
|
+
* The MOUNTED `get` verb's result — the plain issue card ({@link IIssueCard},
|
|
425
|
+
* exactly the five-field default per AC-13 when `uid` was given) or one of
|
|
426
|
+
* the three registry detail shapes (§3a/AC-11). Same structural-disjointness
|
|
427
|
+
* reasoning as {@link IIssueGetInput} above: `IIssueCard` requires only
|
|
428
|
+
* `uid`, while every registry detail type requires several fields NONE of
|
|
429
|
+
* the others (nor `IIssueCard`) declare (`IProjectDetail`:
|
|
430
|
+
* `components`+`locations`; `IComponentDetail`: `projectUid`+`project`;
|
|
431
|
+
* `ILocationDetail`: `locType`+`value`+`componentUid`+`component`+`project`)
|
|
432
|
+
* — a missing required key disqualifies a branch outright in
|
|
433
|
+
* `scoreUnionBranch`, so the four branches can never tie.
|
|
434
|
+
*
|
|
435
|
+
* NOTE (BUG-APIGEN-CORE-CLIENT-BARE-NAME-COLLISION-001, now fixed at the
|
|
436
|
+
* source): putting `query/types.ts`'s `IIssueCard` at a top-level
|
|
437
|
+
* operation-return position here (for the first time) exposed a real
|
|
438
|
+
* apigen-core-client extraction defect — `write/create-issue.ts` ALSO
|
|
439
|
+
* exported an interface bare-named `IIssueCard` (differently shaped:
|
|
440
|
+
* `title`/`kind`/`status`/`project`/`component`/`createdAt` required there,
|
|
441
|
+
* vs. only `uid` here), and the extractor's declaration resolution collided
|
|
442
|
+
* on the bare name across the whole extracted program, non-deterministically
|
|
443
|
+
* substituting the wrong shape into `query`'s `items` schema (confirmed
|
|
444
|
+
* empirically: `dist/index.js` resolved it to the wrong, stricter shape;
|
|
445
|
+
* `dist/index.mjs`, built from the identical source in the same pass, failed
|
|
446
|
+
* to resolve it at all). Fixed by renaming `write/create-issue.ts`'s
|
|
447
|
+
* interface to `ICreateIssueCard` — see that file's doc comment for the full
|
|
448
|
+
* repro — so no workaround is needed here; this type is plain `IIssueCard`.
|
|
449
|
+
*/
|
|
450
|
+
export type IIssueGetResult = IIssueCard | IProjectDetail | IComponentDetail | ILocationDetail;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { IComponentDetail, IComponentSummary, ILocationDetail, ILocationSummary, ILookupResult, IProjectDetail, IProjectSummary, IRegistryQueryFilter } from '../types.js';
|
|
2
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
3
|
+
|
|
4
|
+
/** `query --input '{"view":"projects"}'` (§3a) — every live `project` row, optionally narrowed by `filter.project` (name/uid substring is NOT supported here; pass the exact ref — this is a listing view, not a search). */
|
|
5
|
+
export declare function listProjects(graph: GraphBackend, filter?: IRegistryQueryFilter): Promise<IProjectSummary[]>;
|
|
6
|
+
/** `query --input '{"view":"components"}'` (§3a) — every live `component` row, optionally narrowed by `filter.project`. */
|
|
7
|
+
export declare function listComponents(graph: GraphBackend, filter?: IRegistryQueryFilter): Promise<IComponentSummary[]>;
|
|
8
|
+
/** `query --input '{"view":"locations"}'` (§3a) — every live `location` row, optionally narrowed by `filter.component` (scoped within `filter.project` when both are given). */
|
|
9
|
+
export declare function listLocations(graph: GraphBackend, filter?: IRegistryQueryFilter): Promise<ILocationSummary[]>;
|
|
10
|
+
/**
|
|
11
|
+
* `get --input '{"registry":"project"|"component"|"location", "name":...}'`
|
|
12
|
+
* (§3a) — expanded detail. `name` accepts a uid or a name (project/component)
|
|
13
|
+
* per SPEC.md §6.1's shape-disambiguation rule; a location has no independent
|
|
14
|
+
* `name`, so it is looked up by uid only. `filter.project` scopes the
|
|
15
|
+
* `component` case (SPEC.md §6.1/§8 AC-23: a bare component NAME is
|
|
16
|
+
* ambiguous across projects — every project's reserved `(root)` component
|
|
17
|
+
* shares the same name — so `filter.project` disambiguates exactly like
|
|
18
|
+
* `listComponents`' own `filter.project`); omitted, `component` resolves
|
|
19
|
+
* against the first live component matching `name` in ANY project, same as
|
|
20
|
+
* before this parameter existed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getRegistryDetail(graph: GraphBackend, input: {
|
|
23
|
+
registry: 'project';
|
|
24
|
+
name: string;
|
|
25
|
+
}): Promise<IProjectDetail>;
|
|
26
|
+
export declare function getRegistryDetail(graph: GraphBackend, input: {
|
|
27
|
+
registry: 'component';
|
|
28
|
+
name: string;
|
|
29
|
+
filter?: IRegistryQueryFilter;
|
|
30
|
+
}): Promise<IComponentDetail>;
|
|
31
|
+
export declare function getRegistryDetail(graph: GraphBackend, input: {
|
|
32
|
+
registry: 'location';
|
|
33
|
+
name: string;
|
|
34
|
+
}): Promise<ILocationDetail>;
|
|
35
|
+
/**
|
|
36
|
+
* `query --input '{"view":"lookup", "lookup": "<tool|file|url>"}'` (§3a) —
|
|
37
|
+
* classify → match → walk `location → component → project`. Never a silent
|
|
38
|
+
* null: an unresolved query throws `CatalogNotFoundError('location', q)`
|
|
39
|
+
* rather than returning an empty/undefined result, since "no match" is a
|
|
40
|
+
* distinct, actionable outcome from "found, but only a hint" (the `hint`
|
|
41
|
+
* field below).
|
|
42
|
+
*/
|
|
43
|
+
export declare function lookup(graph: GraphBackend, q: string): Promise<ILookupResult>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { IQueryStoreHandle } from '../query.js';
|
|
2
|
+
import { IIssueCard, IIssueFilter, IIssueQueryInput } from '../types.js';
|
|
3
|
+
import { SearchResult } from '@adhd/sox-hybrid-search';
|
|
4
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* FEAT-022's rescore knob (SPEC.md §5a: `rescore:[{kind:'temporal',decay}]`)
|
|
8
|
+
* — SPEC.md names the shape but states no value anywhere, and neither
|
|
9
|
+
* `IIssueFilter` nor `IIssueQueryInput` (the frozen filter/cursor contract)
|
|
10
|
+
* exposes a caller-supplied one. Rather than fabricate a number, this mirrors
|
|
11
|
+
* the ALREADY-established sibling convention `sox-hybrid-search` itself is
|
|
12
|
+
* pinned to for its OTHER FEAT-022 constant: `RRF_K = 60` is documented
|
|
13
|
+
* in that package's own source as "Matches memory-core's RRF_K so a
|
|
14
|
+
* 3-channel cutover produces the same rank magnitudes" — i.e. this package
|
|
15
|
+
* is deliberately kept rank-compatible with the sibling `memory-core` system
|
|
16
|
+
* FEAT-022 originated in. That system's own documented temporal-rescore
|
|
17
|
+
* convention is "recency×importance rerank (0.995/hour decay)"
|
|
18
|
+
* (`docs/sox/CAPABILITY-CATALOG.md:336`, this monorepo). `temporalRescore`'s
|
|
19
|
+
* formula is `exp(-decay * ageHours)`, so a 0.995-per-hour retention factor
|
|
20
|
+
* is `decay = -ln(0.995) ≈ 0.0050125`. Citing the same precedent this
|
|
21
|
+
* package's own `RRF_K` already cites, not inventing a fresh figure — but
|
|
22
|
+
* genuinely a decision this module makes, not a value SPEC.md itself states;
|
|
23
|
+
* flagged here rather than silently asserted as spec-given.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DEFAULT_TEMPORAL_DECAY_PER_HOUR = 0.0050125;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves every edge-scoped/metadata/date dimension of `filter` (everything
|
|
28
|
+
* EXCEPT `grep`/`semantic`/`anchor`, which the caller consumes separately) to
|
|
29
|
+
* a concrete candidate issue-id set — the "resolve any node filter to
|
|
30
|
+
* concrete ids via the graph first" this module's top doc comment names.
|
|
31
|
+
*
|
|
32
|
+
* Returns:
|
|
33
|
+
* - `undefined` — no filter dimension this function handles was given at
|
|
34
|
+
* all; the caller may use the cheap `{kind:'issue'}` fast path (`kind` IS
|
|
35
|
+
* one of `buildFilterClause`'s recognized keys, so `searchRanked` applies
|
|
36
|
+
* it correctly on its own) rather than paying for an unbounded
|
|
37
|
+
* `queryNodes` scan just to re-derive "every live issue."
|
|
38
|
+
* - a `Set` (possibly empty) — at least one dimension was given; an empty
|
|
39
|
+
* `Set` means the filter, taken as a whole, matches zero issues. The
|
|
40
|
+
* caller MUST treat this as "return `[]`", NEVER pass it through as
|
|
41
|
+
* `ids: []` (see this file's top doc comment for why that would silently
|
|
42
|
+
* do the OPPOSITE — an unfiltered scan).
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveSimilarFilterIds(graph: GraphBackend, filter: IIssueFilter | undefined): Promise<Set<number> | undefined>;
|
|
45
|
+
export interface IRelevanceRankOptions {
|
|
46
|
+
/** FTS query text — fused via the `'text'` RRF signal. */
|
|
47
|
+
text?: string;
|
|
48
|
+
/** Embedding query vector — fused via the `'vec'` RRF signal. */
|
|
49
|
+
vec: Float32Array;
|
|
50
|
+
/**
|
|
51
|
+
* A pre-resolved candidate id set (see {@link resolveSimilarFilterIds}).
|
|
52
|
+
* `undefined` ⇒ no restriction beyond `kind:'issue'`. A DEFINED-BUT-EMPTY
|
|
53
|
+
* set short-circuits to `[]` WITHOUT calling `searchRanked` at all — this
|
|
54
|
+
* guard exists at THIS layer too (not only in {@link querySimilarView}),
|
|
55
|
+
* so a future direct caller of this exported primitive gets the same
|
|
56
|
+
* protection against the empty-`ids`-means-unfiltered hazard by
|
|
57
|
+
* construction, not by caller discipline.
|
|
58
|
+
*/
|
|
59
|
+
candidateIds?: Set<number>;
|
|
60
|
+
limit: number;
|
|
61
|
+
/** Overrides {@link DEFAULT_TEMPORAL_DECAY_PER_HOUR} — for tests and any future caller that wants a different recency curve. */
|
|
62
|
+
decayPerHour?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The one `searchRanked` call shape SPEC.md §5a specifies for `view:'similar'`
|
|
66
|
+
* / `sort:'relevance'` / `sort:'textMatch'` / `_score`: fused text+vec (RRF)
|
|
67
|
+
* plus a temporal-recency rescore. Exported standalone (not only reachable
|
|
68
|
+
* via {@link querySimilarView}) so a future `view:'list'` ranked-sort
|
|
69
|
+
* integration can call the EXACT same primitive `view:'similar'` uses,
|
|
70
|
+
* rather than reimplementing a second ranking path — that reuse is the
|
|
71
|
+
* "relevance ordering" half of this module's brief, distinct from
|
|
72
|
+
* `view:'similar'` itself.
|
|
73
|
+
*/
|
|
74
|
+
export declare function rankByFusedRelevance(handle: IQueryStoreHandle, opts: IRelevanceRankOptions): Promise<SearchResult[]>;
|
|
75
|
+
/**
|
|
76
|
+
* `view:'similar'` (SPEC.md §5a) — `filter.anchor` (item-anchored) or
|
|
77
|
+
* `filter.semantic` (free text), fused text+vec ranked via
|
|
78
|
+
* {@link rankByFusedRelevance}, projected to `IIssueCard`s with `_score`
|
|
79
|
+
* populated when requested (`card.ts`'s existing
|
|
80
|
+
* `IAssembleIssueCardOptions.score` seam — SPEC.md §5a's `_score` exposure).
|
|
81
|
+
*
|
|
82
|
+
* The anchor issue is EXCLUDED from its own results (RAG-SPEC.md §3.2's
|
|
83
|
+
* carried-forward "the query item itself is excluded" — SPEC.md §5a does not
|
|
84
|
+
* restate this explicitly, a genuine spec gap this implementation fills per
|
|
85
|
+
* that precedent rather than silently, since "similar to X" trivially
|
|
86
|
+
* self-matching X at rank 1 is a real usability defect, not a feature).
|
|
87
|
+
* Exclusion is done POST-search (fetch one extra candidate, drop the anchor,
|
|
88
|
+
* slice to `limit`) rather than by enumerating the whole issue table to
|
|
89
|
+
* subtract one id up front — far cheaper for the common "no other filter"
|
|
90
|
+
* case, and still exactly correct.
|
|
91
|
+
*
|
|
92
|
+
* Errors: `IssueNotFoundError(anchor)` (SPEC.md §6.1's general `uid`-
|
|
93
|
+
* addressing convention — `anchor` is `uid`-typed per §6.1's own statement
|
|
94
|
+
* that it is "the SAME `uid`-typed field" as every other addressing field;
|
|
95
|
+
* reused directly from `resolve.ts`'s `resolveIssueByUid` rather than
|
|
96
|
+
* re-derived, which also means this gets the SPEC-correct error class for
|
|
97
|
+
* free). `InvalidArgumentError('semantic', ...)` (no search backend configured).
|
|
98
|
+
* `InvalidArgumentError('filter', ...)` (neither `anchor` nor `semantic`
|
|
99
|
+
* given). `BacklogValidationError('limit', ...)` (out-of-range `limit`).
|
|
100
|
+
*/
|
|
101
|
+
export declare function querySimilarView(handle: IQueryStoreHandle, input: IIssueQueryInput): Promise<IIssueCard[]>;
|