@mikedown/core 0.2.0 → 0.4.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.
- package/CHANGELOG.md +19 -0
- package/README.md +121 -2
- package/dist/ai/engines-page.d.ts +137 -0
- package/dist/ai/engines-page.js +11 -0
- package/dist/ai/engines-page.js.map +1 -0
- package/dist/ai/index.d.ts +2722 -0
- package/dist/ai/index.js +684 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai-ui-QFYFN73D.js +6397 -0
- package/dist/ai-ui-QFYFN73D.js.map +1 -0
- package/dist/chunk-APPBNQEY.js +216 -0
- package/dist/chunk-APPBNQEY.js.map +1 -0
- package/dist/chunk-DWXGWVA3.js +5748 -0
- package/dist/chunk-DWXGWVA3.js.map +1 -0
- package/dist/chunk-GWCRPPCX.js +18 -0
- package/dist/chunk-GWCRPPCX.js.map +1 -0
- package/dist/chunk-IWCXWUWW.js +6958 -0
- package/dist/chunk-IWCXWUWW.js.map +1 -0
- package/dist/chunk-L4FO63DF.js +113 -0
- package/dist/chunk-L4FO63DF.js.map +1 -0
- package/dist/chunk-N4N54LK2.js +39 -0
- package/dist/chunk-N4N54LK2.js.map +1 -0
- package/dist/chunk-QWKT57TR.js +62 -0
- package/dist/chunk-QWKT57TR.js.map +1 -0
- package/dist/chunk-TSP7BAV3.js +22 -0
- package/dist/chunk-TSP7BAV3.js.map +1 -0
- package/dist/index.d.ts +19 -463
- package/dist/index.js +7717 -2103
- package/dist/index.js.map +1 -1
- package/dist/schema-DVfssxQX.d.ts +100 -0
- package/dist/shared/anchoring.js +4 -16
- package/dist/shared/anchoring.js.map +1 -1
- package/dist/shared/imagePaste.js +3 -57
- package/dist/shared/imagePaste.js.map +1 -1
- package/dist/shared/sha1.js +3 -57
- package/dist/shared/sha1.js.map +1 -1
- package/dist/shared/wordCount.js +4 -12
- package/dist/shared/wordCount.js.map +1 -1
- package/dist/styles.css +4562 -108
- package/dist/types-2TZErbJr.d.ts +619 -0
- package/dist/types-DO8UBybZ.d.ts +741 -0
- package/package.json +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
- New `ai/docs/` module (public through `@mikedown/core/ai`): the documentation base model, home document precedence, link graph, keyword fallback, secrets scan, citations and the navigation loop. Hosts provide `host.docs` (`MikeDownDocsHost`) to back it; without it the chat shows "This document" only.
|
|
6
|
+
- `@mikedown/core/ai` adds the `chat` feature (status `available`), the `docs` task, the `docsBase` value of `AiSendsScope` and an optional `enabled` flag per base.
|
|
7
|
+
- `@mikedown/core` exports the chat panel (`ai-chat-panel.ts`), the documentation bases page (`ai-docs-page.ts`) and the run wiring (`ai-docs-run.ts`) through the AI UI, loaded only when the host has `host.ai`.
|
|
8
|
+
- Run requests can be pinned to one engine and model (`AiRunRequest.pin`). A pinned run never re-routes or falls back within the turn.
|
|
9
|
+
- Inline suggestions: `ai-ghost.ts`, `ai-ghost-plugin.ts` and `ai-ghost-session.ts` in the AI UI, with `ghostContext`, `ghostTrim` and the `continue` prompt in `@mikedown/core/ai`. New `ghostText` feature id and `cursor` consent scope.
|
|
10
|
+
- AI Activity panel: an opt-in, in-memory record of each AI request (`ai-activity.ts`, `ai-activity-panel.ts`), with an optional `saveTextFile` on the host.
|
|
11
|
+
- Insert from chat goes through an allow-list of node and mark types (`ai-insert-guard.ts`).
|
|
12
|
+
- A bare URL at the end of a document's first block is no longer turned into a link on load.
|
|
13
|
+
|
|
14
|
+
## 0.3.0
|
|
15
|
+
|
|
16
|
+
- New prompt modules under `ai/prompts/` (`rewrite`, `explain`, `structureCheck`, `summary`, `title`, `properties`) for the AI writing features.
|
|
17
|
+
- `ai/json.ts` parses model JSON leniently and makes one repair retry before reporting `badOutput`. `ai/documentBudget.ts` takes sections from the top of a long document and reports the coverage. `ai-prefs.ts` stores the per-session AI preferences.
|
|
18
|
+
- `AiCompletionRequest.requestOverrides` carries per-request body fields (for example `reasoning_effort`). Hosts merge them over the model's configured overrides, so the request wins. Tier 1 hosts may ignore them.
|
|
19
|
+
- The `summarize` and `structure` tasks now require chat only; `json` and `context` are preferences for them. There is a new `title` feature id, and a `badOutput` error code.
|
|
20
|
+
- The rewrite popover gained modes for insert and choose, used by the summary and title commands.
|
|
21
|
+
|
|
3
22
|
## 0.2.0
|
|
4
23
|
|
|
5
24
|
- `bindMikeDownValue` (`@mikedown/core/binding`): the framework-neutral value binding the React, Vue, Angular and web component wrappers are built on (pristine writes, debounced change, flush on blur, read-only, disabled and touched state).
|
package/README.md
CHANGED
|
@@ -86,11 +86,127 @@ field.destroy(); // flushes, then removes observers and listeners
|
|
|
86
86
|
| `onHeadingRenamed`, `onHeadingRenameAmbiguous` | no rename callbacks |
|
|
87
87
|
| `exportHtml`, `printDocument`, `viewInBrowser` | export buttons hidden |
|
|
88
88
|
| `sidebarPrefs` | sidebar keeps in-memory defaults |
|
|
89
|
+
| `ai` | no AI features, no AI tab (see [Bring your own AI](#bring-your-own-ai)) |
|
|
89
90
|
|
|
90
91
|
Request and response methods return Promises. For example `uploadImage(file)` receives `{ mime, bytes, name }` and resolves `{ src, alt }`.
|
|
91
92
|
|
|
92
93
|
The returned `MikeDownEditorHandle` takes pushes from the host: `setMarkdown`, `markSaved`, `updateSettings`, `setReadOnly`, `setTags`, `setBacklinks`, `setDocMeta`, `scrollToAnchor`, `getHtml`, `command(name)` and more. `handle.on('ready' | ...)` subscribes to events. All types are exported from the package root.
|
|
93
94
|
|
|
95
|
+
## Bring your own AI
|
|
96
|
+
|
|
97
|
+
`host.ai` turns on the editor's AI features (selection rewrite today, more later) and an AI tab in the Settings modal. Leave it out and nothing AI shows. **`@mikedown/core` ships no provider SDK and makes no AI network calls of its own.** Your `host.ai` does the transport; `@mikedown/core/ai` holds only pure helpers (settings schema, router, request builders, stream parsers) you may use or ignore.
|
|
98
|
+
|
|
99
|
+
There are two tiers. Pick by how much of the engine setup you want the editor to own.
|
|
100
|
+
|
|
101
|
+
**Tier 1: one method.** Implement `complete` and proxy it to your backend. Your server picks the model, holds the keys and decides what may leave your network. The editor shows the on/off switch and the feature toggles in Settings, but no engine list.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { createMikeDownEditor, type MikeDownAiHost } from '@mikedown/core';
|
|
105
|
+
|
|
106
|
+
const ai: MikeDownAiHost = {
|
|
107
|
+
async complete(req, onToken, signal) {
|
|
108
|
+
const res = await fetch('/api/ai/complete', {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: { 'Content-Type': 'application/json' },
|
|
111
|
+
// Image parts carry raw bytes; encode them first (bytesToBase64 from '@mikedown/core/ai') if you forward them.
|
|
112
|
+
body: JSON.stringify({ feature: req.feature, task: req.task, messages: req.messages, maxTokens: req.maxTokens }),
|
|
113
|
+
signal,
|
|
114
|
+
});
|
|
115
|
+
if (!res.ok) throw { code: res.status === 429 ? 'rateLimited' : 'unknown', message: await res.text() };
|
|
116
|
+
// This backend streams plain text. Rejecting with an AbortError (or aborting `signal`) cancels cleanly.
|
|
117
|
+
const reader = res.body!.getReader();
|
|
118
|
+
const decoder = new TextDecoder();
|
|
119
|
+
let text = '';
|
|
120
|
+
for (;;) {
|
|
121
|
+
const { done, value } = await reader.read();
|
|
122
|
+
if (done) break;
|
|
123
|
+
const delta = decoder.decode(value, { stream: true });
|
|
124
|
+
text += delta;
|
|
125
|
+
onToken(delta);
|
|
126
|
+
}
|
|
127
|
+
return { text, served: { engineName: 'Our AI service', modelId: 'server-chosen', isLocal: false }, finishReason: 'stop' };
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
createMikeDownEditor(el, { host: { onChange, ai } });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Tier 2: an engine registry.** Add `listEngines` (and optionally `testEngine`, `discoverModels`, `setSecret`, `requestCloudConsent`) and the editor shows the full AI tab: engines, models, capabilities and per-task routing. Core resolves which engine and model serves each request and passes it as `req.route`; your host sends it. The example calls a local Ollama from the browser, which suits development (start Ollama with `OLLAMA_ORIGINS` set to your dev origin so the browser may call it; in production, send these calls through your server).
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { createMikeDownEditor, type MikeDownAiHost } from '@mikedown/core';
|
|
138
|
+
import {
|
|
139
|
+
aiErrorCodeFromHttp, buildAuthHeaders, buildCompletionBody, completeCapabilities, createCompletionStreamReader,
|
|
140
|
+
engineEndpoints, makeAiError, parseAiSettings, parseOllamaTags, type AiEngineStatus,
|
|
141
|
+
} from '@mikedown/core/ai';
|
|
142
|
+
|
|
143
|
+
const settings = parseAiSettings({
|
|
144
|
+
enabled: true,
|
|
145
|
+
engines: [{ id: 'ollama', name: 'Ollama (dev)', kind: 'ollama', baseUrl: 'http://127.0.0.1:11434/v1', models: [{ id: 'qwen3:8b' }] }],
|
|
146
|
+
routing: { default: { engineId: 'ollama', modelId: 'qwen3:8b' }, fallback: 'none', tasks: {} },
|
|
147
|
+
});
|
|
148
|
+
const engine = settings.engines[0];
|
|
149
|
+
const urls = engineEndpoints(engine);
|
|
150
|
+
|
|
151
|
+
async function probe(): Promise<AiEngineStatus> {
|
|
152
|
+
const started = performance.now();
|
|
153
|
+
try {
|
|
154
|
+
const res = await fetch(urls.nativeModels!);
|
|
155
|
+
if (!res.ok) throw makeAiError(aiErrorCodeFromHttp(res.status));
|
|
156
|
+
const ids = parseOllamaTags(await res.json());
|
|
157
|
+
return {
|
|
158
|
+
engineId: engine.id, ok: true, isLocal: true, hasKey: false, latencyMs: Math.round(performance.now() - started),
|
|
159
|
+
models: ids.map((id) => ({ id, capabilities: completeCapabilities({}, id, engine.kind), source: 'heuristic' as const })),
|
|
160
|
+
};
|
|
161
|
+
} catch (err) {
|
|
162
|
+
return { engineId: engine.id, ok: false, isLocal: true, hasKey: false, error: err instanceof Error ? err.message : 'Ollama is not reachable', models: [] };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const ai: MikeDownAiHost = {
|
|
167
|
+
async complete(req, onToken, signal) {
|
|
168
|
+
const model = engine.models.find((m) => m.id === req.route?.modelId) ?? engine.models[0];
|
|
169
|
+
const res = await fetch(urls.completions, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: buildAuthHeaders(engine.kind, null),
|
|
172
|
+
body: JSON.stringify(buildCompletionBody(engine.kind, model, req)),
|
|
173
|
+
signal,
|
|
174
|
+
});
|
|
175
|
+
if (!res.ok) throw makeAiError(aiErrorCodeFromHttp(res.status, await res.text()));
|
|
176
|
+
const stream = createCompletionStreamReader(engine.kind);
|
|
177
|
+
const reader = res.body!.getReader();
|
|
178
|
+
const decoder = new TextDecoder();
|
|
179
|
+
for (;;) {
|
|
180
|
+
const { done, value } = await reader.read();
|
|
181
|
+
if (done) break;
|
|
182
|
+
for (const delta of stream.push(decoder.decode(value, { stream: true }))) onToken(delta);
|
|
183
|
+
}
|
|
184
|
+
const out = stream.finish();
|
|
185
|
+
return {
|
|
186
|
+
text: out.text, usage: out.usage, finishReason: out.finishReason,
|
|
187
|
+
served: { engineId: engine.id, engineName: engine.name, modelId: model.id, isLocal: true },
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
listEngines: async () => [await probe()],
|
|
191
|
+
testEngine: probe,
|
|
192
|
+
discoverModels: probe,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
createMikeDownEditor(el, { host: { onChange, ai, saveSettings /* persists the ai.* keys */ }, settings: { ai: settings } });
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Consent.** Cloud engines are off until the user turns on *Allow cloud engines* in the AI tab. Even then, in tier 2 the first request a cloud engine would serve calls your `requestCloudConsent(engineId)`. Show your own dialog naming the engine, its URL and what is sent (the selection and one paragraph for rewrite; `aiConsentText` in `@mikedown/core/ai` has the words), and resolve `true` (allowed for the workspace; core remembers it for the session), `'once'` (this request only; the next one calls you again; a chat turn asks the optional `requestTurnConsent(engineId, about)` first, where it means the whole turn: each of its requests carries `req.turn`, and the optional `endTurn(turnId)` says when it is over), `false` (declined; it counts as unusable for that request, and you may answer later calls with `false` without a dialog, as VS Code and Desktop do until a restart) or `'never'` (a stored refusal; core disables the entries for that engine for the session). **A host without `requestCloudConsent` sends to cloud engines without asking** (the *Allow cloud engines* switch still applies), so implement it if users can add cloud engines. Optionally add `listConsents()` (records of `{ engineId, answer, at, scope }`) and `forgetConsent(engineId)`: the AI tab then shows a *Cloud consents* list with a Forget button for each. In tier 1 core never sees which model answers, so consent is your backend's and your UI's to handle.
|
|
199
|
+
|
|
200
|
+
**Setup wizard.** With no engines configured, the toolbar's AI button opens a setup wizard (on the AI Engines page) instead of the engine form. It uses three more optional methods, each of which just hides its part of the wizard when absent: `detectLocalServers(candidates, signal)` looks for running local servers (one GET each, 1.5 s cap, only on request, never in the background; send a key only to the preset's own address), `hardwareInfo()` reports memory, CPU and GPU for the local model size hint, and `detectHostEngines()` lists models the host itself offers without an address or key (VS Code uses it for GitHub Copilot, the `vscode-lm` engine kind). Set `shellEnv: false` if your process cannot see shell variables, so the engine form points at a key file or a pasted key instead of `apiKeyEnv`. Choosing a cloud provider in the wizard turns *Allow cloud engines* on, and AI turns on when the user finishes with a usable default model.
|
|
201
|
+
|
|
202
|
+
The wrappers pass `host.ai` through untouched: `host={{ ai }}` in React, `:host` in Vue, the `[ai]` input in Angular, and the `ai` property (properties only, no attribute) on `<mikedown-editor>`. Wrapper docs list the exact binding. The [developers hub](https://www.iadev.net/mikedown/developers/#byo-ai) has a live demo with a stub host that streams canned text.
|
|
203
|
+
|
|
204
|
+
### Feature ids and request overrides
|
|
205
|
+
|
|
206
|
+
Each AI feature has an id, and `host.ai` receives requests tagged with it. `rewrite` covers the rewrite popover, Explain and Translate; `summary` covers `/summary` and Summarize document; `title` covers `/title` and Suggest titles; `frontmatter` covers Properties Suggest (tags, title, description); `altText` covers image alt text. The full list is in `packages/core/src/ai/features.ts`. Use the id to route or log a feature, or to turn one off in your own UI.
|
|
207
|
+
|
|
208
|
+
`AiCompletionRequest.requestOverrides` is a set of extra request body fields (for example `reasoning_effort` or `chat_template_kwargs`). Core fills it when the user changes the thinking dial in the rewrite popover, and merges it over the model's configured overrides, so the request wins. Hosts that do not support per-request fields can ignore it.
|
|
209
|
+
|
|
94
210
|
## Features
|
|
95
211
|
|
|
96
212
|
Switch UI blocks with `options.features`. Defaults shown.
|
|
@@ -107,9 +223,12 @@ Switch UI blocks with `options.features`. Defaults shown.
|
|
|
107
223
|
| `findReplace` | on | `Cmd/Ctrl+F` and `Cmd/Ctrl+H` |
|
|
108
224
|
| `frontmatter` | on | Collapsible YAML block |
|
|
109
225
|
| `supportCard` | off | VS Code only |
|
|
226
|
+
| `customizeToolbar` | on | Settings > Toolbar section (Customize, Reset). Off keeps the toolbar fixed for the user |
|
|
110
227
|
|
|
111
228
|
Also built in: tables, task lists, GFM callouts (`> [!NOTE]`), `==highlight==`, footnotes, emoji, wikilinks, code blocks with language picker.
|
|
112
229
|
|
|
230
|
+
**Toolbar layout.** Users can reorder, remove and add toolbar buttons in the editor (Settings, then Toolbar). The result is one JSON value, `settings.toolbarLayout` (`{ version, items, seen }`, typed `ToolbarLayout`). Pass it in `settings` to preset or restore a layout, and store the value your `host.saveSettings` receives; `null` means Reset to Default, and an absent or invalid value shows the default toolbar. Set `features.customizeToolbar: false` to hide the customize controls; a `toolbarLayout` you pass still applies. `ToolbarLayout`, `ToolbarItemId`, `TOOLBAR_ITEM_IDS`, `DEFAULT_TOOLBAR_LAYOUT` and `normalizeToolbarLayout` are exported from `@mikedown/core`.
|
|
231
|
+
|
|
113
232
|
## Theming
|
|
114
233
|
|
|
115
234
|
Colors, fonts and radii come only from `--mikedown-*` custom properties, with light and dark defaults in `@mikedown/core/tokens.css` (already included in `styles.css`). Every selector is scoped under `.mikedown-root` and `.mikedown-portal`, so the stylesheet cannot restyle your page. Set `theme: 'light' | 'dark' | 'auto'` or call `handle.setTheme()`.
|
|
@@ -130,7 +249,7 @@ Without `spellcheckDictionaryUrl`, spell check stays off and nothing is fetched.
|
|
|
130
249
|
|
|
131
250
|
## Shortcuts
|
|
132
251
|
|
|
133
|
-
The core binds `Mod-/` (Cmd on macOS, Ctrl elsewhere) to the source toggle in both the rich editor and source mode. A host that binds the shortcut itself, such as the VS Code keybinding, passes `hostOwnsShortcuts: true` so one keystroke never toggles twice.
|
|
252
|
+
The core binds `Mod-/` (Cmd on macOS, Ctrl elsewhere) to the source toggle in both the rich editor and source mode. A host that binds the shortcut itself, such as the VS Code keybinding, passes `hostOwnsShortcuts: true` so one keystroke never toggles twice. The same goes for `Mod-Alt-K`, which opens the AI rewrite popover when the host has an `ai` group (VS Code binds it as `mikedown.ai.rewrite`).
|
|
134
253
|
|
|
135
254
|
## Peer dependencies
|
|
136
255
|
|
|
@@ -197,7 +316,7 @@ Current Chrome, Edge, Firefox and Safari (ES2020 output, ESM only).
|
|
|
197
316
|
|
|
198
317
|
## Privacy
|
|
199
318
|
|
|
200
|
-
No telemetry. The editor makes no network calls except the ones you configure: spell check dictionaries (when `spellcheckDictionaryUrl` is set), your `host` callbacks, and the lazy `import()` of KaTeX and Mermaid from your own bundle.
|
|
319
|
+
No telemetry. The editor makes no network calls except the ones you configure: spell check dictionaries (when `spellcheckDictionaryUrl` is set), your `host` callbacks (including `host.ai`, which is the only way AI requests leave the page), and the lazy `import()` of KaTeX and Mermaid from your own bundle.
|
|
201
320
|
|
|
202
321
|
## Links
|
|
203
322
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { MikeDownAiHost, AiSettings, AiEngineStatus, MikeDownDocsHost } from './index.js';
|
|
2
|
+
import { AiSettingsPatch } from './index.js';
|
|
3
|
+
import { MikeDownSettingsSectionContext } from '../index.js';
|
|
4
|
+
import '@tiptap/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One editing session over the AI settings, shared by the Settings modal's AI
|
|
8
|
+
* tab (`ai-settings.ts`) and the AI Engines page (`ai-engines-page.ts`): the
|
|
9
|
+
* draft, the save patch, and the bookkeeping that keeps API keys and early
|
|
10
|
+
* saves honest. No DOM; each view owns its own rendering and announcements.
|
|
11
|
+
*
|
|
12
|
+
* Everything edits a draft copy of the settings; `collect` gives only the
|
|
13
|
+
* `ai.*` keys that changed. API keys never touch the draft: they go through
|
|
14
|
+
* `host.ai.setSecret` as soon as a field settles, and a deleted engine's key
|
|
15
|
+
* is dropped on `commit`. Test connection and fetching models need the host
|
|
16
|
+
* to know the engine, so `ensureSaved` saves the engines first and waits for
|
|
17
|
+
* the host's settings echo. `discard` takes back engines added in this
|
|
18
|
+
* session that reached the host that way, and their keys.
|
|
19
|
+
*
|
|
20
|
+
* The page opened from the tab runs a child session (`fork`): it starts from
|
|
21
|
+
* the tab's draft, shares what the session knows about the host (statuses,
|
|
22
|
+
* stored keys), and on Done the tab `absorb`s the saved result.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
interface AiSettingsSessionOptions {
|
|
26
|
+
ai: MikeDownAiHost;
|
|
27
|
+
/** The settings the session starts from (the host's, or a parent session's draft). */
|
|
28
|
+
settings: AiSettings;
|
|
29
|
+
/** Last known engine statuses. */
|
|
30
|
+
statuses: readonly AiEngineStatus[];
|
|
31
|
+
/** The host's settings now (they change when the session saves engines before a test). */
|
|
32
|
+
getHostSettings(): AiSettings;
|
|
33
|
+
/** Persist an AI patch right away. Absent when the host cannot persist settings. */
|
|
34
|
+
saveNow?(patch: AiSettingsPatch): void;
|
|
35
|
+
/** Resolves with the host's next settings `accept` likes, or null after `timeoutMs`. */
|
|
36
|
+
waitForSettings(accept: (s: AiSettings) => boolean, timeoutMs: number): Promise<AiSettings | null>;
|
|
37
|
+
/** Fresh statuses (list, test, discover) for the editor's cache and the indicator. */
|
|
38
|
+
onStatuses(statuses: AiEngineStatus[]): void;
|
|
39
|
+
/** Statuses that arrive without the view asking (a host push, a settings refresh). Returns an unsubscribe. */
|
|
40
|
+
subscribeStatuses?(listener: (statuses: AiEngineStatus[]) => void): () => void;
|
|
41
|
+
/**
|
|
42
|
+
* A child session opened while the parent's "Enable AI features" is ticked
|
|
43
|
+
* but not saved: when this session saves anything, it saves
|
|
44
|
+
* `ai.enabled: true` with it, so finishing on the Engines page keeps the
|
|
45
|
+
* tick (Q2).
|
|
46
|
+
*/
|
|
47
|
+
pendingEnable?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The AI Engines page (M3c): engines and routing on a full-size page of
|
|
52
|
+
* their own, laid out like VS Code's Settings editor or the Network pane of
|
|
53
|
+
* Apple's System Settings. A header with Back and Done; on the left a quiet
|
|
54
|
+
* list of engines, then Tasks (which model does what), then Add engine; on
|
|
55
|
+
* the right the selected engine's Express form (`ai-engine-form.ts`), the
|
|
56
|
+
* Tasks section (`ai-routing-section.ts`) or the quick-start cards. Under 720 px the page
|
|
57
|
+
* is one column: the list first, and picking an entry pushes its detail,
|
|
58
|
+
* with Back returning to the list.
|
|
59
|
+
*
|
|
60
|
+
* Standalone and mountable: it renders into the container it is given and
|
|
61
|
+
* touches nothing outside it (no modal, no editor, no `document.body`), so a
|
|
62
|
+
* host can show it as an overlay (`editor.ts#showAiEnginesPage`) or, later,
|
|
63
|
+
* in its own editor tab or window. Dialog semantics, the focus trap and
|
|
64
|
+
* focus restore belong to whoever hosts it.
|
|
65
|
+
*
|
|
66
|
+
* Edits run in an `AiSettingsSession` (`ai-settings-session.ts`): Done hands
|
|
67
|
+
* the changed `ai.*` keys to `onDone`; Back with unsaved changes asks
|
|
68
|
+
* "Discard changes?" in the page, and discarding takes back engines added
|
|
69
|
+
* here and their keys before `onCancel`. Opened by the first-run panel's
|
|
70
|
+
* "Set up" (`turnOnWhenDone`), the header says AI turns on at Done, and Done
|
|
71
|
+
* adds `ai.enabled: true` when the result has a usable default route; Back
|
|
72
|
+
* leaves AI off.
|
|
73
|
+
*
|
|
74
|
+
* On a host that can look for local servers (`host.ai.detectLocalServers`),
|
|
75
|
+
* the quick-start cards look when they first show and on "Look again": a
|
|
76
|
+
* local card says Running · 3 models (and leads), Not running, or Added
|
|
77
|
+
* (it opens the engine already set up there). Without the method the cards
|
|
78
|
+
* are the plain list.
|
|
79
|
+
*
|
|
80
|
+
* The cloud cards carry the **Allow cloud engines** switch, one line on what
|
|
81
|
+
* it means and the privacy card folded under "What this means"; it edits the
|
|
82
|
+
* page's draft, so Done saves it with the rest. A cloud engine's head, while
|
|
83
|
+
* the switch is off, says so with a "Turn on cloud engines" button (F4). On
|
|
84
|
+
* VS Code, a "Built into VS Code" group offers GitHub Copilot when the host
|
|
85
|
+
* reports a Copilot model (`detectHostEngines`).
|
|
86
|
+
*
|
|
87
|
+
* Opened on the `'wizard'` section (the first-run panel's "Set up" with no
|
|
88
|
+
* engines yet, tier 2 only), the page shows the setup wizard
|
|
89
|
+
* (`ai-setup-wizard.ts`) instead of the list and detail: the header says
|
|
90
|
+
* "Set up AI" with the step dots and Skip, Back walks back through the
|
|
91
|
+
* steps, and the wizard's Done is the page's Done. "Change settings in AI Engines"
|
|
92
|
+
* leaves the wizard for the full page, in the same session.
|
|
93
|
+
*
|
|
94
|
+
* On a host with `host.docs` the list also has Documentation bases
|
|
95
|
+
* (`ai-docs-page.ts`), the `'bases'` section. A base saves at once through the
|
|
96
|
+
* host; only the bases' advanced options wait for Done.
|
|
97
|
+
*
|
|
98
|
+
* Modal UI only: nothing here touches the editor document or its DOM.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
type AiEnginesPageSection = 'engines' | 'routing' | 'wizard' | 'bases';
|
|
102
|
+
interface AiEnginesPageOptions extends AiSettingsSessionOptions {
|
|
103
|
+
/**
|
|
104
|
+
* What to show first: an engine, the routing section, the documentation
|
|
105
|
+
* bases (with `docs`) or the setup wizard (tier 2 only). Default: the first
|
|
106
|
+
* engine (the cards when there is none).
|
|
107
|
+
*/
|
|
108
|
+
initial?: {
|
|
109
|
+
engineId?: string;
|
|
110
|
+
section?: AiEnginesPageSection;
|
|
111
|
+
};
|
|
112
|
+
/** Shared with the session that opened the page (stored-key knowledge). */
|
|
113
|
+
keyOverride?: Map<string, boolean>;
|
|
114
|
+
/** Shared with the session that opened the page (engine statuses). */
|
|
115
|
+
statusMap?: Map<string, AiEngineStatus>;
|
|
116
|
+
/** Done: the `ai.*` keys that changed (possibly none) and the settings they lead to. */
|
|
117
|
+
onDone(patch: AiSettingsPatch, settings: AiSettings): void;
|
|
118
|
+
/** Back without saving; the page already took back what it added. */
|
|
119
|
+
onCancel(): void;
|
|
120
|
+
/**
|
|
121
|
+
* Opened to set AI up while it is off: Done also turns AI on (`ai.enabled`
|
|
122
|
+
* in the patch) when the result has a usable default route.
|
|
123
|
+
*/
|
|
124
|
+
turnOnWhenDone?: boolean;
|
|
125
|
+
/** The host's documentation bases. Absent: no Documentation bases section. */
|
|
126
|
+
docs?: MikeDownDocsHost;
|
|
127
|
+
}
|
|
128
|
+
interface AiEnginesPageHandle {
|
|
129
|
+
/** Tear down (timers, listeners) and leave the container empty. Unresolved changes are discarded. */
|
|
130
|
+
dispose(): void;
|
|
131
|
+
/** Focus where a keyboard user should land: the selected list entry, or the detail when it was pushed. */
|
|
132
|
+
focus(): void;
|
|
133
|
+
}
|
|
134
|
+
declare function mountAiEnginesPage(container: HTMLElement, ctx: MikeDownSettingsSectionContext, opts: AiEnginesPageOptions): AiEnginesPageHandle;
|
|
135
|
+
|
|
136
|
+
export { mountAiEnginesPage };
|
|
137
|
+
export type { AiEnginesPageHandle, AiEnginesPageOptions, AiEnginesPageSection };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mountAiEnginesPage
|
|
3
|
+
} from "../chunk-DWXGWVA3.js";
|
|
4
|
+
import "../chunk-N4N54LK2.js";
|
|
5
|
+
import "../chunk-IWCXWUWW.js";
|
|
6
|
+
import "../chunk-APPBNQEY.js";
|
|
7
|
+
import "../chunk-TSP7BAV3.js";
|
|
8
|
+
export {
|
|
9
|
+
mountAiEnginesPage
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=engines-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|