@dev_desh/flux-cap 0.9.1 → 0.10.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.
package/README.md CHANGED
@@ -1,15 +1,29 @@
1
1
  # flux-cap
2
2
 
3
- **A git-aware CLI context manager for ADHD developers**
3
+ > Loosing your train of thought often? flux-cap is a git-aware brain dump CLI for developers who context-switch with intelligent search and a lazygit-inspired TUI built in.
4
+
5
+ ---
6
+
7
+ ### How this was built
8
+
9
+ flux-cap is a personal project built incrementally over several weeks — not generated in one shot. The search algorithm (`searchV2Helper`) was designed from first principles: Fuse.js scores are inverted and weighted, recency uses exponential decay (`e^(-days/7)`), and git context gets a dynamic boost multiplier when you have uncommitted changes. The TUI was built twice — once in Ink, once in Rezi — to compare performance and ergonomics firsthand.
10
+
11
+ The commit history tells the story better than this paragraph.
12
+
13
+ ---
4
14
 
5
- > *Never lose track of what you were coding after interruptions again. Now with intelligent, context-aware search.*
6
15
 
16
+ [![npm version](https://img.shields.io/npm/v/@dev_desh/flux-cap)](https://www.npmjs.com/package/@dev_desh/flux-cap)
17
+ [![npm downloads](https://img.shields.io/npm/dm/@dev_desh/flux-cap)](https://www.npmjs.com/package/@dev_desh/flux-cap)
18
+ [![license](https://img.shields.io/npm/l/@dev_desh/flux-cap)](LICENSE)
7
19
 
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.
20
+ **Now at v1.0.0** with Search 2.0 multi-signal ranking, Ink-powered interactive TUI, and a Rezi-based lazygit-style interface.
9
21
 
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
22
+ ### What's new:
23
+ - **v1.0.0:** First stable release
24
+ - **v0.10.0:** Rezi-based lazygit-style TUI (`flux u`)
25
+ - **v0.9.0:** Ink-powered interactive search TUI (`flux ui-ink`)
26
+ - **v0.8.0:** Search 2.0 — multi-signal ranking with git context awareness
13
27
 
14
28
 
15
29
  ## Installation
@@ -38,13 +52,13 @@ flux init
38
52
  ### 2. Start capturing thoughts with tags
39
53
  ```bash
40
54
  # Basic brain dumps
41
- flux dump "remember to add error handling to auth module"
42
- flux dump "bug in user validation - check line 42"
55
+ flux d "remember to add error handling to auth module"
56
+ flux d "bug in user validation - check line 42"
43
57
 
44
58
  # Tagged brain dumps for better organization
45
- flux dump -i "add dark mode toggle" # Ideas
46
- flux dump -n "team meeting at 3pm tomorrow" # Notes
47
- flux dump -t "refactor payment processing logic" # Tasks
59
+ flux d -i "add dark mode toggle" # Ideas
60
+ flux d -n "team meeting at 3pm tomorrow" # Notes
61
+ flux d -t "refactor payment processing logic" # Tasks
48
62
  ```
49
63
  ## 3. **New TUI Section** (add after Commands)
50
64
 
@@ -52,7 +66,7 @@ flux dump -t "refactor payment processing logic" # Tasks
52
66
 
53
67
  Flux-Cap includes a terminal user interface for interactive searching:
54
68
 
55
- ![TUI Screenshot](images/tui-demo.png)
69
+ ![TUI Interface](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.10-rezi-interactive.png)
56
70
 
57
71
  ### Features
58
72
  - **Real-time Search**: Results update as you type
@@ -78,7 +92,7 @@ flux-cap now features **Search 2.0** - intelligent, context-aware search that pr
78
92
  - **Recent dumps** (exponential decay scoring)
79
93
  - **Same git branch** as your current work
80
94
  - **Same working directory** context
81
- - **Exact tag matches** (coming in v0.8.0)
95
+ - **Exact tag matches** search for specific tag/branch
82
96
  - **Quick Brain Dumps**: Capture thoughts instantly with git context
83
97
  - **SearchV2**: Multi-signal ranking (fuzzy + recency + git context)
84
98
  - **Interactive TUI**: Real-time search with professional interface
@@ -92,11 +106,11 @@ flux-cap now features **Search 2.0** - intelligent, context-aware search that pr
92
106
 
93
107
 
94
108
  ### Interactive TUI
95
- ![TUI Interface]([images/tui-interface.png](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.6-search-output.png))
109
+ ![TUI Interface](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.10-rezi-interactive.png)
96
110
 
97
111
 
98
112
  ### Search Comparison
99
- ![Search Demo]([images/search-comparison.gif](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.9-interactive.mov)
113
+ ![TUI Demo](https://github.com/kaustubh285/flux-cap/blob/main/images/v0.10-rezi-interactive.gif)
100
114
 
101
115
 
102
116
  ```bash
@@ -113,7 +127,7 @@ flux notes # All note-tagged dumps
113
127
  ## Features
114
128
 
115
129
  ### Brain Dump System with Smart Tags
116
- - Instantly capture thoughts without breaking flow: `flux dump "fix auth validation bug"`
130
+ - Instantly capture thoughts without breaking flow: `flux d fix auth validation bug`
117
131
  - **Tag system** for better organization: `-i` for ideas, `-n` for notes, `-t` for tasks
118
132
  - Git-aware context tracking (branch, working directory, uncommitted changes)
119
133
  - Monthly file organization for easy browsing
@@ -156,18 +170,18 @@ flux ui # Same as above (alias)
156
170
  | Command | Description | Example |
157
171
  |---------|-------------|---------|
158
172
  | `flux init` | Initialize flux-cap with privacy setup | `flux init` |
173
+ | `flux d <message...>` | Capture a brain dump | `flux dump "fix the bug in auth.ts"` |
159
174
  | `flux dump <message...>` | Capture a brain dump | `flux dump "fix the bug in auth.ts"` |
160
- | `flux dump -i <message...>` | Capture important | `flux dump -i "add keyboard shortcuts"` |
161
- | `flux dump -d <message...>` | Capture an idea | `flux dump -d "a new cli tool project"` |
162
- | `flux dump -l <message...>` | Capture a link | `flux dump -l "https://github.com/kaustubh285/flux-cap"` |
163
- | `flux dump -b <message...>` | Capture a bug | `flux dump -b "tsconfig mismatch"` |
164
- | `flux dump -n <message...>` | Capture a note | `flux dump -n "meeting notes from standup"` |
165
- | `flux dump -t <message...>` | Capture a task | `flux dump -t "refactor user authentication"` |
166
- | `flux dump -m` | Multiline input mode | `flux dump -m` |
175
+ | `flux d -i <message...>` | Capture important | `flux dump -i "add keyboard shortcuts"` |
176
+ | `flux d -d <message...>` | Capture an idea | `flux dump -d "a new cli tool project"` |
177
+ | `flux d -l <message...>` | Capture a link | `flux dump -l "https://github.com/kaustubh285/flux-cap"` |
178
+ | `flux d -b <message...>` | Capture a bug | `flux dump -b "tsconfig mismatch"` |
179
+ | `flux d -n <message...>` | Capture a note | `flux dump -n "meeting notes from standup"` |
180
+ | `flux d -t <message...>` | Capture a task | `flux dump -t "refactor user authentication"` |
181
+ | `flux d -m` | Multiline input mode | `flux dump -m` |
182
+ | `flux s [query...]` | Search brain dumps or list recent ones | `flux search "authentication"` |
167
183
  | `flux search [query...]` | Search brain dumps or list recent ones | `flux search "authentication"` |
168
184
  | `flux config [field] [value]` | View or update configuration | `flux config search.resultLimit 20` |
169
- | `flux config --add-tag <tag>` | Add custom tags to configuration | `flux config --add-tag "bug"` |
170
- | `flux config --remove-tag <tag>` | Remove tags from configuration | `flux config --remove-tag "old-tag"` |
171
185
  | `flux reset` | Complete reset (deletes all data) | `flux reset` |
172
186
 
173
187
  ## Tag System
@@ -182,33 +196,33 @@ flux-cap comes with three built-in tag shortcuts:
182
196
  Extend your tagging system by adding custom tags for brain dumps:
183
197
  ```bash
184
198
  # Built-in shortcuts (current)
185
- flux dump -i "idea message"
186
- flux dump -n "note message"
187
- flux dump -t "task message"
199
+ flux d -i "idea message"
200
+ flux d -n "note message"
201
+ flux d -t "task message"
188
202
 
189
203
  # Generic tag option (new)
190
- flux dump --tag thought "my message"
191
- flux dump --tag bug "found an issue"
192
- flux dump --tag meeting "standup notes"
204
+ flux d --tag thought "my message"
205
+ flux d --tag bug "found an issue"
206
+ flux d --tag meeting "standup notes"
193
207
  ```
194
208
 
195
209
 
196
210
  ### Tag Examples
197
211
  ```bash
198
212
  # Ideas for future features
199
- flux dump -i "add real-time collaboration to the editor"
200
- flux dump -i "implement auto-save every 30 seconds"
213
+ flux d -i "add real-time collaboration to the editor"
214
+ flux d -i "implement auto-save every 30 seconds"
201
215
 
202
216
  # Meeting notes and reminders
203
- flux dump -n "team decided to use TypeScript for new components"
204
- flux dump -n "remember to update documentation before release"
217
+ flux d -n "team decided to use TypeScript for new components"
218
+ flux d -n "remember to update documentation before release"
205
219
 
206
220
  # Task tracking
207
- flux dump -t "fix memory leak in image processor"
208
- flux dump -t "write unit tests for authentication module"
221
+ flux d -t "fix memory leak in image processor"
222
+ flux d -t "write unit tests for authentication module"
209
223
 
210
224
  # Combine with multiline for detailed entries
211
- flux dump -t -m # Opens editor for detailed task description
225
+ flux d -t -m # Opens editor for detailed task description
212
226
  ```
213
227
 
214
228
  ## Use Cases
@@ -216,22 +230,22 @@ flux dump -t -m # Opens editor for detailed task description
216
230
  ### Context Switching
217
231
  ```bash
218
232
  # Before switching tasks
219
- flux dump -t "was working on user auth, next: add validation to login form"
233
+ flux d -t "was working on user auth, next: add validation to login form"
220
234
 
221
235
  # After interruption
222
- flux search "auth" # Quickly find where you left off
223
- flux search "tasks" # Find your pending tasks
236
+ flux s "auth" # Quickly find where you left off
237
+ flux s "tasks" # Find your pending tasks
224
238
  ```
225
239
 
226
240
  ### Bug Tracking & Ideas
227
241
  ```bash
228
242
  # Track bugs and investigations
229
- flux dump -n "weird bug in payment flow - users can't checkout"
230
- flux dump -n "bug seems related to session timeout - check Redis config"
243
+ flux d -n "weird bug in payment flow - users can't checkout"
244
+ flux d -n "bug seems related to session timeout - check Redis config"
231
245
 
232
246
  # Capture ideas as they come
233
- flux dump -i "add keyboard shortcuts to dashboard"
234
- flux dump -i "maybe use React.memo for performance optimization"
247
+ flux d -i "add keyboard shortcuts to dashboard"
248
+ flux d -i "maybe use React.memo for performance optimization"
235
249
 
236
250
  # Later...
237
251
  flux search "payment bug"
@@ -241,12 +255,12 @@ flux search "ideas"
241
255
  ### Meeting Notes & Task Management
242
256
  ```bash
243
257
  # Capture meeting outcomes
244
- flux dump -n "team standup: focus on performance this sprint"
245
- flux dump -t "implement caching layer for API responses"
258
+ flux d -n "team standup: focus on performance this sprint"
259
+ flux d -t "implement caching layer for API responses"
246
260
 
247
261
  # Track follow-up tasks
248
- flux dump -t "review Sarah's PR for authentication changes"
249
- flux dump -t "update deployment documentation"
262
+ flux d -t "review Sarah's PR for authentication changes"
263
+ flux d -t "update deployment documentation"
250
264
  ```
251
265
 
252
266
  ## Configuration
@@ -356,7 +370,7 @@ Want to contribute or run locally?
356
370
 
357
371
  ```bash
358
372
  # Clone and setup
359
- git clone https://github.com/yourusername/flux-cap
373
+ git clone https://github.com/kaustubh285/flux-cap
360
374
  cd flux-cap
361
375
  bun install
362
376
 
@@ -373,6 +387,7 @@ Built with:
373
387
  - **TypeScript** - Type safety
374
388
  - **Commander.js** - CLI parsing
375
389
  - **Fuse.js** - Fuzzy search
390
+ - **Rezi** - Terminal UI components
376
391
 
377
392
  ### Project Structure
378
393
  ```
@@ -380,6 +395,7 @@ src/
380
395
  ├── commands/ # Command implementations
381
396
  │ ├── dump.command.ts
382
397
  │ ├── search.command.ts
398
+ │ ├── ui.command.ts
383
399
  │ └── init.command.ts
384
400
  ├── utils/ # Shared utilities
385
401
  │ ├── privacy.ts # Git integration
@@ -390,14 +406,19 @@ src/
390
406
 
391
407
  ## Roadmap
392
408
 
393
- ### Phase 2 (v0.8.0 - Coming Soon)
394
- - [ ] Convenience search commands (`flux recent`, `flux here`, `flux notes`)
395
- - [ ] Tag match scoring integration
396
- - [ ] Grouped result display by relevance
397
- - [ ] Enhanced tag-based search filtering
398
- - [ ] ASCII Pomodoro timer with themes
399
- - [ ] Visual focus mode display
400
- - [ ] Theme rotation system
409
+ ### Shipped
410
+ - [x] SearchV2 multi-signal ranking (fuzzy + recency + git context)
411
+ - [x] Interactive TUI with Ink (`flux u`)
412
+ - [x] Lazygit-style Rezi TUI (`flux u --rezi`)
413
+ - [x] Custom tag support (`--tag`)
414
+ - [x] Parent directory `.flux` discovery
415
+
416
+ ### Coming next
417
+ - [ ] Convenience commands (`flux recent`, `flux here`, `flux notes`)
418
+ - [ ] Tag match scoring in SearchV2
419
+ - [ ] AI export format (`flux ai`)
420
+ - [ ] Todo scanning from codebase (`flux t --scan`)
421
+
401
422
 
402
423
  ### Phase 3 (Future)
403
424
  - [ ] Advanced git context switching
@@ -445,5 +466,3 @@ The system will now only auto-detect major bumps with very explicit indicators l
445
466
  MIT
446
467
 
447
468
  ---
448
-
449
- Built for developers who think fast, context-switch often, and never want to lose a good idea.
package/dist/index.js CHANGED
@@ -52701,7 +52701,7 @@ var {
52701
52701
  var package_default = {
52702
52702
  name: "@dev_desh/flux-cap",
52703
52703
  type: "module",
52704
- version: "0.9.1",
52704
+ version: "0.10.1",
52705
52705
  description: "Git-aware CLI context manager for ADHD developers",
52706
52706
  bin: {
52707
52707
  flux: "./dist/index.js"
@@ -52712,7 +52712,7 @@ var package_default = {
52712
52712
  "LICENSE"
52713
52713
  ],
52714
52714
  scripts: {
52715
- build: "bun build src/index.ts --outdir dist --target node --format esm",
52715
+ build: "bun build src/index.ts --outdir dist --target node --format esm --external @rezi-ui/core --external @rezi-ui/node --external @rezi-ui/jsx --external @rezi-ui/native",
52716
52716
  dev: "bun run src/index.ts",
52717
52717
  prepublishOnly: "bun run build",
52718
52718
  publish: "npm publish --access=public",
@@ -52739,6 +52739,9 @@ var package_default = {
52739
52739
  "developer-tools"
52740
52740
  ],
52741
52741
  dependencies: {
52742
+ "@rezi-ui/core": "^0.1.0-alpha.59",
52743
+ "@rezi-ui/jsx": "^0.1.0-alpha.59",
52744
+ "@rezi-ui/node": "^0.1.0-alpha.59",
52742
52745
  "@types/react": "^19.2.14",
52743
52746
  "@types/react-dom": "^19.2.3",
52744
52747
  commander: "^14.0.3",
@@ -52869,7 +52872,10 @@ function getTimeAgo(date) {
52869
52872
  return `${diffHours}h ago`;
52870
52873
  if (diffDays < 7)
52871
52874
  return `${diffDays}d ago`;
52872
- return date.toLocaleDateString();
52875
+ return date.toLocaleDateString("en-US", {
52876
+ month: "short",
52877
+ day: "numeric"
52878
+ });
52873
52879
  }
52874
52880
  var getContextTags = (result) => {
52875
52881
  const contextTags = [];
@@ -57523,14 +57529,14 @@ var searchV2Helper = async (config, searchResults) => {
57523
57529
  };
57524
57530
 
57525
57531
  // src/commands/search.command.ts
57526
- async function searchBrainDumpCommand(query, returnResults = false) {
57532
+ async function searchBrainDumpCommand(query, returnResults = false, searchResultLimit, specificListOfFiles = null) {
57527
57533
  if (!returnResults)
57528
57534
  console.log("Searching all brain dumps...");
57529
57535
  const fluxPath = await getFluxPath();
57530
57536
  const config = await getConfigFile(fluxPath);
57531
57537
  const combinedQuery = query.join(" ").trim();
57532
57538
  const searchResults = [];
57533
- const allFilePaths = await getAllBrainDumpFilePaths(fluxPath);
57539
+ const allFilePaths = specificListOfFiles ? specificListOfFiles : await getAllBrainDumpFilePaths(fluxPath);
57534
57540
  if (combinedQuery) {
57535
57541
  for (const searchQuery of query) {
57536
57542
  for await (const filePath of allFilePaths) {
@@ -57566,7 +57572,7 @@ async function searchBrainDumpCommand(query, returnResults = false) {
57566
57572
  return timeB - timeA;
57567
57573
  });
57568
57574
  }
57569
- const resultLimit = config?.search?.resultLimit || (combinedQuery ? 10 : 5);
57575
+ const resultLimit = searchResultLimit ? searchResultLimit : config?.search?.resultLimit || (combinedQuery ? 10 : 5);
57570
57576
  const limitedResults = searchResults.slice(0, resultLimit);
57571
57577
  if (returnResults) {
57572
57578
  return limitedResults;
@@ -66047,8 +66053,441 @@ var SearchApp = () => {
66047
66053
  }, undefined, true, undefined, this);
66048
66054
  };
66049
66055
 
66056
+ // src/components/search.rezi.tsx
66057
+ import { createNodeApp } from "@rezi-ui/node";
66058
+ import { Column, Row, Text as Text2, Input, Button, Box as Box2, Divider, Table, Page } from "@rezi-ui/jsx";
66059
+ import { draculaTheme, rgb } from "@rezi-ui/core";
66060
+ import { jsxDEV as jsxDEV5 } from "@rezi-ui/jsx/jsx-dev-runtime";
66061
+ var FluxTui = async () => {
66062
+ const fluxPath = await getFluxPath();
66063
+ const allFiles = await getAllBrainDumpFilePaths(fluxPath);
66064
+ const fileNames = allFiles.map((p) => p.match(/(\d{4}-\d{2})\.json$/)?.[1] ?? null).filter((f) => f !== null).sort().reverse();
66065
+ const app = createNodeApp({
66066
+ initialState: {
66067
+ query: "",
66068
+ results: [],
66069
+ selectedIndex: 0,
66070
+ loading: false,
66071
+ availableFiles: fileNames,
66072
+ selectedFile: "all"
66073
+ },
66074
+ theme: draculaTheme
66075
+ });
66076
+ const loadDumps = async (query, selectedFile) => {
66077
+ app.update((prev) => ({ ...prev, loading: true }));
66078
+ const specificFiles = selectedFile && selectedFile !== "all" ? [allFiles.find((f) => f.endsWith(`${selectedFile}.json`))] : null;
66079
+ try {
66080
+ const raw = query?.trim() ? await searchBrainDumpCommand(query.split(" "), true, 15, specificFiles) : await searchBrainDumpCommand([], true, 20, specificFiles);
66081
+ app.update((prev) => ({
66082
+ ...prev,
66083
+ results: raw || [],
66084
+ loading: false,
66085
+ selectedIndex: 0
66086
+ }));
66087
+ } catch {
66088
+ app.update((prev) => ({ ...prev, results: [], loading: false }));
66089
+ }
66090
+ };
66091
+ await loadDumps();
66092
+ const getContextTags2 = (result) => {
66093
+ const tags = [];
66094
+ if (result.scores) {
66095
+ if (result.scores.recency > 0.8)
66096
+ tags.push("recent");
66097
+ if (result.scores.gitContext >= 1)
66098
+ tags.push("branch");
66099
+ if (result.scores.gitContext >= 1.5)
66100
+ tags.push("dir");
66101
+ }
66102
+ if (result.item.tags?.length)
66103
+ tags.push(...result.item.tags);
66104
+ return tags.join(", ");
66105
+ };
66106
+ app.view((state) => {
66107
+ const selected = state.results[state.selectedIndex] ?? null;
66108
+ return /* @__PURE__ */ jsxDEV5(Page, {
66109
+ header: /* @__PURE__ */ jsxDEV5(Row, {
66110
+ gap: 2,
66111
+ p: 1,
66112
+ children: [
66113
+ /* @__PURE__ */ jsxDEV5(Text2, {
66114
+ variant: "label",
66115
+ style: { bold: true },
66116
+ children: "flux"
66117
+ }, undefined, false, undefined, this),
66118
+ /* @__PURE__ */ jsxDEV5(Text2, {
66119
+ variant: "caption",
66120
+ style: { dim: true },
66121
+ children: "·"
66122
+ }, undefined, false, undefined, this),
66123
+ /* @__PURE__ */ jsxDEV5(Row, {
66124
+ gap: 0,
66125
+ children: [
66126
+ /* @__PURE__ */ jsxDEV5(Text2, {
66127
+ variant: "label",
66128
+ children: [
66129
+ "Search ",
66130
+ state.query && `[searching for:`
66131
+ ]
66132
+ }, undefined, true, undefined, this),
66133
+ " ",
66134
+ /* @__PURE__ */ jsxDEV5(Text2, {
66135
+ style: {
66136
+ fg: rgb(200, 100, 200),
66137
+ underline: true,
66138
+ bold: true,
66139
+ italic: true
66140
+ },
66141
+ children: state.query
66142
+ }, undefined, false, undefined, this),
66143
+ state.query && `]`
66144
+ ]
66145
+ }, undefined, true, undefined, this),
66146
+ /* @__PURE__ */ jsxDEV5(Box2, {
66147
+ flex: 1,
66148
+ border: "none"
66149
+ }, undefined, false, undefined, this),
66150
+ /* @__PURE__ */ jsxDEV5(Text2, {
66151
+ variant: "caption",
66152
+ style: { dim: true },
66153
+ children: state.loading ? "searching..." : `${state.results.length} results`
66154
+ }, undefined, false, undefined, this)
66155
+ ]
66156
+ }, undefined, true, undefined, this),
66157
+ body: /* @__PURE__ */ jsxDEV5(Row, {
66158
+ flex: 1,
66159
+ gap: 0,
66160
+ children: [
66161
+ /* @__PURE__ */ jsxDEV5(Column, {
66162
+ flex: 1,
66163
+ gap: 0,
66164
+ children: /* @__PURE__ */ jsxDEV5(Table, {
66165
+ id: "results-table",
66166
+ columns: [
66167
+ { key: "time", header: "Time", width: 10 },
66168
+ { key: "message", header: "Message", flex: 1, overflow: "ellipsis" }
66169
+ ],
66170
+ onRowPress: (value) => {
66171
+ const index = state.results.findIndex((r) => `#${r.item.id.substring(0, 8)}` === value.id);
66172
+ if (index !== -1) {
66173
+ app.update((prev) => ({ ...prev, selectedIndex: index }));
66174
+ }
66175
+ },
66176
+ data: state.results.map((result, index) => ({
66177
+ index: String(index + 1),
66178
+ id: `#${result.item.id.substring(0, 8)}`,
66179
+ score: result.scores?.final?.toFixed(2) ?? "0.00",
66180
+ time: getTimeAgo(new Date(result.item.timestamp)).replace(" ago", ""),
66181
+ message: result.item.message ?? ""
66182
+ })),
66183
+ stripedRows: true,
66184
+ getRowKey: (_row, index) => `row-${index}`,
66185
+ selectionMode: "single",
66186
+ selection: [`row-${state.selectedIndex}`],
66187
+ borderStyle: { variant: "rounded" }
66188
+ }, undefined, false, undefined, this)
66189
+ }, undefined, false, undefined, this),
66190
+ /* @__PURE__ */ jsxDEV5(Column, {
66191
+ flex: 2,
66192
+ gap: 1,
66193
+ p: 2,
66194
+ scrollY: 100,
66195
+ children: [
66196
+ selected && /* @__PURE__ */ jsxDEV5(Row, {
66197
+ children: [
66198
+ /* @__PURE__ */ jsxDEV5(Row, {
66199
+ gap: 2,
66200
+ flex: 1,
66201
+ children: [
66202
+ /* @__PURE__ */ jsxDEV5(Text2, {
66203
+ variant: "caption",
66204
+ style: { dim: true },
66205
+ children: "ID"
66206
+ }, undefined, false, undefined, this),
66207
+ /* @__PURE__ */ jsxDEV5(Text2, {
66208
+ style: {
66209
+ underline: true,
66210
+ fg: rgb(200, 0, 200)
66211
+ },
66212
+ children: [
66213
+ "#",
66214
+ selected.item.id.substring(0, 8)
66215
+ ]
66216
+ }, undefined, true, undefined, this)
66217
+ ]
66218
+ }, undefined, true, undefined, this),
66219
+ /* @__PURE__ */ jsxDEV5(Column, {
66220
+ gap: 0,
66221
+ children: [
66222
+ /* @__PURE__ */ jsxDEV5(Row, {
66223
+ gap: 2,
66224
+ children: [
66225
+ /* @__PURE__ */ jsxDEV5(Text2, {
66226
+ variant: "caption",
66227
+ style: { dim: true },
66228
+ children: "Created"
66229
+ }, undefined, false, undefined, this),
66230
+ /* @__PURE__ */ jsxDEV5(Text2, {
66231
+ children: new Date(selected.item.timestamp).toLocaleString()
66232
+ }, undefined, false, undefined, this)
66233
+ ]
66234
+ }, undefined, true, undefined, this),
66235
+ selected.item.branch && /* @__PURE__ */ jsxDEV5(Row, {
66236
+ gap: 2,
66237
+ children: [
66238
+ /* @__PURE__ */ jsxDEV5(Text2, {
66239
+ variant: "caption",
66240
+ style: { dim: true },
66241
+ children: "Branch"
66242
+ }, undefined, false, undefined, this),
66243
+ /* @__PURE__ */ jsxDEV5(Text2, {
66244
+ style: {
66245
+ fg: rgb(200, 200, 25)
66246
+ },
66247
+ children: [
66248
+ selected.item.branch,
66249
+ selected.item.hasUncommittedChanges ? " (uncommitted)" : ""
66250
+ ]
66251
+ }, undefined, true, undefined, this)
66252
+ ]
66253
+ }, undefined, true, undefined, this),
66254
+ selected.item.workingDir && /* @__PURE__ */ jsxDEV5(Row, {
66255
+ gap: 2,
66256
+ children: [
66257
+ /* @__PURE__ */ jsxDEV5(Text2, {
66258
+ variant: "caption",
66259
+ style: { dim: true },
66260
+ children: "Dir"
66261
+ }, undefined, false, undefined, this),
66262
+ /* @__PURE__ */ jsxDEV5(Text2, {
66263
+ children: (() => {
66264
+ const parts = selected.item.workingDir?.split("/") || [];
66265
+ return parts.length >= 2 ? `${parts[parts.length - 2]} / ${parts[parts.length - 1]}` : selected.item.workingDir || "";
66266
+ })()
66267
+ }, undefined, false, undefined, this)
66268
+ ]
66269
+ }, undefined, true, undefined, this)
66270
+ ]
66271
+ }, undefined, true, undefined, this)
66272
+ ]
66273
+ }, undefined, true, undefined, this),
66274
+ /* @__PURE__ */ jsxDEV5(Divider, {}, undefined, false, undefined, this),
66275
+ selected ? /* @__PURE__ */ jsxDEV5(Column, {
66276
+ gap: 1,
66277
+ children: [
66278
+ /* @__PURE__ */ jsxDEV5(Column, {
66279
+ gap: 0,
66280
+ wrap: true,
66281
+ children: [
66282
+ /* @__PURE__ */ jsxDEV5(Text2, {
66283
+ variant: "caption",
66284
+ style: { dim: true },
66285
+ children: "Message:"
66286
+ }, undefined, false, undefined, this),
66287
+ /* @__PURE__ */ jsxDEV5(Text2, {
66288
+ wrap: true,
66289
+ children: selected.item.message
66290
+ }, undefined, false, undefined, this)
66291
+ ]
66292
+ }, undefined, true, undefined, this),
66293
+ selected.scores && /* @__PURE__ */ jsxDEV5(Column, {
66294
+ gap: 0,
66295
+ children: [
66296
+ /* @__PURE__ */ jsxDEV5(Text2, {
66297
+ variant: "caption",
66298
+ style: { dim: true },
66299
+ children: "Context Rating: "
66300
+ }, undefined, false, undefined, this),
66301
+ /* @__PURE__ */ jsxDEV5(Row, {
66302
+ gap: 1,
66303
+ children: [
66304
+ /* @__PURE__ */ jsxDEV5(Column, {
66305
+ gap: 0,
66306
+ children: [
66307
+ /* @__PURE__ */ jsxDEV5(Text2, {
66308
+ variant: "caption",
66309
+ style: { dim: true },
66310
+ children: "final"
66311
+ }, undefined, false, undefined, this),
66312
+ /* @__PURE__ */ jsxDEV5(Text2, {
66313
+ children: [
66314
+ (selected.scores.final * 100).toFixed(0),
66315
+ "%"
66316
+ ]
66317
+ }, undefined, true, undefined, this)
66318
+ ]
66319
+ }, undefined, true, undefined, this),
66320
+ /* @__PURE__ */ jsxDEV5(Column, {
66321
+ gap: 0,
66322
+ children: [
66323
+ /* @__PURE__ */ jsxDEV5(Text2, {
66324
+ variant: "caption",
66325
+ style: { dim: true },
66326
+ children: "fuzzy"
66327
+ }, undefined, false, undefined, this),
66328
+ /* @__PURE__ */ jsxDEV5(Text2, {
66329
+ children: [
66330
+ (selected.scores.fuzzyMatch * 100).toFixed(0),
66331
+ "%"
66332
+ ]
66333
+ }, undefined, true, undefined, this)
66334
+ ]
66335
+ }, undefined, true, undefined, this),
66336
+ /* @__PURE__ */ jsxDEV5(Column, {
66337
+ gap: 0,
66338
+ children: [
66339
+ /* @__PURE__ */ jsxDEV5(Text2, {
66340
+ variant: "caption",
66341
+ style: { dim: true },
66342
+ children: "recency"
66343
+ }, undefined, false, undefined, this),
66344
+ /* @__PURE__ */ jsxDEV5(Text2, {
66345
+ children: [
66346
+ (selected.scores.recency * 100).toFixed(0),
66347
+ "%"
66348
+ ]
66349
+ }, undefined, true, undefined, this)
66350
+ ]
66351
+ }, undefined, true, undefined, this),
66352
+ /* @__PURE__ */ jsxDEV5(Column, {
66353
+ gap: 0,
66354
+ children: [
66355
+ /* @__PURE__ */ jsxDEV5(Text2, {
66356
+ variant: "caption",
66357
+ style: { dim: true },
66358
+ children: "git"
66359
+ }, undefined, false, undefined, this),
66360
+ /* @__PURE__ */ jsxDEV5(Text2, {
66361
+ children: [
66362
+ (selected.scores.gitContext * 100).toFixed(0),
66363
+ "%"
66364
+ ]
66365
+ }, undefined, true, undefined, this)
66366
+ ]
66367
+ }, undefined, true, undefined, this)
66368
+ ]
66369
+ }, undefined, true, undefined, this)
66370
+ ]
66371
+ }, undefined, true, undefined, this)
66372
+ ]
66373
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV5(Text2, {
66374
+ variant: "caption",
66375
+ style: { dim: true },
66376
+ children: "Use j / k or ↑ ↓ to select a dump"
66377
+ }, undefined, false, undefined, this)
66378
+ ]
66379
+ }, undefined, true, undefined, this)
66380
+ ]
66381
+ }, undefined, true, undefined, this),
66382
+ footer: /* @__PURE__ */ jsxDEV5(Column, {
66383
+ gap: 0,
66384
+ children: [
66385
+ /* @__PURE__ */ jsxDEV5(Divider, {}, undefined, false, undefined, this),
66386
+ /* @__PURE__ */ jsxDEV5(Row, {
66387
+ gap: 2,
66388
+ p: 1,
66389
+ items: "center",
66390
+ children: [
66391
+ /* @__PURE__ */ jsxDEV5(Button, {
66392
+ id: `file-all`,
66393
+ label: "all",
66394
+ dsVariant: state.selectedFile === "all" ? "solid" : "ghost",
66395
+ dsTone: state.selectedFile === "all" ? "primary" : "default",
66396
+ dsSize: "sm",
66397
+ onPress: () => {
66398
+ loadDumps("", "all");
66399
+ app.update((prev) => ({
66400
+ ...prev,
66401
+ selectedFile: prev.selectedFile === "all" ? null : "all"
66402
+ }));
66403
+ }
66404
+ }, undefined, false, undefined, this),
66405
+ state.availableFiles.slice(0, 5).map((file) => /* @__PURE__ */ jsxDEV5(Button, {
66406
+ id: `file-${file}`,
66407
+ label: file,
66408
+ dsVariant: state.selectedFile === file ? "solid" : "ghost",
66409
+ dsTone: state.selectedFile === file ? "primary" : "default",
66410
+ dsSize: "sm",
66411
+ onPress: () => {
66412
+ loadDumps("", file);
66413
+ app.update((prev) => ({
66414
+ ...prev,
66415
+ selectedFile: prev.selectedFile === file ? null : file
66416
+ }));
66417
+ }
66418
+ }, file, false, undefined, this)),
66419
+ /* @__PURE__ */ jsxDEV5(Text2, {
66420
+ variant: "caption",
66421
+ style: { dim: true },
66422
+ children: "j/k navigate · q quit"
66423
+ }, undefined, false, undefined, this)
66424
+ ]
66425
+ }, undefined, true, undefined, this),
66426
+ /* @__PURE__ */ jsxDEV5(Row, {
66427
+ gap: 1,
66428
+ p: 1,
66429
+ items: "center",
66430
+ children: [
66431
+ /* @__PURE__ */ jsxDEV5(Text2, {
66432
+ variant: "caption",
66433
+ style: { dim: true },
66434
+ children: "Search:"
66435
+ }, undefined, false, undefined, this),
66436
+ /* @__PURE__ */ jsxDEV5(Box2, {
66437
+ width: "full",
66438
+ flex: 1,
66439
+ children: /* @__PURE__ */ jsxDEV5(Input, {
66440
+ focusable: true,
66441
+ style: {
66442
+ blink: true
66443
+ },
66444
+ focusConfig: { indicator: "bracket", ringVariant: "dotted", animation: "pulse" },
66445
+ dsSize: "lg",
66446
+ id: "search",
66447
+ value: state.query,
66448
+ placeholder: "type to search using ...",
66449
+ onInput: (value) => {
66450
+ app.update((prev) => ({ ...prev, query: value }));
66451
+ loadDumps(value);
66452
+ }
66453
+ }, undefined, false, undefined, this)
66454
+ }, undefined, false, undefined, this)
66455
+ ]
66456
+ }, undefined, true, undefined, this)
66457
+ ]
66458
+ }, undefined, true, undefined, this)
66459
+ }, undefined, false, undefined, this);
66460
+ });
66461
+ app.keys({
66462
+ q: () => app.stop(),
66463
+ j: () => app.update((prev) => ({
66464
+ ...prev,
66465
+ selectedIndex: Math.min(prev.results.length - 1, prev.selectedIndex + 1)
66466
+ })),
66467
+ k: () => app.update((prev) => ({
66468
+ ...prev,
66469
+ selectedIndex: Math.max(0, prev.selectedIndex - 1)
66470
+ })),
66471
+ down: () => app.update((prev) => ({
66472
+ ...prev,
66473
+ selectedIndex: Math.min(prev.results.length - 1, prev.selectedIndex + 1)
66474
+ })),
66475
+ up: () => app.update((prev) => ({
66476
+ ...prev,
66477
+ selectedIndex: Math.max(0, prev.selectedIndex - 1)
66478
+ }))
66479
+ });
66480
+ await app.start();
66481
+ };
66482
+
66050
66483
  // src/commands/ui.command.ts
66051
- async function tuiCommand() {
66484
+ async function tuiCommandRezi() {
66485
+ console.log(`
66486
+ Starting Flux-Cap Interactive Search...
66487
+ `);
66488
+ await FluxTui();
66489
+ }
66490
+ async function tuiCommandInk() {
66052
66491
  console.log(`
66053
66492
  Starting Flux-Cap Interactive Search...
66054
66493
  `);
@@ -66067,5 +66506,6 @@ program2.command("s [query...]").alias("search").description("Search brain dumps
66067
66506
  searchBrainDumpCommand(query ? query : [""]);
66068
66507
  });
66069
66508
  program2.command("config [data...]").description("Update configuration fields. Example: flux config search.limit 10").action(configCommand);
66070
- program2.command("u").alias("ui").description("Open interactive search TUI").action(tuiCommand);
66509
+ program2.command("u").alias("ui").description("Open interactive search TUI built using rezi").action(tuiCommandRezi);
66510
+ program2.command("ui-ink").description("Open interactive search TUI built using ink").action(tuiCommandInk);
66071
66511
  program2.parse(process.argv);
package/package.json CHANGED
@@ -1,64 +1,67 @@
1
1
  {
2
- "name": "@dev_desh/flux-cap",
3
- "type": "module",
4
- "version": "0.9.1",
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
- "@types/react": "^19.2.14",
43
- "@types/react-dom": "^19.2.3",
44
- "commander": "^14.0.3",
45
- "fuse.js": "^7.1.0",
46
- "ink": "^6.8.0",
47
- "ink-text-input": "^6.0.0",
48
- "inquirer": "^13.2.5",
49
- "react": "^19.2.4",
50
- "react-devtools-core": "^7.0.1",
51
- "react-dom": "^19.2.4"
52
- },
53
- "devDependencies": {
54
- "@biomejs/biome": "2.4.4",
55
- "@changesets/cli": "^2.29.8",
56
- "@types/inquirer": "^9.0.9",
57
- "@types/node": "^25.3.3"
58
- },
59
- "repository": {
60
- "type": "git",
61
- "url": "https://github.com/kaustubh285/flux-cap"
62
- },
63
- "license": "MIT"
2
+ "name": "@dev_desh/flux-cap",
3
+ "type": "module",
4
+ "version": "0.10.1",
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 --external @rezi-ui/core --external @rezi-ui/node --external @rezi-ui/jsx --external @rezi-ui/native",
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
+ "@rezi-ui/core": "^0.1.0-alpha.59",
43
+ "@rezi-ui/jsx": "^0.1.0-alpha.59",
44
+ "@rezi-ui/node": "^0.1.0-alpha.59",
45
+ "@types/react": "^19.2.14",
46
+ "@types/react-dom": "^19.2.3",
47
+ "commander": "^14.0.3",
48
+ "fuse.js": "^7.1.0",
49
+ "ink": "^6.8.0",
50
+ "ink-text-input": "^6.0.0",
51
+ "inquirer": "^13.2.5",
52
+ "react": "^19.2.4",
53
+ "react-devtools-core": "^7.0.1",
54
+ "react-dom": "^19.2.4"
55
+ },
56
+ "devDependencies": {
57
+ "@biomejs/biome": "2.4.4",
58
+ "@changesets/cli": "^2.29.8",
59
+ "@types/inquirer": "^9.0.9",
60
+ "@types/node": "^25.3.3"
61
+ },
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "https://github.com/kaustubh285/flux-cap"
65
+ },
66
+ "license": "MIT"
64
67
  }