@samline/autocomplete 0.0.0-stage → 2.0.0

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 (45) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +314 -2
  4. package/dist/browser/global.global.js +668 -0
  5. package/dist/browser/global.global.js.map +1 -0
  6. package/dist/browser/index.cjs +663 -0
  7. package/dist/browser/index.cjs.map +1 -0
  8. package/dist/browser/index.d.cts +31 -0
  9. package/dist/browser/index.d.ts +31 -0
  10. package/dist/browser/index.js +24 -0
  11. package/dist/browser/index.js.map +1 -0
  12. package/dist/chunk-4IPBCQDZ.js +218 -0
  13. package/dist/chunk-4IPBCQDZ.js.map +1 -0
  14. package/dist/chunk-5UZVFHB4.js +70 -0
  15. package/dist/chunk-5UZVFHB4.js.map +1 -0
  16. package/dist/chunk-AD7T42HJ.js +1 -0
  17. package/dist/chunk-AD7T42HJ.js.map +1 -0
  18. package/dist/chunk-PPDQPLPE.js +1 -0
  19. package/dist/chunk-PPDQPLPE.js.map +1 -0
  20. package/dist/chunk-U5JYDGKW.js +403 -0
  21. package/dist/chunk-U5JYDGKW.js.map +1 -0
  22. package/dist/core/index.cjs +181 -0
  23. package/dist/core/index.cjs.map +1 -0
  24. package/dist/core/index.d.cts +31 -0
  25. package/dist/core/index.d.ts +31 -0
  26. package/dist/core/index.js +22 -0
  27. package/dist/core/index.js.map +1 -0
  28. package/dist/index.cjs +697 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.cts +22 -0
  31. package/dist/index.d.ts +22 -0
  32. package/dist/index.js +61 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/render-B38UXYCT.d.ts +7 -0
  35. package/dist/render-WD69VMUs.d.cts +7 -0
  36. package/dist/styles.css +61 -0
  37. package/dist/types-CPvjhqjb.d.cts +118 -0
  38. package/dist/types-CPvjhqjb.d.ts +118 -0
  39. package/dist/vanilla/index.cjs +598 -0
  40. package/dist/vanilla/index.cjs.map +1 -0
  41. package/dist/vanilla/index.d.cts +11 -0
  42. package/dist/vanilla/index.d.ts +11 -0
  43. package/dist/vanilla/index.js +13 -0
  44. package/dist/vanilla/index.js.map +1 -0
  45. package/package.json +127 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@samline/autocomplete` are documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [2.0.0] - Unreleased
6
+
7
+ Sources beyond HTTP, caching, highlighting, a stricter listbox and the registry shared by the other `@samline` packages.
8
+
9
+ ### Breaking
10
+
11
+ - The browser registry follows the shared `@samline` shape: `newAutocomplete({ id, options })`, `getAutocomplete(id)`, `getAutocompletes()`, `destroyAutocomplete(idOrInput)` and `destroyAutocompletes()` replace `create(target, options)` and `destroy(id)`. `newAutocomplete` logs and returns `null` instead of throwing when the id or input is missing.
12
+ - `@samline/autocomplete/browser` is now the registry as an ESM/CommonJS module. The standalone script moved to `@samline/autocomplete/browser/global` (the file is still `dist/browser/global.global.js`).
13
+ - Options are `<div role="option">` elements instead of `<button>`, so they are no longer Tab stops. `renderOption` receives an `HTMLElement` and a third `context` argument.
14
+ - The listbox now sits inside `[data-autocomplete-popup]`, which carries the positioning styles. Loading, empty and error messages render in `[data-autocomplete-status]` outside the listbox, instead of inside it with `role="status"` / `role="alert"`; a separate polite live region announces them. Update selectors that targeted `[data-autocomplete-list]` for positioning.
15
+ - Labels are highlighted by default. Set `highlight: false` for plain text.
16
+ - Function and endpoint results are cached per query for five minutes by default. Set `cache: false` for the previous behavior.
17
+ - `createAutocompleteController` is removed; use `createAutocomplete` or `autocomplete`.
18
+ - The default label and value also read a `name` field.
19
+
20
+ ### Added
21
+
22
+ - `source`: a local array filtered in the browser, or `(query, { signal, input }) => items`, as an alternative to `endpoint`. Array sources default to `minLength: 1` and `debounce: 0`.
23
+ - `filter` and `normalize` options; matching ignores case and accents by default.
24
+ - `cache` (`true`, `false` or `{ max, ttl }`) and `controller.clearCache()`. `autocomplete:load` reports `cached`.
25
+ - `highlight` option and `<mark data-autocomplete-highlight>` rendering. `renderOption` context `{ query, index, label, highlight }`.
26
+ - `messages.results` and message functions of `{ query, count }` for translations and plurals.
27
+ - Controller `popupElement`, `statusElement` and `liveElement`. The listbox is labelled by the input's `<label>`.
28
+ - Helpers `fromEndpoint`, `filterSuggestions`, `normalizeText`, `highlight`, `renderHighlight`, `createCache` and `DEFAULT_MESSAGES`.
29
+ - Entrypoints `@samline/autocomplete/core`, `@samline/autocomplete/vanilla` and the `style.css` alias.
30
+ - Stylesheet: highlight custom properties and a forced-colors outline for the active option.
31
+ - A "Local data" example.
32
+
33
+ ## [1.0.0] - 2026-11-13
34
+
35
+ First public release.
36
+
37
+ ### Added
38
+
39
+ - `createAutocomplete(input, options)` (alias `autocomplete`) turns an existing text input into an accessible remote combobox: debounce, abortable requests, stale-response protection, listbox rendering, keyboard and pointer selection, events and cleanup.
40
+ - Options: `endpoint`, `queryParam`, `requestInit`, `parseResponse`, `mapResponse`, `getId`, `getLabel`, `getValue`, `renderOption`, `minLength`, `debounce`, `maxResults`, `searchOnFocus`, `messages`, `onSelect` and `onError`.
41
+ - Events `autocomplete:loadstart`, `autocomplete:load`, `autocomplete:error`, `autocomplete:select` and `autocomplete:clear`.
42
+ - Keyboard: ArrowUp, ArrowDown, Home, End, Enter, Escape and Tab. Searches wait for IME composition to finish.
43
+ - Browser global `window.Autocomplete` with `create`, `destroy`, `available` and `autocomplete`, and an optional stylesheet themed with `--autocomplete-*` custom properties.
44
+ - Website with examples and documentation at https://samline.github.io/autocomplete/.
45
+
46
+ ### Fixed (since the unpublished 0.1.0)
47
+
48
+ - Escape, Tab, clicking outside, selecting a suggestion and `close()` cancel the pending debounced search and abort the request in flight. Before, a late response reopened the list after it was dismissed.
49
+ - The standalone script defines `window.Autocomplete` with its documented members. Before, the global was wrapped as `{ default }`.
50
+
51
+ [2.0.0]: https://github.com/samline/autocomplete/compare/v1.0.0...HEAD
52
+ [1.0.0]: https://github.com/samline/autocomplete/releases/tag/v1.0.0
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Samuel Olvera (samline)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,315 @@
1
- # Temporary Holding Version
1
+ # @samline/autocomplete
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ An accessible, framework-agnostic autocomplete (combobox) for vanilla JavaScript, TypeScript and plain HTML. Point an input at an endpoint, an async function or a local array; debounce, cancellation, caching, accent-insensitive matching, highlighting, keyboard navigation, screen reader announcements, events and cleanup are handled for you.
4
+
5
+ [Demo](https://samline.github.io/autocomplete/) · [Examples](https://samline.github.io/autocomplete/examples/) · [Documentation](https://samline.github.io/autocomplete/docs/) · [Changelog](CHANGELOG.md)
6
+
7
+ ## Table of contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick start](#quick-start)
11
+ - [HTML / CDN](#html--cdn)
12
+ - [Capabilities](#capabilities)
13
+ - [API at a glance](#api-at-a-glance)
14
+ - [Documentation](#documentation)
15
+ - [Changelog](#changelog)
16
+ - [AI agent skill](#ai-agent-skill)
17
+ - [License](#license)
18
+
19
+ ## Installation
20
+
21
+ ```sh
22
+ npm install @samline/autocomplete
23
+ ```
24
+
25
+ ```sh
26
+ pnpm add @samline/autocomplete
27
+ ```
28
+
29
+ ```sh
30
+ bun add @samline/autocomplete
31
+ ```
32
+
33
+ Requires Node 20+ when bundling. Runs in modern browsers with `fetch` and `AbortController`. No runtime dependencies.
34
+
35
+ Import the optional stylesheet once in your application entrypoint:
36
+
37
+ ```js
38
+ import '@samline/autocomplete/styles.css'
39
+ ```
40
+
41
+ ## Quick start
42
+
43
+ ```html
44
+ <div class="field" style="position: relative">
45
+ <label for="city">City</label>
46
+ <input id="city" type="text" />
47
+ </div>
48
+ ```
49
+
50
+ ```js
51
+ import { createAutocomplete } from '@samline/autocomplete'
52
+ import '@samline/autocomplete/styles.css'
53
+
54
+ const controller = createAutocomplete('#city', {
55
+ endpoint: '/api/cities', // GET /api/cities?q=<query>
56
+ getId: city => city.id,
57
+ getLabel: city => city.name,
58
+ onSelect: city => console.log('Selected', city),
59
+ })
60
+
61
+ // When the owning component or page leaves:
62
+ controller.destroy()
63
+ ```
64
+
65
+ What this does:
66
+
67
+ - Turns the existing input into an ARIA combobox and renders a popup with a listbox right after it.
68
+ - Searches once the query reaches two characters, 250 ms after typing stops, and caches each query's results for five minutes.
69
+ - Reads a root array, or a `suggestions`, `items` or `data` array, from the JSON response.
70
+ - Highlights the typed words in each label and announces the result count to screen readers.
71
+ - Writes the chosen suggestion into the input, dispatches `autocomplete:select` and calls `onSelect`.
72
+ - Restores the input attributes it changed and removes the list when `destroy()` runs.
73
+
74
+ The wrapper needs `position: relative` because the default popup is absolutely positioned under the input.
75
+
76
+ ## HTML / CDN
77
+
78
+ Choose **Package / ESM** when installing with npm, pnpm or bun and importing Autocomplete in your application. Choose **HTML / CDN** for Shopify, WordPress or plain HTML pages without a build step. Both use the same options and controller.
79
+
80
+ ```html
81
+ <link
82
+ rel="stylesheet"
83
+ href="https://cdn.jsdelivr.net/npm/@samline/autocomplete@2.0.0/dist/styles.css"
84
+ />
85
+ <script src="https://cdn.jsdelivr.net/npm/@samline/autocomplete@2.0.0/dist/browser/global.global.js"></script>
86
+ ```
87
+
88
+ > Pin the version in production, or self-host the same files.
89
+
90
+ The standalone script (an IIFE) defines `window.Autocomplete`:
91
+
92
+ ```html
93
+ <div class="field" style="position: relative">
94
+ <label for="city">City</label>
95
+ <input id="city" type="text" />
96
+ </div>
97
+
98
+ <script>
99
+ const city = window.Autocomplete.newAutocomplete({
100
+ id: 'city',
101
+ options: { endpoint: '/api/cities' },
102
+ })
103
+ </script>
104
+ ```
105
+
106
+ The global follows the same registry shape as the other `@samline` packages:
107
+
108
+ | Member | Purpose |
109
+ | ---------------------------------------- | ------------------------------------------------------------------ |
110
+ | `newAutocomplete({ id, options })` | Enhances the input with that id; replaces a previous registration. |
111
+ | `getAutocomplete(id)` | The registered controller, or `null`. |
112
+ | `getAutocompletes()` | A copy of every registered controller by id. |
113
+ | `destroyAutocomplete(idOrInput)` | Destroys one registered controller. |
114
+ | `destroyAutocompletes()` | Destroys them all. |
115
+ | `available`, `autocomplete(input, opts)` | The live registry, and a factory that bypasses it. |
116
+
117
+ `newAutocomplete` logs and returns `null` when the id is empty or no input has it.
118
+
119
+ ## Capabilities
120
+
121
+ - Three kinds of source: an HTTP endpoint, an async function (SDKs, GraphQL, workers) or a local array.
122
+ - Any response shape through `parseResponse`, `mapResponse`, `getId`, `getLabel` and `getValue`.
123
+ - Accent- and case-insensitive matching: `merida` finds `Mérida`.
124
+ - Highlighted matches rendered as `<mark>` elements, never HTML strings.
125
+ - A per-query LRU cache with expiry for function and endpoint sources.
126
+ - WAI-ARIA combobox and listbox with full keyboard operation and a polite live region.
127
+ - Debounced searches, aborted superseded requests and ignored late responses.
128
+ - Bubbling DOM events that keep hidden fields and other UI in sync.
129
+ - An optional stylesheet themed with `--autocomplete-*` custom properties.
130
+ - React, Vue, Svelte, Shopify and WordPress through the same API, with no adapter.
131
+
132
+ [Working examples](https://samline.github.io/autocomplete/examples/) cover remote search, custom options, events and local data, each with copyable files.
133
+
134
+ ### Any source
135
+
136
+ Pass exactly one of `source` or `endpoint`.
137
+
138
+ ```js
139
+ // A local array, filtered in the browser (minLength 1, no debounce by default).
140
+ createAutocomplete('#state', { source: ['Michoacán', 'Nuevo León', 'Querétaro'] })
141
+
142
+ // Any async function. Pass the signal on so dismissed searches abort.
143
+ createAutocomplete('#user', {
144
+ source: (query, { signal }) => api.users.search(query, { signal }),
145
+ getLabel: user => user.name,
146
+ })
147
+ ```
148
+
149
+ `filter(item, query)` replaces the local match, and `normalize(text)` replaces the accent- and case-insensitive comparison used by the filter and the highlighting.
150
+
151
+ ### Any endpoint, any response
152
+
153
+ `endpoint` is a URL or a function of the query. `queryParam` names the query-string key (`q` by default; `null` when the function builds the complete URL). `requestInit` adds headers or credentials, `parseResponse` replaces JSON parsing, and `mapResponse` returns the suggestion array.
154
+
155
+ ```js
156
+ createAutocomplete('#city', {
157
+ endpoint: query => `/api/search?term=${encodeURIComponent(query)}`,
158
+ queryParam: null,
159
+ requestInit: { headers: { Authorization: `Bearer ${token}` } },
160
+ mapResponse: payload => payload.data.items,
161
+ getLabel: item => item.title,
162
+ })
163
+ ```
164
+
165
+ ### Caching
166
+
167
+ Function and endpoint results are cached per query: up to 50 queries for five minutes, least recently used first out. Failures are never cached.
168
+
169
+ ```js
170
+ createAutocomplete('#city', { endpoint: '/api/cities', cache: { max: 100, ttl: 60_000 } })
171
+ createAutocomplete('#stock', { endpoint: '/api/stock', cache: false })
172
+ ```
173
+
174
+ Call `controller.clearCache()` after the data changes. `autocomplete:load` reports `cached: true` for cache hits.
175
+
176
+ ### Highlighting and custom options
177
+
178
+ Each label is split into matching and non-matching parts and rendered with `<mark data-autocomplete-highlight>`; set `highlight: false` to render plain text. `renderOption(element, item, context)` receives `{ query, index, label, highlight }` to append your own DOM nodes, never HTML strings.
179
+
180
+ ```js
181
+ import { createAutocomplete, renderHighlight } from '@samline/autocomplete'
182
+
183
+ createAutocomplete('#city', {
184
+ endpoint: '/api/cities',
185
+ renderOption: (option, city, { highlight }) => {
186
+ option.replaceChildren()
187
+ const name = document.createElement('strong')
188
+ renderHighlight(name, highlight)
189
+ const country = document.createElement('small')
190
+ country.textContent = city.country
191
+ option.append(name, country)
192
+ },
193
+ })
194
+ ```
195
+
196
+ `highlight(text, query)`, `filterSuggestions(items, query, { getText })` and `normalizeText(text)` are exported for your own rendering and filtering.
197
+
198
+ ### An accessible combobox
199
+
200
+ ARIA `combobox` and `listbox` roles, `aria-expanded`, `aria-activedescendant` and a labelled listbox, and ArrowUp, ArrowDown, Home, End, Enter, Escape and Tab. Options are non-focusable `role="option"` elements. Loading, empty and error states are shown outside the listbox, and results, empty and error messages are announced through a polite live region. Searches wait for IME composition to finish.
201
+
202
+ Every message is a string or a function of `{ query, count }`:
203
+
204
+ ```js
205
+ createAutocomplete('#ciudad', {
206
+ endpoint: '/api/ciudades',
207
+ messages: {
208
+ loading: 'Buscando…',
209
+ empty: ({ query }) => `Sin resultados para «${query}»`,
210
+ error: 'La búsqueda falló',
211
+ results: ({ count }) => (count === 1 ? '1 resultado' : `${count} resultados`),
212
+ },
213
+ })
214
+ ```
215
+
216
+ ### No stale results
217
+
218
+ Searches are debounced, superseded requests are aborted and late responses ignored. Closing the list (Escape, Tab, clicking outside, selecting or `close()`) cancels the pending search.
219
+
220
+ ## API at a glance
221
+
222
+ | API | Purpose |
223
+ | ---------------------------------------- | ------------------------------------------------------ |
224
+ | `createAutocomplete(input, options)` | Controller factory (`autocomplete` is an alias). |
225
+ | `search(query?)`, `close()`, `cancel()` | Run a search now, close the list, cancel pending work. |
226
+ | `clear()`, `getSelected()` | Clear input and selection, or read the selected item. |
227
+ | `clearCache()` | Forget cached results. |
228
+ | `destroy()` | Cleanup. |
229
+ | `fromEndpoint(options)` | Build a reusable endpoint source function. |
230
+ | `highlight`, `renderHighlight` | Split a label into matches, and render the parts. |
231
+ | `filterSuggestions`, `normalizeText` | The default local filter and text normalizer. |
232
+ | `createCache(options?)` | The LRU cache used per instance. |
233
+ | `mapCommonResponse`, `parseJsonResponse` | The default response mapper and parser. |
234
+ | `Autocomplete`, `browser` | Importable equivalent of `window.Autocomplete`. |
235
+
236
+ The controller also exposes `element` (the input), `popupElement`, `listElement` (the listbox), `statusElement`, `liveElement` and `options`.
237
+
238
+ ### Entrypoints
239
+
240
+ | Entrypoint | When to use |
241
+ | -------------------------------------- | ------------------------------------------------------------- |
242
+ | `@samline/autocomplete` | ESM or CommonJS: everything below, side-effect free. |
243
+ | `@samline/autocomplete/core` | DOM-free helpers: sources, cache, filtering, highlighting. |
244
+ | `@samline/autocomplete/vanilla` | The DOM factory and `renderHighlight`. |
245
+ | `@samline/autocomplete/browser` | The registry as a module (`Autocomplete`, `newAutocomplete`). |
246
+ | `@samline/autocomplete/browser/global` | Standalone script (IIFE) that defines `window.Autocomplete`. |
247
+ | `@samline/autocomplete/styles.css` | Optional base stylesheet (also `style.css`). |
248
+
249
+ ### Events
250
+
251
+ All events bubble from the input.
252
+
253
+ | Event | `detail` |
254
+ | ------------------------ | -------------------------------- |
255
+ | `autocomplete:loadstart` | `{ query }` |
256
+ | `autocomplete:load` | `{ query, suggestions, cached }` |
257
+ | `autocomplete:error` | `{ query, error }` |
258
+ | `autocomplete:select` | `{ suggestion, label, value }` |
259
+ | `autocomplete:clear` | `{ query }` |
260
+
261
+ ```js
262
+ const input = document.querySelector('#city')
263
+ const hidden = document.querySelector('#city-id')
264
+
265
+ input.addEventListener('autocomplete:select', event => {
266
+ hidden.value = event.detail.suggestion.id
267
+ })
268
+ input.addEventListener('autocomplete:clear', () => (hidden.value = ''))
269
+ ```
270
+
271
+ ### One lifecycle
272
+
273
+ - Each `createAutocomplete()` call owns one input. Keep the returned controller.
274
+ - `close()` and `cancel()` keep the controller usable; `clear()` also empties the input and dispatches `autocomplete:clear` when something was selected.
275
+ - `destroy()` aborts pending work, removes the list and listeners, and restores the input attributes. Repeated calls are harmless.
276
+ - With the registry, `newAutocomplete()` on an id that is already registered destroys the previous controller first, and a direct `destroy()` also unregisters it.
277
+
278
+ ### TypeScript
279
+
280
+ The package includes declarations. Pass your suggestion type to `createAutocomplete<T>()` to type `getLabel`, `onSelect`, `renderOption` and `getSelected()`. `AutocompleteOptions<T>`, `AutocompleteController<T>` and the event detail types are exported; see the [API reference](https://samline.github.io/autocomplete/docs/reference/api/#types).
281
+
282
+ ## Documentation
283
+
284
+ Read the [documentation](https://samline.github.io/autocomplete/docs/) for the full guides and API contracts, and explore [working examples](https://samline.github.io/autocomplete/examples/) with complete and separate source files.
285
+
286
+ | Guide | What it covers |
287
+ | ---------------------------------------------------------------------------------- | -------------------------------------------------------- |
288
+ | [Installation](https://samline.github.io/autocomplete/docs/getting-started/) | Package / ESM, HTML / CDN, frameworks and starter files. |
289
+ | [Examples](https://samline.github.io/autocomplete/docs/guides/examples/) | Live previews with their complete, copyable source. |
290
+ | [Options](https://samline.github.io/autocomplete/docs/reference/configuration/) | Every option and its default. |
291
+ | [API reference](https://samline.github.io/autocomplete/docs/reference/api/) | The controller, helpers, browser global, events, types. |
292
+ | [Accessibility](https://samline.github.io/autocomplete/docs/guides/accessibility/) | What the combobox provides and what your page provides. |
293
+ | [Styling](https://samline.github.io/autocomplete/docs/guides/styling/) | The DOM contract and the custom properties. |
294
+
295
+ ## Changelog
296
+
297
+ Read [CHANGELOG.md](CHANGELOG.md) or the [published changelog](https://samline.github.io/autocomplete/docs/changelog/) for release history and explicitly marked breaking and behavior changes. Review the notes before upgrading.
298
+
299
+ ## AI agent skill
300
+
301
+ The [Autocomplete skill](https://samline.github.io/autocomplete/skills/autocomplete/SKILL.md) teaches verified package integration. Its maintained [repository source](skills/autocomplete/SKILL.md) and website download are the same file. Verify the installed package version before applying its guidance.
302
+
303
+ Download [SKILL.md](https://samline.github.io/autocomplete/skills/autocomplete/SKILL.md) into an `autocomplete/` folder in your agent's supported skill directory. For agents that discover project skills from `.agents/skills/`:
304
+
305
+ ```sh
306
+ mkdir -p .agents/skills/autocomplete
307
+ curl --fail --location https://samline.github.io/autocomplete/skills/autocomplete/SKILL.md \
308
+ --output .agents/skills/autocomplete/SKILL.md
309
+ ```
310
+
311
+ When working from this repository, copy `skills/autocomplete/SKILL.md` instead. Keep the filename `SKILL.md`; discovery paths and invocation syntax depend on the agent.
312
+
313
+ ## License
314
+
315
+ MIT — [LICENSE.md](LICENSE.md).