@cerebriline/core 4.100.240 → 4.100.242

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.
Files changed (64) hide show
  1. package/assets/skills/README.md +14 -0
  2. package/assets/skills/build-project/SKILL.md +103 -0
  3. package/assets/skills/docker-compose-deploy/SKILL.md +239 -0
  4. package/assets/skills/librarian/SKILL.md +177 -0
  5. package/assets/skills/mandatory-qa-prompt-and-issue-resolution/SKILL.md +58 -0
  6. package/assets/skills/run-project/SKILL.md +103 -0
  7. package/assets/skills/sdd-discuss/SKILL.md +129 -0
  8. package/assets/skills/sdd-execute/SKILL.md +146 -0
  9. package/assets/skills/sdd-plan/SKILL.md +140 -0
  10. package/assets/skills/sdd-quick/SKILL.md +40 -0
  11. package/assets/skills/sdd-status/SKILL.md +75 -0
  12. package/assets/skills/sdd-verify/SKILL.md +122 -0
  13. package/assets/skills/sdd-wizard/SKILL.md +105 -0
  14. package/assets/skills/tdd-coverage/SKILL.md +88 -0
  15. package/assets/skills/tdd-gen/SKILL.md +82 -0
  16. package/assets/skills/tdd-test/SKILL.md +61 -0
  17. package/assets/skills/tdd-wizard/SKILL.md +162 -0
  18. package/dist/document-reader-child.js +23 -0
  19. package/dist/extensions/config/bundled-skills.d.ts +24 -0
  20. package/dist/extensions/config/index.d.ts +2 -1
  21. package/dist/extensions/config/unified-config-file-watcher.d.ts +15 -0
  22. package/dist/extensions/config/user-instruction-config-loader.d.ts +15 -0
  23. package/dist/extensions/tools/executors/document/ebook.d.ts +10 -0
  24. package/dist/extensions/tools/executors/document/formats.d.ts +25 -0
  25. package/dist/extensions/tools/executors/document/ocr.d.ts +8 -0
  26. package/dist/extensions/tools/executors/document/read-job.d.ts +68 -0
  27. package/dist/extensions/tools/executors/document/read-process.d.ts +52 -0
  28. package/dist/extensions/tools/executors/document/read-protocol.d.ts +65 -0
  29. package/dist/extensions/tools/executors/document/recognition.d.ts +14 -5
  30. package/dist/extensions/tools/executors/document-extract.d.ts +120 -1
  31. package/dist/extensions/tools/librarian-tools.d.ts +32 -0
  32. package/dist/extensions/tools/library-import-run.d.ts +79 -0
  33. package/dist/extensions/tools/library-tools.d.ts +88 -0
  34. package/dist/extensions/tools/memory-tools.d.ts +41 -0
  35. package/dist/extensions/tools/sdd-tool.d.ts +215 -0
  36. package/dist/extensions/tools/team/create-agent-tool.d.ts +5 -4
  37. package/dist/hub/daemon/entry.js +607 -603
  38. package/dist/hub/index.js +595 -591
  39. package/dist/index.d.ts +17 -1
  40. package/dist/index.js +1080 -695
  41. package/dist/services/global-settings.d.ts +9 -0
  42. package/dist/services/llms/provider-settings.d.ts +15 -15
  43. package/dist/services/retrieval/catalogue.d.ts +397 -0
  44. package/dist/services/retrieval/chunker.d.ts +44 -0
  45. package/dist/services/retrieval/embedding-client.d.ts +78 -0
  46. package/dist/services/retrieval/fingerprint.d.ts +21 -0
  47. package/dist/services/retrieval/firecrawl.d.ts +77 -0
  48. package/dist/services/retrieval/lancedb-runtime.d.ts +84 -0
  49. package/dist/services/retrieval/lancedb-runtime.manifest.d.ts +17 -0
  50. package/dist/services/retrieval/library-store.d.ts +148 -0
  51. package/dist/services/retrieval/library.d.ts +139 -0
  52. package/dist/services/retrieval/memory-recall.d.ts +97 -0
  53. package/dist/services/retrieval/memory.d.ts +184 -0
  54. package/dist/services/retrieval/retrieve.d.ts +85 -0
  55. package/dist/services/retrieval/running-heads.d.ts +38 -0
  56. package/dist/services/retrieval/tar-extract.d.ts +14 -0
  57. package/dist/services/retrieval/tar-write.d.ts +20 -0
  58. package/dist/services/retrieval/vector-index.d.ts +82 -0
  59. package/dist/services/sdd/sdd-engine.d.ts +248 -0
  60. package/dist/services/telemetry/index.js +1 -1
  61. package/dist/types/config.d.ts +7 -0
  62. package/dist/types/session.d.ts +2 -0
  63. package/package.json +4 -4
  64. package/dist/extensions/tools/code-intel.d.ts +0 -131
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Memory: short notes the model keeps between tasks.
3
+ *
4
+ * A note is a fact worth having next time: a decision and its reason, how
5
+ * this project is built and tested, a preference of the user, a trap that
6
+ * cost an hour. It is kept by the retrieval core the Library uses, in a
7
+ * store of its own, so it is searched the same way: by keyword always, and
8
+ * by meaning when an embedding model is set.
9
+ *
10
+ * There are any number of memories, all in the one store: the main one,
11
+ * which every workspace starts on, and whichever others the user makes --
12
+ * one for a workspace, one for a client, one imported from a colleague. A
13
+ * session keeps new notes in exactly one of them and searches as many as
14
+ * the user allows it; which, is the user's choice per workspace and not
15
+ * something the model can widen.
16
+ */
17
+ import { type MemorySettings } from "@cerebriline/shared";
18
+ import type { RetrievalEndpoint } from "./embedding-client";
19
+ import { type EmbedPendingResult, type LibraryOptions, type LibraryVectorSet } from "./library";
20
+ export interface MemoryItem {
21
+ /** `m12`: what `forget` takes. */
22
+ id: string;
23
+ text: string;
24
+ /** The memory it is kept in. */
25
+ memory: string;
26
+ tags: string[];
27
+ createdAt: string;
28
+ }
29
+ export interface RecalledMemory extends MemoryItem {
30
+ /** The reranker's score, 0 to 1, when there was one. */
31
+ relevance?: number;
32
+ /** Cosine similarity to the query, when the note was found by meaning. */
33
+ similarity?: number;
34
+ }
35
+ export interface MemoryEndpoints {
36
+ embedding?: RetrievalEndpoint;
37
+ reranker?: RetrievalEndpoint;
38
+ }
39
+ /** One of the memories, as the settings panel lists it. */
40
+ export interface MemoryInfo {
41
+ name: string;
42
+ /** The main memory: always there, never deleted. */
43
+ main: boolean;
44
+ notes: number;
45
+ /** The workspace it was made for, when it was made for one. */
46
+ workspace?: string;
47
+ createdAt: string;
48
+ }
49
+ /** A memory written to a file, to be read back here or on another machine. */
50
+ export interface MemoryExport {
51
+ format: typeof MEMORY_EXPORT_FORMAT;
52
+ version: 1;
53
+ name: string;
54
+ workspace?: string;
55
+ exportedAt: string;
56
+ notes: Array<{
57
+ text: string;
58
+ tags: string[];
59
+ createdAt: string;
60
+ }>;
61
+ }
62
+ export declare const MEMORY_EXPORT_FORMAT = "cerebriline-memory";
63
+ /** A memory is a note, not a document: longer than this belongs in the Library. */
64
+ export declare const MEMORY_MAX_CHARS = 4000;
65
+ export declare const MEMORY_NAME_MAX_CHARS = 60;
66
+ export declare function resolveMemoryDirectory(): string;
67
+ /** A name as it is kept: trimmed, one line, of a length a list can show. */
68
+ export declare function normalizeMemoryName(name: string): string;
69
+ export declare class Memory {
70
+ private readonly library;
71
+ private readonly directory;
72
+ private migrated;
73
+ constructor(options?: LibraryOptions);
74
+ /** Which workspace each memory was made for. Not in the database: it is about the user's folders, not the notes. */
75
+ private get registryPath();
76
+ private readRegistry;
77
+ private writeRegistry;
78
+ /**
79
+ * Bring a store made by the first build to this one's names, once: its
80
+ * `global` collection is the main memory, and each `project:<path>` is a
81
+ * memory named after the folder, made for that workspace.
82
+ */
83
+ private migrate;
84
+ private freeName;
85
+ /** Every memory in the store, the main one first. */
86
+ listMemories(): MemoryInfo[];
87
+ /** Make a memory. A name already taken is refused, not reused. */
88
+ createMemory(input: {
89
+ name: string;
90
+ workspace?: string;
91
+ }): MemoryInfo;
92
+ /**
93
+ * Give a memory another name. Its notes, their ids and their vectors stay
94
+ * as they are. The main memory keeps its name: everything starts on it.
95
+ */
96
+ renameMemory(from: string, to: string): MemoryInfo;
97
+ /** Delete a memory and every note in it. The main memory stays. */
98
+ deleteMemory(name: string): Promise<number>;
99
+ /** The collections of these memories; a name that is not a memory is left out. */
100
+ private collections;
101
+ private toItem;
102
+ /** Keep a note. The same text in the same memory is kept once. */
103
+ remember(input: {
104
+ text: string;
105
+ /** @default the main memory */
106
+ memory?: string;
107
+ tags?: readonly string[];
108
+ /** For an imported note: when it was first noted. */
109
+ createdAt?: string;
110
+ endpoints?: MemoryEndpoints;
111
+ signal?: AbortSignal;
112
+ }): Promise<{
113
+ item: MemoryItem;
114
+ outcome: "added" | "unchanged";
115
+ note?: string;
116
+ }>;
117
+ /** The notes that best match, best first, from the memories named. */
118
+ recall(query: string, options?: {
119
+ /** @default the main memory */
120
+ memories?: readonly string[];
121
+ settings?: MemorySettings;
122
+ endpoints?: MemoryEndpoints;
123
+ limit?: number;
124
+ signal?: AbortSignal;
125
+ }): Promise<{
126
+ items: RecalledMemory[];
127
+ notes: string[];
128
+ }>;
129
+ /** Every note of the memories named, newest first. */
130
+ list(options?: {
131
+ memories?: readonly string[];
132
+ }): MemoryItem[];
133
+ /** Remove a note. False when the memories named hold none with that id. */
134
+ forget(id: string, options?: {
135
+ memories?: readonly string[];
136
+ }): Promise<boolean>;
137
+ /** A memory as a file's content. The notes only: vectors are made again where it is read. */
138
+ exportMemory(name: string): MemoryExport;
139
+ /**
140
+ * Read an exported memory in. Into the memory named, or into one of the
141
+ * file's own name, made if it is not there. A note already there is left
142
+ * alone, so reading the same file twice adds nothing.
143
+ */
144
+ importMemory(data: unknown, options?: {
145
+ into?: string;
146
+ endpoints?: MemoryEndpoints;
147
+ }): Promise<{
148
+ memory: string;
149
+ created: boolean;
150
+ added: number;
151
+ unchanged: number;
152
+ skipped: number;
153
+ }>;
154
+ /** How many notes there are, and how many have vectors for this embedding model. */
155
+ counts(model?: string): {
156
+ notes: number;
157
+ embeddedNotes: number;
158
+ };
159
+ /** Give vectors to every note that has none for this embedding model. */
160
+ embedPending(options: {
161
+ embedding: RetrievalEndpoint;
162
+ onProgress?: (progress: {
163
+ done: number;
164
+ total: number;
165
+ }) => void;
166
+ probe?: boolean;
167
+ signal?: AbortSignal;
168
+ }): Promise<EmbedPendingResult>;
169
+ /** The sets of vectors the notes have, one per embedding model and size. */
170
+ vectorSets(current?: string): Promise<LibraryVectorSet[]>;
171
+ deleteVectorSet(table: string): Promise<boolean>;
172
+ /** Record the vector size a model returned, as a search would. */
173
+ noteDimension(model: string, dimension: number): void;
174
+ /** Whether notes can be found by meaning here now, and if not, why. */
175
+ vectorState(): {
176
+ installed: boolean;
177
+ unsupported?: string;
178
+ };
179
+ close(): Promise<void>;
180
+ }
181
+ /** Closes every Memory this process opened. For shutdown, like `closeSharedLibraries`. */
182
+ export declare function closeSharedMemories(): Promise<void>;
183
+ /** The one Memory of a folder in this process. */
184
+ export declare function sharedMemory(options?: LibraryOptions): Memory;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Retrieval over the Library: keywords, vectors, or both, then a reranker.
3
+ *
4
+ * The shape follows open-webui's, which works well in practice: take
5
+ * candidates from the keyword index and from the vector index, merge the two
6
+ * rankings by weighted reciprocal rank (the "BM25 weight" slides between
7
+ * semantic and lexical), keep the top K, and let a reranking model score
8
+ * those against the query and keep the best few above a threshold.
9
+ *
10
+ * Every stage past the keywords is optional. With no embedding model the
11
+ * search is keywords alone; when an embedder or reranker cannot be reached,
12
+ * the stages that did run still answer and the result says what was skipped.
13
+ */
14
+ import { type RetrievalEndpoint } from "./embedding-client";
15
+ import type { LibraryHit, LibraryStore } from "./library-store";
16
+ import type { VectorSearcher } from "./vector-index";
17
+ export interface RetrieveOptions {
18
+ store: LibraryStore;
19
+ collectionIds?: readonly number[];
20
+ /** Where vectors are searched. Left out, the search is keywords alone. */
21
+ vectors?: VectorSearcher;
22
+ embedding?: RetrievalEndpoint & {
23
+ /** Put in front of the query, for embedders trained with an instruction. */
24
+ queryPrefix?: string;
25
+ };
26
+ reranker?: RetrievalEndpoint & {
27
+ batchSize?: number;
28
+ };
29
+ /**
30
+ * Use the keyword index together with the vectors. Off, a search with
31
+ * vectors available is semantic alone. Default on.
32
+ */
33
+ hybrid?: boolean;
34
+ /** 0 is semantic alone, 1 lexical alone. Default 0.5. */
35
+ bm25Weight?: number;
36
+ /** Also match file names, titles and section headers by keyword. Default on. */
37
+ enrich?: boolean;
38
+ /** Chunks kept after merging. Default 5. */
39
+ topK?: number;
40
+ /** Chunks kept after reranking. Default 3. */
41
+ topKReranker?: number;
42
+ /**
43
+ * Chunks scoring below this are dropped: the reranker's score (0 to 1)
44
+ * when there is one, the cosine similarity of a semantic-only search
45
+ * otherwise. A merged ranking has no score to hold against it. Default 0.
46
+ */
47
+ relevanceThreshold?: number;
48
+ signal?: AbortSignal;
49
+ fetch?: typeof fetch;
50
+ }
51
+ export interface RetrievedHit extends LibraryHit {
52
+ /** Position in the keyword ranking, from 1, when it was found there. */
53
+ keywordRank?: number;
54
+ /** Position in the vector ranking, from 1, when it was found there. */
55
+ vectorRank?: number;
56
+ similarity?: number;
57
+ /** The reranker's score, 0 to 1. */
58
+ rerankScore?: number;
59
+ }
60
+ export interface RetrieveResult {
61
+ hits: RetrievedHit[];
62
+ /** Which rankings the hits came from. */
63
+ mode: "keyword" | "vector" | "hybrid";
64
+ reranked: boolean;
65
+ /** Stages that were asked for and did not run, and why. */
66
+ notes: string[];
67
+ }
68
+ /**
69
+ * Rerankers answer on two scales: a probability, or the raw logit behind it
70
+ * (llama.cpp). Anything outside 0..1 marks the second, and is put through
71
+ * the logistic function so that one threshold means the same on both.
72
+ */
73
+ export declare function normalizeRerankScores(scores: readonly number[]): number[];
74
+ /**
75
+ * Merge rankings by weighted reciprocal rank. Each ranking is a list of ids,
76
+ * best first; the result is the ids with their merged score, best first.
77
+ */
78
+ export declare function fuseRankings(rankings: readonly {
79
+ ids: readonly number[];
80
+ weight: number;
81
+ }[]): {
82
+ id: number;
83
+ score: number;
84
+ }[];
85
+ export declare function retrieve(query: string, options: RetrieveOptions): Promise<RetrieveResult>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A document's running heads: the lines printed on most of its pages, and
3
+ * what they say about which document it is.
4
+ *
5
+ * Text in common says two documents are related, not that one is a version of
6
+ * the other. Measured on a folder of AMD's processor manuals: two Processor
7
+ * Programming References for different processors share 77% of their five-word
8
+ * runs, more than two revisions of one revision guide (68%), because whole
9
+ * register chapters are reused from product to product. No threshold on the
10
+ * text separates them. The running head does: "55803 Rev 0.54 - Sep 12, 2019
11
+ * PPR for AMD Family 17h Model 31h B0" against "56176 Rev 3.06 - Jul 17, 2019
12
+ * PPR for AMD Family 17h Model 71h B0". Between revisions of one document only
13
+ * the revision and the date change; between two documents the number and the
14
+ * subject do.
15
+ *
16
+ * So the head is not stripped as boilerplate: it is read as the document's
17
+ * name. Only its identifying part is compared -- the tokens that carry a
18
+ * digit, once revision numbers and dates are taken out -- because the words
19
+ * around them ("AMD64 Technology", "PPR for AMD Family") are shared by a
20
+ * whole series.
21
+ */
22
+ /**
23
+ * The lines that repeat, word for word, on most pages. A page number printed
24
+ * on the same line makes it differ from page to page, so it drops out; a
25
+ * table heading that recurs is kept, and carries no identity (see below).
26
+ * Empty for a document without pages: an ebook has none to repeat on.
27
+ */
28
+ export declare function runningHeads(markdown: string): string[];
29
+ /** What the running heads say the document is, as sorted tokens; empty if they say nothing. */
30
+ export declare function documentIdentity(heads: readonly string[]): string[];
31
+ /**
32
+ * Whether two documents are the same one by their running heads: true when
33
+ * the identities match, false when both have one and they differ, undefined
34
+ * when either says nothing -- then the text and the title decide, as before.
35
+ */
36
+ export declare function sameDocument(a: readonly string[] | undefined, b: readonly string[] | undefined): boolean | undefined;
37
+ /** The head that names the document, for a message: the first with an identity. */
38
+ export declare function namingHead(heads: readonly string[] | undefined): string | undefined;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Unpacks an npm tarball (gzip over tar) as it streams in, without holding
3
+ * it in memory: the native library the Library downloads is 200 MB and more.
4
+ *
5
+ * Only what npm tarballs contain is handled: regular files and directories,
6
+ * with PAX and GNU long names. Links and devices are skipped. The first path
7
+ * component (`package/`) is dropped, and a path that would leave the target
8
+ * folder is refused.
9
+ */
10
+ /**
11
+ * Unpack the gzipped tar read from `source` into `root`. Resolves with the
12
+ * number of files written.
13
+ */
14
+ export declare function extractTarGz(source: AsyncIterable<Uint8Array>, root: string): Promise<number>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Writes a gzipped tar file by file, without holding it in memory: an export
3
+ * of the Library carries the books' own files, and a shelf of them is large.
4
+ *
5
+ * What `extractTarGz` reads back: regular files, with a PAX record for a name
6
+ * past the header's 100 bytes.
7
+ */
8
+ export interface TarEntry {
9
+ /** The path inside the archive, with forward slashes. */
10
+ name: string;
11
+ /** A file to copy in, */
12
+ path?: string;
13
+ /** or the content itself. */
14
+ data?: string | Uint8Array;
15
+ }
16
+ /**
17
+ * Write `entries` to `target` as a gzipped tar. Resolves with the number of
18
+ * files written.
19
+ */
20
+ export declare function writeTarGz(target: string, entries: Iterable<TarEntry> | AsyncIterable<TarEntry>): Promise<number>;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The Library's vectors, in LanceDB.
3
+ *
4
+ * SQLite holds the text and answers keyword queries; this holds one vector
5
+ * per chunk and answers "what is close to this". The two are joined on the
6
+ * chunk id. Vectors from different embedding models are not comparable, so
7
+ * each model and dimension has a table of its own: changing the model leaves
8
+ * the old vectors where they are and starts a new table.
9
+ */
10
+ import type { LanceDbRuntime } from "./lancedb-runtime";
11
+ export interface VectorRow {
12
+ chunkId: number;
13
+ collectionId: number;
14
+ documentId: number;
15
+ vector: Float32Array;
16
+ }
17
+ export interface VectorHit {
18
+ chunkId: number;
19
+ /** Cosine similarity, 1 for the same direction. */
20
+ similarity: number;
21
+ }
22
+ export interface VectorSearchOptions {
23
+ collectionIds?: readonly number[];
24
+ /** Default 10. */
25
+ limit?: number;
26
+ }
27
+ /** What hybrid retrieval needs from a vector index. */
28
+ export interface VectorSearcher {
29
+ search(model: string, vector: Float32Array, options?: VectorSearchOptions): Promise<VectorHit[]>;
30
+ }
31
+ /**
32
+ * Below this many rows a table is scanned: exact, and fast enough. Above it
33
+ * an approximate index is built, which is what keeps a library of gigabytes
34
+ * answering in milliseconds.
35
+ */
36
+ export declare const VECTOR_INDEX_MIN_ROWS = 50000;
37
+ export declare function vectorTableName(model: string, dimension: number): string;
38
+ export declare class VectorIndex implements VectorSearcher {
39
+ private readonly runtime;
40
+ private readonly db;
41
+ private readonly tables;
42
+ private constructor();
43
+ static open(runtime: LanceDbRuntime, directory: string): Promise<VectorIndex>;
44
+ /** The tables there are, as `{model slug, dimension}` names. */
45
+ tableNames(): Promise<string[]>;
46
+ private table;
47
+ private createTable;
48
+ /**
49
+ * Add vectors. The caller removes a document's old vectors first
50
+ * (`deleteDocuments`): chunk ids are new each time a document is replaced.
51
+ */
52
+ add(model: string, rows: readonly VectorRow[]): Promise<void>;
53
+ search(model: string, vector: Float32Array, options?: VectorSearchOptions): Promise<VectorHit[]>;
54
+ count(model: string, dimension?: number): Promise<number>;
55
+ /**
56
+ * Remove these documents' vectors from one model's table only. For
57
+ * embedding a document again: its vectors for other models are not this
58
+ * run's to touch, and deleting them empties a set the store still counts.
59
+ */
60
+ deleteDocumentsIn(model: string, dimension: number, documentIds: readonly number[]): Promise<void>;
61
+ /** Every set of vectors there is: its table, the size of its vectors, and how many. */
62
+ sets(): Promise<{
63
+ table: string;
64
+ dimension: number;
65
+ rows: number;
66
+ }[]>;
67
+ /** Delete a whole set of vectors. */
68
+ dropSet(table: string): Promise<boolean>;
69
+ /** Remove the vectors of these documents, in every table. */
70
+ deleteDocuments(documentIds: readonly number[]): Promise<void>;
71
+ deleteCollection(collectionId: number): Promise<void>;
72
+ private deleteWhere;
73
+ /**
74
+ * Housekeeping after a large ingest: compact what the adds wrote, and build
75
+ * the approximate index once the table is large enough to need one.
76
+ * Returns whether the table has an index on its vectors afterwards.
77
+ */
78
+ optimize(model: string, dimension: number, options?: {
79
+ minRows?: number;
80
+ }): Promise<boolean>;
81
+ close(): void;
82
+ }
@@ -0,0 +1,248 @@
1
+ /**
2
+ * The engine behind the spec-driven skills.
3
+ *
4
+ * The plan of a piece of software — what is wanted, the milestones, their
5
+ * slices, each slice's tasks, and what was proved along the way — is kept in
6
+ * one SQLite file, `.sdd/sdd.db` in the project. The database is the truth.
7
+ * The markdown beside it is written from it, for people to read and to
8
+ * review in a diff; nothing is read back from those files.
9
+ *
10
+ * Why a database and not the files: a model that keeps its place by reading
11
+ * and ticking markdown has to get every read and every edit right, and a
12
+ * small model does not. Here the order of the work is the engine's. It
13
+ * refuses a step that is out of turn and says why, and `next()` answers
14
+ * "what do I do now" with the one step that is due and everything that step
15
+ * needs.
16
+ *
17
+ * The hierarchy and the order of the phases are those of Get Shit Done
18
+ * (GSD 2, https://getshitdone.help/), which also keeps its state in a
19
+ * database and dispatches each step itself.
20
+ */
21
+ export declare const SDD_DIRECTORY = ".sdd";
22
+ export declare const SDD_DATABASE = "sdd.db";
23
+ export type RequirementStatus = "active" | "validated" | "deferred" | "out_of_scope";
24
+ export type MilestoneStatus = "open" | "complete";
25
+ export type SliceStatus = "pending" | "done";
26
+ export type TaskStatus = "pending" | "in_progress" | "done" | "blocked";
27
+ export type Verdict = "pass" | "needs_remediation";
28
+ export type UatResult = "pass" | "fail" | "needs_human";
29
+ export interface SddRequirement {
30
+ id: string;
31
+ title: string;
32
+ description: string;
33
+ status: RequirementStatus;
34
+ /** The slice that owns it, as `M001/S01`, once a roadmap names one. */
35
+ owner?: string;
36
+ }
37
+ export interface SddMilestone {
38
+ id: string;
39
+ title: string;
40
+ context: string;
41
+ status: MilestoneStatus;
42
+ requirementsApproved: boolean;
43
+ roadmapApproved: boolean;
44
+ verdict?: Verdict;
45
+ validation?: string;
46
+ summary?: string;
47
+ }
48
+ export interface SddSlice {
49
+ milestone: string;
50
+ id: string;
51
+ title: string;
52
+ goal: string;
53
+ demo: string;
54
+ depends: string[];
55
+ status: SliceStatus;
56
+ research?: string;
57
+ summary?: string;
58
+ replans: number;
59
+ uat: {
60
+ check: string;
61
+ result: UatResult;
62
+ note?: string;
63
+ }[];
64
+ }
65
+ export interface SddTask {
66
+ milestone: string;
67
+ slice: string;
68
+ id: string;
69
+ title: string;
70
+ steps: string;
71
+ files: string[];
72
+ verify: string;
73
+ expect?: string;
74
+ status: TaskStatus;
75
+ summary?: string;
76
+ evidence?: string;
77
+ blocker?: string;
78
+ }
79
+ export interface SliceInput {
80
+ title: string;
81
+ goal?: string;
82
+ demo?: string;
83
+ depends?: string[];
84
+ requirements?: string[];
85
+ }
86
+ export interface TaskInput {
87
+ title: string;
88
+ steps: string;
89
+ files?: string[];
90
+ verify: string;
91
+ expect?: string;
92
+ }
93
+ export type SddStep = "discuss_project" | "discuss_milestone" | "approve_requirements" | "plan_milestone" | "approve_roadmap" | "plan_slice" | "execute_task" | "resume_task" | "replan_slice" | "close_slice" | "validate_milestone" | "complete_milestone" | "stuck";
94
+ export interface SddNext {
95
+ step: SddStep;
96
+ /** `M001`, `M001/S01` or `M001/S01/T01`: what the step is about. */
97
+ ref?: string;
98
+ /** Whether the step is the user's to answer, so auto mode stops here. */
99
+ needsUser: boolean;
100
+ /** What to do, with everything the step needs. */
101
+ instruction: string;
102
+ }
103
+ /** A step asked for out of turn, or with something missing. The message says what to do instead. */
104
+ export declare class SddRuleError extends Error {
105
+ constructor(message: string);
106
+ }
107
+ export declare const milestoneId: (n: number) => string;
108
+ export declare const sliceId: (n: number) => string;
109
+ export declare const taskId: (n: number) => string;
110
+ export declare class SddEngine {
111
+ private readonly db;
112
+ /** The `.sdd` folder. */
113
+ readonly directory: string;
114
+ constructor(projectRoot: string);
115
+ close(): void;
116
+ private all;
117
+ private one;
118
+ private run;
119
+ private change;
120
+ project(): {
121
+ name: string;
122
+ description: string;
123
+ agreements: string;
124
+ } | undefined;
125
+ requirements(): SddRequirement[];
126
+ decisions(): {
127
+ id: string;
128
+ title: string;
129
+ choice: string;
130
+ why: string;
131
+ }[];
132
+ knowledge(): string[];
133
+ captures(): string[];
134
+ private toMilestone;
135
+ milestones(): SddMilestone[];
136
+ /** The milestone being worked on: the first that is not complete. */
137
+ activeMilestone(): SddMilestone | undefined;
138
+ private toSlice;
139
+ slices(milestone: string): SddSlice[];
140
+ private toTask;
141
+ tasks(milestone: string, slice: string): SddTask[];
142
+ journal(limit?: number): {
143
+ at: string;
144
+ action: string;
145
+ ref?: string;
146
+ text: string;
147
+ }[];
148
+ private milestoneOf;
149
+ /** `S02`, `M001/S02` or nothing (the slice that is due). */
150
+ private sliceOf;
151
+ private taskOf;
152
+ /** The first slice not done whose dependencies are all done. */
153
+ private dueSlice;
154
+ setProject(input: {
155
+ name?: string;
156
+ description?: string;
157
+ agreements?: string;
158
+ }): void;
159
+ addRequirement(input: {
160
+ title: string;
161
+ description?: string;
162
+ status?: RequirementStatus;
163
+ }): string;
164
+ updateRequirement(id: string, patch: {
165
+ status?: RequirementStatus;
166
+ title?: string;
167
+ description?: string;
168
+ }): void;
169
+ addDecision(input: {
170
+ title: string;
171
+ choice: string;
172
+ why?: string;
173
+ }): string;
174
+ addKnowledge(note: string): void;
175
+ /** A thought that is not for now, kept so it is not lost. */
176
+ capture(note: string): void;
177
+ quick(input: {
178
+ title: string;
179
+ summary: string;
180
+ }): string;
181
+ addMilestone(input: {
182
+ title: string;
183
+ context: string;
184
+ }): string;
185
+ /** Change the open milestone's title or context, when the user changes course. */
186
+ updateMilestone(input: {
187
+ title?: string;
188
+ context?: string;
189
+ }): void;
190
+ /** Record that the user approved the requirements or the roadmap. */
191
+ approve(what: "requirements" | "roadmap"): void;
192
+ private insertSlices;
193
+ /** The roadmap: the milestone cut into slices. Replaces an unapproved roadmap. */
194
+ planMilestone(slices: readonly SliceInput[], ref?: string): string[];
195
+ /** Slices added to an approved roadmap: remediation, or new scope the user agreed to. */
196
+ addSlices(slices: readonly SliceInput[], ref?: string): string[];
197
+ /** Take a slice that has not produced anything off the roadmap. */
198
+ removeSlice(input: {
199
+ slice: string;
200
+ reason: string;
201
+ }): void;
202
+ private insertTasks;
203
+ planSlice(input: {
204
+ slice?: string;
205
+ research?: string;
206
+ tasks: readonly TaskInput[];
207
+ }): string[];
208
+ /** Replace the tasks that are not done, after a blocker or a plan that proved wrong. */
209
+ replanSlice(input: {
210
+ slice?: string;
211
+ reason: string;
212
+ tasks: readonly TaskInput[];
213
+ }): string[];
214
+ private setTask;
215
+ startTask(ref?: string): SddTask;
216
+ completeTask(input: {
217
+ task?: string;
218
+ summary: string;
219
+ evidence: string;
220
+ }): void;
221
+ blockTask(input: {
222
+ task?: string;
223
+ reason: string;
224
+ }): void;
225
+ /** Close a slice: its summary and how its acceptance checks went. */
226
+ completeSlice(input: {
227
+ slice?: string;
228
+ summary: string;
229
+ uat: readonly {
230
+ check: string;
231
+ result: UatResult;
232
+ note?: string;
233
+ }[];
234
+ }): void;
235
+ validateMilestone(input: {
236
+ verdict: Verdict;
237
+ findings: string;
238
+ remediation?: readonly SliceInput[];
239
+ }): string[];
240
+ completeMilestone(summary: string): void;
241
+ next(): SddNext;
242
+ status(): string;
243
+ /**
244
+ * Write the markdown from the database. Called after every change. The
245
+ * files are for reading and for review; nothing reads them back.
246
+ */
247
+ render(): void;
248
+ }