@medicine-wheel/app 0.6.2 → 0.6.4
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/app/api/ceremonies/[id]/route.ts +24 -0
- package/app/api/ceremonies/route.ts +14 -1
- package/app/graph/page.tsx +105 -17
- package/components/workspaces-panel.tsx +7 -9
- package/lib/ceremony-response.ts +21 -0
- package/package.json +24 -24
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createProvider, detectProvider } from "@medicine-wheel/storage-provider";
|
|
3
|
+
|
|
4
|
+
type RouteContext = { params: Promise<{ id: string }> };
|
|
5
|
+
|
|
6
|
+
export async function GET(_request: Request, context: RouteContext) {
|
|
7
|
+
try {
|
|
8
|
+
const { id } = await context.params;
|
|
9
|
+
const store = await createProvider();
|
|
10
|
+
const ceremony = await store.getCeremony(id);
|
|
11
|
+
|
|
12
|
+
if (!ceremony) {
|
|
13
|
+
return NextResponse.json(
|
|
14
|
+
{ error: `Ceremony not found: ${id}` },
|
|
15
|
+
{ status: 404 },
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return NextResponse.json({ ceremony, provider: detectProvider() });
|
|
20
|
+
} catch (error: unknown) {
|
|
21
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { createProvider, detectProvider } from "@medicine-wheel/storage-provider";
|
|
3
|
+
import { ceremonyBelongsToEpisode } from "@/lib/ceremony-response";
|
|
3
4
|
|
|
4
5
|
export async function GET(request: Request) {
|
|
5
6
|
try {
|
|
6
7
|
const { searchParams } = new URL(request.url);
|
|
7
8
|
const direction = searchParams.get("direction");
|
|
8
9
|
const type = searchParams.get("type");
|
|
10
|
+
const episodePath = searchParams.get("episode_path");
|
|
9
11
|
|
|
10
12
|
const store = await createProvider();
|
|
11
|
-
|
|
13
|
+
// Provider list methods intentionally default to one page (100). A scoped
|
|
14
|
+
// episode query must search the complete ceremony store before filtering,
|
|
15
|
+
// or an older but valid ceremony silently disappears from its episode.
|
|
16
|
+
let ceremonies = await store.getAllCeremonies(
|
|
17
|
+
episodePath ? Number.MAX_SAFE_INTEGER : undefined,
|
|
18
|
+
);
|
|
12
19
|
|
|
13
20
|
if (direction) {
|
|
14
21
|
ceremonies = ceremonies.filter((c) => c.direction === direction);
|
|
@@ -18,6 +25,12 @@ export async function GET(request: Request) {
|
|
|
18
25
|
ceremonies = ceremonies.filter((c) => c.type === type);
|
|
19
26
|
}
|
|
20
27
|
|
|
28
|
+
if (episodePath) {
|
|
29
|
+
ceremonies = ceremonies.filter((ceremony) =>
|
|
30
|
+
ceremonyBelongsToEpisode(ceremony, episodePath),
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
return NextResponse.json({
|
|
22
35
|
ceremonies,
|
|
23
36
|
provider: detectProvider(),
|
package/app/graph/page.tsx
CHANGED
|
@@ -17,8 +17,11 @@ import {
|
|
|
17
17
|
Route,
|
|
18
18
|
Save,
|
|
19
19
|
ShieldCheck,
|
|
20
|
+
SlidersHorizontal,
|
|
21
|
+
X,
|
|
20
22
|
} from "lucide-react";
|
|
21
23
|
import { type RelationalNode, type RelationalEdge, DIRECTION_COLORS } from "@/lib/types";
|
|
24
|
+
import { cn } from "@/lib/utils";
|
|
22
25
|
import {
|
|
23
26
|
applyWheelLayout,
|
|
24
27
|
buildGraphData,
|
|
@@ -109,6 +112,40 @@ export default function GraphPage() {
|
|
|
109
112
|
);
|
|
110
113
|
const layoutStoreRef = useRef(layoutStore);
|
|
111
114
|
|
|
115
|
+
// Mobile presentation: the side panel becomes a slide-up sheet so the
|
|
116
|
+
// canvas can own the screen, and the canvas height fills the viewport.
|
|
117
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
118
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
119
|
+
const [graphHeight, setGraphHeight] = useState<number | string>(600);
|
|
120
|
+
const selectedPanelRef = useRef<HTMLDivElement>(null);
|
|
121
|
+
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const mq = window.matchMedia("(max-width: 1023px)");
|
|
124
|
+
const apply = () => {
|
|
125
|
+
setIsMobile(mq.matches);
|
|
126
|
+
setGraphHeight(
|
|
127
|
+
mq.matches ? Math.max(360, Math.round(window.innerHeight * 0.66)) : 600,
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
apply();
|
|
131
|
+
mq.addEventListener("change", apply);
|
|
132
|
+
window.addEventListener("resize", apply);
|
|
133
|
+
return () => {
|
|
134
|
+
mq.removeEventListener("change", apply);
|
|
135
|
+
window.removeEventListener("resize", apply);
|
|
136
|
+
};
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
// When a being is tapped on mobile the sheet opens; bring its details into
|
|
140
|
+
// view once the slide-up transition settles.
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (!isMobile || !sheetOpen || !selectedNode) return;
|
|
143
|
+
const t = window.setTimeout(() => {
|
|
144
|
+
selectedPanelRef.current?.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
145
|
+
}, 320);
|
|
146
|
+
return () => window.clearTimeout(t);
|
|
147
|
+
}, [isMobile, sheetOpen, selectedNode]);
|
|
148
|
+
|
|
112
149
|
const saveLayoutStore = useCallback(
|
|
113
150
|
(
|
|
114
151
|
nextStore: GraphLayoutStore,
|
|
@@ -380,21 +417,21 @@ export default function GraphPage() {
|
|
|
380
417
|
);
|
|
381
418
|
|
|
382
419
|
return (
|
|
383
|
-
<div className="min-h-screen bg-[#0a0a1a] text-white p-6">
|
|
420
|
+
<div className="min-h-screen bg-[#0a0a1a] text-white p-3 sm:p-6">
|
|
384
421
|
<div className="max-w-7xl mx-auto">
|
|
385
|
-
<div className="flex items-center justify-between
|
|
422
|
+
<div className="flex flex-col gap-3 mb-4 sm:mb-6 sm:flex-row sm:items-center sm:justify-between">
|
|
386
423
|
<div>
|
|
387
|
-
<h1 className="text-2xl font-bold flex items-center gap-2">
|
|
388
|
-
<span className="text-3xl">🔮</span> Medicine Wheel Graph
|
|
424
|
+
<h1 className="text-xl sm:text-2xl font-bold flex items-center gap-2">
|
|
425
|
+
<span className="text-2xl sm:text-3xl">🔮</span> Medicine Wheel Graph
|
|
389
426
|
</h1>
|
|
390
|
-
<p className="text-gray-400 text-sm mt-1">
|
|
391
|
-
Interactive relational web — drag, pan,
|
|
427
|
+
<p className="text-gray-400 text-xs sm:text-sm mt-1">
|
|
428
|
+
Interactive relational web — tap a being, drag, pan, and pinch to zoom
|
|
392
429
|
</p>
|
|
393
430
|
</div>
|
|
394
|
-
<div className="flex gap-2">
|
|
431
|
+
<div className="flex flex-wrap gap-2">
|
|
395
432
|
<button
|
|
396
433
|
onClick={() => setShowLabels(!showLabels)}
|
|
397
|
-
className={`px-3 py-1.5 rounded text-sm ${showLabels ? "bg-white/10" : "bg-white/5"}`}
|
|
434
|
+
className={`min-h-11 px-3 py-1.5 rounded text-sm ${showLabels ? "bg-white/10" : "bg-white/5"}`}
|
|
398
435
|
>
|
|
399
436
|
Labels {showLabels ? "ON" : "OFF"}
|
|
400
437
|
</button>
|
|
@@ -402,18 +439,18 @@ export default function GraphPage() {
|
|
|
402
439
|
onClick={() =>
|
|
403
440
|
setRadialSnap((s) => (s === "off" ? "ring" : s === "ring" ? "sector" : "off"))
|
|
404
441
|
}
|
|
405
|
-
className={`px-3 py-1.5 rounded text-sm ${radialSnap !== "off" ? "bg-white/10" : "bg-white/5"}`}
|
|
442
|
+
className={`min-h-11 px-3 py-1.5 rounded text-sm ${radialSnap !== "off" ? "bg-white/10" : "bg-white/5"}`}
|
|
406
443
|
title="Radial snapping: the wheel guides dragged beings — ring keeps them in their band, sector also inside their quadrant"
|
|
407
444
|
>
|
|
408
445
|
Snap {radialSnap === "off" ? "OFF" : radialSnap.toUpperCase()}
|
|
409
446
|
</button>
|
|
410
|
-
<button onClick={loadData} className="px-3 py-1.5 rounded text-sm bg-white/5 hover:bg-white/10 inline-flex items-center gap-2">
|
|
447
|
+
<button onClick={loadData} className="min-h-11 px-3 py-1.5 rounded text-sm bg-white/5 hover:bg-white/10 inline-flex items-center gap-2">
|
|
411
448
|
<RefreshCw className="h-4 w-4" /> Refresh
|
|
412
449
|
</button>
|
|
413
450
|
</div>
|
|
414
451
|
</div>
|
|
415
452
|
|
|
416
|
-
<div className="flex gap-6">
|
|
453
|
+
<div className="flex flex-col lg:flex-row gap-4 lg:gap-6">
|
|
417
454
|
<div className="relative flex-1 rounded-xl border border-white/10 overflow-hidden">
|
|
418
455
|
{!loading && graph.nodes.length > 0 && (
|
|
419
456
|
<label className="absolute right-3 top-3 z-10 inline-flex items-center gap-2 rounded-md border border-white/10 bg-[#0a0a1a]/80 px-2 py-1 text-[11px] text-gray-300 shadow-sm backdrop-blur">
|
|
@@ -428,9 +465,9 @@ export default function GraphPage() {
|
|
|
428
465
|
</label>
|
|
429
466
|
)}
|
|
430
467
|
{loading ? (
|
|
431
|
-
<div className="flex items-center justify-center
|
|
468
|
+
<div className="flex items-center justify-center text-gray-500" style={{ height: graphHeight }}>Loading graph data...</div>
|
|
432
469
|
) : graph.nodes.length === 0 ? (
|
|
433
|
-
<div className="flex flex-col items-center justify-center
|
|
470
|
+
<div className="flex flex-col items-center justify-center text-gray-500" style={{ height: graphHeight }}>
|
|
434
471
|
<span className="text-4xl mb-3">🌀</span>
|
|
435
472
|
<p>No relational nodes yet.</p>
|
|
436
473
|
<p className="text-sm mt-1">Create nodes via the Nodes page.</p>
|
|
@@ -438,12 +475,16 @@ export default function GraphPage() {
|
|
|
438
475
|
) : (
|
|
439
476
|
<MedicineWheelFlowGraph
|
|
440
477
|
data={graphData}
|
|
441
|
-
height={
|
|
478
|
+
height={graphHeight}
|
|
442
479
|
darkMode
|
|
443
480
|
showNodeLabels={showLabels}
|
|
481
|
+
showMiniMap={!isMobile}
|
|
444
482
|
animationsEnabled={animationsEnabled}
|
|
445
483
|
nodePositions={activeLayout.positions}
|
|
446
|
-
onNodeClick={(node) =>
|
|
484
|
+
onNodeClick={(node) => {
|
|
485
|
+
setSelectedNode(node);
|
|
486
|
+
if (isMobile) setSheetOpen(true);
|
|
487
|
+
}}
|
|
447
488
|
onNodeDoubleClick={navigateToNode}
|
|
448
489
|
onNodePositionsChange={handleNodePositionsChange}
|
|
449
490
|
enableConnections
|
|
@@ -458,7 +499,53 @@ export default function GraphPage() {
|
|
|
458
499
|
)}
|
|
459
500
|
</div>
|
|
460
501
|
|
|
461
|
-
|
|
502
|
+
{/* Mobile: floating toggle opens the panels as a slide-up sheet so
|
|
503
|
+
the canvas keeps the whole screen. */}
|
|
504
|
+
{isMobile && !sheetOpen && (
|
|
505
|
+
<button
|
|
506
|
+
onClick={() => setSheetOpen(true)}
|
|
507
|
+
className="fixed bottom-4 right-4 z-30 inline-flex min-h-11 max-w-[70vw] items-center gap-2 rounded-full border border-white/15 bg-[#12122a]/95 px-4 py-2 text-sm font-medium text-white shadow-lg backdrop-blur"
|
|
508
|
+
aria-label="Open graph panels"
|
|
509
|
+
>
|
|
510
|
+
<SlidersHorizontal className="h-4 w-4 shrink-0" />
|
|
511
|
+
<span className="truncate">{selectedNode ? selectedNode.label : "Panels"}</span>
|
|
512
|
+
</button>
|
|
513
|
+
)}
|
|
514
|
+
|
|
515
|
+
{/* Mobile: dim backdrop behind the open sheet. */}
|
|
516
|
+
{isMobile && sheetOpen && (
|
|
517
|
+
<div
|
|
518
|
+
onClick={() => setSheetOpen(false)}
|
|
519
|
+
className="fixed inset-0 z-40 bg-black/60"
|
|
520
|
+
aria-hidden="true"
|
|
521
|
+
/>
|
|
522
|
+
)}
|
|
523
|
+
|
|
524
|
+
<div
|
|
525
|
+
className={cn(
|
|
526
|
+
isMobile
|
|
527
|
+
? cn(
|
|
528
|
+
"fixed inset-x-0 bottom-0 z-50 max-h-[82vh] overflow-y-auto rounded-t-2xl border-t border-white/10 bg-[#0a0a1a] px-4 pb-8 shadow-2xl transition-transform duration-300 ease-out",
|
|
529
|
+
sheetOpen ? "translate-y-0" : "translate-y-full",
|
|
530
|
+
)
|
|
531
|
+
: "w-72",
|
|
532
|
+
)}
|
|
533
|
+
aria-hidden={isMobile && !sheetOpen ? "true" : undefined}
|
|
534
|
+
>
|
|
535
|
+
{isMobile && (
|
|
536
|
+
<div className="sticky top-0 z-10 -mx-4 mb-3 flex items-center justify-between gap-2 border-b border-white/10 bg-[#0a0a1a] px-4 pb-3 pt-3">
|
|
537
|
+
<span className="text-sm font-semibold text-gray-300">Graph panels</span>
|
|
538
|
+
<button
|
|
539
|
+
onClick={() => setSheetOpen(false)}
|
|
540
|
+
aria-label="Close panels"
|
|
541
|
+
className="inline-flex h-11 w-11 items-center justify-center rounded-md bg-white/10 text-white hover:bg-white/15"
|
|
542
|
+
>
|
|
543
|
+
<X className="h-5 w-5" />
|
|
544
|
+
</button>
|
|
545
|
+
</div>
|
|
546
|
+
)}
|
|
547
|
+
|
|
548
|
+
<div className="space-y-4">
|
|
462
549
|
<div className="rounded-lg border border-white/10 p-4">
|
|
463
550
|
<h3 className="text-sm font-semibold text-gray-400 mb-3">Dispositions</h3>
|
|
464
551
|
<div className="space-y-3">
|
|
@@ -539,7 +626,7 @@ export default function GraphPage() {
|
|
|
539
626
|
</div>
|
|
540
627
|
|
|
541
628
|
{selectedNode && (
|
|
542
|
-
<div className="rounded-xl border border-white/10 p-4">
|
|
629
|
+
<div ref={selectedPanelRef} className="rounded-xl border border-white/10 p-4 scroll-mt-16">
|
|
543
630
|
<h3 className="text-sm font-semibold text-gray-400 mb-2">Selected Node</h3>
|
|
544
631
|
<div className="space-y-2">
|
|
545
632
|
<div><span className="text-xs text-gray-500">Name</span><p className="font-medium">{selectedNode.label}</p></div>
|
|
@@ -565,6 +652,7 @@ export default function GraphPage() {
|
|
|
565
652
|
<div><p className="text-2xl font-bold">{directionCount}</p><p className="text-xs text-gray-500">Directions</p></div>
|
|
566
653
|
</div>
|
|
567
654
|
</div>
|
|
655
|
+
</div>
|
|
568
656
|
</div>
|
|
569
657
|
</div>
|
|
570
658
|
</div>
|
|
@@ -47,22 +47,20 @@ export function WorkspacesPanel({
|
|
|
47
47
|
return () => window.removeEventListener("keydown", onKey);
|
|
48
48
|
}, [open, onClose]);
|
|
49
49
|
|
|
50
|
+
// Robustness: when closed, render nothing at all so the panel can never
|
|
51
|
+
// occupy layout space — not even if the CSS bundle that hides it (transform)
|
|
52
|
+
// fails to load. This is what keeps the switcher discreet on first paint.
|
|
53
|
+
if (!open) return null;
|
|
54
|
+
|
|
50
55
|
return (
|
|
51
56
|
<>
|
|
52
57
|
<div
|
|
53
|
-
aria-hidden={!open}
|
|
54
58
|
onClick={onClose}
|
|
55
|
-
className=
|
|
56
|
-
"fixed inset-0 z-40 bg-background/60 backdrop-blur-sm transition-opacity",
|
|
57
|
-
open ? "opacity-100" : "pointer-events-none opacity-0"
|
|
58
|
-
)}
|
|
59
|
+
className="fixed inset-0 z-40 bg-background/60 backdrop-blur-sm"
|
|
59
60
|
/>
|
|
60
61
|
<aside
|
|
61
62
|
aria-label="Workspaces"
|
|
62
|
-
className=
|
|
63
|
-
"fixed left-0 top-0 z-50 h-full w-[340px] border-r border-border bg-card transition-transform",
|
|
64
|
-
open ? "translate-x-0" : "-translate-x-full"
|
|
65
|
-
)}
|
|
63
|
+
className="fixed left-0 top-0 z-50 h-full w-[340px] max-w-[85vw] border-r border-border bg-card"
|
|
66
64
|
>
|
|
67
65
|
<div className="flex items-center justify-between border-b border-border px-5 py-4">
|
|
68
66
|
<div className="mw-h2">Workspaces</div>
|
package/lib/ceremony-response.ts
CHANGED
|
@@ -50,6 +50,27 @@ export function normalizeCeremonyLog(value: unknown): CeremonyLog | null {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
export function ceremonyEpisodePath(value: unknown): string | undefined {
|
|
54
|
+
if (!value || typeof value !== "object") return undefined;
|
|
55
|
+
const researchContext = (value as Record<string, unknown>).research_context;
|
|
56
|
+
if (typeof researchContext !== "string") return undefined;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(researchContext) as Record<string, unknown> | null;
|
|
60
|
+
if (!parsed || typeof parsed !== "object") return undefined;
|
|
61
|
+
const episodePath = parsed.episode_path ?? parsed.episodePath;
|
|
62
|
+
return typeof episodePath === "string" && episodePath.length > 0
|
|
63
|
+
? episodePath
|
|
64
|
+
: undefined;
|
|
65
|
+
} catch {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function ceremonyBelongsToEpisode(value: unknown, episodePath: string): boolean {
|
|
71
|
+
return ceremonyEpisodePath(value) === episodePath;
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
export function extractCeremonyLogs(response: unknown): CeremonyLog[] {
|
|
54
75
|
const candidate = Array.isArray(response)
|
|
55
76
|
? response
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medicine-wheel/app",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Medicine Wheel — Interactive visual layer for Indigenous relational research with Four Directions, ceremonies, and narrative arcs",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mw": "dist/cli/mw.js",
|
|
@@ -85,29 +85,29 @@
|
|
|
85
85
|
"release:major": "npm run version:major && npm run publish:all && npm run release:commit"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@medicine-wheel/ceremonial-diary": "^0.6.
|
|
89
|
-
"@medicine-wheel/ceremony-protocol": "^0.6.
|
|
90
|
-
"@medicine-wheel/community-review": "^0.6.
|
|
91
|
-
"@medicine-wheel/consent-lifecycle": "^0.6.
|
|
92
|
-
"@medicine-wheel/creative-orientation": "^0.6.
|
|
93
|
-
"@medicine-wheel/data-store": "^0.6.
|
|
94
|
-
"@medicine-wheel/data-store-postgres": "^0.6.
|
|
95
|
-
"@medicine-wheel/fire-keeper": "^0.6.
|
|
96
|
-
"@medicine-wheel/github-ceremony": "^0.6.
|
|
97
|
-
"@medicine-wheel/graph-viz": "^0.6.
|
|
98
|
-
"@medicine-wheel/importance-unit": "^0.6.
|
|
99
|
-
"@medicine-wheel/mcp": "^4.6.
|
|
100
|
-
"@medicine-wheel/narrative-cluster": "^0.6.
|
|
101
|
-
"@medicine-wheel/narrative-engine": "^0.6.
|
|
102
|
-
"@medicine-wheel/ontology-core": "^0.6.
|
|
103
|
-
"@medicine-wheel/perception-layer": "^0.6.
|
|
104
|
-
"@medicine-wheel/prompt-decomposition": "^0.6.
|
|
105
|
-
"@medicine-wheel/relational-index": "^0.6.
|
|
106
|
-
"@medicine-wheel/relational-query": "^0.6.
|
|
107
|
-
"@medicine-wheel/session-reader": "^0.6.
|
|
108
|
-
"@medicine-wheel/storage-provider": "^0.6.
|
|
109
|
-
"@medicine-wheel/transformation-tracker": "^0.6.
|
|
110
|
-
"@medicine-wheel/ui-components": "^0.6.
|
|
88
|
+
"@medicine-wheel/ceremonial-diary": "^0.6.4",
|
|
89
|
+
"@medicine-wheel/ceremony-protocol": "^0.6.4",
|
|
90
|
+
"@medicine-wheel/community-review": "^0.6.4",
|
|
91
|
+
"@medicine-wheel/consent-lifecycle": "^0.6.4",
|
|
92
|
+
"@medicine-wheel/creative-orientation": "^0.6.4",
|
|
93
|
+
"@medicine-wheel/data-store": "^0.6.4",
|
|
94
|
+
"@medicine-wheel/data-store-postgres": "^0.6.4",
|
|
95
|
+
"@medicine-wheel/fire-keeper": "^0.6.4",
|
|
96
|
+
"@medicine-wheel/github-ceremony": "^0.6.4",
|
|
97
|
+
"@medicine-wheel/graph-viz": "^0.6.4",
|
|
98
|
+
"@medicine-wheel/importance-unit": "^0.6.4",
|
|
99
|
+
"@medicine-wheel/mcp": "^4.6.4",
|
|
100
|
+
"@medicine-wheel/narrative-cluster": "^0.6.4",
|
|
101
|
+
"@medicine-wheel/narrative-engine": "^0.6.4",
|
|
102
|
+
"@medicine-wheel/ontology-core": "^0.6.4",
|
|
103
|
+
"@medicine-wheel/perception-layer": "^0.6.4",
|
|
104
|
+
"@medicine-wheel/prompt-decomposition": "^0.6.4",
|
|
105
|
+
"@medicine-wheel/relational-index": "^0.6.4",
|
|
106
|
+
"@medicine-wheel/relational-query": "^0.6.4",
|
|
107
|
+
"@medicine-wheel/session-reader": "^0.6.4",
|
|
108
|
+
"@medicine-wheel/storage-provider": "^0.6.4",
|
|
109
|
+
"@medicine-wheel/transformation-tracker": "^0.6.4",
|
|
110
|
+
"@medicine-wheel/ui-components": "^0.6.4",
|
|
111
111
|
"@neondatabase/serverless": "^0.10.0",
|
|
112
112
|
"@xyflow/react": "^12.3.0",
|
|
113
113
|
"clsx": "^2.1.1",
|