sandstream-kit 1.2.0 → 1.3.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 (102) hide show
  1. package/README.md +101 -92
  2. package/dist/adapters/expo-eas.js +1 -1
  3. package/dist/adapters/expo-eas.js.map +1 -1
  4. package/dist/audit-logging-service.js +1 -1
  5. package/dist/audit-logging-service.js.map +1 -1
  6. package/dist/author-verification.js +1 -1
  7. package/dist/author-verification.js.map +1 -1
  8. package/dist/cli-shared.d.ts +4 -0
  9. package/dist/cli-shared.js +11 -0
  10. package/dist/cli-shared.js.map +1 -0
  11. package/dist/cli.js +156 -1232
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/audit.d.ts +1 -0
  14. package/dist/commands/audit.js +99 -0
  15. package/dist/commands/audit.js.map +1 -0
  16. package/dist/commands/auth.d.ts +1 -0
  17. package/dist/commands/auth.js +121 -0
  18. package/dist/commands/auth.js.map +1 -0
  19. package/dist/commands/env.d.ts +1 -0
  20. package/dist/commands/env.js +149 -0
  21. package/dist/commands/env.js.map +1 -0
  22. package/dist/commands/hooks.d.ts +1 -0
  23. package/dist/commands/hooks.js +146 -0
  24. package/dist/commands/hooks.js.map +1 -0
  25. package/dist/commands/mcp.d.ts +1 -0
  26. package/dist/commands/mcp.js +120 -0
  27. package/dist/commands/mcp.js.map +1 -0
  28. package/dist/commands/memory.d.ts +1 -0
  29. package/dist/commands/memory.js +534 -0
  30. package/dist/commands/memory.js.map +1 -0
  31. package/dist/config.js +3 -0
  32. package/dist/config.js.map +1 -1
  33. package/dist/mcp-server.js +59 -6
  34. package/dist/mcp-server.js.map +1 -1
  35. package/dist/memory/amazonq.d.ts +5 -0
  36. package/dist/memory/amazonq.js +161 -0
  37. package/dist/memory/amazonq.js.map +1 -0
  38. package/dist/memory/cline.d.ts +5 -0
  39. package/dist/memory/cline.js +117 -0
  40. package/dist/memory/cline.js.map +1 -0
  41. package/dist/memory/cursor.d.ts +4 -0
  42. package/dist/memory/cursor.js +116 -0
  43. package/dist/memory/cursor.js.map +1 -0
  44. package/dist/memory/parser.js +6 -0
  45. package/dist/memory/parser.js.map +1 -1
  46. package/dist/memory/suggest.d.ts +21 -0
  47. package/dist/memory/suggest.js +36 -0
  48. package/dist/memory/suggest.js.map +1 -0
  49. package/dist/onepassword.js +1 -1
  50. package/dist/onepassword.js.map +1 -1
  51. package/dist/open.js +8 -2
  52. package/dist/open.js.map +1 -1
  53. package/dist/run.js +1 -1
  54. package/dist/run.js.map +1 -1
  55. package/dist/service-auth.d.ts +31 -0
  56. package/dist/service-auth.js +47 -0
  57. package/dist/service-auth.js.map +1 -0
  58. package/dist/stack-detector.js +53 -76
  59. package/dist/stack-detector.js.map +1 -1
  60. package/package.json +9 -4
  61. package/dist/memory/backup 2.d.ts +0 -6
  62. package/dist/memory/backup 2.js +0 -80
  63. package/dist/memory/backup 2.js.map +0 -1
  64. package/dist/memory/db 2.d.ts +0 -40
  65. package/dist/memory/db 2.js +0 -233
  66. package/dist/memory/db 2.js.map +0 -1
  67. package/dist/memory/hook 2.d.ts +0 -6
  68. package/dist/memory/hook 2.js +0 -51
  69. package/dist/memory/hook 2.js.map +0 -1
  70. package/dist/memory/hook.test 2.d.ts +0 -1
  71. package/dist/memory/hook.test 2.js +0 -35
  72. package/dist/memory/hook.test 2.js.map +0 -1
  73. package/dist/memory/install 2.d.ts +0 -8
  74. package/dist/memory/install 2.js +0 -72
  75. package/dist/memory/install 2.js.map +0 -1
  76. package/dist/memory/install.test 2.d.ts +0 -1
  77. package/dist/memory/install.test 2.js +0 -59
  78. package/dist/memory/install.test 2.js.map +0 -1
  79. package/dist/memory/pal 2.d.ts +0 -47
  80. package/dist/memory/pal 2.js +0 -154
  81. package/dist/memory/pal 2.js.map +0 -1
  82. package/dist/memory/project 2.d.ts +0 -1
  83. package/dist/memory/project 2.js +0 -24
  84. package/dist/memory/project 2.js.map +0 -1
  85. package/dist/memory/scan 2.d.ts +0 -15
  86. package/dist/memory/scan 2.js +0 -94
  87. package/dist/memory/scan 2.js.map +0 -1
  88. package/dist/memory/scan.test 2.d.ts +0 -1
  89. package/dist/memory/scan.test 2.js +0 -55
  90. package/dist/memory/scan.test 2.js.map +0 -1
  91. package/dist/memory/shared 2.d.ts +0 -33
  92. package/dist/memory/shared 2.js +0 -120
  93. package/dist/memory/shared 2.js.map +0 -1
  94. package/dist/memory/threads 2.d.ts +0 -37
  95. package/dist/memory/threads 2.js +0 -50
  96. package/dist/memory/threads 2.js.map +0 -1
  97. package/dist/memory/threads.test 2.d.ts +0 -1
  98. package/dist/memory/threads.test 2.js +0 -66
  99. package/dist/memory/threads.test 2.js.map +0 -1
  100. package/dist/memory/types 2.d.ts +0 -52
  101. package/dist/memory/types 2.js +0 -5
  102. package/dist/memory/types 2.js.map +0 -1
@@ -0,0 +1,120 @@
1
+ // `kit mcp` command (MCP orchestrator + stdio server) — extracted from cli.ts (split step 5).
2
+ import { startMcpServer } from "../mcp-server.js";
3
+ import { loadConfig } from "../config.js";
4
+ import { resolveConfigPath } from "../cli-shared.js";
5
+ import { c } from "../utils/colors.js";
6
+ import { hasFlag } from "../utils/flags.js";
7
+ export async function cmdMcp() {
8
+ const sub = process.argv[3];
9
+ // An MCP client launches `kit mcp` and speaks the stdio transport — no
10
+ // sub-command and a non-TTY stdin. Start the server in that case. Interactive
11
+ // use (TTY) or any explicit sub falls through to the orchestrator below.
12
+ if (!sub && !process.stdin.isTTY) {
13
+ await startMcpServer();
14
+ return true;
15
+ }
16
+ const config = await loadConfig(resolveConfigPath()).catch(() => null);
17
+ const mcpConfig = config?.mcp;
18
+ const { statusAll, statusForMcp, clearMcpToken, storeStaticToken, } = await import("../mcp-orchestrator.js");
19
+ if (!sub || sub === "list" || sub === "status") {
20
+ console.log(`${c.bold}${c.cyan}kit mcp${c.reset}`);
21
+ console.log(`${c.dim}${"─".repeat(50)}${c.reset}\n`);
22
+ const entries = await statusAll(mcpConfig);
23
+ if (entries.length === 0) {
24
+ console.log(`${c.dim}No [mcp.*] blocks declared in .kit.toml${c.reset}`);
25
+ console.log(`${c.dim}Add e.g. [mcp.sentry] scopes = ["org:read", "project:write"]${c.reset}`);
26
+ return true;
27
+ }
28
+ for (const e of entries) {
29
+ const color = e.status === "ok"
30
+ ? c.green
31
+ : e.status === "missing" || e.status === "expired"
32
+ ? c.yellow
33
+ : c.red;
34
+ const marker = e.status === "ok" ? "✓" : e.status === "missing" ? "?" : "✗";
35
+ const scopeStr = e.declared?.scopes ? ` ${c.dim}[${e.declared.scopes.join(", ")}]${c.reset}` : "";
36
+ console.log(` ${color}${marker}${c.reset} ${e.name.padEnd(14)} ${color}${e.status}${c.reset}${scopeStr}`);
37
+ if (e.detail)
38
+ console.log(` ${c.dim}${e.detail}${c.reset}`);
39
+ }
40
+ console.log();
41
+ return entries.every((e) => e.status === "ok" || e.status === "missing");
42
+ }
43
+ if (sub === "auth") {
44
+ const name = process.argv[4];
45
+ if (!name) {
46
+ console.error(`${c.red}Usage: kit mcp auth <name>${c.reset}`);
47
+ return false;
48
+ }
49
+ const declared = mcpConfig?.[name];
50
+ if (!declared) {
51
+ console.error(`${c.red}No [mcp.${name}] block in .kit.toml${c.reset}`);
52
+ return false;
53
+ }
54
+ // For now we surface vendor-specific guidance; full OAuth flow is
55
+ // delegated to the operator (paste callback URL). When the vendor's
56
+ // MCP server publishes a stable /authorize endpoint we can fully
57
+ // automate.
58
+ const authUrl = declared.url ?? `https://mcp.${name}.dev`;
59
+ console.log(`${c.bold}Authorize kit for MCP server "${name}"${c.reset}`);
60
+ console.log(`${c.dim}Vendor URL: ${authUrl}${c.reset}`);
61
+ console.log(`${c.dim}Required scopes: ${(declared.scopes ?? ["(none declared)"]).join(", ")}${c.reset}\n`);
62
+ console.log(`${c.yellow}OAuth-flow not yet automated for "${name}". Two options:${c.reset}`);
63
+ console.log(` 1. Set env var: ${c.bold}kit mcp set-token ${name} --from-env <VAR>${c.reset}`);
64
+ console.log(` 2. Paste token: ${c.bold}kit mcp set-token ${name} --paste${c.reset}`);
65
+ return true;
66
+ }
67
+ if (sub === "set-token") {
68
+ const name = process.argv[4];
69
+ if (!name) {
70
+ console.error(`${c.red}Usage: kit mcp set-token <name> [--from-env VAR | --paste]${c.reset}`);
71
+ return false;
72
+ }
73
+ const args = process.argv.slice(5);
74
+ const fromEnvIdx = args.indexOf("--from-env");
75
+ let accessToken;
76
+ if (fromEnvIdx >= 0 && args[fromEnvIdx + 1]) {
77
+ const envVar = args[fromEnvIdx + 1];
78
+ accessToken = process.env[envVar];
79
+ if (!accessToken) {
80
+ console.error(`${c.red}Env var ${envVar} is empty${c.reset}`);
81
+ return false;
82
+ }
83
+ }
84
+ else if (hasFlag(args, "--paste")) {
85
+ const readline = await import("node:readline/promises");
86
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
87
+ try {
88
+ accessToken = (await rl.question(`Paste access token for "${name}": `)).trim();
89
+ }
90
+ finally {
91
+ rl.close();
92
+ }
93
+ }
94
+ else {
95
+ console.error(`${c.red}Missing --from-env <VAR> or --paste${c.reset}`);
96
+ return false;
97
+ }
98
+ const declared = mcpConfig?.[name];
99
+ await storeStaticToken(name, accessToken, {
100
+ scopes: declared?.scopes,
101
+ });
102
+ console.log(`${c.green}✓${c.reset} Token stored for ${name} in ~/.kit/mcp-tokens.json (chmod 0o600)`);
103
+ const status = await statusForMcp(name, declared ?? null);
104
+ console.log(`${c.dim}Status: ${status.status}${c.reset}`);
105
+ return true;
106
+ }
107
+ if (sub === "clear") {
108
+ const name = process.argv[4];
109
+ if (!name) {
110
+ console.error(`${c.red}Usage: kit mcp clear <name>${c.reset}`);
111
+ return false;
112
+ }
113
+ await clearMcpToken(name);
114
+ console.log(`${c.green}✓${c.reset} Cleared token for ${name}`);
115
+ return true;
116
+ }
117
+ console.error(`${c.red}Usage: kit mcp [list | status | auth <name> | set-token <name> | clear <name>]${c.reset}`);
118
+ return false;
119
+ }
120
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function cmdMemory(): Promise<boolean>;
@@ -0,0 +1,534 @@
1
+ // kit memory commands — extracted from cli.ts (split step 7). The large
2
+ // subcommand dispatcher; restructured to a handler table in a follow-up.
3
+ import { c } from "../utils/colors.js";
4
+ import { hasFlag, flagValue } from "../utils/flags.js";
5
+ import { existsSync } from "node:fs";
6
+ import { basename } from "node:path";
7
+ import { openMemoryDb, getStats, getMemoryDbPath, searchMessages } from "../memory/db.js";
8
+ import { indexAllHarnesses } from "../memory/parser.js";
9
+ import { mergeDb } from "../memory/merge.js";
10
+ import { buildSuggestPrompt } from "../memory/suggest.js";
11
+ import { getCurrentProjectRoot } from "../memory/project.js";
12
+ import { scanDbForSecrets } from "../memory/scan.js";
13
+ import { backupEncrypted, restoreEncrypted } from "../memory/backup.js";
14
+ import { shareEntry, listAreas, queryArea, getSharedPath, } from "../memory/shared.js";
15
+ import { userPromptSubmitReminder, runSessionEndIndex, sessionStartRecovery } from "../memory/hook.js";
16
+ import { installMemoryHooks, uninstallMemoryHooks, getClaudeSettingsPath, } from "../memory/install.js";
17
+ import { palAdd, palList, palDone, palSnooze, palAutoVerify, importLegacyLedger, } from "../memory/pal.js";
18
+ import { saveThread, listThreads, removeThread, latestSessionId, resolveThread, } from "../memory/threads.js";
19
+ export async function cmdMemory() {
20
+ const subcommand = process.argv[3];
21
+ if (!subcommand || subcommand === "--help" || subcommand === "-h")
22
+ return memHelp();
23
+ // One handler per subcommand — keeps this dispatcher flat (was a complexity-132
24
+ // if-chain). Each handler reads process.argv itself, so no args thread through.
25
+ const handlers = {
26
+ index: memIndex,
27
+ merge: memMerge,
28
+ stats: memStats,
29
+ suggest: memSuggest,
30
+ search: memSearch,
31
+ hook: memHook,
32
+ install: memInstall,
33
+ uninstall: memUninstall,
34
+ share: memShare,
35
+ areas: memAreas,
36
+ area: memArea,
37
+ scan: memScan,
38
+ backup: memBackup,
39
+ restore: memRestore,
40
+ save: memSave,
41
+ threads: memThreads,
42
+ resume: memResume,
43
+ forget: memForget,
44
+ pal: memPal,
45
+ };
46
+ const handler = handlers[subcommand];
47
+ if (handler)
48
+ return handler();
49
+ console.error(`${c.red}Unknown memory subcommand: ${subcommand}${c.reset}`);
50
+ console.error("Use: kit memory index | search <query> | stats | install | uninstall | pal");
51
+ return false;
52
+ }
53
+ async function memPal() {
54
+ const jsonMode = hasFlag(process.argv, "--json");
55
+ const action = process.argv[4] && !process.argv[4].startsWith("--") ? process.argv[4] : "list";
56
+ const db = openMemoryDb();
57
+ try {
58
+ if (action === "list") {
59
+ const scope = hasFlag(process.argv, "--global")
60
+ ? undefined
61
+ : basename(getCurrentProjectRoot());
62
+ const items = palList(db, { scope });
63
+ if (jsonMode) {
64
+ console.log(JSON.stringify(items));
65
+ return true;
66
+ }
67
+ if (!items.length) {
68
+ console.log(`${c.dim}no open action items${c.reset}`);
69
+ return true;
70
+ }
71
+ console.log(`${c.bold}${items.length}${c.reset} open action item(s):`);
72
+ for (const p of items) {
73
+ const tag = p.kind === "auto" ? ` ${c.dim}· auto${c.reset}` : "";
74
+ const scope = p.scope ? ` ${c.dim}[${p.scope}]${c.reset}` : "";
75
+ console.log(` ${c.bold}${p.id}${c.reset} ${p.title}${scope}${tag}`);
76
+ }
77
+ return true;
78
+ }
79
+ if (action === "add") {
80
+ const title = process.argv.slice(5).filter((a) => !a.startsWith("--")).join(" ").trim();
81
+ if (!title) {
82
+ console.error(`${c.red}usage: kit memory pal add <title> [--verify=<cmd>] [--scope=<s>]${c.reset}`);
83
+ return false;
84
+ }
85
+ const id = palAdd(db, {
86
+ title,
87
+ verifyCmd: flagValue(process.argv, "--verify"),
88
+ scope: flagValue(process.argv, "--scope") ?? basename(getCurrentProjectRoot()),
89
+ });
90
+ console.log(`${c.green}✓${c.reset} added ${c.bold}${id}${c.reset}`);
91
+ return true;
92
+ }
93
+ if (action === "done") {
94
+ const id = process.argv[5];
95
+ if (!id) {
96
+ console.error(`${c.red}usage: kit memory pal done <id>${c.reset}`);
97
+ return false;
98
+ }
99
+ console.log(palDone(db, id)
100
+ ? `${c.green}✓${c.reset} closed ${id}`
101
+ : `${c.dim}${id} not found or already closed${c.reset}`);
102
+ return true;
103
+ }
104
+ if (action === "snooze") {
105
+ const id = process.argv[5];
106
+ const days = Number(process.argv[6] ?? "7") || 7;
107
+ if (!id) {
108
+ console.error(`${c.red}usage: kit memory pal snooze <id> [days]${c.reset}`);
109
+ return false;
110
+ }
111
+ console.log(palSnooze(db, id, days)
112
+ ? `${c.green}✓${c.reset} snoozed ${id} for ${days}d`
113
+ : `${c.dim}${id} not found${c.reset}`);
114
+ return true;
115
+ }
116
+ if (action === "verify") {
117
+ const r = palAutoVerify(db);
118
+ console.log(`${c.dim}checked ${r.checked} · closed ${r.closed.length} · reopened ${r.reopened.length}${c.reset}`);
119
+ return true;
120
+ }
121
+ if (action === "import") {
122
+ const r = importLegacyLedger(db);
123
+ console.log(`${c.green}✓${c.reset} imported ${r.imported} item(s) from the legacy ledger`);
124
+ return true;
125
+ }
126
+ console.error(`${c.red}Unknown pal action: ${action}${c.reset}`);
127
+ console.error("Use: kit memory pal [list|add|done|snooze|verify|import]");
128
+ return false;
129
+ }
130
+ finally {
131
+ db.close();
132
+ }
133
+ }
134
+ async function memHelp() {
135
+ console.log("kit memory — local conversation memory (SQLite + FTS5)");
136
+ console.log("\nUsage:");
137
+ console.log(" kit memory index Index ~/.claude transcripts into the memory store");
138
+ console.log(" kit memory search <query> Search memory (current project; --global for all)");
139
+ console.log(" kit memory stats Show what the memory store contains");
140
+ console.log(" kit memory merge <file> Merge another machine's memory.db into this one");
141
+ console.log(" kit memory install Wire the 2 hooks into ~/.claude/settings.json");
142
+ console.log(" kit memory uninstall Remove the hooks");
143
+ console.log(" kit memory pal [list|add|done|snooze|verify|import] Pending action ledger");
144
+ console.log(" kit memory save <name> Bookmark the current session as a named copilot");
145
+ console.log(" kit memory threads List saved copilots (--global for all)");
146
+ console.log(" kit memory resume <name|n> Print the resume command for a saved copilot");
147
+ console.log(" kit memory forget <name> Remove a saved copilot");
148
+ console.log(" kit memory scan Scan the store for stored secrets");
149
+ console.log(" kit memory backup <file> Encrypted backup (set KIT_MEMORY_PASSPHRASE)");
150
+ console.log(" kit memory restore <file> Restore an encrypted backup (new machine)");
151
+ console.log(" kit memory share … Promote a curated entry to shared (team) memory");
152
+ console.log(" kit memory areas List shared responsibility areas");
153
+ console.log(" kit memory area <name> Show shared entries for one area");
154
+ return true;
155
+ }
156
+ async function memIndex() {
157
+ const jsonMode = hasFlag(process.argv, "--json");
158
+ const db = openMemoryDb();
159
+ const t0 = Date.now();
160
+ const byHarness = indexAllHarnesses(db);
161
+ const ms = Date.now() - t0;
162
+ db.close();
163
+ if (jsonMode) {
164
+ console.log(JSON.stringify({ byHarness, ms }));
165
+ return true;
166
+ }
167
+ let messages = 0;
168
+ let toolUses = 0;
169
+ let files = 0;
170
+ let skipped = 0;
171
+ for (const r of Object.values(byHarness)) {
172
+ messages += r.messages;
173
+ toolUses += r.toolUses;
174
+ files += r.files;
175
+ skipped += r.filesSkipped;
176
+ }
177
+ console.log(`${c.green}✓${c.reset} indexed ${c.bold}${messages}${c.reset} messages + ${toolUses} tool-uses from ${files} sessions${skipped ? `, ${skipped} unchanged` : ""} ${c.dim}(${ms}ms)${c.reset}`);
178
+ for (const [harness, r] of Object.entries(byHarness)) {
179
+ if (r.files || r.messages) {
180
+ console.log(` ${c.dim}${harness}: ${r.messages} msg · ${r.files} sessions${r.filesSkipped ? ` · ${r.filesSkipped} unchanged` : ""}${c.reset}`);
181
+ }
182
+ }
183
+ return true;
184
+ }
185
+ async function memMerge() {
186
+ const sourcePath = process.argv[4];
187
+ if (!sourcePath) {
188
+ console.error(`${c.red}usage: kit memory merge <other-machine-memory.db>${c.reset}`);
189
+ return false;
190
+ }
191
+ const db = openMemoryDb();
192
+ try {
193
+ const r = mergeDb(db, sourcePath);
194
+ console.log(`${c.green}✓${c.reset} merged ${c.bold}${r.messages}${c.reset} messages + ${r.toolUses} tool-uses · ${r.sessions} sessions · ${r.pending} pending · ${r.threads} copilots ${c.dim}from ${sourcePath}${c.reset}`);
195
+ }
196
+ catch (err) {
197
+ db.close();
198
+ console.error(`${c.red}${err.message}${c.reset}`);
199
+ return false;
200
+ }
201
+ db.close();
202
+ return true;
203
+ }
204
+ async function memStats() {
205
+ const jsonMode = hasFlag(process.argv, "--json");
206
+ const db = openMemoryDb();
207
+ const s = getStats(db);
208
+ db.close();
209
+ if (jsonMode) {
210
+ console.log(JSON.stringify(s));
211
+ return true;
212
+ }
213
+ console.log(`${c.bold}kit memory${c.reset} ${c.dim}${s.dbPath}${c.reset}`);
214
+ console.log(` sessions ${s.sessions}`);
215
+ console.log(` messages ${s.messages}`);
216
+ console.log(` tool-uses ${s.toolUses}`);
217
+ console.log(` pending ${s.pendingOpen} ${c.dim}(open action items)${c.reset}`);
218
+ console.log(` size ${Math.round(s.sizeBytes / 1024)} KB`);
219
+ return true;
220
+ }
221
+ async function memSuggest() {
222
+ const jsonMode = hasFlag(process.argv, "--json");
223
+ // BYO-LLM: kit emits a prompt; it never calls a model. Pipe to your own:
224
+ // kit memory suggest | <your-llm>
225
+ const limitArg = flagValue(process.argv, "--limit");
226
+ const limit = limitArg ? Math.max(1, parseInt(limitArg, 10) || 30) : undefined;
227
+ const db = openMemoryDb();
228
+ const out = buildSuggestPrompt(db, { limit });
229
+ db.close();
230
+ if (jsonMode) {
231
+ console.log(JSON.stringify(out));
232
+ return true;
233
+ }
234
+ console.log(out.prompt);
235
+ return true;
236
+ }
237
+ async function memSearch() {
238
+ const jsonMode = hasFlag(process.argv, "--json");
239
+ const terms = process.argv.slice(4).filter((a) => !a.startsWith("--"));
240
+ const query = terms.join(" ").trim();
241
+ if (!query) {
242
+ console.error(`${c.red}usage: kit memory search <query> [--global] [--project=<path>] [--limit=N]${c.reset}`);
243
+ return false;
244
+ }
245
+ const limit = Number(flagValue(process.argv, "--limit") ?? "20") || 20;
246
+ const projectPath = hasFlag(process.argv, "--global")
247
+ ? undefined
248
+ : (flagValue(process.argv, "--project") ?? getCurrentProjectRoot());
249
+ const db = openMemoryDb();
250
+ const hits = searchMessages(db, query, { limit, projectPath });
251
+ db.close();
252
+ if (jsonMode) {
253
+ console.log(JSON.stringify(hits));
254
+ return true;
255
+ }
256
+ const scope = projectPath ? `${c.dim}in ${projectPath}${c.reset}` : `${c.dim}(global)${c.reset}`;
257
+ if (!hits.length) {
258
+ console.log(`${c.dim}no matches for "${query}" ${projectPath ?? "(global)"}${c.reset}`);
259
+ return true;
260
+ }
261
+ console.log(`${c.bold}${hits.length}${c.reset} match(es) ${scope}`);
262
+ for (const h of hits) {
263
+ const snippet = (h.content ?? "").replace(/\s+/g, " ").slice(0, 120);
264
+ console.log(` ${c.dim}${h.timestamp ?? "?"}${c.reset} ${c.bold}${h.role ?? h.uuid ?? ""}${c.reset} ${snippet}`);
265
+ }
266
+ return true;
267
+ }
268
+ async function memHook() {
269
+ // Internal: invoked by Claude Code hooks. Fail-open — never block.
270
+ const event = process.argv[4];
271
+ if (event === "user-prompt-submit") {
272
+ const text = userPromptSubmitReminder();
273
+ if (text)
274
+ console.log(text);
275
+ return true;
276
+ }
277
+ if (event === "session-end") {
278
+ runSessionEndIndex();
279
+ return true;
280
+ }
281
+ if (event === "session-start") {
282
+ const text = sessionStartRecovery();
283
+ if (text)
284
+ console.log(text);
285
+ return true;
286
+ }
287
+ console.error(`${c.red}Unknown hook event: ${event ?? "(none)"}${c.reset}`);
288
+ return false;
289
+ }
290
+ async function memInstall() {
291
+ const { added, alreadyPresent } = installMemoryHooks();
292
+ for (const e of added)
293
+ console.log(`${c.green}✓${c.reset} installed ${e} hook`);
294
+ for (const e of alreadyPresent)
295
+ console.log(`${c.dim}• ${e} hook already present${c.reset}`);
296
+ console.log(`${c.dim}settings: ${getClaudeSettingsPath()}${c.reset}`);
297
+ return true;
298
+ }
299
+ async function memUninstall() {
300
+ const { removed } = uninstallMemoryHooks();
301
+ if (removed.length) {
302
+ for (const e of removed)
303
+ console.log(`${c.green}✓${c.reset} removed ${e} hook`);
304
+ }
305
+ else {
306
+ console.log(`${c.dim}no kit memory hooks were installed${c.reset}`);
307
+ }
308
+ return true;
309
+ }
310
+ async function memShare() {
311
+ const area = flagValue(process.argv, "--area");
312
+ const title = flagValue(process.argv, "--title");
313
+ const kind = (flagValue(process.argv, "--kind") ?? "note");
314
+ const body = flagValue(process.argv, "--body") ?? "";
315
+ const ref = flagValue(process.argv, "--ref");
316
+ if (!area || !title) {
317
+ console.error(`${c.red}usage: kit memory share --area <a> --title <t> [--kind decision|convention|how-built|status|security|note] [--body <b>] [--ref <r>]${c.reset}`);
318
+ return false;
319
+ }
320
+ const root = getCurrentProjectRoot();
321
+ try {
322
+ const e = shareEntry(root, { area, kind, title, body, refs: ref ? [ref] : [] }, new Date().toISOString());
323
+ console.log(`${c.green}✓${c.reset} shared ${c.bold}${e.id}${c.reset} to area ${c.bold}${area}${c.reset} ${c.dim}(${getSharedPath(root)})${c.reset}`);
324
+ console.log(`${c.dim}commit .kit/shared/memory.jsonl + open a PR — shared memory is reviewed like code${c.reset}`);
325
+ }
326
+ catch (err) {
327
+ console.error(`${c.red}${err.message}${c.reset}`);
328
+ return false;
329
+ }
330
+ return true;
331
+ }
332
+ async function memAreas() {
333
+ const jsonMode = hasFlag(process.argv, "--json");
334
+ const areas = listAreas(getCurrentProjectRoot());
335
+ if (jsonMode) {
336
+ console.log(JSON.stringify(areas));
337
+ return true;
338
+ }
339
+ if (!areas.length) {
340
+ console.log(`${c.dim}no shared areas yet — add one with kit memory share${c.reset}`);
341
+ return true;
342
+ }
343
+ console.log(`${c.bold}${areas.length}${c.reset} responsibility area(s):`);
344
+ for (const a of areas) {
345
+ console.log(` ${c.bold}${a.area}${c.reset} ${c.dim}· ${a.count} entr${a.count === 1 ? "y" : "ies"}${c.reset}`);
346
+ }
347
+ return true;
348
+ }
349
+ async function memArea() {
350
+ const jsonMode = hasFlag(process.argv, "--json");
351
+ const name = process.argv[4];
352
+ if (!name) {
353
+ console.error(`${c.red}usage: kit memory area <name>${c.reset}`);
354
+ return false;
355
+ }
356
+ const entries = queryArea(getCurrentProjectRoot(), name);
357
+ if (jsonMode) {
358
+ console.log(JSON.stringify(entries));
359
+ return true;
360
+ }
361
+ if (!entries.length) {
362
+ console.log(`${c.dim}no shared memory for area '${name}'${c.reset}`);
363
+ return true;
364
+ }
365
+ console.log(`${c.bold}${name}${c.reset} ${c.dim}· ${entries.length} entr${entries.length === 1 ? "y" : "ies"}${c.reset}`);
366
+ for (const e of entries) {
367
+ const prov = `${e.author}${e.source_ref ? ` @${e.source_ref}` : ""}`;
368
+ console.log(` ${c.bold}[${e.kind}]${c.reset} ${e.title} ${c.dim}— ${prov}${c.reset}`);
369
+ if (e.body)
370
+ console.log(` ${e.body}`);
371
+ if (e.refs.length)
372
+ console.log(` ${c.dim}refs: ${e.refs.join(", ")}${c.reset}`);
373
+ }
374
+ return true;
375
+ }
376
+ async function memScan() {
377
+ const jsonMode = hasFlag(process.argv, "--json");
378
+ const db = openMemoryDb();
379
+ const findings = scanDbForSecrets(db);
380
+ db.close();
381
+ if (jsonMode) {
382
+ console.log(JSON.stringify(findings));
383
+ return !findings.some((f) => f.confidence === "high");
384
+ }
385
+ if (!findings.length) {
386
+ console.log(`${c.green}✓${c.reset} no stored secrets found in the memory store`);
387
+ return true;
388
+ }
389
+ const high = findings.filter((f) => f.confidence === "high");
390
+ const heuristic = findings.filter((f) => f.confidence === "heuristic");
391
+ const times = (n) => (n > 1 ? ` ×${n}` : "");
392
+ if (high.length) {
393
+ console.log(`${c.red}⚠ ${high.length} high-confidence secret(s):${c.reset}`);
394
+ for (const f of high) {
395
+ const proj = f.projects.length ? `${c.bold}[${f.projects.join(", ")}]${c.reset}${c.dim} · ` : "";
396
+ console.log(` ${c.bold}${f.label}${c.reset} ${c.dim}${f.preview}${times(f.count)} · ${proj}${f.sample}${c.reset}`);
397
+ }
398
+ }
399
+ else {
400
+ console.log(`${c.green}✓${c.reset} no high-confidence secrets`);
401
+ }
402
+ if (heuristic.length) {
403
+ const showAll = hasFlag(process.argv, "--all");
404
+ if (showAll) {
405
+ console.log(`${c.dim}${heuristic.length} heuristic match(es) (KEY=value patterns — usually env vars / paths):${c.reset}`);
406
+ for (const f of heuristic) {
407
+ console.log(` ${c.dim}${f.label} ${f.preview}${times(f.count)} · ${f.sample}${c.reset}`);
408
+ }
409
+ }
410
+ else {
411
+ console.log(`${c.dim}+ ${heuristic.length} heuristic match(es) (likely env vars / paths) — run with --all to see${c.reset}`);
412
+ }
413
+ }
414
+ return high.length === 0; // exit non-zero only on high-confidence findings
415
+ }
416
+ async function memBackup() {
417
+ const out = process.argv[4];
418
+ const pass = process.env.KIT_MEMORY_PASSPHRASE ?? flagValue(process.argv, "--passphrase");
419
+ if (!out) {
420
+ console.error(`${c.red}usage: kit memory backup <file> (set KIT_MEMORY_PASSPHRASE)${c.reset}`);
421
+ return false;
422
+ }
423
+ if (!pass) {
424
+ console.error(`${c.red}set KIT_MEMORY_PASSPHRASE (or --passphrase) — the key is never stored${c.reset}`);
425
+ return false;
426
+ }
427
+ try {
428
+ backupEncrypted(pass, getMemoryDbPath(), out);
429
+ }
430
+ catch (err) {
431
+ console.error(`${c.red}${err.message}${c.reset}`);
432
+ return false;
433
+ }
434
+ console.log(`${c.green}✓${c.reset} encrypted backup → ${out} ${c.dim}(AES-256-GCM · scrypt)${c.reset}`);
435
+ return true;
436
+ }
437
+ async function memRestore() {
438
+ const inFile = process.argv[4];
439
+ const pass = process.env.KIT_MEMORY_PASSPHRASE ?? flagValue(process.argv, "--passphrase");
440
+ if (!inFile) {
441
+ console.error(`${c.red}usage: kit memory restore <file> [--to <path>] [--force]${c.reset}`);
442
+ return false;
443
+ }
444
+ if (!pass) {
445
+ console.error(`${c.red}set KIT_MEMORY_PASSPHRASE (or --passphrase)${c.reset}`);
446
+ return false;
447
+ }
448
+ const dest = flagValue(process.argv, "--to") ?? getMemoryDbPath();
449
+ if (existsSync(dest) && !hasFlag(process.argv, "--force")) {
450
+ console.error(`${c.red}${dest} exists — pass --force to overwrite${c.reset}`);
451
+ return false;
452
+ }
453
+ try {
454
+ restoreEncrypted(pass, inFile, dest);
455
+ }
456
+ catch {
457
+ console.error(`${c.red}restore failed — wrong passphrase or corrupt backup${c.reset}`);
458
+ return false;
459
+ }
460
+ console.log(`${c.green}✓${c.reset} restored → ${dest}`);
461
+ return true;
462
+ }
463
+ async function memSave() {
464
+ const name = process.argv.slice(4).filter((a) => !a.startsWith("--")).join(" ").trim();
465
+ if (!name) {
466
+ console.error(`${c.red}usage: kit memory save <name> [--session=<id>]${c.reset}`);
467
+ return false;
468
+ }
469
+ const root = getCurrentProjectRoot();
470
+ const db = openMemoryDb();
471
+ const sessionId = flagValue(process.argv, "--session") ?? latestSessionId(db, { projectPath: root });
472
+ if (!sessionId) {
473
+ db.close();
474
+ console.error(`${c.red}no session found for ${root} — index first or pass --session=<id>${c.reset}`);
475
+ return false;
476
+ }
477
+ saveThread(db, { name, sessionId, projectPath: root });
478
+ db.close();
479
+ console.log(`${c.green}✓${c.reset} saved copilot ${c.bold}${name}${c.reset} ${c.dim}→ ${sessionId}${c.reset}`);
480
+ return true;
481
+ }
482
+ async function memThreads() {
483
+ const jsonMode = hasFlag(process.argv, "--json");
484
+ const projectPath = hasFlag(process.argv, "--global") ? undefined : getCurrentProjectRoot();
485
+ const db = openMemoryDb();
486
+ const list = listThreads(db, { projectPath });
487
+ db.close();
488
+ if (jsonMode) {
489
+ console.log(JSON.stringify(list));
490
+ return true;
491
+ }
492
+ if (!list.length) {
493
+ console.log(`${c.dim}no saved copilots${projectPath ? ` in ${projectPath}` : ""}${c.reset}`);
494
+ return true;
495
+ }
496
+ const scope = projectPath ? `${c.dim}in ${projectPath}${c.reset}` : `${c.dim}(global)${c.reset}`;
497
+ console.log(`${c.bold}${list.length}${c.reset} saved copilot(s) ${scope}:`);
498
+ list.forEach((t, i) => {
499
+ console.log(` ${c.bold}${i + 1}${c.reset}. ${t.name} ${c.dim}${t.session_id}${c.reset}`);
500
+ });
501
+ console.log(`${c.dim}resume with: kit memory resume <name|number>${c.reset}`);
502
+ return true;
503
+ }
504
+ async function memResume() {
505
+ const ref = process.argv[4];
506
+ if (!ref) {
507
+ console.error(`${c.red}usage: kit memory resume <name|number>${c.reset}`);
508
+ return false;
509
+ }
510
+ const projectPath = hasFlag(process.argv, "--global") ? undefined : getCurrentProjectRoot();
511
+ const db = openMemoryDb();
512
+ const t = resolveThread(db, ref, { projectPath });
513
+ db.close();
514
+ if (!t) {
515
+ console.error(`${c.red}no saved copilot '${ref}'${c.reset}`);
516
+ return false;
517
+ }
518
+ console.log(`${c.bold}${t.name}${c.reset} — run:`);
519
+ console.log(` claude --resume ${t.session_id}`);
520
+ return true;
521
+ }
522
+ async function memForget() {
523
+ const name = process.argv.slice(4).filter((a) => !a.startsWith("--")).join(" ").trim();
524
+ if (!name) {
525
+ console.error(`${c.red}usage: kit memory forget <name>${c.reset}`);
526
+ return false;
527
+ }
528
+ const db = openMemoryDb();
529
+ const ok = removeThread(db, name);
530
+ db.close();
531
+ console.log(ok ? `${c.green}✓${c.reset} forgot ${name}` : `${c.dim}no copilot '${name}'${c.reset}`);
532
+ return true;
533
+ }
534
+ //# sourceMappingURL=memory.js.map