@jkwd/inbase 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -2
- package/apps/explorer/scripts/session-store.d.ts +4 -0
- package/apps/explorer/scripts/session-store.mjs +16 -0
- package/apps/explorer/src/App.tsx +40 -9
- package/apps/explorer/src/codebase.ts +23 -5
- package/apps/explorer/src/index.css +190 -4
- package/apps/explorer/src/scene/Bridge.tsx +57 -20
- package/apps/explorer/src/scene/MapView.tsx +37 -8
- package/apps/explorer/src/scene/Player.tsx +106 -42
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +140 -8
- package/apps/explorer/src/scene/World.tsx +0 -3
- package/apps/explorer/src/types.ts +1 -0
- package/apps/explorer/src/ui/HUD.tsx +343 -90
- package/apps/explorer/vite.config.ts +13 -3
- package/package.json +1 -1
|
@@ -42,12 +42,18 @@ function symbolLabels(items: PatchSymbolAddition[]) {
|
|
|
42
42
|
}))
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
function importLabel(item: Pick<PatchImportAddition, 'name' | 'from'>) {
|
|
46
|
+
const from = fileBase(item.from)
|
|
47
|
+
return item.name === item.from || item.name === from
|
|
48
|
+
? from
|
|
49
|
+
: `${item.name} from ${from}`
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
function importLabels(items: PatchImportAddition[]) {
|
|
46
53
|
const files = new Set(items.map((item) => item.file))
|
|
47
54
|
const showFile = files.size > 1
|
|
48
55
|
return items.map((item) => {
|
|
49
|
-
const what =
|
|
50
|
-
item.name === item.from ? item.from : `${item.name} from ${item.from}`
|
|
56
|
+
const what = importLabel(item)
|
|
51
57
|
return {
|
|
52
58
|
key: `${item.file}:${item.name}:${item.from}`,
|
|
53
59
|
label: showFile ? `${what} · ${fileBase(item.file)}` : what,
|
|
@@ -692,6 +698,212 @@ function SessionPanel({
|
|
|
692
698
|
)
|
|
693
699
|
}
|
|
694
700
|
|
|
701
|
+
type ExplorerInstruction = {
|
|
702
|
+
id: string
|
|
703
|
+
keys: string[]
|
|
704
|
+
label: string
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
type InstructionView = 'walk' | '3dview' | 'map'
|
|
708
|
+
|
|
709
|
+
type ExplorerInstructionSection = {
|
|
710
|
+
id: InstructionView
|
|
711
|
+
title: string
|
|
712
|
+
items: ExplorerInstruction[]
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function InstructionList({ items }: { items: ExplorerInstruction[] }) {
|
|
716
|
+
return (
|
|
717
|
+
<ul className="hud-instructions-list">
|
|
718
|
+
{items.map((hint) => (
|
|
719
|
+
<li className="hud-instruction" key={hint.id}>
|
|
720
|
+
{hint.keys.length > 0 && (
|
|
721
|
+
<span className="hud-instruction-keys">
|
|
722
|
+
{hint.keys.map((key) => (
|
|
723
|
+
<kbd key={key}>{key}</kbd>
|
|
724
|
+
))}
|
|
725
|
+
</span>
|
|
726
|
+
)}
|
|
727
|
+
<span className="hud-instruction-label">{hint.label}</span>
|
|
728
|
+
</li>
|
|
729
|
+
))}
|
|
730
|
+
</ul>
|
|
731
|
+
)
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function explorerInstructions({
|
|
735
|
+
creatingBlueprint,
|
|
736
|
+
hasChangeSet,
|
|
737
|
+
changePathsOnly,
|
|
738
|
+
selectedUserCreated,
|
|
739
|
+
infoVisible,
|
|
740
|
+
thumbnailVisible,
|
|
741
|
+
importedBy,
|
|
742
|
+
canStop,
|
|
743
|
+
sessionCount,
|
|
744
|
+
}: {
|
|
745
|
+
creatingBlueprint: boolean
|
|
746
|
+
hasChangeSet: boolean
|
|
747
|
+
changePathsOnly: boolean
|
|
748
|
+
selectedUserCreated: boolean
|
|
749
|
+
infoVisible: boolean
|
|
750
|
+
thumbnailVisible: boolean
|
|
751
|
+
importedBy: boolean
|
|
752
|
+
canStop: boolean
|
|
753
|
+
sessionCount: number
|
|
754
|
+
}): ExplorerInstructionSection[] {
|
|
755
|
+
const backspace: ExplorerInstruction[] =
|
|
756
|
+
selectedUserCreated && creatingBlueprint
|
|
757
|
+
? [{ id: 'backspace', keys: ['Backspace'], label: 'Delete' }]
|
|
758
|
+
: []
|
|
759
|
+
const info: ExplorerInstruction[] = [
|
|
760
|
+
{
|
|
761
|
+
id: 'info',
|
|
762
|
+
keys: ['I'],
|
|
763
|
+
label: infoVisible ? 'Hide info' : 'Show info',
|
|
764
|
+
},
|
|
765
|
+
...(infoVisible
|
|
766
|
+
? [{ id: 'scroll-info', keys: ['↑', '↓'], label: 'Scroll info' }]
|
|
767
|
+
: []),
|
|
768
|
+
]
|
|
769
|
+
const imported: ExplorerInstruction = {
|
|
770
|
+
id: 'imported',
|
|
771
|
+
keys: ['K'],
|
|
772
|
+
label: importedBy ? 'Show imports' : 'Show imported by',
|
|
773
|
+
}
|
|
774
|
+
const stop: ExplorerInstruction[] = canStop
|
|
775
|
+
? [
|
|
776
|
+
{
|
|
777
|
+
id: 'stop',
|
|
778
|
+
keys: ['Stop'],
|
|
779
|
+
label:
|
|
780
|
+
sessionCount > 1
|
|
781
|
+
? 'Ends the focused LLM session'
|
|
782
|
+
: 'Ends this LLM session',
|
|
783
|
+
},
|
|
784
|
+
]
|
|
785
|
+
: []
|
|
786
|
+
const thumbnail: ExplorerInstruction = {
|
|
787
|
+
id: 'thumbnail',
|
|
788
|
+
keys: ['T'],
|
|
789
|
+
label: thumbnailVisible ? 'Hide 3D view' : 'Show 3D view',
|
|
790
|
+
}
|
|
791
|
+
return [
|
|
792
|
+
{
|
|
793
|
+
id: 'walk',
|
|
794
|
+
title: 'Walk',
|
|
795
|
+
items: [
|
|
796
|
+
{ id: 'wasd', keys: ['W', 'A', 'S', 'D'], label: 'Walk' },
|
|
797
|
+
{ id: 'mouse-look', keys: ['Mouse'], label: 'Look around' },
|
|
798
|
+
{ id: 'shift', keys: ['Shift'], label: 'Sprint' },
|
|
799
|
+
...(creatingBlueprint
|
|
800
|
+
? [
|
|
801
|
+
{ id: 'space', keys: ['Space'], label: 'Place file' },
|
|
802
|
+
{ id: 'b-island', keys: ['B'], label: 'Place island' },
|
|
803
|
+
]
|
|
804
|
+
: []),
|
|
805
|
+
...backspace,
|
|
806
|
+
{
|
|
807
|
+
id: 'dblclick-info',
|
|
808
|
+
keys: ['Double-click'],
|
|
809
|
+
label: 'A block for info',
|
|
810
|
+
},
|
|
811
|
+
{ id: 'aim-line', keys: ['Click'], label: 'Aim a line to fly' },
|
|
812
|
+
...info,
|
|
813
|
+
imported,
|
|
814
|
+
{
|
|
815
|
+
id: 'update-model',
|
|
816
|
+
keys: ['Update model'],
|
|
817
|
+
label: 'Rescan and rebuild the map',
|
|
818
|
+
},
|
|
819
|
+
{ id: 'toggle-map', keys: ['M'], label: 'Toggle map' },
|
|
820
|
+
{
|
|
821
|
+
id: 'release',
|
|
822
|
+
keys: ['Double-click', 'Esc'],
|
|
823
|
+
label: 'Release mouse',
|
|
824
|
+
},
|
|
825
|
+
...stop,
|
|
826
|
+
],
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
id: '3dview',
|
|
830
|
+
title: '3D view',
|
|
831
|
+
items: [
|
|
832
|
+
{ id: 'scroll-zoom', keys: ['Scroll'], label: 'Zoom' },
|
|
833
|
+
{ id: 'drag-pan', keys: ['Drag'], label: 'Pan' },
|
|
834
|
+
{
|
|
835
|
+
id: 'cmd-drag-rotate',
|
|
836
|
+
keys: ['⌘', 'Ctrl', 'Drag'],
|
|
837
|
+
label: 'Rotate',
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
id: 'dblclick-reset',
|
|
841
|
+
keys: ['Double-click'],
|
|
842
|
+
label: 'Reset view',
|
|
843
|
+
},
|
|
844
|
+
thumbnail,
|
|
845
|
+
],
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
id: 'map',
|
|
849
|
+
title: 'Map',
|
|
850
|
+
items: [
|
|
851
|
+
{ id: 'scroll-zoom', keys: ['Scroll'], label: 'Zoom' },
|
|
852
|
+
{ id: 'drag-pan', keys: ['Drag'], label: 'Pan' },
|
|
853
|
+
{ id: 'click-block', keys: ['Click'], label: 'A block for info' },
|
|
854
|
+
{
|
|
855
|
+
id: 'click-island',
|
|
856
|
+
keys: ['Click'],
|
|
857
|
+
label: 'An island for its files',
|
|
858
|
+
},
|
|
859
|
+
...(creatingBlueprint
|
|
860
|
+
? [
|
|
861
|
+
{ id: 'select-island', keys: ['Click'], label: 'Select an island' },
|
|
862
|
+
{
|
|
863
|
+
id: 'add-file-folder',
|
|
864
|
+
keys: [],
|
|
865
|
+
label: 'Add file / Add folder in panel',
|
|
866
|
+
},
|
|
867
|
+
]
|
|
868
|
+
: []),
|
|
869
|
+
{ id: 'click-line', keys: ['Click'], label: 'A line to fly there' },
|
|
870
|
+
{
|
|
871
|
+
id: 'ctrl-click-walk',
|
|
872
|
+
keys: ['Ctrl', 'Click'],
|
|
873
|
+
label: 'An island to walk',
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
id: 'gold-pin',
|
|
877
|
+
keys: [],
|
|
878
|
+
label: 'Gold pin is your walk position',
|
|
879
|
+
},
|
|
880
|
+
...(hasChangeSet
|
|
881
|
+
? [
|
|
882
|
+
{
|
|
883
|
+
id: 'toggle-paths',
|
|
884
|
+
keys: ['C'],
|
|
885
|
+
label: changePathsOnly
|
|
886
|
+
? 'Show all paths'
|
|
887
|
+
: 'Show only changed paths',
|
|
888
|
+
},
|
|
889
|
+
]
|
|
890
|
+
: []),
|
|
891
|
+
...backspace,
|
|
892
|
+
...info,
|
|
893
|
+
thumbnail,
|
|
894
|
+
imported,
|
|
895
|
+
{
|
|
896
|
+
id: 'update-model',
|
|
897
|
+
keys: ['Update model'],
|
|
898
|
+
label: 'Rescan and rebuild the map',
|
|
899
|
+
},
|
|
900
|
+
{ id: 'map-walk', keys: ['M'], label: 'Back to walk' },
|
|
901
|
+
...stop,
|
|
902
|
+
],
|
|
903
|
+
},
|
|
904
|
+
]
|
|
905
|
+
}
|
|
906
|
+
|
|
695
907
|
type HUDProps = {
|
|
696
908
|
graph: CodebaseGraph
|
|
697
909
|
layout: WorldLayout
|
|
@@ -704,7 +916,6 @@ type HUDProps = {
|
|
|
704
916
|
landAt: [number, number]
|
|
705
917
|
aimedRelation: AimedRelation | null
|
|
706
918
|
aimedFileId?: string | null
|
|
707
|
-
currentFolder: string
|
|
708
919
|
intent: AgentIntent
|
|
709
920
|
intents?: AgentIntent[]
|
|
710
921
|
focusedSessionId?: string | null
|
|
@@ -719,6 +930,8 @@ type HUDProps = {
|
|
|
719
930
|
onWalk: () => void
|
|
720
931
|
followLook: boolean
|
|
721
932
|
onToggleFollowLook: () => void
|
|
933
|
+
onUpdateModel: () => void
|
|
934
|
+
updatingModel?: boolean
|
|
722
935
|
importedBy: boolean
|
|
723
936
|
onToggleImportedBy: () => void
|
|
724
937
|
changePathsOnly?: boolean
|
|
@@ -762,7 +975,6 @@ export function HUD({
|
|
|
762
975
|
landAt,
|
|
763
976
|
aimedRelation,
|
|
764
977
|
aimedFileId = null,
|
|
765
|
-
currentFolder,
|
|
766
978
|
intent,
|
|
767
979
|
intents,
|
|
768
980
|
focusedSessionId = null,
|
|
@@ -773,6 +985,8 @@ export function HUD({
|
|
|
773
985
|
onWalk,
|
|
774
986
|
followLook,
|
|
775
987
|
onToggleFollowLook,
|
|
988
|
+
onUpdateModel,
|
|
989
|
+
updatingModel = false,
|
|
776
990
|
importedBy,
|
|
777
991
|
onToggleImportedBy,
|
|
778
992
|
changePathsOnly = false,
|
|
@@ -821,10 +1035,12 @@ export function HUD({
|
|
|
821
1035
|
const canStop = canStopSession(intent)
|
|
822
1036
|
const [walkIntro, setWalkIntro] = useState(false)
|
|
823
1037
|
const walkIntroSeen = useRef(false)
|
|
1038
|
+
const [instructionsOpen, setInstructionsOpen] = useState(false)
|
|
824
1039
|
const [infoVisible, setInfoVisible] = useState(false)
|
|
825
1040
|
const [infoMinimized, setInfoMinimized] = useState(false)
|
|
826
1041
|
const [thumbnailVisible, setThumbnailVisible] = useState(true)
|
|
827
1042
|
const [thumbnailMinimized, setThumbnailMinimized] = useState(false)
|
|
1043
|
+
const [thumbnailMaximized, setThumbnailMaximized] = useState(false)
|
|
828
1044
|
const infoPanelRef = useRef<HTMLDivElement>(null)
|
|
829
1045
|
const creatingBlueprint = sessions.some(
|
|
830
1046
|
(item) => item.creationMode || item.status === 'blueprint',
|
|
@@ -1000,7 +1216,12 @@ export function HUD({
|
|
|
1000
1216
|
}
|
|
1001
1217
|
event.preventDefault()
|
|
1002
1218
|
setThumbnailVisible((visible) => {
|
|
1003
|
-
if (!visible)
|
|
1219
|
+
if (!visible) {
|
|
1220
|
+
setThumbnailMinimized(false)
|
|
1221
|
+
setThumbnailMaximized(false)
|
|
1222
|
+
} else {
|
|
1223
|
+
setThumbnailMaximized(false)
|
|
1224
|
+
}
|
|
1004
1225
|
return !visible
|
|
1005
1226
|
})
|
|
1006
1227
|
}
|
|
@@ -1033,6 +1254,36 @@ export function HUD({
|
|
|
1033
1254
|
return () => window.removeEventListener('keydown', onKey, true)
|
|
1034
1255
|
}, [infoVisible, selectedId, selectedFolder])
|
|
1035
1256
|
|
|
1257
|
+
useEffect(() => {
|
|
1258
|
+
if (!instructionsOpen) return
|
|
1259
|
+
document.exitPointerLock()
|
|
1260
|
+
const onKey = (event: KeyboardEvent) => {
|
|
1261
|
+
if (event.code !== 'Escape') return
|
|
1262
|
+
event.preventDefault()
|
|
1263
|
+
event.stopPropagation()
|
|
1264
|
+
setInstructionsOpen(false)
|
|
1265
|
+
}
|
|
1266
|
+
window.addEventListener('keydown', onKey, true)
|
|
1267
|
+
return () => window.removeEventListener('keydown', onKey, true)
|
|
1268
|
+
}, [instructionsOpen])
|
|
1269
|
+
|
|
1270
|
+
const instructionSections = explorerInstructions({
|
|
1271
|
+
creatingBlueprint,
|
|
1272
|
+
hasChangeSet,
|
|
1273
|
+
changePathsOnly,
|
|
1274
|
+
selectedUserCreated: Boolean(selected?.userCreated),
|
|
1275
|
+
infoVisible,
|
|
1276
|
+
thumbnailVisible,
|
|
1277
|
+
importedBy,
|
|
1278
|
+
canStop,
|
|
1279
|
+
sessionCount: sessions.length,
|
|
1280
|
+
})
|
|
1281
|
+
const currentInstructionView: InstructionView = mapping
|
|
1282
|
+
? thumbnailMaximized
|
|
1283
|
+
? '3dview'
|
|
1284
|
+
: 'map'
|
|
1285
|
+
: 'walk'
|
|
1286
|
+
|
|
1036
1287
|
return (
|
|
1037
1288
|
<div className="hud">
|
|
1038
1289
|
{mode === 'walk' && !locked && walkIntro && !naming && (
|
|
@@ -1076,9 +1327,6 @@ export function HUD({
|
|
|
1076
1327
|
)}
|
|
1077
1328
|
|
|
1078
1329
|
<div className="hud-top">
|
|
1079
|
-
<div className="hud-chip">
|
|
1080
|
-
{mapping ? `Map of ${graph.targetName}` : `You are in ${currentFolder}`}
|
|
1081
|
-
</div>
|
|
1082
1330
|
<div className="hud-mode">
|
|
1083
1331
|
<button
|
|
1084
1332
|
className="hud-button"
|
|
@@ -1303,7 +1551,9 @@ export function HUD({
|
|
|
1303
1551
|
) : (
|
|
1304
1552
|
<ul>
|
|
1305
1553
|
{importers.map((file) => (
|
|
1306
|
-
<li key={file.id}
|
|
1554
|
+
<li key={file.id} title={file.id}>
|
|
1555
|
+
{file.name}
|
|
1556
|
+
</li>
|
|
1307
1557
|
))}
|
|
1308
1558
|
</ul>
|
|
1309
1559
|
)
|
|
@@ -1317,8 +1567,9 @@ export function HUD({
|
|
|
1317
1567
|
className={
|
|
1318
1568
|
intendedImportFrom.has(id) ? 'hud-intended' : undefined
|
|
1319
1569
|
}
|
|
1570
|
+
title={id}
|
|
1320
1571
|
>
|
|
1321
|
-
{id}
|
|
1572
|
+
{fileBase(id)}
|
|
1322
1573
|
</span>
|
|
1323
1574
|
{canEditBlueprint && intendedImportFrom.has(id) && (
|
|
1324
1575
|
<button
|
|
@@ -1345,10 +1596,8 @@ export function HUD({
|
|
|
1345
1596
|
))}
|
|
1346
1597
|
{extraBlueprintImports.map((item) => (
|
|
1347
1598
|
<li key={`bp-${item.name}-${item.from}`}>
|
|
1348
|
-
<span className="hud-intended">
|
|
1349
|
-
{item
|
|
1350
|
-
? item.from
|
|
1351
|
-
: `${item.name} from ${item.from}`}
|
|
1599
|
+
<span className="hud-intended" title={item.from}>
|
|
1600
|
+
{importLabel(item)}
|
|
1352
1601
|
</span>
|
|
1353
1602
|
{canEditBlueprint && (
|
|
1354
1603
|
<button
|
|
@@ -1460,93 +1709,92 @@ export function HUD({
|
|
|
1460
1709
|
landAt={landAt}
|
|
1461
1710
|
importedBy={importedBy}
|
|
1462
1711
|
minimized={thumbnailMinimized}
|
|
1712
|
+
maximized={thumbnailMaximized}
|
|
1463
1713
|
plannedIds={plannedIds}
|
|
1464
1714
|
createdIds={createdIds}
|
|
1465
1715
|
deletedIds={deletedIds}
|
|
1466
|
-
onMinimize={() =>
|
|
1716
|
+
onMinimize={() => {
|
|
1717
|
+
setThumbnailMaximized(false)
|
|
1718
|
+
setThumbnailMinimized((current) => !current)
|
|
1719
|
+
}}
|
|
1720
|
+
onMaximize={() => {
|
|
1721
|
+
setThumbnailMinimized(false)
|
|
1722
|
+
setThumbnailMaximized((current) => !current)
|
|
1723
|
+
}}
|
|
1467
1724
|
onHide={() => {
|
|
1468
1725
|
setThumbnailVisible(false)
|
|
1469
1726
|
setThumbnailMinimized(false)
|
|
1727
|
+
setThumbnailMaximized(false)
|
|
1470
1728
|
}}
|
|
1471
1729
|
/>
|
|
1472
1730
|
)}
|
|
1473
1731
|
</div>
|
|
1474
1732
|
|
|
1733
|
+
{instructionsOpen && (
|
|
1734
|
+
<div
|
|
1735
|
+
className="hud-instructions-overlay"
|
|
1736
|
+
onClick={() => setInstructionsOpen(false)}
|
|
1737
|
+
>
|
|
1738
|
+
<div
|
|
1739
|
+
className="hud-instructions-card"
|
|
1740
|
+
role="dialog"
|
|
1741
|
+
aria-modal="true"
|
|
1742
|
+
aria-labelledby="hud-instructions-title"
|
|
1743
|
+
onClick={(event) => event.stopPropagation()}
|
|
1744
|
+
>
|
|
1745
|
+
<div className="hud-instructions-header">
|
|
1746
|
+
<h1 id="hud-instructions-title">Instructions</h1>
|
|
1747
|
+
<button
|
|
1748
|
+
className="hud-button"
|
|
1749
|
+
type="button"
|
|
1750
|
+
onClick={() => setInstructionsOpen(false)}
|
|
1751
|
+
>
|
|
1752
|
+
Close
|
|
1753
|
+
</button>
|
|
1754
|
+
</div>
|
|
1755
|
+
<div className="hud-instructions-sections">
|
|
1756
|
+
{instructionSections.map((section) => (
|
|
1757
|
+
<section
|
|
1758
|
+
className="hud-instructions-section"
|
|
1759
|
+
data-current={section.id === currentInstructionView}
|
|
1760
|
+
key={section.id}
|
|
1761
|
+
aria-labelledby={`hud-instructions-${section.id}`}
|
|
1762
|
+
>
|
|
1763
|
+
<h2 id={`hud-instructions-${section.id}`}>
|
|
1764
|
+
{section.title}
|
|
1765
|
+
{section.id === currentInstructionView && (
|
|
1766
|
+
<span className="hud-instructions-current">Current</span>
|
|
1767
|
+
)}
|
|
1768
|
+
</h2>
|
|
1769
|
+
<InstructionList items={section.items} />
|
|
1770
|
+
</section>
|
|
1771
|
+
))}
|
|
1772
|
+
</div>
|
|
1773
|
+
</div>
|
|
1774
|
+
</div>
|
|
1775
|
+
)}
|
|
1776
|
+
|
|
1475
1777
|
<div className="hud-bottom">
|
|
1476
|
-
<div className="hud-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
</span>
|
|
1497
|
-
)}
|
|
1498
|
-
{selected?.userCreated && creatingBlueprint && (
|
|
1499
|
-
<span>Backspace delete</span>
|
|
1500
|
-
)}
|
|
1501
|
-
<span>{infoVisible ? 'I hide info' : 'I show info'}</span>
|
|
1502
|
-
{infoVisible && <span>↑↓ scroll info</span>}
|
|
1503
|
-
<span>
|
|
1504
|
-
{thumbnailVisible ? 'T hide 3D view' : 'T show 3D view'}
|
|
1505
|
-
</span>
|
|
1506
|
-
<span>
|
|
1507
|
-
{importedBy ? 'K show imports' : 'K show imported by'}
|
|
1508
|
-
</span>
|
|
1509
|
-
<span>M back to walk</span>
|
|
1510
|
-
{canStop && (
|
|
1511
|
-
<span>
|
|
1512
|
-
{sessions.length > 1
|
|
1513
|
-
? 'Stop ends the focused LLM session'
|
|
1514
|
-
: 'Stop ends this LLM session'}
|
|
1515
|
-
</span>
|
|
1516
|
-
)}
|
|
1517
|
-
</>
|
|
1518
|
-
) : (
|
|
1519
|
-
<>
|
|
1520
|
-
<span>WASD walk</span>
|
|
1521
|
-
<span>Mouse look</span>
|
|
1522
|
-
<span>Shift sprint</span>
|
|
1523
|
-
{creatingBlueprint && (
|
|
1524
|
-
<>
|
|
1525
|
-
<span>Space place file</span>
|
|
1526
|
-
<span>B place island</span>
|
|
1527
|
-
</>
|
|
1528
|
-
)}
|
|
1529
|
-
{selected?.userCreated && creatingBlueprint && (
|
|
1530
|
-
<span>Backspace delete</span>
|
|
1531
|
-
)}
|
|
1532
|
-
<span>Double-click a block for info</span>
|
|
1533
|
-
<span>Aim a line to fly</span>
|
|
1534
|
-
<span>{infoVisible ? 'I hide info' : 'I show info'}</span>
|
|
1535
|
-
{infoVisible && <span>↑↓ scroll info</span>}
|
|
1536
|
-
<span>
|
|
1537
|
-
{importedBy ? 'K show imports' : 'K show imported by'}
|
|
1538
|
-
</span>
|
|
1539
|
-
<span>M toggle map</span>
|
|
1540
|
-
<span>Double-click or Esc release mouse</span>
|
|
1541
|
-
{canStop && (
|
|
1542
|
-
<span>
|
|
1543
|
-
{sessions.length > 1
|
|
1544
|
-
? 'Stop ends the focused LLM session'
|
|
1545
|
-
: 'Stop ends this LLM session'}
|
|
1546
|
-
</span>
|
|
1547
|
-
)}
|
|
1548
|
-
</>
|
|
1549
|
-
)}
|
|
1778
|
+
<div className="hud-bottom-actions">
|
|
1779
|
+
<button
|
|
1780
|
+
className="hud-button"
|
|
1781
|
+
data-active={instructionsOpen}
|
|
1782
|
+
type="button"
|
|
1783
|
+
aria-haspopup="dialog"
|
|
1784
|
+
aria-expanded={instructionsOpen}
|
|
1785
|
+
onClick={() => setInstructionsOpen((open) => !open)}
|
|
1786
|
+
>
|
|
1787
|
+
Instructions
|
|
1788
|
+
</button>
|
|
1789
|
+
<button
|
|
1790
|
+
className="hud-button"
|
|
1791
|
+
type="button"
|
|
1792
|
+
aria-label="Rescan the project and rebuild the map"
|
|
1793
|
+
disabled={updatingModel}
|
|
1794
|
+
onClick={onUpdateModel}
|
|
1795
|
+
>
|
|
1796
|
+
{updatingModel ? 'Updating…' : 'Update model'}
|
|
1797
|
+
</button>
|
|
1550
1798
|
</div>
|
|
1551
1799
|
<div className="hud-icon-row">
|
|
1552
1800
|
{mapping && hasChangeSet && onToggleChangePathsOnly && (
|
|
@@ -1600,7 +1848,12 @@ export function HUD({
|
|
|
1600
1848
|
type="button"
|
|
1601
1849
|
onClick={() => {
|
|
1602
1850
|
setThumbnailVisible((visible) => {
|
|
1603
|
-
if (!visible)
|
|
1851
|
+
if (!visible) {
|
|
1852
|
+
setThumbnailMinimized(false)
|
|
1853
|
+
setThumbnailMaximized(false)
|
|
1854
|
+
} else {
|
|
1855
|
+
setThumbnailMaximized(false)
|
|
1856
|
+
}
|
|
1604
1857
|
return !visible
|
|
1605
1858
|
})
|
|
1606
1859
|
}}
|
|
@@ -10,8 +10,8 @@ import { dataDir, targetRoot } from './scripts/target-config.mjs'
|
|
|
10
10
|
import { editorFileUri, openInEditor } from './scripts/open-editor.mjs'
|
|
11
11
|
import {
|
|
12
12
|
answerBlueprint,
|
|
13
|
+
clearDiffSessions,
|
|
13
14
|
continueDiff,
|
|
14
|
-
discardInactiveDiffSessions,
|
|
15
15
|
inspectTargetFile,
|
|
16
16
|
invokeStep,
|
|
17
17
|
listSessionIntents,
|
|
@@ -56,7 +56,9 @@ function rescanTarget(when: string) {
|
|
|
56
56
|
})
|
|
57
57
|
if (scan.status !== 0) {
|
|
58
58
|
console.error(scan.stderr || scan.stdout || `scan failed ${when}`)
|
|
59
|
+
return false
|
|
59
60
|
}
|
|
61
|
+
return true
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
function knownFileIds() {
|
|
@@ -82,8 +84,8 @@ function jsonFilePlugin(): Plugin {
|
|
|
82
84
|
return {
|
|
83
85
|
name: 'visual-coder-json-files',
|
|
84
86
|
configureServer(server) {
|
|
85
|
-
|
|
86
|
-
rescanTarget('after
|
|
87
|
+
clearDiffSessions(dataDir, targetRoot)
|
|
88
|
+
rescanTarget('after clearing diff sessions')
|
|
87
89
|
server.middlewares.use('/api/user-context', (req, res, next) => {
|
|
88
90
|
if (req.method === 'GET') {
|
|
89
91
|
sendJson(res, 200, readUserContext())
|
|
@@ -101,6 +103,14 @@ function jsonFilePlugin(): Plugin {
|
|
|
101
103
|
sendJson(res, 200, readCodebase())
|
|
102
104
|
return
|
|
103
105
|
}
|
|
106
|
+
if (req.method === 'POST') {
|
|
107
|
+
if (!rescanTarget('on user request')) {
|
|
108
|
+
sendJson(res, 500, { error: 'scan failed' })
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
sendJson(res, 200, readCodebase())
|
|
112
|
+
return
|
|
113
|
+
}
|
|
104
114
|
next()
|
|
105
115
|
})
|
|
106
116
|
|