quilltap 4.6.0-dev → 4.6.0-dev.39
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/bin/quilltap.js +78 -22
- package/lib/completion/bash.template +152 -33
- package/lib/completion/fish.template +262 -87
- package/lib/completion/zsh.template +219 -26
- package/lib/db-commands.js +325 -0
- package/package.json +1 -1
package/bin/quilltap.js
CHANGED
|
@@ -266,25 +266,67 @@ function linkNativeModules(standaloneDir) {
|
|
|
266
266
|
|| resolveModuleDir('better-sqlite3');
|
|
267
267
|
linkModule('better-sqlite3', betterSqlite3Dir);
|
|
268
268
|
|
|
269
|
-
// Link node-pty —
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
269
|
+
// Link node-pty — but only when we have to. The standalone tarball ships
|
|
270
|
+
// node-pty intact with cross-platform prebuilds (darwin-arm64, darwin-x64,
|
|
271
|
+
// win32-arm64, win32-x64). On those platforms the tarball-shipped copy is
|
|
272
|
+
// already correct, and we MUST NOT replace it with a symlink to the
|
|
273
|
+
// npm-installed copy: `sudo npm install -g quilltap` on macOS can strip the
|
|
274
|
+
// executable bit off `spawn-helper`, and we can't chmod a root-owned file
|
|
275
|
+
// back as a non-root runtime user — pty.spawn() then fails with
|
|
276
|
+
// `posix_spawnp failed`. Only Linux (which has no node-pty prebuild) and
|
|
277
|
+
// rebuild-failure cases need the symlink.
|
|
278
|
+
const standaloneNodePtyPath = path.join(standaloneNodeModules, 'node-pty');
|
|
279
|
+
const standaloneHasUsablePty = (() => {
|
|
280
|
+
try {
|
|
281
|
+
const stat = fs.lstatSync(standaloneNodePtyPath);
|
|
282
|
+
if (stat.isSymbolicLink()) return false; // prior broken-symlink state — replace it
|
|
283
|
+
if (!stat.isDirectory()) return false;
|
|
284
|
+
} catch {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
const platformPrebuildDir = path.join(
|
|
288
|
+
standaloneNodePtyPath,
|
|
289
|
+
'prebuilds',
|
|
290
|
+
`${process.platform}-${process.arch}`,
|
|
291
|
+
);
|
|
292
|
+
return fs.existsSync(platformPrebuildDir);
|
|
293
|
+
})();
|
|
294
|
+
|
|
295
|
+
if (!standaloneHasUsablePty) {
|
|
296
|
+
const nodePtyDir = resolveModuleDir('node-pty');
|
|
297
|
+
linkModule('node-pty', nodePtyDir);
|
|
298
|
+
if (nodePtyDir) {
|
|
299
|
+
// Some npm cache extractions (notably `sudo npm install -g`) strip the
|
|
300
|
+
// executable bit on spawn-helper. Restore it where we can. If chmod
|
|
301
|
+
// fails because we don't own the file (typical when the CLI was
|
|
302
|
+
// installed with sudo and is run as a non-root user), warn loudly —
|
|
303
|
+
// silent failure here produces the `posix_spawnp failed` runtime error
|
|
304
|
+
// with no actionable hint.
|
|
305
|
+
const prebuildsDir = path.join(nodePtyDir, 'prebuilds');
|
|
306
|
+
if (fs.existsSync(prebuildsDir)) {
|
|
307
|
+
try {
|
|
308
|
+
for (const entry of fs.readdirSync(prebuildsDir, { withFileTypes: true })) {
|
|
309
|
+
if (!entry.isDirectory()) continue;
|
|
310
|
+
const helper = path.join(prebuildsDir, entry.name, 'spawn-helper');
|
|
311
|
+
if (!fs.existsSync(helper)) continue;
|
|
312
|
+
try {
|
|
313
|
+
fs.chmodSync(helper, 0o755);
|
|
314
|
+
} catch (err) {
|
|
315
|
+
if (err && err.code === 'EPERM') {
|
|
316
|
+
console.error('');
|
|
317
|
+
console.error(` Warning: Could not make node-pty spawn-helper executable:`);
|
|
318
|
+
console.error(` ${helper}`);
|
|
319
|
+
console.error(` The file is owned by another user (likely root from a sudo'd`);
|
|
320
|
+
console.error(` global install). Terminal sessions will fail to spawn with`);
|
|
321
|
+
console.error(` "posix_spawnp failed" until this is fixed. Run:`);
|
|
322
|
+
console.error(` sudo chmod 755 "${helper}"`);
|
|
323
|
+
console.error('');
|
|
324
|
+
}
|
|
325
|
+
// Other errors are non-fatal — node-pty may still work if the bit was already set.
|
|
326
|
+
}
|
|
285
327
|
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
328
|
+
} catch { /* best-effort */ }
|
|
329
|
+
}
|
|
288
330
|
}
|
|
289
331
|
}
|
|
290
332
|
|
|
@@ -740,6 +782,11 @@ Subcommands (high-level shortcuts; auto-pick the right database):
|
|
|
740
782
|
log <id> Full request/response of a single LLM log
|
|
741
783
|
memories --character <id> Memories held by a character
|
|
742
784
|
(flags: --about <id|name> --source AUTO|MANUAL)
|
|
785
|
+
characters status Per-character vault readiness report:
|
|
786
|
+
flag value, vault present, single-file count,
|
|
787
|
+
Prompts/ and Scenarios/ folder counts, and any
|
|
788
|
+
divergence between DB columns and vault content.
|
|
789
|
+
(flags: --id <id|name> --diverged --blocked --limit N)
|
|
743
790
|
optimize [target...] Run maintenance (VACUUM + ANALYZE + PRAGMA optimize)
|
|
744
791
|
on the named databases, or all of them if no
|
|
745
792
|
target is given. Targets: main, llm-logs,
|
|
@@ -762,6 +809,8 @@ Low-level options (legacy; still supported):
|
|
|
762
809
|
--tables List all tables in the active database
|
|
763
810
|
--count <table> Show row count for a table
|
|
764
811
|
--repl Interactive SQL prompt (extras: .cols, .find)
|
|
812
|
+
--json Emit machine-readable JSON instead of a table
|
|
813
|
+
(works with --tables, --count, and raw SQL)
|
|
765
814
|
--llm-logs Target the LLM logs database
|
|
766
815
|
--mount-points Target the document mount-index database
|
|
767
816
|
--data-dir <path> Override data directory (pass instance root)
|
|
@@ -869,6 +918,7 @@ async function dbCommand(args) {
|
|
|
869
918
|
let lockStatus = false;
|
|
870
919
|
let lockClean = false;
|
|
871
920
|
let lockOverride = false;
|
|
921
|
+
let asJson = false;
|
|
872
922
|
|
|
873
923
|
let i = 0;
|
|
874
924
|
while (i < cleaned.length) {
|
|
@@ -878,6 +928,7 @@ async function dbCommand(args) {
|
|
|
878
928
|
case '--tables': showTables = true; break;
|
|
879
929
|
case '--count': countTable = cleaned[++i]; break;
|
|
880
930
|
case '--repl': repl = true; break;
|
|
931
|
+
case '--json': asJson = true; break;
|
|
881
932
|
case '--help': case '-h': showHelp = true; break;
|
|
882
933
|
case '--lock-status': lockStatus = true; break;
|
|
883
934
|
case '--lock-clean': lockClean = true; break;
|
|
@@ -971,22 +1022,27 @@ async function dbCommand(args) {
|
|
|
971
1022
|
try {
|
|
972
1023
|
if (showTables) {
|
|
973
1024
|
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name").all();
|
|
974
|
-
|
|
1025
|
+
if (asJson) console.log(JSON.stringify(tables.map(t => t.name), null, 2));
|
|
1026
|
+
else for (const t of tables) console.log(t.name);
|
|
975
1027
|
} else if (countTable) {
|
|
976
1028
|
const row = db.prepare(`SELECT count(*) as count FROM "${countTable}"`).get();
|
|
977
|
-
console.log(row.count);
|
|
1029
|
+
if (asJson) console.log(JSON.stringify({ table: countTable, count: row.count }, null, 2));
|
|
1030
|
+
else console.log(row.count);
|
|
978
1031
|
} else if (sql) {
|
|
979
1032
|
const stmt = db.prepare(sql);
|
|
980
1033
|
if (stmt.reader) {
|
|
981
1034
|
const rows = stmt.all();
|
|
982
|
-
if (
|
|
1035
|
+
if (asJson) {
|
|
1036
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
1037
|
+
} else if (rows.length === 0) {
|
|
983
1038
|
console.log('(no results)');
|
|
984
1039
|
} else {
|
|
985
1040
|
console.table(rows);
|
|
986
1041
|
}
|
|
987
1042
|
} else {
|
|
988
1043
|
const info = stmt.run();
|
|
989
|
-
console.log(
|
|
1044
|
+
if (asJson) console.log(JSON.stringify({ changes: info.changes, lastInsertRowid: Number(info.lastInsertRowid) }, null, 2));
|
|
1045
|
+
else console.log(`Changes: ${info.changes}`);
|
|
990
1046
|
}
|
|
991
1047
|
} else if (repl) {
|
|
992
1048
|
const readline = require('readline');
|
|
@@ -12,15 +12,19 @@ _quilltap_complete() {
|
|
|
12
12
|
cword=$COMP_CWORD
|
|
13
13
|
|
|
14
14
|
# Global options that can appear before subcommands
|
|
15
|
-
local global_opts="-d --data-dir -i --instance -p --port -o --open -v --version -h --help --update"
|
|
15
|
+
local global_opts="-d --data-dir -i --instance -p --port -o --open -v --version -h --help --update --passphrase"
|
|
16
|
+
|
|
17
|
+
# Top-level subcommands
|
|
18
|
+
local top_cmds="db docs themes instances memories memory-diff logs migrations completion"
|
|
16
19
|
|
|
17
20
|
# Get the subcommand (first non-option word after quilltap)
|
|
18
21
|
local subcommand=""
|
|
22
|
+
local subverb=""
|
|
19
23
|
local i=1
|
|
20
24
|
while [[ $i -lt $cword ]]; do
|
|
21
25
|
local word="${words[$i]}"
|
|
22
26
|
case "$word" in
|
|
23
|
-
-d|--data-dir|-i|--instance|-p|--port)
|
|
27
|
+
-d|--data-dir|-i|--instance|-p|--port|--passphrase)
|
|
24
28
|
# These take a value, skip the next word
|
|
25
29
|
((i += 2))
|
|
26
30
|
;;
|
|
@@ -33,22 +37,26 @@ _quilltap_complete() {
|
|
|
33
37
|
((i += 1))
|
|
34
38
|
;;
|
|
35
39
|
*)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
if [[ -z "$subcommand" ]]; then
|
|
41
|
+
subcommand="$word"
|
|
42
|
+
elif [[ -z "$subverb" ]]; then
|
|
43
|
+
subverb="$word"
|
|
44
|
+
fi
|
|
45
|
+
((i += 1))
|
|
39
46
|
;;
|
|
40
47
|
esac
|
|
41
48
|
done
|
|
42
49
|
|
|
43
50
|
# If we're completing a global flag value
|
|
44
|
-
if [[ "$prev" == "-d" ]] || [[ "$prev" == "--data-dir" ]]
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
if [[ "$prev" == "-d" ]] || [[ "$prev" == "--data-dir" ]]; then
|
|
52
|
+
# Complete with directories
|
|
53
|
+
COMPREPLY=($(compgen -d -- "$cur"))
|
|
54
|
+
return
|
|
55
|
+
fi
|
|
56
|
+
if [[ "$prev" == "-p" ]] || [[ "$prev" == "--port" ]] || [[ "$prev" == "--passphrase" ]]; then
|
|
47
57
|
return
|
|
48
58
|
fi
|
|
49
|
-
|
|
50
59
|
if [[ "$prev" == "-i" ]] || [[ "$prev" == "--instance" ]]; then
|
|
51
|
-
# Complete with instance names
|
|
52
60
|
local instances=$(command quilltap instances list --names-only 2>/dev/null)
|
|
53
61
|
COMPREPLY=($(compgen -W "$instances" -- "$cur"))
|
|
54
62
|
return
|
|
@@ -59,53 +67,164 @@ _quilltap_complete() {
|
|
|
59
67
|
if [[ "$cur" == -* ]]; then
|
|
60
68
|
COMPREPLY=($(compgen -W "$global_opts" -- "$cur"))
|
|
61
69
|
else
|
|
62
|
-
COMPREPLY=($(compgen -W "
|
|
70
|
+
COMPREPLY=($(compgen -W "$top_cmds" -- "$cur"))
|
|
63
71
|
fi
|
|
64
72
|
return
|
|
65
73
|
fi
|
|
66
74
|
|
|
75
|
+
# Shared flag-value completions for any subcommand
|
|
76
|
+
case "$prev" in
|
|
77
|
+
--mount)
|
|
78
|
+
local mounts=$(command quilltap docs list --names-only 2>/dev/null)
|
|
79
|
+
COMPREPLY=($(compgen -W "$mounts" -- "$cur"))
|
|
80
|
+
return
|
|
81
|
+
;;
|
|
82
|
+
--character|--about)
|
|
83
|
+
# No live source; suggest common literals
|
|
84
|
+
COMPREPLY=($(compgen -W "all self none" -- "$cur"))
|
|
85
|
+
return
|
|
86
|
+
;;
|
|
87
|
+
--source)
|
|
88
|
+
COMPREPLY=($(compgen -W "AUTO MANUAL" -- "$cur"))
|
|
89
|
+
return
|
|
90
|
+
;;
|
|
91
|
+
--sort)
|
|
92
|
+
COMPREPLY=($(compgen -W "name path size modified created reinforced importance accessed reinforcement-count links" -- "$cur"))
|
|
93
|
+
return
|
|
94
|
+
;;
|
|
95
|
+
--field)
|
|
96
|
+
COMPREPLY=($(compgen -W "request response both" -- "$cur"))
|
|
97
|
+
return
|
|
98
|
+
;;
|
|
99
|
+
--type)
|
|
100
|
+
COMPREPLY=($(compgen -W "file folder" -- "$cur"))
|
|
101
|
+
return
|
|
102
|
+
;;
|
|
103
|
+
--stream)
|
|
104
|
+
COMPREPLY=($(compgen -W "combined error stdout stderr startup" -- "$cur"))
|
|
105
|
+
return
|
|
106
|
+
;;
|
|
107
|
+
esac
|
|
108
|
+
|
|
67
109
|
# Subcommand-specific completion
|
|
68
|
-
local subcommand_opts=""
|
|
69
110
|
case "$subcommand" in
|
|
70
111
|
db)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
112
|
+
local db_verbs="schema find chats messages logs message log memories optimize backup integrity"
|
|
113
|
+
local db_flags="--instance --data-dir --passphrase --json --limit --grep \
|
|
114
|
+
--character --project --about --source --chat --message --rendered --field \
|
|
115
|
+
--tail --last --full --from --type --out --help \
|
|
116
|
+
--tables --count --repl --llm-logs --mount-points \
|
|
117
|
+
--lock-status --lock-clean --lock-override"
|
|
118
|
+
if [[ -z "$subverb" ]]; then
|
|
119
|
+
if [[ "$cur" == -* ]]; then
|
|
120
|
+
COMPREPLY=($(compgen -W "$db_flags" -- "$cur"))
|
|
121
|
+
else
|
|
122
|
+
COMPREPLY=($(compgen -W "$db_verbs" -- "$cur"))
|
|
123
|
+
fi
|
|
124
|
+
else
|
|
125
|
+
COMPREPLY=($(compgen -W "$db_flags" -- "$cur"))
|
|
74
126
|
fi
|
|
75
|
-
COMPREPLY=($(compgen -W "$subcommand_opts" -- "$cur"))
|
|
76
127
|
;;
|
|
77
128
|
docs)
|
|
78
129
|
local docs_verbs="list show files ls dir read export scan write delete mkdir move copy status find grep reindex embed"
|
|
79
|
-
|
|
80
|
-
|
|
130
|
+
local docs_flags="--mount --instance --data-dir --passphrase --port --json --help \
|
|
131
|
+
--force --rendered --links --folder --type --ext --limit --max --context --top --threshold \
|
|
132
|
+
--ignore-case -l --wait -R --recursive --sort -r --reverse --depth --max-nodes --long --semantic"
|
|
133
|
+
if [[ -z "$subverb" ]]; then
|
|
134
|
+
if [[ "$cur" == -* ]]; then
|
|
135
|
+
COMPREPLY=($(compgen -W "$docs_flags" -- "$cur"))
|
|
136
|
+
else
|
|
137
|
+
COMPREPLY=($(compgen -W "$docs_verbs" -- "$cur"))
|
|
138
|
+
fi
|
|
139
|
+
else
|
|
140
|
+
COMPREPLY=($(compgen -W "$docs_flags" -- "$cur"))
|
|
81
141
|
fi
|
|
82
|
-
COMPREPLY=($(compgen -W "$docs_verbs" -- "$cur"))
|
|
83
142
|
;;
|
|
84
143
|
themes)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
144
|
+
local themes_verbs="list install uninstall validate export create search update registry"
|
|
145
|
+
local themes_flags="--instance --data-dir --output -o --help"
|
|
146
|
+
if [[ -z "$subverb" ]]; then
|
|
147
|
+
if [[ "$cur" == -* ]]; then
|
|
148
|
+
COMPREPLY=($(compgen -W "$themes_flags" -- "$cur"))
|
|
149
|
+
else
|
|
150
|
+
COMPREPLY=($(compgen -W "$themes_verbs" -- "$cur"))
|
|
151
|
+
fi
|
|
152
|
+
elif [[ "$subverb" == "registry" ]]; then
|
|
153
|
+
local registry_verbs="list add remove refresh keygen sign"
|
|
154
|
+
local registry_flags="--key -k --name -n --output -o --help"
|
|
155
|
+
if [[ "$cur" == -* ]]; then
|
|
156
|
+
COMPREPLY=($(compgen -W "$registry_flags" -- "$cur"))
|
|
157
|
+
else
|
|
158
|
+
COMPREPLY=($(compgen -W "$registry_verbs" -- "$cur"))
|
|
159
|
+
fi
|
|
160
|
+
else
|
|
161
|
+
COMPREPLY=($(compgen -W "$themes_flags" -- "$cur"))
|
|
88
162
|
fi
|
|
89
|
-
COMPREPLY=($(compgen -W "$subcommand_opts" -- "$cur"))
|
|
90
163
|
;;
|
|
91
164
|
instances)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
165
|
+
local inst_verbs="list ls show path where add create remove rm delete set-passphrase passphrase default rename"
|
|
166
|
+
local inst_flags="--names-only --json --clear --help"
|
|
167
|
+
if [[ -z "$subverb" ]]; then
|
|
168
|
+
if [[ "$cur" == -* ]]; then
|
|
169
|
+
COMPREPLY=($(compgen -W "$inst_flags" -- "$cur"))
|
|
170
|
+
else
|
|
171
|
+
COMPREPLY=($(compgen -W "$inst_verbs" -- "$cur"))
|
|
172
|
+
fi
|
|
173
|
+
else
|
|
174
|
+
# Most instances verbs take a name as positional; offer registered names
|
|
175
|
+
case "$subverb" in
|
|
176
|
+
show|remove|rm|delete|set-passphrase|passphrase|default|rename)
|
|
177
|
+
local instances=$(command quilltap instances list --names-only 2>/dev/null)
|
|
178
|
+
if [[ "$cur" == -* ]]; then
|
|
179
|
+
COMPREPLY=($(compgen -W "$inst_flags" -- "$cur"))
|
|
180
|
+
else
|
|
181
|
+
COMPREPLY=($(compgen -W "$instances" -- "$cur"))
|
|
182
|
+
fi
|
|
183
|
+
;;
|
|
184
|
+
*)
|
|
185
|
+
COMPREPLY=($(compgen -W "$inst_flags" -- "$cur"))
|
|
186
|
+
;;
|
|
187
|
+
esac
|
|
95
188
|
fi
|
|
96
|
-
COMPREPLY=($(compgen -W "$subcommand_opts" -- "$cur"))
|
|
97
189
|
;;
|
|
98
190
|
memories)
|
|
99
191
|
local mem_verbs="ls find grep show tree status validate"
|
|
100
|
-
|
|
101
|
-
|
|
192
|
+
local mem_flags="--character --about --source --chat --project --since --until \
|
|
193
|
+
--min-importance --min-reinforced --has-embedding --no-embedding \
|
|
194
|
+
--sort -r --reverse --limit --full-titles --in --no-related --list \
|
|
195
|
+
--ignore-case -i --paths-only -l --max --context --depth --max-nodes \
|
|
196
|
+
--semantic --top --threshold \
|
|
197
|
+
--instance --data-dir --passphrase --port --json --help"
|
|
198
|
+
if [[ -z "$subverb" ]]; then
|
|
199
|
+
if [[ "$cur" == -* ]]; then
|
|
200
|
+
COMPREPLY=($(compgen -W "$mem_flags" -- "$cur"))
|
|
201
|
+
else
|
|
202
|
+
COMPREPLY=($(compgen -W "$mem_verbs" -- "$cur"))
|
|
203
|
+
fi
|
|
204
|
+
else
|
|
205
|
+
COMPREPLY=($(compgen -W "$mem_flags" -- "$cur"))
|
|
102
206
|
fi
|
|
103
|
-
COMPREPLY=($(compgen -W "$mem_verbs" -- "$cur"))
|
|
104
207
|
;;
|
|
105
208
|
memory-diff)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
209
|
+
local md_flags="--instance --data-dir --passphrase --port --concurrency --out --help"
|
|
210
|
+
COMPREPLY=($(compgen -W "$md_flags" -- "$cur"))
|
|
211
|
+
;;
|
|
212
|
+
logs)
|
|
213
|
+
local logs_flags="--stream --tail -f --follow --grep \
|
|
214
|
+
--instance --data-dir --passphrase --help"
|
|
215
|
+
COMPREPLY=($(compgen -W "$logs_flags" -- "$cur"))
|
|
216
|
+
;;
|
|
217
|
+
migrations)
|
|
218
|
+
local mig_verbs="status pending run"
|
|
219
|
+
local mig_flags="--dry-run --json --instance --data-dir --passphrase --help"
|
|
220
|
+
if [[ -z "$subverb" ]]; then
|
|
221
|
+
if [[ "$cur" == -* ]]; then
|
|
222
|
+
COMPREPLY=($(compgen -W "$mig_flags" -- "$cur"))
|
|
223
|
+
else
|
|
224
|
+
COMPREPLY=($(compgen -W "$mig_verbs" -- "$cur"))
|
|
225
|
+
fi
|
|
226
|
+
else
|
|
227
|
+
COMPREPLY=($(compgen -W "$mig_flags" -- "$cur"))
|
|
109
228
|
fi
|
|
110
229
|
;;
|
|
111
230
|
completion)
|