@pithosai/pithosai 1.0.7 → 1.0.32
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/CHANGELOG.md +784 -0
- package/LICENSE +1 -1
- package/README.md +544 -130
- package/dist/529.mjs +2 -0
- package/dist/813.mjs +3 -0
- package/dist/cosai +3 -0
- package/dist/heartbeat.mjs +378 -125
- package/dist/init.mjs +1 -1
- package/dist/mktai +3 -0
- package/dist/nl-fallback-classify.mjs +7 -0
- package/dist/pithosai-git-ai-adapter.mjs +2 -0
- package/dist/pithosai-nl-fallback.sh +456 -0
- package/dist/pithosai.mjs +378 -125
- package/dist/pmsai +3 -0
- package/dist/qasai +3 -0
- package/dist/rdsai +3 -0
- package/dist/render-markdown.mjs +7 -7
- package/dist/wrsai +3 -0
- package/docs/KROUTER.md +140 -0
- package/docs/hooks-usage.md +335 -0
- package/package.json +40 -14
- package/src/agent-orch/READEM.md +62 -0
- package/src/models/README.md +469 -0
- package/src/models/krouter.README.md +63 -0
- package/dist/935.mjs +0 -3
- package/dist/cosai.mjs +0 -596
- package/dist/mktai.mjs +0 -596
- package/dist/pmsai.mjs +0 -596
- package/dist/qasai.mjs +0 -596
- package/dist/rdsai.mjs +0 -596
- package/dist/wrsai.mjs +0 -596
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# pithosai-nl-fallback.sh
|
|
2
|
+
# Source from zsh or bash 4+ (do not execute):
|
|
3
|
+
# source /path/to/scripts/pithosai-nl-fallback.sh
|
|
4
|
+
#
|
|
5
|
+
# Unknown commands that look like natural language are classified by Node
|
|
6
|
+
# (`nl-fallback-classify`: lookpath + tinyld) and forwarded to:
|
|
7
|
+
# pithosai --no-interactive --model krouter-rd "$input"
|
|
8
|
+
#
|
|
9
|
+
# The command_not_found path never rewrites the typed line. Interactive zsh
|
|
10
|
+
# (ZLE) and bash 4+ (readline `bind -x`, on Ctrl-J) intercept before parse so
|
|
11
|
+
# `for these files: …` can reach pithosai instead of a keyword parse error; the
|
|
12
|
+
# bash handler rewrites READLINE_LINE in place and lets accept-line run it.
|
|
13
|
+
# Real PATH commands skip that intercept.
|
|
14
|
+
#
|
|
15
|
+
# Env:
|
|
16
|
+
# PITHOSAI_NL_FALLBACK=0 disable all NL interception
|
|
17
|
+
# PITHOSAI_NL_ZLE=0 disable zsh/bash Enter intercept only
|
|
18
|
+
# PITHOSAI_NL_MODEL default krouter-rd
|
|
19
|
+
# PITHOSAI_NL_CLASSIFY_LLM=0 skip the LLM step when shell-score < 50
|
|
20
|
+
# PITHOSAI_NL_DEBUG_LOG=1 print classify/LLM debug on stderr
|
|
21
|
+
# PITHOSAI_BIN default pithosai
|
|
22
|
+
# PITHOSAI_LANG override locale for messages and --lang
|
|
23
|
+
# PITHOSAI_NODE node binary (default: node)
|
|
24
|
+
|
|
25
|
+
# Executed instead of sourced: print help and exit. `return` works only when sourced.
|
|
26
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
27
|
+
case "${ZSH_EVAL_CONTEXT:-}" in
|
|
28
|
+
*:file*) ;;
|
|
29
|
+
*)
|
|
30
|
+
echo "Source this file from bash or zsh (do not execute it): source scripts/pithosai-nl-fallback.sh" >&2
|
|
31
|
+
return 1 2>/dev/null || exit 1
|
|
32
|
+
;;
|
|
33
|
+
esac
|
|
34
|
+
# zsh NOMATCH aborts on unmatched globs (`you?`, `*.xyz`) before command_not_found_handler.
|
|
35
|
+
setopt NO_NOMATCH
|
|
36
|
+
setopt NO_BAD_PATTERN
|
|
37
|
+
elif [ -n "${BASH_VERSION:-}" ]; then
|
|
38
|
+
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
39
|
+
echo "Source this file from bash or zsh (do not execute it): source scripts/pithosai-nl-fallback.sh" >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
else
|
|
43
|
+
echo "Source this file from bash or zsh (do not execute it): source scripts/pithosai-nl-fallback.sh" >&2
|
|
44
|
+
return 1 2>/dev/null || exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ -n "${_PITHOSAI_NL_FALLBACK_LOADED:-}" ]; then
|
|
48
|
+
:
|
|
49
|
+
else
|
|
50
|
+
# Copy a pre-existing command-not-found handler so skips still use it.
|
|
51
|
+
_pithosai_copy_shell_function() {
|
|
52
|
+
local src="$1"
|
|
53
|
+
local dst="$2"
|
|
54
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
55
|
+
if typeset -f "$src" >/dev/null 2>&1; then
|
|
56
|
+
functions -c "$src" "$dst"
|
|
57
|
+
fi
|
|
58
|
+
elif typeset -f "$src" >/dev/null 2>&1; then
|
|
59
|
+
eval "$(typeset -f "$src" | sed "1s/^${src}/${dst}/")"
|
|
60
|
+
fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
64
|
+
if typeset -f command_not_found_handler >/dev/null 2>&1; then
|
|
65
|
+
_pithosai_copy_shell_function command_not_found_handler _pithosai_orig_cnf
|
|
66
|
+
fi
|
|
67
|
+
elif typeset -f command_not_found_handle >/dev/null 2>&1; then
|
|
68
|
+
_pithosai_copy_shell_function command_not_found_handle _pithosai_orig_cnf
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
_PITHOSAI_NL_FALLBACK_LOADED=1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Directory of this sourced script (zsh %x / bash BASH_SOURCE).
|
|
75
|
+
pithosai_nl_fallback_script_dir() {
|
|
76
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
77
|
+
local file="${(%):-%x}"
|
|
78
|
+
printf '%s' "${file:A:h}"
|
|
79
|
+
return 0
|
|
80
|
+
fi
|
|
81
|
+
(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Path to the Node classifier (dist bundle, or src when sourcing from the repo).
|
|
85
|
+
pithosai_nl_fallback_classify_js() {
|
|
86
|
+
local dir
|
|
87
|
+
dir="$(pithosai_nl_fallback_script_dir)"
|
|
88
|
+
if [ -f "$dir/nl-fallback-classify.mjs" ]; then
|
|
89
|
+
printf '%s' "$dir/nl-fallback-classify.mjs"
|
|
90
|
+
return 0
|
|
91
|
+
fi
|
|
92
|
+
if [ -f "$dir/../src/cli/shared/nl-fallback/nl-fallback-classify.js" ]; then
|
|
93
|
+
printf '%s' "$dir/../src/cli/shared/nl-fallback/nl-fallback-classify.js"
|
|
94
|
+
return 0
|
|
95
|
+
fi
|
|
96
|
+
return 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Map locale env to a pithosai --lang code (en, zh, zh-Hant, …).
|
|
100
|
+
# Used when Node is unavailable. LANG=en_US.UTF-8 → en; zh_CN → zh; zh_TW → zh-Hant.
|
|
101
|
+
pithosai_nl_fallback_lang() {
|
|
102
|
+
local raw="${PITHOSAI_LANG:-${LC_ALL:-${LC_MESSAGES:-${LANG:-}}}}"
|
|
103
|
+
raw="${raw%%.*}"
|
|
104
|
+
case "$raw" in
|
|
105
|
+
zh_TW|zh-TW|zh_HK|zh-HK|zh-Hant|zh_Hant|zh-hant|zh_hant)
|
|
106
|
+
echo "zh-Hant"
|
|
107
|
+
return 0
|
|
108
|
+
;;
|
|
109
|
+
esac
|
|
110
|
+
raw="${raw%%_*}"
|
|
111
|
+
raw="${raw%%-*}"
|
|
112
|
+
case "$raw" in
|
|
113
|
+
zh) echo "zh" ;;
|
|
114
|
+
ja) echo "ja" ;;
|
|
115
|
+
ko) echo "ko" ;;
|
|
116
|
+
ar) echo "ar" ;;
|
|
117
|
+
de) echo "de" ;;
|
|
118
|
+
es) echo "es" ;;
|
|
119
|
+
fr) echo "fr" ;;
|
|
120
|
+
it) echo "it" ;;
|
|
121
|
+
nl) echo "nl" ;;
|
|
122
|
+
pt) echo "pt" ;;
|
|
123
|
+
en) echo "en" ;;
|
|
124
|
+
*) echo "en" ;;
|
|
125
|
+
esac
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# Print a localized hook message (pithosaiMissing, classifyUnavailable, or sourceOnly).
|
|
129
|
+
pithosai_nl_fallback_msg() {
|
|
130
|
+
local key="$1"
|
|
131
|
+
local input="${2:-}"
|
|
132
|
+
local lang
|
|
133
|
+
lang="$(pithosai_nl_fallback_lang)"
|
|
134
|
+
local msg=""
|
|
135
|
+
case "$key" in
|
|
136
|
+
pithosaiMissing)
|
|
137
|
+
case "$lang" in
|
|
138
|
+
zh) msg="未找到 pithosai。请安装 pithosai 或设置 PITHOSAI_BIN。" ;;
|
|
139
|
+
zh-Hant) msg="找不到 pithosai。請安裝 pithosai 或設定 PITHOSAI_BIN。" ;;
|
|
140
|
+
ja) msg="pithosai が見つかりません。インストールするか PITHOSAI_BIN を設定してください。" ;;
|
|
141
|
+
ko) msg="pithosai를 찾을 수 없습니다. pithosai를 설치하거나 PITHOSAI_BIN을 설정하세요." ;;
|
|
142
|
+
de) msg="pithosai nicht gefunden. Installieren Sie pithosai oder setzen Sie PITHOSAI_BIN." ;;
|
|
143
|
+
fr) msg="pithosai introuvable. Installez pithosai ou définissez PITHOSAI_BIN." ;;
|
|
144
|
+
es) msg="No se encontró pithosai. Instale pithosai o defina PITHOSAI_BIN." ;;
|
|
145
|
+
it) msg="pithosai non trovato. Installa pithosai o imposta PITHOSAI_BIN." ;;
|
|
146
|
+
nl) msg="pithosai niet gevonden. Installeer pithosai of zet PITHOSAI_BIN." ;;
|
|
147
|
+
pt) msg="pithosai não encontrado. Instale pithosai ou defina PITHOSAI_BIN." ;;
|
|
148
|
+
ar) msg="لم يتم العثور على pithosai. ثبّت pithosai أو عيّن PITHOSAI_BIN." ;;
|
|
149
|
+
*) msg="pithosai not found. Install pithosai or set PITHOSAI_BIN." ;;
|
|
150
|
+
esac
|
|
151
|
+
;;
|
|
152
|
+
classifyUnavailable)
|
|
153
|
+
case "$lang" in
|
|
154
|
+
zh) msg="pithosai nl-fallback:无法运行分类器(需要 node 和 nl-fallback-classify)。" ;;
|
|
155
|
+
zh-Hant) msg="pithosai nl-fallback:無法執行分類器(需要 node 和 nl-fallback-classify)。" ;;
|
|
156
|
+
ja) msg="pithosai nl-fallback: 分類器を実行できません(node と nl-fallback-classify が必要です)。" ;;
|
|
157
|
+
ko) msg="pithosai nl-fallback: 분류기를 실행할 수 없습니다(node 및 nl-fallback-classify 필요)." ;;
|
|
158
|
+
de) msg="pithosai nl-fallback: Klassifizierer nicht verfügbar (node und nl-fallback-classify erforderlich)." ;;
|
|
159
|
+
fr) msg="pithosai nl-fallback : classifieur indisponible (node et nl-fallback-classify requis)." ;;
|
|
160
|
+
es) msg="pithosai nl-fallback: clasificador no disponible (se necesita node y nl-fallback-classify)." ;;
|
|
161
|
+
it) msg="pithosai nl-fallback: classificatore non disponibile (servono node e nl-fallback-classify)." ;;
|
|
162
|
+
nl) msg="pithosai nl-fallback: classifier niet beschikbaar (node en nl-fallback-classify vereist)." ;;
|
|
163
|
+
pt) msg="pithosai nl-fallback: classificador indisponível (é preciso node e nl-fallback-classify)." ;;
|
|
164
|
+
ar) msg="pithosai nl-fallback: المصنّف غير متاح (يلزم node و nl-fallback-classify)." ;;
|
|
165
|
+
*) msg="pithosai nl-fallback: classifier unavailable (need node + nl-fallback-classify)." ;;
|
|
166
|
+
esac
|
|
167
|
+
;;
|
|
168
|
+
sourceOnly)
|
|
169
|
+
case "$lang" in
|
|
170
|
+
zh) msg="请在 bash 或 zsh 中 source 此文件(不要直接执行):source scripts/pithosai-nl-fallback.sh" ;;
|
|
171
|
+
zh-Hant) msg="請在 bash 或 zsh 中 source 此檔案(不要直接執行):source scripts/pithosai-nl-fallback.sh" ;;
|
|
172
|
+
ja) msg="bash または zsh から source してください(直接実行しないでください): source scripts/pithosai-nl-fallback.sh" ;;
|
|
173
|
+
ko) msg="bash 또는 zsh에서 이 파일을 source 하세요(직접 실행하지 마세요): source scripts/pithosai-nl-fallback.sh" ;;
|
|
174
|
+
de) msg="Diese Datei in bash oder zsh sourcen (nicht ausführen): source scripts/pithosai-nl-fallback.sh" ;;
|
|
175
|
+
fr) msg="Sourcez ce fichier depuis bash ou zsh (ne l'exécutez pas) : source scripts/pithosai-nl-fallback.sh" ;;
|
|
176
|
+
es) msg="Haga source de este archivo en bash o zsh (no lo ejecute): source scripts/pithosai-nl-fallback.sh" ;;
|
|
177
|
+
it) msg="Esegui source di questo file da bash o zsh (non eseguirlo): source scripts/pithosai-nl-fallback.sh" ;;
|
|
178
|
+
nl) msg="Source dit bestand in bash of zsh (niet uitvoeren): source scripts/pithosai-nl-fallback.sh" ;;
|
|
179
|
+
pt) msg="Faça source deste ficheiro no bash ou zsh (não o execute): source scripts/pithosai-nl-fallback.sh" ;;
|
|
180
|
+
ar) msg="قم بعمل source لهذا الملف من bash أو zsh (لا تشغّله): source scripts/pithosai-nl-fallback.sh" ;;
|
|
181
|
+
*) msg="Source this file from bash or zsh (do not execute it): source scripts/pithosai-nl-fallback.sh" ;;
|
|
182
|
+
esac
|
|
183
|
+
;;
|
|
184
|
+
esac
|
|
185
|
+
printf '%s\n' "${msg//\{\{input\}\}/$input}"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Return 0 when NL fallback env is enabled.
|
|
189
|
+
pithosai_nl_fallback_is_enabled() {
|
|
190
|
+
local disabled
|
|
191
|
+
disabled="$(printf '%s' "${PITHOSAI_NL_FALLBACK:-}" | tr '[:upper:]' '[:lower:]')"
|
|
192
|
+
case "$disabled" in
|
|
193
|
+
0|false|no|off) return 1 ;;
|
|
194
|
+
esac
|
|
195
|
+
return 0
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# Print a debug line on stderr when PITHOSAI_NL_DEBUG_LOG=1.
|
|
199
|
+
pithosai_nl_debug() {
|
|
200
|
+
local flag
|
|
201
|
+
flag="$(printf '%s' "${PITHOSAI_NL_DEBUG_LOG:-}" | tr '[:upper:]' '[:lower:]')"
|
|
202
|
+
case "$flag" in
|
|
203
|
+
1|true|yes|on) printf '[pithosai-nl] %s\n' "$*" >&2 ;;
|
|
204
|
+
esac
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Run pithosai --no-interactive with the reconstructed natural-language input.
|
|
208
|
+
# $1 = input line, $2 = optional --lang code from the Node classifier.
|
|
209
|
+
pithosai_nl_fallback_run() {
|
|
210
|
+
local input="$1"
|
|
211
|
+
local lang="${2:-}"
|
|
212
|
+
local bin="${PITHOSAI_BIN:-pithosai}"
|
|
213
|
+
local model="${PITHOSAI_NL_MODEL:-krouter-rd}"
|
|
214
|
+
if [ -z "$lang" ]; then
|
|
215
|
+
lang="$(pithosai_nl_fallback_lang)"
|
|
216
|
+
fi
|
|
217
|
+
if [ -x "$bin" ] || command -v "$bin" >/dev/null 2>&1; then
|
|
218
|
+
"$bin" --no-interactive --model "$model" --lang "$lang" "$input"
|
|
219
|
+
return $?
|
|
220
|
+
fi
|
|
221
|
+
pithosai_nl_fallback_msg pithosaiMissing >&2
|
|
222
|
+
echo "command not found: ${bin}" >&2
|
|
223
|
+
return 127
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Ask Node whether this line is NL. Prints lang on stdout when it should run.
|
|
227
|
+
# Exit 0 = run, 1 = skip, 2 = classifier error.
|
|
228
|
+
pithosai_nl_fallback_classify() {
|
|
229
|
+
local input="$1"
|
|
230
|
+
local js nodebin
|
|
231
|
+
js="$(pithosai_nl_fallback_classify_js)" || return 2
|
|
232
|
+
nodebin="${PITHOSAI_NODE:-node}"
|
|
233
|
+
if ! command -v "$nodebin" >/dev/null 2>&1; then
|
|
234
|
+
return 2
|
|
235
|
+
fi
|
|
236
|
+
"$nodebin" "$js" "$input"
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Shared bash/zsh command-not-found body.
|
|
240
|
+
pithosai_handle_command_not_found() {
|
|
241
|
+
local cmd="$1"
|
|
242
|
+
local input="$*"
|
|
243
|
+
local lang code
|
|
244
|
+
pithosai_nl_debug "command_not_found cmd=${cmd} input=${input}"
|
|
245
|
+
if ! pithosai_nl_fallback_is_enabled; then
|
|
246
|
+
pithosai_nl_debug "fallback disabled"
|
|
247
|
+
pithosai_nl_fallback_not_found "$@"
|
|
248
|
+
return $?
|
|
249
|
+
fi
|
|
250
|
+
lang="$(pithosai_nl_fallback_classify "$input")"
|
|
251
|
+
code=$?
|
|
252
|
+
pithosai_nl_debug "classify exit=${code} lang=${lang}"
|
|
253
|
+
if [ "$code" -eq 0 ]; then
|
|
254
|
+
pithosai_nl_debug "run pithosai"
|
|
255
|
+
pithosai_nl_fallback_run "$input" "$lang"
|
|
256
|
+
return $?
|
|
257
|
+
fi
|
|
258
|
+
if [ "$code" -eq 2 ]; then
|
|
259
|
+
pithosai_nl_fallback_msg classifyUnavailable >&2
|
|
260
|
+
fi
|
|
261
|
+
pithosai_nl_debug "skip as command-not-found"
|
|
262
|
+
pithosai_nl_fallback_not_found "$@"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Delegate to a previous handler, or print the usual command-not-found line.
|
|
266
|
+
pithosai_nl_fallback_not_found() {
|
|
267
|
+
local cmd="$1"
|
|
268
|
+
if typeset -f _pithosai_orig_cnf >/dev/null 2>&1; then
|
|
269
|
+
_pithosai_orig_cnf "$@"
|
|
270
|
+
return $?
|
|
271
|
+
fi
|
|
272
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
273
|
+
echo "zsh: command not found: $cmd" >&2
|
|
274
|
+
else
|
|
275
|
+
echo "bash: $cmd: command not found" >&2
|
|
276
|
+
fi
|
|
277
|
+
return 127
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
command_not_found_handler() {
|
|
281
|
+
pithosai_handle_command_not_found "$@"
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
command_not_found_handle() {
|
|
285
|
+
pithosai_handle_command_not_found "$@"
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# Return 0 when the line is empty or only whitespace (no Node classify).
|
|
289
|
+
pithosai_nl_line_is_blank() {
|
|
290
|
+
case "$1" in
|
|
291
|
+
"") return 0 ;;
|
|
292
|
+
esac
|
|
293
|
+
[ -z "${1##*[![:space:]]*}" ] && return 1
|
|
294
|
+
return 0
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# First whitespace-separated token of a line.
|
|
298
|
+
pithosai_nl_first_word() {
|
|
299
|
+
printf '%s\n' "$1" | awk '{ print $1; exit }'
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# Return 0 for shell keywords that users also type as English (`for these files:`).
|
|
303
|
+
pithosai_nl_is_reserved_word() {
|
|
304
|
+
local w
|
|
305
|
+
w="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
|
|
306
|
+
w="${w%%[^a-z]*}"
|
|
307
|
+
case "$w" in
|
|
308
|
+
for|do|if|while|until|case|then|else|elif|fi|done|in|select) return 0 ;;
|
|
309
|
+
esac
|
|
310
|
+
return 1
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
# Return 0 when Enter should pass the line through to the shell (no classify).
|
|
314
|
+
pithosai_nl_should_passthrough_line() {
|
|
315
|
+
local line="$1"
|
|
316
|
+
local first
|
|
317
|
+
if pithosai_nl_line_is_blank "$line"; then
|
|
318
|
+
return 0
|
|
319
|
+
fi
|
|
320
|
+
first="$(pithosai_nl_first_word "$line")"
|
|
321
|
+
if [ -n "$first" ] && ! pithosai_nl_is_reserved_word "$first"; then
|
|
322
|
+
if command -v -- "$first" >/dev/null 2>&1; then
|
|
323
|
+
return 0
|
|
324
|
+
fi
|
|
325
|
+
fi
|
|
326
|
+
return 1
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
# Return 0 when the zsh/bash Enter intercept is enabled.
|
|
330
|
+
pithosai_nl_zle_is_enabled() {
|
|
331
|
+
local zle_off
|
|
332
|
+
zle_off="$(printf '%s' "${PITHOSAI_NL_ZLE:-}" | tr '[:upper:]' '[:lower:]')"
|
|
333
|
+
case "$zle_off" in
|
|
334
|
+
0|false|no|off) return 1 ;;
|
|
335
|
+
esac
|
|
336
|
+
pithosai_nl_fallback_is_enabled
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
# Classify and run pithosai when the line is NL. Return 0 if pithosai ran.
|
|
340
|
+
pithosai_nl_try_run_line() {
|
|
341
|
+
local line="$1"
|
|
342
|
+
local lang code
|
|
343
|
+
pithosai_nl_debug "try_run_line input=${line}"
|
|
344
|
+
lang="$(pithosai_nl_fallback_classify "$line")"
|
|
345
|
+
code=$?
|
|
346
|
+
pithosai_nl_debug "try_run_line classify exit=${code} lang=${lang}"
|
|
347
|
+
if [ "$code" -eq 2 ]; then
|
|
348
|
+
pithosai_nl_fallback_msg classifyUnavailable >&2
|
|
349
|
+
fi
|
|
350
|
+
if [ "$code" -eq 0 ]; then
|
|
351
|
+
pithosai_nl_fallback_run "$line" "$lang"
|
|
352
|
+
return 0
|
|
353
|
+
fi
|
|
354
|
+
return 1
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
# zsh: intercept Enter before parse. Never assign BUFFER to a pithosai CLI string.
|
|
358
|
+
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
359
|
+
pithosai_nl_accept_line() {
|
|
360
|
+
local line="${BUFFER}"
|
|
361
|
+
pithosai_nl_debug "zle accept-line input=${line}"
|
|
362
|
+
if ! pithosai_nl_zle_is_enabled; then
|
|
363
|
+
pithosai_nl_debug "zle intercept disabled"
|
|
364
|
+
zle .accept-line
|
|
365
|
+
return
|
|
366
|
+
fi
|
|
367
|
+
if pithosai_nl_should_passthrough_line "$line"; then
|
|
368
|
+
pithosai_nl_debug "zle passthrough"
|
|
369
|
+
zle .accept-line
|
|
370
|
+
return
|
|
371
|
+
fi
|
|
372
|
+
# Unfreeze the line editor so classify/LLM stderr can paint (otherwise Enter looks hung).
|
|
373
|
+
zle -I
|
|
374
|
+
print
|
|
375
|
+
if pithosai_nl_try_run_line "$line"; then
|
|
376
|
+
pithosai_nl_debug "zle run pithosai"
|
|
377
|
+
print -s -- "$line"
|
|
378
|
+
BUFFER=""
|
|
379
|
+
zle .reset-prompt
|
|
380
|
+
return 0
|
|
381
|
+
fi
|
|
382
|
+
zle .accept-line
|
|
383
|
+
}
|
|
384
|
+
if [[ -o interactive ]]; then
|
|
385
|
+
zle -N pithosai_nl_accept_line 2>/dev/null || true
|
|
386
|
+
zle -N accept-line pithosai_nl_accept_line 2>/dev/null || true
|
|
387
|
+
fi
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
# Build the quoted pithosai CLI invocation for an NL line so the native
|
|
391
|
+
# accept-line (not the readline handler) runs it. $1 = line, $2 = lang code.
|
|
392
|
+
pithosai_nl_bash_cli_command() {
|
|
393
|
+
local input="$1"
|
|
394
|
+
local lang="${2:-}"
|
|
395
|
+
local bin="${PITHOSAI_BIN:-pithosai}"
|
|
396
|
+
local model="${PITHOSAI_NL_MODEL:-krouter-rd}"
|
|
397
|
+
if [ -z "$lang" ]; then
|
|
398
|
+
lang="$(pithosai_nl_fallback_lang)"
|
|
399
|
+
fi
|
|
400
|
+
printf '%q --no-interactive --model %q --lang %q %q' \
|
|
401
|
+
"$bin" "$model" "$lang" "$input"
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
# bash 4+: intercept a key via readline bind -x and REWRITE the line in place.
|
|
405
|
+
#
|
|
406
|
+
# A bind -x handler runs while readline does not own the terminal, so it must
|
|
407
|
+
# never eval a command, spawn a child that reads stdin, or printf a newline:
|
|
408
|
+
# doing so desyncs readline and breaks TAB completion afterwards. Instead the
|
|
409
|
+
# handler only rewrites READLINE_LINE and returns.
|
|
410
|
+
#
|
|
411
|
+
# bind -x ALONE does NOT submit the line — it replaces the default accept-line
|
|
412
|
+
# binding. To submit the rewritten line in one keypress we use a two-key macro:
|
|
413
|
+
# bind -x '"\C-x\C-p": handler' (shell command)
|
|
414
|
+
# bind '"\C-j": "\C-x\C-p\C-m"' (macro: handler + accept-line)
|
|
415
|
+
# Pressing Ctrl-J dispatches \C-x\C-p (runs handler, rewrites), then \C-m
|
|
416
|
+
# (accept-line executes the rewritten line) — all with readline in control.
|
|
417
|
+
#
|
|
418
|
+
# Note: bash cannot intercept plain Enter (\C-m is consumed by accept-line and
|
|
419
|
+
# never reaches a bind -x macro). Lines that fail a shell parse error
|
|
420
|
+
# (`for these files: ...`) never reach the command-not-found path either;
|
|
421
|
+
# only \C-j or the command-not-found handle can recover them.
|
|
422
|
+
if [ -n "${BASH_VERSION:-}" ]; then
|
|
423
|
+
pithosai_nl_bash_accept_line() {
|
|
424
|
+
local line="${READLINE_LINE}"
|
|
425
|
+
local lang code cmd
|
|
426
|
+
pithosai_nl_debug "bash accept-line input=${line}"
|
|
427
|
+
if pithosai_nl_zle_is_enabled && ! pithosai_nl_should_passthrough_line "$line"; then
|
|
428
|
+
lang="$(pithosai_nl_fallback_classify "$line")"
|
|
429
|
+
code=$?
|
|
430
|
+
pithosai_nl_debug "bash classify exit=${code} lang=${lang}"
|
|
431
|
+
if [ "$code" -eq 0 ]; then
|
|
432
|
+
cmd="$(pithosai_nl_bash_cli_command "$line" "$lang")"
|
|
433
|
+
pithosai_nl_debug "bash rewrite to pithosai"
|
|
434
|
+
READLINE_LINE="$cmd"
|
|
435
|
+
READLINE_POINT=${#cmd}
|
|
436
|
+
return 0
|
|
437
|
+
fi
|
|
438
|
+
if [ "$code" -eq 2 ]; then
|
|
439
|
+
pithosai_nl_fallback_msg classifyUnavailable >&2
|
|
440
|
+
fi
|
|
441
|
+
pithosai_nl_debug "bash passthrough (classify miss)"
|
|
442
|
+
fi
|
|
443
|
+
# No rewrite happened: restore the buffer exactly as readline gave it, so a
|
|
444
|
+
# skipped line (PATH command, valid for/if one-liner, empty line) runs
|
|
445
|
+
# unchanged. Set both vars explicitly because a previous handler call may
|
|
446
|
+
# have left a rewritten buffer in place.
|
|
447
|
+
READLINE_LINE="$line"
|
|
448
|
+
READLINE_POINT=${#line}
|
|
449
|
+
return 0
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if [[ $- == *i* ]] && [ "${BASH_VERSINFO[0]}" -ge 4 ]; then
|
|
453
|
+
bind -x '"\C-x\C-p": pithosai_nl_bash_accept_line' 2>/dev/null || true
|
|
454
|
+
bind '"\C-j": "\C-x\C-p\C-m"' 2>/dev/null || true
|
|
455
|
+
fi
|
|
456
|
+
fi
|