@almadar/shell-web 0.0.0-stage → 1.0.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/bundling.d.mts +18 -0
- package/bundling.mjs +28 -0
- package/dist/ArbitraryClassCompiler-CO_iASBn.d.ts +195 -0
- package/dist/AvlGlyph-EPJKFEO3.js +6 -0
- package/dist/AvlStateMachine-RKZIKNGC.js +9 -0
- package/dist/AvlTransitionDetail-63SD6GZF.js +11 -0
- package/dist/AvlTransitionExplainer-ZBTLOM3T.js +12 -0
- package/dist/BehaviorView-YS5G4GNB.js +11 -0
- package/dist/Canvas3DHost-BkZQB5l2.d.ts +552 -0
- package/dist/EventBusProvider-BFFHfN4O.d.ts +296 -0
- package/dist/FileTree-BCFnBEuQ.d.ts +254 -0
- package/dist/FlowCanvas-3JRMNJLV.css +1756 -0
- package/dist/FlowCanvas-AUMTWMNG.js +26 -0
- package/dist/GameAudioProvider-ceM_n0ey.d.ts +90 -0
- package/dist/KaTeX_AMS-Regular-CYEKBG2K.woff +0 -0
- package/dist/KaTeX_AMS-Regular-JKX5W2C4.ttf +0 -0
- package/dist/KaTeX_AMS-Regular-U6PRYMIZ.woff2 +0 -0
- package/dist/KaTeX_Caligraphic-Bold-5QL5CMTE.woff2 +0 -0
- package/dist/KaTeX_Caligraphic-Bold-WZ3QSGD3.woff +0 -0
- package/dist/KaTeX_Caligraphic-Bold-ZTS3R3HK.ttf +0 -0
- package/dist/KaTeX_Caligraphic-Regular-3LKEU76G.woff +0 -0
- package/dist/KaTeX_Caligraphic-Regular-A7XRTZ5Q.ttf +0 -0
- package/dist/KaTeX_Caligraphic-Regular-KX5MEWCF.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Bold-2QVFK6NQ.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Bold-T4SWXBMT.woff +0 -0
- package/dist/KaTeX_Fraktur-Bold-WGHVTYOR.ttf +0 -0
- package/dist/KaTeX_Fraktur-Regular-2PEIFJSJ.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Regular-5U4OPH2X.ttf +0 -0
- package/dist/KaTeX_Fraktur-Regular-PQMHCIK6.woff +0 -0
- package/dist/KaTeX_Main-Bold-2GA4IZIN.woff +0 -0
- package/dist/KaTeX_Main-Bold-W5FBVCZM.ttf +0 -0
- package/dist/KaTeX_Main-Bold-YP5VVQRP.woff2 +0 -0
- package/dist/KaTeX_Main-BoldItalic-4P4C7HJH.woff +0 -0
- package/dist/KaTeX_Main-BoldItalic-N4V3DX7S.woff2 +0 -0
- package/dist/KaTeX_Main-BoldItalic-ODMLBJJQ.ttf +0 -0
- package/dist/KaTeX_Main-Italic-I43T2HSR.ttf +0 -0
- package/dist/KaTeX_Main-Italic-RELBIK7M.woff2 +0 -0
- package/dist/KaTeX_Main-Italic-SASNQFN2.woff +0 -0
- package/dist/KaTeX_Main-Regular-ARRPAO67.woff2 +0 -0
- package/dist/KaTeX_Main-Regular-P5I74A2A.woff +0 -0
- package/dist/KaTeX_Main-Regular-W74P5G27.ttf +0 -0
- package/dist/KaTeX_Math-BoldItalic-6EBV3DK5.woff +0 -0
- package/dist/KaTeX_Math-BoldItalic-K4WTGH3J.woff2 +0 -0
- package/dist/KaTeX_Math-BoldItalic-VB447A4D.ttf +0 -0
- package/dist/KaTeX_Math-Italic-6KGCHLFN.woff2 +0 -0
- package/dist/KaTeX_Math-Italic-KKK3USB2.woff +0 -0
- package/dist/KaTeX_Math-Italic-SON4MRCA.ttf +0 -0
- package/dist/KaTeX_SansSerif-Bold-RRNVJFFW.woff2 +0 -0
- package/dist/KaTeX_SansSerif-Bold-STQ6RXC7.ttf +0 -0
- package/dist/KaTeX_SansSerif-Bold-X5M5EMOD.woff +0 -0
- package/dist/KaTeX_SansSerif-Italic-HMPFTM52.woff2 +0 -0
- package/dist/KaTeX_SansSerif-Italic-PSN4QKYX.woff +0 -0
- package/dist/KaTeX_SansSerif-Italic-WTBAZBGY.ttf +0 -0
- package/dist/KaTeX_SansSerif-Regular-2TL3USAE.ttf +0 -0
- package/dist/KaTeX_SansSerif-Regular-OQCII6EP.woff +0 -0
- package/dist/KaTeX_SansSerif-Regular-XIQ62X4E.woff2 +0 -0
- package/dist/KaTeX_Script-Regular-72OLXYNA.ttf +0 -0
- package/dist/KaTeX_Script-Regular-A5IFOEBS.woff +0 -0
- package/dist/KaTeX_Script-Regular-APUWIHLP.woff2 +0 -0
- package/dist/KaTeX_Size1-Regular-4HRHTS65.woff +0 -0
- package/dist/KaTeX_Size1-Regular-5LRUTBFT.woff2 +0 -0
- package/dist/KaTeX_Size1-Regular-7K6AASVL.ttf +0 -0
- package/dist/KaTeX_Size2-Regular-222HN3GT.ttf +0 -0
- package/dist/KaTeX_Size2-Regular-K5ZHAIS6.woff +0 -0
- package/dist/KaTeX_Size2-Regular-LELKET5D.woff2 +0 -0
- package/dist/KaTeX_Size3-Regular-TLFPAHDE.woff +0 -0
- package/dist/KaTeX_Size3-Regular-UFCO6WCA.ttf +0 -0
- package/dist/KaTeX_Size3-Regular-WQRQ47UD.woff2 +0 -0
- package/dist/KaTeX_Size4-Regular-7PGNVPQK.ttf +0 -0
- package/dist/KaTeX_Size4-Regular-CDMV7U5C.woff2 +0 -0
- package/dist/KaTeX_Size4-Regular-PKMWZHNC.woff +0 -0
- package/dist/KaTeX_Typewriter-Regular-3F5K6SQ6.ttf +0 -0
- package/dist/KaTeX_Typewriter-Regular-MJMFSK64.woff +0 -0
- package/dist/KaTeX_Typewriter-Regular-VBYJ4NRC.woff2 +0 -0
- package/dist/KernelEngineContext-CcxGYtlr.d.ts +33 -0
- package/dist/LayersPanel-M2LHWUFF.js +6 -0
- package/dist/ModuleCard-QHDGK5XK.js +7 -0
- package/dist/OrbInspector-MHLJ6OEE.css +1756 -0
- package/dist/OrbInspector-QCPEPUPH.js +26 -0
- package/dist/Select-B-iDdnvE.d.ts +185 -0
- package/dist/ServerBridge-Bqsj-lOU.d.ts +124 -0
- package/dist/ThemeContext-DJmO59xd.d.ts +147 -0
- package/dist/UISlotContext-Dl_ewwCI.d.ts +79 -0
- package/dist/UISlotRenderer-C7WWOK43.js +26 -0
- package/dist/UISlotRenderer-KVFO6J7R.css +1756 -0
- package/dist/auth/browser/index.d.ts +2 -0
- package/dist/auth/browser/index.js +2 -0
- package/dist/auth/react/index.d.ts +56 -0
- package/dist/auth/react/index.js +157 -0
- package/dist/avl/index.css +1756 -0
- package/dist/avl/index.d.ts +2248 -0
- package/dist/avl/index.js +2693 -0
- package/dist/avl-3d-context-BycmO6tG.d.ts +201 -0
- package/dist/avl-schema-parser-CtJxJ9KU.d.ts +132 -0
- package/dist/avl-zoom-state-CKMVuBFg.d.ts +17 -0
- package/dist/chunk-3BBUBJFF.js +339 -0
- package/dist/chunk-3S54FWRC.js +131 -0
- package/dist/chunk-3VZ36ZKO.js +775 -0
- package/dist/chunk-4T3P43NS.js +1133 -0
- package/dist/chunk-4YXBKHHM.js +11488 -0
- package/dist/chunk-57DC34LY.js +525 -0
- package/dist/chunk-5QTYQTPS.js +15 -0
- package/dist/chunk-A2LR6VQQ.js +349 -0
- package/dist/chunk-AB3X7QTE.js +505 -0
- package/dist/chunk-AE7VCQB6.js +561 -0
- package/dist/chunk-AGXD77SL.js +98 -0
- package/dist/chunk-AU7O65OX.js +66 -0
- package/dist/chunk-CPLN6NBQ.js +701 -0
- package/dist/chunk-DZBQA2OW.js +176 -0
- package/dist/chunk-E6KA4J6N.js +227 -0
- package/dist/chunk-EOWMARUB.js +16 -0
- package/dist/chunk-G7DCAZ22.js +19 -0
- package/dist/chunk-GFXCPUMX.js +1334 -0
- package/dist/chunk-HH5KSMH5.js +311 -0
- package/dist/chunk-ILQXJ2AR.js +280 -0
- package/dist/chunk-ILZ7ORX7.js +432 -0
- package/dist/chunk-K4MOPSEL.js +674 -0
- package/dist/chunk-LHP2TK7O.js +47587 -0
- package/dist/chunk-P4ZFUQFF.js +93 -0
- package/dist/chunk-PCR37T3U.js +296 -0
- package/dist/chunk-PRXQGGCO.js +580 -0
- package/dist/chunk-REXYVBUO.js +191 -0
- package/dist/chunk-ROICKAU7.js +24 -0
- package/dist/chunk-SP5CDJ6K.js +338 -0
- package/dist/chunk-TUPZWTRE.js +1051 -0
- package/dist/chunk-TXAUOLWZ.js +490 -0
- package/dist/chunk-TZZBINQY.js +82 -0
- package/dist/chunk-UTDC2NEA.js +14 -0
- package/dist/chunk-UU57VNS2.js +1053 -0
- package/dist/chunk-UXLE3IPR.js +421 -0
- package/dist/chunk-VO2TTLS5.js +94 -0
- package/dist/chunk-X3DMMX27.js +11 -0
- package/dist/chunk-YHMRX6YA.js +455 -0
- package/dist/components/index.css +1756 -0
- package/dist/components/index.d.ts +11299 -0
- package/dist/components/index.js +1110 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.js +8 -0
- package/dist/core.d.ts +2599 -0
- package/dist/core.js +3 -0
- package/dist/design-classes/index.cjs +431 -0
- package/dist/design-classes/index.d.cts +165 -0
- package/dist/design-classes/index.d.ts +165 -0
- package/dist/design-classes/index.js +399 -0
- package/dist/emojiItems-QGSNAABW.js +20 -0
- package/dist/fx-CmQjnHmT.d.ts +371 -0
- package/dist/hooks/index.d.ts +971 -0
- package/dist/hooks/index.js +8 -0
- package/dist/index.d.ts +408 -0
- package/dist/index.js +178 -0
- package/dist/katexPlugin-FA7NX4PE.css +1161 -0
- package/dist/katexPlugin-NCDKOOQY.js +2 -0
- package/dist/kernel-client-TZKGHJRY.js +516 -0
- package/dist/kernel-wire-wNdAPfhJ.d.ts +88 -0
- package/dist/lib/index.d.ts +602 -0
- package/dist/lib/index.js +1289 -0
- package/dist/paintDispatch-CuJLsr9Y.d.ts +688 -0
- package/dist/parseLessonSegments-GpCeMrb2.d.ts +334 -0
- package/dist/perf-CKiBKbkw.d.ts +22 -0
- package/dist/perf-Dr28-AgT.d.ts +57 -0
- package/dist/prism-X5YWKXO5.js +136 -0
- package/dist/providers/index.css +1756 -0
- package/dist/providers/index.d.ts +355 -0
- package/dist/providers/index.js +29 -0
- package/dist/renderer/index.d.ts +465 -0
- package/dist/renderer/index.js +4 -0
- package/dist/runtime/index.css +1756 -0
- package/dist/runtime/index.d.ts +239 -0
- package/dist/runtime/index.js +28 -0
- package/dist/slot-host-CPzrxLo9.d.ts +48 -0
- package/dist/ssr/index.cjs +9739 -0
- package/dist/ssr/index.d.cts +464 -0
- package/dist/ssr/index.d.ts +464 -0
- package/dist/ssr/index.js +9703 -0
- package/dist/storage/browser/index.d.ts +1 -0
- package/dist/storage/browser/index.js +2 -0
- package/dist/test-support.d.ts +42 -0
- package/dist/test-support.js +181 -0
- package/dist/themeTokens-CRd8AEDF.d.ts +125 -0
- package/dist/three/index.css +503 -0
- package/dist/three/index.d.ts +1185 -0
- package/dist/three/index.js +3908 -0
- package/dist/useUISlots-CiobNFGb.d.ts +211 -0
- package/dist/verification-C5pTeMJv.d.ts +66 -0
- package/dist/verificationRegistry-CVrcxG1s.d.ts +122 -0
- package/dist/wrapCallbackForEvent-B9QLbhxX.d.ts +19 -0
- package/index.css +199 -0
- package/package.json +273 -3
- package/src/core/lib/band-shapes.json +7 -0
- package/src/core/locales/ar.json +1276 -0
- package/src/core/locales/en.json +1276 -0
- package/src/core/locales/index.ts +54 -0
- package/src/core/locales/sl.json +1276 -0
- package/src/core/tokens/native-tokens.json +369 -0
- package/tailwind-compile.cjs +29 -0
- package/tailwind-preset.cjs +1020 -0
- package/themes/_base.css +451 -0
- package/themes/_contract.md +307 -0
- package/themes/_fonts-kenney.css +11 -0
- package/themes/_fonts.css +12 -0
- package/themes/_foundation.css +105 -0
- package/themes/_head.css +22 -0
- package/themes/_presets.css +67 -0
- package/themes/almadar-heritage.css +455 -0
- package/themes/almadar-website.css +269 -0
- package/themes/almadar.css +269 -0
- package/themes/aqua.css +455 -0
- package/themes/arabesque.css +459 -0
- package/themes/art-deco.css +457 -0
- package/themes/art-nouveau.css +459 -0
- package/themes/atelier.css +463 -0
- package/themes/bauhaus.css +461 -0
- package/themes/bloomberg-dense.css +463 -0
- package/themes/blueprint.css +457 -0
- package/themes/clay.css +449 -0
- package/themes/comic.css +453 -0
- package/themes/constructivist.css +457 -0
- package/themes/corporate.css +449 -0
- package/themes/cyberpunk.css +453 -0
- package/themes/frutiger-aero.css +458 -0
- package/themes/game-adventure.css +201 -0
- package/themes/game-rpg.css +203 -0
- package/themes/game-sci-fi.css +201 -0
- package/themes/game-ui-pack.css +200 -0
- package/themes/gazette.css +449 -0
- package/themes/glass.css +457 -0
- package/themes/gothic.css +453 -0
- package/themes/index.css +21 -0
- package/themes/ink-wash.css +459 -0
- package/themes/kawaii.css +459 -0
- package/themes/kflow.css +310 -0
- package/themes/kiosk.css +449 -0
- package/themes/linear-clean.css +463 -0
- package/themes/luxury.css +451 -0
- package/themes/mac-classic.css +455 -0
- package/themes/material.css +463 -0
- package/themes/memphis.css +453 -0
- package/themes/mid-century.css +455 -0
- package/themes/minimalist.css +449 -0
- package/themes/mudcloth.css +459 -0
- package/themes/nata.css +310 -0
- package/themes/neon.css +453 -0
- package/themes/neumorphic.css +451 -0
- package/themes/newsprint.css +455 -0
- package/themes/notion-editorial.css +463 -0
- package/themes/orb.css +465 -0
- package/themes/pixel.css +449 -0
- package/themes/prism.css +309 -0
- package/themes/rawi.css +310 -0
- package/themes/retro.css +452 -0
- package/themes/risograph.css +463 -0
- package/themes/scandi.css +469 -0
- package/themes/sketch.css +455 -0
- package/themes/solarpunk.css +469 -0
- package/themes/steampunk.css +451 -0
- package/themes/swiss.css +455 -0
- package/themes/terminal.css +466 -0
- package/themes/trait-wars.css +487 -0
- package/themes/ukiyo-e.css +459 -0
- package/themes/vaporwave.css +455 -0
- package/themes/victorian.css +453 -0
- package/themes/wabi-sabi.css +459 -0
- package/themes/win95.css +455 -0
- package/themes/wireframe.css +439 -0
- package/themes/zine.css +455 -0
- package/README.md +0 -3
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
import { claimDelivery } from './chunk-PRXQGGCO.js';
|
|
2
|
+
import { useEventBus, getTraitPresence, beginPending, endPending } from './chunk-4YXBKHHM.js';
|
|
3
|
+
import { createContext, useState, useCallback, useEffect, useMemo, useRef, useContext, useSyncExternalStore } from 'react';
|
|
4
|
+
import { createLogger } from '@almadar/logger';
|
|
5
|
+
import { mergeEntityFrame } from '@almadar/core';
|
|
6
|
+
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
|
|
7
|
+
|
|
8
|
+
var log = createLogger("almadar:ui:filesystem");
|
|
9
|
+
function useFileSystem() {
|
|
10
|
+
const [status, setStatus] = useState("idle");
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
13
|
+
const [files, setFiles] = useState([]);
|
|
14
|
+
const [selectedFile, setSelectedFile] = useState(null);
|
|
15
|
+
const [selectedPath, setSelectedPath] = useState(null);
|
|
16
|
+
const [previewUrl, setPreviewUrl] = useState(null);
|
|
17
|
+
const [fileContents, setFileContents] = useState(/* @__PURE__ */ new Map());
|
|
18
|
+
const boot = useCallback(async () => {
|
|
19
|
+
setStatus("booting");
|
|
20
|
+
setError(null);
|
|
21
|
+
setIsLoading(true);
|
|
22
|
+
try {
|
|
23
|
+
log.debug("Booting WebContainer");
|
|
24
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
25
|
+
setStatus("ready");
|
|
26
|
+
} catch (err) {
|
|
27
|
+
setError(err instanceof Error ? err.message : "Failed to boot");
|
|
28
|
+
setStatus("error");
|
|
29
|
+
} finally {
|
|
30
|
+
setIsLoading(false);
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
const mountFiles = useCallback(async (filesToMount) => {
|
|
34
|
+
setIsLoading(true);
|
|
35
|
+
try {
|
|
36
|
+
let filesArray;
|
|
37
|
+
if (Array.isArray(filesToMount)) {
|
|
38
|
+
filesArray = filesToMount;
|
|
39
|
+
} else {
|
|
40
|
+
filesArray = [];
|
|
41
|
+
const flattenTree = (obj, basePath = "") => {
|
|
42
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
43
|
+
const path = basePath ? `${basePath}/${key}` : key;
|
|
44
|
+
if (value && "file" in value) {
|
|
45
|
+
filesArray.push({ path, content: value.file.contents || "" });
|
|
46
|
+
} else if (value && "directory" in value) {
|
|
47
|
+
flattenTree(value.directory, path);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
flattenTree(filesToMount);
|
|
52
|
+
}
|
|
53
|
+
const newContents = /* @__PURE__ */ new Map();
|
|
54
|
+
for (const file of filesArray) {
|
|
55
|
+
newContents.set(file.path, file.content);
|
|
56
|
+
}
|
|
57
|
+
setFileContents(newContents);
|
|
58
|
+
const newTree = [];
|
|
59
|
+
for (const file of filesArray) {
|
|
60
|
+
const parts = file.path.split("/").filter(Boolean);
|
|
61
|
+
let current = newTree;
|
|
62
|
+
for (let i = 0; i < parts.length; i++) {
|
|
63
|
+
const part = parts[i];
|
|
64
|
+
const isFile = i === parts.length - 1;
|
|
65
|
+
const currentPath = "/" + parts.slice(0, i + 1).join("/");
|
|
66
|
+
let node = current.find((n) => n.name === part);
|
|
67
|
+
if (!node) {
|
|
68
|
+
node = {
|
|
69
|
+
path: currentPath,
|
|
70
|
+
name: part,
|
|
71
|
+
type: isFile ? "file" : "directory",
|
|
72
|
+
children: isFile ? void 0 : []
|
|
73
|
+
};
|
|
74
|
+
current.push(node);
|
|
75
|
+
}
|
|
76
|
+
if (!isFile && node && node.children) {
|
|
77
|
+
current = node.children;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
setFiles(newTree);
|
|
82
|
+
setStatus("running");
|
|
83
|
+
} catch (err) {
|
|
84
|
+
log.error("Failed to mount files", { error: err instanceof Error ? err : String(err) });
|
|
85
|
+
} finally {
|
|
86
|
+
setIsLoading(false);
|
|
87
|
+
}
|
|
88
|
+
}, []);
|
|
89
|
+
const readFile = useCallback(async (path) => {
|
|
90
|
+
return fileContents.get(path) || "";
|
|
91
|
+
}, [fileContents]);
|
|
92
|
+
const writeFile = useCallback(async (path, content) => {
|
|
93
|
+
setFileContents((prev) => {
|
|
94
|
+
const next = new Map(prev);
|
|
95
|
+
next.set(path, content);
|
|
96
|
+
return next;
|
|
97
|
+
});
|
|
98
|
+
}, []);
|
|
99
|
+
const selectFile = useCallback(async (path) => {
|
|
100
|
+
const content = fileContents.get(path) || "";
|
|
101
|
+
const ext = path.split(".").pop()?.toLowerCase() || "";
|
|
102
|
+
const languageMap = {
|
|
103
|
+
ts: "typescript",
|
|
104
|
+
tsx: "typescript",
|
|
105
|
+
js: "javascript",
|
|
106
|
+
jsx: "javascript",
|
|
107
|
+
json: "json",
|
|
108
|
+
md: "markdown",
|
|
109
|
+
css: "css",
|
|
110
|
+
html: "html",
|
|
111
|
+
orb: "json"
|
|
112
|
+
};
|
|
113
|
+
setSelectedPath(path);
|
|
114
|
+
setSelectedFile({
|
|
115
|
+
path,
|
|
116
|
+
content,
|
|
117
|
+
language: languageMap[ext] || "plaintext",
|
|
118
|
+
isDirty: false
|
|
119
|
+
});
|
|
120
|
+
}, [fileContents]);
|
|
121
|
+
const updateContent = useCallback((pathOrContent, contentArg) => {
|
|
122
|
+
const path = contentArg !== void 0 ? pathOrContent : selectedPath;
|
|
123
|
+
const content = contentArg !== void 0 ? contentArg : pathOrContent;
|
|
124
|
+
if (!path) {
|
|
125
|
+
log.warn("updateContent called without path and no file selected");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
setFileContents((prev) => {
|
|
129
|
+
const next = new Map(prev);
|
|
130
|
+
next.set(path, content);
|
|
131
|
+
return next;
|
|
132
|
+
});
|
|
133
|
+
if (selectedPath === path) {
|
|
134
|
+
setSelectedFile((prev) => prev ? { ...prev, content, isDirty: true } : null);
|
|
135
|
+
}
|
|
136
|
+
}, [selectedPath]);
|
|
137
|
+
const updateSelectedContent = useCallback((content) => {
|
|
138
|
+
setSelectedFile((prev) => prev ? { ...prev, content, isDirty: true } : null);
|
|
139
|
+
}, []);
|
|
140
|
+
const refreshTree = useCallback(async () => {
|
|
141
|
+
log.debug("Refreshing tree");
|
|
142
|
+
}, []);
|
|
143
|
+
const runCommand = useCallback(async (command) => {
|
|
144
|
+
log.debug("Running command", { command });
|
|
145
|
+
return { exitCode: 0, output: "" };
|
|
146
|
+
}, []);
|
|
147
|
+
const startDevServer = useCallback(async () => {
|
|
148
|
+
log.debug("Starting dev server");
|
|
149
|
+
setPreviewUrl("http://localhost:5173");
|
|
150
|
+
}, []);
|
|
151
|
+
return {
|
|
152
|
+
status,
|
|
153
|
+
error,
|
|
154
|
+
isLoading,
|
|
155
|
+
files,
|
|
156
|
+
selectedFile,
|
|
157
|
+
selectedPath,
|
|
158
|
+
previewUrl,
|
|
159
|
+
boot,
|
|
160
|
+
mountFiles,
|
|
161
|
+
readFile,
|
|
162
|
+
writeFile,
|
|
163
|
+
selectFile,
|
|
164
|
+
updateContent,
|
|
165
|
+
updateSelectedContent,
|
|
166
|
+
refreshTree,
|
|
167
|
+
runCommand,
|
|
168
|
+
startDevServer
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
var log2 = createLogger("almadar:ui:extensions");
|
|
172
|
+
var defaultManifest = {
|
|
173
|
+
languages: {
|
|
174
|
+
typescript: { extensions: [".ts", ".tsx"], icon: "ts", color: "#3178c6" },
|
|
175
|
+
javascript: { extensions: [".js", ".jsx"], icon: "js", color: "#f7df1e" },
|
|
176
|
+
json: { extensions: [".json", ".orb"], icon: "json", color: "#000000" },
|
|
177
|
+
css: { extensions: [".css"], icon: "css", color: "#264de4" },
|
|
178
|
+
html: { extensions: [".html"], icon: "html", color: "#e34c26" },
|
|
179
|
+
markdown: { extensions: [".md", ".mdx"], icon: "md", color: "#083fa1" }
|
|
180
|
+
},
|
|
181
|
+
extensions: []
|
|
182
|
+
};
|
|
183
|
+
function useExtensions(options) {
|
|
184
|
+
const { appId, loadOnMount = true } = options;
|
|
185
|
+
const [extensions, setExtensions] = useState([]);
|
|
186
|
+
const [manifest] = useState(defaultManifest);
|
|
187
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
188
|
+
const [error, setError] = useState(null);
|
|
189
|
+
const loadExtension = useCallback(async (extensionId) => {
|
|
190
|
+
log2.debug("Loading extension", { extensionId });
|
|
191
|
+
}, []);
|
|
192
|
+
const loadExtensions = useCallback(async () => {
|
|
193
|
+
setIsLoading(true);
|
|
194
|
+
setError(null);
|
|
195
|
+
try {
|
|
196
|
+
const defaultExtensions = [
|
|
197
|
+
{ id: "typescript", name: "TypeScript", language: "typescript", loaded: true },
|
|
198
|
+
{ id: "javascript", name: "JavaScript", language: "javascript", loaded: true },
|
|
199
|
+
{ id: "json", name: "JSON", language: "json", loaded: true },
|
|
200
|
+
{ id: "css", name: "CSS", language: "css", loaded: true },
|
|
201
|
+
{ id: "html", name: "HTML", language: "html", loaded: true },
|
|
202
|
+
{ id: "markdown", name: "Markdown", language: "markdown", loaded: true }
|
|
203
|
+
];
|
|
204
|
+
setExtensions(defaultExtensions);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
setError(err instanceof Error ? err.message : "Failed to load extensions");
|
|
207
|
+
} finally {
|
|
208
|
+
setIsLoading(false);
|
|
209
|
+
}
|
|
210
|
+
}, []);
|
|
211
|
+
const getExtensionForFile = useCallback((filename) => {
|
|
212
|
+
const ext = filename.split(".").pop()?.toLowerCase();
|
|
213
|
+
if (!ext) return null;
|
|
214
|
+
const languageMap = {
|
|
215
|
+
ts: "typescript",
|
|
216
|
+
tsx: "typescript",
|
|
217
|
+
js: "javascript",
|
|
218
|
+
jsx: "javascript",
|
|
219
|
+
json: "json",
|
|
220
|
+
md: "markdown",
|
|
221
|
+
css: "css",
|
|
222
|
+
html: "html",
|
|
223
|
+
orb: "json"
|
|
224
|
+
};
|
|
225
|
+
const language = languageMap[ext];
|
|
226
|
+
if (!language) return null;
|
|
227
|
+
return extensions.find((e) => e.language === language) || null;
|
|
228
|
+
}, [extensions]);
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
if (!appId || !loadOnMount) return;
|
|
231
|
+
const loadExtensions2 = async () => {
|
|
232
|
+
setIsLoading(true);
|
|
233
|
+
setError(null);
|
|
234
|
+
try {
|
|
235
|
+
const defaultExtensions = [
|
|
236
|
+
{ id: "typescript", name: "TypeScript", language: "typescript", loaded: true },
|
|
237
|
+
{ id: "javascript", name: "JavaScript", language: "javascript", loaded: true },
|
|
238
|
+
{ id: "json", name: "JSON", language: "json", loaded: true },
|
|
239
|
+
{ id: "css", name: "CSS", language: "css", loaded: true },
|
|
240
|
+
{ id: "html", name: "HTML", language: "html", loaded: true },
|
|
241
|
+
{ id: "markdown", name: "Markdown", language: "markdown", loaded: true }
|
|
242
|
+
];
|
|
243
|
+
setExtensions(defaultExtensions);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
setError(err instanceof Error ? err.message : "Failed to load extensions");
|
|
246
|
+
} finally {
|
|
247
|
+
setIsLoading(false);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
loadExtensions2();
|
|
251
|
+
}, [appId, loadOnMount]);
|
|
252
|
+
return {
|
|
253
|
+
extensions,
|
|
254
|
+
manifest,
|
|
255
|
+
isLoading,
|
|
256
|
+
error,
|
|
257
|
+
loadExtension,
|
|
258
|
+
loadExtensions,
|
|
259
|
+
getExtensionForFile
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
var log3 = createLogger("almadar:ui:file-editor");
|
|
263
|
+
function parseSchemaText(text) {
|
|
264
|
+
try {
|
|
265
|
+
return JSON.parse(text);
|
|
266
|
+
} catch {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function useFileEditor(options) {
|
|
271
|
+
const { extensions, fileSystem, onSchemaUpdate } = options;
|
|
272
|
+
const [openFiles, setOpenFiles] = useState([]);
|
|
273
|
+
const [activeFilePath, setActiveFilePath] = useState(null);
|
|
274
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
275
|
+
const activeFile = openFiles.find((f) => f.path === activeFilePath) || null;
|
|
276
|
+
const openFile = useCallback(async (path) => {
|
|
277
|
+
const existing = openFiles.find((f) => f.path === path);
|
|
278
|
+
if (existing) {
|
|
279
|
+
setActiveFilePath(path);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const content = await fileSystem.readFile(path);
|
|
284
|
+
const ext = extensions.getExtensionForFile(path);
|
|
285
|
+
const newFile = {
|
|
286
|
+
path,
|
|
287
|
+
content,
|
|
288
|
+
isDirty: false,
|
|
289
|
+
language: ext?.language
|
|
290
|
+
};
|
|
291
|
+
setOpenFiles((prev) => [...prev, newFile]);
|
|
292
|
+
setActiveFilePath(path);
|
|
293
|
+
} catch (err) {
|
|
294
|
+
log3.error("Failed to open file", { error: err instanceof Error ? err : String(err) });
|
|
295
|
+
}
|
|
296
|
+
}, [openFiles, fileSystem, extensions]);
|
|
297
|
+
const closeFile = useCallback((path) => {
|
|
298
|
+
setOpenFiles((prev) => prev.filter((f) => f.path !== path));
|
|
299
|
+
if (activeFilePath === path) {
|
|
300
|
+
const remaining = openFiles.filter((f) => f.path !== path);
|
|
301
|
+
setActiveFilePath(remaining.length > 0 ? remaining[0].path : null);
|
|
302
|
+
}
|
|
303
|
+
}, [activeFilePath, openFiles]);
|
|
304
|
+
const setActiveFile = useCallback((path) => {
|
|
305
|
+
setActiveFilePath(path);
|
|
306
|
+
}, []);
|
|
307
|
+
const updateFileContent = useCallback((path, content) => {
|
|
308
|
+
setOpenFiles(
|
|
309
|
+
(prev) => prev.map(
|
|
310
|
+
(f) => f.path === path ? { ...f, content, isDirty: true } : f
|
|
311
|
+
)
|
|
312
|
+
);
|
|
313
|
+
}, []);
|
|
314
|
+
const handleFileEdit = useCallback(async (path, content) => {
|
|
315
|
+
try {
|
|
316
|
+
await fileSystem.writeFile(path, content);
|
|
317
|
+
let action = "saved";
|
|
318
|
+
if (path.endsWith(".orb") || path.endsWith("schema.json")) {
|
|
319
|
+
const schema = parseSchemaText(content);
|
|
320
|
+
if (schema !== null) {
|
|
321
|
+
await onSchemaUpdate?.(schema);
|
|
322
|
+
action = "updated_schema";
|
|
323
|
+
} else {
|
|
324
|
+
log3.warn("schema-file-not-json", { path });
|
|
325
|
+
}
|
|
326
|
+
} else if (path.includes("/extensions/")) {
|
|
327
|
+
action = path.endsWith(".new") ? "converted_extension" : "saved_extension";
|
|
328
|
+
}
|
|
329
|
+
return { success: true, action };
|
|
330
|
+
} catch (err) {
|
|
331
|
+
return {
|
|
332
|
+
success: false,
|
|
333
|
+
error: err instanceof Error ? err.message : "Failed to save file"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}, [fileSystem, onSchemaUpdate]);
|
|
337
|
+
const saveFile = useCallback(async (path) => {
|
|
338
|
+
const file = openFiles.find((f) => f.path === path);
|
|
339
|
+
if (!file) return;
|
|
340
|
+
setIsSaving(true);
|
|
341
|
+
try {
|
|
342
|
+
await fileSystem.writeFile(path, file.content);
|
|
343
|
+
setOpenFiles(
|
|
344
|
+
(prev) => prev.map(
|
|
345
|
+
(f) => f.path === path ? { ...f, isDirty: false } : f
|
|
346
|
+
)
|
|
347
|
+
);
|
|
348
|
+
if (path.endsWith(".orb") || path.endsWith("schema.json")) {
|
|
349
|
+
const schema = parseSchemaText(file.content);
|
|
350
|
+
if (schema !== null) await onSchemaUpdate?.(schema);
|
|
351
|
+
else log3.warn("schema-file-not-json", { path });
|
|
352
|
+
}
|
|
353
|
+
} catch (err) {
|
|
354
|
+
log3.error("Failed to save file", { error: err instanceof Error ? err : String(err) });
|
|
355
|
+
} finally {
|
|
356
|
+
setIsSaving(false);
|
|
357
|
+
}
|
|
358
|
+
}, [openFiles, fileSystem, onSchemaUpdate]);
|
|
359
|
+
const saveAllFiles = useCallback(async () => {
|
|
360
|
+
setIsSaving(true);
|
|
361
|
+
try {
|
|
362
|
+
const dirtyFiles = openFiles.filter((f) => f.isDirty);
|
|
363
|
+
for (const file of dirtyFiles) {
|
|
364
|
+
await saveFile(file.path);
|
|
365
|
+
}
|
|
366
|
+
} finally {
|
|
367
|
+
setIsSaving(false);
|
|
368
|
+
}
|
|
369
|
+
}, [openFiles, saveFile]);
|
|
370
|
+
return {
|
|
371
|
+
openFiles,
|
|
372
|
+
activeFile,
|
|
373
|
+
isSaving,
|
|
374
|
+
openFile,
|
|
375
|
+
closeFile,
|
|
376
|
+
setActiveFile,
|
|
377
|
+
updateFileContent,
|
|
378
|
+
handleFileEdit,
|
|
379
|
+
saveFile,
|
|
380
|
+
saveAllFiles
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
var log4 = createLogger("almadar:ui:compile");
|
|
384
|
+
function useCompile() {
|
|
385
|
+
const [isCompiling, setIsCompiling] = useState(false);
|
|
386
|
+
const [stage, setStage] = useState("idle");
|
|
387
|
+
const [lastResult, setLastResult] = useState(null);
|
|
388
|
+
const [error, setError] = useState(null);
|
|
389
|
+
const compileSchema = useCallback(async (schema) => {
|
|
390
|
+
setIsCompiling(true);
|
|
391
|
+
setStage("compiling");
|
|
392
|
+
setError(null);
|
|
393
|
+
try {
|
|
394
|
+
log4.debug("Compiling schema", { name: schema.name });
|
|
395
|
+
const result = {
|
|
396
|
+
success: true,
|
|
397
|
+
files: []
|
|
398
|
+
};
|
|
399
|
+
setLastResult(result);
|
|
400
|
+
setStage("done");
|
|
401
|
+
return result;
|
|
402
|
+
} catch (err) {
|
|
403
|
+
const errorMessage = err instanceof Error ? err.message : "Compilation failed";
|
|
404
|
+
setError(errorMessage);
|
|
405
|
+
setStage("error");
|
|
406
|
+
setLastResult({ success: false, errors: [errorMessage] });
|
|
407
|
+
return null;
|
|
408
|
+
} finally {
|
|
409
|
+
setIsCompiling(false);
|
|
410
|
+
}
|
|
411
|
+
}, []);
|
|
412
|
+
return {
|
|
413
|
+
isCompiling,
|
|
414
|
+
stage,
|
|
415
|
+
lastResult,
|
|
416
|
+
error,
|
|
417
|
+
compileSchema
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
var log5 = createLogger("almadar:ui:preview");
|
|
421
|
+
function usePreview(options) {
|
|
422
|
+
const [previewUrl, setPreviewUrl] = useState(null);
|
|
423
|
+
const [isLoading, setIsLoading] = useState(!!options?.appId);
|
|
424
|
+
const [error, setError] = useState(null);
|
|
425
|
+
const [loadError, setLoadError] = useState(null);
|
|
426
|
+
const [app, setApp] = useState(null);
|
|
427
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
428
|
+
const [isExecutingEvent, setIsExecutingEvent] = useState(false);
|
|
429
|
+
const [errorToast, setErrorToast] = useState(null);
|
|
430
|
+
const [currentStateName, setCurrentStateName] = useState(null);
|
|
431
|
+
const [notificationsList, setNotificationsList] = useState([]);
|
|
432
|
+
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
|
433
|
+
const notifications = useMemo(() => ({
|
|
434
|
+
notifications: notificationsList,
|
|
435
|
+
isPanelOpen,
|
|
436
|
+
closePanel: () => setIsPanelOpen(false),
|
|
437
|
+
dismissNotification: (id) => {
|
|
438
|
+
setNotificationsList((prev) => prev.filter((n) => n.id !== id));
|
|
439
|
+
},
|
|
440
|
+
markAsRead: (id) => {
|
|
441
|
+
setNotificationsList(
|
|
442
|
+
(prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n)
|
|
443
|
+
);
|
|
444
|
+
},
|
|
445
|
+
clearAll: () => setNotificationsList([])
|
|
446
|
+
}), [notificationsList, isPanelOpen]);
|
|
447
|
+
useEffect(() => {
|
|
448
|
+
const appId = options?.appId;
|
|
449
|
+
if (!appId) {
|
|
450
|
+
setApp(null);
|
|
451
|
+
setIsLoading(false);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
log5.debug("Setting up preview for app", { appId });
|
|
455
|
+
setPreviewUrl(`/api/orbitals/${appId}`);
|
|
456
|
+
setIsLoading(false);
|
|
457
|
+
}, [options?.appId]);
|
|
458
|
+
const startPreview = useCallback(async () => {
|
|
459
|
+
log5.debug("startPreview called");
|
|
460
|
+
}, []);
|
|
461
|
+
const stopPreview = useCallback(async () => {
|
|
462
|
+
setIsLoading(true);
|
|
463
|
+
try {
|
|
464
|
+
log5.debug("Stopping preview server");
|
|
465
|
+
setPreviewUrl(null);
|
|
466
|
+
setApp(null);
|
|
467
|
+
} finally {
|
|
468
|
+
setIsLoading(false);
|
|
469
|
+
}
|
|
470
|
+
}, []);
|
|
471
|
+
const refresh = useCallback(async () => {
|
|
472
|
+
if (!previewUrl) return;
|
|
473
|
+
log5.debug("Refreshing preview");
|
|
474
|
+
setPreviewUrl(`${previewUrl.split("?")[0]}?t=${Date.now()}`);
|
|
475
|
+
}, [previewUrl]);
|
|
476
|
+
const handleRefresh = useCallback(async () => {
|
|
477
|
+
log5.debug("Handle refresh");
|
|
478
|
+
await refresh();
|
|
479
|
+
}, [refresh]);
|
|
480
|
+
const handleReset = useCallback(async () => {
|
|
481
|
+
log5.debug("Resetting preview");
|
|
482
|
+
setError(null);
|
|
483
|
+
setLoadError(null);
|
|
484
|
+
setErrorToast(null);
|
|
485
|
+
setIsExecutingEvent(false);
|
|
486
|
+
setCurrentStateName(null);
|
|
487
|
+
}, []);
|
|
488
|
+
const toggleFullscreen = useCallback(() => {
|
|
489
|
+
setIsFullscreen((prev) => !prev);
|
|
490
|
+
}, []);
|
|
491
|
+
const dismissErrorToast = useCallback(() => {
|
|
492
|
+
setErrorToast(null);
|
|
493
|
+
}, []);
|
|
494
|
+
return {
|
|
495
|
+
previewUrl,
|
|
496
|
+
isLoading,
|
|
497
|
+
error,
|
|
498
|
+
loadError,
|
|
499
|
+
app,
|
|
500
|
+
isFullscreen,
|
|
501
|
+
isExecutingEvent,
|
|
502
|
+
errorToast,
|
|
503
|
+
currentStateName,
|
|
504
|
+
notifications,
|
|
505
|
+
startPreview,
|
|
506
|
+
stopPreview,
|
|
507
|
+
refresh,
|
|
508
|
+
handleRefresh,
|
|
509
|
+
handleReset,
|
|
510
|
+
toggleFullscreen,
|
|
511
|
+
setErrorToast,
|
|
512
|
+
dismissErrorToast
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
var log6 = createLogger("almadar:ui:agent-chat");
|
|
516
|
+
function useAgentChat(options) {
|
|
517
|
+
const [messages, setMessages] = useState([]);
|
|
518
|
+
const [status, setStatus] = useState("idle");
|
|
519
|
+
const [activities, setActivities] = useState([]);
|
|
520
|
+
const [todos, setTodos] = useState([]);
|
|
521
|
+
const [schemaDiffs, setSchemaDiffs] = useState([]);
|
|
522
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
523
|
+
const [error, setError] = useState(null);
|
|
524
|
+
const [threadId] = useState(null);
|
|
525
|
+
const [interrupt, setInterrupt] = useState(null);
|
|
526
|
+
const sendMessage = useCallback(async (content) => {
|
|
527
|
+
setIsLoading(true);
|
|
528
|
+
setStatus("running");
|
|
529
|
+
setError(null);
|
|
530
|
+
try {
|
|
531
|
+
const userMessage = {
|
|
532
|
+
id: Date.now().toString(),
|
|
533
|
+
role: "user",
|
|
534
|
+
content,
|
|
535
|
+
timestamp: Date.now()
|
|
536
|
+
};
|
|
537
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
538
|
+
log6.debug("Sending message", { content });
|
|
539
|
+
const assistantMessage = {
|
|
540
|
+
id: (Date.now() + 1).toString(),
|
|
541
|
+
role: "assistant",
|
|
542
|
+
content: "Agent chat is not yet implemented.",
|
|
543
|
+
timestamp: Date.now()
|
|
544
|
+
};
|
|
545
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
546
|
+
setStatus("idle");
|
|
547
|
+
options?.onComplete?.();
|
|
548
|
+
} catch (err) {
|
|
549
|
+
setError(err instanceof Error ? err.message : "Failed to send message");
|
|
550
|
+
setStatus("error");
|
|
551
|
+
} finally {
|
|
552
|
+
setIsLoading(false);
|
|
553
|
+
}
|
|
554
|
+
}, [options]);
|
|
555
|
+
const startGeneration = useCallback(async (skill, prompt, genOptions) => {
|
|
556
|
+
setStatus("running");
|
|
557
|
+
setIsLoading(true);
|
|
558
|
+
setError(null);
|
|
559
|
+
const skillName = Array.isArray(skill) ? skill[0] : skill;
|
|
560
|
+
try {
|
|
561
|
+
log6.debug("Starting generation", () => ({ skillName, prompt, genOptions: JSON.stringify(genOptions) }));
|
|
562
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
563
|
+
setStatus("complete");
|
|
564
|
+
options?.onComplete?.();
|
|
565
|
+
} catch (err) {
|
|
566
|
+
setError(err instanceof Error ? err.message : "Generation failed");
|
|
567
|
+
setStatus("error");
|
|
568
|
+
} finally {
|
|
569
|
+
setIsLoading(false);
|
|
570
|
+
}
|
|
571
|
+
}, [options]);
|
|
572
|
+
const continueConversation = useCallback(async (message) => {
|
|
573
|
+
log6.debug("Continue conversation", { message: Array.isArray(message) ? message : [message] });
|
|
574
|
+
}, []);
|
|
575
|
+
const resumeWithDecision = useCallback(async (decisions) => {
|
|
576
|
+
log6.debug("Resume with decision", () => ({ decisions: JSON.stringify(decisions), count: decisions.length }));
|
|
577
|
+
setInterrupt(null);
|
|
578
|
+
}, []);
|
|
579
|
+
const cancel = useCallback(() => {
|
|
580
|
+
setStatus("idle");
|
|
581
|
+
setIsLoading(false);
|
|
582
|
+
setInterrupt(null);
|
|
583
|
+
}, []);
|
|
584
|
+
const clearMessages = useCallback(() => {
|
|
585
|
+
setMessages([]);
|
|
586
|
+
}, []);
|
|
587
|
+
const clearHistory = useCallback(() => {
|
|
588
|
+
setMessages([]);
|
|
589
|
+
setActivities([]);
|
|
590
|
+
setTodos([]);
|
|
591
|
+
setSchemaDiffs([]);
|
|
592
|
+
setError(null);
|
|
593
|
+
}, []);
|
|
594
|
+
return {
|
|
595
|
+
messages,
|
|
596
|
+
status,
|
|
597
|
+
activities,
|
|
598
|
+
todos,
|
|
599
|
+
schemaDiffs,
|
|
600
|
+
isLoading,
|
|
601
|
+
error,
|
|
602
|
+
threadId,
|
|
603
|
+
interrupt,
|
|
604
|
+
sendMessage,
|
|
605
|
+
startGeneration,
|
|
606
|
+
continueConversation,
|
|
607
|
+
resumeWithDecision,
|
|
608
|
+
cancel,
|
|
609
|
+
clearMessages,
|
|
610
|
+
clearHistory
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
var log7 = createLogger("almadar:ui:validation");
|
|
614
|
+
function useValidation() {
|
|
615
|
+
const [result, setResult] = useState(null);
|
|
616
|
+
const [isValidating, setIsValidating] = useState(false);
|
|
617
|
+
const [error, setError] = useState(null);
|
|
618
|
+
const [stage, setStage] = useState("idle");
|
|
619
|
+
const [isFixing, setIsFixing] = useState(false);
|
|
620
|
+
const [progressMessage, setProgressMessage] = useState(null);
|
|
621
|
+
const validate = useCallback(async (appId) => {
|
|
622
|
+
setIsValidating(true);
|
|
623
|
+
setError(null);
|
|
624
|
+
setStage("validating");
|
|
625
|
+
setProgressMessage("Validating schema...");
|
|
626
|
+
try {
|
|
627
|
+
log7.debug("Validating app", { appId });
|
|
628
|
+
const validationResult = {
|
|
629
|
+
valid: true,
|
|
630
|
+
errors: [],
|
|
631
|
+
warnings: []
|
|
632
|
+
};
|
|
633
|
+
setResult(validationResult);
|
|
634
|
+
setStage("complete");
|
|
635
|
+
setProgressMessage(null);
|
|
636
|
+
return validationResult;
|
|
637
|
+
} catch (err) {
|
|
638
|
+
const errorMessage = err instanceof Error ? err.message : "Validation failed";
|
|
639
|
+
setError(errorMessage);
|
|
640
|
+
const failedResult = {
|
|
641
|
+
valid: false,
|
|
642
|
+
errors: [{ code: "VALIDATION_ERROR", message: errorMessage, severity: "error" }],
|
|
643
|
+
warnings: []
|
|
644
|
+
};
|
|
645
|
+
setResult(failedResult);
|
|
646
|
+
setStage("complete");
|
|
647
|
+
setProgressMessage(null);
|
|
648
|
+
return failedResult;
|
|
649
|
+
} finally {
|
|
650
|
+
setIsValidating(false);
|
|
651
|
+
}
|
|
652
|
+
}, []);
|
|
653
|
+
const clearResult = useCallback(() => {
|
|
654
|
+
setResult(null);
|
|
655
|
+
setError(null);
|
|
656
|
+
}, []);
|
|
657
|
+
const reset = useCallback(() => {
|
|
658
|
+
setResult(null);
|
|
659
|
+
setError(null);
|
|
660
|
+
setStage("idle");
|
|
661
|
+
setIsFixing(false);
|
|
662
|
+
setProgressMessage(null);
|
|
663
|
+
setIsValidating(false);
|
|
664
|
+
}, []);
|
|
665
|
+
return {
|
|
666
|
+
result,
|
|
667
|
+
isValidating,
|
|
668
|
+
error,
|
|
669
|
+
stage,
|
|
670
|
+
isFixing,
|
|
671
|
+
progressMessage,
|
|
672
|
+
errors: result?.errors ?? [],
|
|
673
|
+
warnings: result?.warnings ?? [],
|
|
674
|
+
isValid: result?.valid ?? false,
|
|
675
|
+
validate,
|
|
676
|
+
clearResult,
|
|
677
|
+
reset
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
var log8 = createLogger("almadar:ui:deep-agent");
|
|
681
|
+
function useDeepAgentGeneration() {
|
|
682
|
+
const [requests, setRequests] = useState([]);
|
|
683
|
+
const [currentRequest, setCurrentRequest] = useState(null);
|
|
684
|
+
const [isGenerating, setIsGenerating] = useState(false);
|
|
685
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
686
|
+
const [isComplete, setIsComplete] = useState(false);
|
|
687
|
+
const [progress, setProgress] = useState({ stage: "idle", percent: 0, message: "" });
|
|
688
|
+
const [error, setError] = useState(null);
|
|
689
|
+
const [interrupt, setInterrupt] = useState(null);
|
|
690
|
+
const generate = useCallback(async (prompt) => {
|
|
691
|
+
setIsGenerating(true);
|
|
692
|
+
setIsLoading(true);
|
|
693
|
+
setIsComplete(false);
|
|
694
|
+
setError(null);
|
|
695
|
+
setProgress({ stage: "starting", percent: 0, message: "Starting generation..." });
|
|
696
|
+
const request = {
|
|
697
|
+
id: Date.now().toString(),
|
|
698
|
+
prompt,
|
|
699
|
+
status: "running"
|
|
700
|
+
};
|
|
701
|
+
setCurrentRequest(request);
|
|
702
|
+
setRequests((prev) => [...prev, request]);
|
|
703
|
+
try {
|
|
704
|
+
log8.debug("Generating from prompt", { prompt });
|
|
705
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
706
|
+
request.status = "completed";
|
|
707
|
+
setCurrentRequest(request);
|
|
708
|
+
setIsComplete(true);
|
|
709
|
+
setProgress({ stage: "complete", percent: 100, message: "Generation complete" });
|
|
710
|
+
return null;
|
|
711
|
+
} catch (err) {
|
|
712
|
+
const errorMessage = err instanceof Error ? err.message : "Generation failed";
|
|
713
|
+
setError(errorMessage);
|
|
714
|
+
request.status = "failed";
|
|
715
|
+
request.error = errorMessage;
|
|
716
|
+
setCurrentRequest(request);
|
|
717
|
+
return null;
|
|
718
|
+
} finally {
|
|
719
|
+
setIsGenerating(false);
|
|
720
|
+
setIsLoading(false);
|
|
721
|
+
}
|
|
722
|
+
}, []);
|
|
723
|
+
const startGeneration = useCallback(async (skill, prompt, _options) => {
|
|
724
|
+
log8.debug("Starting generation with skill", { skill });
|
|
725
|
+
await generate(prompt);
|
|
726
|
+
}, [generate]);
|
|
727
|
+
const cancelGeneration = useCallback(() => {
|
|
728
|
+
if (currentRequest) {
|
|
729
|
+
currentRequest.status = "failed";
|
|
730
|
+
currentRequest.error = "Cancelled by user";
|
|
731
|
+
setCurrentRequest(null);
|
|
732
|
+
}
|
|
733
|
+
setIsGenerating(false);
|
|
734
|
+
setIsLoading(false);
|
|
735
|
+
setIsComplete(false);
|
|
736
|
+
setProgress({ stage: "idle", percent: 0, message: "" });
|
|
737
|
+
}, [currentRequest]);
|
|
738
|
+
const clearRequests = useCallback(() => {
|
|
739
|
+
setRequests([]);
|
|
740
|
+
setCurrentRequest(null);
|
|
741
|
+
setError(null);
|
|
742
|
+
setProgress({ stage: "idle", percent: 0, message: "" });
|
|
743
|
+
setIsComplete(false);
|
|
744
|
+
}, []);
|
|
745
|
+
const submitInterruptDecisions = useCallback((decisions) => {
|
|
746
|
+
log8.debug("Submitting interrupt decisions", () => ({ decisions: JSON.stringify(decisions), count: decisions.length }));
|
|
747
|
+
setInterrupt(null);
|
|
748
|
+
}, []);
|
|
749
|
+
return {
|
|
750
|
+
requests,
|
|
751
|
+
currentRequest,
|
|
752
|
+
isGenerating,
|
|
753
|
+
isLoading,
|
|
754
|
+
isComplete,
|
|
755
|
+
progress,
|
|
756
|
+
error,
|
|
757
|
+
interrupt,
|
|
758
|
+
generate,
|
|
759
|
+
startGeneration,
|
|
760
|
+
cancelGeneration,
|
|
761
|
+
clearRequests,
|
|
762
|
+
submitInterruptDecisions
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
var UI_PREFIX = "UI:";
|
|
766
|
+
function useUIEvents(dispatch, traitName, validEvents, eventBusInstance) {
|
|
767
|
+
const defaultEventBus = useEventBus();
|
|
768
|
+
const eventBus = eventBusInstance ?? defaultEventBus;
|
|
769
|
+
const validEventsKey = validEvents.slice().sort().join(",");
|
|
770
|
+
const stableValidEvents = useMemo(
|
|
771
|
+
() => validEvents,
|
|
772
|
+
[validEventsKey]
|
|
773
|
+
// intentional — validEventsKey is the stable dep
|
|
774
|
+
);
|
|
775
|
+
useEffect(() => {
|
|
776
|
+
const unsubscribes = [];
|
|
777
|
+
for (const smEvent of stableValidEvents) {
|
|
778
|
+
const handler = (event) => {
|
|
779
|
+
if (event.source && event.source.dispatched) {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (!claimDelivery(event.source, traitName, smEvent)) return;
|
|
783
|
+
const pendingKey = event.source?.pendingKey;
|
|
784
|
+
const settled = dispatch(smEvent, event.payload);
|
|
785
|
+
if (pendingKey !== void 0 && settled instanceof Promise) {
|
|
786
|
+
beginPending(pendingKey);
|
|
787
|
+
void settled.finally(() => endPending(pendingKey));
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
unsubscribes.push(
|
|
791
|
+
eventBus.on(`${UI_PREFIX}${traitName}.${smEvent}`, handler)
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
return () => {
|
|
795
|
+
for (const unsub of unsubscribes) {
|
|
796
|
+
if (typeof unsub === "function") unsub();
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
}, [eventBus, dispatch, traitName, stableValidEvents]);
|
|
800
|
+
}
|
|
801
|
+
function useTraitListens(dispatch, listens, eventBusInstance) {
|
|
802
|
+
const defaultEventBus = useEventBus();
|
|
803
|
+
const eventBus = eventBusInstance ?? defaultEventBus;
|
|
804
|
+
const stableKey = listens.map((l) => `${l.sourceKey}->${l.trigger}`).sort().join("|");
|
|
805
|
+
const stableListens = useMemo(
|
|
806
|
+
() => listens,
|
|
807
|
+
[stableKey]
|
|
808
|
+
// intentional
|
|
809
|
+
);
|
|
810
|
+
useEffect(() => {
|
|
811
|
+
const unsubscribes = [];
|
|
812
|
+
for (const spec of stableListens) {
|
|
813
|
+
const handler = (event) => {
|
|
814
|
+
dispatch(spec.trigger, event.payload);
|
|
815
|
+
};
|
|
816
|
+
unsubscribes.push(eventBus.on(`${UI_PREFIX}${spec.sourceKey}`, handler));
|
|
817
|
+
}
|
|
818
|
+
return () => {
|
|
819
|
+
for (const unsub of unsubscribes) {
|
|
820
|
+
if (typeof unsub === "function") unsub();
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
}, [eventBus, dispatch, stableListens]);
|
|
824
|
+
}
|
|
825
|
+
var log9 = createLogger("almadar:ui:shared-entity-store");
|
|
826
|
+
var EMPTY_ENTITY_STATE = {};
|
|
827
|
+
function createSharedEntityStore() {
|
|
828
|
+
const states = /* @__PURE__ */ new Map();
|
|
829
|
+
const subscribers = /* @__PURE__ */ new Map();
|
|
830
|
+
const getSnapshot = (entityId) => states.get(entityId) ?? EMPTY_ENTITY_STATE;
|
|
831
|
+
const subscribe = (entityId, callback) => {
|
|
832
|
+
let set = subscribers.get(entityId);
|
|
833
|
+
if (!set) {
|
|
834
|
+
set = /* @__PURE__ */ new Set();
|
|
835
|
+
subscribers.set(entityId, set);
|
|
836
|
+
}
|
|
837
|
+
set.add(callback);
|
|
838
|
+
return () => {
|
|
839
|
+
const current = subscribers.get(entityId);
|
|
840
|
+
if (!current) return;
|
|
841
|
+
current.delete(callback);
|
|
842
|
+
if (current.size === 0) {
|
|
843
|
+
subscribers.delete(entityId);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
};
|
|
847
|
+
const commit = (entityId, nextState) => {
|
|
848
|
+
states.set(entityId, nextState);
|
|
849
|
+
const set = subscribers.get(entityId);
|
|
850
|
+
if (!set) return;
|
|
851
|
+
set.forEach((callback) => {
|
|
852
|
+
try {
|
|
853
|
+
callback();
|
|
854
|
+
} catch (error) {
|
|
855
|
+
log9.error("Shared entity subscriber error", {
|
|
856
|
+
entityId,
|
|
857
|
+
error: error instanceof Error ? error : String(error)
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
};
|
|
862
|
+
const seed = (entityId, initialState) => {
|
|
863
|
+
if (!states.has(entityId)) {
|
|
864
|
+
states.set(entityId, initialState);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
return { getSnapshot, subscribe, commit, seed };
|
|
868
|
+
}
|
|
869
|
+
function useSharedEntityStore() {
|
|
870
|
+
const storeRef = useRef(null);
|
|
871
|
+
if (storeRef.current === null) {
|
|
872
|
+
storeRef.current = createSharedEntityStore();
|
|
873
|
+
}
|
|
874
|
+
return storeRef.current;
|
|
875
|
+
}
|
|
876
|
+
var SharedEntityStoreContext = createContext(null);
|
|
877
|
+
function useSharedEntityStoreContext() {
|
|
878
|
+
const store = useContext(SharedEntityStoreContext);
|
|
879
|
+
if (!store) {
|
|
880
|
+
throw new Error(
|
|
881
|
+
"useSharedEntityStoreContext: no SharedEntityStoreContext.Provider found in the component tree"
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
return store;
|
|
885
|
+
}
|
|
886
|
+
function useSharedEntitySnapshot(store, entityId) {
|
|
887
|
+
return useSyncExternalStore(
|
|
888
|
+
(onStoreChange) => store.subscribe(entityId, onStoreChange),
|
|
889
|
+
() => store.getSnapshot(entityId)
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
function runTickFrame(entityId, orderedWriters, store) {
|
|
893
|
+
let scratch = store.getSnapshot(entityId);
|
|
894
|
+
for (const writer of orderedWriters) {
|
|
895
|
+
const writes = writer(scratch);
|
|
896
|
+
scratch = mergeEntityFrame(scratch, writes);
|
|
897
|
+
}
|
|
898
|
+
store.commit(entityId, scratch);
|
|
899
|
+
return scratch;
|
|
900
|
+
}
|
|
901
|
+
var log10 = createLogger("almadar:ui:render-interpolation");
|
|
902
|
+
function useRenderInterpolation(options = {}) {
|
|
903
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
904
|
+
const prevRef = useRef(null);
|
|
905
|
+
const currRef = useRef(null);
|
|
906
|
+
const rafRef = useRef(null);
|
|
907
|
+
const onSnapshot = useCallback((entities) => {
|
|
908
|
+
prevRef.current = currRef.current;
|
|
909
|
+
currRef.current = { entities, arrivedAt: performance.now() };
|
|
910
|
+
}, []);
|
|
911
|
+
const getInterpolated = useCallback((now) => {
|
|
912
|
+
const out = /* @__PURE__ */ new Map();
|
|
913
|
+
const curr = currRef.current;
|
|
914
|
+
if (!curr) return out;
|
|
915
|
+
const prev = prevRef.current;
|
|
916
|
+
if (!prev) {
|
|
917
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
918
|
+
return out;
|
|
919
|
+
}
|
|
920
|
+
const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
|
|
921
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
922
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
923
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
924
|
+
for (const c of curr.entities) {
|
|
925
|
+
const p = prevMap.get(c.id);
|
|
926
|
+
if (!p) {
|
|
927
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
928
|
+
} else {
|
|
929
|
+
out.set(c.id, {
|
|
930
|
+
x: p.x + (c.x - p.x) * alpha,
|
|
931
|
+
y: p.y + (c.y - p.y) * alpha
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return out;
|
|
936
|
+
}, [tickIntervalMs]);
|
|
937
|
+
const startLoop = useCallback(
|
|
938
|
+
(draw) => {
|
|
939
|
+
let active = true;
|
|
940
|
+
let reported = false;
|
|
941
|
+
const loop = () => {
|
|
942
|
+
if (!active) return;
|
|
943
|
+
try {
|
|
944
|
+
draw(getInterpolated(performance.now()));
|
|
945
|
+
} catch (error) {
|
|
946
|
+
if (!reported) log10.error("draw-failed", { error: error instanceof Error ? error.message : String(error) });
|
|
947
|
+
reported = true;
|
|
948
|
+
}
|
|
949
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
950
|
+
};
|
|
951
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
952
|
+
return () => {
|
|
953
|
+
active = false;
|
|
954
|
+
if (rafRef.current !== null) {
|
|
955
|
+
cancelAnimationFrame(rafRef.current);
|
|
956
|
+
rafRef.current = null;
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
},
|
|
960
|
+
[getInterpolated]
|
|
961
|
+
);
|
|
962
|
+
useEffect(() => {
|
|
963
|
+
return () => {
|
|
964
|
+
if (rafRef.current !== null) {
|
|
965
|
+
cancelAnimationFrame(rafRef.current);
|
|
966
|
+
rafRef.current = null;
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
}, []);
|
|
970
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
971
|
+
}
|
|
972
|
+
var API_BASE = typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
|
|
973
|
+
function getUserId() {
|
|
974
|
+
return localStorage.getItem("userId") || "anonymous";
|
|
975
|
+
}
|
|
976
|
+
async function fetchWithAuth(endpoint, options) {
|
|
977
|
+
const userId = getUserId();
|
|
978
|
+
const response = await fetch(`${API_BASE}${endpoint}`, {
|
|
979
|
+
...options,
|
|
980
|
+
headers: {
|
|
981
|
+
"Content-Type": "application/json",
|
|
982
|
+
"x-user-id": userId,
|
|
983
|
+
...options?.headers
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
if (!response.ok) {
|
|
987
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
988
|
+
throw new Error(error.error || error.message || "Request failed");
|
|
989
|
+
}
|
|
990
|
+
return response.json();
|
|
991
|
+
}
|
|
992
|
+
function useGitHubStatus() {
|
|
993
|
+
return useQuery({
|
|
994
|
+
queryKey: ["github", "status"],
|
|
995
|
+
queryFn: () => fetchWithAuth("/api/github/status"),
|
|
996
|
+
staleTime: 6e4,
|
|
997
|
+
// 1 minute
|
|
998
|
+
retry: false
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
function useConnectGitHub() {
|
|
1002
|
+
const connectGitHub = useCallback(() => {
|
|
1003
|
+
const userId = getUserId();
|
|
1004
|
+
const state = btoa(JSON.stringify({ userId, returnUrl: window.location.href }));
|
|
1005
|
+
window.location.href = `${API_BASE}/api/github/oauth/authorize?state=${state}`;
|
|
1006
|
+
}, []);
|
|
1007
|
+
return { connectGitHub };
|
|
1008
|
+
}
|
|
1009
|
+
function useDisconnectGitHub() {
|
|
1010
|
+
const queryClient = useQueryClient();
|
|
1011
|
+
return useMutation({
|
|
1012
|
+
mutationFn: () => fetchWithAuth("/api/github/disconnect", { method: "POST" }),
|
|
1013
|
+
onSuccess: () => {
|
|
1014
|
+
queryClient.invalidateQueries({ queryKey: ["github", "status"] });
|
|
1015
|
+
queryClient.removeQueries({ queryKey: ["github", "repos"] });
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
function useGitHubRepos(page = 1, perPage = 30) {
|
|
1020
|
+
return useQuery({
|
|
1021
|
+
queryKey: ["github", "repos", page, perPage],
|
|
1022
|
+
queryFn: () => fetchWithAuth(`/api/github/repos?page=${page}&per_page=${perPage}`),
|
|
1023
|
+
enabled: true,
|
|
1024
|
+
// Only fetch if user is connected
|
|
1025
|
+
staleTime: 3e5
|
|
1026
|
+
// 5 minutes
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
function useGitHubRepo(owner, repo, enabled = true) {
|
|
1030
|
+
return useQuery({
|
|
1031
|
+
queryKey: ["github", "repo", owner, repo],
|
|
1032
|
+
queryFn: () => fetchWithAuth(`/api/github/repos/${owner}/${repo}`),
|
|
1033
|
+
enabled: enabled && !!owner && !!repo,
|
|
1034
|
+
staleTime: 3e5
|
|
1035
|
+
// 5 minutes
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
function useGitHubBranches(owner, repo, enabled = true) {
|
|
1039
|
+
return useQuery({
|
|
1040
|
+
queryKey: ["github", "branches", owner, repo],
|
|
1041
|
+
queryFn: () => fetchWithAuth(`/api/github/repos/${owner}/${repo}/branches`),
|
|
1042
|
+
enabled: enabled && !!owner && !!repo,
|
|
1043
|
+
staleTime: 6e4
|
|
1044
|
+
// 1 minute
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function useTickVisibility(traits) {
|
|
1048
|
+
const key = traits.join("\0");
|
|
1049
|
+
useEffect(() => getTraitPresence().watch(key.split("\0")), [key]);
|
|
1050
|
+
return useCallback(() => getTraitPresence().state(key.split("\0")) !== "off-screen", [key]);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
export { SharedEntityStoreContext, createSharedEntityStore, runTickFrame, useAgentChat, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, usePreview, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useTickVisibility, useTraitListens, useUIEvents, useValidation };
|