engrm 0.1.0 → 0.2.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 (98) hide show
  1. package/README.md +214 -73
  2. package/bin/build.mjs +97 -0
  3. package/bin/engrm.mjs +13 -0
  4. package/dist/cli.js +2712 -0
  5. package/dist/hooks/elicitation-result.js +1786 -0
  6. package/dist/hooks/post-tool-use.js +2357 -0
  7. package/dist/hooks/pre-compact.js +1321 -0
  8. package/dist/hooks/sentinel.js +1168 -0
  9. package/dist/hooks/session-start.js +1473 -0
  10. package/dist/hooks/stop.js +1834 -0
  11. package/dist/server.js +16628 -0
  12. package/package.json +29 -4
  13. package/packs/api-best-practices.json +182 -0
  14. package/packs/nextjs-patterns.json +68 -0
  15. package/packs/node-security.json +68 -0
  16. package/packs/python-django.json +68 -0
  17. package/packs/react-gotchas.json +182 -0
  18. package/packs/typescript-patterns.json +67 -0
  19. package/packs/web-security.json +182 -0
  20. package/.mcp.json +0 -9
  21. package/AUTH-DESIGN.md +0 -436
  22. package/BRIEF.md +0 -197
  23. package/CLAUDE.md +0 -44
  24. package/COMPETITIVE.md +0 -174
  25. package/CONTEXT-OPTIMIZATION.md +0 -305
  26. package/INFRASTRUCTURE.md +0 -252
  27. package/MARKET.md +0 -230
  28. package/PLAN.md +0 -278
  29. package/SENTINEL.md +0 -293
  30. package/SERVER-API-PLAN.md +0 -553
  31. package/SPEC.md +0 -843
  32. package/SWOT.md +0 -148
  33. package/SYNC-ARCHITECTURE.md +0 -294
  34. package/VIBE-CODER-STRATEGY.md +0 -250
  35. package/bun.lock +0 -375
  36. package/hooks/post-tool-use.ts +0 -144
  37. package/hooks/session-start.ts +0 -64
  38. package/hooks/stop.ts +0 -131
  39. package/mem-page.html +0 -1305
  40. package/src/capture/dedup.test.ts +0 -103
  41. package/src/capture/dedup.ts +0 -76
  42. package/src/capture/extractor.test.ts +0 -245
  43. package/src/capture/extractor.ts +0 -330
  44. package/src/capture/quality.test.ts +0 -168
  45. package/src/capture/quality.ts +0 -104
  46. package/src/capture/retrospective.test.ts +0 -115
  47. package/src/capture/retrospective.ts +0 -121
  48. package/src/capture/scanner.test.ts +0 -131
  49. package/src/capture/scanner.ts +0 -100
  50. package/src/capture/scrubber.test.ts +0 -144
  51. package/src/capture/scrubber.ts +0 -181
  52. package/src/cli.ts +0 -517
  53. package/src/config.ts +0 -238
  54. package/src/context/inject.test.ts +0 -940
  55. package/src/context/inject.ts +0 -382
  56. package/src/embeddings/backfill.ts +0 -50
  57. package/src/embeddings/embedder.test.ts +0 -76
  58. package/src/embeddings/embedder.ts +0 -139
  59. package/src/lifecycle/aging.test.ts +0 -103
  60. package/src/lifecycle/aging.ts +0 -36
  61. package/src/lifecycle/compaction.test.ts +0 -264
  62. package/src/lifecycle/compaction.ts +0 -190
  63. package/src/lifecycle/purge.test.ts +0 -100
  64. package/src/lifecycle/purge.ts +0 -37
  65. package/src/lifecycle/scheduler.test.ts +0 -120
  66. package/src/lifecycle/scheduler.ts +0 -101
  67. package/src/provisioning/browser-auth.ts +0 -172
  68. package/src/provisioning/provision.test.ts +0 -198
  69. package/src/provisioning/provision.ts +0 -94
  70. package/src/register.test.ts +0 -167
  71. package/src/register.ts +0 -178
  72. package/src/server.ts +0 -436
  73. package/src/storage/migrations.test.ts +0 -244
  74. package/src/storage/migrations.ts +0 -261
  75. package/src/storage/outbox.test.ts +0 -229
  76. package/src/storage/outbox.ts +0 -131
  77. package/src/storage/projects.test.ts +0 -137
  78. package/src/storage/projects.ts +0 -184
  79. package/src/storage/sqlite.test.ts +0 -798
  80. package/src/storage/sqlite.ts +0 -934
  81. package/src/storage/vec.test.ts +0 -198
  82. package/src/sync/auth.test.ts +0 -76
  83. package/src/sync/auth.ts +0 -68
  84. package/src/sync/client.ts +0 -183
  85. package/src/sync/engine.test.ts +0 -94
  86. package/src/sync/engine.ts +0 -127
  87. package/src/sync/pull.test.ts +0 -279
  88. package/src/sync/pull.ts +0 -170
  89. package/src/sync/push.test.ts +0 -117
  90. package/src/sync/push.ts +0 -230
  91. package/src/tools/get.ts +0 -34
  92. package/src/tools/pin.ts +0 -47
  93. package/src/tools/save.test.ts +0 -301
  94. package/src/tools/save.ts +0 -231
  95. package/src/tools/search.test.ts +0 -69
  96. package/src/tools/search.ts +0 -181
  97. package/src/tools/timeline.ts +0 -64
  98. package/tsconfig.json +0 -22
package/src/config.ts DELETED
@@ -1,238 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { homedir, hostname } from "node:os";
3
- import { join } from "node:path";
4
- import { randomBytes } from "node:crypto";
5
-
6
- // --- Types ---
7
-
8
- export interface SyncConfig {
9
- enabled: boolean;
10
- interval_seconds: number;
11
- batch_size: number;
12
- }
13
-
14
- export interface SearchConfig {
15
- default_limit: number;
16
- local_boost: number;
17
- scope: "personal" | "team" | "all";
18
- }
19
-
20
- export interface ScrubbingConfig {
21
- enabled: boolean;
22
- custom_patterns: string[];
23
- default_sensitivity: "shared" | "personal" | "secret";
24
- }
25
-
26
- export interface TeamMembership {
27
- id: string;
28
- name: string;
29
- namespace: string;
30
- }
31
-
32
- export interface Config {
33
- candengo_url: string;
34
- candengo_api_key: string;
35
- site_id: string;
36
- namespace: string;
37
- user_id: string;
38
- user_email: string;
39
- device_id: string;
40
- teams: TeamMembership[];
41
- sync: SyncConfig;
42
- search: SearchConfig;
43
- scrubbing: ScrubbingConfig;
44
- }
45
-
46
- // --- Paths ---
47
-
48
- const CONFIG_DIR = join(homedir(), ".engrm");
49
- const SETTINGS_PATH = join(CONFIG_DIR, "settings.json");
50
- const DB_PATH = join(CONFIG_DIR, "engrm.db");
51
-
52
- export function getConfigDir(): string {
53
- return CONFIG_DIR;
54
- }
55
-
56
- export function getSettingsPath(): string {
57
- return SETTINGS_PATH;
58
- }
59
-
60
- export function getDbPath(): string {
61
- return DB_PATH;
62
- }
63
-
64
- // --- Device ID ---
65
-
66
- function generateDeviceId(): string {
67
- const host = hostname().toLowerCase().replace(/[^a-z0-9-]/g, "");
68
- const suffix = randomBytes(4).toString("hex");
69
- return `${host}-${suffix}`;
70
- }
71
-
72
- // --- Defaults ---
73
-
74
- function createDefaultConfig(): Config {
75
- return {
76
- candengo_url: "",
77
- candengo_api_key: "",
78
- site_id: "",
79
- namespace: "",
80
- user_id: "",
81
- user_email: "",
82
- device_id: generateDeviceId(),
83
- teams: [],
84
- sync: {
85
- enabled: true,
86
- interval_seconds: 30,
87
- batch_size: 50,
88
- },
89
- search: {
90
- default_limit: 10,
91
- local_boost: 1.2,
92
- scope: "all",
93
- },
94
- scrubbing: {
95
- enabled: true,
96
- custom_patterns: [],
97
- default_sensitivity: "shared",
98
- },
99
- };
100
- }
101
-
102
- // --- Load / Save ---
103
-
104
- export function loadConfig(): Config {
105
- if (!existsSync(SETTINGS_PATH)) {
106
- throw new Error(
107
- `Config not found at ${SETTINGS_PATH}. Run 'engrm init --manual' to configure.`
108
- );
109
- }
110
-
111
- const raw = readFileSync(SETTINGS_PATH, "utf-8");
112
- let parsed: unknown;
113
- try {
114
- parsed = JSON.parse(raw);
115
- } catch {
116
- throw new Error(`Invalid JSON in ${SETTINGS_PATH}`);
117
- }
118
-
119
- if (typeof parsed !== "object" || parsed === null) {
120
- throw new Error(`Config at ${SETTINGS_PATH} is not a JSON object`);
121
- }
122
-
123
- const config = parsed as Record<string, unknown>;
124
-
125
- // Merge with defaults to fill any missing fields
126
- const defaults = createDefaultConfig();
127
- return {
128
- candengo_url: asString(config["candengo_url"], defaults.candengo_url),
129
- candengo_api_key: asString(config["candengo_api_key"], defaults.candengo_api_key),
130
- site_id: asString(config["site_id"], defaults.site_id),
131
- namespace: asString(config["namespace"], defaults.namespace),
132
- user_id: asString(config["user_id"], defaults.user_id),
133
- user_email: asString(config["user_email"], defaults.user_email),
134
- device_id: asString(config["device_id"], defaults.device_id),
135
- teams: asTeams(config["teams"], defaults.teams),
136
- sync: {
137
- enabled: asBool(
138
- (config["sync"] as Record<string, unknown> | undefined)?.["enabled"],
139
- defaults.sync.enabled
140
- ),
141
- interval_seconds: asNumber(
142
- (config["sync"] as Record<string, unknown> | undefined)?.["interval_seconds"],
143
- defaults.sync.interval_seconds
144
- ),
145
- batch_size: asNumber(
146
- (config["sync"] as Record<string, unknown> | undefined)?.["batch_size"],
147
- defaults.sync.batch_size
148
- ),
149
- },
150
- search: {
151
- default_limit: asNumber(
152
- (config["search"] as Record<string, unknown> | undefined)?.["default_limit"],
153
- defaults.search.default_limit
154
- ),
155
- local_boost: asNumber(
156
- (config["search"] as Record<string, unknown> | undefined)?.["local_boost"],
157
- defaults.search.local_boost
158
- ),
159
- scope: asScope(
160
- (config["search"] as Record<string, unknown> | undefined)?.["scope"],
161
- defaults.search.scope
162
- ),
163
- },
164
- scrubbing: {
165
- enabled: asBool(
166
- (config["scrubbing"] as Record<string, unknown> | undefined)?.["enabled"],
167
- defaults.scrubbing.enabled
168
- ),
169
- custom_patterns: asStringArray(
170
- (config["scrubbing"] as Record<string, unknown> | undefined)?.["custom_patterns"],
171
- defaults.scrubbing.custom_patterns
172
- ),
173
- default_sensitivity: asSensitivity(
174
- (config["scrubbing"] as Record<string, unknown> | undefined)?.["default_sensitivity"],
175
- defaults.scrubbing.default_sensitivity
176
- ),
177
- },
178
- };
179
- }
180
-
181
- export function saveConfig(config: Config): void {
182
- if (!existsSync(CONFIG_DIR)) {
183
- mkdirSync(CONFIG_DIR, { recursive: true });
184
- }
185
- writeFileSync(SETTINGS_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
186
- }
187
-
188
- export function configExists(): boolean {
189
- return existsSync(SETTINGS_PATH);
190
- }
191
-
192
- // --- Type helpers ---
193
-
194
- function asString(value: unknown, fallback: string): string {
195
- return typeof value === "string" ? value : fallback;
196
- }
197
-
198
- function asNumber(value: unknown, fallback: number): number {
199
- return typeof value === "number" && !Number.isNaN(value) ? value : fallback;
200
- }
201
-
202
- function asBool(value: unknown, fallback: boolean): boolean {
203
- return typeof value === "boolean" ? value : fallback;
204
- }
205
-
206
- function asStringArray(value: unknown, fallback: string[]): string[] {
207
- return Array.isArray(value) && value.every((v) => typeof v === "string")
208
- ? (value as string[])
209
- : fallback;
210
- }
211
-
212
- function asScope(
213
- value: unknown,
214
- fallback: "personal" | "team" | "all"
215
- ): "personal" | "team" | "all" {
216
- if (value === "personal" || value === "team" || value === "all") return value;
217
- return fallback;
218
- }
219
-
220
- function asSensitivity(
221
- value: unknown,
222
- fallback: "shared" | "personal" | "secret"
223
- ): "shared" | "personal" | "secret" {
224
- if (value === "shared" || value === "personal" || value === "secret") return value;
225
- return fallback;
226
- }
227
-
228
- function asTeams(value: unknown, fallback: TeamMembership[]): TeamMembership[] {
229
- if (!Array.isArray(value)) return fallback;
230
- return value.filter(
231
- (t): t is TeamMembership =>
232
- typeof t === "object" &&
233
- t !== null &&
234
- typeof t.id === "string" &&
235
- typeof t.name === "string" &&
236
- typeof t.namespace === "string"
237
- );
238
- }