@adhd/backlog 0.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 +1 -0
- package/README.md +67 -0
- package/client.d.ts +72 -0
- package/env.d.ts +36 -0
- package/index.d.ts +11 -0
- package/index.js +179 -0
- package/index.mjs +14842 -0
- package/markdown.d.ts +64 -0
- package/model.d.ts +220 -0
- package/package.json +20 -0
- package/server.d.ts +31 -0
- package/store/claim.d.ts +24 -0
- package/store/crud.d.ts +20 -0
- package/store/graph-backlog-store.d.ts +11 -0
- package/store/ids.d.ts +3 -0
- package/store/lifecycle.d.ts +23 -0
- package/store/mapping.d.ts +49 -0
- package/store/mutate-metadata.d.ts +8 -0
- package/store/query.d.ts +28 -0
- package/store/structure.d.ts +35 -0
package/markdown.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BacklogFilter, BacklogItem, BacklogStatus, Priority } from './model.js';
|
|
2
|
+
|
|
3
|
+
declare const LEGACY_TERMINAL_DONE: string[];
|
|
4
|
+
declare const LEGACY_TERMINAL_WORKAROUND: string[];
|
|
5
|
+
declare const LEGACY_TERMINAL_DISMISSED: string[];
|
|
6
|
+
declare const LEGACY_TERMINAL: Set<string>;
|
|
7
|
+
export declare function normalizeLegacyStatus(rawLabel: string): BacklogStatus;
|
|
8
|
+
/**
|
|
9
|
+
* Classify a free-form status string into a {label, open} pair — ported
|
|
10
|
+
* verbatim from tools/util/backlog.mjs:56-82 (`classifyStatus`). Backlog
|
|
11
|
+
* Status lines are prose, so an open signal must win over a closed word when
|
|
12
|
+
* both are present.
|
|
13
|
+
*/
|
|
14
|
+
export declare function classifyStatus(raw: string | undefined): {
|
|
15
|
+
label: string;
|
|
16
|
+
open: boolean;
|
|
17
|
+
} | null;
|
|
18
|
+
/** Ported verbatim from tools/util/backlog.mjs:84-96 (`detectStatus`). */
|
|
19
|
+
export declare function detectStatus(headerLine: string, body: string): {
|
|
20
|
+
label: string;
|
|
21
|
+
open: boolean;
|
|
22
|
+
};
|
|
23
|
+
/** Ported verbatim from tools/util/backlog.mjs:98-104 (`detectPriority`). */
|
|
24
|
+
export declare function detectPriority(headerLine: string, body: string): string;
|
|
25
|
+
export interface ParsedMarkdownItem {
|
|
26
|
+
id: string;
|
|
27
|
+
kind: string;
|
|
28
|
+
family: string;
|
|
29
|
+
title: string;
|
|
30
|
+
level: number;
|
|
31
|
+
line: number;
|
|
32
|
+
headerLine: string;
|
|
33
|
+
status: string;
|
|
34
|
+
open: boolean;
|
|
35
|
+
terminal: boolean;
|
|
36
|
+
priority: string;
|
|
37
|
+
body: string;
|
|
38
|
+
}
|
|
39
|
+
/** Ported (structure preserved) from tools/util/backlog.mjs:106-155 (`parse`). */
|
|
40
|
+
export declare function parseBacklogMarkdown(text: string): ParsedMarkdownItem[];
|
|
41
|
+
/**
|
|
42
|
+
* SPEC.md §5.6 `renderToMarkdown` — one `###` block per item. Archived-item
|
|
43
|
+
* exclusion (SPEC.md §5.4 `archiveResolved`'s "renderToMarkdown's default
|
|
44
|
+
* view excludes them") happens one layer up, in `client.ts`'s
|
|
45
|
+
* `renderToMarkdown`, which has access to the raw node `metadata.archivedAt`
|
|
46
|
+
* flag — `BacklogItem` (SPEC.md §4.1) deliberately carries no `archivedAt`
|
|
47
|
+
* field of its own, so this function (pure, no store access) cannot filter
|
|
48
|
+
* on it and takes an already-filtered `items` array.
|
|
49
|
+
*/
|
|
50
|
+
export declare function renderItemsToMarkdown(items: BacklogItem[]): string;
|
|
51
|
+
/** Ported from tools/util/backlog.mjs:351-361 (`buildChangelogSection`). */
|
|
52
|
+
export declare function buildChangelogSection(items: BacklogItem[], date: string): string;
|
|
53
|
+
/** Applies the SAME filters `applyFilters`/`BacklogFilter` describes, used only for markdown-side symmetry checks in tests. */
|
|
54
|
+
export declare function matchesFilter(item: ParsedMarkdownItem, filter: BacklogFilter): boolean;
|
|
55
|
+
export interface ParsedImportItem {
|
|
56
|
+
humanId: string;
|
|
57
|
+
title: string;
|
|
58
|
+
body: string;
|
|
59
|
+
status: BacklogStatus;
|
|
60
|
+
priority?: Priority;
|
|
61
|
+
}
|
|
62
|
+
/** Bridges the legacy parser's raw shape into the canonical vocabulary (SPEC.md §5.6 `importFromMarkdown`). */
|
|
63
|
+
export declare function toImportItems(parsed: ParsedMarkdownItem[]): ParsedImportItem[];
|
|
64
|
+
export { LEGACY_TERMINAL, LEGACY_TERMINAL_DONE, LEGACY_TERMINAL_DISMISSED, LEGACY_TERMINAL_WORKAROUND };
|
package/model.d.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* model.ts — the `BacklogItem` domain shape and every operation-surface input
|
|
3
|
+
* / output type. Ported verbatim from `SPEC.md` §4/§5. Pure types + a handful
|
|
4
|
+
* of tiny, dependency-free classification helpers — no store/env imports.
|
|
5
|
+
*/
|
|
6
|
+
export type BacklogStatus = 'OPEN' | 'IN_PROGRESS' | 'PARTIAL' | 'OUTSTANDING' | 'DEFERRED' | 'BLOCKED' | 'MIXED' | 'UNKNOWN' | 'FIXED' | 'RESOLVED' | 'DONE' | 'SHIPPED' | 'VERIFIED' | 'REMOVED' | 'MITIGATED' | 'SUPERSEDED' | 'INVALID' | 'DUPLICATE' | 'WONTFIX';
|
|
7
|
+
/** §4.2 rule 3 — terminal-done + terminal-workaround: require ≥1 citation. */
|
|
8
|
+
export declare const TERMINAL_DONE_STATUSES: ReadonlySet<BacklogStatus>;
|
|
9
|
+
export declare const TERMINAL_WORKAROUND_STATUSES: ReadonlySet<BacklogStatus>;
|
|
10
|
+
/** §4.2 rule 3 — terminal-dismissed: require a reason (citation optional). */
|
|
11
|
+
export declare const TERMINAL_DISMISSED_STATUSES: ReadonlySet<BacklogStatus>;
|
|
12
|
+
export declare const TERMINAL_STATUSES: ReadonlySet<BacklogStatus>;
|
|
13
|
+
export declare function isTerminalStatus(status: BacklogStatus): boolean;
|
|
14
|
+
/** §4.2 rule 3 — "a transition INTO any terminal status requires evidence." */
|
|
15
|
+
export declare function requiresCitation(status: BacklogStatus): boolean;
|
|
16
|
+
export declare function requiresReason(status: BacklogStatus): boolean;
|
|
17
|
+
export type Priority = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
|
|
18
|
+
export interface Citation {
|
|
19
|
+
/** Repo-relative path, matching the global CLAUDE.md citation format. */
|
|
20
|
+
file: string;
|
|
21
|
+
/** e.g. "42-58"; omit for a whole-file citation. */
|
|
22
|
+
lines?: string;
|
|
23
|
+
/** Free text — active git context / agent name / model, per the citation format. */
|
|
24
|
+
context?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Note {
|
|
27
|
+
by: string;
|
|
28
|
+
at: string;
|
|
29
|
+
text: string;
|
|
30
|
+
}
|
|
31
|
+
export interface BacklogItem {
|
|
32
|
+
/** The graph node id (see DESIGN.md §2). Never exposed to markdown; internal only. */
|
|
33
|
+
nodeId: number;
|
|
34
|
+
/** Human-facing id, e.g. "BUG-APIGEN-014". Unique within (repo, family). */
|
|
35
|
+
humanId: string;
|
|
36
|
+
/** First hyphen segment of humanId, e.g. "BUG". Open vocabulary — not an enum. */
|
|
37
|
+
kind: string;
|
|
38
|
+
/** humanId with the trailing "-NNN" stripped, e.g. "BUG-APIGEN". */
|
|
39
|
+
family: string;
|
|
40
|
+
title: string;
|
|
41
|
+
/** Markdown body — the full entry text minus the header line. */
|
|
42
|
+
body: string;
|
|
43
|
+
status: BacklogStatus;
|
|
44
|
+
priority?: Priority;
|
|
45
|
+
/** Stable repo slug — see SPEC.md §3 "Repo identity". */
|
|
46
|
+
repo: string;
|
|
47
|
+
/** Package-relative path within the repo, e.g. "packages/apigen/apigen-core-client". Optional — repo-level items omit it. */
|
|
48
|
+
projectPath?: string;
|
|
49
|
+
/** Plan slug this item is attached to, if any — e.g. "agent-registry-schema". */
|
|
50
|
+
plan?: string;
|
|
51
|
+
/** Durable ownership — who this item is assigned to (may differ from the active claimant). */
|
|
52
|
+
assignee?: string;
|
|
53
|
+
/** Ephemeral claim lease — see SPEC.md §5. */
|
|
54
|
+
claimedBy?: string;
|
|
55
|
+
claimedAt?: string;
|
|
56
|
+
citations: Citation[];
|
|
57
|
+
notes: Note[];
|
|
58
|
+
tags: string[];
|
|
59
|
+
createdAt: string;
|
|
60
|
+
updatedAt: string;
|
|
61
|
+
}
|
|
62
|
+
export declare class BacklogItemNotFoundError extends Error {
|
|
63
|
+
constructor(repo: string, humanId: string);
|
|
64
|
+
}
|
|
65
|
+
export declare class CitationRequiredError extends Error {
|
|
66
|
+
constructor(status: BacklogStatus);
|
|
67
|
+
}
|
|
68
|
+
export declare class ReasonRequiredError extends Error {
|
|
69
|
+
constructor(status: BacklogStatus);
|
|
70
|
+
}
|
|
71
|
+
export declare class ClaimHeldError extends Error {
|
|
72
|
+
readonly heldBy: string;
|
|
73
|
+
readonly heldSince: string;
|
|
74
|
+
constructor(heldBy: string, heldSince: string);
|
|
75
|
+
}
|
|
76
|
+
export declare class DependencyCycleError extends Error {
|
|
77
|
+
readonly cycle: string[];
|
|
78
|
+
constructor(cycle: string[]);
|
|
79
|
+
}
|
|
80
|
+
export interface DedupeScanInput {
|
|
81
|
+
symbol?: string;
|
|
82
|
+
path?: string;
|
|
83
|
+
errorText?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface CreateItemInput {
|
|
86
|
+
family: string;
|
|
87
|
+
idOverride?: string;
|
|
88
|
+
title: string;
|
|
89
|
+
body: string;
|
|
90
|
+
repo: string;
|
|
91
|
+
projectPath?: string;
|
|
92
|
+
priority?: Priority;
|
|
93
|
+
tags?: string[];
|
|
94
|
+
plan?: string;
|
|
95
|
+
dedupeScan?: DedupeScanInput;
|
|
96
|
+
/** Skip the dedupe gate and file anyway (planner override after reviewing candidates). */
|
|
97
|
+
force?: boolean;
|
|
98
|
+
}
|
|
99
|
+
export interface CreateItemResult {
|
|
100
|
+
item: BacklogItem;
|
|
101
|
+
created: boolean;
|
|
102
|
+
duplicateCandidates: BacklogItem[];
|
|
103
|
+
}
|
|
104
|
+
export interface UpdateItemInput {
|
|
105
|
+
title?: string;
|
|
106
|
+
body?: string;
|
|
107
|
+
tags?: string[];
|
|
108
|
+
projectPath?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface BacklogFilter {
|
|
111
|
+
repo?: string;
|
|
112
|
+
projectPath?: string;
|
|
113
|
+
status?: BacklogStatus | 'open' | 'closed';
|
|
114
|
+
kind?: string;
|
|
115
|
+
family?: string;
|
|
116
|
+
priority?: Priority;
|
|
117
|
+
plan?: string;
|
|
118
|
+
assignee?: string;
|
|
119
|
+
claimedBy?: string;
|
|
120
|
+
tags?: string[];
|
|
121
|
+
grep?: string;
|
|
122
|
+
limit?: number;
|
|
123
|
+
offset?: number;
|
|
124
|
+
}
|
|
125
|
+
export interface StatsScope {
|
|
126
|
+
repo?: string;
|
|
127
|
+
projectPath?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface BacklogStats {
|
|
130
|
+
total: number;
|
|
131
|
+
open: number;
|
|
132
|
+
closed: number;
|
|
133
|
+
byStatus: Record<string, number>;
|
|
134
|
+
byKind: Record<string, number>;
|
|
135
|
+
byFamily: Record<string, number>;
|
|
136
|
+
byPriority: Record<string, number>;
|
|
137
|
+
byRepo: Record<string, number>;
|
|
138
|
+
}
|
|
139
|
+
export interface DependencyGraph {
|
|
140
|
+
nodes: Array<{
|
|
141
|
+
humanId: string;
|
|
142
|
+
title: string;
|
|
143
|
+
status: BacklogStatus;
|
|
144
|
+
}>;
|
|
145
|
+
edges: Array<{
|
|
146
|
+
from: string;
|
|
147
|
+
to: string;
|
|
148
|
+
rel: 'DEPENDS_ON' | 'RELATES_TO' | 'PART_OF';
|
|
149
|
+
}>;
|
|
150
|
+
}
|
|
151
|
+
export type TopoOrderResult = {
|
|
152
|
+
ok: true;
|
|
153
|
+
order: string[];
|
|
154
|
+
} | {
|
|
155
|
+
ok: false;
|
|
156
|
+
cycle: string[];
|
|
157
|
+
};
|
|
158
|
+
export interface ClaimOpts {
|
|
159
|
+
/** Minutes after which an unrenewed claim is considered abandoned. Default: 30 (DESIGN.md §4.2). */
|
|
160
|
+
staleAfterMin?: number;
|
|
161
|
+
/** Explicitly override a claim that is NOT stale (human-confirmed abandonment). */
|
|
162
|
+
force?: boolean;
|
|
163
|
+
}
|
|
164
|
+
export type ClaimStatus = 'claimed' | 'renewed' | 'reclaimed-stale' | 'held';
|
|
165
|
+
export interface ClaimResult {
|
|
166
|
+
status: ClaimStatus;
|
|
167
|
+
claimedBy: string;
|
|
168
|
+
claimedAt: string;
|
|
169
|
+
/** Only present when status === 'held'. */
|
|
170
|
+
heldBy?: string;
|
|
171
|
+
heldSince?: string;
|
|
172
|
+
/** Only present when status === 'reclaimed-stale' — the abandoned claimant, for audit. */
|
|
173
|
+
previousClaimant?: string;
|
|
174
|
+
}
|
|
175
|
+
export interface ReleaseResult {
|
|
176
|
+
status: 'released' | 'release-noop';
|
|
177
|
+
wasClaimedBy?: string;
|
|
178
|
+
}
|
|
179
|
+
export interface TransitionOpts {
|
|
180
|
+
by: string;
|
|
181
|
+
note?: string;
|
|
182
|
+
citations?: Citation[];
|
|
183
|
+
reason?: string;
|
|
184
|
+
}
|
|
185
|
+
export interface ArchiveOpts {
|
|
186
|
+
/** Exclude specific humanIds from the sweep even though they're terminal (mirrors tools/util/backlog.mjs's --exclude). */
|
|
187
|
+
exclude?: string[];
|
|
188
|
+
}
|
|
189
|
+
export interface ArchiveResult {
|
|
190
|
+
archivedCount: number;
|
|
191
|
+
changelogMarkdown: string;
|
|
192
|
+
}
|
|
193
|
+
export interface ImportMarkdownInput {
|
|
194
|
+
path: string;
|
|
195
|
+
repo: string;
|
|
196
|
+
projectPath?: string;
|
|
197
|
+
dryRun?: boolean;
|
|
198
|
+
}
|
|
199
|
+
export interface ImportResult {
|
|
200
|
+
parsed: number;
|
|
201
|
+
created: number;
|
|
202
|
+
skippedDuplicates: number;
|
|
203
|
+
errors: Array<{
|
|
204
|
+
humanId: string;
|
|
205
|
+
message: string;
|
|
206
|
+
}>;
|
|
207
|
+
}
|
|
208
|
+
export interface AuditTrailEntry {
|
|
209
|
+
at: string;
|
|
210
|
+
kind: 'created' | 'transition' | 'claim' | 'note' | 'citation' | 'supersession';
|
|
211
|
+
detail: Record<string, unknown>;
|
|
212
|
+
}
|
|
213
|
+
export interface AuditTrailResult {
|
|
214
|
+
humanId: string;
|
|
215
|
+
history: AuditTrailEntry[];
|
|
216
|
+
supersessionChain?: {
|
|
217
|
+
supersedes?: string;
|
|
218
|
+
supersededBy?: string;
|
|
219
|
+
};
|
|
220
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adhd/backlog",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@adhd/sox-graph-store": "^0.3.0",
|
|
6
|
+
"better-sqlite3": "^12.10.0",
|
|
7
|
+
"@adhd/environment": "^0.0.2",
|
|
8
|
+
"@adhd/environment-base-spec": "^0.0.3",
|
|
9
|
+
"@adhd/apigen-core-client": "^0.1.2",
|
|
10
|
+
"@adhd/apigen-plugin-api-fastify": "^0.1.3",
|
|
11
|
+
"@adhd/apigen-plugin-openapi": "^0.1.4",
|
|
12
|
+
"@adhd/apigen-plugin-mcp": "^0.1.3"
|
|
13
|
+
},
|
|
14
|
+
"main": "./index.js",
|
|
15
|
+
"module": "./index.mjs",
|
|
16
|
+
"typings": "./index.d.ts",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/server.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BacklogCtx } from './client.js';
|
|
2
|
+
import { composeSchemas, Operation } from '@adhd/apigen-core-client';
|
|
3
|
+
import { Scope } from '@adhd/environment-base-spec';
|
|
4
|
+
|
|
5
|
+
export interface StartOpts {
|
|
6
|
+
transport: 'http' | 'mcp' | 'both';
|
|
7
|
+
port?: number;
|
|
8
|
+
host?: string;
|
|
9
|
+
scope?: Scope;
|
|
10
|
+
/** Test-only override — see `buildBacklogEnv`'s `BuildBacklogEnvOptions`. */
|
|
11
|
+
adhdRoot?: string;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
signal: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
/** Builds the composed, apigen-ready package descriptor for `client.ts`'s exports. */
|
|
16
|
+
export declare function buildBacklogApigenPackage(ctx: BacklogCtx): Promise<{
|
|
17
|
+
pkg: {
|
|
18
|
+
id: string;
|
|
19
|
+
schemas: ReturnType<typeof composeSchemas>;
|
|
20
|
+
importPath: string;
|
|
21
|
+
fns: Record<string, (...args: unknown[]) => unknown>;
|
|
22
|
+
createClient: () => Promise<BacklogCtx>;
|
|
23
|
+
};
|
|
24
|
+
operations: Operation[];
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Opens (or reuses) the backlog store + env, mounts every `client.ts` export
|
|
28
|
+
* live via `@adhd/apigen-plugin-api-fastify` and/or `@adhd/apigen-plugin-mcp`
|
|
29
|
+
* — no code generation.
|
|
30
|
+
*/
|
|
31
|
+
export declare function startBacklogServer(opts: StartOpts): Promise<void>;
|
package/store/claim.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
2
|
+
import { ClaimOpts, ClaimResult, ReleaseResult } from '../model.js';
|
|
3
|
+
|
|
4
|
+
/** DESIGN.md §4.2 — matches STALE_CLAIM_S = 30*60 at state-transition.js:601. */
|
|
5
|
+
export declare const DEFAULT_STALE_AFTER_MIN = 30;
|
|
6
|
+
export declare class ClaimContentionError extends Error {
|
|
7
|
+
readonly heldBy: string;
|
|
8
|
+
constructor(heldBy: string, by: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* DESIGN.md §4.2 — the exact branch table:
|
|
12
|
+
* unclaimed -> claimed
|
|
13
|
+
* by === claimedBy -> renewed (no contention check, ever)
|
|
14
|
+
* by !== claimedBy, age <= staleAfterMin -> held (refuse, no write)
|
|
15
|
+
* by !== claimedBy, age > staleAfterMin -> reclaimed-stale
|
|
16
|
+
* by !== claimedBy, opts.force -> proceeds anyway (reclaimed-stale-shaped)
|
|
17
|
+
*/
|
|
18
|
+
export declare function claimItemNode(store: GraphBacklogStore, nodeId: number, by: string, opts?: ClaimOpts): ClaimResult;
|
|
19
|
+
/** SPEC.md §5.3 — "always succeeds (bumps claimedAt), no contention check, ever." */
|
|
20
|
+
export declare function renewClaimNode(store: GraphBacklogStore, nodeId: number, by: string): ClaimResult;
|
|
21
|
+
/** DESIGN.md §4.2 — releasing an already-unclaimed item is a no-op, never an error. */
|
|
22
|
+
export declare function releaseClaimNode(store: GraphBacklogStore, nodeId: number, by: string, opts?: {
|
|
23
|
+
force?: boolean;
|
|
24
|
+
}): ReleaseResult;
|
package/store/crud.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
2
|
+
import { BacklogItem, CreateItemInput, CreateItemResult, UpdateItemInput } from '../model.js';
|
|
3
|
+
|
|
4
|
+
declare function dedupeScan(store: GraphBacklogStore, repo: string, input: CreateItemInput): BacklogItem[];
|
|
5
|
+
export declare function createItemNode(store: GraphBacklogStore, input: CreateItemInput): CreateItemResult;
|
|
6
|
+
export declare function getItemNode(store: GraphBacklogStore, repo: string, humanId: string): BacklogItem | null;
|
|
7
|
+
/**
|
|
8
|
+
* DEVIATION: `@adhd/sox-graph-store` exposes no primitive to update a node's
|
|
9
|
+
* `content` column after creation (`touch()`'s `Partial<NodeMeta>` covers
|
|
10
|
+
* name/summary/topic/tags/importance/confidence/tExpires/metadata — never
|
|
11
|
+
* `content`; verified against the real source). `title` updates the `summary`
|
|
12
|
+
* column (source of truth for the API) AND `metadata.title`; `body` updates
|
|
13
|
+
* ONLY `metadata.body` (source of truth for the API). The underlying FTS
|
|
14
|
+
* `content` (set once at `createItem` time) therefore does not reflect a
|
|
15
|
+
* later body edit — `listItems({ grep })` may miss a post-edit body term
|
|
16
|
+
* until the item is superseded. Filed as DEBT-BACKLOG-CONTENT-IMMUTABLE-001.
|
|
17
|
+
*/
|
|
18
|
+
export declare function updateItemNode(store: GraphBacklogStore, repo: string, humanId: string, patch: UpdateItemInput): BacklogItem;
|
|
19
|
+
export declare function softDeleteItemNode(store: GraphBacklogStore, repo: string, humanId: string, reason: string): void;
|
|
20
|
+
export { dedupeScan };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
2
|
+
import { default as Database } from 'better-sqlite3';
|
|
3
|
+
|
|
4
|
+
export interface GraphBacklogStore {
|
|
5
|
+
/** Raw handle — ONLY for the CAS transaction wrapper (mutate-metadata.ts / ids.ts). */
|
|
6
|
+
readonly db: Database.Database;
|
|
7
|
+
/** All non-CAS reads/writes go through this. */
|
|
8
|
+
readonly graph: GraphBackend;
|
|
9
|
+
}
|
|
10
|
+
export declare function openGraphBacklogStore(dbPath: string): GraphBacklogStore;
|
|
11
|
+
export declare function closeGraphBacklogStore(store: GraphBacklogStore): void;
|
package/store/ids.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
2
|
+
import { ArchiveOpts, BacklogItem, BacklogStatus, Citation, StatsScope, TransitionOpts } from '../model.js';
|
|
3
|
+
|
|
4
|
+
export declare function transitionStatusNode(store: GraphBacklogStore, repo: string, humanId: string, status: BacklogStatus, opts: TransitionOpts): BacklogItem;
|
|
5
|
+
/** Sugar for transitionStatus into any terminal status (SPEC.md §5.4). */
|
|
6
|
+
export declare function resolveItemNode(store: GraphBacklogStore, repo: string, humanId: string, status: BacklogStatus, opts: TransitionOpts): BacklogItem;
|
|
7
|
+
/**
|
|
8
|
+
* `transitionStatus(id, 'IN_PROGRESS', ...)` + an implicit `claimItem(id, by)`.
|
|
9
|
+
* If the item is actively claimed (not stale) by someone else, the claim
|
|
10
|
+
* step returns `held` and startWork refuses — starting work on a
|
|
11
|
+
* contended item would silently override the claim protocol otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare function startWorkNode(store: GraphBacklogStore, repo: string, humanId: string, by: string): BacklogItem;
|
|
14
|
+
export declare function addCitationNode(store: GraphBacklogStore, repo: string, humanId: string, citation: Citation): BacklogItem;
|
|
15
|
+
export declare function appendNoteNode(store: GraphBacklogStore, repo: string, humanId: string, by: string, text: string): BacklogItem;
|
|
16
|
+
/**
|
|
17
|
+
* Marks every terminal, non-excluded item in scope as archived
|
|
18
|
+
* (`metadata.archivedAt`) and returns them — the graph node itself is NEVER
|
|
19
|
+
* deleted (bi-temporal history is permanent). Rendering the archived set to
|
|
20
|
+
* CHANGELOG.md-formatted markdown is `client.ts`'s job (via `markdown.ts`) —
|
|
21
|
+
* store/* never depends on markdown.ts (DESIGN.md §1 layering).
|
|
22
|
+
*/
|
|
23
|
+
export declare function archiveTerminalItems(store: GraphBacklogStore, scope: StatsScope, opts?: ArchiveOpts): BacklogItem[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { BacklogItem, BacklogStatus, Citation, Note, Priority } from '../model.js';
|
|
2
|
+
import { NodeRecord } from '@adhd/sox-graph-store';
|
|
3
|
+
|
|
4
|
+
export declare const BACKLOG_ITEM_TAG = "backlog-item";
|
|
5
|
+
export declare const BACKLOG_PLAN_TAG = "backlog-plan";
|
|
6
|
+
export declare const BACKLOG_ASSIGNEE_TAG = "backlog-assignee";
|
|
7
|
+
/**
|
|
8
|
+
* The JSON shape persisted in `node.meta` (DESIGN.md §2.2/§4.1). Every
|
|
9
|
+
* mutating store operation reads the CURRENT full object, computes a new
|
|
10
|
+
* COMPLETE object, and writes it back via `mutateMetadata` — `touch()`
|
|
11
|
+
* replaces `meta` wholesale (verified, DESIGN.md §14 point 4), so a partial
|
|
12
|
+
* write here would silently drop every other field.
|
|
13
|
+
*/
|
|
14
|
+
export interface BacklogNodeMeta {
|
|
15
|
+
humanId: string;
|
|
16
|
+
kind: string;
|
|
17
|
+
family: string;
|
|
18
|
+
title: string;
|
|
19
|
+
body: string;
|
|
20
|
+
status: BacklogStatus;
|
|
21
|
+
priority?: Priority;
|
|
22
|
+
repo: string;
|
|
23
|
+
projectPath?: string;
|
|
24
|
+
plan?: string;
|
|
25
|
+
assignee?: string;
|
|
26
|
+
claimedBy?: string;
|
|
27
|
+
claimedAt?: string;
|
|
28
|
+
citations: Citation[];
|
|
29
|
+
notes: Note[];
|
|
30
|
+
createdAt: string;
|
|
31
|
+
updatedAt: string;
|
|
32
|
+
/** Set by archiveResolved — excludes the item from renderToMarkdown's default view. */
|
|
33
|
+
archivedAt?: string;
|
|
34
|
+
/** Dedupe-scan exact-match fields (DESIGN.md §2.4). */
|
|
35
|
+
dedupeSymbol?: string;
|
|
36
|
+
dedupePath?: string;
|
|
37
|
+
dedupeErrorText?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function humanIdKind(humanId: string): string;
|
|
40
|
+
export declare function humanIdFamily(humanId: string): string;
|
|
41
|
+
/** See the file-level DEVIATION doc comment for why the marker is appended. */
|
|
42
|
+
export declare function buildNodeContent(repo: string, humanId: string, title: string, body: string): string;
|
|
43
|
+
export declare function buildNodeName(repo: string, humanId: string): string;
|
|
44
|
+
/** DESIGN.md §2.2 — importance derived deterministically from priority. */
|
|
45
|
+
export declare function importanceForPriority(priority: Priority | undefined): number;
|
|
46
|
+
export declare function buildTags(kind: string, family: string, userTags?: readonly string[]): string[];
|
|
47
|
+
/** A node counts as a live backlog item iff it carries the tag AND is not superseded (DESIGN.md §14). */
|
|
48
|
+
export declare function isLiveBacklogItemNode(node: NodeRecord): boolean;
|
|
49
|
+
export declare function toBacklogItem(node: NodeRecord): BacklogItem;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BacklogNodeMeta } from './mapping.js';
|
|
2
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
3
|
+
|
|
4
|
+
export declare class NotFoundError extends Error {
|
|
5
|
+
readonly nodeId: number;
|
|
6
|
+
constructor(nodeId: number);
|
|
7
|
+
}
|
|
8
|
+
export declare function mutateMetadata<M = BacklogNodeMeta>(store: GraphBacklogStore, nodeId: number, updater: (current: M) => M): M;
|
package/store/query.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BacklogNodeMeta } from './mapping.js';
|
|
2
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
3
|
+
import { AuditTrailResult, BacklogFilter, BacklogItem, DependencyGraph, StatsScope, TopoOrderResult } from '../model.js';
|
|
4
|
+
import { NodeRecord } from '@adhd/sox-graph-store';
|
|
5
|
+
|
|
6
|
+
/** Raw NodeRecord query — used internally where the full node (not just the mapped BacklogItem) is needed. */
|
|
7
|
+
export declare function queryItemNodes(store: GraphBacklogStore, filter?: BacklogFilter): NodeRecord[];
|
|
8
|
+
export declare function listItems(store: GraphBacklogStore, filter?: BacklogFilter): BacklogItem[];
|
|
9
|
+
export declare function findItemNode(store: GraphBacklogStore, repo: string, humanId: string): NodeRecord | null;
|
|
10
|
+
export declare function computeStats(store: GraphBacklogStore, scope?: StatsScope): import('../model.js').BacklogStats;
|
|
11
|
+
export declare function spotlight(store: GraphBacklogStore, scope?: StatsScope, limit?: number): BacklogItem[];
|
|
12
|
+
export declare function blockers(store: GraphBacklogStore, repo: string, humanId: string): BacklogItem[];
|
|
13
|
+
export declare function readyItems(store: GraphBacklogStore, scope?: StatsScope): BacklogItem[];
|
|
14
|
+
export declare function dependencyGraph(store: GraphBacklogStore, scope?: StatsScope): DependencyGraph;
|
|
15
|
+
export declare function topoOrder(store: GraphBacklogStore, scope?: StatsScope): TopoOrderResult;
|
|
16
|
+
export declare function staleClaims(store: GraphBacklogStore, maxAgeMin: number, scope?: StatsScope): BacklogItem[];
|
|
17
|
+
/**
|
|
18
|
+
* Bi-temporal history + supersession chain (SPEC.md §5.6, DESIGN.md §2.3).
|
|
19
|
+
* DEVIATION: the store does not persist a full mutation event log (no
|
|
20
|
+
* separate transitions/claims-over-time table) — `history` is therefore
|
|
21
|
+
* honestly derived from the durable fields we DO keep (a synthetic
|
|
22
|
+
* `created` entry, every real `note`, every real `citation`), not a
|
|
23
|
+
* fabricated replay of every status/claim change. Citation entries reuse
|
|
24
|
+
* `item.updatedAt` as their timestamp since `Citation` carries no `at` field
|
|
25
|
+
* of its own. Filed as DEBT-BACKLOG-AUDIT-TRAIL-PARTIAL-001.
|
|
26
|
+
*/
|
|
27
|
+
export declare function auditTrail(store: GraphBacklogStore, repo: string, humanId: string): AuditTrailResult;
|
|
28
|
+
export type { BacklogNodeMeta };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
2
|
+
import { BacklogItem, CreateItemInput, Priority } from '../model.js';
|
|
3
|
+
|
|
4
|
+
export declare function addDependencyNode(store: GraphBacklogStore, repo: string, humanId: string, dependsOnHumanId: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* `@adhd/sox-graph-store` exposes no edge-delete primitive (only
|
|
7
|
+
* `invalidate()` for nodes, bi-temporal) — DESIGN.md §14 explicitly sanctions
|
|
8
|
+
* a raw `DELETE` on the store-owned `db` handle as the one place the adapter
|
|
9
|
+
* reaches past the `GraphBackend` API, confirmed against the real `edge`
|
|
10
|
+
* table column names (`src`/`dst`/`rel`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function removeDependencyNode(store: GraphBacklogStore, repo: string, humanId: string, dependsOnHumanId: string): void;
|
|
13
|
+
export declare function linkRelatedNode(store: GraphBacklogStore, repo: string, humanIdA: string, humanIdB: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* DESIGN.md §14 point 2 (CONFIRMED against the real source): `supersede(oldId,
|
|
16
|
+
* newContent, meta)` writes `SUPERSEDES` new -> old, sets `is_superseded=1`
|
|
17
|
+
* on the old node, and mints the new node — ALL in one internal transaction.
|
|
18
|
+
* It does NOT invalidate the old node (`t_invalid` stays null) — SPEC.md
|
|
19
|
+
* §5.5 additionally requires the old item to become bi-temporally invalid
|
|
20
|
+
* with `reason`, so this composes `supersede()` with a status update (BEFORE
|
|
21
|
+
* invalidation — `touch()`/`mutateMetadata` throw once `t_invalid` is set)
|
|
22
|
+
* and a final `invalidate(oldId, reason)`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function supersedeItemNode(store: GraphBacklogStore, repo: string, oldHumanId: string, newInput: CreateItemInput, reason: string): BacklogItem;
|
|
25
|
+
/** Creates N children, each linked child PART_OF parent. Parent is left open. */
|
|
26
|
+
export declare function splitItemNode(store: GraphBacklogStore, repo: string, parentHumanId: string, children: CreateItemInput[]): BacklogItem[];
|
|
27
|
+
/**
|
|
28
|
+
* `SAME_AS(drop -> keep)` per DESIGN.md §14 point 2 (obsolete -> canonical,
|
|
29
|
+
* matching the `supersede()` convention), then `invalidate(drop, reason)`.
|
|
30
|
+
* Returns the KEPT item.
|
|
31
|
+
*/
|
|
32
|
+
export declare function mergeItemsNode(store: GraphBacklogStore, repo: string, keepHumanId: string, dropHumanId: string, reason: string): BacklogItem;
|
|
33
|
+
export declare function setPriorityNode(store: GraphBacklogStore, repo: string, humanId: string, priority: Priority): BacklogItem;
|
|
34
|
+
export declare function attachToPlanNode(store: GraphBacklogStore, repo: string, humanId: string, planSlug: string): void;
|
|
35
|
+
export declare function assignItemNode(store: GraphBacklogStore, repo: string, humanId: string, to: string, by: string): BacklogItem;
|