@notis_ai/cli 0.2.0-beta.167.1 → 0.2.0-beta.177.1
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/dist/agent-hooks/notis-agent-hook.mjs +10 -13
- package/dist/base-skills/notis-apps/references/design.md +14 -1
- package/dist/base-skills/notis-apps/references/sdk.md +1 -0
- package/dist/sdk/src/components/Dialog.tsx +46 -0
- package/{template/packages → dist}/sdk/src/index.ts +2 -0
- package/{template/packages → dist}/sdk/src/interactions/shortcuts.tsx +10 -1
- package/{template/packages → dist}/sdk/src/styles.css +93 -74
- package/package.json +1 -1
- package/src/command-specs/diagnostics.js +15 -14
- package/src/runtime/app-platform.js +2 -2
- package/src/runtime/app-test-server.js +1 -1
- package/template/packages/sdk/tsconfig.json +0 -16
- /package/{template/packages → dist}/sdk/package.json +0 -0
- /package/{template/packages → dist}/sdk/src/agentContext.ts +0 -0
- /package/{template/packages → dist}/sdk/src/components/DocumentEditor.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/Markdown.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/MarkdownEditor.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/MultiSelectActionBar.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/MultiSelectCheckbox.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/MultiSelectDragOverlay.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/NotisCommentBoundary.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/NotisSelectionBoundary.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/ShortcutHints.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/Skeleton.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/config.ts +0 -0
- /package/{template/packages → dist}/sdk/src/documents.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useActiveResource.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useAgentContext.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useBackend.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useCloudComputer.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useCollectionInteractions.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useDatabaseSchema.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useDatabaseSubscription.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useDocument.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useDocuments.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useHandover.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useLongPressSelection.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useMultiSelect.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useNotis.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useNotisNavigation.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useQuery.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useTool.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useToolQuery.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useTools.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useTopBarSearch.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useUpsertDocument.ts +0 -0
- /package/{template/packages → dist}/sdk/src/interactions/actions.ts +0 -0
- /package/{template/packages → dist}/sdk/src/interactions/visibility.ts +0 -0
- /package/{template/packages → dist}/sdk/src/interactions.ts +0 -0
- /package/{template/packages → dist}/sdk/src/provider.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/queryCache.ts +0 -0
- /package/{template/packages → dist}/sdk/src/runtime.ts +0 -0
- /package/{template/packages → dist}/sdk/src/tailwind.ts +0 -0
- /package/{template/packages → dist}/sdk/src/ui.ts +0 -0
- /package/{template/packages → dist}/sdk/src/vite.ts +0 -0
|
@@ -9050,7 +9050,7 @@ var BUNDLE_DIR = join4(OUTPUT_DIR, "bundle");
|
|
|
9050
9050
|
var MANIFEST_FILE = join4(OUTPUT_DIR, "manifest.json");
|
|
9051
9051
|
var METADATA_DIR = "metadata";
|
|
9052
9052
|
var CLI_ROOT = resolve3(dirname3(fileURLToPath2(import.meta.url)), "../..");
|
|
9053
|
-
var TEMPLATE_SDK_DIR = join4(CLI_ROOT, "
|
|
9053
|
+
var TEMPLATE_SDK_DIR = join4(CLI_ROOT, "dist", "sdk");
|
|
9054
9054
|
var NOTIS_APP_CATEGORIES = [
|
|
9055
9055
|
"Productivity",
|
|
9056
9056
|
"Sales & Marketing",
|
|
@@ -11533,7 +11533,7 @@ function resolveHarnessReactVersion(projectDir) {
|
|
|
11533
11533
|
const candidates = [
|
|
11534
11534
|
join5(projectDir, "node_modules", "@notis", "sdk", "package.json"),
|
|
11535
11535
|
join5(REPO_ROOT, "packages", "sdk", "package.json"),
|
|
11536
|
-
join5(CLI_ROOT2, "
|
|
11536
|
+
join5(CLI_ROOT2, "dist", "sdk", "package.json")
|
|
11537
11537
|
];
|
|
11538
11538
|
for (const candidate of candidates) {
|
|
11539
11539
|
const pkg = readJsonFile(candidate);
|
|
@@ -16633,7 +16633,7 @@ async function discoverSupabaseSqlTool(runtime) {
|
|
|
16633
16633
|
return match;
|
|
16634
16634
|
}
|
|
16635
16635
|
function unwrapToolExecutionPayload(payload) {
|
|
16636
|
-
return payload?.data?.results?.[0]?.response?.data ?? payload?.results?.[0]?.response?.data ?? payload?.data?.result ?? payload?.result ?? payload?.data ?? payload;
|
|
16636
|
+
return payload?.data?.data?.results?.[0]?.response?.data ?? payload?.data?.results?.[0]?.response?.data ?? payload?.results?.[0]?.response?.data ?? payload?.data?.result ?? payload?.result ?? payload?.data ?? payload;
|
|
16637
16637
|
}
|
|
16638
16638
|
function parseJsonCandidate(value) {
|
|
16639
16639
|
if (typeof value !== "string") return null;
|
|
@@ -16642,20 +16642,17 @@ function parseJsonCandidate(value) {
|
|
|
16642
16642
|
return JSON.parse(trimmed);
|
|
16643
16643
|
} catch {
|
|
16644
16644
|
const boundaryEnd = trimmed.lastIndexOf("</untrusted-data");
|
|
16645
|
-
const
|
|
16646
|
-
const
|
|
16647
|
-
|
|
16648
|
-
const
|
|
16645
|
+
const boundaryName = boundaryEnd >= 0 ? trimmed.slice(boundaryEnd + 2, trimmed.indexOf(">", boundaryEnd)) : null;
|
|
16646
|
+
const opening = boundaryName ? `<${boundaryName}>` : null;
|
|
16647
|
+
for (let boundaryStart = opening ? trimmed.indexOf(opening) : -1; boundaryStart >= 0 && boundaryStart < boundaryEnd; boundaryStart = trimmed.indexOf(opening, boundaryStart + opening.length)) {
|
|
16648
|
+
const contentStart = boundaryStart + opening.length;
|
|
16649
|
+
const inner = trimmed.slice(contentStart, boundaryEnd).trim().replace(/^(?:(?:\\r)?\\n)+/, "").replace(/(?:(?:\\r)?\\n)+$/, "").trim();
|
|
16649
16650
|
try {
|
|
16650
16651
|
return JSON.parse(inner);
|
|
16651
|
-
} catch
|
|
16652
|
-
const nested = parseJsonCandidate(inner);
|
|
16653
|
-
if (nested !== null) return nested;
|
|
16654
|
-
throw usageError(
|
|
16655
|
-
`Supabase diagnostic rows were not valid JSON: ${error instanceof Error ? error.message : String(error)}; prefix=${JSON.stringify(inner.slice(0, 100))}`
|
|
16656
|
-
);
|
|
16652
|
+
} catch {
|
|
16657
16653
|
}
|
|
16658
16654
|
}
|
|
16655
|
+
if (boundaryEnd >= 0) throw usageError("Supabase diagnostic rows were not valid JSON.");
|
|
16659
16656
|
const arrayMatch = trimmed.match(/(\[[\s\S]*\])/);
|
|
16660
16657
|
if (arrayMatch) {
|
|
16661
16658
|
try {
|
|
@@ -15,12 +15,25 @@
|
|
|
15
15
|
- Let Notis own navigation, folder trees, and search. Use `PageHeading`,
|
|
16
16
|
`NativeSelect`, `.list-row`, and `useTopBarSearch` instead of duplicating chrome.
|
|
17
17
|
- Prefer inline optimistic edits for simple changes, with rollback on failure.
|
|
18
|
-
Use
|
|
18
|
+
Use SDK `Dialog` for multi-field edits or destructive confirmation; keep its actions app-owned.
|
|
19
19
|
|
|
20
20
|
Build enforces the existing design rules and reports violations by file/line.
|
|
21
21
|
Use those diagnostics to fix specific problems; passing them does not establish
|
|
22
22
|
that the design is good. See [troubleshooting](troubleshooting.md) when needed.
|
|
23
23
|
|
|
24
|
+
### Controls and side panels
|
|
25
|
+
|
|
26
|
+
- **Keep controls with what they control.** Filters, counts, and Create belong
|
|
27
|
+
above the list; record actions belong inside the detail panel. Only controls
|
|
28
|
+
that affect both panes belong above both.
|
|
29
|
+
- **Align sibling panes.** Start the list and detail panel at the same height,
|
|
30
|
+
with consistent header spacing and control sizes.
|
|
31
|
+
- **Keep secondary actions quiet.** Put occasional destructive actions in an
|
|
32
|
+
overflow menu, retaining their confirmation step.
|
|
33
|
+
|
|
34
|
+
For example, a ticket view has two side-by-side panes: **Tickets / New ticket →
|
|
35
|
+
filters → list**, and **ticket ID / actions / close → details**.
|
|
36
|
+
|
|
24
37
|
### Look at the result
|
|
25
38
|
|
|
26
39
|
Run build and verification, then inspect screenshots of the affected view at a
|
|
@@ -23,6 +23,7 @@ already installs `ShortcutProvider`; app code should not add a second provider.
|
|
|
23
23
|
| `NotisSelectionBoundary` | `(NotisSelectionBoundaryProps) => ReactElement` | Attach structured, explicitly untrusted app/resource/selection context to selected content and copy operations |
|
|
24
24
|
| `SelectionCheckbox` / `SelectionMarquee` | components | Standard selection controls backed by `useCollectionInteractions` |
|
|
25
25
|
| `MultiSelectActionBar` | component | Standard bulk actions with pending/disabled state and shortcut support |
|
|
26
|
+
| `Dialog` | `{ open, onClose, title, description?, role?, children }` | Themed native modal with top-layer stacking, focus handling and background shortcut isolation. Use `role="alertdialog"` for destructive confirmation; put the safe action first. |
|
|
26
27
|
|
|
27
28
|
Import headless collection action types and helpers from
|
|
28
29
|
`@notis/sdk/interactions`. Keep an open detail view synchronized with
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useId, useRef, type ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface DialogProps {
|
|
6
|
+
open: boolean;
|
|
7
|
+
/** Request dismissal. Keep open unchanged to prevent dismissal while saving. */
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
title: ReactNode;
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
role?: 'dialog' | 'alertdialog';
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Native top-layer dialog; content and actions remain app-owned. */
|
|
16
|
+
export function Dialog({ open, onClose, title, description, role = 'dialog', children }: DialogProps) {
|
|
17
|
+
const ref = useRef<HTMLDialogElement>(null);
|
|
18
|
+
const titleId = useId();
|
|
19
|
+
const descriptionId = useId();
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!open) return;
|
|
23
|
+
const dialog = ref.current!;
|
|
24
|
+
dialog.showModal();
|
|
25
|
+
return () => dialog.close();
|
|
26
|
+
}, [open]);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<dialog
|
|
30
|
+
ref={ref}
|
|
31
|
+
className="notis-dialog"
|
|
32
|
+
role={role}
|
|
33
|
+
aria-labelledby={titleId}
|
|
34
|
+
aria-describedby={description == null ? undefined : descriptionId}
|
|
35
|
+
onCancel={(event) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
onClose();
|
|
38
|
+
}}
|
|
39
|
+
onKeyDown={(event) => event.stopPropagation()}
|
|
40
|
+
>
|
|
41
|
+
<h2 id={titleId} className="notis-dialog-title">{title}</h2>
|
|
42
|
+
{description != null && <p id={descriptionId} className="notis-dialog-description">{description}</p>}
|
|
43
|
+
{children}
|
|
44
|
+
</dialog>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -72,6 +72,8 @@ export {
|
|
|
72
72
|
} from './documents';
|
|
73
73
|
|
|
74
74
|
// Multi-select components
|
|
75
|
+
export { Dialog } from './components/Dialog';
|
|
76
|
+
export type { DialogProps } from './components/Dialog';
|
|
75
77
|
export { MultiSelectActionBar } from './components/MultiSelectActionBar';
|
|
76
78
|
export { MultiSelectCheckbox, MultiSelectCheckbox as SelectionCheckbox } from './components/MultiSelectCheckbox';
|
|
77
79
|
export { MultiSelectDragOverlay, MultiSelectDragOverlay as SelectionMarquee } from './components/MultiSelectDragOverlay';
|
|
@@ -215,6 +215,14 @@ function consumeShortcut(event: KeyboardEvent, definition: ShortcutDefinition):
|
|
|
215
215
|
void definition.onTrigger(event);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// Native dialogs make the background inert, but document capture listeners still
|
|
219
|
+
// receive their keyboard events. Leave those events to the dialog and its controls.
|
|
220
|
+
function isDialogEvent(event: KeyboardEvent): boolean {
|
|
221
|
+
return event.composedPath().some((target) =>
|
|
222
|
+
target instanceof HTMLElement && target.matches('dialog.notis-dialog[open]'),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
218
226
|
export function ShortcutProvider({ children }: { children: ReactNode }) {
|
|
219
227
|
const parentRegistry = useContext(ShortcutContext);
|
|
220
228
|
if (parentRegistry) return <>{children}</>;
|
|
@@ -280,7 +288,7 @@ function registerFallbackShortcut(input: Omit<ShortcutRegistration, 'id' | 'orde
|
|
|
280
288
|
registrations,
|
|
281
289
|
nextId: 1,
|
|
282
290
|
dispatch: (event) => {
|
|
283
|
-
if (event.defaultPrevented) return;
|
|
291
|
+
if (event.defaultPrevented || isDialogEvent(event)) return;
|
|
284
292
|
const editable = isEditableShortcutEvent(event);
|
|
285
293
|
const token = chordToken(eventChord(event));
|
|
286
294
|
for (const registration of applicableRegistrations(registrations.values())) {
|
|
@@ -370,6 +378,7 @@ function ShortcutProviderRoot({ children }: { children: ReactNode }) {
|
|
|
370
378
|
|
|
371
379
|
useEffect(() => {
|
|
372
380
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
381
|
+
if (event.defaultPrevented || isDialogEvent(event)) return;
|
|
373
382
|
const editable = isEditableShortcutEvent(event);
|
|
374
383
|
if (!editable && !event.repeat && event.key === '?' && !event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
375
384
|
event.preventDefault();
|
|
@@ -8,94 +8,113 @@
|
|
|
8
8
|
* The portal injects the live Notis theme variables at render time.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
/* Top-layer surfaces must remain distinct from the app's flat content panels. */
|
|
12
|
+
dialog.notis-dialog {
|
|
13
|
+
position: fixed;
|
|
14
|
+
inset: 0;
|
|
15
|
+
margin: auto;
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
width: min(28rem, calc(100% - 2rem));
|
|
18
|
+
max-height: calc(100dvh - 2rem);
|
|
19
|
+
overflow: auto;
|
|
20
|
+
padding: 1.25rem;
|
|
21
|
+
border: 1px solid hsl(var(--border));
|
|
22
|
+
border-radius: 0.75rem;
|
|
23
|
+
background: hsl(var(--popover));
|
|
24
|
+
color: hsl(var(--popover-foreground));
|
|
25
|
+
box-shadow: 0 16px 48px rgb(0 0 0 / 0.2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
dialog.notis-dialog::backdrop { background: rgb(0 0 0 / 0.45); }
|
|
29
|
+
.notis-dialog-title { margin: 0; font-size: 1rem; font-weight: 600; line-height: 1.5; }
|
|
30
|
+
.notis-dialog-description { margin: 0.5rem 0 0; color: hsl(var(--muted-foreground)); font-size: 0.875rem; line-height: 1.5; }
|
|
31
|
+
|
|
11
32
|
/* Framework-neutral styles: the app owns its Tailwind entry point. This file
|
|
12
|
-
* is also consumed in shadow roots and by apps on older Tailwind versions.
|
|
13
|
-
@layer
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
* is also consumed in shadow roots and by apps on older Tailwind versions.
|
|
34
|
+
* Keep rules outside Tailwind-owned @layer blocks: Vite processes this import
|
|
35
|
+
* separately from the app stylesheet, so Tailwind 3 has no matching directives. */
|
|
36
|
+
* {
|
|
37
|
+
border-color: hsl(var(--border));
|
|
38
|
+
}
|
|
39
|
+
[data-notis-app-root] {
|
|
40
|
+
color: hsl(var(--foreground));
|
|
41
|
+
display: block;
|
|
42
|
+
min-height: 100%;
|
|
22
43
|
}
|
|
23
44
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
45
|
+
.notis-app-shell {
|
|
46
|
+
margin-inline: auto;
|
|
47
|
+
width: 100%;
|
|
48
|
+
max-width: var(--portal-page-max-width);
|
|
49
|
+
padding: 1.5rem 1rem;
|
|
50
|
+
}
|
|
31
51
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
/* Flat panel: no border or shadow around items. */
|
|
53
|
+
.notis-app-surface {
|
|
54
|
+
border-radius: 1rem;
|
|
55
|
+
background-color: hsl(var(--muted));
|
|
56
|
+
color: hsl(var(--card-foreground));
|
|
57
|
+
}
|
|
38
58
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
59
|
+
.list-row {
|
|
60
|
+
border-radius: 0.75rem;
|
|
61
|
+
background-color: hsl(var(--muted));
|
|
62
|
+
padding: 0.75rem 1rem;
|
|
63
|
+
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
|
64
|
+
transition-duration: 150ms;
|
|
65
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
66
|
+
}
|
|
47
67
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
.list-row-selected {
|
|
69
|
+
background-color: hsl(var(--primary) / 0.06);
|
|
70
|
+
}
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
/* Split pages are full-bleed; only the list pane carries a hairline. */
|
|
73
|
+
.notis-app-split {
|
|
74
|
+
display: flex;
|
|
75
|
+
height: 100%;
|
|
76
|
+
min-height: 0;
|
|
77
|
+
width: 100%;
|
|
78
|
+
max-width: none;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
}
|
|
61
81
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
.notis-app-pane-list {
|
|
83
|
+
width: 100%;
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
background-color: hsl(var(--muted) / 0.4);
|
|
86
|
+
}
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
.notis-app-pane-detail {
|
|
89
|
+
min-width: 0;
|
|
90
|
+
flex: 1 1 0%;
|
|
91
|
+
background-color: hsl(var(--background));
|
|
92
|
+
}
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
.notis-app-section {
|
|
95
|
+
padding: 1.25rem;
|
|
96
|
+
}
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
@media (min-width: 768px) {
|
|
99
|
+
.notis-app-shell { padding-block: 2rem; }
|
|
100
|
+
.notis-app-section { padding: 1.5rem; }
|
|
101
|
+
}
|
|
82
102
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
103
|
+
@media (min-width: 1024px) {
|
|
104
|
+
.list-row { background-color: transparent; }
|
|
105
|
+
.list-row:hover { background-color: hsl(var(--muted) / 0.6); }
|
|
106
|
+
.list-row-selected,
|
|
107
|
+
.list-row-selected:hover { background-color: hsl(var(--primary) / 0.06); }
|
|
108
|
+
.notis-app-split { flex-direction: row; }
|
|
109
|
+
.notis-app-pane-list {
|
|
110
|
+
width: 20rem;
|
|
111
|
+
border-right-width: 1px;
|
|
112
|
+
border-right-color: hsl(var(--border));
|
|
94
113
|
}
|
|
114
|
+
}
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
116
|
+
@media (min-width: 1280px) {
|
|
117
|
+
.notis-app-pane-list { width: 24rem; }
|
|
99
118
|
}
|
|
100
119
|
|
|
101
120
|
/*
|
package/package.json
CHANGED
|
@@ -58,7 +58,8 @@ async function discoverSupabaseSqlTool(runtime) {
|
|
|
58
58
|
|
|
59
59
|
export function unwrapToolExecutionPayload(payload) {
|
|
60
60
|
return (
|
|
61
|
-
payload?.data?.results?.[0]?.response?.data
|
|
61
|
+
payload?.data?.data?.results?.[0]?.response?.data
|
|
62
|
+
?? payload?.data?.results?.[0]?.response?.data
|
|
62
63
|
?? payload?.results?.[0]?.response?.data
|
|
63
64
|
?? payload?.data?.result
|
|
64
65
|
?? payload?.result
|
|
@@ -74,30 +75,30 @@ function parseJsonCandidate(value) {
|
|
|
74
75
|
return JSON.parse(trimmed);
|
|
75
76
|
} catch {
|
|
76
77
|
const boundaryEnd = trimmed.lastIndexOf('</untrusted-data');
|
|
77
|
-
const
|
|
78
|
-
? trimmed.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const boundaryName = boundaryEnd >= 0
|
|
79
|
+
? trimmed.slice(boundaryEnd + 2, trimmed.indexOf('>', boundaryEnd)) : null;
|
|
80
|
+
const opening = boundaryName ? `<${boundaryName}>` : null;
|
|
81
|
+
for (let boundaryStart = opening ? trimmed.indexOf(opening) : -1;
|
|
82
|
+
boundaryStart >= 0 && boundaryStart < boundaryEnd;
|
|
83
|
+
boundaryStart = trimmed.indexOf(opening, boundaryStart + opening.length)) {
|
|
84
|
+
const contentStart = boundaryStart + opening.length;
|
|
82
85
|
// Supabase MCP sometimes returns the prose envelope with literal "\\n"
|
|
83
86
|
// separators. Strip those only at the boundary: globally replacing them
|
|
84
87
|
// corrupts valid escaped newlines inside JSON string values.
|
|
85
88
|
const inner = trimmed
|
|
86
89
|
.slice(contentStart, boundaryEnd)
|
|
87
90
|
.trim()
|
|
88
|
-
.replace(/^(?:\\r?\\n)+/, '')
|
|
89
|
-
.replace(/(?:\\r?\\n)+$/, '')
|
|
91
|
+
.replace(/^(?:(?:\\r)?\\n)+/, '')
|
|
92
|
+
.replace(/(?:(?:\\r)?\\n)+$/, '')
|
|
90
93
|
.trim();
|
|
91
94
|
try {
|
|
92
95
|
return JSON.parse(inner);
|
|
93
|
-
} catch
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
throw usageError(
|
|
97
|
-
`Supabase diagnostic rows were not valid JSON: ${error instanceof Error ? error.message : String(error)}; prefix=${JSON.stringify(inner.slice(0, 100))}`,
|
|
98
|
-
);
|
|
96
|
+
} catch {
|
|
97
|
+
// The provider also mentions this marker in its introductory prose.
|
|
98
|
+
// Try its actual opening, never a nested tool result's different marker.
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
if (boundaryEnd >= 0) throw usageError('Supabase diagnostic rows were not valid JSON.');
|
|
101
102
|
const arrayMatch = trimmed.match(/(\[[\s\S]*\])/);
|
|
102
103
|
if (arrayMatch) {
|
|
103
104
|
try {
|
|
@@ -27,7 +27,7 @@ const BUNDLE_DIR = join(OUTPUT_DIR, 'bundle');
|
|
|
27
27
|
const MANIFEST_FILE = join(OUTPUT_DIR, 'manifest.json');
|
|
28
28
|
const METADATA_DIR = 'metadata';
|
|
29
29
|
const CLI_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
30
|
-
const TEMPLATE_SDK_DIR = join(CLI_ROOT, '
|
|
30
|
+
const TEMPLATE_SDK_DIR = join(CLI_ROOT, 'dist', 'sdk');
|
|
31
31
|
export const NOTIS_APP_CATEGORIES = [
|
|
32
32
|
'Productivity',
|
|
33
33
|
'Sales & Marketing',
|
|
@@ -1847,7 +1847,7 @@ function listFilesRecursive(dir, base = dir, results = []) {
|
|
|
1847
1847
|
/**
|
|
1848
1848
|
* Keep an app's embedded `packages/sdk` copy identical to the SDK this CLI
|
|
1849
1849
|
* ships. The copy is a mirror by contract (the parity test in the CLI keeps
|
|
1850
|
-
* the
|
|
1850
|
+
* the bundled artifact generated from packages/sdk), so an app never edits it; before
|
|
1851
1851
|
* this sync existed every app silently ran whatever SDK snapshot it was
|
|
1852
1852
|
* scaffolded with and never received hook or style updates.
|
|
1853
1853
|
*
|
|
@@ -80,7 +80,7 @@ function resolveHarnessReactVersion(projectDir) {
|
|
|
80
80
|
const candidates = [
|
|
81
81
|
join(projectDir, 'node_modules', '@notis', 'sdk', 'package.json'),
|
|
82
82
|
join(REPO_ROOT, 'packages', 'sdk', 'package.json'),
|
|
83
|
-
join(CLI_ROOT, '
|
|
83
|
+
join(CLI_ROOT, 'dist', 'sdk', 'package.json'),
|
|
84
84
|
];
|
|
85
85
|
for (const candidate of candidates) {
|
|
86
86
|
const pkg = readJsonFile(candidate);
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"types": ["node", "react", "react-dom"],
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"outDir": "dist",
|
|
13
|
-
"rootDir": "src"
|
|
14
|
-
},
|
|
15
|
-
"include": ["src"]
|
|
16
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|