@ulrichc1/sparn 1.1.1 → 1.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.
package/dist/cli/index.js CHANGED
@@ -358,7 +358,8 @@ var init_config = __esm({
358
358
  logFile: ".sparn/daemon.log",
359
359
  debounceMs: 5e3,
360
360
  incremental: true,
361
- windowSize: 500
361
+ windowSize: 500,
362
+ consolidationInterval: null
362
363
  }
363
364
  };
364
365
  }
@@ -918,16 +919,16 @@ __export(optimize_exports, {
918
919
  import { readFile, writeFile as writeFile2 } from "fs/promises";
919
920
  async function optimizeCommand(options) {
920
921
  const { memory, dryRun = false, verbose = false } = options;
921
- let input;
922
+ let input2;
922
923
  if (options.inputFile) {
923
- input = await readFile(options.inputFile, "utf-8");
924
+ input2 = await readFile(options.inputFile, "utf-8");
924
925
  } else if (options.input) {
925
- input = options.input;
926
+ input2 = options.input;
926
927
  } else {
927
928
  throw new Error("No input provided. Use --input or --input-file");
928
929
  }
929
930
  const adapter = createGenericAdapter(memory, DEFAULT_CONFIG);
930
- const result = await adapter.optimize(input, { dryRun, verbose });
931
+ const result = await adapter.optimize(input2, { dryRun, verbose });
931
932
  if (options.outputFile) {
932
933
  await writeFile2(options.outputFile, result.optimizedContext, "utf-8");
933
934
  }
@@ -1058,7 +1059,7 @@ async function relayCommand(options) {
1058
1059
  return result;
1059
1060
  }
1060
1061
  function executeCommand(command, args) {
1061
- return new Promise((resolve2) => {
1062
+ return new Promise((resolve3) => {
1062
1063
  const child = spawn(command, args, {
1063
1064
  stdio: ["ignore", "pipe", "pipe"]
1064
1065
  });
@@ -1071,14 +1072,14 @@ function executeCommand(command, args) {
1071
1072
  stderr += data.toString();
1072
1073
  });
1073
1074
  child.on("close", (code) => {
1074
- resolve2({
1075
+ resolve3({
1075
1076
  stdout,
1076
1077
  stderr,
1077
1078
  exitCode: code ?? 0
1078
1079
  });
1079
1080
  });
1080
1081
  child.on("error", (error) => {
1081
- resolve2({
1082
+ resolve3({
1082
1083
  stdout,
1083
1084
  stderr: error.message,
1084
1085
  exitCode: 1
@@ -1740,7 +1741,7 @@ function createDaemonCommand() {
1740
1741
  while (waited < maxWait) {
1741
1742
  try {
1742
1743
  process.kill(status2.pid, 0);
1743
- await new Promise((resolve2) => setTimeout(resolve2, interval));
1744
+ await new Promise((resolve3) => setTimeout(resolve3, interval));
1744
1745
  waited += interval;
1745
1746
  } catch {
1746
1747
  removePidFile(pidFile);
@@ -1963,22 +1964,526 @@ var init_hooks = __esm({
1963
1964
  }
1964
1965
  });
1965
1966
 
1967
+ // src/cli/commands/interactive.ts
1968
+ var interactive_exports = {};
1969
+ __export(interactive_exports, {
1970
+ interactiveCommand: () => interactiveCommand
1971
+ });
1972
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
1973
+ import { resolve } from "path";
1974
+ import { confirm, input, number, select } from "@inquirer/prompts";
1975
+ import { load as parseYAML2, dump as stringifyYAML2 } from "js-yaml";
1976
+ function showWelcomeBanner() {
1977
+ console.log(brainPink("\n\u2501".repeat(60)));
1978
+ console.log(brainPink(" \u{1F9E0} Sparn Interactive Mode"));
1979
+ console.log(brainPink("\u2501".repeat(60)));
1980
+ console.log(dim(" Conversational configuration and exploration\n"));
1981
+ }
1982
+ async function showMainMenu() {
1983
+ return select({
1984
+ message: "What would you like to do?",
1985
+ choices: [
1986
+ {
1987
+ name: "\u2699\uFE0F Configure Settings",
1988
+ value: "configure",
1989
+ description: "Guided configuration wizard"
1990
+ },
1991
+ {
1992
+ name: "\u{1F50D} Optimize Preview",
1993
+ value: "preview",
1994
+ description: "Preview optimization with confirmation"
1995
+ },
1996
+ {
1997
+ name: "\u{1F4CA} Stats Dashboard",
1998
+ value: "stats",
1999
+ description: "View metrics and performance data"
2000
+ },
2001
+ {
2002
+ name: "\u{1F9F9} Memory Consolidation",
2003
+ value: "consolidate",
2004
+ description: "Clean up decayed entries and duplicates"
2005
+ },
2006
+ {
2007
+ name: "\u{1F680} Quick Actions",
2008
+ value: "quick",
2009
+ description: "Common tasks and shortcuts"
2010
+ },
2011
+ {
2012
+ name: "\u274C Exit",
2013
+ value: "exit",
2014
+ description: "Return to shell"
2015
+ }
2016
+ ]
2017
+ });
2018
+ }
2019
+ async function configureWizard(configPath) {
2020
+ console.log(neuralCyan("\n\u{1F4DD} Configuration Wizard\n"));
2021
+ const configYAML = readFileSync5(configPath, "utf-8");
2022
+ const config = parseYAML2(configYAML);
2023
+ const section = await select({
2024
+ message: "Which settings would you like to configure?",
2025
+ choices: [
2026
+ { name: "\u{1F52A} Pruning (Sparse Coding)", value: "pruning" },
2027
+ { name: "\u23F3 Decay (Engram Theory)", value: "decay" },
2028
+ { name: "\u{1F3AF} States (Multi-State Synapses)", value: "states" },
2029
+ { name: "\u26A1 Real-time Optimization", value: "realtime" },
2030
+ { name: "\u{1F3A8} UI Preferences", value: "ui" },
2031
+ { name: "\u2190 Back to Main Menu", value: "back" }
2032
+ ]
2033
+ });
2034
+ if (section === "back") return;
2035
+ switch (section) {
2036
+ case "pruning": {
2037
+ console.log(synapseViolet("\n\u{1F52A} Pruning Configuration"));
2038
+ console.log(dim("Sparse coding: Keep only the most relevant context\n"));
2039
+ const threshold = await number({
2040
+ message: "Pruning threshold (percentage of entries to keep):",
2041
+ default: config.pruning.threshold,
2042
+ min: 1,
2043
+ max: 100
2044
+ });
2045
+ const aggressiveness = await number({
2046
+ message: "Aggressiveness (0-100, affects TF-IDF weighting):",
2047
+ default: config.pruning.aggressiveness,
2048
+ min: 0,
2049
+ max: 100
2050
+ });
2051
+ config.pruning.threshold = threshold ?? config.pruning.threshold;
2052
+ config.pruning.aggressiveness = aggressiveness ?? config.pruning.aggressiveness;
2053
+ console.log(neuralCyan("\n\u2713 Pruning settings updated"));
2054
+ break;
2055
+ }
2056
+ case "decay": {
2057
+ console.log(synapseViolet("\n\u23F3 Decay Configuration"));
2058
+ console.log(dim("Engram theory: Apply time-based decay to memories\n"));
2059
+ const defaultTTL = await number({
2060
+ message: "Default TTL in hours:",
2061
+ default: config.decay.defaultTTL,
2062
+ min: 1
2063
+ });
2064
+ const decayThreshold = await number({
2065
+ message: "Decay threshold (0.0-1.0, entries below this are pruned):",
2066
+ default: config.decay.decayThreshold,
2067
+ min: 0,
2068
+ max: 1,
2069
+ step: 0.05
2070
+ });
2071
+ config.decay.defaultTTL = defaultTTL ?? config.decay.defaultTTL;
2072
+ config.decay.decayThreshold = decayThreshold ?? config.decay.decayThreshold;
2073
+ console.log(neuralCyan("\n\u2713 Decay settings updated"));
2074
+ break;
2075
+ }
2076
+ case "states": {
2077
+ console.log(synapseViolet("\n\u{1F3AF} State Threshold Configuration"));
2078
+ console.log(dim("Multi-state synapses: Classify entries as active/ready/silent\n"));
2079
+ const activeThreshold = await number({
2080
+ message: "Active state threshold (0.0-1.0):",
2081
+ default: config.states.activeThreshold,
2082
+ min: 0,
2083
+ max: 1,
2084
+ step: 0.05
2085
+ });
2086
+ const readyThreshold = await number({
2087
+ message: "Ready state threshold (0.0-1.0):",
2088
+ default: config.states.readyThreshold,
2089
+ min: 0,
2090
+ max: 1,
2091
+ step: 0.05
2092
+ });
2093
+ config.states.activeThreshold = activeThreshold ?? config.states.activeThreshold;
2094
+ config.states.readyThreshold = readyThreshold ?? config.states.readyThreshold;
2095
+ console.log(neuralCyan("\n\u2713 State settings updated"));
2096
+ break;
2097
+ }
2098
+ case "realtime": {
2099
+ console.log(synapseViolet("\n\u26A1 Real-time Optimization Configuration"));
2100
+ console.log(dim("Daemon settings for automatic optimization\n"));
2101
+ const tokenBudget = await number({
2102
+ message: "Target token budget:",
2103
+ default: config.realtime.tokenBudget,
2104
+ min: 1e3
2105
+ });
2106
+ const autoOptimizeThreshold = await number({
2107
+ message: "Auto-optimize threshold (triggers optimization):",
2108
+ default: config.realtime.autoOptimizeThreshold,
2109
+ min: 1e3
2110
+ });
2111
+ const windowSize = await number({
2112
+ message: "Sliding window size (entries):",
2113
+ default: config.realtime.windowSize,
2114
+ min: 100
2115
+ });
2116
+ const incremental = await confirm({
2117
+ message: "Enable incremental optimization (faster delta processing)?",
2118
+ default: config.realtime.incremental
2119
+ });
2120
+ config.realtime.tokenBudget = tokenBudget ?? config.realtime.tokenBudget;
2121
+ config.realtime.autoOptimizeThreshold = autoOptimizeThreshold ?? config.realtime.autoOptimizeThreshold;
2122
+ config.realtime.windowSize = windowSize ?? config.realtime.windowSize;
2123
+ config.realtime.incremental = incremental;
2124
+ console.log(neuralCyan("\n\u2713 Real-time settings updated"));
2125
+ break;
2126
+ }
2127
+ case "ui": {
2128
+ console.log(synapseViolet("\n\u{1F3A8} UI Preferences"));
2129
+ console.log(dim("Customize terminal output\n"));
2130
+ const colors = await confirm({
2131
+ message: "Enable colored output?",
2132
+ default: config.ui.colors
2133
+ });
2134
+ const verbose = await confirm({
2135
+ message: "Enable verbose logging?",
2136
+ default: config.ui.verbose
2137
+ });
2138
+ config.ui.colors = colors;
2139
+ config.ui.verbose = verbose;
2140
+ console.log(neuralCyan("\n\u2713 UI settings updated"));
2141
+ break;
2142
+ }
2143
+ }
2144
+ const updatedYAML = stringifyYAML2(config);
2145
+ writeFileSync4(configPath, updatedYAML, "utf-8");
2146
+ console.log(neuralCyan(`
2147
+ \u{1F4BE} Configuration saved to ${configPath}
2148
+ `));
2149
+ }
2150
+ async function optimizePreview(memory) {
2151
+ console.log(neuralCyan("\n\u{1F50D} Optimization Preview\n"));
2152
+ const inputFile = await input({
2153
+ message: "Input file path (or press Enter to skip):",
2154
+ default: ""
2155
+ });
2156
+ if (!inputFile) {
2157
+ console.log(dim("\nNo file specified. Returning to menu.\n"));
2158
+ return;
2159
+ }
2160
+ try {
2161
+ const content = readFileSync5(resolve(process.cwd(), inputFile), "utf-8");
2162
+ const tokensBefore = Math.ceil(content.length / 4);
2163
+ console.log(synapseViolet("\n\u{1F4C4} File Preview:"));
2164
+ console.log(dim(` Length: ${content.length} characters`));
2165
+ console.log(dim(` Estimated tokens: ${tokensBefore.toLocaleString()}
2166
+ `));
2167
+ const shouldOptimize = await confirm({
2168
+ message: "Proceed with optimization?",
2169
+ default: true
2170
+ });
2171
+ if (!shouldOptimize) {
2172
+ console.log(dim("\nOptimization cancelled.\n"));
2173
+ return;
2174
+ }
2175
+ console.log(neuralCyan("\n\u26A1 Optimizing...\n"));
2176
+ const { optimizeCommand: optimizeCommand2 } = await Promise.resolve().then(() => (init_optimize(), optimize_exports));
2177
+ const result = await optimizeCommand2({
2178
+ inputFile,
2179
+ memory,
2180
+ dryRun: false,
2181
+ verbose: false
2182
+ });
2183
+ console.log(neuralCyan(`
2184
+ \u2713 Optimization complete in ${result.durationMs}ms!`));
2185
+ console.log(synapseViolet(` Tokens: ${result.tokensBefore} \u2192 ${result.tokensAfter}`));
2186
+ console.log(
2187
+ brainPink(
2188
+ ` Saved: ${result.tokensBefore - result.tokensAfter} tokens (${(result.reduction * 100).toFixed(1)}%)
2189
+ `
2190
+ )
2191
+ );
2192
+ const saveOutput = await confirm({
2193
+ message: "Save optimized output to file?",
2194
+ default: false
2195
+ });
2196
+ if (saveOutput) {
2197
+ const outputFile = await input({
2198
+ message: "Output file path:",
2199
+ default: inputFile.replace(/(\.[^.]+)$/, ".optimized$1")
2200
+ });
2201
+ writeFileSync4(resolve(process.cwd(), outputFile), result.output, "utf-8");
2202
+ console.log(neuralCyan(`
2203
+ \u{1F4BE} Saved to ${outputFile}
2204
+ `));
2205
+ }
2206
+ } catch (error) {
2207
+ console.error(errorRed("\n\u2717 Error:"), error instanceof Error ? error.message : String(error));
2208
+ console.log();
2209
+ }
2210
+ }
2211
+ async function showStatsDashboard(memory) {
2212
+ console.log(neuralCyan("\n\u{1F4CA} Stats Dashboard\n"));
2213
+ const view = await select({
2214
+ message: "Select view:",
2215
+ choices: [
2216
+ { name: "\u{1F4C8} Optimization History", value: "history" },
2217
+ { name: "\u26A1 Real-time Metrics", value: "realtime" },
2218
+ { name: "\u{1F4BE} Memory Statistics", value: "memory" },
2219
+ { name: "\u2190 Back to Main Menu", value: "back" }
2220
+ ]
2221
+ });
2222
+ if (view === "back") return;
2223
+ switch (view) {
2224
+ case "history": {
2225
+ const stats = await memory.getOptimizationStats();
2226
+ const totalRuns = stats.length;
2227
+ const totalTokensSaved = stats.reduce(
2228
+ (sum, s) => sum + (s.tokens_before - s.tokens_after),
2229
+ 0
2230
+ );
2231
+ const avgReduction = totalRuns > 0 ? stats.reduce((sum, s) => {
2232
+ return sum + (s.tokens_before > 0 ? (s.tokens_before - s.tokens_after) / s.tokens_before : 0);
2233
+ }, 0) / totalRuns : 0;
2234
+ console.log(brainPink("\n\u2501".repeat(60)));
2235
+ console.log(neuralCyan(" \u{1F4C8} Optimization History"));
2236
+ console.log(brainPink("\u2501".repeat(60)));
2237
+ console.log(` ${synapseViolet("Total runs:")} ${totalRuns.toLocaleString()}`);
2238
+ console.log(` ${synapseViolet("Tokens saved:")} ${totalTokensSaved.toLocaleString()}`);
2239
+ console.log(` ${synapseViolet("Avg reduction:")} ${(avgReduction * 100).toFixed(1)}%`);
2240
+ if (totalRuns > 0) {
2241
+ console.log(`
2242
+ ${dim("Recent optimizations:")}`);
2243
+ const recent = stats.slice(0, 5);
2244
+ for (const stat of recent) {
2245
+ const date = new Date(stat.timestamp).toLocaleString();
2246
+ const reduction = stat.tokens_before > 0 ? (stat.tokens_before - stat.tokens_after) / stat.tokens_before * 100 : 0;
2247
+ console.log(` ${dim(date)} - ${neuralCyan(`${reduction.toFixed(1)}%`)} reduction`);
2248
+ }
2249
+ }
2250
+ console.log(brainPink(`${"\u2501".repeat(60)}
2251
+ `));
2252
+ break;
2253
+ }
2254
+ case "realtime": {
2255
+ const metrics = getMetrics();
2256
+ const snapshot = metrics.getSnapshot();
2257
+ console.log(brainPink("\n\u2501".repeat(60)));
2258
+ console.log(neuralCyan(" \u26A1 Real-time Metrics"));
2259
+ console.log(brainPink("\u2501".repeat(60)));
2260
+ console.log(
2261
+ ` ${synapseViolet("Total runs:")} ${snapshot.optimization.totalRuns.toLocaleString()}`
2262
+ );
2263
+ console.log(
2264
+ ` ${synapseViolet("Tokens saved:")} ${snapshot.optimization.totalTokensSaved.toLocaleString()}`
2265
+ );
2266
+ console.log(
2267
+ ` ${synapseViolet("Avg reduction:")} ${(snapshot.optimization.averageReduction * 100).toFixed(1)}%`
2268
+ );
2269
+ console.log(
2270
+ ` ${synapseViolet("P50 latency:")} ${snapshot.optimization.p50Latency.toFixed(0)}ms`
2271
+ );
2272
+ console.log(
2273
+ ` ${synapseViolet("P95 latency:")} ${snapshot.optimization.p95Latency.toFixed(0)}ms`
2274
+ );
2275
+ console.log(
2276
+ ` ${synapseViolet("P99 latency:")} ${snapshot.optimization.p99Latency.toFixed(0)}ms`
2277
+ );
2278
+ console.log(
2279
+ `
2280
+ ${synapseViolet("Cache hit rate:")} ${(snapshot.cache.hitRate * 100).toFixed(1)}%`
2281
+ );
2282
+ console.log(
2283
+ ` ${synapseViolet("Cache hits:")} ${snapshot.cache.totalHits.toLocaleString()}`
2284
+ );
2285
+ console.log(
2286
+ ` ${synapseViolet("Cache misses:")} ${snapshot.cache.totalMisses.toLocaleString()}`
2287
+ );
2288
+ console.log(brainPink(`${"\u2501".repeat(60)}
2289
+ `));
2290
+ break;
2291
+ }
2292
+ case "memory": {
2293
+ const entries = await memory.query({});
2294
+ const totalEntries = entries.length;
2295
+ const totalSize = entries.reduce((sum, e) => sum + (e.content?.length || 0), 0);
2296
+ console.log(brainPink("\n\u2501".repeat(60)));
2297
+ console.log(neuralCyan(" \u{1F4BE} Memory Statistics"));
2298
+ console.log(brainPink("\u2501".repeat(60)));
2299
+ console.log(` ${synapseViolet("Total entries:")} ${totalEntries.toLocaleString()}`);
2300
+ console.log(` ${synapseViolet("Total size:")} ${(totalSize / 1024).toFixed(1)} KB`);
2301
+ console.log(
2302
+ ` ${synapseViolet("Avg entry size:")} ${totalEntries > 0 ? (totalSize / totalEntries).toFixed(0) : 0} bytes`
2303
+ );
2304
+ console.log(brainPink(`${"\u2501".repeat(60)}
2305
+ `));
2306
+ break;
2307
+ }
2308
+ }
2309
+ }
2310
+ async function consolidateMemory(memory) {
2311
+ console.log(neuralCyan("\n\u{1F9F9} Memory Consolidation\n"));
2312
+ console.log(dim("This will:"));
2313
+ console.log(dim(" \u2022 Remove decayed entries"));
2314
+ console.log(dim(" \u2022 Merge duplicate entries"));
2315
+ console.log(dim(" \u2022 VACUUM database to reclaim space\n"));
2316
+ const shouldConsolidate = await confirm({
2317
+ message: "Proceed with consolidation?",
2318
+ default: true
2319
+ });
2320
+ if (!shouldConsolidate) {
2321
+ console.log(dim("\nConsolidation cancelled.\n"));
2322
+ return;
2323
+ }
2324
+ const { consolidateCommand: consolidateCommand2 } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
2325
+ console.log(neuralCyan("\n\u26A1 Consolidating...\n"));
2326
+ const result = await consolidateCommand2({ memory });
2327
+ console.log(neuralCyan(`
2328
+ \u2713 Consolidation complete in ${result.durationMs}ms!`));
2329
+ console.log(synapseViolet(` Entries: ${result.entriesBefore} \u2192 ${result.entriesAfter}`));
2330
+ console.log(
2331
+ brainPink(
2332
+ ` Removed: ${result.decayedRemoved} decayed, ${result.duplicatesRemoved} duplicates
2333
+ `
2334
+ )
2335
+ );
2336
+ }
2337
+ async function showQuickActions(memory, configPath) {
2338
+ const action = await select({
2339
+ message: "Quick Actions:",
2340
+ choices: [
2341
+ { name: "\u{1F504} Reset Statistics", value: "reset-stats" },
2342
+ { name: "\u{1F4CB} Export Config (JSON)", value: "export-config" },
2343
+ { name: "\u{1F9EA} Run Test Optimization", value: "test-optimize" },
2344
+ { name: "\u2190 Back to Main Menu", value: "back" }
2345
+ ]
2346
+ });
2347
+ if (action === "back") return;
2348
+ switch (action) {
2349
+ case "reset-stats": {
2350
+ const confirmReset = await confirm({
2351
+ message: "Are you sure you want to reset all statistics?",
2352
+ default: false
2353
+ });
2354
+ if (confirmReset) {
2355
+ await memory.clearOptimizationStats();
2356
+ console.log(neuralCyan("\n\u2713 Statistics cleared\n"));
2357
+ } else {
2358
+ console.log(dim("\nReset cancelled.\n"));
2359
+ }
2360
+ break;
2361
+ }
2362
+ case "export-config": {
2363
+ const configYAML = readFileSync5(configPath, "utf-8");
2364
+ const config = parseYAML2(configYAML);
2365
+ const json = JSON.stringify(config, null, 2);
2366
+ console.log(synapseViolet("\n\u{1F4CB} Configuration (JSON):\n"));
2367
+ console.log(json);
2368
+ console.log();
2369
+ const shouldSave = await confirm({
2370
+ message: "Save to file?",
2371
+ default: false
2372
+ });
2373
+ if (shouldSave) {
2374
+ const outputPath = resolve(configPath.replace(/\.yaml$/, ".json"));
2375
+ writeFileSync4(outputPath, json, "utf-8");
2376
+ console.log(neuralCyan(`
2377
+ \u{1F4BE} Saved to ${outputPath}
2378
+ `));
2379
+ }
2380
+ break;
2381
+ }
2382
+ case "test-optimize": {
2383
+ console.log(neuralCyan("\n\u{1F9EA} Running test optimization...\n"));
2384
+ const testContent = `
2385
+ # Test Context
2386
+
2387
+ This is a test context for optimization.
2388
+ It includes some sample content to demonstrate the optimization process.
2389
+
2390
+ ## Features
2391
+ - Token counting
2392
+ - Sparse coding
2393
+ - Decay application
2394
+ - State classification
2395
+ `.trim();
2396
+ const { optimizeCommand: optimizeCommand2 } = await Promise.resolve().then(() => (init_optimize(), optimize_exports));
2397
+ const result = await optimizeCommand2({
2398
+ input: testContent,
2399
+ memory,
2400
+ dryRun: true,
2401
+ verbose: false
2402
+ });
2403
+ console.log(neuralCyan(`
2404
+ \u2713 Test optimization complete in ${result.durationMs}ms!`));
2405
+ console.log(synapseViolet(` Tokens: ${result.tokensBefore} \u2192 ${result.tokensAfter}`));
2406
+ console.log(
2407
+ brainPink(
2408
+ ` Saved: ${result.tokensBefore - result.tokensAfter} tokens (${(result.reduction * 100).toFixed(1)}%)
2409
+ `
2410
+ )
2411
+ );
2412
+ break;
2413
+ }
2414
+ }
2415
+ }
2416
+ async function interactiveCommand(options) {
2417
+ const { memory, configPath } = options;
2418
+ showWelcomeBanner();
2419
+ let running = true;
2420
+ while (running) {
2421
+ try {
2422
+ const choice = await showMainMenu();
2423
+ switch (choice) {
2424
+ case "configure":
2425
+ await configureWizard(configPath);
2426
+ break;
2427
+ case "preview":
2428
+ await optimizePreview(memory);
2429
+ break;
2430
+ case "stats":
2431
+ await showStatsDashboard(memory);
2432
+ break;
2433
+ case "consolidate":
2434
+ await consolidateMemory(memory);
2435
+ break;
2436
+ case "quick":
2437
+ await showQuickActions(memory, configPath);
2438
+ break;
2439
+ case "exit":
2440
+ running = false;
2441
+ console.log(brainPink("\n\u{1F44B} Thanks for using Sparn!\n"));
2442
+ break;
2443
+ }
2444
+ } catch (error) {
2445
+ if (error.message === "User force closed the prompt") {
2446
+ running = false;
2447
+ console.log(brainPink("\n\u{1F44B} Thanks for using Sparn!\n"));
2448
+ } else {
2449
+ console.error(
2450
+ errorRed("\n\u2717 Error:"),
2451
+ error instanceof Error ? error.message : String(error)
2452
+ );
2453
+ console.log();
2454
+ }
2455
+ }
2456
+ }
2457
+ return {
2458
+ success: true,
2459
+ message: "Interactive session completed"
2460
+ };
2461
+ }
2462
+ var init_interactive = __esm({
2463
+ "src/cli/commands/interactive.ts"() {
2464
+ "use strict";
2465
+ init_esm_shims();
2466
+ init_metrics();
2467
+ init_colors();
2468
+ }
2469
+ });
2470
+
1966
2471
  // src/cli/index.ts
1967
2472
  init_esm_shims();
1968
2473
  init_banner();
1969
2474
  import { spawn as spawn2 } from "child_process";
1970
- import { readFileSync as readFileSync5 } from "fs";
1971
- import { dirname as dirname4, join as join4, resolve } from "path";
2475
+ import { readFileSync as readFileSync6 } from "fs";
2476
+ import { dirname as dirname4, join as join4, resolve as resolve2 } from "path";
1972
2477
  import { fileURLToPath as fileURLToPath5 } from "url";
1973
2478
  import { Command } from "commander";
1974
2479
  function getVersion2() {
1975
2480
  try {
1976
- const pkg = JSON.parse(readFileSync5(join4(process.cwd(), "package.json"), "utf-8"));
2481
+ const pkg = JSON.parse(readFileSync6(join4(process.cwd(), "package.json"), "utf-8"));
1977
2482
  return pkg.version;
1978
2483
  } catch {
1979
2484
  const __filename2 = fileURLToPath5(import.meta.url);
1980
2485
  const __dirname2 = dirname4(__filename2);
1981
- const pkg = JSON.parse(readFileSync5(join4(__dirname2, "../../package.json"), "utf-8"));
2486
+ const pkg = JSON.parse(readFileSync6(join4(__dirname2, "../../package.json"), "utf-8"));
1982
2487
  return pkg.version;
1983
2488
  }
1984
2489
  }
@@ -2087,23 +2592,23 @@ Typical Results:
2087
2592
  const spinner = createOptimizeSpinner2("\u{1F9E0} Initializing optimization...");
2088
2593
  try {
2089
2594
  spinner.start();
2090
- let input;
2595
+ let input2;
2091
2596
  if (!options.input && process.stdin.isTTY === false) {
2092
2597
  spinner.text = "\u{1F4D6} Reading context from stdin...";
2093
2598
  const chunks = [];
2094
2599
  for await (const chunk of process.stdin) {
2095
2600
  chunks.push(chunk);
2096
2601
  }
2097
- input = Buffer.concat(chunks).toString("utf-8");
2602
+ input2 = Buffer.concat(chunks).toString("utf-8");
2098
2603
  } else if (options.input) {
2099
2604
  spinner.text = `\u{1F4D6} Reading context from ${options.input}...`;
2100
2605
  }
2101
2606
  spinner.text = "\u{1F4BE} Loading memory database...";
2102
- const dbPath = resolve(process.cwd(), ".sparn/memory.db");
2607
+ const dbPath = resolve2(process.cwd(), ".sparn/memory.db");
2103
2608
  const memory = await createKVMemory2(dbPath);
2104
2609
  spinner.text = "\u26A1 Applying neuroscience principles...";
2105
2610
  const result = await optimizeCommand2({
2106
- input,
2611
+ input: input2,
2107
2612
  inputFile: options.input,
2108
2613
  outputFile: options.output,
2109
2614
  memory,
@@ -2163,7 +2668,7 @@ Tracked Metrics:
2163
2668
  try {
2164
2669
  if (spinner) spinner.start();
2165
2670
  if (spinner) spinner.text = "\u{1F4BE} Loading optimization history...";
2166
- const dbPath = resolve(process.cwd(), ".sparn/memory.db");
2671
+ const dbPath = resolve2(process.cwd(), ".sparn/memory.db");
2167
2672
  const memory = await createKVMemory2(dbPath);
2168
2673
  let confirmReset = false;
2169
2674
  if (options.reset) {
@@ -2223,7 +2728,7 @@ The relay command passes the exit code from the wrapped command.
2223
2728
  const { relayCommand: relayCommand2 } = await Promise.resolve().then(() => (init_relay(), relay_exports));
2224
2729
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2225
2730
  try {
2226
- const dbPath = resolve(process.cwd(), ".sparn/memory.db");
2731
+ const dbPath = resolve2(process.cwd(), ".sparn/memory.db");
2227
2732
  const memory = await createKVMemory2(dbPath);
2228
2733
  const result = await relayCommand2({
2229
2734
  command,
@@ -2276,7 +2781,7 @@ Typical Results:
2276
2781
  try {
2277
2782
  spinner.start();
2278
2783
  spinner.text = "\u{1F4BE} Loading memory database...";
2279
- const dbPath = resolve(process.cwd(), ".sparn/memory.db");
2784
+ const dbPath = resolve2(process.cwd(), ".sparn/memory.db");
2280
2785
  const memory = await createKVMemory2(dbPath);
2281
2786
  spinner.text = "\u{1F50D} Identifying decayed entries...";
2282
2787
  const result = await consolidateCommand2({ memory });
@@ -2324,7 +2829,7 @@ The config file is located at .sparn/config.yaml
2324
2829
  const { configCommand: configCommand2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
2325
2830
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2326
2831
  try {
2327
- const configPath = resolve(process.cwd(), ".sparn/config.yaml");
2832
+ const configPath = resolve2(process.cwd(), ".sparn/config.yaml");
2328
2833
  const result = await configCommand2({
2329
2834
  configPath,
2330
2835
  subcommand,
@@ -2379,13 +2884,13 @@ The daemon watches ~/.claude/projects/**/*.jsonl and automatically
2379
2884
  optimizes contexts when they exceed the configured threshold.
2380
2885
  `
2381
2886
  ).action(async (subcommand) => {
2382
- const { load: parseYAML2 } = await import("js-yaml");
2887
+ const { load: parseYAML3 } = await import("js-yaml");
2383
2888
  const { createDaemonCommand: createDaemonCommand2 } = await Promise.resolve().then(() => (init_daemon_process(), daemon_process_exports));
2384
2889
  const { neuralCyan: neuralCyan2, errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
2385
2890
  try {
2386
- const configPath = resolve(process.cwd(), ".sparn/config.yaml");
2387
- const configYAML = readFileSync5(configPath, "utf-8");
2388
- const config = parseYAML2(configYAML);
2891
+ const configPath = resolve2(process.cwd(), ".sparn/config.yaml");
2892
+ const configYAML = readFileSync6(configPath, "utf-8");
2893
+ const config = parseYAML3(configYAML);
2389
2894
  const daemon = createDaemonCommand2();
2390
2895
  switch (subcommand) {
2391
2896
  case "start": {
@@ -2495,6 +3000,41 @@ and compress verbose tool results after execution.
2495
3000
  process.exit(1);
2496
3001
  }
2497
3002
  });
3003
+ program.command("interactive").alias("i").description("Launch interactive mode for configuration and exploration").addHelpText(
3004
+ "after",
3005
+ `
3006
+ Examples:
3007
+ $ sparn interactive # Launch interactive mode
3008
+ $ sparn i # Short alias
3009
+
3010
+ Features:
3011
+ \u2022 \u{1F4DD} Configuration Wizard - Guided prompts for all settings
3012
+ \u2022 \u{1F50D} Optimization Preview - Test optimization with file preview
3013
+ \u2022 \u{1F4CA} Stats Dashboard - Beautiful metrics display
3014
+ \u2022 \u{1F9F9} Memory Consolidation - Interactive cleanup
3015
+ \u2022 \u{1F680} Quick Actions - Common tasks and shortcuts
3016
+
3017
+ The interactive mode provides a conversational interface for exploring
3018
+ and configuring Sparn without memorizing CLI flags.
3019
+ `
3020
+ ).action(async () => {
3021
+ const { createKVMemory: createKVMemory2 } = await Promise.resolve().then(() => (init_kv_memory(), kv_memory_exports));
3022
+ const { interactiveCommand: interactiveCommand2 } = await Promise.resolve().then(() => (init_interactive(), interactive_exports));
3023
+ const { errorRed: errorRed2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
3024
+ try {
3025
+ const dbPath = resolve2(process.cwd(), ".sparn/memory.db");
3026
+ const memory = await createKVMemory2(dbPath);
3027
+ const configPath = resolve2(process.cwd(), ".sparn/config.yaml");
3028
+ await interactiveCommand2({
3029
+ memory,
3030
+ configPath
3031
+ });
3032
+ await memory.close();
3033
+ } catch (error) {
3034
+ console.error(errorRed2("Error:"), error instanceof Error ? error.message : String(error));
3035
+ process.exit(1);
3036
+ }
3037
+ });
2498
3038
  program.on("option:version", () => {
2499
3039
  console.log(getBanner(VERSION2));
2500
3040
  process.exit(0);