quilltap 4.9.0-dev.73 → 4.9.0-dev.87

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
@@ -182,6 +182,7 @@ quilltap docs export <mount> <outputDir> # Mount → directory
182
182
  quilltap docs find <pattern> # Substring match on file names (--mount, --ext, --type, --limit)
183
183
  quilltap docs grep <pattern> # Substring match on extracted text (--mount, --ignore-case, -l, --max, --context)
184
184
  quilltap docs status # Per-mount extraction + embedding rollup (--mount, --top)
185
+ quilltap docs docker-mounts # Bind mounts filesystem stores need under Docker (--format args|json)
185
186
 
186
187
  # Server-required
187
188
  quilltap docs scan <mount> # Trigger a rescan
@@ -391,8 +392,11 @@ Fish picks new completion files up automatically — no shell restart needed.
391
392
 
392
393
  - **Subcommands**: `quilltap d<TAB>` → `db docs`
393
394
  - **Sub-verbs per namespace**: `quilltap db s<TAB>` → `schema show`
395
+ - **Flags per verb**: `quilltap docs docker-mounts --<TAB>` → the flags that verb accepts
394
396
  - **Instance names**: `quilltap --instance Fr<TAB>` → registered instances
395
- - **Mount names**: `quilltap docs ls --mount Qu<TAB>` mount points in the active instance
397
+ - **Mount names**: both `--mount` and the positional a verb takes — `quilltap docs ls Qu<TAB>`, and either end of `docs move`/`copy`/`link`
398
+
399
+ Completions **parse the line rather than counting words**, so a flag typed anywhere the CLI itself accepts one does not derail them: `quilltap docs --instance Friday <TAB>` still offers the `docs` verbs. bash and zsh also reuse the `-i` / `-d` / `--passphrase` already on the line when looking store names up, so the names offered come from the instance you are addressing rather than the default one. fish completes `--mount` but not the positionals, and always reads the default instance.
396
400
 
397
401
  Dynamic completions shell out to `quilltap`'s own subcommands. If the active instance is encrypted and no passphrase is reachable, the completion silently returns nothing rather than prompting in the middle of a tab.
398
402
 
@@ -94,3 +94,98 @@ describe('every subcommand has its own completion arm', () => {
94
94
  expect(noFlags).toEqual([]);
95
95
  });
96
96
  });
97
+
98
+ /**
99
+ * The arm-per-subcommand check above is still too coarse: `docs docker-mounts`
100
+ * had its own arm in all three shells while `--format`, its only flag, was
101
+ * offered by none of them. A flag documented in a subcommand's own `--help` is
102
+ * the contract the user reads, so that text is the source of truth here —
103
+ * whatever `--help` advertises, the three templates must offer.
104
+ *
105
+ * Each entry names the single function whose template literal prints that
106
+ * subcommand's help.
107
+ */
108
+ const HELP_SOURCES = {
109
+ db: ['bin/quilltap.js', 'printDbHelp'],
110
+ docs: ['lib/docs-commands.js', 'printDocsHelp'],
111
+ memories: ['lib/memories-commands.js', 'printMemoriesHelp'],
112
+ themes: ['lib/theme-commands.js', 'printHelp'],
113
+ instances: ['lib/instances-commands.js', 'printHelp'],
114
+ logs: ['lib/logs-commands.js', 'printLogsHelp'],
115
+ migrations: ['lib/migrations-commands.js', 'printHelp'],
116
+ maintenance: ['lib/maintenance-commands.js', 'printHelp'],
117
+ 'file-verify': ['lib/file-verify-commands.js', 'printHelp'],
118
+ 'memory-diff': ['lib/memory-diff-command.js', 'printMemoryDiffHelp'],
119
+ 'recall-replay': ['lib/recall-replay-command.js', 'printRecallReplayHelp'],
120
+ completion: ['lib/completion-commands.js', 'printCompletionHelp'],
121
+ };
122
+
123
+ const PKG_ROOT = path.join(__dirname, '..', '..');
124
+
125
+ /**
126
+ * Long flags named anywhere in one subcommand's help text. The declaration
127
+ * pattern tolerates arbitrary whitespace and an `async`/parameter list, so
128
+ * reformatting a help function does not fail a test about its content.
129
+ */
130
+ function flagsInHelp(relPath, fnName) {
131
+ const src = fs.readFileSync(path.join(PKG_ROOT, relPath), 'utf8');
132
+ const decl = String.raw`(?:async\s+)?function\s+${fnName}\s*\([^)]*\)\s*\{`;
133
+ const body = src.match(new RegExp(`${decl}([\\s\\S]*?)\\n\\}`));
134
+ if (!body) throw new Error(`Could not locate ${fnName}() in ${relPath}`);
135
+ return [...new Set(body[1].match(/--[a-z0-9][a-z0-9-]+/g) || [])].sort();
136
+ }
137
+
138
+ /**
139
+ * `--max` is a prefix of `--max-nodes`, so a plain substring test passes for a
140
+ * flag that is not actually there. Require the match to end at a non-flag
141
+ * character.
142
+ */
143
+ function mentionsFlag(haystack, flag) {
144
+ return new RegExp(`${flag}(?![a-z0-9-])`).test(haystack);
145
+ }
146
+
147
+ describe('completions offer every flag the help text advertises', () => {
148
+ it('covers every subcommand in the dispatch table', () => {
149
+ // A new subcommand needs a help source here, or its flags go unchecked.
150
+ expect(Object.keys(HELP_SOURCES).sort()).toEqual([...SUBCOMMANDS].sort());
151
+ });
152
+
153
+ const cases = Object.entries(HELP_SOURCES).flatMap(([sub, [file, fn]]) =>
154
+ ['bash', 'zsh', 'fish'].map((shell) => [sub, shell, file, fn])
155
+ );
156
+
157
+ it.each(cases)('%s: %s template offers every documented flag', (sub, shell, file, fn) => {
158
+ const tpl = fs.readFileSync(path.join(COMPLETION_DIR, `${shell}.template`), 'utf8');
159
+ // fish spells the flag `-l 'name'`, already an exact quoted token.
160
+ const present = (flag) =>
161
+ shell === 'fish' ? tpl.includes(`-l '${flag.slice(2)}'`) : mentionsFlag(tpl, flag);
162
+ const missing = flagsInHelp(file, fn).filter((flag) => !present(flag));
163
+ expect(missing).toEqual([]);
164
+ });
165
+ });
166
+
167
+ /**
168
+ * bash cannot infer which flags swallow the next word, so it carries explicit
169
+ * `vf_*` lists. A valued flag missing from its list makes the flag's value look
170
+ * like the subcommand's verb — the bug 101 failure mode. zsh and fish take the
171
+ * value from the flag's own spec, so only bash needs guarding.
172
+ */
173
+ describe('bash knows which docs flags take a value', () => {
174
+ it('lists every valued docs flag in vf_docs', () => {
175
+ const tpl = fs.readFileSync(path.join(COMPLETION_DIR, 'bash.template'), 'utf8');
176
+ // The scanner reads `$vf_global$vf_docs`, so a flag in either list counts.
177
+ const vfGlobal = tpl.match(/local vf_global="([^"]*)"/);
178
+ const vfDocs = tpl.match(/local vf_docs="([^"]*)"/);
179
+ expect(vfGlobal).toBeTruthy();
180
+ expect(vfDocs).toBeTruthy();
181
+ const scanned = new Set(`${vfGlobal[1]} ${vfDocs[1]}`.trim().split(/\s+/));
182
+ // A docs flag zsh declares with a `:value:` spec is by definition valued.
183
+ const zsh = fs.readFileSync(path.join(COMPLETION_DIR, 'zsh.template'), 'utf8');
184
+ const docsOpts = zsh.match(/docs_opts=\(([\s\S]*?)\n \)/);
185
+ expect(docsOpts).toBeTruthy();
186
+ const valued = [...docsOpts[1].matchAll(/'(--[a-z0-9-]+)\[[^\]]*\]:[^']*'/g)].map((m) => m[1]);
187
+ expect(valued.length).toBeGreaterThan(5);
188
+ const missing = valued.filter((flag) => !scanned.has(flag));
189
+ expect(missing).toEqual([]);
190
+ });
191
+ });
@@ -70,7 +70,7 @@ _quilltap_complete() {
70
70
  # `quilltap docs --limit 5 <TAB>` used to lose the verb list.
71
71
  local vf_global=" -d --data-dir -i --instance -p --port --passphrase "
72
72
  local vf_db=" --limit --grep --character --project --about --source --chat --message --field --tail --last --from --type --out --id --count "
73
- local vf_docs=" --mount --folder --type --ext --limit --max --context --top --threshold --sort --depth --max-nodes "
73
+ local vf_docs=" --mount --folder --type --ext --limit --max --context --top --threshold --sort --depth --max-nodes --format "
74
74
  local vf_themes=" -o --output -k --key -n --name "
75
75
  local vf_memories=" -d --data-dir --instance --passphrase --port --character --about --source --chat --project --since --until --min-importance --min-reinforced --sort --limit --in --max --context --depth --max-nodes --top --threshold "
76
76
  local vf_logs=" --stream --tail --grep "
@@ -193,6 +193,10 @@ _quilltap_complete() {
193
193
  COMPREPLY=($(compgen -W "combined error stdout stderr startup" -- "$cur"))
194
194
  return
195
195
  ;;
196
+ --format)
197
+ COMPREPLY=($(compgen -W "args json" -- "$cur"))
198
+ return
199
+ ;;
196
200
  esac
197
201
 
198
202
  # Subcommand-specific completion
@@ -227,7 +231,8 @@ _quilltap_complete() {
227
231
  local docs_verbs="list show files ls dir tree read export scan write delete mkdir move copy link rmdir mvdir status docker-mounts find grep reindex embed"
228
232
  local docs_flags="--mount --instance --data-dir --passphrase --port --json --help \
229
233
  --uri --base64 --force --rendered --links --folder --type --ext --limit --max --context --top --threshold \
230
- --ignore-case -l --wait -R --recursive --sort -r --reverse --depth --max-nodes --long --semantic"
234
+ --ignore-case -l --wait -R --recursive --sort -r --reverse --depth --max-nodes --long --semantic \
235
+ --format"
231
236
  if [[ "$cur" == -* ]]; then
232
237
  COMPREPLY=($(compgen -W "$docs_flags" -- "$cur"))
233
238
  elif [[ -z "$subverb" ]]; then
@@ -184,6 +184,9 @@ complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'depth' -d 'Maximu
184
184
  complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'max-nodes' -d 'Maximum graph nodes' -x
185
185
  complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'long' -d 'Long-form output'
186
186
  complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'semantic' -d 'Semantic search'
187
+ complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'uri' -d 'Show canonical qtap:// URIs'
188
+ complete -c quilltap -n '__quilltap_using_subcommand docs' -l 'base64' -d 'Base64 transfer for binary files'
189
+ complete -c quilltap -n '__quilltap_using_subverb docs docker-mounts' -l 'format' -d 'Output shape' -x -a 'args json'
187
190
 
188
191
  # ---------- themes verbs ----------
189
192
  complete -c quilltap -n '__quilltap_using_subcommand themes' -f -a 'list' -d 'List themes'
@@ -293,6 +293,7 @@ _quilltap_docs() {
293
293
  '--max-nodes[Maximum nodes in graph]:n:'
294
294
  '--long[Long-form output]'
295
295
  '--semantic[Use semantic search]'
296
+ '--format[For docker-mounts: output shape]:format:(args json)'
296
297
  '(-h --help)'{-h,--help}'[Show help]'
297
298
  )
298
299
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quilltap",
3
- "version": "4.9.0-dev.73",
3
+ "version": "4.9.0-dev.87",
4
4
  "description": "Self-hosted AI workspace for writers, worldbuilders, and roleplayers. Run with npx quilltap.",
5
5
  "author": {
6
6
  "name": "Charles Sebold",