@intentic/extension-ui 1.309.0 → 1.311.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/README.md CHANGED
@@ -1,58 +1,36 @@
1
- # @intentic/extension-ui
1
+ # extension-ui
2
2
 
3
- The UI kit an extension renders with, so its views look like the app rather than like a website.
3
+ The UI kit extensions render with: a curated slice of the editor's design system that the host supplies at runtime, so extension views use the shell's own component instances.
4
4
 
5
- A curated slice of the app design system ([`@intentic/ui`](../../_editor/ui)) plus the PrimeVue primitives extension views
6
- actually use. One of the two packages an extension may depend on (with
7
- [`@intentic/extension-api`](../../_shared/extension-api)).
8
-
9
- ## Host-provided at runtime
10
-
11
- This package's [`src/index.ts`](src/index.ts) is its one public surface (the repo's re-export exception). The
12
- kit is **host-provided**: the web app maps this module into its import map
13
- ([extension-host/hostModules.ts](../../_editor/web/src/extension-host/hostModules.ts)), so a third-party bundle
14
- that marks it external resolves to the **shell's own** component instances and theming: one Vue, one
15
- PrimeVue, one theme across the host and every extension. In-repo builtin extensions bundle this same module
16
- and land on the same instances.
17
-
18
- The scope reads oddly (an `@intentic/*` package depending on the app-side `@intentic/ui`) but it is
19
- deliberate: the dependency is build-time-only (for in-repo builtins); at runtime the import map supplies the
20
- shell's instances, so no second copy is shipped.
21
-
22
- ## Drift assertion
5
+ ```mermaid
6
+ flowchart LR
7
+ ui["_editor/ui<br/>design system"] -- "re-exported by src/" --> kit(["extension-ui"])
8
+ kit -- "compiled into" --> host["Editor<br/>hostModules.ts"]
9
+ bundle["Extension bundle"] -- "import map" --> shim["/ext-shims/extension-ui.js"]
10
+ shim -- "globalThis.__intenticHost" --> host
11
+ ```
23
12
 
24
- Export names are mirrored in [`names.mjs`](names.mjs), which drives shim generation and a drift assertion:
25
- keep the two in sync when adding or removing an export. Publishing a typed npm artifact for out-of-repo
26
- authors is a marketplace-phase task.
13
+ - `src/index.ts` re-exports chosen components and helpers from `@intentic/ui` (`_editor/ui`) plus the PrimeVue
14
+ primitives extension views use. Nothing is reimplemented, so an extension view looks and behaves like the shell
15
+ around it. This dependency on `_editor/ui` is a recorded exception to the [`_shared/` boundary](../README.md).
16
+ - At runtime the host supplies the kit: `hostModules.ts` publishes the editor's own module instances on
17
+ `globalThis.__intenticHost`, and the import map in the editor's `index.html` resolves `@intentic/extension-ui` to a
18
+ shim that reads them. A second copy would render unthemed, outside the app's reactivity and its query cache.
19
+ - `scripts/build.mjs` compiles the published package from `_editor/ui`'s sources: declarations pruned to what the kit
20
+ re-exports, and a `dist/index.js` bridge that throws when loaded outside an intentic host.
21
+ - `names.mjs` lists the runtime export names by hand, because the `.vue` graph cannot load in Node. The editor's shim
22
+ generator reads it, and a dev-time assertion in `hostModules.ts` catches drift.
23
+ - `./diff`, `./format` and `./i18n` skip the component barrel, for extension tests that run without a Vue compiler.
27
24
 
28
25
  ## Key files
29
26
 
30
- - [src/index.ts](src/index.ts), the whole surface: which components and helpers an extension may render with.
31
- - [src/format.ts](src/format.ts): the shared formatters, so two extensions render a duration the same way.
32
- - [src/i18n.ts](src/i18n.ts): the extension's words. `extensionI18n(id, base, load)` is the one call every in-repo
33
- extension's `src/i18n.ts` now makes, returning the catalog the host mounts and the translator its components read;
34
- `extensionT(id)` is that translator alone, bound to its own slice of the host's one message tree, and
35
- `registerExtensionMessages` mounts a catalog, which is what the host does before `activate` and what a test
36
- calling `activate` itself has to do instead.
37
-
38
- ## The one control worth calling out
39
-
40
- `AgentRunButton` and `useAgentRunPick` are re-exported because five extensions start an agent for the user:
41
- pipelines, deployments, maintenance, documentation, acceptance: and each had reached its own answer about how
42
- you choose what that costs. Press the primary half and the run opens on the sandbox's standing model for the job
43
- the caller named; use the caret and a panel opens on that run, ending in a bar that carries the button's own
44
- label. Both halves emit the same `run`, because both are the same act: the press that finishes configuring the
45
- run is the press that starts it.
46
-
47
- The choice covers more than the model — the account, the harness, the tier, extended thinking and speed
48
- (`AgentRunChoice`) — and every one of them is a different price. Send them on the turn you start beside `model`:
49
- the sandbox fills a pinned entry's knobs in only for a run that named no model, so dropping them runs the model
50
- you chose on the provider's defaults for everything else. `runPickOf(choice)` (from `@intentic/sandbox-contract`)
51
- translates the whole thing into the turn's own field names in one call.
27
+ - [src/index.ts](src/index.ts) — the kit: every name an extension may import, with usage notes.
28
+ - [scripts/build.mjs](scripts/build.mjs) — builds the published types and the host bridge from `_editor/ui`.
29
+ - [names.mjs](names.mjs) — the runtime export names the shims and the host check read.
30
+ - [../../_editor/web/src/extension-host/hostModules.ts](../../_editor/web/src/extension-host/hostModules.ts) — where the shell publishes its instances to extension bundles.
52
31
 
53
- `useAgentRunPick` takes `api.models` as an argument rather than importing it, which is what lets the control
54
- live in a kit that knows nothing about the extension API. Pass the extension's own host handle:
32
+ ## Commands
55
33
 
56
- ```ts
57
- const runModel = useAgentRunPick(() => host().models);
34
+ ```sh
35
+ pnpm --filter @intentic/extension-ui build
58
36
  ```
package/dist/index.js CHANGED
@@ -80,13 +80,13 @@ export const formatDateTime = m["formatDateTime"];
80
80
  export const formatDayMonth = m["formatDayMonth"];
81
81
  export const formatDayMonthTime = m["formatDayMonthTime"];
82
82
  export const formatDuration = m["formatDuration"];
83
+ export const formatOf = m["formatOf"];
83
84
  export const formatTime = m["formatTime"];
84
85
  export const formatTimestamp = m["formatTimestamp"];
85
86
  export const formatTokens = m["formatTokens"];
86
87
  export const formatWeekdayTime = m["formatWeekdayTime"];
87
88
  export const formatWhen = m["formatWhen"];
88
89
  export const freshness = m["freshness"];
89
- export const isRenderableImage = m["isRenderableImage"];
90
90
  export const noticeFrom = m["noticeFrom"];
91
91
  export const noticeOf = m["noticeOf"];
92
92
  export const openForwardedPort = m["openForwardedPort"];
@@ -103,6 +103,7 @@ export const useAsyncAction = m["useAsyncAction"];
103
103
  export const useCompact = m["useCompact"];
104
104
  export const useDevice = m["useDevice"];
105
105
  export const useKeyedDraft = m["useKeyedDraft"];
106
+ export const useLatest = m["useLatest"];
106
107
  export const useListNavigation = m["useListNavigation"];
107
108
  export const useLoadingReveal = m["useLoadingReveal"];
108
109
  export const useNarrow = m["useNarrow"];
@@ -1,4 +1,4 @@
1
- export { AgentRunButton, type AgentRunAttempt, type AgentRunChoice, type AgentRunPicker, type ModelPicking, useAgentRunPick, type FixStanceLook, fixStanceLook, AnchoredOverlay, Avatar, Button, vAction, BarChart, BottomSheet, BrandMark, Card, clipboardOf, browserOwnsClick, appLink, openForwardedPort, ChangeStatusMark, type ChangeStatus, ui, Code, CodeField, ConfirmDialog, ContextMenu, CopyButton, StatusTally, type TallyItem, DagEditor, DagGraph, type DagEdge, type DagNode, DiffStat, DisclosureRow, FilterBar, Icon, type IconName, ImageView, InfoDialog, InfoHint, InfoTable, isRenderableImage, Markdown, MarkdownDocument, MarkdownFigure, Modal, type NavGroup, NavRail, NoteEditor, type NoteDraft, type NoteDraftOptions, useNoteDraft, useKeyedDraft, type NoticeModel, type NoticeTone, type NoticeAction, Notice, NoticeStack, Page, PageAction, PageHeader, ScrollFrame, PersonaFace, type PersonaLike, Picker, ProjectChip, type PickerGroup, type PickerOption, type PickerOptions, ProgressRing, RepoRail, type RepoRailAll, type RepoRailGroup, type RepoRailRow, ProseField, ResizeSeam, ResponsiveOverlay, Row, RowGroup, SearchBar, SegmentedControl, seriesColor, sinceOf, useLoadingReveal, SkeletonRows, SplitView, StatStrip, StatusBadge, type StatusVariant, StepSection, timeWindows, type TimeWindow, timeWindowWords, useCompact, useDevice, useListNavigation, useNow, errorMessage, noticeFrom, noticeOf, useAsyncAction, useNarrow, useRailMemory, useScrollReset, type StickyTop, useStickyTop, useTheme, } from "../../ui/src/index.js";
1
+ export { AgentRunButton, type AgentRunAttempt, type AgentRunChoice, type AgentRunPicker, type ModelPicking, useAgentRunPick, type FixStanceLook, fixStanceLook, AnchoredOverlay, Avatar, Button, vAction, BarChart, BottomSheet, BrandMark, Card, clipboardOf, browserOwnsClick, appLink, openForwardedPort, ChangeStatusMark, type ChangeStatus, ui, Code, CodeField, ConfirmDialog, ContextMenu, CopyButton, StatusTally, type TallyItem, DagEditor, DagGraph, type DagEdge, type DagNode, DiffStat, DisclosureRow, FilterBar, Icon, type IconName, ImageView, InfoDialog, InfoHint, InfoTable, type FileFormat, formatOf, Markdown, MarkdownDocument, MarkdownFigure, Modal, type NavGroup, NavRail, NoteEditor, type NoteDraft, type NoteDraftOptions, useNoteDraft, useKeyedDraft, type NoticeModel, type NoticeTone, type NoticeAction, Notice, NoticeStack, Page, PageAction, PageHeader, ScrollFrame, PersonaFace, type PersonaLike, Picker, ProjectChip, type PickerGroup, type PickerOption, type PickerOptions, ProgressRing, RepoRail, type RepoRailAll, type RepoRailGroup, type RepoRailRow, ProseField, ResizeSeam, ResponsiveOverlay, Row, RowGroup, SearchBar, SegmentedControl, seriesColor, sinceOf, useLoadingReveal, SkeletonRows, SplitView, StatStrip, StatusBadge, type StatusVariant, StepSection, timeWindows, type TimeWindow, timeWindowWords, useCompact, useDevice, useListNavigation, useNow, useLatest, errorMessage, noticeFrom, noticeOf, useAsyncAction, useNarrow, useRailMemory, useScrollReset, type StickyTop, useStickyTop, useTheme, } from "../../ui/src/index.js";
2
2
  export { formatBytes, formatDate, formatDateTime, formatDayMonth, formatDayMonthTime, formatDuration, formatTime, formatTimestamp, formatTokens, formatWeekdayTime, formatWhen, freshness, timeAgo, } from "./format.js";
3
3
  export { diffSequence, pairEdits, similarity, wordDiff } from "./diff.js";
4
4
  export { activeLocale, extensionT } from "./i18n.js";
@@ -8,6 +8,7 @@ type __VLS_Props = {
8
8
  clampLines?: number;
9
9
  scrollLines?: number;
10
10
  scrollBottom?: boolean;
11
+ tail?: boolean;
11
12
  };
12
13
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
14
  copied: () => any;
@@ -1,4 +1,3 @@
1
- export declare const isRenderableImage: (path: string) => boolean;
2
1
  export type ImageViewState = {
3
2
  readonly fit: true;
4
3
  } | {
@@ -0,0 +1 @@
1
+ export declare const useLatest: () => (() => () => boolean);
@@ -29,7 +29,6 @@ export { type DagEdge, type DagNode } from "./components/charts/dagLayout.js";
29
29
  export { default as FilterBar } from "./components/forms/FilterBar.vue";
30
30
  export { default as Icon } from "./components/primitives/Icon.vue";
31
31
  export { default as ImageView } from "./components/primitives/ImageView.vue";
32
- export { isRenderableImage } from "./components/primitives/imageView.js";
33
32
  export { default as InfoDialog } from "./components/overlays/InfoDialog.vue";
34
33
  export { default as InfoHint } from "./components/feedback/InfoHint.vue";
35
34
  export { default as InfoTable } from "./components/feedback/InfoTable.vue";
@@ -73,6 +72,7 @@ export { default as StatusBadge, type StatusVariant } from "./components/feedbac
73
72
  export { default as StepSection } from "./components/layout/StepSection.vue";
74
73
  export { sinceOf, timeWindows, type TimeWindow, timeWindowWords } from "./lib/timeWindow.js";
75
74
  export { type IconName } from "./icons/iconSets.js";
75
+ export { type FileFormat, formatOf } from "./lib/fileFormat.js";
76
76
  export { useDevice } from "./composables/useDevice.js";
77
77
  export { useNarrow } from "./composables/useNarrow.js";
78
78
  export { useListNavigation } from "./composables/useListNavigation.js";
@@ -80,6 +80,7 @@ export { useScrollReset } from "./composables/useScrollReset.js";
80
80
  export { type StickyTop, useStickyTop } from "./composables/useStickyTop.js";
81
81
  export { useRailMemory } from "./composables/useRailMemory.js";
82
82
  export { useNow } from "./composables/useNow.js";
83
+ export { useLatest } from "./composables/useLatest.js";
83
84
  export { useLoadingReveal } from "./composables/loadingReveal.js";
84
85
  export { errorMessage, noticeFrom, noticeOf, useAsyncAction } from "./composables/useAsyncAction.js";
85
86
  export { useTheme } from "./composables/useTheme.js";
@@ -0,0 +1,11 @@
1
+ export type FileCategory = "code" | "style" | "config" | "data" | "image" | "audio" | "video" | "doc" | "shell" | "archive" | "lock" | "binary" | "generic";
2
+ export interface FileFormat {
3
+ readonly category: FileCategory;
4
+ readonly label?: string;
5
+ readonly binary?: true;
6
+ readonly reads?: "markdown" | "plain" | "table" | "document";
7
+ readonly sheet?: true;
8
+ readonly pages?: true;
9
+ }
10
+ export declare const extensionOf: (path: string) => string;
11
+ export declare const formatOf: (path: string) => FileFormat;
@@ -5,4 +5,4 @@ export { createMarkdownHistory, type DocumentState, type EditKind, type Markdown
5
5
  export { blockBody, buildBlockElement, caretAtOffset, offsetOfCaret } from "./sourceDom.js";
6
6
  export { type BarsFigure, type BarsFigureItem, type DagFigure, type DagFigureEdge, type DagFigureNode, type Figure, FIGURE_ACCENTS, type FigureAccent, FIGURE_LANGS, JSON_FIGURE_LANGS, type MarkdownSegment, MERMAID_LANG, type MermaidFigure, parseFigure, splitFigureSegments, type StatsFigure, type StatsFigureItem, } from "./figures.js";
7
7
  export { type Frontmatter, type FrontmatterField, frontmatterHtml, splitFrontmatter } from "./frontmatter.js";
8
- export { createStreamingMarkdown, lexBlocks, lexInline, type MarkdownDecorator, type MarkdownPart, markdownParseCount, type MarkdownToken, renderMarkdown, renderMarkdownParts, type RenderedMarkdown, settledEnd, type StreamingMarkdown, } from "./render.js";
8
+ export { createStreamingMarkdown, lexBlocks, lexInline, type MarkdownDecorator, type MarkdownPart, markdownParseCount, type MarkdownToken, parseMarkdownParts, type ParsedMarkdown, renderMarkdown, renderMarkdownParts, renderParsedMarkdown, type RenderedMarkdown, settledEnd, type StreamingMarkdown, } from "./render.js";
@@ -1,3 +1,4 @@
1
+ import { type CodeBlock } from "./code.js";
1
2
  import { type Figure } from "./figures.js";
2
3
  export interface MarkdownToken {
3
4
  readonly type: string;
@@ -7,6 +8,10 @@ export interface MarkdownToken {
7
8
  export declare const lexBlocks: (source: string) => readonly MarkdownToken[] | undefined;
8
9
  export declare const lexInline: (source: string) => readonly MarkdownToken[] | undefined;
9
10
  export type MarkdownDecorator = (fragment: DocumentFragment) => void;
11
+ interface MarkdownParts {
12
+ readonly html: string;
13
+ readonly blocks: readonly CodeBlock[];
14
+ }
10
15
  export declare const markdownParseCount: () => number;
11
16
  export declare const renderMarkdown: (source: string, decorate?: MarkdownDecorator) => string;
12
17
  export type MarkdownPart = {
@@ -17,9 +22,20 @@ export type MarkdownPart = {
17
22
  readonly figure: Figure;
18
23
  };
19
24
  export type RenderedMarkdown = readonly MarkdownPart[];
25
+ type ParsedPart = {
26
+ readonly kind: "prose";
27
+ readonly parts: MarkdownParts;
28
+ } | {
29
+ readonly kind: "figure";
30
+ readonly figure: Figure;
31
+ };
32
+ export type ParsedMarkdown = readonly ParsedPart[];
33
+ export declare const parseMarkdownParts: (source: string, decorate?: MarkdownDecorator) => ParsedMarkdown;
34
+ export declare const renderParsedMarkdown: (parsed: ParsedMarkdown) => RenderedMarkdown;
20
35
  export declare const renderMarkdownParts: (source: string, decorate?: MarkdownDecorator) => RenderedMarkdown;
21
36
  export declare const settledEnd: (text: string, from: number) => number;
22
37
  export interface StreamingMarkdown {
23
38
  readonly render: (source: string) => RenderedMarkdown;
24
39
  }
25
40
  export declare const createStreamingMarkdown: (decorate?: MarkdownDecorator) => StreamingMarkdown;
41
+ export {};
@@ -1,4 +1,5 @@
1
1
  export declare const blockBody: (element: Element) => string;
2
+ export declare const FIGURE_HOLDER = "md-code-figure";
2
3
  export declare const buildBlockElement: (source: string) => HTMLElement;
3
4
  export declare const offsetOfCaret: (element: HTMLElement, node: Node, offset: number) => number;
4
5
  export declare const caretAtOffset: (element: HTMLElement, offset: number) => {
package/names.mjs CHANGED
@@ -30,6 +30,7 @@ export const extensionUiNames = [
30
30
  "FilterBar",
31
31
  "fixStanceLook",
32
32
  "formatBytes",
33
+ "formatOf",
33
34
  "formatDate",
34
35
  "formatDateTime",
35
36
  "formatDayMonth",
@@ -48,7 +49,6 @@ export const extensionUiNames = [
48
49
  "InfoDialog",
49
50
  "InfoHint",
50
51
  "InfoTable",
51
- "isRenderableImage",
52
52
  "Markdown",
53
53
  "MarkdownDocument",
54
54
  "MarkdownFigure",
@@ -100,6 +100,7 @@ export const extensionUiNames = [
100
100
  "useNarrow",
101
101
  "useNoteDraft",
102
102
  "useNow",
103
+ "useLatest",
103
104
  "pairEdits",
104
105
  "useRailMemory",
105
106
  "useScrollReset",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/extension-ui",
3
- "version": "1.309.0",
3
+ "version": "1.311.0",
4
4
  "description": "The UI kit intentic extensions render with, host-provided at runtime (the app's own components via the import map), so extension UI is always native to the shell",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/i18n.ts CHANGED
@@ -19,6 +19,8 @@ import type { Ref } from "vue";
19
19
  */
20
20
  export type ExtensionT = (key: string, values?: Record<string, unknown>, plural?: number) => string;
21
21
 
22
+ const namespaceOf = (extensionId: string): string => `ext.${extensionId}`;
23
+
22
24
  /**
23
25
  * One extension's translator, bound to the slice of the message tree the host mounted its catalog under. Keys are its
24
26
  * own — `t("panel.title")` for what lives at `ext.<id>.panel.title` — so nothing it writes can collide with the app's
@@ -34,7 +36,7 @@ export type ExtensionT = (key: string, values?: Record<string, unknown>, plural?
34
36
  * The messages themselves are declared on the extension's module (`export const messages`), which the host loads for
35
37
  * the reader's language before it calls `activate`.
36
38
  */
37
- export const extensionT = (extensionId: string): ExtensionT => useT(`ext.${extensionId}`);
39
+ export const extensionT = (extensionId: string): ExtensionT => useT(namespaceOf(extensionId));
38
40
 
39
41
  /**
40
42
  * One extension's words in one call: the catalog the host mounts (`messages`) and the translator its components
@@ -70,7 +72,7 @@ export const extensionI18n = (
70
72
  export const registerExtensionMessages = (
71
73
  extensionId: string,
72
74
  messages: { readonly base: MessageTree; readonly load: (locale: string) => Promise<{ readonly default: MessageTree }> },
73
- ): Promise<void> => registerCatalog({ namespace: `ext.${extensionId}`, base: messages.base, load: (locale: string) => messages.load(locale) });
75
+ ): Promise<void> => registerCatalog({ namespace: namespaceOf(extensionId), ...messages });
74
76
 
75
77
  /** The language on screen, for the rare contribution that formats something itself. Read-only: change it with nothing. */
76
78
  export const activeLocale: Readonly<Ref<Locale>> = active;
package/src/index.ts CHANGED
@@ -65,7 +65,9 @@ export {
65
65
  InfoDialog,
66
66
  InfoHint,
67
67
  InfoTable,
68
- isRenderableImage,
68
+ // What a file is by its name (category, label, whether it is ever text), the table the shell's own surfaces read.
69
+ type FileFormat,
70
+ formatOf,
69
71
  Markdown,
70
72
  // An editable markdown document (author-facing), unlike `Markdown`'s read-only render.
71
73
  MarkdownDocument,
@@ -140,6 +142,8 @@ export {
140
142
  useListNavigation,
141
143
  // A ticking clock (`useNow`) and a busy/error flag for one mutation at a time (`useAsyncAction`).
142
144
  useNow,
145
+ // Drops an answer a newer request has superseded: `const current = begin(); …; if (!current()) return;`.
146
+ useLatest,
143
147
  errorMessage,
144
148
  noticeFrom,
145
149
  noticeOf,