@adhd/backlog 0.1.9 → 1.0.1
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 +128 -47
- package/README.md +369 -81
- package/api.d.ts +196 -0
- package/api.ir.json +1 -0
- package/cli.d.ts +45 -18
- package/env.d.ts +23 -3
- package/envelope.d.ts +163 -0
- package/extract-live.d.ts +56 -0
- package/index.d.ts +11 -10
- package/index.js +255 -197
- package/index.mjs +11348 -19043
- package/install-skill.d.ts +23 -0
- package/ir-artifact.d.ts +86 -0
- package/package.json +51 -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 +632 -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 +161 -0
- package/write/catalog.d.ts +369 -0
- package/write/citation-path.d.ts +133 -0
- package/write/claim-lease.d.ts +21 -0
- package/write/claim.d.ts +80 -0
- package/write/create-issue.d.ts +253 -0
- package/write/delete.d.ts +39 -0
- package/write/embed-drain.d.ts +68 -0
- package/write/embedding-config.d.ts +81 -0
- package/write/embedding-observer.d.ts +80 -0
- package/write/errors.d.ts +365 -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 +64 -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/install-skill.d.ts
CHANGED
|
@@ -7,6 +7,29 @@ export declare const ALL_HOSTS: readonly SkillHost[];
|
|
|
7
7
|
* re-derives — and risks desyncing from — this resolution rule. */
|
|
8
8
|
export declare function resolveCodexHomeDir(home: string, homeOverride?: string): string;
|
|
9
9
|
export declare function hostSkillsDir(host: SkillHost, scope: SkillScope, cwd: string, homeOverride?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* A USAGE error — the caller typed something wrong — as opposed to a genuine
|
|
12
|
+
* internal fault. BUG-BACKLOG-INSTALLSKILL-UX-001: `install-skill`/`install`
|
|
13
|
+
* are special-cased in `cli.ts` BEFORE the apigen command table is built, so
|
|
14
|
+
* they never get the outcome-envelope error handling the six mounted verbs
|
|
15
|
+
* get. Their argument errors used to propagate to the bin entry-guard, which
|
|
16
|
+
* prints `err.stack` — burying a perfectly good one-line message under ten
|
|
17
|
+
* frames of minified dist. Distinguishing usage errors by TYPE (rather than
|
|
18
|
+
* catching everything) keeps real faults loud and stack-bearing while giving
|
|
19
|
+
* typos the short, actionable output the mounted verbs already produce.
|
|
20
|
+
*/
|
|
21
|
+
export declare class BacklogUsageError extends Error {
|
|
22
|
+
constructor(message: string);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Prints a usage error the SAME way the apigen-mounted verbs and every
|
|
26
|
+
* other CLI command's own rejection path already do — a machine-readable
|
|
27
|
+
* `{"code":"invalid_argument","message":…}` as the last stderr line, exit
|
|
28
|
+
* code 2 (`CLI_EXIT_CODE['invalid_argument']`) — plus the human-readable
|
|
29
|
+
* usage text, so a reader gets both the parse and the fix in one screen.
|
|
30
|
+
*/
|
|
31
|
+
export declare function failUsage(err: BacklogUsageError, helpText: string): void;
|
|
32
|
+
export declare const INSTALL_SKILL_HELP_TEXT = "backlog install-skill [--host claude|codex|opencode|all] [--scope user|project]\n\nCopies the packaged backlog SKILL.md into an agent host's skills directory.\n(`backlog install` is the richer successor \u2014 it also registers the MCP server.)\n\n --host <name> claude | codex | opencode | all (default: all)\n --scope <name> user | project (default: user)\n \"user\" is the machine-wide install (~/.claude/skills/...);\n there is no \"global\" \u2014 that is spelled \"user\" here.\n\nExamples:\n backlog install-skill\n backlog install-skill --host opencode --scope user\n backlog install-skill --host claude --scope project\n";
|
|
10
33
|
export interface InstallSkillResult {
|
|
11
34
|
host: SkillHost;
|
|
12
35
|
scope: SkillScope;
|
package/ir-artifact.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Operation } from '@adhd/apigen-core-client';
|
|
2
|
+
|
|
3
|
+
/** The artifact filename emitted into `dist/` by the `ir-artifact` subcommand. */
|
|
4
|
+
export declare const BACKLOG_IR_ARTIFACT_FILENAME = "api.ir.json";
|
|
5
|
+
/**
|
|
6
|
+
* The extractor version this build expects — the installed
|
|
7
|
+
* `@adhd/apigen-core-client` package version. An artifact whose recorded
|
|
8
|
+
* `extractorVersion` differs (e.g. a package baked against one core-client
|
|
9
|
+
* release and consumed under another) is refused, because a changed extractor
|
|
10
|
+
* can change extraction output for byte-identical input. This is the SAME
|
|
11
|
+
* value `extract-live.ts` stamps into every runtime-cache entry
|
|
12
|
+
* (`CORE_CLIENT_VERSION` there re-exports this constant), so the baked path,
|
|
13
|
+
* the fallback cache, and the artifact gate can never disagree.
|
|
14
|
+
*
|
|
15
|
+
* Read here (not in `extract-live.ts`) precisely because this module must stay
|
|
16
|
+
* ts-morph-free: a bare `package.json` version read is pure metadata.
|
|
17
|
+
*/
|
|
18
|
+
export declare const EXPECTED_EXTRACTOR_VERSION: string;
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the directory holding the built `api.d.ts`/`api.ir.json` for the
|
|
21
|
+
* currently running module. Three layouts are supported without needing to
|
|
22
|
+
* distinguish them explicitly (published npm package, this repo's own
|
|
23
|
+
* `nx build backlog` output, and vitest running `src/` in place):
|
|
24
|
+
*
|
|
25
|
+
* 1. PUBLISHED (`node_modules/@adhd/backlog/dist/index.js`): `api.d.ts` is a
|
|
26
|
+
* sibling of the running module.
|
|
27
|
+
* 2. DEV-BUILT (`entrypoint/backlog/dist/index.js`): identical sibling shape.
|
|
28
|
+
* 3. VITEST (`entrypoint/backlog/src/...` transformed in place): `api.d.ts`
|
|
29
|
+
* is one level up and back down, under `../dist`.
|
|
30
|
+
*
|
|
31
|
+
* Probing "is api.d.ts sitting right next to me?" before falling back to the
|
|
32
|
+
* vitest-only `../dist` shape covers all three. Moved here from `server.ts`
|
|
33
|
+
* (verbatim, including this rationale) so the ts-morph-free artifact reader and
|
|
34
|
+
* `server.ts` share ONE resolution — `extract-live.ts` imports it too, never a
|
|
35
|
+
* second, drift-prone copy.
|
|
36
|
+
*/
|
|
37
|
+
export declare function backlogDistDir(): string;
|
|
38
|
+
/** Absolute path to the baked artifact inside `distDir`. */
|
|
39
|
+
export declare function bakedIrArtifactPath(distDir: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Reads and VALIDATES the baked IR artifact for `distDir`.
|
|
42
|
+
*
|
|
43
|
+
* Returns `operations` ONLY when every gate passes; returns `undefined` (and
|
|
44
|
+
* NEVER throws — a corrupt/partial artifact must degrade to the fallback, not
|
|
45
|
+
* crash startup) on any of:
|
|
46
|
+
* - the artifact file is missing or unreadable;
|
|
47
|
+
* - it is not valid JSON, or does not carry an `operations` array;
|
|
48
|
+
* - `formatVersion` != the current entry format;
|
|
49
|
+
* - `extractorVersion` != {@link EXPECTED_EXTRACTOR_VERSION};
|
|
50
|
+
* - `artifactSource` is absent/malformed;
|
|
51
|
+
* - `api.d.ts` is missing, its byte length differs from the recorded one, or
|
|
52
|
+
* its sha256 does not match the recorded one (SOURCE-HASH-MISMATCH);
|
|
53
|
+
* - the `artifactSource.deps` full-`.d.ts`-surface map is absent/malformed, or
|
|
54
|
+
* the CURRENT `distDir` `*.d.ts` surface no longer matches it — an imported
|
|
55
|
+
* sibling declaration drifted even though `api.d.ts` did not
|
|
56
|
+
* (SURFACE-HASH-MISMATCH). Both are the never-serve-stale gate.
|
|
57
|
+
*
|
|
58
|
+
* @returns the baked operations, or `undefined` (never a throw) on any of the
|
|
59
|
+
* above — every one degrades to the live extraction fallback.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readBakedIrArtifact(distDir: string): Operation[] | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Writes the baked IR artifact to `outFile`, recording the provenance the
|
|
64
|
+
* reader re-validates against: the source `.d.ts` path (audit), its sha256 and
|
|
65
|
+
* byte length, plus a sha256 per EVERY `*.d.ts` under the artifact's `dist/`
|
|
66
|
+
* (`artifactSource.deps`). Uses the plugin's shared `atomicWriteJson`, so the
|
|
67
|
+
* artifact is published atomically and durably exactly like a runtime-cache
|
|
68
|
+
* entry — a build killed mid-write can never leave a half-written artifact
|
|
69
|
+
* behind.
|
|
70
|
+
*
|
|
71
|
+
* The per-file `deps` map is what makes the reader's freshness gate cover the
|
|
72
|
+
* FULL extracted surface rather than only `api.d.ts`: extraction resolves
|
|
73
|
+
* types through `api.d.ts`'s local siblings, so their content is part of what
|
|
74
|
+
* the recorded `operations` depends on. See {@link readBakedIrArtifact}.
|
|
75
|
+
*
|
|
76
|
+
* `extractorVersion` is passed explicitly (the `ir-artifact` subcommand
|
|
77
|
+
* supplies {@link EXPECTED_EXTRACTOR_VERSION}) rather than read here, so the
|
|
78
|
+
* written artifact always records the version of the extractor that actually
|
|
79
|
+
* produced `operations` — not merely the version installed at write time.
|
|
80
|
+
*/
|
|
81
|
+
export declare function writeBakedIrArtifact(args: {
|
|
82
|
+
apiDts: string;
|
|
83
|
+
outFile: string;
|
|
84
|
+
extractorVersion: string;
|
|
85
|
+
operations: Operation[];
|
|
86
|
+
}): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhd/backlog",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"bin": {
|
|
5
|
-
"backlog": "index.js"
|
|
5
|
+
"adhd-backlog": "index.js"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@adhd/apigen-
|
|
9
|
-
"@adhd/apigen-
|
|
10
|
-
"@adhd/apigen-
|
|
11
|
-
"@adhd/apigen-plugin-
|
|
12
|
-
"@adhd/apigen-plugin-
|
|
13
|
-
"@adhd/apigen-plugin-
|
|
14
|
-
"@adhd/apigen-plugin-
|
|
15
|
-
"@adhd/apigen-plugin-
|
|
16
|
-
"@adhd/
|
|
17
|
-
"@adhd/environment
|
|
18
|
-
"@adhd/
|
|
19
|
-
"@adhd/
|
|
20
|
-
"@adhd/sox-
|
|
8
|
+
"@adhd/apigen-base-logical": "^0.1.3",
|
|
9
|
+
"@adhd/apigen-core-client": "^0.3.2",
|
|
10
|
+
"@adhd/apigen-engine-naming": "^0.2.4",
|
|
11
|
+
"@adhd/apigen-plugin-api-fastify": "^0.2.5",
|
|
12
|
+
"@adhd/apigen-plugin-batch": "^0.2.4",
|
|
13
|
+
"@adhd/apigen-plugin-cli-output": "^0.2.5",
|
|
14
|
+
"@adhd/apigen-plugin-ir-cache": "^0.1.2",
|
|
15
|
+
"@adhd/apigen-plugin-mcp": "^0.3.0",
|
|
16
|
+
"@adhd/apigen-plugin-openapi": "^0.2.4",
|
|
17
|
+
"@adhd/environment": "^0.1.7",
|
|
18
|
+
"@adhd/environment-base-spec": "^0.1.2",
|
|
19
|
+
"@adhd/environment-builder": "^0.1.6",
|
|
20
|
+
"@adhd/sox-graph-store": "^0.11.1",
|
|
21
|
+
"@adhd/sox-hybrid-search": "^0.5.0",
|
|
22
|
+
"@adhd/sox-semantic": "^0.1.8",
|
|
23
|
+
"@adhd/sox-store-adapter": "^0.10.0",
|
|
24
|
+
"@adhd/sox-telemetry": "^0.3.2",
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
26
|
+
"ajv": "^8.20.0",
|
|
27
|
+
"ajv-formats": "2.1.1",
|
|
28
|
+
"commander": "^14.0.3",
|
|
29
|
+
"fastify": "^4.0.0",
|
|
21
30
|
"pino": "10.3.1",
|
|
22
31
|
"pino-pretty": "13.1.3",
|
|
32
|
+
"ts-json-schema-generator": "^2.3.0",
|
|
33
|
+
"ts-morph": "^23.0.0",
|
|
34
|
+
"typescript": "^5.5.0",
|
|
35
|
+
"vite": "~5.0.13",
|
|
23
36
|
"yaml": "1.10.3"
|
|
24
37
|
},
|
|
38
|
+
"optionalDependencies": {
|
|
39
|
+
"@adhd/sox-embedding-provider": "^0.6.0",
|
|
40
|
+
"@adhd/sox-vector-store": "^0.7.2"
|
|
41
|
+
},
|
|
25
42
|
"assets": [
|
|
26
43
|
"skill"
|
|
27
44
|
],
|
|
@@ -30,5 +47,24 @@
|
|
|
30
47
|
"typings": "./index.d.ts",
|
|
31
48
|
"publishConfig": {
|
|
32
49
|
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"description": "Graph-store backlog for multi-agent teams - queryable, claimable, multi-agent-safe issue tracking with CLI and MCP",
|
|
52
|
+
"keywords": [
|
|
53
|
+
"backlog",
|
|
54
|
+
"issue-tracking",
|
|
55
|
+
"graph",
|
|
56
|
+
"cli",
|
|
57
|
+
"mcp",
|
|
58
|
+
"multi-agent"
|
|
59
|
+
],
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/PseudoSky/adhd.git",
|
|
64
|
+
"directory": "entrypoint/backlog"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/PseudoSky/adhd/tree/main/entrypoint/backlog#readme",
|
|
67
|
+
"bugs": {
|
|
68
|
+
"url": "https://github.com/PseudoSky/adhd/issues"
|
|
33
69
|
}
|
|
34
70
|
}
|
package/query/card.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IIssueAuditEntry, IIssueCard, IIssueField, IIssueRef } from './types.js';
|
|
2
|
+
import { EdgeRecord, GraphBackend, NodeRecord } from '@adhd/sox-graph-store';
|
|
3
|
+
|
|
4
|
+
/** SPEC.md §6.5's `assertKnownFields` — unknown name → `BacklogValidationError` naming it, never a silent drop. */
|
|
5
|
+
export declare function assertKnownIssueFields(fields: readonly string[] | undefined): asserts fields is readonly IIssueField[] | undefined;
|
|
6
|
+
/** `status.meta.metadata.terminal` — the closedness knob (DATA_MODEL.md §3, SPEC.md §2). Defaults to `false` for a status row written before the field existed, never `true` by omission (a closedness knob that defaults closed would silently exclude items from open-item views). */
|
|
7
|
+
export declare function isStatusTerminal(statusRecord: NodeRecord | undefined): boolean;
|
|
8
|
+
/** The full audit trail for an issue — `audits` edges FROM the issue (SPEC.md §3: `audits: * → audit (1:n)`, the subject is the edge SOURCE), sorted oldest-first. */
|
|
9
|
+
export declare function resolveAuditTrail(graph: GraphBackend, issueId: number, outgoing?: EdgeRecord[]): Promise<IIssueAuditEntry[]>;
|
|
10
|
+
/**
|
|
11
|
+
* `blockers` (SPEC.md §5.2's definition, restated onto the `blocks` edge,
|
|
12
|
+
* §6.2): the set of issues that `blocks` this one (incoming
|
|
13
|
+
* `blocks` edges — `e.dst === issueId`) and are NOT YET terminal — "what's
|
|
14
|
+
* actually blocking it right now," never the full historical blocker set.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveBlockers(graph: GraphBackend, issueId: number): Promise<IIssueRef[]>;
|
|
17
|
+
/** `related` — both directions of `relates_to` (an `n:m` symmetric-in-practice rel, §3), deduplicated. */
|
|
18
|
+
export declare function resolveRelated(graph: GraphBackend, issueId: number, outgoing?: EdgeRecord[]): Promise<IIssueRef[]>;
|
|
19
|
+
export interface IAssembleIssueCardOptions {
|
|
20
|
+
/** Score from a `searchRanked`/`searchNodes` response — populates `_score` when requested (§5a). */
|
|
21
|
+
score?: number;
|
|
22
|
+
/** Pre-fetched outgoing edges (`getEdges({src: issue.id})`) — pass when the caller already has them (e.g. a batch `query` page) to avoid a redundant round trip. */
|
|
23
|
+
outgoingEdges?: EdgeRecord[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Project `issue` onto the requested `fields` (default: the five-field terse
|
|
27
|
+
* card, SPEC.md §6.5). `uid` is always populated regardless of `fields`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function assembleIssueCard(graph: GraphBackend, issue: NodeRecord, fields: readonly IIssueField[], opts?: IAssembleIssueCardOptions): Promise<IIssueCard>;
|
|
30
|
+
/** Batch-assemble cards for a page of issue nodes, sharing one `getNodesByIds`-batched catalog/placement resolution pass where possible. Falls back to per-issue assembly (still batches internally) — a cross-issue batch would require a different, `getEdges`-list API this file's dependency (`GraphBackend`) does not expose. */
|
|
31
|
+
export declare function assembleIssueCards(graph: GraphBackend, issues: NodeRecord[], fields: readonly IIssueField[], scoreByUid?: ReadonlyMap<string, number>): Promise<IIssueCard[]>;
|
package/query/get.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IIssueCard, IIssueGetByUidInput } from './types.js';
|
|
2
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch one issue by `uid`, projected to the requested `fields` (default:
|
|
6
|
+
* the same five-field card `query` defaults to, SPEC.md §6.3.1/§6.5/AC-13).
|
|
7
|
+
*
|
|
8
|
+
* Errors: `IssueNotFoundError(uid)` (no live node carries `uid`),
|
|
9
|
+
* `BacklogValidationError('fields', ...)` (an unknown field name).
|
|
10
|
+
*/
|
|
11
|
+
export declare function getIssue(graph: GraphBackend, input: IIssueGetByUidInput): Promise<IIssueCard>;
|
package/query/index.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index.ts — the `@adhd/backlog` read/query layer's public surface
|
|
3
|
+
* (SPEC.md §5, §5a, §6.1, §6.3.1, §6.5, §3a).
|
|
4
|
+
*
|
|
5
|
+
* **Layout:**
|
|
6
|
+
* - `types.ts` — every shared TS shape (`IIssueCard`, `IIssueField`,
|
|
7
|
+
* `IIssueQueryInput`/`IIssueFilter`, `IIssuePage`, registry types). Import
|
|
8
|
+
* from here, not from `get.ts`/`query.ts`/`card.ts` directly, to avoid
|
|
9
|
+
* depending on an implementation module's re-export surface.
|
|
10
|
+
* - `resolve.ts` — read-only (non-transactional) uid/name resolution and edge
|
|
11
|
+
* traversal, built directly on the bare `GraphBackend` (see that file's own
|
|
12
|
+
* doc comment for why this is safe, unlike `write/tx.ts`'s hand-composed
|
|
13
|
+
* forms). The six sibling write verbs (`update`/`transition`/`claim`/
|
|
14
|
+
* `relate`/`move`/`delete`) should import from here for any READ they need
|
|
15
|
+
* OUTSIDE their own `immediate` transaction (e.g. resolving a `filter`
|
|
16
|
+
* parameter, or re-reading a node post-commit to build their own outcome's
|
|
17
|
+
* card) — never re-implement uid/name resolution a third time.
|
|
18
|
+
* - `card.ts` — `assembleIssueCard`/`assembleIssueCards`: projects a live
|
|
19
|
+
* `issue` `NodeRecord` onto a requested `IIssueField` list. The six sibling
|
|
20
|
+
* write verbs' own outcome shapes (`IUpdateOutcome`, `ITransitionOutcome`,
|
|
21
|
+
* etc.) embed card-shaped fields (SPEC.md §6.3) — call `assembleIssueCard`
|
|
22
|
+
* post-commit rather than hand-rolling a second field-projection pass.
|
|
23
|
+
* - `get.ts` — the `get` verb (§6.3.1).
|
|
24
|
+
* - `query.ts` — the `query` verb (§5, §5a, §6.5) and its `view` union
|
|
25
|
+
* (`list`/`ready`/`graph`/`order`/`stale`/`similar`/`overlap`).
|
|
26
|
+
* - `views/registry.ts` — §3a's registry read surface (`projects`/`components`/
|
|
27
|
+
* `locations`/`lookup`/registry `get` detail).
|
|
28
|
+
* - `views/stats.ts` — the stats/rollup read views (§5): the status-aware
|
|
29
|
+
* priority matrix (`priorityMatrix`, BUG-023), the `part_of` hierarchy
|
|
30
|
+
* rollup (`partOfRollup`, FEAT-005 — transitive, not one-level), and
|
|
31
|
+
* `validAt` point-in-time cumulative-open curves (`openCurve`).
|
|
32
|
+
* - `views/semantic.ts` — the semantic read views (§5a, FEAT-022):
|
|
33
|
+
* `querySimilarView` (`view:'similar'`) and the shared fused-relevance
|
|
34
|
+
* ranking primitive (`rankByFusedRelevance`). `query.ts`'s `case 'similar':`
|
|
35
|
+
* dispatch calls `querySimilarView` directly — there is no second,
|
|
36
|
+
* embedding-only `view:'similar'` implementation left in `query.ts`.
|
|
37
|
+
* - `markdown.ts` — `query`'s `format:'markdown'` rendering (§6.5/§6.6,
|
|
38
|
+
* DATA_MODEL.md §8): a pure re-serialization of the SAME `IIssueCard[]`
|
|
39
|
+
* `format:'json'` already returns for `list`/`ready`/`stale`/`similar` —
|
|
40
|
+
* never a second query path.
|
|
41
|
+
*
|
|
42
|
+
* **Reconciliation note for the write layer.** `write/create-issue.ts`
|
|
43
|
+
* declares its OWN `ICreateIssueCard` (a narrower, always-fully-populated
|
|
44
|
+
* shape it builds inline from data it already has after a fresh insert — it
|
|
45
|
+
* never needs a field-projected read; named distinctly from this module's
|
|
46
|
+
* `IIssueCard` on purpose — see that file's doc comment for
|
|
47
|
+
* BUG-APIGEN-CORE-CLIENT-BARE-NAME-COLLISION-001, a real apigen-core-client
|
|
48
|
+
* extraction defect the original shared bare name `IIssueCard` triggered
|
|
49
|
+
* once both types became simultaneously reachable from `api.d.ts`). This
|
|
50
|
+
* module's {@link IIssueCard} (from `types.ts`) is the FIELDS-PROJECTED
|
|
51
|
+
* read-layer shape every OTHER verb should use — the two are intentionally
|
|
52
|
+
* not unified in this slice (unifying them means either widening
|
|
53
|
+
* `create-issue.ts`'s always-populated shape to all-optional, or teaching
|
|
54
|
+
* this module's card assembler to skip a post-insert read entirely; both are
|
|
55
|
+
* a `create-issue.ts` edit, out of scope for a read-layer-only task). A
|
|
56
|
+
* future consolidation should re-export `create-issue.ts`'s result through
|
|
57
|
+
* THIS module's `IIssueCard` instead of maintaining two card shapes.
|
|
58
|
+
*/
|
|
59
|
+
export * from './types.js';
|
|
60
|
+
export * from './resolve.js';
|
|
61
|
+
export * from './card.js';
|
|
62
|
+
export * from './get.js';
|
|
63
|
+
export * from './query.js';
|
|
64
|
+
export * from './views/registry.js';
|
|
65
|
+
export * from './views/stats.js';
|
|
66
|
+
export * from './views/semantic.js';
|
|
67
|
+
export * from './markdown.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IIssueCard } from './types.js';
|
|
2
|
+
|
|
3
|
+
/** Renders one `IIssueCard` as a markdown section — title header, never the `uid` (DATA_MODEL.md §8). */
|
|
4
|
+
export declare function renderOneIssueCardMarkdown(card: IIssueCard): string;
|
|
5
|
+
/**
|
|
6
|
+
* Renders a full page of issue cards as markdown (`query`'s `format:'markdown'`
|
|
7
|
+
* result) — one `##` section per card, separated by a blank line. An empty
|
|
8
|
+
* page renders a stated "no results" line rather than an empty string, so a
|
|
9
|
+
* caller piping this straight to a file never gets a silently blank document.
|
|
10
|
+
*/
|
|
11
|
+
export declare function renderIssueCardsMarkdown(items: readonly IIssueCard[]): string;
|
package/query/query.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { IIssueQueryInput, IIssueQueryResult } from './types.js';
|
|
2
|
+
import { IQueryEnvelopeMeta } from '../envelope.js';
|
|
3
|
+
import { StoreSearchBackend } from '@adhd/sox-hybrid-search';
|
|
4
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The dependencies `query`/the view helpers need. `search` is OPTIONAL —
|
|
8
|
+
* `@adhd/sox-embedding-provider`/`@adhd/sox-vector-store` are
|
|
9
|
+
* `optionalDependencies` of this package (package.json), so a store opened
|
|
10
|
+
* without a configured embedding backend simply cannot serve
|
|
11
|
+
* `filter.semantic`/`view:'similar'`; those paths throw
|
|
12
|
+
* `InvalidArgumentError('semantic', ...)` rather than silently degrading to a
|
|
13
|
+
* grep-only result the caller did not ask for.
|
|
14
|
+
*/
|
|
15
|
+
export interface IQueryStoreHandle {
|
|
16
|
+
readonly graph: GraphBackend;
|
|
17
|
+
readonly search?: {
|
|
18
|
+
readonly backend: StoreSearchBackend;
|
|
19
|
+
/** Embeds `filter.semantic`'s free text into the SAME vector space `backend`'s vector store was built against. */
|
|
20
|
+
embedQuery(text: string): Promise<Float32Array>;
|
|
21
|
+
/**
|
|
22
|
+
* One-row probe of the REAL vector table: `true` iff at least one vector
|
|
23
|
+
* exists under this backend's own space. Per-query truth, never a
|
|
24
|
+
* process-lifetime latch — see `write/bootstrap.ts`'s
|
|
25
|
+
* {@link isVectorSpacePopulated}. `api.ts`'s `queryHandle` runs this and
|
|
26
|
+
* snapshots the result onto {@link IQueryStoreHandle.spacePopulated}
|
|
27
|
+
* before the (synchronous) routing decision reads it.
|
|
28
|
+
*/
|
|
29
|
+
spacePopulated(): Promise<boolean>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Snapshot of {@link IQueryStoreHandle.search}'s `spacePopulated()` probe,
|
|
33
|
+
* taken by `api.ts`'s `queryHandle` when the caller passed a bare `text:`
|
|
34
|
+
* positional. `resolveTextInput` is synchronous, so the (async) probe
|
|
35
|
+
* result is resolved onto the handle first; a handle built directly by a
|
|
36
|
+
* test or the ETL sets it itself. Absent means "unknown" and is treated as
|
|
37
|
+
* "not populated" — routing then falls back to grep.
|
|
38
|
+
*/
|
|
39
|
+
readonly spacePopulated?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Fail-loud vocabulary guard (`store/vocabulary-guard.ts`). When present,
|
|
42
|
+
* `queryIssuesWithMeta` awaits it before dispatching any view: a store
|
|
43
|
+
* holding live nodes under a vocabulary this build does not recognize must
|
|
44
|
+
* never read as `{ok:true, total:0}`. OPTIONAL so a hand-built handle
|
|
45
|
+
* (tests, the ETL) is unaffected — `api.ts`'s `queryHandle` wires it for
|
|
46
|
+
* every real host, and it is deliberately re-run per query (not latched at
|
|
47
|
+
* open) so a long-lived process notices a store rewritten under it.
|
|
48
|
+
*/
|
|
49
|
+
readonly assertVocabulary?: () => Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether a `query` verb's own input touches the semantic channel at all —
|
|
53
|
+
* the need-predicate `api.ts`'s `query` call site passes as
|
|
54
|
+
* `queryHandle(ctx, { needsSemantic: queryNeedsSemanticBackend(input) })`
|
|
55
|
+
* (SPEC.md §5b point 1). Structural, not a maintained list: it names the
|
|
56
|
+
* SAME "semantic inputs" vocabulary `env.ts`'s `embedding.enabled` doc
|
|
57
|
+
* comment already names, plus a bare `text` positional — deciding whether
|
|
58
|
+
* `text` auto-routes to `semantic` or `grep` itself requires the backend to
|
|
59
|
+
* be live, so a `text` query must bootstrap it even though it may end up on
|
|
60
|
+
* the grep route.
|
|
61
|
+
*
|
|
62
|
+
* A verb that returns `false` never derives a semantic backend: no embedding
|
|
63
|
+
* provider construction, no vector-store open, no cold ONNX load.
|
|
64
|
+
*/
|
|
65
|
+
export declare function queryNeedsSemanticBackend(input: IIssueQueryInput): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Normalises `input.text` (the natural-language query shared by every mount —
|
|
68
|
+
* CLI `search`, MCP, HTTP) into `filter.semantic` or `filter.grep`, exactly
|
|
69
|
+
* ONCE, so every caller gets identical routing rather than each transport
|
|
70
|
+
* reimplementing it. Routes to `semantic` when the store handle actually
|
|
71
|
+
* carries a `search` backend AND that backend's space is populated
|
|
72
|
+
* ({@link IQueryStoreHandle.spacePopulated}, the per-query snapshot of
|
|
73
|
+
* {@link IQueryStoreHandle.search}'s `spacePopulated()` probe taken by
|
|
74
|
+
* `api.ts`'s `queryHandle`); otherwise routes to `grep`. A non-empty handle
|
|
75
|
+
* whose space is still empty must NOT route to semantic: over an empty vector
|
|
76
|
+
* table `searchRanked` returns zero candidates, which is an empty page — worse
|
|
77
|
+
* than the grep fallback — so populated-ness is load-bearing, not an
|
|
78
|
+
* optimization. The matching default `sort` (`'relevance'` / `'textMatch'`)
|
|
79
|
+
* is only applied when the caller did not pass `sort` explicitly — an
|
|
80
|
+
* explicit `sort` always wins.
|
|
81
|
+
*
|
|
82
|
+
* Exported (in addition to being called internally by {@link queryIssues})
|
|
83
|
+
* so the sort-precedence rule above can be unit-tested directly: the ranked
|
|
84
|
+
* grep/semantic branch of `queryList` never echoes the resolved `sort` value
|
|
85
|
+
* back in its output (it only gates on relevance/textMatch requiring
|
|
86
|
+
* grep/semantic, then ignores `sort` entirely when ordering ranked results),
|
|
87
|
+
* so there is no way to observe "explicit sort survived" from `queryIssues`'s
|
|
88
|
+
* return value alone — `text-routing.spec.ts` asserts on this function's
|
|
89
|
+
* return value for that one property, and drives every other behaviour
|
|
90
|
+
* through the real `queryIssues`/real store end-to-end.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveTextInput(handle: IQueryStoreHandle, input: IIssueQueryInput): IIssueQueryInput;
|
|
93
|
+
/** {@link queryIssuesWithMeta}'s return shape. */
|
|
94
|
+
export interface IQueryIssuesOutcome {
|
|
95
|
+
result: IIssueQueryResult;
|
|
96
|
+
/**
|
|
97
|
+
* Present only for `view:'list'` — the only view whose result is a
|
|
98
|
+
* filtered/paginated row set with an honestly countable pre-limit total
|
|
99
|
+
* (`envelope.ts`'s {@link IQueryEnvelopeMeta}). `view:'ready'` computes
|
|
100
|
+
* readiness in-memory and stops enumerating once `limit` candidates are
|
|
101
|
+
* found (`queryReady`'s own doc comment: removing that early exit to count
|
|
102
|
+
* a true pre-limit total would reintroduce the O(candidates) cost its
|
|
103
|
+
* grouped-relation-fetch design exists to avoid), `view:'stale'` applies no
|
|
104
|
+
* limit at all so every row it returns already IS the total, and
|
|
105
|
+
* `view:'similar'`/`'graph'`/`'order'`/`'overlap'` are a ranking, a graph
|
|
106
|
+
* projection, a topological order, and an axis grouping respectively — none
|
|
107
|
+
* of them a filtered row set with a "how many matched" count. Adding a
|
|
108
|
+
* `meta` to any of those would mean inventing a number this module cannot
|
|
109
|
+
* stand behind.
|
|
110
|
+
*/
|
|
111
|
+
meta?: IQueryEnvelopeMeta;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `queryIssues` (below) plus the transport-facing `meta` the envelope
|
|
115
|
+
* exposes for a list-shaped read (`api.ts`'s `query` mount is the one caller
|
|
116
|
+
* that needs it). Every other in-process caller keeps calling `queryIssues`
|
|
117
|
+
* itself, which discards `meta` and returns exactly the shape it always has.
|
|
118
|
+
*
|
|
119
|
+
* `format:'markdown'` (SPEC.md §6.5/§6.6, DATA_MODEL.md §8) is handled here,
|
|
120
|
+
* as a POST-PROCESSING step over {@link dispatchQueryView}'s always-`json`
|
|
121
|
+
* result — never a second query path (SPEC.md §6.5: "renders this same page
|
|
122
|
+
* ... never a second code path"). Only the four item-list views
|
|
123
|
+
* ({@link MARKDOWN_CAPABLE_VIEWS}) have a markdown rendering rule at all; any
|
|
124
|
+
* other view (`graph`/`order`/`overlap`/`projects`/`components`/`locations`)
|
|
125
|
+
* rejects `format:'markdown'` outright rather than silently falling back to
|
|
126
|
+
* `json` or inventing an ad hoc rendering for a shape DATA_MODEL.md §8 never
|
|
127
|
+
* describes.
|
|
128
|
+
*/
|
|
129
|
+
export declare function queryIssuesWithMeta(handle: IQueryStoreHandle, rawInput?: IIssueQueryInput): Promise<IQueryIssuesOutcome>;
|
|
130
|
+
/** The `query` verb (SPEC.md §5, §6.5) — dispatches on `input.view`, default `'list'`. */
|
|
131
|
+
export declare function queryIssues(handle: IQueryStoreHandle, rawInput?: IIssueQueryInput): Promise<IIssueQueryResult>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isUidShaped } from '../write/catalog.js';
|
|
2
|
+
import { EdgeRecord, GraphBackend, NodeRecord } from '@adhd/sox-graph-store';
|
|
3
|
+
|
|
4
|
+
export { isUidShaped };
|
|
5
|
+
/** A resolved catalog/registry row, read-only. */
|
|
6
|
+
export interface IResolvedRef {
|
|
7
|
+
id: number;
|
|
8
|
+
uid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
record: NodeRecord;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolve `uid` → the live `issue` node, or throw {@link IssueNotFoundError}
|
|
14
|
+
* (SPEC.md §6.1: "a `uid` with no matching live node throws
|
|
15
|
+
* `IssueNotFoundError(uid)`"). This is the READ-PATH counterpart of
|
|
16
|
+
* `write/tx.ts`'s `getNodeByUidTx` — safe to call standalone because it is
|
|
17
|
+
* not composing a check-then-act write around the result.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveIssueByUid(graph: GraphBackend, uid: string): Promise<NodeRecord>;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve `ref` (uid or name, disambiguated by shape — SPEC.md §6.1) against
|
|
22
|
+
* `expectedKind`, on the READ path: an unresolved NAME is never an error here
|
|
23
|
+
* (unlike the write-path `mintOrResolveCatalogTx`) — SPEC.md §6.1's own read-
|
|
24
|
+
* path rule: "an unresolved `name` is not an error; it resolves to zero
|
|
25
|
+
* matches." Callers that need read-path "resolve or throw" semantics (e.g.
|
|
26
|
+
* `get`'s `project`/`component` display resolution once an issue's edges are
|
|
27
|
+
* already known to exist) use {@link resolveRefOrThrow} instead.
|
|
28
|
+
*/
|
|
29
|
+
export declare function tryResolveRef(graph: GraphBackend, expectedKind: string, ref: string): Promise<IResolvedRef | null>;
|
|
30
|
+
/** Like {@link tryResolveRef}, but throws {@link CatalogNotFoundError} on a miss — for call sites that need "this reference must already exist." */
|
|
31
|
+
export declare function resolveRefOrThrow(graph: GraphBackend, expectedKind: string, ref: string): Promise<IResolvedRef>;
|
|
32
|
+
/** `component`, scoped within `project` (SPEC.md §6.1) — read path, `component.meta.metadata.projectUid` must match. */
|
|
33
|
+
export declare function tryResolveComponentRef(graph: GraphBackend, projectUid: string, ref: string): Promise<IResolvedRef | null>;
|
|
34
|
+
/** The single live edge of `rel` FROM `srcId` (SPEC.md §3's `n:1` rels — `has_kind`/`has_status`/`has_priority`/`authored_by`), or `null` when none exists. */
|
|
35
|
+
export declare function pickSingleEdge(edges: EdgeRecord[], rel: string, srcId: number): EdgeRecord | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* All edges ORIGINATING at `nodeId` — a single `getEdges({src})` call covers
|
|
38
|
+
* every `n:1`/`1:n` outgoing rel an issue carries (`has_kind`/`has_status`/
|
|
39
|
+
* `has_priority`/`authored_by`/`has_note`/`has_citation`/`has_transition`/
|
|
40
|
+
* `audits`/`relates_to`/`supersedes`/`duplicate_of`/`part_of`/`blocks`) —
|
|
41
|
+
* cheaper than one `getEdges` call per rel.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getOutgoingEdges(graph: GraphBackend, nodeId: number): Promise<EdgeRecord[]>;
|
|
44
|
+
/** All edges TARGETING `nodeId` — used for the reverse traversals (`owns_component`'s issue→component lookup, `blocks`'s incoming-blocker lookup, `duplicate_of`'s incoming lookup). */
|
|
45
|
+
export declare function getIncomingEdges(graph: GraphBackend, nodeId: number): Promise<EdgeRecord[]>;
|
|
46
|
+
/**
|
|
47
|
+
* The component that owns `issueId` (SPEC.md §3: `owns_component: component →
|
|
48
|
+
* issue (1:n)`) and, one hop further, the project that owns that component
|
|
49
|
+
* (`owns_project: project → component (1:n)`). Every live issue has exactly
|
|
50
|
+
* one of each (§8 AC-23), so this returns `undefined` only for a
|
|
51
|
+
* pre-invariant / corrupted row, never as an expected steady-state case.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveIssuePlacement(graph: GraphBackend, issueId: number): Promise<{
|
|
54
|
+
component?: NodeRecord;
|
|
55
|
+
project?: NodeRecord;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Resolve an edge-scoped filter value (SPEC.md §6.5 rule 3: `kind`/`status`/
|
|
59
|
+
* `priority`/`project`/`component`/`author` live on EDGES, not `NodeFilter`
|
|
60
|
+
* columns) to the set of candidate issue rowids satisfying it.
|
|
61
|
+
*
|
|
62
|
+
* **Direction is looked up, not assumed.** The six edge-scoped dimensions do
|
|
63
|
+
* NOT all run the same way: `has_kind`/`has_status`/`has_priority`/
|
|
64
|
+
* `authored_by` point issue → catalog (the catalog node is the edge TARGET),
|
|
65
|
+
* while `owns_project`/`owns_component` point catalog → child (the catalog
|
|
66
|
+
* node is the edge SOURCE). This function previously hard-coded the first
|
|
67
|
+
* shape — `getEdges({dst: resolved.id, rel})` collecting `src` — for all six,
|
|
68
|
+
* so calling it for `project`/`component` looked for edges INTO a component
|
|
69
|
+
* when every real `owns_component` edge points OUT of it, and it silently
|
|
70
|
+
* returned an EMPTY set for a component that genuinely owned issues. Silent,
|
|
71
|
+
* because an empty candidate set is indistinguishable from "nothing matched."
|
|
72
|
+
*
|
|
73
|
+
* `views/semantic.ts` worked around this by hand-composing its own
|
|
74
|
+
* source-directed traversal for those two dimensions and reusing this
|
|
75
|
+
* function only for the four it got right, flagging in its own header that
|
|
76
|
+
* "a future caller who takes that doc comment at face value for
|
|
77
|
+
* component/project will reproduce this exact miss." That is now fixed at
|
|
78
|
+
* source instead: the `edge_kind` row for `rel` carries `source_kind`/
|
|
79
|
+
* `target_kind` (the same rows `resolveEdgeKindTx` reads on the write path),
|
|
80
|
+
* so the traversal direction is derived from the data rather than assumed,
|
|
81
|
+
* and stays correct for any rel added later.
|
|
82
|
+
*
|
|
83
|
+
* Returns `undefined` (never an empty array) when `ref` does not resolve to
|
|
84
|
+
* any live catalog/registry row — SPEC.md §6.1's read-path rule ("an
|
|
85
|
+
* unresolved name is not an error; it resolves to zero matches") is realized
|
|
86
|
+
* by the CALLER treating `undefined` as "this filter can never match
|
|
87
|
+
* anything," short-circuiting the whole query to an empty page rather than
|
|
88
|
+
* querying with a meaningless empty `ids: []` (which `NodeFilter.ids` would
|
|
89
|
+
* otherwise interpret as "no restriction" on some backends — never rely on
|
|
90
|
+
* that ambiguity here).
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveEdgeScopedCandidates(graph: GraphBackend, input: {
|
|
93
|
+
rel: string;
|
|
94
|
+
expectedKind: string;
|
|
95
|
+
ref: string;
|
|
96
|
+
projectUid?: string;
|
|
97
|
+
}): Promise<Set<number> | undefined>;
|
|
98
|
+
/** Every live catalog row's `name` for a given open-vocabulary catalog kind — used only to VALIDATE a filter value against what genuinely exists, never to constrain what a caller may create. */
|
|
99
|
+
export declare function fetchCatalogNames(graph: GraphBackend, catalogKind: 'kind' | 'status' | 'priority'): Promise<string[]>;
|
|
100
|
+
/**
|
|
101
|
+
* Nearest-name suggestions for an unresolved filter value — case-insensitive
|
|
102
|
+
* edit distance over the catalog's OWN live names, bounded to a distance
|
|
103
|
+
* proportional to the typo'd value's own length so an unrelated short
|
|
104
|
+
* catalog name is never suggested for a long, clearly-different value.
|
|
105
|
+
* Sorted nearest-first, capped at `max`.
|
|
106
|
+
*/
|
|
107
|
+
export declare function suggestClosestCatalogNames(value: string, candidates: readonly string[], max?: number): string[];
|
|
108
|
+
/**
|
|
109
|
+
* Resolves a multi-valued `kind`/`status`/`priority` filter dimension
|
|
110
|
+
* (OR-union across `refs`), rejecting with a `BacklogValidationError` naming
|
|
111
|
+
* every ref that matches NO live catalog row of that kind — see this
|
|
112
|
+
* section's top doc comment for the full rationale. Never rejects a ref that
|
|
113
|
+
* resolves to a real row with zero owning issues; that still contributes an
|
|
114
|
+
* empty set exactly as a plain unresolved-name read would.
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveValidatedCatalogFilter(graph: GraphBackend, input: {
|
|
117
|
+
rel: string;
|
|
118
|
+
catalogKind: 'kind' | 'status' | 'priority';
|
|
119
|
+
field: string;
|
|
120
|
+
refs: readonly string[];
|
|
121
|
+
}): Promise<Set<number>>;
|
|
122
|
+
/** Intersect a list of candidate-rowid sets (SPEC.md §6.5 rule 3: "AND semantics — an issue must satisfy every edge-scoped filter given"). An empty input list means "no edge-scoped filter was given" — returns `undefined` (no restriction), never an empty set. */
|
|
123
|
+
export declare function intersectCandidateSets(sets: ReadonlyArray<Set<number>>): Set<number> | undefined;
|