aidimag 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +102 -0
  2. package/README.md +113 -0
  3. package/dist/capture/bootstrap.d.ts +25 -0
  4. package/dist/capture/bootstrap.js +188 -0
  5. package/dist/capture/commit-miner.d.ts +59 -0
  6. package/dist/capture/commit-miner.js +381 -0
  7. package/dist/capture/harvest.d.ts +50 -0
  8. package/dist/capture/harvest.js +207 -0
  9. package/dist/capture/pr-miner.d.ts +57 -0
  10. package/dist/capture/pr-miner.js +185 -0
  11. package/dist/capture/session-briefing.d.ts +36 -0
  12. package/dist/capture/session-briefing.js +150 -0
  13. package/dist/capture/session-extraction.d.ts +23 -0
  14. package/dist/capture/session-extraction.js +54 -0
  15. package/dist/capture/triage.d.ts +30 -0
  16. package/dist/capture/triage.js +108 -0
  17. package/dist/cli/commands/capture.d.ts +5 -0
  18. package/dist/cli/commands/capture.js +357 -0
  19. package/dist/cli/commands/hosts.d.ts +5 -0
  20. package/dist/cli/commands/hosts.js +98 -0
  21. package/dist/cli/commands/knowledge.d.ts +5 -0
  22. package/dist/cli/commands/knowledge.js +121 -0
  23. package/dist/cli/commands/memory.d.ts +6 -0
  24. package/dist/cli/commands/memory.js +392 -0
  25. package/dist/cli/commands/sync.d.ts +5 -0
  26. package/dist/cli/commands/sync.js +307 -0
  27. package/dist/cli/commands/tickets.d.ts +6 -0
  28. package/dist/cli/commands/tickets.js +328 -0
  29. package/dist/cli/commands/verify.d.ts +5 -0
  30. package/dist/cli/commands/verify.js +136 -0
  31. package/dist/cli/index.d.ts +19 -0
  32. package/dist/cli/index.js +46 -0
  33. package/dist/cli/shared.d.ts +37 -0
  34. package/dist/cli/shared.js +175 -0
  35. package/dist/config.d.ts +55 -0
  36. package/dist/config.js +51 -0
  37. package/dist/context/generate.d.ts +24 -0
  38. package/dist/context/generate.js +115 -0
  39. package/dist/critique/critique.d.ts +40 -0
  40. package/dist/critique/critique.js +110 -0
  41. package/dist/db/schema.d.ts +28 -0
  42. package/dist/db/schema.js +269 -0
  43. package/dist/db/store.d.ts +182 -0
  44. package/dist/db/store.js +906 -0
  45. package/dist/debug.d.ts +14 -0
  46. package/dist/debug.js +25 -0
  47. package/dist/embeddings/provider.d.ts +16 -0
  48. package/dist/embeddings/provider.js +100 -0
  49. package/dist/embeddings/search.d.ts +22 -0
  50. package/dist/embeddings/search.js +95 -0
  51. package/dist/index.d.ts +11 -0
  52. package/dist/index.js +12 -0
  53. package/dist/knowledge/chunk.d.ts +9 -0
  54. package/dist/knowledge/chunk.js +78 -0
  55. package/dist/knowledge/extract.d.ts +34 -0
  56. package/dist/knowledge/extract.js +113 -0
  57. package/dist/knowledge/ingest.d.ts +79 -0
  58. package/dist/knowledge/ingest.js +305 -0
  59. package/dist/knowledge/llm.d.ts +21 -0
  60. package/dist/knowledge/llm.js +110 -0
  61. package/dist/mcp/server.d.ts +11 -0
  62. package/dist/mcp/server.js +532 -0
  63. package/dist/security/evidence.d.ts +11 -0
  64. package/dist/security/evidence.js +15 -0
  65. package/dist/security/seal.d.ts +3 -0
  66. package/dist/security/seal.js +28 -0
  67. package/dist/security/sync-push.d.ts +2 -0
  68. package/dist/security/sync-push.js +37 -0
  69. package/dist/security/url.d.ts +6 -0
  70. package/dist/security/url.js +67 -0
  71. package/dist/sync/client.d.ts +84 -0
  72. package/dist/sync/client.js +391 -0
  73. package/dist/sync/server.d.ts +75 -0
  74. package/dist/sync/server.js +659 -0
  75. package/dist/tickets/provider.d.ts +80 -0
  76. package/dist/tickets/provider.js +375 -0
  77. package/dist/types.d.ts +133 -0
  78. package/dist/types.js +5 -0
  79. package/dist/ui/page.d.ts +5 -0
  80. package/dist/ui/page.js +841 -0
  81. package/dist/ui/server.d.ts +10 -0
  82. package/dist/ui/server.js +437 -0
  83. package/dist/verify/check.d.ts +38 -0
  84. package/dist/verify/check.js +121 -0
  85. package/dist/verify/engine.d.ts +39 -0
  86. package/dist/verify/engine.js +178 -0
  87. package/dist/verify/hooks.d.ts +24 -0
  88. package/dist/verify/hooks.js +125 -0
  89. package/dist/verify/runners.d.ts +26 -0
  90. package/dist/verify/runners.js +193 -0
  91. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,102 @@
1
+ Elastic License 2.0
2
+
3
+ Copyright (c) 2025 Anup Khanal
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable,
12
+ non-transferable license to use, copy, distribute, make available, and prepare
13
+ derivative works of the software, in each case subject to the limitations and
14
+ conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed service,
19
+ where the service provides users with access to any substantial set of the features
20
+ or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality in
23
+ the software, and you may not remove or obscure any functionality in the software
24
+ that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor's trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Additional Use Grant: Small Team License
31
+
32
+ **Free for organizations with 10 or fewer total employees/users.**
33
+
34
+ If your organization has more than 10 employees or users (including all affiliates
35
+ and entities under common control), you must obtain a commercial license from the
36
+ licensor. Contact: https://github.com/anupkhanal/aidimag/issues (commercial licensing inquiries)
37
+
38
+ For determining the user count, "users" includes anyone who:
39
+ - Runs commands using the software
40
+ - Uses AI agents connected to the software
41
+ - Accesses dashboards or IDE extensions provided by the software
42
+
43
+ ## Patents
44
+
45
+ The licensor grants you a license, under any patent claims the licensor can license,
46
+ or becomes able to license, to make, have made, use, sell, offer for sale, import
47
+ and have imported the software, in each case subject to the limitations and conditions
48
+ in this license. This license does not cover any patent claims that you cause to be
49
+ infringed by modifications or additions to the software. If you or your company make
50
+ any written claim that the software infringes or contributes to infringement of any
51
+ patent, your patent license for the software granted under these terms ends immediately.
52
+ If your company makes such a claim, your patent license ends immediately for work on
53
+ behalf of your company.
54
+
55
+ ## Notices
56
+
57
+ You must ensure that anyone who gets a copy of any part of the software from you also
58
+ gets a copy of these terms.
59
+
60
+ If you modify the software, you must include in any modified copies of the software
61
+ prominent notices stating that you have modified the software.
62
+
63
+ ## No Other Rights
64
+
65
+ These terms do not imply any licenses other than those expressly granted in these terms.
66
+
67
+ ## Termination
68
+
69
+ If you use the software in violation of these terms, such use is not licensed, and
70
+ your licenses will automatically terminate. If the licensor provides you with a notice
71
+ of your violation, and you cease all violation of this license no later than 30 days
72
+ after you receive that notice, your licenses will be reinstated retroactively. However,
73
+ if you violate these terms after such reinstatement, any additional violation of these
74
+ terms will cause your licenses to terminate automatically and permanently.
75
+
76
+ ## No Liability
77
+
78
+ **As far as the law allows, the software comes as is, without any warranty or condition,
79
+ and the licensor will not be liable to you for any damages arising out of these terms
80
+ or the use or nature of the software, under any kind of legal claim.**
81
+
82
+ ## Definitions
83
+
84
+ The **licensor** is Anup Khanal.
85
+
86
+ The **software** is the software the licensor makes available under these terms,
87
+ including any portion of it.
88
+
89
+ **You** refers to the individual or entity agreeing to these terms.
90
+
91
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization
92
+ that you work for, plus all organizations that have control over, are under the control
93
+ of, or are under common control with that organization. **Control** means ownership of
94
+ substantially all the assets of an entity, or the power to direct its management and
95
+ policies by vote, contract, or otherwise. Control can be direct or indirect.
96
+
97
+ **Your licenses** are all the licenses granted to you for the software under these terms.
98
+
99
+ **Use** means anything you do with the software requiring one of your licenses.
100
+
101
+ **Trademark** means trademarks, service marks, and similar rights.
102
+
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # aiDimag
2
+
3
+ > Persistent, verified memory for AI coding agents. CLI: **`dim`**.
4
+
5
+ aiDimag gives any MCP-compatible agent (Claude Code, Cursor, Copilot, …) a memory of your
6
+ codebase that survives across sessions — decisions, conventions, gotchas, failed approaches,
7
+ **guardrails**, and reusable **skills** — stored as **falsifiable claims with grounding
8
+ evidence** in `.aidimag/` next to your code. It also generates the static context files
9
+ (`CLAUDE.md`, `.cursorrules`, …) that *non-MCP* tools read, so every AI tool benefits.
10
+
11
+ What makes it different: **memories are verified, not just stored.** Every memory carries
12
+ evidence (a shell check, an anchored commit, a test) that `dim verify` re-runs against the
13
+ current repo — beliefs that stop being true go **STALE** instead of silently misleading
14
+ your AI.
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ npm install -g aidimag
20
+ ```
21
+
22
+ Requires Node 18+. Ships two equivalent binaries: `dim` (short) and `aidimag`.
23
+
24
+ ## Quick start
25
+
26
+ ```sh
27
+ cd your-repo
28
+ dim init # creates .aidimag/, installs additive git hooks
29
+ dim bootstrap # optional: LLM-survey the repo into a starter memory set
30
+ dim review # approve what enters memory (nothing is stored unreviewed)
31
+
32
+ dim remember "All DB access goes through src/db/store.ts" -k INVARIANT -p src/db \
33
+ -e "STATIC_CHECK:grep -rL better-sqlite3 src --include=*.ts"
34
+ dim recall db access
35
+ dim verify # re-run all evidence; stale beliefs get flagged
36
+ dim brief # session-start briefing: in-scope memory, guardrails, gaps
37
+
38
+ # For non-MCP tools (Copilot, Cursor without MCP, etc.):
39
+ dim generate-context --format all --auto # creates .cursorrules, CLAUDE.md, copilot-instructions.md
40
+ ```
41
+
42
+ ## Hook it up to your AI agent (MCP)
43
+
44
+ Add to your agent config (e.g. `.mcp.json` for Claude Code):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "aidimag": {
50
+ "command": "npx",
51
+ "args": ["-y", "aidimag", "mcp"],
52
+ "env": { "AIDIMAG_REPO": "/path/to/your/repo" }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ Agents get `memory_search`, `memory_propose`, `context_note` (live in-chat fact capture),
59
+ `memory_critique` (a second critic grounded in verified memory), session-start briefings,
60
+ session-end extraction, and more. For non-MCP tools, `dim generate-context -f all` renders
61
+ verified memory into `CLAUDE.md` / `.cursorrules` / `.github/copilot-instructions.md`
62
+ (`--auto` keeps them refreshed).
63
+
64
+ ## Highlights
65
+
66
+ - **Human-gated capture** — commits, PRs, AI-chat transcripts, and pasted docs are mined
67
+ into *proposals*; nothing enters memory until you approve it in `dim review`
68
+ (auto-triaged best-first, `approve all --min-score 0.7` for batches).
69
+ - **Verification lifecycle** — `STATIC_CHECK` / `COMMIT_REF` / `TEST_RESULT` /
70
+ `EXEC_TRACE` / `HUMAN_ATTESTED` evidence; failing evidence flips memories to STALE and
71
+ auto-drafts a recovery proposal. Confidence decays without re-confirmation.
72
+ - **Evidence trust gate** — shell-command evidence that arrives via team sync is **never
73
+ executed** until you inspect and approve it (`dim verify --trust`).
74
+ - **Hybrid semantic recall** — FTS5 keyword + vector KNN (OpenAI or local Ollama,
75
+ auto-detected; works keyword-only with neither).
76
+ - **Guardrails & skills** — behavioral rules (`never` / `ask-first` / `always`) and
77
+ step-by-step procedures, enforced by `dim check` (pre-commit) and `memory_critique`.
78
+ - **Team mode, self-hosted** — `dim serve` + `dim sync`: local-first replicas, device-code
79
+ login, brain-scoped API keys, hashed credentials, cross-machine verification consensus.
80
+ - **Knowledgebase inbox** — drop design docs / ADRs / PDFs / DOCX into `knowledge/` and
81
+ they're summarized into reviewed, pinned memories.
82
+ - **Web dashboard** (`dim ui`) plus [VS Code](https://github.com/anupkhanal/aidimag/tree/main/vscode-extension) and
83
+ [IntelliJ](https://github.com/anupkhanal/aidimag/tree/main/intellij-plugin) extensions.
84
+
85
+ ## Documentation
86
+
87
+ Full documentation available at: **[github.com/anupkhanal/aidimag](https://github.com/anupkhanal/aidimag)**
88
+
89
+ - [Getting Started](https://github.com/anupkhanal/aidimag/blob/main/docs/getting-started.md)
90
+ - [Quick Start](https://github.com/anupkhanal/aidimag/blob/main/docs/quickstart.md)
91
+ - [CLI Reference](https://github.com/anupkhanal/aidimag/blob/main/docs/cli-reference.md)
92
+ - [MCP Integration](https://github.com/anupkhanal/aidimag/blob/main/docs/mcp.md)
93
+ - [Team Sync Guide](https://github.com/anupkhanal/aidimag/blob/main/docs/guides/team-sync.md)
94
+ - [Configuration](https://github.com/anupkhanal/aidimag/blob/main/docs/configuration.md)
95
+
96
+ ## Development
97
+
98
+ ```sh
99
+ npm install
100
+ npm run build # tsc → dist/
101
+ npm test # node --test (builds first)
102
+ ```
103
+
104
+ Self-hosted sync deployment (Docker / Fly.io): [deploy/](https://github.com/anupkhanal/aidimag/tree/main/deploy).
105
+
106
+ ## Author
107
+
108
+ **Anup Khanal**
109
+
110
+ ## License
111
+
112
+ [Elastic License 2.0](./LICENSE) — free for teams of 10 or fewer users. Commercial license required for larger organizations. Cannot be offered as a managed service to third parties. See [pricing & licensing](docs/pricing.md) for details.
113
+
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `dim bootstrap` — instant brain on day one (kills the cold-start problem).
3
+ *
4
+ * Surveys the repo (README/docs/ADRs, manifests, directory shape, git churn)
5
+ * and LLM-extracts an initial set of falsifiable memory candidates, each with
6
+ * a suggested STATIC_CHECK where one makes sense. Everything lands in the
7
+ * proposal queue (source `bootstrap`) — `dim review` remains the trust gate.
8
+ */
9
+ import type { MemoryStore } from "../db/store.js";
10
+ export interface BootstrapResult {
11
+ proposed: number;
12
+ duplicates: number;
13
+ provider: string | null;
14
+ surveyedFiles: string[];
15
+ alreadyBootstrapped: boolean;
16
+ }
17
+ /** Top-level directory listing, two levels deep — enough shape without noise. */
18
+ export declare function surveyTree(repoRoot: string): string;
19
+ /** Most-changed files in recent history — where the action (and the gotchas) live. */
20
+ export declare function surveyChurn(repoRoot: string, maxCommits?: number, top?: number): string;
21
+ export declare const BOOTSTRAP_INSTRUCTIONS = "You are bootstrapping a \"repo brain\" for an AI coding assistant memory system. Below is a survey of a codebase: its docs, manifests, directory shape, and most-changed files.\n\nExtract the durable, project-specific knowledge as FALSIFIABLE claims. Rules:\n\n1. Only facts THIS survey supports \u2014 architecture, conventions, decisions, invariants, build/deploy procedures (SKILL), behavioral rules (GUARDRAIL with guardrail_level never|ask-first|always). Do NOT invent or pad; skip anything generic (\"uses TypeScript\" is useless unless there's a rule attached).\n2. Write each claim as a checkable statement scoped with paths when the survey names them.\n3. Where possible, include \"static_check\": a cheap shell command (grep/test/ls) that exits 0 iff the claim holds. Omit it when no honest check exists.\n4. kinds: DECISION, CONVENTION, GOTCHA, FAILED_APPROACH, ARCHITECTURE, INVARIANT, GUARDRAIL, SKILL, TODO_CONTEXT.\n5. Extract 5\u201330 claims depending on how much real signal exists. Quality over quantity.\n\nRespond with ONLY a JSON object:\n{\"claims\":[{\"kind\":\"ARCHITECTURE\",\"claim\":\"...\",\"paths\":[\"src/x\"],\"symbols\":[],\"guardrail_level\":null,\"rationale\":\"from README section ...\",\"static_check\":\"test -f src/x/index.ts\"}]}";
22
+ /** Turn a repo survey into an initial proposal set. */
23
+ export declare function bootstrapRepo(store: MemoryStore, repoRoot: string, opts?: {
24
+ force?: boolean;
25
+ }): Promise<BootstrapResult>;
@@ -0,0 +1,188 @@
1
+ /**
2
+ * `dim bootstrap` — instant brain on day one (kills the cold-start problem).
3
+ *
4
+ * Surveys the repo (README/docs/ADRs, manifests, directory shape, git churn)
5
+ * and LLM-extracts an initial set of falsifiable memory candidates, each with
6
+ * a suggested STATIC_CHECK where one makes sense. Everything lands in the
7
+ * proposal queue (source `bootstrap`) — `dim review` remains the trust gate.
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
11
+ import path from "node:path";
12
+ import { getTextProvider } from "../knowledge/llm.js";
13
+ import { parseClaims } from "../knowledge/extract.js";
14
+ const BOOTSTRAP_DONE_KEY = "bootstrap_done_at";
15
+ const MAX_DOC_CHARS = 12_000;
16
+ const MAX_TOTAL_CHARS = 48_000;
17
+ /** Files worth reading whole (truncated) for the survey. */
18
+ const DOC_CANDIDATES = [
19
+ "README.md", "readme.md", "ARCHITECTURE.md", "DESIGN.md", "CONTRIBUTING.md",
20
+ "docs/architecture.md", "docs/adr", "adr", "docs/decisions",
21
+ ];
22
+ const MANIFEST_CANDIDATES = [
23
+ "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "pom.xml",
24
+ "build.gradle", "build.gradle.kts", "Gemfile", "composer.json", "Makefile",
25
+ "docker-compose.yml", "Dockerfile", ".github/workflows",
26
+ ];
27
+ function git(repoRoot, args) {
28
+ try {
29
+ return execFileSync("git", args, { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
30
+ }
31
+ catch {
32
+ return "";
33
+ }
34
+ }
35
+ function readCapped(abs) {
36
+ try {
37
+ return readFileSync(abs, "utf8").slice(0, MAX_DOC_CHARS);
38
+ }
39
+ catch {
40
+ return "";
41
+ }
42
+ }
43
+ /** Top-level directory listing, two levels deep — enough shape without noise. */
44
+ export function surveyTree(repoRoot) {
45
+ const lines = [];
46
+ const skip = new Set(["node_modules", ".git", "dist", "build", ".aidimag", "coverage", "target", ".idea", ".vscode"]);
47
+ const walk = (dir, depth, prefix) => {
48
+ if (depth > 2)
49
+ return;
50
+ let entries;
51
+ try {
52
+ entries = readdirSync(dir).filter((e) => !skip.has(e) && !e.startsWith("."));
53
+ }
54
+ catch {
55
+ return;
56
+ }
57
+ for (const e of entries.slice(0, 30)) {
58
+ const abs = path.join(dir, e);
59
+ let isDir = false;
60
+ try {
61
+ isDir = statSync(abs).isDirectory();
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ lines.push(`${prefix}${e}${isDir ? "/" : ""}`);
67
+ if (isDir)
68
+ walk(abs, depth + 1, prefix + " ");
69
+ }
70
+ };
71
+ walk(repoRoot, 1, "");
72
+ return lines.join("\n");
73
+ }
74
+ /** Most-changed files in recent history — where the action (and the gotchas) live. */
75
+ export function surveyChurn(repoRoot, maxCommits = 300, top = 15) {
76
+ const raw = git(repoRoot, ["log", `--max-count=${maxCommits}`, "--name-only", "--pretty=format:"]);
77
+ const counts = new Map();
78
+ for (const f of raw.split("\n").map((l) => l.trim()).filter(Boolean)) {
79
+ counts.set(f, (counts.get(f) ?? 0) + 1);
80
+ }
81
+ return [...counts.entries()]
82
+ .sort((a, b) => b[1] - a[1])
83
+ .slice(0, top)
84
+ .map(([f, n]) => `${n}× ${f}`)
85
+ .join("\n");
86
+ }
87
+ function collectDocs(repoRoot) {
88
+ const out = [];
89
+ for (const cand of DOC_CANDIDATES) {
90
+ const abs = path.join(repoRoot, cand);
91
+ if (!existsSync(abs))
92
+ continue;
93
+ if (statSync(abs).isDirectory()) {
94
+ for (const f of readdirSync(abs).filter((f) => f.endsWith(".md")).slice(0, 5)) {
95
+ out.push({ file: path.join(cand, f), content: readCapped(path.join(abs, f)) });
96
+ }
97
+ }
98
+ else {
99
+ out.push({ file: cand, content: readCapped(abs) });
100
+ }
101
+ }
102
+ for (const cand of MANIFEST_CANDIDATES) {
103
+ const abs = path.join(repoRoot, cand);
104
+ if (!existsSync(abs) || statSync(abs).isDirectory())
105
+ continue;
106
+ out.push({ file: cand, content: readCapped(abs).slice(0, 4_000) });
107
+ }
108
+ // existing hand-written AI context files are pre-distilled knowledge — gold
109
+ for (const cand of ["CLAUDE.md", ".cursorrules", ".github/copilot-instructions.md"]) {
110
+ const abs = path.join(repoRoot, cand);
111
+ if (existsSync(abs) && !statSync(abs).isDirectory())
112
+ out.push({ file: cand, content: readCapped(abs) });
113
+ }
114
+ return out;
115
+ }
116
+ export const BOOTSTRAP_INSTRUCTIONS = `You are bootstrapping a "repo brain" for an AI coding assistant memory system. Below is a survey of a codebase: its docs, manifests, directory shape, and most-changed files.
117
+
118
+ Extract the durable, project-specific knowledge as FALSIFIABLE claims. Rules:
119
+
120
+ 1. Only facts THIS survey supports — architecture, conventions, decisions, invariants, build/deploy procedures (SKILL), behavioral rules (GUARDRAIL with guardrail_level never|ask-first|always). Do NOT invent or pad; skip anything generic ("uses TypeScript" is useless unless there's a rule attached).
121
+ 2. Write each claim as a checkable statement scoped with paths when the survey names them.
122
+ 3. Where possible, include "static_check": a cheap shell command (grep/test/ls) that exits 0 iff the claim holds. Omit it when no honest check exists.
123
+ 4. kinds: DECISION, CONVENTION, GOTCHA, FAILED_APPROACH, ARCHITECTURE, INVARIANT, GUARDRAIL, SKILL, TODO_CONTEXT.
124
+ 5. Extract 5–30 claims depending on how much real signal exists. Quality over quantity.
125
+
126
+ Respond with ONLY a JSON object:
127
+ {"claims":[{"kind":"ARCHITECTURE","claim":"...","paths":["src/x"],"symbols":[],"guardrail_level":null,"rationale":"from README section ...","static_check":"test -f src/x/index.ts"}]}`;
128
+ /** Turn a repo survey into an initial proposal set. */
129
+ export async function bootstrapRepo(store, repoRoot, opts = {}) {
130
+ const result = {
131
+ proposed: 0,
132
+ duplicates: 0,
133
+ provider: null,
134
+ surveyedFiles: [],
135
+ alreadyBootstrapped: false,
136
+ };
137
+ if (!opts.force && store.getMeta(BOOTSTRAP_DONE_KEY)) {
138
+ result.alreadyBootstrapped = true;
139
+ return result;
140
+ }
141
+ const provider = await getTextProvider();
142
+ if (!provider)
143
+ return result;
144
+ result.provider = `${provider.name}/${provider.model}`;
145
+ const docs = collectDocs(repoRoot);
146
+ result.surveyedFiles = docs.map((d) => d.file);
147
+ const sections = [];
148
+ sections.push(`## Directory shape\n${surveyTree(repoRoot)}`);
149
+ const churn = surveyChurn(repoRoot);
150
+ if (churn)
151
+ sections.push(`## Most-changed files (recent history)\n${churn}`);
152
+ for (const d of docs) {
153
+ if (sections.join("\n").length > MAX_TOTAL_CHARS)
154
+ break;
155
+ sections.push(`## File: ${d.file}\n${d.content}`);
156
+ }
157
+ let claims = [];
158
+ try {
159
+ const raw = await provider.generate(BOOTSTRAP_INSTRUCTIONS, sections.join("\n\n").slice(0, MAX_TOTAL_CHARS));
160
+ claims = parseClaims(raw);
161
+ }
162
+ catch {
163
+ return result; // provider hiccup — bootstrap can simply be re-run
164
+ }
165
+ for (const c of claims) {
166
+ const evidence = [];
167
+ if (c.staticCheck)
168
+ evidence.push({ type: "STATIC_CHECK", payload: c.staticCheck });
169
+ const p = store.propose({
170
+ kind: c.kind,
171
+ claim: c.claim,
172
+ paths: c.paths,
173
+ symbols: c.symbols,
174
+ guardrailLevel: c.guardrailLevel,
175
+ evidence: evidence.length ? evidence : undefined,
176
+ rationale: c.rationale ?? "Extracted by repo bootstrap survey.",
177
+ source: "bootstrap",
178
+ sourceRef: "initial-survey",
179
+ });
180
+ if (p)
181
+ result.proposed++;
182
+ else
183
+ result.duplicates++;
184
+ }
185
+ store.setMeta(BOOTSTRAP_DONE_KEY, new Date().toISOString());
186
+ return result;
187
+ }
188
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Commit miner (Phase 2 capture pipeline).
3
+ *
4
+ * Walks git history since the last mined commit and heuristically extracts
5
+ * memory-worthy candidates from commit messages + touched files. Candidates
6
+ * land in the proposal queue (human-in-the-loop) — never directly in memory.
7
+ *
8
+ * Each proposal is anchored with COMMIT_REF evidence so Phase 3 verification
9
+ * can re-check it against history.
10
+ */
11
+ import type { MemoryKind, Proposal } from "../types.js";
12
+ import type { MemoryStore } from "../db/store.js";
13
+ export interface MinedCommit {
14
+ sha: string;
15
+ subject: string;
16
+ body: string;
17
+ files: string[];
18
+ }
19
+ export interface MineResult {
20
+ scanned: number;
21
+ proposed: Proposal[];
22
+ skippedDuplicates: number;
23
+ lastSha: string | null;
24
+ /** True when the repo is a git repo but has no commits yet (HEAD does not exist). */
25
+ noCommits?: boolean;
26
+ /** True when incremental mining found no commits newer than the stored cursor. */
27
+ noNewCommits?: boolean;
28
+ }
29
+ /** False when the repo is initialized but has no commits yet (no HEAD). */
30
+ export declare function hasGitCommits(repoRoot: string): boolean;
31
+ export declare function readCommits(repoRoot: string, sinceSha: string | null, maxCommits?: number): MinedCommit[];
32
+ export declare function classifyCommit(c: MinedCommit): {
33
+ kind: MemoryKind;
34
+ matched: string;
35
+ } | null;
36
+ /** Reduce touched files to a few representative scope paths (common directories). */
37
+ export declare function scopeFromFiles(files: string[], maxPaths?: number): string[];
38
+ export declare function mineCommits(store: MemoryStore, repoRoot: string, opts?: {
39
+ maxCommits?: number;
40
+ full?: boolean;
41
+ }): MineResult;
42
+ export declare const COMMIT_EXTRACT_INSTRUCTIONS = "You are mining a git commit for durable, project-specific knowledge worth remembering across AI coding sessions: decisions (and rejected alternatives), conventions, gotchas, failed approaches, invariants, architecture facts.\n\nRules:\n1. Most commits contain NOTHING durable \u2014 routine features/fixes/refactors. Return zero claims for those. Do NOT invent.\n2. When there IS signal, SYNTHESIZE a falsifiable claim about the codebase \u2014 do not parrot the commit message. Bad: \"A decision was made: use Redis\". Good: \"Rate limiting uses Redis (src/limits); the in-memory limiter was abandoned because multi-instance deploys need shared counters\".\n3. Use the DIFF, not just the message \u2014 renamed modules, deleted approaches, and added config tell the real story.\n4. kinds: DECISION, CONVENTION, GOTCHA, FAILED_APPROACH, ARCHITECTURE, INVARIANT, GUARDRAIL (guardrail_level never|ask-first|always), SKILL, TODO_CONTEXT.\n5. Scope with the touched paths; add \"static_check\" (cheap shell command, exit 0 iff true) when an honest one exists.\n6. 0\u20132 claims per commit. Zero is the common case.\n\nRespond with ONLY: {\"claims\":[{\"kind\":\"DECISION\",\"claim\":\"...\",\"paths\":[\"src/x\"],\"symbols\":[],\"guardrail_level\":null,\"rationale\":\"...\",\"static_check\":null}]}";
43
+ /**
44
+ * LLM-powered deep mining: reads message + diff, synthesizes claims with
45
+ * suggested STATIC_CHECKs. Requires a text provider (OpenAI/Ollama); the
46
+ * caller falls back to regex mining when none is available. Same cursor as
47
+ * regex mining — the two modes are alternatives over the same history.
48
+ */
49
+ export declare function mineCommitsLlm(store: MemoryStore, repoRoot: string, opts?: {
50
+ maxCommits?: number;
51
+ full?: boolean;
52
+ }): Promise<MineResult & {
53
+ provider: string | null;
54
+ }>;
55
+ /** Human-readable summary of a mine run (CLI + MCP). */
56
+ export declare function describeMineResult(r: MineResult, opts?: {
57
+ llmProvider?: string | null;
58
+ llmRequested?: boolean;
59
+ }): string;