@j-o-r/hello-dave 0.0.5 → 0.0.7

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 (127) hide show
  1. package/CHANGELOG.md +13 -26
  2. package/README.md +161 -522
  3. package/README.md.bak +144 -449
  4. package/{examples → agents}/ask_agent.js +5 -5
  5. package/{examples → agents}/codeserver.sh +14 -14
  6. package/{examples → agents}/daisy_agent.js +5 -5
  7. package/{examples → agents}/docs_agent.js +5 -5
  8. package/{examples → agents}/gpt_agent.js +5 -5
  9. package/{examples → agents}/grok_agent.js +5 -5
  10. package/agents/memory_agent.js +263 -0
  11. package/{examples → agents}/npm_agent.js +5 -5
  12. package/{examples → agents}/prompt_agent.js +5 -5
  13. package/agents/spawn_agent.js +137 -0
  14. package/{examples → agents}/test_agent.js +6 -8
  15. package/{examples → agents}/todo_agent.js +5 -5
  16. package/bin/codeDave +58 -0
  17. package/bin/dave.js +114 -96
  18. package/lib/AgentClient.js +111 -67
  19. package/lib/AgentManager.js +111 -80
  20. package/lib/AgentServer.js +144 -104
  21. package/lib/Cli.js +126 -93
  22. package/lib/Prompt.js +38 -5
  23. package/lib/Session.js +102 -79
  24. package/lib/ToolSet.js +79 -60
  25. package/lib/fafs.js +54 -19
  26. package/lib/genericToolset.js +109 -213
  27. package/lib/wsCli.js +50 -19
  28. package/lib/wsIO.js +11 -17
  29. package/package.json +2 -2
  30. package/types/AgentClient.d.ts +69 -35
  31. package/types/AgentManager.d.ts +50 -56
  32. package/types/AgentServer.d.ts +63 -16
  33. package/types/Cli.d.ts +56 -10
  34. package/types/Prompt.d.ts +36 -4
  35. package/types/Session.d.ts +23 -9
  36. package/types/ToolSet.d.ts +49 -32
  37. package/types/fafs.d.ts +68 -25
  38. package/types/wsCli.d.ts +14 -0
  39. package/types/wsIO.d.ts +9 -5
  40. package/utils/search_sessions.sh +100 -53
  41. package/README.md.backup +0 -269
  42. package/README.md.bak.1774780058 +0 -338
  43. package/README.md.bak2 +0 -531
  44. package/bin/spawn_agent.js +0 -293
  45. package/docs.bak.1774780058/agent-manager.md +0 -167
  46. package/docs.bak.1774780058/agent-manager.md.bak +0 -137
  47. package/docs.bak.1774780058/agent-manager.md.bak2 +0 -157
  48. package/docs.bak.1774780058/codeserver-pattern.md +0 -191
  49. package/docs.bak.1774780058/path-resolution-best-practices.md +0 -104
  50. package/docs.bak.1774780058/project-overview.md +0 -67
  51. package/docs.bak.1774780058/project-overview.md.bak +0 -67
  52. package/docs.bak.1774780058/prompt-class.md +0 -141
  53. package/docs.bak.1774780058/prompt-class.md.bak +0 -142
  54. package/docs.bak.1774780058/tools-syntax-validation.md +0 -121
  55. package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +0 -125
  56. package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +0 -125
  57. package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +0 -106
  58. package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +0 -106
  59. package/docs.bak.1774780058/toolset.md +0 -164
  60. package/docs.bak.1774780058/toolset.md.bak +0 -94
  61. package/docs.bak.1774780058/toolset.md.bak3 +0 -161
  62. package/docs.bak.1774780058/toolset.md.bak4 +0 -161
  63. package/docs.bak.1774780058/toolset.md.bak5 +0 -161
  64. package/docs.bak.1774780058/toolset.md.bak6 +0 -163
  65. package/docs.bak.1774780058/toolset.md.bak_path +0 -163
  66. package/docs.bak.1774780058/toolset.md.bak_syntax +0 -161
  67. package/docs.bak.1774780058/xai-responses.md +0 -111
  68. package/docs.bak.1774780058/xai-responses.md.bak +0 -107
  69. package/docs.bak.1774780058/xai-responses.md.bak2 +0 -107
  70. package/docs.bak.1774780058/xai_collections.md +0 -106
  71. package/examples/memory_agent.js +0 -152
  72. package/examples.bak.1774780058/ask_agent.js +0 -114
  73. package/examples.bak.1774780058/code_agent.js +0 -149
  74. package/examples.bak.1774780058/coderev_agent.js +0 -72
  75. package/examples.bak.1774780058/codeserver.sh +0 -47
  76. package/examples.bak.1774780058/daisy_agent.js +0 -177
  77. package/examples.bak.1774780058/docs_agent.js +0 -119
  78. package/examples.bak.1774780058/gpt_agent.js +0 -109
  79. package/examples.bak.1774780058/grok_agent.js +0 -98
  80. package/examples.bak.1774780058/memory_agent.js +0 -112
  81. package/examples.bak.1774780058/npm_agent.js +0 -175
  82. package/examples.bak.1774780058/prompt_agent.js +0 -112
  83. package/examples.bak.1774780058/readme_agent.js +0 -144
  84. package/examples.bak.1774780058/spawn_agent.js +0 -263
  85. package/examples.bak.1774780058/test_agent.js +0 -162
  86. package/examples.bak.1774780058/todo_agent.js +0 -138
  87. package/lib/genericToolset.js.bak_syntax +0 -402
  88. package/scenarios.bak.1774780058/data/eval_node_message.json +0 -9
  89. package/scenarios.bak.1774780058/data/hist_oa.json +0 -66
  90. package/scenarios.bak.1774780058/data/o3_response1.json +0 -96
  91. package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +0 -112
  92. package/scenarios.bak.1774780058/data/tool_oa.json +0 -96
  93. package/scenarios.bak.1774780058/data/tool_xai.json +0 -59
  94. package/scenarios.bak.1774780058/data/tool_xai2.json +0 -40
  95. package/scenarios.bak.1774780058/data/xai-response-1.json +0 -59
  96. package/scenarios.bak.1774780058/data/xai-response-2.json +0 -10
  97. package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +0 -59
  98. package/scenarios.bak.1774780058/data/xai_search_response.json +0 -58
  99. package/scenarios.bak.1774780058/environment.js +0 -10
  100. package/scenarios.bak.1774780058/example.js +0 -17
  101. package/scenarios.bak.1774780058/genericToolset.test.js +0 -182
  102. package/scenarios.bak.1774780058/grok.js +0 -113
  103. package/scenarios.bak.1774780058/memory-tools.js +0 -51
  104. package/scenarios.bak.1774780058/openai-o3.js +0 -137
  105. package/scenarios.bak.1774780058/openai-prompt.js +0 -155
  106. package/scenarios.bak.1774780058/openai-session.js +0 -148
  107. package/scenarios.bak.1774780058/openai.js +0 -102
  108. package/scenarios.bak.1774780058/prompt.js +0 -118
  109. package/scenarios.bak.1774780058/promptFishbowl.js +0 -76
  110. package/scenarios.bak.1774780058/search.brave.com.js +0 -25
  111. package/scenarios.bak.1774780058/sh.js +0 -15
  112. package/scenarios.bak.1774780058/test-wsio.js +0 -26
  113. package/scenarios.bak.1774780058/testToolset.js +0 -42
  114. package/scenarios.bak.1774780058/toolset.js +0 -16
  115. package/scenarios.bak.1774780058/toolset.test.js +0 -141
  116. package/scenarios.bak.1774780058/write_file_syntax.test.js +0 -145
  117. package/scenarios.bak.1774780058/write_file_validation/README.md +0 -30
  118. package/scenarios.bak.1774780058/write_file_validation/bad.js +0 -3
  119. package/scenarios.bak.1774780058/write_file_validation/good.js +0 -4
  120. package/scenarios.bak.1774780058/write_file_validation/test.sh +0 -43
  121. package/scenarios.bak.1774780058/wsClient.js +0 -69
  122. package/scenarios.bak.1774780058/xai_responses.integration.test.js +0 -57
  123. package/scenarios.bak.1774780058/xai_responses.test.js +0 -154
  124. package/scenarios.bak.1774780058/xaicoll.js +0 -50
  125. package/scenarios.bak.1774780058/xaifiles.js +0 -48
  126. /package/{examples → agents}/code_agent.js +0 -0
  127. /package/{examples → agents}/readme_agent.js +0 -0
@@ -22,6 +22,9 @@ export type TSTool = {
22
22
  * - JS JSON schema
23
23
  */
24
24
  parameters: TSSchema;
25
+ /**
26
+ * - The async method to execute
27
+ */
25
28
  method: (arg0: object) => Promise<any>;
26
29
  };
27
30
  export type TSToolListItem = {
@@ -38,57 +41,71 @@ export type TSToolListItem = {
38
41
  */
39
42
  parameters: TSSchema;
40
43
  };
44
+ /**
45
+ * @classdesc ToolSet manages a collection of tools (functions) that can be registered and executed, typically for AI agent function calling.
46
+ * Supports schema definition compatible with JSON Schema for parameters.
47
+ */
41
48
  declare class ToolSet {
42
49
  /**
43
- * @param {string} [choice] - Default 'auto' auto|none|required
44
- */
50
+ * Constructs a new ToolSet instance.
51
+ * @param {string} [choice='auto'] - Default tool choice: 'auto' | 'none' | 'required'
52
+ */
45
53
  constructor(choice?: string);
46
54
  /**
47
- * How many functions have we registered
48
- * @returns {number}
49
- */
55
+ * Getter for the number of registered tools.
56
+ * @returns {number} The count of tools in the set
57
+ */
50
58
  get length(): number;
51
59
  /**
52
- * Register a Tool/Command/Function
53
- * @param {string} name - [a-z_0-9]{2,} The lowercase string name of the callback e.g. 'get_node_version'
54
- * @param {string} description - What does it do
55
- * @param {TSSchema} parameters - SCHEMA object describing the function's input parameters
56
- * @param {function(object): Promise<*>} method - Async function to call
57
- */
60
+ * Registers a new tool/command/function in the set.
61
+ * Overwrites if already exists (no error thrown).
62
+ * @param {string} name - The lowercase string name of the tool e.g. 'get_node_version'. Must match /^[#!a-z_0-9]{2,}$/
63
+ * @param {string} description - Human-readable description of what the tool does
64
+ * @param {TSSchema} parameters - JSON Schema object describing the input parameters
65
+ * @param {function(object): Promise<*>} method - The async function to call with parsed parameters
66
+ */
58
67
  add(name: string, description: string, parameters: TSSchema, method: (arg0: object) => Promise<any>): void;
59
68
  /**
60
- * Get a tool from the toolset
61
- * @param {string} name
62
- * @returns {TSTool}
63
- */
69
+ * Retrieves a registered tool by name.
70
+ * @param {string} name - The name of the tool
71
+ * @returns {TSTool} The tool object
72
+ * @throws {Error} If tool not found
73
+ */
64
74
  get(name: string): TSTool;
65
75
  /**
66
- * Delete a function_call
67
- * @param {string} name
68
- */
76
+ * Deletes a tool from the set by name.
77
+ * @param {string} name - The name of the tool to delete
78
+ */
69
79
  delete(name: string): void;
70
80
  /**
71
- * Is 'name' already registered
72
- * @param {string} name
73
- * @returns {boolean}
74
- */
81
+ * Checks if a tool with the given name is registered.
82
+ * @param {string} name - The tool name to check
83
+ * @returns {boolean} True if the tool exists
84
+ */
75
85
  has(name: string): boolean;
76
86
  /**
77
- * Get a list of tools available
78
- * @returns {TSToolListItem[]}
79
- */
87
+ * Returns a sorted list of all registered tools (excluding methods).
88
+ * @returns {TSToolListItem[]} Array of tool summaries, sorted by name
89
+ */
80
90
  list(): TSToolListItem[];
91
+ /**
92
+ * Getter for the current tool choice setting.
93
+ * @returns {string} The tool choice: 'auto', 'none', or 'required'
94
+ */
81
95
  get toolChoice(): string;
82
96
  /**
83
- * Execute a method
84
- * @param {string} name
85
- * @param {object} params
86
- * @returns {Promise<*>}
87
- */
97
+ * Executes a specific tool by name with given parameters.
98
+ * @param {string} name - The tool name
99
+ * @param {object} params - The parameters object
100
+ * @returns {Promise<*>} The result from the tool method
101
+ * @throws {Error} If tool not found or execution fails
102
+ */
88
103
  call(name: string, params: object): Promise<any>;
89
104
  /**
90
- * Execute function requests from the last message.
91
- * @param {Prompt} prompt - Handle tool calls.
105
+ * Processes and executes function requests from the last message in a Prompt.
106
+ * Automatically handles multiple calls, emits events, and adds responses back to the prompt.
107
+ * @param {Prompt} prompt - The Prompt instance containing the last message with function_request(s)
108
+ * @returns {Promise<void>}
92
109
  */
93
110
  execute(prompt: Prompt): Promise<void>;
94
111
  #private;
package/types/fafs.d.ts CHANGED
@@ -1,47 +1,90 @@
1
1
  export type EnvironmentInfo = {
2
2
  /**
3
- * - User's name
3
+ * - User's full name (from passwd GECOS field)
4
4
  */
5
5
  name: string;
6
6
  /**
7
- * - Linux OS / PROC
7
+ * - System information (OS release, architecture, kernel, cwd)
8
8
  */
9
9
  system: string;
10
+ /**
11
+ * - City from external IP geolocation
12
+ */
10
13
  city: string;
14
+ /**
15
+ * - Region/State from IP
16
+ */
11
17
  region: string;
18
+ /**
19
+ * - Country from IP
20
+ */
12
21
  country: string;
22
+ /**
23
+ * - Timezone from IP
24
+ */
13
25
  timezone: string;
26
+ /**
27
+ * - External IP address
28
+ */
14
29
  external_ip: string;
15
30
  /**
16
- * - current working folder
31
+ * - Current working directory (relative to home as ~)
17
32
  */
18
33
  cwd: string;
19
34
  };
20
35
  import { jsType } from '@j-o-r/sh';
21
- export namespace GLOBAL {
22
- export let max_recursive_requests: number;
23
- export { APP_CACHE as default_cache };
24
- export let secret: string;
25
- }
26
36
  /**
27
- * Gather information about this environment
28
- * @returns {Promise<EnvironmentInfo>}
29
- */
30
- export function env(): Promise<EnvironmentInfo>;
37
+ * Frequently Asked Functions (FAFS) - Utility module providing environment and system information utilities.
38
+ *
39
+ * Main features:
40
+ * - `env()`: Gathers user, system, location, and path info (cached 31 days).
41
+ * - `systemInfo()`: Detailed OS/architecture/working dir string.
42
+ * - `GLOBAL`: Shared config (max requests, cache path, secret).
43
+ *
44
+ * @module fafs
45
+ * @exports {function} env
46
+ * @exports {function} systemInfo
47
+ * @exports {Object} GLOBAL
48
+ * @exports {function} jsType
49
+ */
31
50
  /**
32
- * @typedef {Object} EnvironmentInfo
33
- * @property {string} name - User's name
34
- * @property {string} system - Linux OS / PROC
35
- * @property {string} city
36
- * @property {string} region
37
- * @property {string} country
38
- * @property {string} timezone
39
- * @property {string} external_ip
40
- * @property {string} cwd - current working folder
41
- */
51
+ * @typedef {Object} EnvironmentInfo
52
+ * @property {string} name - User's full name (from passwd GECOS field)
53
+ * @property {string} system - System information (OS release, architecture, kernel, cwd)
54
+ * @property {string} city - City from external IP geolocation
55
+ * @property {string} region - Region/State from IP
56
+ * @property {string} country - Country from IP
57
+ * @property {string} timezone - Timezone from IP
58
+ * @property {string} external_ip - External IP address
59
+ * @property {string} cwd - Current working directory (relative to home as ~)
60
+ */
61
+ /**
62
+ * Global configuration and constants for the application.
63
+ * @type {Object}
64
+ * @property {number} max_recursive_requests - Maximum number of recursive requests allowed (default: 20)
65
+ * @property {string} default_cache - Path to the default application cache directory
66
+ * @property {string} secret - Secret key for cache encryption/security
67
+ */
68
+ export const GLOBAL: Object;
69
+ /**
70
+ * Gathers comprehensive environment information: user name, fresh system details, IP-based geolocation,
71
+ * and normalized current working directory. Results are cached in ~/.cache/hello-dave/env for 31 days,
72
+ * refreshed on expiry. On cache hit, updates with fresh system info and cwd.
73
+ *
74
+ * @returns {Promise<EnvironmentInfo>} The environment information object.
75
+ * @example
76
+ * const envInfo = await env();
77
+ * console.log(envInfo.name, envInfo.city, envInfo.system);
78
+ */
79
+ export function env(): Promise<EnvironmentInfo>;
42
80
  /**
43
- * @returns {Promise<string>}
44
- */
81
+ * Retrieves detailed system information including OS release (/etc/issue), machine architecture (uname -m),
82
+ * operating system (uname -o), and current working directory.
83
+ *
84
+ * @returns {Promise<string>} Formatted multi-line string with system details.
85
+ * @example
86
+ * const info = await systemInfo();
87
+ * // "system: Ubuntu 25.10 \n\nx86_64\nGNU/Linux\ncwd: /home/user/project"
88
+ */
45
89
  export function systemInfo(): Promise<string>;
46
- declare const APP_CACHE: any;
47
90
  export { jsType };
package/types/wsCli.d.ts CHANGED
@@ -1,3 +1,17 @@
1
1
  #!/usr/bin/env -S node
2
2
  declare function _default(connectUrl: string, secret?: string): void;
3
3
  export default _default;
4
+ export type WsMessage = {
5
+ /**
6
+ * - Action type (e.g., 'user_request')
7
+ */
8
+ action: string;
9
+ /**
10
+ * - Message content
11
+ */
12
+ content: string;
13
+ /**
14
+ * - Unique message ID
15
+ */
16
+ id: number;
17
+ };
package/types/wsIO.d.ts CHANGED
@@ -10,12 +10,16 @@
10
10
  * Sends intro + action, awaits matching response by ID, closes, returns response.
11
11
  *
12
12
  * @param {string} connectUrl - Websocket server endpoint to connect to
13
- * @param {string} [secret] - Secret websocket connection key
14
- * @param {'user_request'|'user_info'|'user_reset'} action - Action
15
- * @param {string} [input] - When action is 'user_request' input is the query
16
- * @returns {Promise<wsResponse>}
13
+ * @param {string} [secret=''] - Secret websocket connection key
14
+ * @param {'user_request'|'user_info'|'user_reset'} action - Action to perform
15
+ * @param {string} [input=''] - Input content (required for 'user_request')
16
+ * @returns {Promise&lt;wsResponse&gt;}
17
+ * @throws {Error} Invalid action or missing input for user_request
18
+ * @example
19
+ * const response = await wsio('ws://localhost:8080', 'secret', 'user_request', 'Hello!');
20
+ * console.log(response.content);
17
21
  */
18
- export default function wsio(connectUrl: string, secret?: string, action: "user_request" | "user_info" | "user_reset", input?: string): Promise<wsResponse>;
22
+ export default function wsio(connectUrl: string, secret?: string, action: "user_request" | "user_info" | "user_reset", input?: string): Promise<any> & lt;
19
23
  export type wsResponse = {
20
24
  action: string;
21
25
  content: string;
@@ -1,73 +1,120 @@
1
1
  #!/bin/bash
2
+ # v2: Role-filtered (user/assistant only), condense per-session/dir, ultra token-efficient.
3
+ # Usage: $0 <query> [--brief] [--all-roles] [--limit=10] [--max-snip=3]
2
4
 
3
- # No set -e to avoid unexpected exits; use explicit checks
4
5
  set -uo pipefail
5
6
 
6
- if [ $# -eq 0 ]; then
7
- echo "Usage: $0 <search_query_or_regex>"
8
- echo " Searches filenames & content in all .cache/[app]/[prompt]/sessions/*.ndjson"
9
- echo " Shows matching sessions/files with context (grep -i -C5, line nums)."
10
- echo " Quote multi-word/regex: $0 \"package.json\" or $0 \"(hdTodo|todo)\""
11
- exit 1
12
- fi
7
+ usage() {
8
+ echo "Usage: $0 <query> [--brief] [--all-roles] [--limit=10] [--max-snip=3]"
9
+ echo " Role-filtered snippets (user/assistant), condensed per session dir."
10
+ exit 1
11
+ }
12
+
13
+ [ $# -eq 0 ] && usage
13
14
 
14
15
  QUERY="$1"
15
- echo "🔍 Searching sessions for (case-insensitive regex): '$QUERY'"
16
- echo "=================================================================="
17
- echo ""
16
+ LIMIT=10
17
+ MAX_SNIP=3
18
+ BRIEF=false
19
+ ROLE_FILTER=true # Default: user/assistant only
20
+ shift
21
+
22
+ while [ $# -gt 0 ]; do
23
+ case "$1" in
24
+ --brief) BRIEF=true; shift ;;
25
+ --all-roles) ROLE_FILTER=false; shift ;;
26
+ --limit=*) LIMIT="${1#*=}"; shift ;;
27
+ --max-snip=*) MAX_SNIP="${1#*=}"; shift ;;
28
+ --limit) LIMIT="$2"; shift 2 ;;
29
+ --max-snip) MAX_SNIP="$2"; shift 2 ;;
30
+ *) echo "Unknown: $1"; usage ;;
31
+ esac
32
+ done
18
33
 
19
- total_matches=0
20
- session_count=0
34
+ # 1st pass: matching sessions/files
35
+ declare -a matching_sessions=()
36
+ total_files=0
37
+ scanned=0
21
38
 
22
- # Process substitution avoids subshell
23
- while IFS= read -r -d '' sess_dir; do
39
+ while IFS= read -r -d '' sess_dir <&3; do
24
40
  [ -d "$sess_dir" ] || continue
41
+ ((scanned++))
42
+
43
+ files_matched=0
44
+ shopt -s nullglob
45
+ for file in "$sess_dir"/*.ndjson; do
46
+ base=$(basename "$file" .ndjson)
47
+ has_match=false
48
+ # Filename
49
+ if echo "$base" | grep -qiE "$QUERY"; then
50
+ has_match=true
51
+ # Content (role-filtered if enabled)
52
+ elif ! $BRIEF && [ "$ROLE_FILTER" = true ] && \
53
+ awk -v q="$QUERY" 'tolower($0) ~ tolower(q) && /"role"\s*:\s*"(user|assistant)"/ {exit 0} END{exit !NR}' "$file" 2>/dev/null; then
54
+ has_match=true
55
+ elif ! $BRIEF && [ "$ROLE_FILTER" = false ] && grep -qiE -m1 "$QUERY" "$file" 2>/dev/null; then
56
+ has_match=true
57
+ fi
58
+ [ "$has_match" = true ] && ((files_matched++))
59
+ done
60
+ shopt -u nullglob
61
+ [ $files_matched -gt 0 ] || continue
62
+ matching_sessions+=("$sess_dir")
63
+ ((total_files += files_matched))
64
+ done 3< <(find .cache -mindepth 3 -maxdepth 5 -type d -name sessions -print0 2>/dev/null | sort -rz | head -"$LIMIT")
65
+
66
+ [ $total_files -eq 0 ] && exit 0
25
67
 
26
- session_count=$((session_count + 1))
27
- app_name=$(basename "$(dirname "$(dirname "$sess_dir")")")
28
- prompt_name=$(basename "$(dirname "$sess_dir")")
29
- mod_time=$(stat -c %Y "$sess_dir" 2>/dev/null || echo 0)
30
- date_str=$(date -d "@$mod_time" '+%Y-%m-%d %H:%M' 2>/dev/null || echo "unknown")
68
+ echo "🔍 $QUERY: $total_files files / ${#matching_sessions[@]} sessions (limit=$LIMIT)"
69
+ echo ===
31
70
 
32
- echo "📁 $app_name/$prompt_name ($date_str)"
33
- echo " $sess_dir"
34
- echo " -------------------------------------------------"
71
+ # 2nd pass: condensed output
72
+ for sess_dir in "${matching_sessions[@]}"; do
73
+ app=$(basename "$(dirname "$(dirname "$sess_dir")")")
74
+ prompt=$(basename "$(dirname "$sess_dir")")
75
+ time=$(stat -c %Y "$sess_dir" 2>/dev/null | xargs -I{} date -d "@{}" '+%H:%M' 2>/dev/null || echo ??)
35
76
 
36
- dir_matches=0
77
+ echo "📁 $app/$prompt ($time)"
78
+ echo ---
79
+
80
+ dir_count=0
81
+ all_snips="" # Condense all files' snippets here
37
82
  shopt -s nullglob
38
- for ndjson_file in "$sess_dir"/*.ndjson; do
39
- [ -f "$ndjson_file" ] || continue
40
-
41
- fname_base=$(basename "$ndjson_file" .ndjson)
42
- fname=$(echo "$fname_base" | sed 's/__/ /g' | sed 's/_[0-9]*$//' | fold -w70 | head -1)
43
- fname_short="${fname:0:70}..."
44
-
45
- # Filename match
46
- if echo "$ndjson_file" | grep -qiE "$QUERY" || echo "$fname_base" | grep -qiE "$QUERY"; then
47
- echo " 💾 FILENAME: $fname_short"
48
- dir_matches=$((dir_matches + 1))
49
- total_matches=$((total_matches + 1))
83
+ for file in "$sess_dir"/*.ndjson; do
84
+ [ -f "$file" ] || continue
85
+ base=$(basename "$file" .ndjson)
86
+ name=$(echo "$base" | sed 's/__/ /g; s/_[0-9]*$//' | fold -w30 | sed -E 's/(.{27}).*/\1.../') || name="$base..."
87
+
88
+ printed=false
89
+ # Filename
90
+ if echo "$base" | grep -qiE "$QUERY"; then
91
+ echo " 💾 $name"
92
+ printed=true
50
93
  fi
51
94
 
52
- # Content matches
53
- content_matches=$(grep -iHn -C 5 -E -m 20 "$QUERY" "$ndjson_file" 2>/dev/null || true)
54
- if [ -n "$content_matches" ]; then
55
- echo " 📄 CONTENT in $fname_short:"
56
- echo "$content_matches"
57
- echo ""
58
- dir_matches=$((dir_matches + 1))
59
- total_matches=$((total_matches + 1))
95
+ # Content snippets (role-filtered awk)
96
+ if ! $BRIEF; then
97
+ if [ "$ROLE_FILTER" = true ]; then
98
+ snips=$(awk -v q="$QUERY" 'tolower($0) ~ tolower(q) && /"role"\s*:\s*"(user|assistant)"/ { print substr($0, 1, 100) }' "$file" 2>/dev/null | head -"$MAX_SNIP" | paste -sd'; ')
99
+ else
100
+ snips=$(grep -iE "$QUERY" "$file" 2>/dev/null | cut -c1-100 | head -"$MAX_SNIP" | paste -sd'; ')
101
+ fi
102
+ [ -n "$snips" ] && {
103
+ all_snips+="$snips; "
104
+ printed=true
105
+ }
60
106
  fi
107
+ [ "$printed" = true ] && ((dir_count++))
61
108
  done
62
109
  shopt -u nullglob
63
110
 
64
- if [ $dir_matches -eq 0 ]; then
65
- echo " (no matches)"
66
- fi
67
- echo ""
68
- done < <(find .cache -mindepth 3 -maxdepth 5 -type d -name "sessions" -print0 2>/dev/null | sort -rz | head -30)
111
+ # Condensed session block
112
+ [ -n "$all_snips" ] && {
113
+ echo " 📄 Session ($dir_count files): $(echo "$all_snips" | fold -w90 | sed ':a;N;$!ba;s/\n/ /g' | cut -c1-180)"
114
+ echo
115
+ }
116
+ echo " ($dir_count files)"
117
+ echo
118
+ done
69
119
 
70
- echo "✅ $total_matches matches across $session_count sessions."
71
- if [ $total_matches -eq 0 ]; then
72
- echo "💡 Tip: Broader query? e.g. 'todo', regex '(package|bin)' or check spelling."
73
- fi
120
+ echo "✅ $total_files files / ${#matching_sessions[@]} sessions (scanned $scanned)"