@feedmepos/mf-miniprogram-v2 0.1.0-dev.3 → 0.1.0-dev.30

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 (31) hide show
  1. package/dist/ControlPlaneView-BR5SKjnN.js +13403 -0
  2. package/dist/app.js +1 -1
  3. package/dist/package.json +4 -2
  4. package/dist/src/api/controlPlane.d.ts +3 -1
  5. package/dist/src/components/AnnotationColorField.vue.d.ts +14 -0
  6. package/dist/src/components/AnnotationMessage.vue.d.ts +7 -0
  7. package/dist/src/components/AnnotationPropertyPanel.vue.d.ts +32 -0
  8. package/dist/src/components/AnnotationStyleControl.vue.d.ts +14 -0
  9. package/dist/src/components/BrandKitPanel.vue.d.ts +9 -0
  10. package/dist/src/components/BrandKitProposalCard.vue.d.ts +7 -0
  11. package/dist/src/components/ChatTextPart.vue.d.ts +6 -0
  12. package/dist/src/components/DiffCard.vue.d.ts +9 -0
  13. package/dist/src/components/MarkdownContent.vue.d.ts +6 -0
  14. package/dist/src/components/MessageItem.vue.d.ts +7 -1
  15. package/dist/src/components/StatusBadge.vue.d.ts +21 -0
  16. package/dist/src/components/ToolCallGroup.vue.d.ts +11 -0
  17. package/dist/src/composables/annotationEditing.d.ts +130 -0
  18. package/dist/src/composables/brandkitProposal.d.ts +14 -0
  19. package/dist/src/composables/imageAttachments.d.ts +23 -0
  20. package/dist/src/composables/localPreference.d.ts +10 -0
  21. package/dist/src/composables/previewAnnotations.d.ts +23 -0
  22. package/dist/src/composables/promptQueue.d.ts +20 -0
  23. package/dist/src/composables/status.d.ts +11 -0
  24. package/dist/src/composables/types.d.ts +124 -4
  25. package/dist/src/composables/useBrandKit.d.ts +45 -0
  26. package/dist/src/composables/useChat.d.ts +140 -2
  27. package/dist/src/composables/useIdleSuspend.d.ts +6 -0
  28. package/dist/src/composables/useProject.d.ts +110 -30
  29. package/dist/style.css +1 -1
  30. package/package.json +4 -2
  31. package/dist/ControlPlaneView-DzD3SfCY.js +0 -9484
package/dist/app.js CHANGED
@@ -3,7 +3,7 @@ const n = [
3
3
  {
4
4
  path: "/",
5
5
  name: "miniprogram-v2-control",
6
- component: () => import("./ControlPlaneView-DzD3SfCY.js")
6
+ component: () => import("./ControlPlaneView-BR5SKjnN.js")
7
7
  },
8
8
  {
9
9
  path: "/:pathMatch(.*)*",
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feedmepos/mf-miniprogram-v2",
3
- "version": "0.1.0-dev.3",
3
+ "version": "0.1.0-dev.30",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -23,6 +23,7 @@
23
23
  "build": "npm run type-check && npm run build-only:dev",
24
24
  "build:prod": "npm run type-check && npm run build-only:prod",
25
25
  "preview": "vite preview",
26
+ "test": "node --test src/components/*.test.mjs src/composables/*.test.mjs",
26
27
  "type-check": "vue-tsc --build --force",
27
28
  "typecheck": "npm run type-check",
28
29
  "build:mf:dev": "vite build --mode fmmf:dev",
@@ -38,7 +39,8 @@
38
39
  "dependencies": {
39
40
  "@feedmepos/mf-common": "^1.27.9",
40
41
  "@feedmepos/ui-library": "1.8.4",
41
- "@opencode-ai/sdk": "*",
42
+ "@opencode-ai/sdk": "1.17.14",
43
+ "diff": "^9.0.0",
42
44
  "dompurify": "^3.4.11",
43
45
  "highlight.js": "^11.11.1",
44
46
  "marked": "^18.0.5",
@@ -12,10 +12,12 @@ export declare function controlPlaneBaseUrl(): string;
12
12
  export declare function controlPlaneUrl(path: string): string;
13
13
  export declare function currentBusiness(): MaybeBusiness | undefined;
14
14
  export declare function currentBusinessId(): string;
15
- export declare function currentBusinessLabel(): string;
16
15
  export declare function currentBusinessSlug(): string | undefined;
17
16
  export declare function currentBusinessName(): string;
18
17
  export declare function currentBusinessCountry(): string | undefined;
18
+ export declare function currentBusinessLiveUrl(): string;
19
+ export declare function sleep(ms: number): Promise<unknown>;
20
+ export declare function errorMessage(error: unknown): string;
19
21
  export declare function controlPlaneAuthorizationHeader(): Promise<string | null>;
20
22
  export declare function authorizedFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
21
23
  export declare function controlPlaneFetch<T>(path: string, init?: RequestInit): Promise<T>;
@@ -0,0 +1,14 @@
1
+ import { type BrandKitPreset } from '../composables/annotationEditing';
2
+ type __VLS_Props = {
3
+ value: string;
4
+ label: string;
5
+ presets: BrandKitPreset[];
6
+ disabled?: boolean;
7
+ };
8
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ update: (args_0: string) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onUpdate?: ((args_0: string) => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import type { PreviewAnnotationItem } from '../composables/previewAnnotations';
2
+ type __VLS_Props = {
3
+ items: PreviewAnnotationItem[];
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,32 @@
1
+ import { type AnnotationStyleKey, type BrandKitPreset } from '../composables/annotationEditing';
2
+ import type { PreviewBridgeElement } from '../composables/types';
3
+ type __VLS_Props = {
4
+ element: PreviewBridgeElement;
5
+ values: Record<string, string>;
6
+ beforeValues: Record<string, string>;
7
+ textValue: string;
8
+ beforeText: string;
9
+ presets: BrandKitPreset[];
10
+ disabled?: boolean;
11
+ };
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
+ reset: (args_0: {
14
+ key: AnnotationStyleKey | "text";
15
+ }) => any;
16
+ change: (args_0: {
17
+ key: AnnotationStyleKey | "text";
18
+ value: string;
19
+ }) => any;
20
+ resetAll: () => any;
21
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
22
+ onReset?: ((args_0: {
23
+ key: AnnotationStyleKey | "text";
24
+ }) => any) | undefined;
25
+ onChange?: ((args_0: {
26
+ key: AnnotationStyleKey | "text";
27
+ value: string;
28
+ }) => any) | undefined;
29
+ onResetAll?: (() => any) | undefined;
30
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
31
+ declare const _default: typeof __VLS_export;
32
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { type AnnotationFieldSpec, type BrandKitPreset } from '../composables/annotationEditing';
2
+ type __VLS_Props = {
3
+ spec: AnnotationFieldSpec;
4
+ value: string;
5
+ fontPresets: BrandKitPreset[];
6
+ disabled?: boolean;
7
+ };
8
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ update: (args_0: string) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onUpdate?: ((args_0: string) => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
@@ -0,0 +1,9 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
2
+ close: () => any;
3
+ saved: () => any;
4
+ }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
5
+ onClose?: (() => any) | undefined;
6
+ onSaved?: (() => any) | undefined;
7
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import type { BrandKitProposal } from '../composables/brandkitProposal';
2
+ type __VLS_Props = {
3
+ proposal: BrandKitProposal;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ text: string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
@@ -0,0 +1,9 @@
1
+ import type { ChatMessage } from '../composables/types';
2
+ type __VLS_Props = {
3
+ files: string[];
4
+ diffs: ChatMessage['diffs'];
5
+ loading?: boolean;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ text: string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
@@ -1,7 +1,13 @@
1
1
  import type { ChatMessage } from '../composables/types';
2
2
  type __VLS_Props = {
3
3
  message: ChatMessage;
4
+ canUndo?: boolean;
5
+ undoing?: boolean;
4
6
  };
5
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
8
+ undo: () => any;
9
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ onUndo?: (() => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
12
  declare const _default: typeof __VLS_export;
7
13
  export default _default;
@@ -0,0 +1,21 @@
1
+ import type { BadgeVariant } from '../composables/status';
2
+ type __VLS_Props = {
3
+ variant?: BadgeVariant;
4
+ size?: 'sm' | 'md';
5
+ };
6
+ declare var __VLS_1: {};
7
+ type __VLS_Slots = {} & {
8
+ default?: (props: typeof __VLS_1) => any;
9
+ };
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
11
+ size: "sm" | "md";
12
+ variant: BadgeVariant;
13
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_WithSlots<T, S> = T & {
18
+ new (): {
19
+ $slots: S;
20
+ };
21
+ };
@@ -0,0 +1,11 @@
1
+ import type { ChatPart } from '../composables/types';
2
+ type ToolPart = Extract<ChatPart, {
3
+ kind: 'tool';
4
+ }>;
5
+ type __VLS_Props = {
6
+ parts: ToolPart[];
7
+ busy: boolean;
8
+ };
9
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
@@ -0,0 +1,130 @@
1
+ import type { PreviewBridgeElement } from './types';
2
+ export type AnnotationStyleKey = 'color' | 'backgroundColor' | 'borderColor' | 'opacity' | 'fontFamily' | 'fontSize' | 'fontWeight' | 'lineHeight' | 'letterSpacing' | 'textAlign' | 'borderRadius' | 'borderWidth' | 'width' | 'height' | 'padding' | 'margin' | 'objectFit' | 'aspectRatio' | 'fill' | 'stroke' | 'display' | 'gap' | 'justifyContent' | 'alignItems';
3
+ /** Which editor a property gets. The bridge validates every value with
4
+ * `CSS.supports` and rejects the whole patch on a miss, so controls must only
5
+ * ever emit complete values — never the intermediate state of a keystroke. */
6
+ export type AnnotationControlKind = 'color' | 'length' | 'ratio' | 'choice' | 'align' | 'font' | 'box';
7
+ export interface AnnotationChoice {
8
+ value: string;
9
+ label: string;
10
+ icon?: string;
11
+ /** Computed styles serialize logical alignment as `start`/`end`. Treating those
12
+ * as the physical choice keeps the segment highlighted instead of showing an
13
+ * unset control, and avoids emitting a no-op `start → left` diff. */
14
+ aliases?: readonly string[];
15
+ }
16
+ export interface AnnotationFieldSpec {
17
+ key: AnnotationStyleKey;
18
+ label: string;
19
+ control: AnnotationControlKind;
20
+ units?: readonly string[];
21
+ /** Non-numeric values the property accepts (`auto`, `normal`). Offered in the
22
+ * unit dropdown so the numeric input can stay a number input. */
23
+ keywords?: readonly string[];
24
+ min?: number;
25
+ max?: number;
26
+ step?: number;
27
+ options?: readonly AnnotationChoice[];
28
+ /** One-click common values, offered next to the numeric input. */
29
+ presets?: readonly string[];
30
+ }
31
+ /** Order is load-bearing: it decides the order of `property before → after`
32
+ * lines in the agent prompt. */
33
+ export declare const ANNOTATION_FIELD_SPECS: readonly AnnotationFieldSpec[];
34
+ export declare function annotationFieldSpec(key: AnnotationStyleKey): AnnotationFieldSpec;
35
+ export interface AnnotationSection {
36
+ key: string;
37
+ label: string;
38
+ keys: readonly AnnotationStyleKey[];
39
+ /** Layout properties are the least-used and the most likely to break the
40
+ * preview, so they stay folded until asked for. */
41
+ defaultOpen: boolean;
42
+ }
43
+ export declare const ANNOTATION_SECTIONS: readonly AnnotationSection[];
44
+ export type AnnotationElementKind = 'media' | 'text' | 'container' | 'control';
45
+ /** Which family of controls the element deserves. Deliberately a heuristic used
46
+ * only to order and pre-collapse sections — never to remove a control — because
47
+ * a `<span style="display:block">` or a div used purely as a label would
48
+ * otherwise lose the properties it actually needs. */
49
+ export declare function annotationElementKind(element: PreviewBridgeElement | null): AnnotationElementKind;
50
+ /** Sections ordered for the element, with the relevant ones expanded. */
51
+ export declare function annotationSectionsFor(kind: AnnotationElementKind): AnnotationSection[];
52
+ /** CSS ignores width, height and vertical padding on a non-replaced inline box.
53
+ * The control still works, so this only feeds a tooltip — silently doing
54
+ * nothing is what makes the panel feel broken. */
55
+ export declare function ignoredOnInline(element: PreviewBridgeElement | null, key: AnnotationStyleKey): boolean;
56
+ export interface AnnotationStyleDiff {
57
+ property: AnnotationStyleKey;
58
+ before: string;
59
+ after: string;
60
+ /** BrandKit token the new value came from, when it came from one. Carried into
61
+ * the prompt so the agent reaches for the token instead of hardcoding the
62
+ * literal value it happens to resolve to today. */
63
+ token?: string;
64
+ }
65
+ export interface BrandKitPreset {
66
+ key: string;
67
+ label: string;
68
+ value: string;
69
+ kind: 'color' | 'font';
70
+ }
71
+ export declare function sanitizeAnnotationValue(value: unknown): string;
72
+ /** Hex form for display and for `<input type="color">`. Fully transparent
73
+ * colors have no meaningful hex, so they read as "no color" instead. */
74
+ export declare function normalizeCssColor(value: string | undefined | null): string | null;
75
+ export declare function sameCssColor(a: string | undefined, b: string | undefined): boolean;
76
+ export interface CssLength {
77
+ value: number;
78
+ unit: string;
79
+ }
80
+ export declare function parseCssLength(value: string | undefined | null): CssLength | null;
81
+ export declare function formatCssLength(value: number, unit: string): string;
82
+ export interface CssBox {
83
+ top: string;
84
+ right: string;
85
+ bottom: string;
86
+ left: string;
87
+ }
88
+ /** Expands a 1–4 token padding/margin shorthand. Returns null for anything with
89
+ * `calc()` or keywords so the caller can fall back to raw text editing. */
90
+ export declare function parseCssBox(value: string | undefined | null): CssBox | null;
91
+ export declare function formatCssBox(box: CssBox): string;
92
+ export declare function annotationStyleValues(element: PreviewBridgeElement | null): Record<AnnotationStyleKey, string>;
93
+ export declare function changedStyleKeys(before: Record<string, string>, after: Record<string, string>): AnnotationStyleKey[];
94
+ export interface StyleOverridePatch {
95
+ styles: Record<string, string>;
96
+ appliedKeys: AnnotationStyleKey[];
97
+ }
98
+ /** Builds the temporary-override message for the preview bridge. Only changed
99
+ * properties are pushed: sending the whole computed set would inline
100
+ * width/height/padding onto the element and pin the layout it inherited from
101
+ * source, so an unrelated edit could visibly break it. A property the user
102
+ * reverted is sent as an empty value, which tells the bridge to drop the
103
+ * override instead of leaving the last one stuck on the element. */
104
+ export declare function buildStyleOverridePatch(before: Record<string, string>, draft: Record<string, string>, appliedKeys: readonly AnnotationStyleKey[]): StyleOverridePatch;
105
+ export declare function buildAnnotationStyleDiff(before: Record<string, string>, after: Record<string, string>, presets?: readonly BrandKitPreset[]): AnnotationStyleDiff[];
106
+ export declare function brandKitPresets(colors: Record<string, string>, fonts: Record<string, string>, labels: {
107
+ colors: Record<string, string>;
108
+ fonts: Record<string, string>;
109
+ }): BrandKitPreset[];
110
+ /** An `<img>` reports no nearby text, so without its src and alt the agent is
111
+ * told only that "some image" changed and has to guess which file — the failure
112
+ * mode being an invented asset path that breaks the build. */
113
+ export declare function annotationAssetContext(element: PreviewBridgeElement | null): string | null;
114
+ export declare function serializeAnnotationPrompt(input: {
115
+ id: number;
116
+ route: string;
117
+ device: string;
118
+ element: PreviewBridgeElement | null;
119
+ note: string;
120
+ styleDiffs: AnnotationStyleDiff[];
121
+ textBefore?: string;
122
+ textAfter?: string;
123
+ /** Images the user attached to this marker. One message carries every
124
+ * annotation, so the filename prefix is what pairs a saved upload with the
125
+ * marker it was dropped on. */
126
+ attachments?: {
127
+ count: number;
128
+ prefix: string;
129
+ };
130
+ }): string;
@@ -0,0 +1,14 @@
1
+ export interface BrandKitProposal {
2
+ name?: string;
3
+ colors: Record<string, string>;
4
+ fonts: Record<string, string>;
5
+ }
6
+ export type ChatSegment = {
7
+ kind: 'markdown';
8
+ text: string;
9
+ } | {
10
+ kind: 'proposal';
11
+ proposal: BrandKitProposal;
12
+ };
13
+ export declare function parseBrandKitProposal(json: string): BrandKitProposal | null;
14
+ export declare function splitBrandKitProposals(text: string): ChatSegment[] | null;
@@ -0,0 +1,23 @@
1
+ import type { OutgoingAttachment } from './types';
2
+ export interface PendingImage extends OutgoingAttachment {
3
+ id: string;
4
+ }
5
+ export declare const ACCEPTED_IMAGE_MIME: Set<string>;
6
+ export declare const MAX_ATTACHMENT_BYTES: number;
7
+ export declare const MAX_ATTACHMENTS = 4;
8
+ export declare function readAsDataUrl(file: File): Promise<string>;
9
+ export declare function imageFilesFromPaste(event: ClipboardEvent): File[];
10
+ export declare function imageFilesFromDrop(event: DragEvent): File[];
11
+ /** Reads files into pending attachments. Returns rather than mutates so each
12
+ * caller keeps ownership of its own list (the chat has one, an annotation has
13
+ * one per marker). */
14
+ export declare function collectImages(files: File[], existingCount: number, max?: number): Promise<{
15
+ added: PendingImage[];
16
+ error: string | null;
17
+ }>;
18
+ /** One chat message carries every annotation, so an image has to say which
19
+ * marker it belongs to. The upload endpoint keeps the name it is given (after
20
+ * sanitizing and adding a timestamp prefix), so the marker survives into the
21
+ * saved path and the agent can pair them up. */
22
+ export declare function annotationAttachmentPrefix(marker: number): string;
23
+ export declare function annotationAttachmentName(marker: number, filename?: string): string;
@@ -0,0 +1,10 @@
1
+ /** Small UI preferences that should survive a reload (panel widths, collapsed
2
+ * state). Every access is guarded: localStorage throws in embedded and private
3
+ * browsing contexts, and a lost preference must never break the layout.
4
+ *
5
+ * Keys are namespaced `mpv2:<name>` so they cannot collide with the portal
6
+ * shell this microfrontend is mounted into. */
7
+ export declare function readStoredBoolean(key: string, fallback: boolean): boolean;
8
+ export declare function readStoredNumber(key: string, fallback: number): number;
9
+ export declare function writeStoredValue(key: string, value: string): void;
10
+ export declare function writeStoredBoolean(key: string, value: boolean): void;
@@ -0,0 +1,23 @@
1
+ /** One property (or the element's text) the user changed, in display terms. The
2
+ * card has to show the intent, not merely that some intent existed, so the
3
+ * before/after values travel with it rather than being summarized to a flag. */
4
+ export interface PreviewAnnotationChange {
5
+ label: string;
6
+ before: string;
7
+ after: string;
8
+ token?: string;
9
+ }
10
+ export interface PreviewAnnotationItem {
11
+ id: number;
12
+ note: string;
13
+ label: string;
14
+ route?: string;
15
+ device?: string;
16
+ changes?: PreviewAnnotationChange[];
17
+ /** Superseded by `changes`. Still read so cards in already-sent transcripts
18
+ * keep showing that properties were edited. */
19
+ hasProperties?: boolean;
20
+ source?: string;
21
+ }
22
+ export declare function wrapAnnotationPayload(items: PreviewAnnotationItem[]): string;
23
+ export declare function parseAnnotationMessage(text: string): PreviewAnnotationItem[] | null;
@@ -0,0 +1,20 @@
1
+ export interface PromptQueueState<T> {
2
+ pending: readonly T[];
3
+ active: T | null;
4
+ }
5
+ export declare function emptyPromptQueue<T>(): PromptQueueState<T>;
6
+ export declare function enqueuePrompt<T>(queue: PromptQueueState<T>, item: T): PromptQueueState<T>;
7
+ export declare function startNextPrompt<T>(queue: PromptQueueState<T>): {
8
+ queue: PromptQueueState<T>;
9
+ item: T | null;
10
+ };
11
+ export declare function finishActivePrompt<T>(queue: PromptQueueState<T>): {
12
+ queue: PromptQueueState<T>;
13
+ item: T | null;
14
+ };
15
+ export interface AscendingMessageIdState {
16
+ lastTimestamp: number;
17
+ counter: number;
18
+ }
19
+ export declare function createAscendingMessageIdState(): AscendingMessageIdState;
20
+ export declare function makeOpencodeMessageId(state: AscendingMessageIdState, timestamp?: number, randomBytes?: Uint8Array): string;
@@ -0,0 +1,11 @@
1
+ import type { AgentSessionSummary, ConnectionStatus, ReleaseSummary } from './types';
2
+ export type BadgeVariant = 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'primary';
3
+ export declare function sessionStatusVariant(status: AgentSessionSummary['status']): BadgeVariant;
4
+ export declare function sessionStatusLabel(status: AgentSessionSummary['status']): string;
5
+ export declare function buildStatusVariant(status: string | null): BadgeVariant;
6
+ export declare function buildStatusLabel(status: string | null): string;
7
+ export declare function provisioningStatusLabel(status: string | null | undefined): string;
8
+ export declare function releaseHasPreview(release: Pick<ReleaseSummary, 'status'>): boolean;
9
+ export declare function releaseDisplayStatus(release: ReleaseSummary): string;
10
+ export declare function releaseDisplayVariant(release: ReleaseSummary): BadgeVariant;
11
+ export declare function connectionStatusVariant(status: ConnectionStatus): BadgeVariant;
@@ -1,4 +1,16 @@
1
1
  import type { ToolState } from '@opencode-ai/sdk';
2
+ /** OpenCode 1.17.14's server emits a unified `patch`, while the generated SDK
3
+ * still declares the older `before`/`after` shape. Keep both so current and
4
+ * already-archived sessions render through the same UI. */
5
+ export interface CodeFileDiff {
6
+ file: string;
7
+ patch?: string;
8
+ status?: 'added' | 'deleted' | 'modified';
9
+ before?: string;
10
+ after?: string;
11
+ additions: number;
12
+ deletions: number;
13
+ }
2
14
  export type ChatPart = {
3
15
  kind: 'text';
4
16
  id: string;
@@ -12,22 +24,72 @@ export type ChatPart = {
12
24
  id: string;
13
25
  tool: string;
14
26
  state: ToolState;
27
+ } | {
28
+ kind: 'file';
29
+ id: string;
30
+ mime: string;
31
+ filename?: string;
32
+ url: string;
15
33
  };
34
+ /** An image attached to an outgoing prompt. `url` is a data: URI so the file
35
+ * rides inline in the OpenCode prompt JSON through the transparent proxy. */
36
+ export interface OutgoingAttachment {
37
+ mime: string;
38
+ filename?: string;
39
+ url: string;
40
+ }
41
+ export interface PreviewBridgeElement {
42
+ tag: string;
43
+ selector: string;
44
+ text: string;
45
+ nearbyText?: string;
46
+ attrs: Record<string, string>;
47
+ rect: {
48
+ x: number;
49
+ y: number;
50
+ width: number;
51
+ height: number;
52
+ };
53
+ computed: Record<string, string>;
54
+ canEditText?: boolean;
55
+ sourceInspector?: {
56
+ file: string;
57
+ line: number;
58
+ column: number;
59
+ } | null;
60
+ sourceInspectorRaw?: string | null;
61
+ }
62
+ export type PromptState = 'queued' | 'submitting' | 'running' | 'failed';
16
63
  export interface ChatMessage {
17
- /** Stable render key. Starts as `local-{partId}` for our own just-sent
18
- * messages (the real message id isn't known until the server echoes it
19
- * back over the event stream) and never changes after that, so v-for
20
- * keys stay stable even once `id` is reconciled to the real one. */
64
+ /** Stable render key. Starts as `local-{uuid}` for queued prompts and never
65
+ * changes; the OpenCode message id is assigned only when that prompt reaches
66
+ * the head of the FIFO, so v-for identity remains stable after dispatch. */
21
67
  key: string;
22
68
  id: string | null;
23
69
  role: 'user' | 'assistant';
70
+ /** Assistant messages point back to the user turn that spawned them. OpenCode
71
+ * stores the turn's final file diff on that user message, so this relation
72
+ * lets the UI render it beside the agent work that produced it. */
73
+ parentId: string | null;
24
74
  createdAt: number;
25
75
  parts: ChatPart[];
76
+ /** Patch parts arrive before the complete before/after diff is summarized.
77
+ * Keep their file names so the UI can show useful live progress. */
78
+ changedFiles: string[];
79
+ diffs: CodeFileDiff[];
26
80
  busy: boolean;
81
+ /** Present only on locally-originated user prompts while they are waiting
82
+ * for, or being handled by, the OpenCode session runner. */
83
+ promptState?: PromptState;
27
84
  errorText?: string;
28
85
  }
29
86
  export type ConnectionStatus = 'idle' | 'starting' | 'ready' | 'error';
30
87
  export type ProjectProvisioningStatus = 'not_started' | 'provisioning' | 'ready' | 'failed';
88
+ export type ArchiveCodeAction = 'save' | 'discard';
89
+ export type CheckpointTrigger = 'manual' | 'turn_completed' | 'interval' | 'archive' | 'pre_restore' | 'pre_discard' | 'turn_revert' | 'turn_unrevert' | 'restore' | 'release';
90
+ export type CheckpointStatus = 'capturing' | 'local_only' | 'pushed_verified' | 'failed';
91
+ export type CheckpointContextStatus = 'pending' | 'snapshotted' | 'failed' | 'unavailable';
92
+ export type WorkspaceSyncState = 'unavailable' | 'diverged' | 'behind' | 'uncommitted' | 'unpushed' | 'saving' | 'save_failed' | 'synced' | 'unknown';
31
93
  export interface ProjectSummary {
32
94
  businessId: string;
33
95
  businessSlug: string | null;
@@ -56,6 +118,13 @@ export interface AgentSessionSummary {
56
118
  archived_at: string | null;
57
119
  last_event_chunk: number;
58
120
  last_snapshot_at: string | null;
121
+ base_commit_sha: string | null;
122
+ last_checkpoint_id: string | null;
123
+ last_durable_commit_sha: string | null;
124
+ last_pushed_at: string | null;
125
+ dirty_since: string | null;
126
+ checkpoint_status: CheckpointStatus | null;
127
+ checkpoint_error: string | null;
59
128
  attention_action?: string | null;
60
129
  attention_error?: string | null;
61
130
  release_count: number;
@@ -63,9 +132,60 @@ export interface AgentSessionSummary {
63
132
  created_at: string;
64
133
  updated_at: string;
65
134
  }
135
+ export interface SessionChangesSummary {
136
+ businessId: string;
137
+ sessionId: string;
138
+ workspaceExists: boolean;
139
+ dirty: boolean;
140
+ hasUncommittedChanges: boolean;
141
+ hasUnpushedCommits: boolean;
142
+ headDiffersFromOrigin: boolean;
143
+ statusCount: number;
144
+ commitsAheadOrigin: number;
145
+ commitsBehindOrigin: number;
146
+ headSha: string | null;
147
+ originSha: string | null;
148
+ syncState: WorkspaceSyncState;
149
+ availability: 'available' | 'unavailable';
150
+ lastCheckpointId: string | null;
151
+ lastDurableCommitSha: string | null;
152
+ lastPushedAt: string | null;
153
+ dirtySince: string | null;
154
+ checkpointStatus: CheckpointStatus | null;
155
+ checkpointError: string | null;
156
+ lastSnapshotAt: string | null;
157
+ latestCheckpoint: SessionCheckpoint | null;
158
+ }
159
+ export interface SessionCheckpoint {
160
+ id: string;
161
+ business_id: string;
162
+ session_id: string;
163
+ sequence: number;
164
+ trigger: CheckpointTrigger;
165
+ status: CheckpointStatus;
166
+ context_status: CheckpointContextStatus;
167
+ base_sha: string | null;
168
+ commit_sha: string | null;
169
+ verified_remote_sha: string | null;
170
+ raw_opencode_message_id: string | null;
171
+ opencode_snapshot_key: string | null;
172
+ workspace_backup_key: string | null;
173
+ file_count: number;
174
+ additions: number;
175
+ deletions: number;
176
+ summary: string | null;
177
+ error_stage: string | null;
178
+ error_message: string | null;
179
+ created_at: string;
180
+ committed_at: string | null;
181
+ pushed_at: string | null;
182
+ context_snapshotted_at: string | null;
183
+ pinned: number;
184
+ }
66
185
  export interface ReleaseSummary {
67
186
  id: string;
68
187
  source_commit_sha: string;
188
+ checkpoint_id: string | null;
69
189
  created_from_session_id: string | null;
70
190
  session_title: string | null;
71
191
  status: 'draft' | 'preview' | 'published' | 'rolled_back';