@ulrichc1/sparn 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -381,7 +381,8 @@ var init_config = __esm({
381
381
  logFile: ".sparn/daemon.log",
382
382
  debounceMs: 5e3,
383
383
  incremental: true,
384
- windowSize: 500
384
+ windowSize: 500,
385
+ consolidationInterval: null
385
386
  }
386
387
  };
387
388
  }
@@ -944,16 +945,16 @@ __export(optimize_exports, {
944
945
  });
945
946
  async function optimizeCommand(options) {
946
947
  const { memory, dryRun = false, verbose = false } = options;
947
- let input;
948
+ let input2;
948
949
  if (options.inputFile) {
949
- input = await (0, import_promises2.readFile)(options.inputFile, "utf-8");
950
+ input2 = await (0, import_promises2.readFile)(options.inputFile, "utf-8");
950
951
  } else if (options.input) {
951
- input = options.input;
952
+ input2 = options.input;
952
953
  } else {
953
954
  throw new Error("No input provided. Use --input or --input-file");
954
955
  }
955
956
  const adapter = createGenericAdapter(memory, DEFAULT_CONFIG);
956
- const result = await adapter.optimize(input, { dryRun, verbose });
957
+ const result = await adapter.optimize(input2, { dryRun, verbose });
957
958
  if (options.outputFile) {
958
959
  await (0, import_promises2.writeFile)(options.outputFile, result.optimizedContext, "utf-8");
959
960
  }
@@ -1085,7 +1086,7 @@ async function relayCommand(options) {
1085
1086
  return result;
1086
1087
  }
1087
1088
  function executeCommand(command, args) {
1088
- return new Promise((resolve2) => {
1089
+ return new Promise((resolve3) => {
1089
1090
  const child = (0, import_node_child_process.spawn)(command, args, {
1090
1091
  stdio: ["ignore", "pipe", "pipe"]
1091
1092
  });
@@ -1098,14 +1099,14 @@ function executeCommand(command, args) {
1098
1099
  stderr += data.toString();
1099
1100
  });
1100
1101
  child.on("close", (code) => {
1101
- resolve2({
1102
+ resolve3({
1102
1103
  stdout,
1103
1104
  stderr,
1104
1105
  exitCode: code ?? 0
1105
1106
  });
1106
1107
  });
1107
1108
  child.on("error", (error) => {
1108
- resolve2({
1109
+ resolve3({
1109
1110
  stdout,
1110
1111
  stderr: error.message,
1111
1112
  exitCode: 1
@@ -1765,7 +1766,7 @@ function createDaemonCommand() {
1765
1766
  while (waited < maxWait) {
1766
1767
  try {
1767
1768
  process.kill(status2.pid, 0);
1768
- await new Promise((resolve2) => setTimeout(resolve2, interval));
1769
+ await new Promise((resolve3) => setTimeout(resolve3, interval));
1769
1770
  waited += interval;
1770
1771
  } catch {
1771
1772
  removePidFile(pidFile);
@@ -1891,8 +1892,8 @@ async function installHooks(settingsPath, prePromptPath, postToolResultPath, glo
1891
1892
  }
1892
1893
  settings["hooks"] = {
1893
1894
  ...typeof settings["hooks"] === "object" && settings["hooks"] !== null ? settings["hooks"] : {},
1894
- "pre-prompt": `node ${prePromptPath}`,
1895
- "post-tool-result": `node ${postToolResultPath}`
1895
+ prePrompt: `node ${prePromptPath}`,
1896
+ postToolResult: `node ${postToolResultPath}`
1896
1897
  };
1897
1898
  (0, import_node_fs5.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
1898
1899
  return {
@@ -1925,8 +1926,8 @@ async function uninstallHooks(settingsPath, global) {
1925
1926
  const settings = JSON.parse(settingsJson);
1926
1927
  if (settings["hooks"] && typeof settings["hooks"] === "object" && settings["hooks"] !== null) {
1927
1928
  const hooks = settings["hooks"];
1928
- delete hooks["pre-prompt"];
1929
- delete hooks["post-tool-result"];
1929
+ delete hooks["prePrompt"];
1930
+ delete hooks["postToolResult"];
1930
1931
  if (Object.keys(hooks).length === 0) {
1931
1932
  delete settings["hooks"];
1932
1933
  }
@@ -1956,7 +1957,7 @@ async function hooksStatus(settingsPath, global) {
1956
1957
  }
1957
1958
  const settingsJson = (0, import_node_fs5.readFileSync)(settingsPath, "utf-8");
1958
1959
  const settings = JSON.parse(settingsJson);
1959
- const hasHooks = settings["hooks"] && typeof settings["hooks"] === "object" && settings["hooks"] !== null && "pre-prompt" in settings["hooks"] && "post-tool-result" in settings["hooks"];
1960
+ const hasHooks = settings["hooks"] && typeof settings["hooks"] === "object" && settings["hooks"] !== null && "prePrompt" in settings["hooks"] && "postToolResult" in settings["hooks"];
1960
1961
  if (!hasHooks) {
1961
1962
  return {
1962
1963
  success: true,
@@ -1970,8 +1971,8 @@ async function hooksStatus(settingsPath, global) {
1970
1971
  message: global ? "Global hooks active" : "Project hooks active",
1971
1972
  installed: true,
1972
1973
  hookPaths: {
1973
- prePrompt: hooks["pre-prompt"] || "",
1974
- postToolResult: hooks["post-tool-result"] || ""
1974
+ prePrompt: hooks["prePrompt"] || "",
1975
+ postToolResult: hooks["postToolResult"] || ""
1975
1976
  }
1976
1977
  };
1977
1978
  } catch (error) {
@@ -1994,22 +1995,527 @@ var init_hooks = __esm({
1994
1995
  }
1995
1996
  });
1996
1997
 
1998
+ // src/cli/commands/interactive.ts
1999
+ var interactive_exports = {};
2000
+ __export(interactive_exports, {
2001
+ interactiveCommand: () => interactiveCommand
2002
+ });
2003
+ function showWelcomeBanner() {
2004
+ console.log(brainPink("\n\u2501".repeat(60)));
2005
+ console.log(brainPink(" \u{1F9E0} Sparn Interactive Mode"));
2006
+ console.log(brainPink("\u2501".repeat(60)));
2007
+ console.log(dim(" Conversational configuration and exploration\n"));
2008
+ }
2009
+ async function showMainMenu() {
2010
+ return (0, import_prompts.select)({
2011
+ message: "What would you like to do?",
2012
+ choices: [
2013
+ {
2014
+ name: "\u2699\uFE0F Configure Settings",
2015
+ value: "configure",
2016
+ description: "Guided configuration wizard"
2017
+ },
2018
+ {
2019
+ name: "\u{1F50D} Optimize Preview",
2020
+ value: "preview",
2021
+ description: "Preview optimization with confirmation"
2022
+ },
2023
+ {
2024
+ name: "\u{1F4CA} Stats Dashboard",
2025
+ value: "stats",
2026
+ description: "View metrics and performance data"
2027
+ },
2028
+ {
2029
+ name: "\u{1F9F9} Memory Consolidation",
2030
+ value: "consolidate",
2031
+ description: "Clean up decayed entries and duplicates"
2032
+ },
2033
+ {
2034
+ name: "\u{1F680} Quick Actions",
2035
+ value: "quick",
2036
+ description: "Common tasks and shortcuts"
2037
+ },
2038
+ {
2039
+ name: "\u274C Exit",
2040
+ value: "exit",
2041
+ description: "Return to shell"
2042
+ }
2043
+ ]
2044
+ });
2045
+ }
2046
+ async function configureWizard(configPath) {
2047
+ console.log(neuralCyan("\n\u{1F4DD} Configuration Wizard\n"));
2048
+ const configYAML = (0, import_node_fs6.readFileSync)(configPath, "utf-8");
2049
+ const config = (0, import_js_yaml3.load)(configYAML);
2050
+ const section = await (0, import_prompts.select)({
2051
+ message: "Which settings would you like to configure?",
2052
+ choices: [
2053
+ { name: "\u{1F52A} Pruning (Sparse Coding)", value: "pruning" },
2054
+ { name: "\u23F3 Decay (Engram Theory)", value: "decay" },
2055
+ { name: "\u{1F3AF} States (Multi-State Synapses)", value: "states" },
2056
+ { name: "\u26A1 Real-time Optimization", value: "realtime" },
2057
+ { name: "\u{1F3A8} UI Preferences", value: "ui" },
2058
+ { name: "\u2190 Back to Main Menu", value: "back" }
2059
+ ]
2060
+ });
2061
+ if (section === "back") return;
2062
+ switch (section) {
2063
+ case "pruning": {
2064
+ console.log(synapseViolet("\n\u{1F52A} Pruning Configuration"));
2065
+ console.log(dim("Sparse coding: Keep only the most relevant context\n"));
2066
+ const threshold = await (0, import_prompts.number)({
2067
+ message: "Pruning threshold (percentage of entries to keep):",
2068
+ default: config.pruning.threshold,
2069
+ min: 1,
2070
+ max: 100
2071
+ });
2072
+ const aggressiveness = await (0, import_prompts.number)({
2073
+ message: "Aggressiveness (0-100, affects TF-IDF weighting):",
2074
+ default: config.pruning.aggressiveness,
2075
+ min: 0,
2076
+ max: 100
2077
+ });
2078
+ config.pruning.threshold = threshold ?? config.pruning.threshold;
2079
+ config.pruning.aggressiveness = aggressiveness ?? config.pruning.aggressiveness;
2080
+ console.log(neuralCyan("\n\u2713 Pruning settings updated"));
2081
+ break;
2082
+ }
2083
+ case "decay": {
2084
+ console.log(synapseViolet("\n\u23F3 Decay Configuration"));
2085
+ console.log(dim("Engram theory: Apply time-based decay to memories\n"));
2086
+ const defaultTTL = await (0, import_prompts.number)({
2087
+ message: "Default TTL in hours:",
2088
+ default: config.decay.defaultTTL,
2089
+ min: 1
2090
+ });
2091
+ const decayThreshold = await (0, import_prompts.number)({
2092
+ message: "Decay threshold (0.0-1.0, entries below this are pruned):",
2093
+ default: config.decay.decayThreshold,
2094
+ min: 0,
2095
+ max: 1,
2096
+ step: 0.05
2097
+ });
2098
+ config.decay.defaultTTL = defaultTTL ?? config.decay.defaultTTL;
2099
+ config.decay.decayThreshold = decayThreshold ?? config.decay.decayThreshold;
2100
+ console.log(neuralCyan("\n\u2713 Decay settings updated"));
2101
+ break;
2102
+ }
2103
+ case "states": {
2104
+ console.log(synapseViolet("\n\u{1F3AF} State Threshold Configuration"));
2105
+ console.log(dim("Multi-state synapses: Classify entries as active/ready/silent\n"));
2106
+ const activeThreshold = await (0, import_prompts.number)({
2107
+ message: "Active state threshold (0.0-1.0):",
2108
+ default: config.states.activeThreshold,
2109
+ min: 0,
2110
+ max: 1,
2111
+ step: 0.05
2112
+ });
2113
+ const readyThreshold = await (0, import_prompts.number)({
2114
+ message: "Ready state threshold (0.0-1.0):",
2115
+ default: config.states.readyThreshold,
2116
+ min: 0,
2117
+ max: 1,
2118
+ step: 0.05
2119
+ });
2120
+ config.states.activeThreshold = activeThreshold ?? config.states.activeThreshold;
2121
+ config.states.readyThreshold = readyThreshold ?? config.states.readyThreshold;
2122
+ console.log(neuralCyan("\n\u2713 State settings updated"));
2123
+ break;
2124
+ }
2125
+ case "realtime": {
2126
+ console.log(synapseViolet("\n\u26A1 Real-time Optimization Configuration"));
2127
+ console.log(dim("Daemon settings for automatic optimization\n"));
2128
+ const tokenBudget = await (0, import_prompts.number)({
2129
+ message: "Target token budget:",
2130
+ default: config.realtime.tokenBudget,
2131
+ min: 1e3
2132
+ });
2133
+ const autoOptimizeThreshold = await (0, import_prompts.number)({
2134
+ message: "Auto-optimize threshold (triggers optimization):",
2135
+ default: config.realtime.autoOptimizeThreshold,
2136
+ min: 1e3
2137
+ });
2138
+ const windowSize = await (0, import_prompts.number)({
2139
+ message: "Sliding window size (entries):",
2140
+ default: config.realtime.windowSize,
2141
+ min: 100
2142
+ });
2143
+ const incremental = await (0, import_prompts.confirm)({
2144
+ message: "Enable incremental optimization (faster delta processing)?",
2145
+ default: config.realtime.incremental
2146
+ });
2147
+ config.realtime.tokenBudget = tokenBudget ?? config.realtime.tokenBudget;
2148
+ config.realtime.autoOptimizeThreshold = autoOptimizeThreshold ?? config.realtime.autoOptimizeThreshold;
2149
+ config.realtime.windowSize = windowSize ?? config.realtime.windowSize;
2150
+ config.realtime.incremental = incremental;
2151
+ console.log(neuralCyan("\n\u2713 Real-time settings updated"));
2152
+ break;
2153
+ }
2154
+ case "ui": {
2155
+ console.log(synapseViolet("\n\u{1F3A8} UI Preferences"));
2156
+ console.log(dim("Customize terminal output\n"));
2157
+ const colors = await (0, import_prompts.confirm)({
2158
+ message: "Enable colored output?",
2159
+ default: config.ui.colors
2160
+ });
2161
+ const verbose = await (0, import_prompts.confirm)({
2162
+ message: "Enable verbose logging?",
2163
+ default: config.ui.verbose
2164
+ });
2165
+ config.ui.colors = colors;
2166
+ config.ui.verbose = verbose;
2167
+ console.log(neuralCyan("\n\u2713 UI settings updated"));
2168
+ break;
2169
+ }
2170
+ }
2171
+ const updatedYAML = (0, import_js_yaml3.dump)(config);
2172
+ (0, import_node_fs6.writeFileSync)(configPath, updatedYAML, "utf-8");
2173
+ console.log(neuralCyan(`
2174
+ \u{1F4BE} Configuration saved to ${configPath}
2175
+ `));
2176
+ }
2177
+ async function optimizePreview(memory) {
2178
+ console.log(neuralCyan("\n\u{1F50D} Optimization Preview\n"));
2179
+ const inputFile = await (0, import_prompts.input)({
2180
+ message: "Input file path (or press Enter to skip):",
2181
+ default: ""
2182
+ });
2183
+ if (!inputFile) {
2184
+ console.log(dim("\nNo file specified. Returning to menu.\n"));
2185
+ return;
2186
+ }
2187
+ try {
2188
+ const content = (0, import_node_fs6.readFileSync)((0, import_node_path4.resolve)(process.cwd(), inputFile), "utf-8");
2189
+ const tokensBefore = Math.ceil(content.length / 4);
2190
+ console.log(synapseViolet("\n\u{1F4C4} File Preview:"));
2191
+ console.log(dim(` Length: ${content.length} characters`));
2192
+ console.log(dim(` Estimated tokens: ${tokensBefore.toLocaleString()}
2193
+ `));
2194
+ const shouldOptimize = await (0, import_prompts.confirm)({
2195
+ message: "Proceed with optimization?",
2196
+ default: true
2197
+ });
2198
+ if (!shouldOptimize) {
2199
+ console.log(dim("\nOptimization cancelled.\n"));
2200
+ return;
2201
+ }
2202
+ console.log(neuralCyan("\n\u26A1 Optimizing...\n"));
2203
+ const { optimizeCommand: optimizeCommand2 } = await Promise.resolve().then(() => (init_optimize(), optimize_exports));
2204
+ const result = await optimizeCommand2({
2205
+ inputFile,
2206
+ memory,
2207
+ dryRun: false,
2208
+ verbose: false
2209
+ });
2210
+ console.log(neuralCyan(`
2211
+ \u2713 Optimization complete in ${result.durationMs}ms!`));
2212
+ console.log(synapseViolet(` Tokens: ${result.tokensBefore} \u2192 ${result.tokensAfter}`));
2213
+ console.log(
2214
+ brainPink(
2215
+ ` Saved: ${result.tokensBefore - result.tokensAfter} tokens (${(result.reduction * 100).toFixed(1)}%)
2216
+ `
2217
+ )
2218
+ );
2219
+ const saveOutput = await (0, import_prompts.confirm)({
2220
+ message: "Save optimized output to file?",
2221
+ default: false
2222
+ });
2223
+ if (saveOutput) {
2224
+ const outputFile = await (0, import_prompts.input)({
2225
+ message: "Output file path:",
2226
+ default: inputFile.replace(/(\.[^.]+)$/, ".optimized$1")
2227
+ });
2228
+ (0, import_node_fs6.writeFileSync)((0, import_node_path4.resolve)(process.cwd(), outputFile), result.output, "utf-8");
2229
+ console.log(neuralCyan(`
2230
+ \u{1F4BE} Saved to ${outputFile}
2231
+ `));
2232
+ }
2233
+ } catch (error) {
2234
+ console.error(errorRed("\n\u2717 Error:"), error instanceof Error ? error.message : String(error));
2235
+ console.log();
2236
+ }
2237
+ }
2238
+ async function showStatsDashboard(memory) {
2239
+ console.log(neuralCyan("\n\u{1F4CA} Stats Dashboard\n"));
2240
+ const view = await (0, import_prompts.select)({
2241
+ message: "Select view:",
2242
+ choices: [
2243
+ { name: "\u{1F4C8} Optimization History", value: "history" },
2244
+ { name: "\u26A1 Real-time Metrics", value: "realtime" },
2245
+ { name: "\u{1F4BE} Memory Statistics", value: "memory" },
2246
+ { name: "\u2190 Back to Main Menu", value: "back" }
2247
+ ]
2248
+ });
2249
+ if (view === "back") return;
2250
+ switch (view) {
2251
+ case "history": {
2252
+ const stats = await memory.getOptimizationStats();
2253
+ const totalRuns = stats.length;
2254
+ const totalTokensSaved = stats.reduce(
2255
+ (sum, s) => sum + (s.tokens_before - s.tokens_after),
2256
+ 0
2257
+ );
2258
+ const avgReduction = totalRuns > 0 ? stats.reduce((sum, s) => {
2259
+ return sum + (s.tokens_before > 0 ? (s.tokens_before - s.tokens_after) / s.tokens_before : 0);
2260
+ }, 0) / totalRuns : 0;
2261
+ console.log(brainPink("\n\u2501".repeat(60)));
2262
+ console.log(neuralCyan(" \u{1F4C8} Optimization History"));
2263
+ console.log(brainPink("\u2501".repeat(60)));
2264
+ console.log(` ${synapseViolet("Total runs:")} ${totalRuns.toLocaleString()}`);
2265
+ console.log(` ${synapseViolet("Tokens saved:")} ${totalTokensSaved.toLocaleString()}`);
2266
+ console.log(` ${synapseViolet("Avg reduction:")} ${(avgReduction * 100).toFixed(1)}%`);
2267
+ if (totalRuns > 0) {
2268
+ console.log(`
2269
+ ${dim("Recent optimizations:")}`);
2270
+ const recent = stats.slice(0, 5);
2271
+ for (const stat of recent) {
2272
+ const date = new Date(stat.timestamp).toLocaleString();
2273
+ const reduction = stat.tokens_before > 0 ? (stat.tokens_before - stat.tokens_after) / stat.tokens_before * 100 : 0;
2274
+ console.log(` ${dim(date)} - ${neuralCyan(`${reduction.toFixed(1)}%`)} reduction`);
2275
+ }
2276
+ }
2277
+ console.log(brainPink(`${"\u2501".repeat(60)}
2278
+ `));
2279
+ break;
2280
+ }
2281
+ case "realtime": {
2282
+ const metrics = getMetrics();
2283
+ const snapshot = metrics.getSnapshot();
2284
+ console.log(brainPink("\n\u2501".repeat(60)));
2285
+ console.log(neuralCyan(" \u26A1 Real-time Metrics"));
2286
+ console.log(brainPink("\u2501".repeat(60)));
2287
+ console.log(
2288
+ ` ${synapseViolet("Total runs:")} ${snapshot.optimization.totalRuns.toLocaleString()}`
2289
+ );
2290
+ console.log(
2291
+ ` ${synapseViolet("Tokens saved:")} ${snapshot.optimization.totalTokensSaved.toLocaleString()}`
2292
+ );
2293
+ console.log(
2294
+ ` ${synapseViolet("Avg reduction:")} ${(snapshot.optimization.averageReduction * 100).toFixed(1)}%`
2295
+ );
2296
+ console.log(
2297
+ ` ${synapseViolet("P50 latency:")} ${snapshot.optimization.p50Latency.toFixed(0)}ms`
2298
+ );
2299
+ console.log(
2300
+ ` ${synapseViolet("P95 latency:")} ${snapshot.optimization.p95Latency.toFixed(0)}ms`
2301
+ );
2302
+ console.log(
2303
+ ` ${synapseViolet("P99 latency:")} ${snapshot.optimization.p99Latency.toFixed(0)}ms`
2304
+ );
2305
+ console.log(
2306
+ `
2307
+ ${synapseViolet("Cache hit rate:")} ${(snapshot.cache.hitRate * 100).toFixed(1)}%`
2308
+ );
2309
+ console.log(
2310
+ ` ${synapseViolet("Cache hits:")} ${snapshot.cache.totalHits.toLocaleString()}`
2311
+ );
2312
+ console.log(
2313
+ ` ${synapseViolet("Cache misses:")} ${snapshot.cache.totalMisses.toLocaleString()}`
2314
+ );
2315
+ console.log(brainPink(`${"\u2501".repeat(60)}
2316
+ `));
2317
+ break;
2318
+ }
2319
+ case "memory": {
2320
+ const entries = await memory.query({});
2321
+ const totalEntries = entries.length;
2322
+ const totalSize = entries.reduce((sum, e) => sum + (e.content?.length || 0), 0);
2323
+ console.log(brainPink("\n\u2501".repeat(60)));
2324
+ console.log(neuralCyan(" \u{1F4BE} Memory Statistics"));
2325
+ console.log(brainPink("\u2501".repeat(60)));
2326
+ console.log(` ${synapseViolet("Total entries:")} ${totalEntries.toLocaleString()}`);
2327
+ console.log(` ${synapseViolet("Total size:")} ${(totalSize / 1024).toFixed(1)} KB`);
2328
+ console.log(
2329
+ ` ${synapseViolet("Avg entry size:")} ${totalEntries > 0 ? (totalSize / totalEntries).toFixed(0) : 0} bytes`
2330
+ );
2331
+ console.log(brainPink(`${"\u2501".repeat(60)}
2332
+ `));
2333
+ break;
2334
+ }
2335
+ }
2336
+ }
2337
+ async function consolidateMemory(memory) {
2338
+ console.log(neuralCyan("\n\u{1F9F9} Memory Consolidation\n"));
2339
+ console.log(dim("This will:"));
2340
+ console.log(dim(" \u2022 Remove decayed entries"));
2341
+ console.log(dim(" \u2022 Merge duplicate entries"));
2342
+ console.log(dim(" \u2022 VACUUM database to reclaim space\n"));
2343
+ const shouldConsolidate = await (0, import_prompts.confirm)({
2344
+ message: "Proceed with consolidation?",
2345
+ default: true
2346
+ });
2347
+ if (!shouldConsolidate) {
2348
+ console.log(dim("\nConsolidation cancelled.\n"));
2349
+ return;
2350
+ }
2351
+ const { consolidateCommand: consolidateCommand2 } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
2352
+ console.log(neuralCyan("\n\u26A1 Consolidating...\n"));
2353
+ const result = await consolidateCommand2({ memory });
2354
+ console.log(neuralCyan(`
2355
+ \u2713 Consolidation complete in ${result.durationMs}ms!`));
2356
+ console.log(synapseViolet(` Entries: ${result.entriesBefore} \u2192 ${result.entriesAfter}`));
2357
+ console.log(
2358
+ brainPink(
2359
+ ` Removed: ${result.decayedRemoved} decayed, ${result.duplicatesRemoved} duplicates
2360
+ `
2361
+ )
2362
+ );
2363
+ }
2364
+ async function showQuickActions(memory, configPath) {
2365
+ const action = await (0, import_prompts.select)({
2366
+ message: "Quick Actions:",
2367
+ choices: [
2368
+ { name: "\u{1F504} Reset Statistics", value: "reset-stats" },
2369
+ { name: "\u{1F4CB} Export Config (JSON)", value: "export-config" },
2370
+ { name: "\u{1F9EA} Run Test Optimization", value: "test-optimize" },
2371
+ { name: "\u2190 Back to Main Menu", value: "back" }
2372
+ ]
2373
+ });
2374
+ if (action === "back") return;
2375
+ switch (action) {
2376
+ case "reset-stats": {
2377
+ const confirmReset = await (0, import_prompts.confirm)({
2378
+ message: "Are you sure you want to reset all statistics?",
2379
+ default: false
2380
+ });
2381
+ if (confirmReset) {
2382
+ await memory.clearOptimizationStats();
2383
+ console.log(neuralCyan("\n\u2713 Statistics cleared\n"));
2384
+ } else {
2385
+ console.log(dim("\nReset cancelled.\n"));
2386
+ }
2387
+ break;
2388
+ }
2389
+ case "export-config": {
2390
+ const configYAML = (0, import_node_fs6.readFileSync)(configPath, "utf-8");
2391
+ const config = (0, import_js_yaml3.load)(configYAML);
2392
+ const json = JSON.stringify(config, null, 2);
2393
+ console.log(synapseViolet("\n\u{1F4CB} Configuration (JSON):\n"));
2394
+ console.log(json);
2395
+ console.log();
2396
+ const shouldSave = await (0, import_prompts.confirm)({
2397
+ message: "Save to file?",
2398
+ default: false
2399
+ });
2400
+ if (shouldSave) {
2401
+ const outputPath = (0, import_node_path4.resolve)(configPath.replace(/\.yaml$/, ".json"));
2402
+ (0, import_node_fs6.writeFileSync)(outputPath, json, "utf-8");
2403
+ console.log(neuralCyan(`
2404
+ \u{1F4BE} Saved to ${outputPath}
2405
+ `));
2406
+ }
2407
+ break;
2408
+ }
2409
+ case "test-optimize": {
2410
+ console.log(neuralCyan("\n\u{1F9EA} Running test optimization...\n"));
2411
+ const testContent = `
2412
+ # Test Context
2413
+
2414
+ This is a test context for optimization.
2415
+ It includes some sample content to demonstrate the optimization process.
2416
+
2417
+ ## Features
2418
+ - Token counting
2419
+ - Sparse coding
2420
+ - Decay application
2421
+ - State classification
2422
+ `.trim();
2423
+ const { optimizeCommand: optimizeCommand2 } = await Promise.resolve().then(() => (init_optimize(), optimize_exports));
2424
+ const result = await optimizeCommand2({
2425
+ input: testContent,
2426
+ memory,
2427
+ dryRun: true,
2428
+ verbose: false
2429
+ });
2430
+ console.log(neuralCyan(`
2431
+ \u2713 Test optimization complete in ${result.durationMs}ms!`));
2432
+ console.log(synapseViolet(` Tokens: ${result.tokensBefore} \u2192 ${result.tokensAfter}`));
2433
+ console.log(
2434
+ brainPink(
2435
+ ` Saved: ${result.tokensBefore - result.tokensAfter} tokens (${(result.reduction * 100).toFixed(1)}%)
2436
+ `
2437
+ )
2438
+ );
2439
+ break;
2440
+ }
2441
+ }
2442
+ }
2443
+ async function interactiveCommand(options) {
2444
+ const { memory, configPath } = options;
2445
+ showWelcomeBanner();
2446
+ let running = true;
2447
+ while (running) {
2448
+ try {
2449
+ const choice = await showMainMenu();
2450
+ switch (choice) {
2451
+ case "configure":
2452
+ await configureWizard(configPath);
2453
+ break;
2454
+ case "preview":
2455
+ await optimizePreview(memory);
2456
+ break;
2457
+ case "stats":
2458
+ await showStatsDashboard(memory);
2459
+ break;
2460
+ case "consolidate":
2461
+ await consolidateMemory(memory);
2462
+ break;
2463
+ case "quick":
2464
+ await showQuickActions(memory, configPath);
2465
+ break;
2466
+ case "exit":
2467
+ running = false;
2468
+ console.log(brainPink("\n\u{1F44B} Thanks for using Sparn!\n"));
2469
+ break;
2470
+ }
2471
+ } catch (error) {
2472
+ if (error.message === "User force closed the prompt") {
2473
+ running = false;
2474
+ console.log(brainPink("\n\u{1F44B} Thanks for using Sparn!\n"));
2475
+ } else {
2476
+ console.error(
2477
+ errorRed("\n\u2717 Error:"),
2478
+ error instanceof Error ? error.message : String(error)
2479
+ );
2480
+ console.log();
2481
+ }
2482
+ }
2483
+ }
2484
+ return {
2485
+ success: true,
2486
+ message: "Interactive session completed"
2487
+ };
2488
+ }
2489
+ var import_node_fs6, import_node_path4, import_prompts, import_js_yaml3;
2490
+ var init_interactive = __esm({
2491
+ "src/cli/commands/interactive.ts"() {
2492
+ "use strict";
2493
+ init_cjs_shims();
2494
+ import_node_fs6 = require("fs");
2495
+ import_node_path4 = require("path");
2496
+ import_prompts = require("@inquirer/prompts");
2497
+ import_js_yaml3 = require("js-yaml");
2498
+ init_metrics();
2499
+ init_colors();
2500
+ }
2501
+ });
2502
+
1997
2503
  // src/cli/index.ts
1998
2504
  init_cjs_shims();
1999
2505
  var import_node_child_process3 = require("child_process");
2000
- var import_node_fs6 = require("fs");
2001
- var import_node_path4 = require("path");
2506
+ var import_node_fs7 = require("fs");
2507
+ var import_node_path5 = require("path");
2002
2508
  var import_node_url4 = require("url");
2003
2509
  var import_commander = require("commander");
2004
2510
  init_banner();
2005
2511
  function getVersion2() {
2006
2512
  try {
2007
- const pkg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path4.join)(process.cwd(), "package.json"), "utf-8"));
2513
+ const pkg = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path5.join)(process.cwd(), "package.json"), "utf-8"));
2008
2514
  return pkg.version;
2009
2515
  } catch {
2010
2516
  const __filename2 = (0, import_node_url4.fileURLToPath)(importMetaUrl);
2011
- const __dirname = (0, import_node_path4.dirname)(__filename2);
2012
- const pkg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path4.join)(__dirname, "../../package.json"), "utf-8"));
2517
+ const __dirname = (0, import_node_path5.dirname)(__filename2);
2518
+ const pkg = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path5.join)(__dirname, "../../package.json"), "utf-8"));
2013
2519
  return pkg.version;
2014
2520
  }
2015
2521
  }
@@ -2118,23 +2624,23 @@ Typical Results:
2118
2624
  const spinner = createOptimizeSpinner2("\u{1F9E0} Initializing optimization...");
2119
2625
  try {
2120
2626
  spinner.start();
2121
- let input;
2627
+ let input2;
2122
2628
  if (!options.input && process.stdin.isTTY === false) {
2123
2629
  spinner.text = "\u{1F4D6} Reading context from stdin...";
2124
2630
  const chunks = [];
2125
2631
  for await (const chunk of process.stdin) {
2126
2632
  chunks.push(chunk);
2127
2633
  }
2128
- input = Buffer.concat(chunks).toString("utf-8");
2634
+ input2 = Buffer.concat(chunks).toString("utf-8");
2129
2635
  } else if (options.input) {
2130
2636
  spinner.text = `\u{1F4D6} Reading context from ${options.input}...`;
2131
2637
  }
2132
2638
  spinner.text = "\u{1F4BE} Loading memory database...";
2133
- const dbPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/memory.db");
2639
+ const dbPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/memory.db");
2134
2640
  const memory = await createKVMemory2(dbPath);
2135
2641
  spinner.text = "\u26A1 Applying neuroscience principles...";
2136
2642
  const result = await optimizeCommand2({
2137
- input,
2643
+ input: input2,
2138
2644
  inputFile: options.input,
2139
2645
  outputFile: options.output,
2140
2646
  memory,
@@ -2194,7 +2700,7 @@ Tracked Metrics:
2194
2700
  try {
2195
2701
  if (spinner) spinner.start();
2196
2702
  if (spinner) spinner.text = "\u{1F4BE} Loading optimization history...";
2197
- const dbPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/memory.db");
2703
+ const dbPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/memory.db");
2198
2704
  const memory = await createKVMemory2(dbPath);
2199
2705
  let confirmReset = false;
2200
2706
  if (options.reset) {
@@ -2254,7 +2760,7 @@ The relay command passes the exit code from the wrapped command.
2254
2760
  const { relayCommand: relayCommand2 } = await Promise.resolve().then(() => (init_relay(), relay_exports));
2255
2761
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2256
2762
  try {
2257
- const dbPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/memory.db");
2763
+ const dbPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/memory.db");
2258
2764
  const memory = await createKVMemory2(dbPath);
2259
2765
  const result = await relayCommand2({
2260
2766
  command,
@@ -2307,7 +2813,7 @@ Typical Results:
2307
2813
  try {
2308
2814
  spinner.start();
2309
2815
  spinner.text = "\u{1F4BE} Loading memory database...";
2310
- const dbPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/memory.db");
2816
+ const dbPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/memory.db");
2311
2817
  const memory = await createKVMemory2(dbPath);
2312
2818
  spinner.text = "\u{1F50D} Identifying decayed entries...";
2313
2819
  const result = await consolidateCommand2({ memory });
@@ -2355,7 +2861,7 @@ The config file is located at .sparn/config.yaml
2355
2861
  const { configCommand: configCommand2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
2356
2862
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2357
2863
  try {
2358
- const configPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/config.yaml");
2864
+ const configPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/config.yaml");
2359
2865
  const result = await configCommand2({
2360
2866
  configPath,
2361
2867
  subcommand,
@@ -2410,13 +2916,13 @@ The daemon watches ~/.claude/projects/**/*.jsonl and automatically
2410
2916
  optimizes contexts when they exceed the configured threshold.
2411
2917
  `
2412
2918
  ).action(async (subcommand) => {
2413
- const { load: parseYAML2 } = await import("js-yaml");
2919
+ const { load: parseYAML3 } = await import("js-yaml");
2414
2920
  const { createDaemonCommand: createDaemonCommand2 } = await Promise.resolve().then(() => (init_daemon_process(), daemon_process_exports));
2415
2921
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2416
2922
  try {
2417
- const configPath = (0, import_node_path4.resolve)(process.cwd(), ".sparn/config.yaml");
2418
- const configYAML = (0, import_node_fs6.readFileSync)(configPath, "utf-8");
2419
- const config = parseYAML2(configYAML);
2923
+ const configPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/config.yaml");
2924
+ const configYAML = (0, import_node_fs7.readFileSync)(configPath, "utf-8");
2925
+ const config = parseYAML3(configYAML);
2420
2926
  const daemon = createDaemonCommand2();
2421
2927
  switch (subcommand) {
2422
2928
  case "start": {
@@ -2526,6 +3032,41 @@ and compress verbose tool results after execution.
2526
3032
  process.exit(1);
2527
3033
  }
2528
3034
  });
3035
+ program.command("interactive").alias("i").description("Launch interactive mode for configuration and exploration").addHelpText(
3036
+ "after",
3037
+ `
3038
+ Examples:
3039
+ $ sparn interactive # Launch interactive mode
3040
+ $ sparn i # Short alias
3041
+
3042
+ Features:
3043
+ \u2022 \u{1F4DD} Configuration Wizard - Guided prompts for all settings
3044
+ \u2022 \u{1F50D} Optimization Preview - Test optimization with file preview
3045
+ \u2022 \u{1F4CA} Stats Dashboard - Beautiful metrics display
3046
+ \u2022 \u{1F9F9} Memory Consolidation - Interactive cleanup
3047
+ \u2022 \u{1F680} Quick Actions - Common tasks and shortcuts
3048
+
3049
+ The interactive mode provides a conversational interface for exploring
3050
+ and configuring Sparn without memorizing CLI flags.
3051
+ `
3052
+ ).action(async () => {
3053
+ const { createKVMemory: createKVMemory2 } = await Promise.resolve().then(() => (init_kv_memory(), kv_memory_exports));
3054
+ const { interactiveCommand: interactiveCommand2 } = await Promise.resolve().then(() => (init_interactive(), interactive_exports));
3055
+ const { errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
3056
+ try {
3057
+ const dbPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/memory.db");
3058
+ const memory = await createKVMemory2(dbPath);
3059
+ const configPath = (0, import_node_path5.resolve)(process.cwd(), ".sparn/config.yaml");
3060
+ await interactiveCommand2({
3061
+ memory,
3062
+ configPath
3063
+ });
3064
+ await memory.close();
3065
+ } catch (error) {
3066
+ console.error(errorRed2("Error:"), error instanceof Error ? error.message : String(error));
3067
+ process.exit(1);
3068
+ }
3069
+ });
2529
3070
  program.on("option:version", () => {
2530
3071
  console.log(getBanner(VERSION2));
2531
3072
  process.exit(0);