ai-consultants 2.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/.claude/commands/ai-consultants:consult.md +94 -0
- package/.claude/commands/ai-consultants:debate.md +103 -0
- package/.claude/commands/ai-consultants:help.md +30 -0
- package/CLAUDE.md +839 -0
- package/LICENSE +21 -0
- package/README.md +758 -0
- package/SKILL.md +156 -0
- package/bin/ai-consultants +96 -0
- package/docs/COST_RATES.md +172 -0
- package/docs/JSON_SCHEMA.md +305 -0
- package/docs/SETUP.md +879 -0
- package/docs/SMART_ROUTING.md +219 -0
- package/docs/cost_rates.json +143 -0
- package/package.json +47 -0
- package/references/configuration.md +141 -0
- package/references/details.md +60 -0
- package/scripts/build_context.sh +562 -0
- package/scripts/classify_question.sh +148 -0
- package/scripts/config.sh +753 -0
- package/scripts/configure.sh +1093 -0
- package/scripts/consult_all.sh +934 -0
- package/scripts/debate_round.sh +421 -0
- package/scripts/doctor.sh +642 -0
- package/scripts/followup.sh +197 -0
- package/scripts/install.sh +319 -0
- package/scripts/lib/api.sh +640 -0
- package/scripts/lib/api_query.sh +228 -0
- package/scripts/lib/cache.sh +338 -0
- package/scripts/lib/chunking.sh +880 -0
- package/scripts/lib/code_optimizer.sh +671 -0
- package/scripts/lib/common.sh +1088 -0
- package/scripts/lib/costs.sh +674 -0
- package/scripts/lib/personas.sh +372 -0
- package/scripts/lib/progress.sh +251 -0
- package/scripts/lib/reflection.sh +447 -0
- package/scripts/lib/routing.sh +566 -0
- package/scripts/lib/schema.json +165 -0
- package/scripts/lib/session.sh +327 -0
- package/scripts/lib/symbol_map.sh +445 -0
- package/scripts/lib/voting.sh +495 -0
- package/scripts/peer_review.sh +460 -0
- package/scripts/preflight_check.sh +452 -0
- package/scripts/query_aider.sh +83 -0
- package/scripts/query_amp.sh +67 -0
- package/scripts/query_claude.sh +99 -0
- package/scripts/query_codex.sh +92 -0
- package/scripts/query_cursor.sh +72 -0
- package/scripts/query_deepseek.sh +17 -0
- package/scripts/query_gemini.sh +85 -0
- package/scripts/query_glm.sh +17 -0
- package/scripts/query_grok.sh +17 -0
- package/scripts/query_kilo.sh +140 -0
- package/scripts/query_kimi.sh +67 -0
- package/scripts/query_minimax.sh +17 -0
- package/scripts/query_mistral.sh +97 -0
- package/scripts/query_ollama.sh +328 -0
- package/scripts/query_qwen3.sh +93 -0
- package/scripts/setup_wizard.sh +367 -0
- package/scripts/skillport-install.sh +196 -0
- package/scripts/synthesize.sh +332 -0
- package/templates/consultation_report.md +323 -0
- package/templates/synthesis_prompt.md +120 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "AI Consultant Response Schema v2.0",
|
|
4
|
+
"description": "Unified output schema for all AI consultants in ai-consultants skill",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["consultant", "response", "confidence", "metadata"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"consultant": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Name of the consultant (Gemini, Codex, Mistral, Kilo, Cursor, Aider, Amp, Kimi, Claude, Qwen3, GLM, Grok, DeepSeek, MiniMax, Ollama)",
|
|
11
|
+
"enum": ["Gemini", "Codex", "Mistral", "Kilo", "Cursor", "Aider", "Amp", "Kimi", "Claude", "Qwen3", "GLM", "Grok", "DeepSeek", "MiniMax", "Ollama"]
|
|
12
|
+
},
|
|
13
|
+
"model": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Specific model version used"
|
|
16
|
+
},
|
|
17
|
+
"persona": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Assigned persona role",
|
|
20
|
+
"enum": ["The Architect", "The Pragmatist", "The Devil's Advocate", "The Innovator", "The Integrator", "The Pair Programmer", "The Systems Thinker", "The Eastern Sage", "The Synthesizer", "The Analyst", "The Methodologist", "The Provocateur", "The Code Specialist", "The Pragmatic Optimizer", "The Local Expert"]
|
|
21
|
+
},
|
|
22
|
+
"response": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["summary", "detailed", "approach"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"summary": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "TL;DR in 2-3 sentences (max 500 chars)",
|
|
29
|
+
"maxLength": 500
|
|
30
|
+
},
|
|
31
|
+
"detailed": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Full detailed response"
|
|
34
|
+
},
|
|
35
|
+
"approach": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "High-level approach name/category"
|
|
38
|
+
},
|
|
39
|
+
"code_snippets": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"description": "Code examples if applicable",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"language": { "type": "string" },
|
|
46
|
+
"code": { "type": "string" },
|
|
47
|
+
"description": { "type": "string" }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"pros": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"description": "Advantages of the proposed solution",
|
|
54
|
+
"items": { "type": "string" }
|
|
55
|
+
},
|
|
56
|
+
"cons": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"description": "Disadvantages or trade-offs",
|
|
59
|
+
"items": { "type": "string" }
|
|
60
|
+
},
|
|
61
|
+
"alternatives": {
|
|
62
|
+
"type": "array",
|
|
63
|
+
"description": "Alternative approaches considered",
|
|
64
|
+
"items": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {
|
|
67
|
+
"name": { "type": "string" },
|
|
68
|
+
"reason_not_chosen": { "type": "string" }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"caveats": {
|
|
73
|
+
"type": "array",
|
|
74
|
+
"description": "Important assumptions or limitations",
|
|
75
|
+
"items": { "type": "string" }
|
|
76
|
+
},
|
|
77
|
+
"references": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"description": "Links or references if applicable",
|
|
80
|
+
"items": { "type": "string" }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"confidence": {
|
|
85
|
+
"type": "object",
|
|
86
|
+
"required": ["score", "reasoning"],
|
|
87
|
+
"properties": {
|
|
88
|
+
"score": {
|
|
89
|
+
"type": "integer",
|
|
90
|
+
"description": "Confidence score from 1-10",
|
|
91
|
+
"minimum": 1,
|
|
92
|
+
"maximum": 10
|
|
93
|
+
},
|
|
94
|
+
"reasoning": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"description": "Why this confidence level was assigned"
|
|
97
|
+
},
|
|
98
|
+
"uncertainty_factors": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"description": "Factors that reduce confidence",
|
|
101
|
+
"items": { "type": "string" }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"debate": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"description": "Data for multi-agent debate rounds",
|
|
108
|
+
"properties": {
|
|
109
|
+
"round": {
|
|
110
|
+
"type": "integer",
|
|
111
|
+
"description": "Current debate round (1, 2, or 3)"
|
|
112
|
+
},
|
|
113
|
+
"position_changed": {
|
|
114
|
+
"type": "boolean",
|
|
115
|
+
"description": "Whether position changed from previous round"
|
|
116
|
+
},
|
|
117
|
+
"critiques": {
|
|
118
|
+
"type": "array",
|
|
119
|
+
"description": "Critiques of other consultants' responses",
|
|
120
|
+
"items": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"properties": {
|
|
123
|
+
"target": { "type": "string" },
|
|
124
|
+
"critique": { "type": "string" },
|
|
125
|
+
"severity": { "enum": ["minor", "moderate", "major"] }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"incorporated_from": {
|
|
130
|
+
"type": "array",
|
|
131
|
+
"description": "Ideas incorporated from other consultants",
|
|
132
|
+
"items": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"properties": {
|
|
135
|
+
"source": { "type": "string" },
|
|
136
|
+
"idea": { "type": "string" }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"metadata": {
|
|
143
|
+
"type": "object",
|
|
144
|
+
"properties": {
|
|
145
|
+
"tokens_used": {
|
|
146
|
+
"type": "integer",
|
|
147
|
+
"description": "Approximate tokens consumed"
|
|
148
|
+
},
|
|
149
|
+
"latency_ms": {
|
|
150
|
+
"type": "integer",
|
|
151
|
+
"description": "Response time in milliseconds"
|
|
152
|
+
},
|
|
153
|
+
"model_version": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "Exact model version string"
|
|
156
|
+
},
|
|
157
|
+
"timestamp": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"format": "date-time",
|
|
160
|
+
"description": "ISO 8601 timestamp of response"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# session.sh - Session state management for AI Consultants v2.0
|
|
3
|
+
#
|
|
4
|
+
# Manages session state to support follow-up queries
|
|
5
|
+
# and maintain context between successive consultations.
|
|
6
|
+
|
|
7
|
+
# =============================================================================
|
|
8
|
+
# CONFIGURATION
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
# Directory for session files
|
|
12
|
+
SESSION_DIR="${SESSION_DIR:-/tmp/ai_consultants_sessions}"
|
|
13
|
+
SESSION_FILE="${SESSION_DIR}/current_session.json"
|
|
14
|
+
SESSION_HISTORY_FILE="${SESSION_DIR}/history.json"
|
|
15
|
+
|
|
16
|
+
# Create directory with secure permissions (owner-only access)
|
|
17
|
+
if [[ ! -d "$SESSION_DIR" ]]; then
|
|
18
|
+
mkdir -p "$SESSION_DIR" 2>/dev/null || true
|
|
19
|
+
fi
|
|
20
|
+
chmod 700 "$SESSION_DIR" 2>/dev/null || true
|
|
21
|
+
|
|
22
|
+
# =============================================================================
|
|
23
|
+
# SESSION MANAGEMENT
|
|
24
|
+
# =============================================================================
|
|
25
|
+
|
|
26
|
+
# Generate new session ID
|
|
27
|
+
# Usage: generate_session_id
|
|
28
|
+
generate_session_id() {
|
|
29
|
+
echo "session_$(date +%Y%m%d_%H%M%S)_$$"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Save current session
|
|
33
|
+
# Usage: save_session <session_id> <query> <responses_dir> [category]
|
|
34
|
+
save_session() {
|
|
35
|
+
local session_id="$1"
|
|
36
|
+
local query="$2"
|
|
37
|
+
local responses_dir="$3"
|
|
38
|
+
local category="${4:-GENERAL}"
|
|
39
|
+
|
|
40
|
+
local timestamp=$(date -Iseconds)
|
|
41
|
+
|
|
42
|
+
# Create file with secure permissions before writing
|
|
43
|
+
touch "$SESSION_FILE"
|
|
44
|
+
chmod 600 "$SESSION_FILE"
|
|
45
|
+
|
|
46
|
+
jq -n \
|
|
47
|
+
--arg id "$session_id" \
|
|
48
|
+
--arg query "$query" \
|
|
49
|
+
--arg dir "$responses_dir" \
|
|
50
|
+
--arg category "$category" \
|
|
51
|
+
--arg timestamp "$timestamp" \
|
|
52
|
+
'{
|
|
53
|
+
id: $id,
|
|
54
|
+
query: $query,
|
|
55
|
+
responses_dir: $dir,
|
|
56
|
+
category: $category,
|
|
57
|
+
timestamp: $timestamp,
|
|
58
|
+
follow_ups: []
|
|
59
|
+
}' > "$SESSION_FILE"
|
|
60
|
+
|
|
61
|
+
# Add to history
|
|
62
|
+
add_to_history "$session_id" "$query" "$responses_dir" "$category"
|
|
63
|
+
|
|
64
|
+
echo "$session_id"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Get current session
|
|
68
|
+
# Usage: get_current_session
|
|
69
|
+
get_current_session() {
|
|
70
|
+
if [[ -f "$SESSION_FILE" ]]; then
|
|
71
|
+
cat "$SESSION_FILE"
|
|
72
|
+
else
|
|
73
|
+
echo "{}"
|
|
74
|
+
fi
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Check if an active session exists
|
|
78
|
+
# Usage: has_active_session
|
|
79
|
+
has_active_session() {
|
|
80
|
+
if [[ -f "$SESSION_FILE" && -s "$SESSION_FILE" ]]; then
|
|
81
|
+
local id=$(jq -r '.id // empty' "$SESSION_FILE" 2>/dev/null)
|
|
82
|
+
[[ -n "$id" ]] && return 0
|
|
83
|
+
fi
|
|
84
|
+
return 1
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Get current session ID
|
|
88
|
+
# Usage: get_current_session_id
|
|
89
|
+
get_current_session_id() {
|
|
90
|
+
if has_active_session; then
|
|
91
|
+
jq -r '.id' "$SESSION_FILE"
|
|
92
|
+
else
|
|
93
|
+
echo ""
|
|
94
|
+
fi
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Get query from current session
|
|
98
|
+
# Usage: get_current_query
|
|
99
|
+
get_current_query() {
|
|
100
|
+
if has_active_session; then
|
|
101
|
+
jq -r '.query' "$SESSION_FILE"
|
|
102
|
+
else
|
|
103
|
+
echo ""
|
|
104
|
+
fi
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Get responses directory from current session
|
|
108
|
+
# Usage: get_current_responses_dir
|
|
109
|
+
get_current_responses_dir() {
|
|
110
|
+
if has_active_session; then
|
|
111
|
+
jq -r '.responses_dir' "$SESSION_FILE"
|
|
112
|
+
else
|
|
113
|
+
echo ""
|
|
114
|
+
fi
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# =============================================================================
|
|
118
|
+
# FOLLOW-UP MANAGEMENT
|
|
119
|
+
# =============================================================================
|
|
120
|
+
|
|
121
|
+
# Add follow-up to session
|
|
122
|
+
# Usage: add_follow_up <follow_up_query> <follow_up_responses_dir>
|
|
123
|
+
add_follow_up() {
|
|
124
|
+
local follow_up_query="$1"
|
|
125
|
+
local follow_up_dir="$2"
|
|
126
|
+
|
|
127
|
+
if ! has_active_session; then
|
|
128
|
+
return 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
local timestamp=$(date -Iseconds)
|
|
132
|
+
|
|
133
|
+
jq --arg query "$follow_up_query" \
|
|
134
|
+
--arg dir "$follow_up_dir" \
|
|
135
|
+
--arg ts "$timestamp" \
|
|
136
|
+
'.follow_ups += [{query: $query, responses_dir: $dir, timestamp: $ts}]' \
|
|
137
|
+
"$SESSION_FILE" > "${SESSION_FILE}.tmp" && \
|
|
138
|
+
mv "${SESSION_FILE}.tmp" "$SESSION_FILE"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Get number of follow-ups in session
|
|
142
|
+
# Usage: get_follow_up_count
|
|
143
|
+
get_follow_up_count() {
|
|
144
|
+
if has_active_session; then
|
|
145
|
+
jq -r '.follow_ups | length // 0' "$SESSION_FILE"
|
|
146
|
+
else
|
|
147
|
+
echo 0
|
|
148
|
+
fi
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# =============================================================================
|
|
152
|
+
# SESSION HISTORY
|
|
153
|
+
# =============================================================================
|
|
154
|
+
|
|
155
|
+
# Initialize history file if it doesn't exist
|
|
156
|
+
init_history() {
|
|
157
|
+
if [[ ! -f "$SESSION_HISTORY_FILE" ]]; then
|
|
158
|
+
# Create file with secure permissions before writing
|
|
159
|
+
touch "$SESSION_HISTORY_FILE"
|
|
160
|
+
chmod 600 "$SESSION_HISTORY_FILE"
|
|
161
|
+
echo '{"sessions": []}' > "$SESSION_HISTORY_FILE"
|
|
162
|
+
fi
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Add session to history
|
|
166
|
+
# Usage: add_to_history <session_id> <query> <responses_dir> <category>
|
|
167
|
+
add_to_history() {
|
|
168
|
+
local session_id="$1"
|
|
169
|
+
local query="$2"
|
|
170
|
+
local responses_dir="$3"
|
|
171
|
+
local category="$4"
|
|
172
|
+
|
|
173
|
+
init_history
|
|
174
|
+
|
|
175
|
+
local timestamp=$(date -Iseconds)
|
|
176
|
+
local query_preview="${query:0:100}"
|
|
177
|
+
|
|
178
|
+
jq --arg id "$session_id" \
|
|
179
|
+
--arg query "$query_preview" \
|
|
180
|
+
--arg dir "$responses_dir" \
|
|
181
|
+
--arg cat "$category" \
|
|
182
|
+
--arg ts "$timestamp" \
|
|
183
|
+
'.sessions += [{id: $id, query_preview: $query, responses_dir: $dir, category: $cat, timestamp: $ts}]' \
|
|
184
|
+
"$SESSION_HISTORY_FILE" > "${SESSION_HISTORY_FILE}.tmp" && \
|
|
185
|
+
mv "${SESSION_HISTORY_FILE}.tmp" "$SESSION_HISTORY_FILE"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Get last N sessions from history
|
|
189
|
+
# Usage: get_recent_sessions [count]
|
|
190
|
+
get_recent_sessions() {
|
|
191
|
+
local count="${1:-5}"
|
|
192
|
+
|
|
193
|
+
init_history
|
|
194
|
+
|
|
195
|
+
jq --argjson n "$count" '.sessions | .[-$n:]' "$SESSION_HISTORY_FILE"
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# Search session by ID
|
|
199
|
+
# Usage: get_session_by_id <session_id>
|
|
200
|
+
get_session_by_id() {
|
|
201
|
+
local session_id="$1"
|
|
202
|
+
|
|
203
|
+
init_history
|
|
204
|
+
|
|
205
|
+
jq --arg id "$session_id" '.sessions[] | select(.id == $id)' "$SESSION_HISTORY_FILE"
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# =============================================================================
|
|
209
|
+
# CONTEXT BUILDING
|
|
210
|
+
# =============================================================================
|
|
211
|
+
|
|
212
|
+
# Build context from session for follow-up
|
|
213
|
+
# Usage: build_follow_up_context <follow_up_instruction>
|
|
214
|
+
build_follow_up_context() {
|
|
215
|
+
local instruction="$1"
|
|
216
|
+
|
|
217
|
+
if ! has_active_session; then
|
|
218
|
+
echo "$instruction"
|
|
219
|
+
return
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
local session=$(get_current_session)
|
|
223
|
+
local original_query=$(echo "$session" | jq -r '.query')
|
|
224
|
+
local responses_dir=$(echo "$session" | jq -r '.responses_dir')
|
|
225
|
+
|
|
226
|
+
local context="# Previous Session Context
|
|
227
|
+
|
|
228
|
+
## Original Question
|
|
229
|
+
$original_query
|
|
230
|
+
|
|
231
|
+
## Consultant Responses
|
|
232
|
+
"
|
|
233
|
+
|
|
234
|
+
# Add response summaries
|
|
235
|
+
if [[ -d "$responses_dir" ]]; then
|
|
236
|
+
for f in "$responses_dir"/*.json; do
|
|
237
|
+
if [[ -f "$f" ]]; then
|
|
238
|
+
local consultant=$(jq -r '.consultant // "Unknown"' "$f" 2>/dev/null)
|
|
239
|
+
local summary=$(jq -r '.response.summary // "No summary"' "$f" 2>/dev/null)
|
|
240
|
+
local approach=$(jq -r '.response.approach // "unknown"' "$f" 2>/dev/null)
|
|
241
|
+
|
|
242
|
+
context+="
|
|
243
|
+
### $consultant
|
|
244
|
+
Approach: $approach
|
|
245
|
+
Summary: $summary
|
|
246
|
+
"
|
|
247
|
+
fi
|
|
248
|
+
done
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
# Add any previous follow-ups
|
|
252
|
+
local follow_up_count=$(get_follow_up_count)
|
|
253
|
+
if [[ $follow_up_count -gt 0 ]]; then
|
|
254
|
+
context+="
|
|
255
|
+
## Previous Follow-ups
|
|
256
|
+
"
|
|
257
|
+
echo "$session" | jq -r '.follow_ups[] | "- \(.query)"' >> /dev/null 2>&1 && \
|
|
258
|
+
context+="$(echo "$session" | jq -r '.follow_ups[] | "- \(.query)"')"
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
context+="
|
|
262
|
+
|
|
263
|
+
# New Request
|
|
264
|
+
$instruction"
|
|
265
|
+
|
|
266
|
+
echo "$context"
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# =============================================================================
|
|
270
|
+
# CLEANUP
|
|
271
|
+
# =============================================================================
|
|
272
|
+
|
|
273
|
+
# Clear current session
|
|
274
|
+
# Usage: clear_current_session
|
|
275
|
+
clear_current_session() {
|
|
276
|
+
rm -f "$SESSION_FILE"
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
# Clean up sessions older than N days
|
|
280
|
+
# Usage: cleanup_old_sessions [days]
|
|
281
|
+
cleanup_old_sessions() {
|
|
282
|
+
local days="${1:-7}"
|
|
283
|
+
|
|
284
|
+
# Clean up old output files
|
|
285
|
+
# Note: $days must be quoted to prevent injection via specially crafted days value
|
|
286
|
+
find /tmp/ai_consultations -type d -mtime +"$days" -exec rm -rf {} \; 2>/dev/null || true
|
|
287
|
+
|
|
288
|
+
# Remove old sessions from history
|
|
289
|
+
init_history
|
|
290
|
+
|
|
291
|
+
local cutoff=$(date -d "-$days days" -Iseconds 2>/dev/null || date -v-${days}d -Iseconds 2>/dev/null || echo "")
|
|
292
|
+
|
|
293
|
+
if [[ -n "$cutoff" ]]; then
|
|
294
|
+
jq --arg cutoff "$cutoff" '.sessions |= [.[] | select(.timestamp > $cutoff)]' \
|
|
295
|
+
"$SESSION_HISTORY_FILE" > "${SESSION_HISTORY_FILE}.tmp" && \
|
|
296
|
+
mv "${SESSION_HISTORY_FILE}.tmp" "$SESSION_HISTORY_FILE"
|
|
297
|
+
fi
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
# =============================================================================
|
|
301
|
+
# DISPLAY
|
|
302
|
+
# =============================================================================
|
|
303
|
+
|
|
304
|
+
# Show current session info
|
|
305
|
+
# Usage: show_session_info
|
|
306
|
+
show_session_info() {
|
|
307
|
+
if ! has_active_session; then
|
|
308
|
+
echo "No active session"
|
|
309
|
+
return
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
local session=$(get_current_session)
|
|
313
|
+
local id=$(echo "$session" | jq -r '.id')
|
|
314
|
+
local query=$(echo "$session" | jq -r '.query')
|
|
315
|
+
local timestamp=$(echo "$session" | jq -r '.timestamp')
|
|
316
|
+
local follow_ups=$(echo "$session" | jq -r '.follow_ups | length')
|
|
317
|
+
|
|
318
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
319
|
+
echo "║ Current Session ║"
|
|
320
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
321
|
+
echo ""
|
|
322
|
+
echo " ID: $id"
|
|
323
|
+
echo " Query: ${query:0:50}..."
|
|
324
|
+
echo " Started: $timestamp"
|
|
325
|
+
echo " Follow-ups: $follow_ups"
|
|
326
|
+
echo ""
|
|
327
|
+
}
|