@dev_desh/flux-cap 0.7.0 → 0.8.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 (3) hide show
  1. package/README.md +33 -17
  2. package/dist/index.js +345 -265
  3. package/package.json +55 -50
package/README.md CHANGED
@@ -2,10 +2,16 @@
2
2
 
3
3
  **A git-aware CLI context manager for ADHD developers**
4
4
 
5
- > *Never lose track of what you were coding after interruptions again.*
5
+ > *Never lose track of what you were coding after interruptions again. Now with intelligent, context-aware search.*
6
+
6
7
 
7
8
  flux-cap is a terminal-native tool that captures your thoughts, tracks your context, and integrates seamlessly with your git workflow. Built specifically for developers who context-switch frequently.
8
9
 
10
+ ### Recent Releases:
11
+ - **v0.8.0:** Search 2.0 - Intelligent multi-signal ranking with context awareness
12
+ - **v0.7.0:** Batch searches with combinedQuery and result sorting
13
+
14
+
9
15
  ## Installation
10
16
 
11
17
  Install flux-cap globally using your preferred package manager:
@@ -41,20 +47,25 @@ flux dump -n "team meeting at 3pm tomorrow" # Notes
41
47
  flux dump -t "refactor payment processing logic" # Tasks
42
48
  ```
43
49
 
44
- ### 3. Search your brain dumps
50
+ ### 3. Search your brain dumps with intelligent ranking
45
51
 
46
- ![https://github.com/kaustubh285/flux-cap/blob/main/images/v0.6-search-output.png](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.6-search-output.png)
52
+ flux-cap now features **Search 2.0** - intelligent, context-aware search that prioritizes:
53
+ - 🔥 **Recent dumps** (exponential decay scoring)
54
+ - ⭐ **Same git branch** as your current work
55
+ - 📁 **Same working directory** context
56
+ - 🏷️ **Exact tag matches** (coming in v0.8.0)
57
+
58
+ ![Search 2.0 Demo - Context-aware ranking](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.8-search-v2-demo.png)
47
59
 
48
60
  ```bash
49
- # Search with a query
50
- flux search auth
61
+ # Smart context-aware search (NEW in v0.8.0!)
62
+ flux search auth # Prioritizes recent + current branch matches
51
63
 
52
- # Search by tags (when implemented in search)
53
- flux search ideas
54
- flux search tasks
64
+ # Coming in v0.8.2: Convenience commands
65
+ flux recent # Last 10 dumps
66
+ flux here # Current branch + directory
67
+ flux notes # All note-tagged dumps
55
68
 
56
- # List recent dumps (no query)
57
- flux search
58
69
  ```
59
70
 
60
71
  ## Features
@@ -66,12 +77,13 @@ flux search
66
77
  - Monthly file organization for easy browsing
67
78
  - Privacy-first design - you control what gets tracked
68
79
 
69
- ### Intelligent Search
70
- - Fuzzy search across all your brain dumps: `flux search "auth"`
71
- - **Tag-aware searching** for filtering by type
72
- - Configurable search fields (message, branch, working directory, tags)
73
- - Result ranking with relevance scores
74
- - Multi-month search with automatic limits
80
+ ### Intelligent Search 2.0 🚀
81
+ - **Multi-signal ranking**: Combines fuzzy matching, recency, and git context
82
+ - **Smart defaults**: Recent dumps + current branch automatically ranked higher
83
+ - **Context-aware**: Prioritizes dumps from your current branch and directory
84
+ - **Debug mode**: `--debug` flag shows detailed scoring breakdown
85
+ - **Flexible filtering**: `--all`, `--since`, `--branch` flags override smart defaults
86
+ - **Fast & local**: No external APIs, blazing fast search results
75
87
 
76
88
  ### Privacy Controls
77
89
  - Choose what information to track during setup
@@ -132,6 +144,7 @@ flux dump --tag bug "found an issue"
132
144
  flux dump --tag meeting "standup notes"
133
145
  ```
134
146
 
147
+
135
148
  ### Tag Examples
136
149
  ```bash
137
150
  # Ideas for future features
@@ -329,7 +342,10 @@ src/
329
342
 
330
343
  ## Roadmap
331
344
 
332
- ### Phase 2 (Coming Soon)
345
+ ### Phase 2 (v0.8.0 - Coming Soon)
346
+ - [ ] Convenience search commands (`flux recent`, `flux here`, `flux notes`)
347
+ - [ ] Tag match scoring integration
348
+ - [ ] Grouped result display by relevance
333
349
  - [ ] Enhanced tag-based search filtering
334
350
  - [ ] ASCII Pomodoro timer with themes
335
351
  - [ ] Visual focus mode display
package/dist/index.js CHANGED
@@ -20623,14 +20623,11 @@ var {
20623
20623
  Option,
20624
20624
  Help
20625
20625
  } = import__.default;
20626
-
20627
- // src/commands/init.command.ts
20628
- import fs2 from "fs";
20629
20626
  // package.json
20630
20627
  var package_default = {
20631
20628
  name: "@dev_desh/flux-cap",
20632
20629
  type: "module",
20633
- version: "0.7.0",
20630
+ version: "0.8.0",
20634
20631
  description: "Git-aware CLI context manager for ADHD developers",
20635
20632
  bin: {
20636
20633
  flux: "./dist/index.js"
@@ -20652,7 +20649,8 @@ var package_default = {
20652
20649
  "changeset:add": "changeset add",
20653
20650
  "changeset:status": "changeset status",
20654
20651
  "changeset:version": "changeset version",
20655
- "changeset:publish": "changeset publish"
20652
+ "changeset:publish": "changeset publish",
20653
+ format: "bunx --bun @biomejs/biome check --write"
20656
20654
  },
20657
20655
  engines: {
20658
20656
  node: ">=18.0.0"
@@ -20667,11 +20665,15 @@ var package_default = {
20667
20665
  "developer-tools"
20668
20666
  ],
20669
20667
  dependencies: {
20668
+ commander: "^14.0.3",
20669
+ "fuse.js": "^7.1.0",
20670
20670
  inquirer: "^13.2.5"
20671
20671
  },
20672
20672
  devDependencies: {
20673
+ "@biomejs/biome": "2.4.4",
20673
20674
  "@changesets/cli": "^2.29.8",
20674
- "@types/inquirer": "^9.0.9"
20675
+ "@types/inquirer": "^9.0.9",
20676
+ "@types/node": "^25.3.3"
20675
20677
  },
20676
20678
  repository: {
20677
20679
  type: "git",
@@ -20707,58 +20709,104 @@ var FLUX_DEFAULT_CONFIG = {
20707
20709
  },
20708
20710
  tags: ["notes", "ideas", "tasks", "bugs", "links", "imporatant"]
20709
20711
  };
20710
- // src/utils/privacy.ts
20711
- import { execSync } from "child_process";
20712
- function getGitUncommittedChanges(config) {
20713
- if (config.privacy.hideUncommittedChanges) {
20714
- return false;
20715
- }
20716
- try {
20717
- const status = execSync("git status --porcelain", { encoding: "utf8", cwd: process.cwd(), timeout: 1000 }).trim();
20718
- return status.length > 0;
20719
- } catch (error) {
20720
- return false;
20721
- }
20722
- }
20723
- async function getWorkingDir(config) {
20724
- return config.privacy.hideWorkingDir ? "" : process.cwd();
20725
- }
20726
- function getCurrentBranch(config) {
20727
- if (config.privacy.hideBranchName) {
20728
- return "";
20729
- }
20730
- try {
20731
- const branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8", cwd: process.cwd(), timeout: 1000 }).trim();
20732
- return branch;
20733
- } catch (error) {
20734
- return "";
20735
- }
20712
+ // src/utils/helper.ts
20713
+ function getMonthString() {
20714
+ const currentDate = new Date;
20715
+ const year = currentDate.getFullYear();
20716
+ const month = String(currentDate.getMonth() + 1).padStart(2, "0");
20717
+ return `${year}-${month}`;
20736
20718
  }
20737
- function getTags(options, config) {
20738
- let tags = [];
20739
- if (options.tag) {
20740
- tags.push(options.tag);
20741
- }
20742
- let optionTags = Object.keys(options).filter((key) => options[key] === true);
20743
- if (!config.tags) {
20744
- console.log("You do not have any tags configured. You can add tags to your config to use this feature. or run `flux config --add-tags notes ideas tasks` to add default tags. or update the config file");
20745
- } else {
20746
- for (const tag of optionTags) {
20747
- if (config.tags && config.tags.includes(tag)) {
20748
- tags.push(tag);
20749
- }
20719
+ function displaySearchResults(results, query) {
20720
+ if (results.length === 0) {
20721
+ if (query) {
20722
+ console.log(`
20723
+ No brain dumps found matching "${query}"
20724
+ `);
20725
+ } else {
20726
+ console.log(`
20727
+ No brain dumps found. Try 'flux dump' to create your first one!
20728
+ `);
20750
20729
  }
20730
+ return;
20751
20731
  }
20752
- return tags;
20732
+ const queryText = query ? ` matching "${query}"` : "";
20733
+ console.log(`
20734
+ Found ${results.length} brain dump${results.length === 1 ? "" : "s"}${queryText}
20735
+ `);
20736
+ const terminalWidth = process.stdout.columns || 100;
20737
+ const indexWidth = results.length.toString().length + 2;
20738
+ const idWidth = 10;
20739
+ const scoreWidth = 8;
20740
+ const timeWidth = 12;
20741
+ const header = `${"#".padEnd(indexWidth)}${"ID".padEnd(idWidth)}${"SCORE".padEnd(scoreWidth)}${"TIME".padEnd(timeWidth)}MESSAGE`;
20742
+ console.log(`\x1B[90m${header}\x1B[0m`);
20743
+ console.log(`\x1B[36m${"─".repeat(Math.min(terminalWidth - 5, header.length))}\x1B[0m`);
20744
+ results.forEach((result, index) => {
20745
+ const dump = result.item;
20746
+ const score = result.scores?.final?.toFixed(2) || "0.00";
20747
+ const shortId = dump.id.substring(0, 8);
20748
+ const timeAgo = getTimeAgo(new Date(dump.timestamp));
20749
+ const indexStr = `${index + 1}.`.padEnd(indexWidth);
20750
+ const idStr = `\x1B[33m#${shortId}\x1B[0m`.padEnd(idWidth + 9);
20751
+ const scoreStr = `\x1B[90m[${score}]\x1B[0m`.padEnd(scoreWidth + 9);
20752
+ const timeStr = `\x1B[90m${timeAgo}\x1B[0m`.padEnd(timeWidth + 9);
20753
+ const lines = dump.message.split(`
20754
+ `).map((l) => l.trim()).filter((l) => l.length > 0);
20755
+ const firstLine = lines[0] || "(empty)";
20756
+ console.log(`
20757
+ ${indexStr}${idStr}${scoreStr}${timeStr}${firstLine}`);
20758
+ const messageIndent = " ".repeat(indexWidth + idWidth + scoreWidth + timeWidth);
20759
+ if (lines.length > 1) {
20760
+ lines.slice(1).forEach((line) => {
20761
+ console.log(`${messageIndent}${line}`);
20762
+ });
20763
+ }
20764
+ const contextTags = [];
20765
+ if (result?.scores?.recency > 0.8) {
20766
+ contextTags.push("recent");
20767
+ }
20768
+ if (result?.scores?.gitContext >= 1) {
20769
+ contextTags.push("same-branch");
20770
+ }
20771
+ if (result?.scores?.gitContext >= 1.5) {
20772
+ contextTags.push("same-dir");
20773
+ }
20774
+ const allTags = [...contextTags, ...dump?.tags || []];
20775
+ if (allTags.length > 0) {
20776
+ const tagsLine = `[${allTags.join(", ")}]`;
20777
+ console.log(`${messageIndent}\x1B[36m${tagsLine}\x1B[0m`);
20778
+ }
20779
+ if (dump.branch && dump.branch !== "main") {
20780
+ const gitInfo = `${dump.branch}${dump.hasUncommittedChanges ? " (uncommitted)" : ""}`;
20781
+ console.log(`${messageIndent}\x1B[33m${gitInfo}\x1B[0m`);
20782
+ }
20783
+ });
20784
+ console.log(`
20785
+ \x1B[90m Tip: Use the 8-character ID to reference dumps (e.g., flux edit ${results[0]?.item.id.substring(0, 8)})\x1B[0m
20786
+ `);
20787
+ }
20788
+ function getTimeAgo(date) {
20789
+ const now = new Date;
20790
+ const diffMs = now.getTime() - date.getTime();
20791
+ const diffMins = Math.floor(diffMs / (1000 * 60));
20792
+ const diffHours = Math.floor(diffMins / 60);
20793
+ const diffDays = Math.floor(diffHours / 24);
20794
+ if (diffMins < 60)
20795
+ return `${diffMins}m ago`;
20796
+ if (diffHours < 24)
20797
+ return `${diffHours}h ago`;
20798
+ if (diffDays < 7)
20799
+ return `${diffDays}d ago`;
20800
+ return date.toLocaleDateString();
20753
20801
  }
20754
20802
  // src/utils/lib.ts
20755
20803
  import fs from "fs";
20756
20804
  import path from "path";
20757
20805
  async function getFluxPath() {
20758
20806
  const cwd = process.cwd();
20759
- let fullPath = cwd.split(path.sep);
20807
+ const fullPath = cwd.split(path.sep);
20760
20808
  while (true) {
20761
- let parentPath = fullPath.join(path.sep) + "/.flux";
20809
+ const parentPath = fullPath.join(path.sep) + "/.flux";
20762
20810
  if (fs.existsSync(parentPath)) {
20763
20811
  return parentPath.split(".flux")[0];
20764
20812
  break;
@@ -20817,7 +20865,7 @@ async function createBrainDumpFileIfNotExists(dateString, fluxPath) {
20817
20865
  async function getConfigFile(fluxPath) {
20818
20866
  const fs2 = await import("fs");
20819
20867
  const configPath = `${fluxPath}${FLUX_CONFIG_PATH}`;
20820
- let config = JSON.parse(fs2.readFileSync(configPath, "utf8"));
20868
+ const config = JSON.parse(fs2.readFileSync(configPath, "utf8"));
20821
20869
  return config;
20822
20870
  }
20823
20871
  async function getAllBrainDumpFilePaths(fluxPath) {
@@ -20826,85 +20874,131 @@ async function getAllBrainDumpFilePaths(fluxPath) {
20826
20874
  const files = fs2.readdirSync(fluxPath + FLUX_BRAIN_DUMP_PATH);
20827
20875
  return files.filter((file) => file.endsWith(".json")).map((file) => path2.join(fluxPath + FLUX_BRAIN_DUMP_PATH, file));
20828
20876
  }
20829
- // src/utils/helper.ts
20830
- function getMonthString() {
20831
- const currentDate = new Date;
20832
- const year = currentDate.getFullYear();
20833
- const month = String(currentDate.getMonth() + 1).padStart(2, "0");
20834
- return `${year}-${month}`;
20877
+ // src/utils/privacy.ts
20878
+ import { execSync } from "child_process";
20879
+ function getGitUncommittedChanges(config) {
20880
+ if (config.privacy.hideUncommittedChanges) {
20881
+ return false;
20882
+ }
20883
+ try {
20884
+ const status = execSync("git status --porcelain", {
20885
+ encoding: "utf8",
20886
+ cwd: process.cwd(),
20887
+ timeout: 1000
20888
+ }).trim();
20889
+ return status.length > 0;
20890
+ } catch (error) {
20891
+ return false;
20892
+ }
20835
20893
  }
20836
- function displaySearchResults(results, query) {
20837
- if (results.length === 0) {
20838
- if (query) {
20839
- console.log(`
20840
- No brain dumps found matching "${query}"
20841
- `);
20842
- } else {
20843
- console.log(`
20844
- No brain dumps found. Try 'flux dump' to create your first one!
20845
- `);
20894
+ async function getWorkingDir(config) {
20895
+ return config.privacy.hideWorkingDir ? "" : process.cwd();
20896
+ }
20897
+ function getCurrentBranch(config) {
20898
+ if (config.privacy.hideBranchName) {
20899
+ return "";
20900
+ }
20901
+ try {
20902
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
20903
+ encoding: "utf8",
20904
+ cwd: process.cwd(),
20905
+ timeout: 1000
20906
+ }).trim();
20907
+ return branch;
20908
+ } catch (error) {
20909
+ return "";
20910
+ }
20911
+ }
20912
+ function getTags(options, config) {
20913
+ const tags = [];
20914
+ if (options.tag) {
20915
+ tags.push(options.tag);
20916
+ }
20917
+ const optionTags = Object.keys(options).filter((key) => options[key] === true);
20918
+ if (!config.tags) {
20919
+ console.log("You do not have any tags configured. You can add tags to your config to use this feature. or run `flux config --add-tags notes ideas tasks` to add default tags. or update the config file");
20920
+ } else {
20921
+ for (const tag of optionTags) {
20922
+ if (config.tags && config.tags.includes(tag)) {
20923
+ tags.push(tag);
20924
+ }
20846
20925
  }
20926
+ }
20927
+ return tags;
20928
+ }
20929
+ // src/commands/config.command.ts
20930
+ async function configCommand(data) {
20931
+ console.log(`Updating key: ${data[0]} to ${data[1]}`);
20932
+ const fluxPath = await getFluxPath();
20933
+ const fs2 = await import("fs");
20934
+ const config = await getConfigFile(fluxPath);
20935
+ if (data.length < 2) {
20936
+ console.log("Please provide a key and value to update the config. Example: flux config --add-tags notes ideas tasks");
20847
20937
  return;
20848
20938
  }
20849
- const queryText = query ? ` matching "${query}"` : "";
20850
- console.log(`
20851
- Found ${results.length} brain dump${results.length === 1 ? "" : "s"}${queryText}
20852
- `);
20853
- const terminalWidth = process.stdout.columns || 100;
20854
- const indexWidth = results.length.toString().length + 2;
20855
- const idWidth = 10;
20856
- const scoreWidth = 8;
20857
- const timeWidth = 12;
20858
- const header = `${"#".padEnd(indexWidth)}${"ID".padEnd(idWidth)}${"SCORE".padEnd(scoreWidth)}${"TIME".padEnd(timeWidth)}MESSAGE`;
20859
- console.log(`\x1B[90m${header}\x1B[0m`);
20860
- console.log(`\x1B[36m${"─".repeat(Math.min(terminalWidth - 5, header.length))}\x1B[0m`);
20861
- results.forEach((result, index) => {
20862
- const dump = result.item;
20863
- const score = result.score?.toFixed(2) || "0.00";
20864
- const shortId = dump.id.substring(0, 8);
20865
- const timeAgo = getTimeAgo(new Date(dump.timestamp));
20866
- const indexStr = `${index + 1}.`.padEnd(indexWidth);
20867
- const idStr = `\x1B[33m#${shortId}\x1B[0m`.padEnd(idWidth + 9);
20868
- const scoreStr = `\x1B[90m[${score}]\x1B[0m`.padEnd(scoreWidth + 9);
20869
- const timeStr = `\x1B[90m${timeAgo}\x1B[0m`.padEnd(timeWidth + 9);
20870
- const lines = dump.message.split(`
20871
- `).map((l) => l.trim()).filter((l) => l.length > 0);
20872
- const firstLine = lines[0] || "(empty)";
20873
- console.log(`
20874
- ${indexStr}${idStr}${scoreStr}${timeStr}${firstLine}`);
20875
- const messageIndent = " ".repeat(indexWidth + idWidth + scoreWidth + timeWidth);
20876
- if (lines.length > 1) {
20877
- lines.slice(1).forEach((line) => {
20878
- console.log(`${messageIndent}${line}`);
20879
- });
20939
+ const key = data[0];
20940
+ const value = data.slice(1).join(" ");
20941
+ const editableKeys = [
20942
+ "hideWorkingDir",
20943
+ "hideBranchName",
20944
+ "hideUncommittedChanges",
20945
+ "resultLimit",
20946
+ "threshold",
20947
+ "includeScore",
20948
+ "defaultFocusDuration"
20949
+ ];
20950
+ if (!editableKeys.includes(key)) {
20951
+ console.log(`Invalid config key.
20952
+ Editable keys are: ${editableKeys.join(", ")}`);
20953
+ return;
20954
+ }
20955
+ if (key === "hideWorkingDir") {
20956
+ config.privacy.hideWorkingDir = value === "true";
20957
+ }
20958
+ if (key === "hideBranchName") {
20959
+ config.privacy.hideBranchName = value === "true";
20960
+ }
20961
+ if (key === "hideUncommittedChanges") {
20962
+ config.privacy.hideUncommittedChanges = value === "true";
20963
+ }
20964
+ if (key === "resultLimit") {
20965
+ const limit = parseInt(value, 10);
20966
+ if (!isNaN(limit)) {
20967
+ config.search.resultLimit = limit;
20968
+ } else {
20969
+ console.log("Invalid value for resultLimit. Please provide a number.");
20970
+ return;
20880
20971
  }
20881
- if (dump?.tags?.length) {
20882
- const tagsLine = `[${dump.tags.join(", ")}]`;
20883
- console.log(`${messageIndent}\x1B[36m${tagsLine}\x1B[0m`);
20972
+ }
20973
+ if (key === "threshold") {
20974
+ const threshold = parseFloat(value);
20975
+ if (!isNaN(threshold)) {
20976
+ if (config.search && config.search.fuseOptions) {
20977
+ config.search.fuseOptions.threshold = threshold;
20978
+ }
20979
+ } else {
20980
+ console.log("Invalid value for threshold. Please provide a number.");
20981
+ return;
20884
20982
  }
20885
- if (dump.branch && dump.branch !== "main") {
20886
- const gitInfo = `${dump.branch}${dump.hasUncommittedChanges ? " (uncommitted)" : ""}`;
20887
- console.log(`${messageIndent}\x1B[33m${gitInfo}\x1B[0m`);
20983
+ }
20984
+ if (key === "includeScore") {
20985
+ if (config.search && config.search.fuseOptions) {
20986
+ config.search.fuseOptions.includeScore = value === "true";
20888
20987
  }
20889
- });
20890
- console.log(`
20891
- \x1B[90m Tip: Use the 8-character ID to reference dumps (e.g., flux edit ${results[0]?.item.id.substring(0, 8)})\x1B[0m
20892
- `);
20893
- }
20894
- function getTimeAgo(date) {
20895
- const now = new Date;
20896
- const diffMs = now.getTime() - date.getTime();
20897
- const diffMins = Math.floor(diffMs / (1000 * 60));
20898
- const diffHours = Math.floor(diffMins / 60);
20899
- const diffDays = Math.floor(diffHours / 24);
20900
- if (diffMins < 60)
20901
- return `${diffMins}m ago`;
20902
- if (diffHours < 24)
20903
- return `${diffHours}h ago`;
20904
- if (diffDays < 7)
20905
- return `${diffDays}d ago`;
20906
- return date.toLocaleDateString();
20988
+ }
20989
+ if (key === "defaultFocusDuration") {
20990
+ const duration = parseInt(value, 10);
20991
+ if (!isNaN(duration)) {
20992
+ config.defaultFocusDuration = duration;
20993
+ } else {
20994
+ console.log("Invalid value for defaultFocusDuration. Please provide a number.");
20995
+ return;
20996
+ }
20997
+ }
20998
+ fs2.writeFileSync(fluxPath + FLUX_CONFIG_PATH, JSON.stringify(config, null, 4));
20999
+ console.log("Config updated successfully.");
20907
21000
  }
21001
+
20908
21002
  // node_modules/@inquirer/core/dist/lib/key.js
20909
21003
  var isUpKey = (key, keybindings = []) => key.name === "up" || keybindings.includes("vim") && key.name === "k" || keybindings.includes("emacs") && key.ctrl && key.name === "p";
20910
21004
  var isDownKey = (key, keybindings = []) => key.name === "down" || keybindings.includes("vim") && key.name === "j" || keybindings.includes("emacs") && key.ctrl && key.name === "n";
@@ -23560,6 +23654,70 @@ var dist_default13 = createPrompt((config, done) => {
23560
23654
  `).trimEnd();
23561
23655
  return `${lines}${cursorHide}`;
23562
23656
  });
23657
+ // src/commands/dump.command.ts
23658
+ import { randomUUID as randomUUID2 } from "crypto";
23659
+ async function handleBrainDump(message, options) {
23660
+ try {
23661
+ let finalMessage;
23662
+ if (options.multiline) {
23663
+ console.log("Opening editor for multiline input...");
23664
+ const initialText = message ? message.join(" ") : "";
23665
+ const multilineInput = await dist_default5({
23666
+ message: "Enter your brain dump (save & exit when done):",
23667
+ default: initialText,
23668
+ waitForUserInput: false
23669
+ });
23670
+ if (!multilineInput.trim()) {
23671
+ console.log("Brain dump cancelled - no content provided");
23672
+ return;
23673
+ }
23674
+ finalMessage = multilineInput.trim();
23675
+ } else {
23676
+ if (!message || message.length === 0) {
23677
+ console.log('Please provide a message: flux dump "your message"');
23678
+ return;
23679
+ }
23680
+ finalMessage = message.join(" ");
23681
+ }
23682
+ await brainDumpAddCommand(finalMessage, options);
23683
+ } catch (error) {
23684
+ console.error("Error creating brain dump:", error instanceof Error ? error.message : "Unknown error");
23685
+ process.exit(1);
23686
+ }
23687
+ }
23688
+ async function brainDumpAddCommand(message, options = {}) {
23689
+ const fluxPath = await getFluxPath();
23690
+ const fs2 = await import("fs");
23691
+ console.log("Creating brain dump...");
23692
+ const monthString = getMonthString();
23693
+ await createBrainDumpFileIfNotExists(monthString, fluxPath);
23694
+ const config = await getConfigFile(fluxPath);
23695
+ const workingDir = await getWorkingDir(config);
23696
+ const branch = getCurrentBranch(config);
23697
+ const hasUncommittedChanges = getGitUncommittedChanges(config);
23698
+ const tags = getTags(options, config);
23699
+ const newDump = {
23700
+ id: randomUUID2(),
23701
+ timestamp: new Date().toISOString(),
23702
+ message,
23703
+ workingDir,
23704
+ branch,
23705
+ hasUncommittedChanges,
23706
+ tags
23707
+ };
23708
+ const data = JSON.parse(fs2.readFileSync(`${fluxPath}${FLUX_BRAIN_DUMP_PATH}/${monthString}.json`, "utf8"));
23709
+ config.sorted ? data.dumps.unshift(newDump) : data.dumps.push(newDump);
23710
+ fs2.writeFileSync(`${fluxPath}${FLUX_BRAIN_DUMP_PATH}/${monthString}.json`, JSON.stringify(data, null, 2));
23711
+ const displayMessage = message.length > 50 ? message.substring(0, 47) + "..." : message;
23712
+ const preview = message.includes(`
23713
+ `) ? `${message.split(`
23714
+ `)[0]}... (multiline)` : displayMessage;
23715
+ console.log(`✅ Brain dump saved: "${preview}"`);
23716
+ }
23717
+
23718
+ // src/commands/init.command.ts
23719
+ import fs2 from "fs";
23720
+
23563
23721
  // node_modules/inquirer/dist/ui/prompt.js
23564
23722
  var import_rxjs = __toESM(require_cjs(), 1);
23565
23723
  var import_run_async = __toESM(require_run_async(), 1);
@@ -23902,12 +24060,14 @@ ${FLUX_FOLDER_PATH}`);
23902
24060
  var resetFluxCommand = async () => {
23903
24061
  console.log("Resetting Flux Capacitor...");
23904
24062
  const fluxPath = await getFluxPath() + FLUX_FOLDER_PATH;
23905
- const { confirmed } = await dist_default14.prompt([{
23906
- type: "confirm",
23907
- name: "confirmed",
23908
- message: "Are you sure? This will delete all your brain dumps and sessions.",
23909
- default: false
23910
- }]);
24063
+ const { confirmed } = await dist_default14.prompt([
24064
+ {
24065
+ type: "confirm",
24066
+ name: "confirmed",
24067
+ message: "Are you sure? This will delete all your brain dumps and sessions.",
24068
+ default: false
24069
+ }
24070
+ ]);
23911
24071
  if (!confirmed) {
23912
24072
  console.log("Reset cancelled.");
23913
24073
  return;
@@ -23926,66 +24086,8 @@ var resetFluxCommand = async () => {
23926
24086
  console.log("Flux Capacitor reset successfully!");
23927
24087
  };
23928
24088
 
23929
- // src/commands/dump.command.ts
23930
- import { randomUUID as randomUUID2 } from "crypto";
23931
- async function handleBrainDump(message, options) {
23932
- try {
23933
- let finalMessage;
23934
- if (options.multiline) {
23935
- console.log("Opening editor for multiline input...");
23936
- const initialText = message ? message.join(" ") : "";
23937
- const multilineInput = await dist_default5({
23938
- message: "Enter your brain dump (save & exit when done):",
23939
- default: initialText,
23940
- waitForUserInput: false
23941
- });
23942
- if (!multilineInput.trim()) {
23943
- console.log("Brain dump cancelled - no content provided");
23944
- return;
23945
- }
23946
- finalMessage = multilineInput.trim();
23947
- } else {
23948
- if (!message || message.length === 0) {
23949
- console.log('Please provide a message: flux dump "your message"');
23950
- return;
23951
- }
23952
- finalMessage = message.join(" ");
23953
- }
23954
- await brainDumpAddCommand(finalMessage, options);
23955
- } catch (error) {
23956
- console.error("Error creating brain dump:", error instanceof Error ? error.message : "Unknown error");
23957
- process.exit(1);
23958
- }
23959
- }
23960
- async function brainDumpAddCommand(message, options = {}) {
23961
- const fluxPath = await getFluxPath();
23962
- const fs3 = await import("fs");
23963
- console.log("Creating brain dump...");
23964
- const monthString = getMonthString();
23965
- await createBrainDumpFileIfNotExists(monthString, fluxPath);
23966
- const config = await getConfigFile(fluxPath);
23967
- const workingDir = await getWorkingDir(config);
23968
- const branch = getCurrentBranch(config);
23969
- const hasUncommittedChanges = getGitUncommittedChanges(config);
23970
- const tags = getTags(options, config);
23971
- const newDump = {
23972
- id: randomUUID2(),
23973
- timestamp: new Date().toISOString(),
23974
- message,
23975
- workingDir,
23976
- branch,
23977
- hasUncommittedChanges,
23978
- tags
23979
- };
23980
- const data = JSON.parse(fs3.readFileSync(`${fluxPath}${FLUX_BRAIN_DUMP_PATH}/${monthString}.json`, "utf8"));
23981
- config.sorted ? data.dumps.unshift(newDump) : data.dumps.push(newDump);
23982
- fs3.writeFileSync(`${fluxPath}${FLUX_BRAIN_DUMP_PATH}/${monthString}.json`, JSON.stringify(data, null, 2));
23983
- const displayMessage = message.length > 50 ? message.substring(0, 47) + "..." : message;
23984
- const preview = message.includes(`
23985
- `) ? `${message.split(`
23986
- `)[0]}... (multiline)` : displayMessage;
23987
- console.log(`✅ Brain dump saved: "${preview}"`);
23988
- }
24089
+ // src/commands/search.command.ts
24090
+ import fs3 from "fs";
23989
24091
 
23990
24092
  // node_modules/fuse.js/dist/fuse.mjs
23991
24093
  function isArray(value) {
@@ -25290,14 +25392,59 @@ function createFuseInstance(data, config) {
25290
25392
  });
25291
25393
  }
25292
25394
 
25395
+ // src/utils/search/helper.ts
25396
+ var searchV2Helper = async (config, searchResults) => {
25397
+ const currentBranch = getCurrentBranch(config);
25398
+ const currentWorkingDir = await getWorkingDir(config);
25399
+ const currentHasUncommitted = getGitUncommittedChanges(config);
25400
+ return searchResults.map(({ item, score }) => {
25401
+ const fuseScore = 1 - (score || 0);
25402
+ const now = new Date;
25403
+ const itemDate = new Date(item.timestamp);
25404
+ const daysSince = (now.getTime() - itemDate.getTime()) / (1000 * 60 * 60 * 24);
25405
+ const recencyScore = Math.exp(-daysSince / 7);
25406
+ let gitContextScore = 0;
25407
+ if (item.branch && currentBranch && item.branch === currentBranch) {
25408
+ gitContextScore += 1;
25409
+ }
25410
+ if (item.workingDir && currentWorkingDir && item.workingDir === currentWorkingDir) {
25411
+ gitContextScore += 0.5;
25412
+ }
25413
+ if (item.hasUncommittedChanges) {
25414
+ gitContextScore += 0.3;
25415
+ }
25416
+ const tagMatchScore = 0;
25417
+ const fuzzyBoost = fuseScore > 0.8 ? 1.3 : 1;
25418
+ const gitBoost = currentHasUncommitted && item.hasUncommittedChanges ? 1.2 : 1;
25419
+ const weights = {
25420
+ fuzzyMatch: 2 * fuzzyBoost,
25421
+ recency: 1,
25422
+ gitContext: 1.5 * gitBoost,
25423
+ tagMatch: 1.2
25424
+ };
25425
+ const totalWeight = Object.values(weights).reduce((sum, weight) => sum + weight, 0);
25426
+ const finalScore = (fuseScore * weights.fuzzyMatch + recencyScore * weights.recency + gitContextScore * weights.gitContext + tagMatchScore * weights.tagMatch) / totalWeight;
25427
+ return {
25428
+ item,
25429
+ scores: {
25430
+ fuzzyMatch: fuseScore,
25431
+ recency: recencyScore,
25432
+ gitContext: gitContextScore,
25433
+ tagMatch: tagMatchScore,
25434
+ final: finalScore
25435
+ },
25436
+ finalScore
25437
+ };
25438
+ });
25439
+ };
25440
+
25293
25441
  // src/commands/search.command.ts
25294
- import fs3 from "fs";
25295
25442
  async function searchBrainDumpCommand(query) {
25296
25443
  console.log("Searching all brain dumps...");
25297
25444
  const fluxPath = await getFluxPath();
25298
25445
  const config = await getConfigFile(fluxPath);
25299
25446
  const combinedQuery = query.join(" ").trim();
25300
- let searchResults = [];
25447
+ const searchResults = [];
25301
25448
  const allFilePaths = await getAllBrainDumpFilePaths(fluxPath);
25302
25449
  if (combinedQuery) {
25303
25450
  for (const searchQuery of query) {
@@ -25305,7 +25452,7 @@ async function searchBrainDumpCommand(query) {
25305
25452
  const fileData = JSON.parse(fs3.readFileSync(filePath, "utf8"));
25306
25453
  const fuse = createFuseInstance(fileData.dumps, config);
25307
25454
  const results = fuse.search(searchQuery);
25308
- searchResults.push(...results);
25455
+ searchResults.push(...await searchV2Helper(config, results));
25309
25456
  }
25310
25457
  }
25311
25458
  } else {
@@ -25313,14 +25460,20 @@ async function searchBrainDumpCommand(query) {
25313
25460
  const fileData = JSON.parse(fs3.readFileSync(filePath, "utf8"));
25314
25461
  const recentDumps = fileData.dumps.filter((dump) => dump && dump.message && dump.message.trim() !== "").map((dump) => ({
25315
25462
  item: dump,
25316
- score: 0,
25463
+ scores: {
25464
+ fuzzyMatch: 0,
25465
+ recency: 0,
25466
+ gitContext: 0,
25467
+ tagMatch: 0,
25468
+ final: 0
25469
+ },
25317
25470
  timestamp: new Date(dump.timestamp).getTime()
25318
25471
  }));
25319
- searchResults.push(...recentDumps);
25472
+ searchResults.push(...await searchV2Helper(config, recentDumps));
25320
25473
  }
25321
25474
  }
25322
25475
  if (combinedQuery) {
25323
- searchResults.sort((a, b) => (a.score || 0) - (b.score || 0));
25476
+ searchResults.sort((a, b) => Number(b.scores?.final || 0) - Number(a.scores?.final || 0));
25324
25477
  } else {
25325
25478
  searchResults.sort((a, b) => {
25326
25479
  const timeA = new Date(a.item.timestamp).getTime();
@@ -25337,79 +25490,6 @@ async function searchBrainDumpCommand(query) {
25337
25490
  displaySearchResults(limitedResults, combinedQuery || undefined);
25338
25491
  }
25339
25492
 
25340
- // src/commands/config.command.ts
25341
- async function configCommand(data) {
25342
- console.log(`Updating key: ${data[0]} to ${data[1]}`);
25343
- const fluxPath = await getFluxPath();
25344
- const fs4 = await import("fs");
25345
- const config = await getConfigFile(fluxPath);
25346
- if (data.length < 2) {
25347
- console.log("Please provide a key and value to update the config. Example: flux config --add-tags notes ideas tasks");
25348
- return;
25349
- }
25350
- const key = data[0];
25351
- const value = data.slice(1).join(" ");
25352
- const editableKeys = [
25353
- "hideWorkingDir",
25354
- "hideBranchName",
25355
- "hideUncommittedChanges",
25356
- "resultLimit",
25357
- "threshold",
25358
- "includeScore",
25359
- "defaultFocusDuration"
25360
- ];
25361
- if (!editableKeys.includes(key)) {
25362
- console.log(`Invalid config key.
25363
- Editable keys are: ${editableKeys.join(", ")}`);
25364
- return;
25365
- }
25366
- if (key === "hideWorkingDir") {
25367
- config.privacy.hideWorkingDir = value === "true";
25368
- }
25369
- if (key === "hideBranchName") {
25370
- config.privacy.hideBranchName = value === "true";
25371
- }
25372
- if (key === "hideUncommittedChanges") {
25373
- config.privacy.hideUncommittedChanges = value === "true";
25374
- }
25375
- if (key === "resultLimit") {
25376
- const limit = parseInt(value, 10);
25377
- if (!isNaN(limit)) {
25378
- config.search.resultLimit = limit;
25379
- } else {
25380
- console.log("Invalid value for resultLimit. Please provide a number.");
25381
- return;
25382
- }
25383
- }
25384
- if (key === "threshold") {
25385
- const threshold = parseFloat(value);
25386
- if (!isNaN(threshold)) {
25387
- if (config.search && config.search.fuseOptions) {
25388
- config.search.fuseOptions.threshold = threshold;
25389
- }
25390
- } else {
25391
- console.log("Invalid value for threshold. Please provide a number.");
25392
- return;
25393
- }
25394
- }
25395
- if (key === "includeScore") {
25396
- if (config.search && config.search.fuseOptions) {
25397
- config.search.fuseOptions.includeScore = value === "true";
25398
- }
25399
- }
25400
- if (key === "defaultFocusDuration") {
25401
- const duration = parseInt(value, 10);
25402
- if (!isNaN(duration)) {
25403
- config.defaultFocusDuration = duration;
25404
- } else {
25405
- console.log("Invalid value for defaultFocusDuration. Please provide a number.");
25406
- return;
25407
- }
25408
- }
25409
- fs4.writeFileSync(fluxPath + FLUX_CONFIG_PATH, JSON.stringify(config, null, 4));
25410
- console.log("Config updated successfully.");
25411
- }
25412
-
25413
25493
  // src/index.ts
25414
25494
  var program2 = new Command;
25415
25495
  program2.name(`flux`).description("Git-aware CLI context manager for ADHD developers").version(package_default.version);
package/package.json CHANGED
@@ -1,52 +1,57 @@
1
1
  {
2
- "name": "@dev_desh/flux-cap",
3
- "type": "module",
4
- "version": "0.7.0",
5
- "description": "Git-aware CLI context manager for ADHD developers",
6
- "bin": {
7
- "flux": "./dist/index.js"
8
- },
9
- "files": [
10
- "dist/**/*",
11
- "README.md",
12
- "LICENSE"
13
- ],
14
- "scripts": {
15
- "build": "bun build src/index.ts --outdir dist --target node --format esm",
16
- "dev": "bun run src/index.ts",
17
- "prepublishOnly": "bun run build",
18
- "publish": "npm publish --access=public",
19
- "local-install": "bun run build && npm link",
20
- "local-uninstall": "npm unlink -g flux-cap",
21
- "local-reinstall": "bun run local-uninstall && bun run local-install",
22
- "changeset": "changeset",
23
- "changeset:add": "changeset add",
24
- "changeset:status": "changeset status",
25
- "changeset:version": "changeset version",
26
- "changeset:publish": "changeset publish"
27
- },
28
- "engines": {
29
- "node": ">=18.0.0"
30
- },
31
- "keywords": [
32
- "cli",
33
- "productivity",
34
- "adhd",
35
- "git",
36
- "context-switching",
37
- "brain-dump",
38
- "developer-tools"
39
- ],
40
- "dependencies": {
41
- "inquirer": "^13.2.5"
42
- },
43
- "devDependencies": {
44
- "@changesets/cli": "^2.29.8",
45
- "@types/inquirer": "^9.0.9"
46
- },
47
- "repository": {
48
- "type": "git",
49
- "url": "https://github.com/kaustubh285/flux-cap"
50
- },
51
- "license": "MIT"
2
+ "name": "@dev_desh/flux-cap",
3
+ "type": "module",
4
+ "version": "0.8.0",
5
+ "description": "Git-aware CLI context manager for ADHD developers",
6
+ "bin": {
7
+ "flux": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist/**/*",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "build": "bun build src/index.ts --outdir dist --target node --format esm",
16
+ "dev": "bun run src/index.ts",
17
+ "prepublishOnly": "bun run build",
18
+ "publish": "npm publish --access=public",
19
+ "local-install": "bun run build && npm link",
20
+ "local-uninstall": "npm unlink -g flux-cap",
21
+ "local-reinstall": "bun run local-uninstall && bun run local-install",
22
+ "changeset": "changeset",
23
+ "changeset:add": "changeset add",
24
+ "changeset:status": "changeset status",
25
+ "changeset:version": "changeset version",
26
+ "changeset:publish": "changeset publish",
27
+ "format": "bunx --bun @biomejs/biome check --write"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "keywords": [
33
+ "cli",
34
+ "productivity",
35
+ "adhd",
36
+ "git",
37
+ "context-switching",
38
+ "brain-dump",
39
+ "developer-tools"
40
+ ],
41
+ "dependencies": {
42
+ "commander": "^14.0.3",
43
+ "fuse.js": "^7.1.0",
44
+ "inquirer": "^13.2.5"
45
+ },
46
+ "devDependencies": {
47
+ "@biomejs/biome": "2.4.4",
48
+ "@changesets/cli": "^2.29.8",
49
+ "@types/inquirer": "^9.0.9",
50
+ "@types/node": "^25.3.3"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/kaustubh285/flux-cap"
55
+ },
56
+ "license": "MIT"
52
57
  }