@jkwd/inbase 0.1.19 → 0.1.21
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 +1 -1
- package/apps/explorer/scripts/patch-lib.d.ts +1 -0
- package/apps/explorer/scripts/patch-lib.mjs +1 -0
- package/apps/explorer/scripts/scan-ignore.mjs +9 -0
- package/apps/explorer/scripts/session-store.d.ts +3 -0
- package/apps/explorer/scripts/session-store.mjs +54 -2
- package/apps/explorer/src/App.tsx +119 -3
- package/apps/explorer/src/agentIntent.ts +10 -1
- package/apps/explorer/src/index.css +9 -0
- package/apps/explorer/src/scene/FileBlock.tsx +27 -0
- package/apps/explorer/src/scene/FolderArea.tsx +21 -0
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +66 -34
- package/apps/explorer/src/scene/World.tsx +22 -3
- package/apps/explorer/src/types.ts +10 -0
- package/apps/explorer/src/ui/CanvasErrorBoundary.tsx +2 -0
- package/apps/explorer/src/ui/EyeIcon.tsx +26 -0
- package/apps/explorer/src/ui/HUD.tsx +183 -24
- package/apps/explorer/src/ui/MapContextMenu.tsx +18 -1
- package/apps/explorer/src/userCreated.ts +97 -0
- package/apps/explorer/vite.config.ts +4 -0
- package/package.json +1 -1
- package/skill/inbase/SKILL.md +17 -20
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import type { PlacedFolder } from '../types'
|
|
12
12
|
import { MapSelectBorder } from './MapSelectBorder'
|
|
13
13
|
import { NameInput } from '../ui/NameInput'
|
|
14
|
+
import { EyeIcon } from '../ui/EyeIcon'
|
|
14
15
|
|
|
15
16
|
type FolderAreaProps = {
|
|
16
17
|
folder: PlacedFolder
|
|
@@ -20,6 +21,7 @@ type FolderAreaProps = {
|
|
|
20
21
|
highlightKind?: ChangeKind | null
|
|
21
22
|
previewLabels?: boolean
|
|
22
23
|
labelVisible?: boolean
|
|
24
|
+
pointed?: boolean
|
|
23
25
|
onCommitName?: (name: string) => void
|
|
24
26
|
onCancelName?: () => void
|
|
25
27
|
}
|
|
@@ -32,6 +34,7 @@ export function FolderArea({
|
|
|
32
34
|
highlightKind = null,
|
|
33
35
|
previewLabels = false,
|
|
34
36
|
labelVisible = true,
|
|
37
|
+
pointed = false,
|
|
35
38
|
onCommitName,
|
|
36
39
|
onCancelName,
|
|
37
40
|
}: FolderAreaProps) {
|
|
@@ -93,6 +96,24 @@ export function FolderArea({
|
|
|
93
96
|
<meshBasicMaterial color={aisle} />
|
|
94
97
|
</mesh>
|
|
95
98
|
)}
|
|
99
|
+
{pointed && !naming && (
|
|
100
|
+
<Html
|
|
101
|
+
position={[0, mapMode ? 1.15 : 1.45, -folder.depth / 2 + 2.2]}
|
|
102
|
+
center
|
|
103
|
+
occlude={false}
|
|
104
|
+
style={{ pointerEvents: 'none' }}
|
|
105
|
+
zIndexRange={[40, 0]}
|
|
106
|
+
>
|
|
107
|
+
<div
|
|
108
|
+
className="blueprint-eye"
|
|
109
|
+
data-map={mapMode ? 'true' : 'false'}
|
|
110
|
+
role="img"
|
|
111
|
+
aria-label="Keep in mind"
|
|
112
|
+
>
|
|
113
|
+
<EyeIcon size={mapMode ? 18 : 22} title="Keep in mind" />
|
|
114
|
+
</div>
|
|
115
|
+
</Html>
|
|
116
|
+
)}
|
|
96
117
|
{naming && mapMode && onCommitName && onCancelName && (
|
|
97
118
|
<Html
|
|
98
119
|
position={[0, 1.35, -folder.depth / 2 + 1.35]}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { CONFIG, WORLD_VOID, type ChangeKind } from '../theme'
|
|
12
12
|
import { shouldIgnoreShortcut } from '../keyboard'
|
|
13
13
|
import type { CodebaseGraph, PlacedFile, PlacedFolder, WorldLayout } from '../types'
|
|
14
|
+
import { CanvasErrorBoundary } from '../ui/CanvasErrorBoundary'
|
|
14
15
|
import { FileBlock } from './FileBlock'
|
|
15
16
|
import { FolderArea } from './FolderArea'
|
|
16
17
|
import { RelationLines } from './RelationLines'
|
|
@@ -30,6 +31,8 @@ type SelectionThumbnailProps = {
|
|
|
30
31
|
plannedIds?: string[]
|
|
31
32
|
createdIds?: string[]
|
|
32
33
|
deletedIds?: string[]
|
|
34
|
+
pointedFileIds?: string[]
|
|
35
|
+
pointedFolderPaths?: string[]
|
|
33
36
|
onMinimize?: () => void
|
|
34
37
|
onMaximize?: () => void
|
|
35
38
|
onHide: () => void
|
|
@@ -464,6 +467,8 @@ function ThumbnailScene({
|
|
|
464
467
|
planned,
|
|
465
468
|
created,
|
|
466
469
|
deleted,
|
|
470
|
+
pointedFiles,
|
|
471
|
+
pointedFolders,
|
|
467
472
|
zoom,
|
|
468
473
|
zoomRef,
|
|
469
474
|
panRef,
|
|
@@ -481,6 +486,8 @@ function ThumbnailScene({
|
|
|
481
486
|
planned: Set<string>
|
|
482
487
|
created: Set<string>
|
|
483
488
|
deleted: Set<string>
|
|
489
|
+
pointedFiles: Set<string>
|
|
490
|
+
pointedFolders: Set<string>
|
|
484
491
|
zoom: number
|
|
485
492
|
zoomRef: { current: number }
|
|
486
493
|
panRef: { current: Vec3 }
|
|
@@ -496,15 +503,18 @@ function ThumbnailScene({
|
|
|
496
503
|
const selected = file.id === target.selectedFileId
|
|
497
504
|
const related = target.relatedIds.has(file.id)
|
|
498
505
|
const changeKind = fileChangeKind(file.id, planned, created, deleted)
|
|
506
|
+
const pointed = pointedFiles.has(file.id)
|
|
499
507
|
const dimmed =
|
|
500
508
|
Boolean(target.selectedFileId) &&
|
|
501
509
|
!selected &&
|
|
502
510
|
!related &&
|
|
503
|
-
!changeKind
|
|
511
|
+
!changeKind &&
|
|
512
|
+
!pointed
|
|
504
513
|
let priority = placed.size[1]
|
|
505
514
|
if (selected) priority += 1000
|
|
506
515
|
else if (related) priority += 400
|
|
507
516
|
else if (changeKind) priority += 300
|
|
517
|
+
else if (pointed) priority += 250
|
|
508
518
|
else if (file.userCreated) priority += 80
|
|
509
519
|
if (dimmed) priority -= 200
|
|
510
520
|
return {
|
|
@@ -517,7 +527,7 @@ function ThumbnailScene({
|
|
|
517
527
|
priority,
|
|
518
528
|
}
|
|
519
529
|
}),
|
|
520
|
-
|
|
530
|
+
[created, deleted, planned, pointedFiles, target],
|
|
521
531
|
)
|
|
522
532
|
|
|
523
533
|
return (
|
|
@@ -554,12 +564,14 @@ function ThumbnailScene({
|
|
|
554
564
|
<FolderArea
|
|
555
565
|
folder={target.folder}
|
|
556
566
|
highlightKind={highlightedFolders[target.folder.path] ?? null}
|
|
567
|
+
pointed={pointedFolders.has(target.folder.path)}
|
|
557
568
|
previewLabels={zoom < 1.45}
|
|
558
569
|
/>
|
|
559
570
|
{target.files.map(({ file, placed }) => {
|
|
560
571
|
const selected = file.id === target.selectedFileId
|
|
561
572
|
const related = target.relatedIds.has(file.id)
|
|
562
573
|
const changeKind = fileChangeKind(file.id, planned, created, deleted)
|
|
574
|
+
const pointed = pointedFiles.has(file.id)
|
|
563
575
|
return (
|
|
564
576
|
<FileBlock
|
|
565
577
|
key={file.id}
|
|
@@ -570,6 +582,7 @@ function ThumbnailScene({
|
|
|
570
582
|
planned={Boolean(changeKind)}
|
|
571
583
|
changeKind={changeKind}
|
|
572
584
|
added={created.has(file.id) || file.userCreated}
|
|
585
|
+
pointed={pointed}
|
|
573
586
|
highlightMapChange
|
|
574
587
|
previewLabels
|
|
575
588
|
labelVisible={visibleLabelIds.has(file.id)}
|
|
@@ -577,7 +590,8 @@ function ThumbnailScene({
|
|
|
577
590
|
Boolean(target.selectedFileId) &&
|
|
578
591
|
!selected &&
|
|
579
592
|
!related &&
|
|
580
|
-
!changeKind
|
|
593
|
+
!changeKind &&
|
|
594
|
+
!pointed
|
|
581
595
|
}
|
|
582
596
|
/>
|
|
583
597
|
)
|
|
@@ -632,6 +646,7 @@ export function SelectionThumbnail({
|
|
|
632
646
|
const [zoom, setZoom] = useState(1)
|
|
633
647
|
const [panning, setPanning] = useState(false)
|
|
634
648
|
const [orbiting, setOrbiting] = useState(false)
|
|
649
|
+
const [canvasReady, setCanvasReady] = useState(false)
|
|
635
650
|
const [visibleLabelIds, setVisibleLabelIds] = useState<Set<string>>(
|
|
636
651
|
() => new Set(),
|
|
637
652
|
)
|
|
@@ -657,6 +672,11 @@ export function SelectionThumbnail({
|
|
|
657
672
|
|
|
658
673
|
const panningRef = useRef(false)
|
|
659
674
|
|
|
675
|
+
useEffect(() => {
|
|
676
|
+
const frame = window.requestAnimationFrame(() => setCanvasReady(true))
|
|
677
|
+
return () => window.cancelAnimationFrame(frame)
|
|
678
|
+
}, [])
|
|
679
|
+
|
|
660
680
|
useEffect(() => {
|
|
661
681
|
zoomRef.current = 1
|
|
662
682
|
panRef.current = ZERO_PAN
|
|
@@ -960,37 +980,49 @@ export function SelectionThumbnail({
|
|
|
960
980
|
data-panning={panning}
|
|
961
981
|
data-orbiting={orbiting}
|
|
962
982
|
>
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
983
|
+
{canvasReady ? (
|
|
984
|
+
<CanvasErrorBoundary
|
|
985
|
+
fallback={
|
|
986
|
+
<div className="hud-thumbnail-hint">3D preview unavailable</div>
|
|
987
|
+
}
|
|
988
|
+
>
|
|
989
|
+
<Canvas
|
|
990
|
+
shadows={false}
|
|
991
|
+
dpr={[1, 1]}
|
|
992
|
+
resize={{ offsetSize: true }}
|
|
993
|
+
gl={{
|
|
994
|
+
antialias: false,
|
|
995
|
+
powerPreference: 'low-power',
|
|
996
|
+
toneMappingExposure: 1.25,
|
|
997
|
+
}}
|
|
998
|
+
camera={{
|
|
999
|
+
fov: 50,
|
|
1000
|
+
near: 0.1,
|
|
1001
|
+
far: 400,
|
|
1002
|
+
position: target.camera.position,
|
|
1003
|
+
}}
|
|
1004
|
+
>
|
|
1005
|
+
<ThumbnailScene
|
|
1006
|
+
graph={graph}
|
|
1007
|
+
layout={layout}
|
|
1008
|
+
importedBy={importedBy}
|
|
1009
|
+
target={target}
|
|
1010
|
+
highlightedFolders={highlightedFolders}
|
|
1011
|
+
planned={planned}
|
|
1012
|
+
created={created}
|
|
1013
|
+
deleted={deleted}
|
|
1014
|
+
zoom={zoom}
|
|
1015
|
+
zoomRef={zoomRef}
|
|
1016
|
+
panRef={panRef}
|
|
1017
|
+
orbitRef={orbitRef}
|
|
1018
|
+
cameraRef={cameraRef}
|
|
1019
|
+
frozenRef={panningRef}
|
|
1020
|
+
visibleLabelIds={visibleLabelIds}
|
|
1021
|
+
onVisibleLabels={setVisibleLabelIds}
|
|
1022
|
+
/>
|
|
1023
|
+
</Canvas>
|
|
1024
|
+
</CanvasErrorBoundary>
|
|
1025
|
+
) : null}
|
|
994
1026
|
<div className="hud-thumbnail-hint">
|
|
995
1027
|
Scroll zoom · drag pan · ⌘ drag rotate
|
|
996
1028
|
</div>
|
|
@@ -73,6 +73,8 @@ type WorldProps = {
|
|
|
73
73
|
userCreatedBlocks?: UserCreatedBlock[]
|
|
74
74
|
userCreatedIslands?: UserCreatedIsland[]
|
|
75
75
|
overlayBlocks?: UserCreatedBlock[]
|
|
76
|
+
pointedFileIds?: string[]
|
|
77
|
+
pointedFolderPaths?: string[]
|
|
76
78
|
namingIslandId?: string | null
|
|
77
79
|
mapGraph?: CodebaseGraph | null
|
|
78
80
|
mapLayout?: WorldLayout | null
|
|
@@ -117,11 +119,15 @@ export function World({
|
|
|
117
119
|
userCreatedBlocks = [],
|
|
118
120
|
userCreatedIslands = [],
|
|
119
121
|
overlayBlocks = [],
|
|
122
|
+
pointedFileIds = [],
|
|
123
|
+
pointedFolderPaths = [],
|
|
120
124
|
mapGraph = null,
|
|
121
125
|
mapLayout = null,
|
|
122
126
|
}: WorldProps) {
|
|
123
127
|
const created = new Set(createdIds)
|
|
124
128
|
const deleted = new Set(deletedIds)
|
|
129
|
+
const pointedFiles = new Set(pointedFileIds)
|
|
130
|
+
const pointedFolders = new Set(pointedFolderPaths)
|
|
125
131
|
const mapping = mode === 'map'
|
|
126
132
|
const viewGraph = mapping && mapGraph ? mapGraph : graph
|
|
127
133
|
const viewLayout = mapping && mapLayout ? mapLayout : layout
|
|
@@ -169,17 +175,19 @@ export function World({
|
|
|
169
175
|
if (selectedId) ids.add(selectedId)
|
|
170
176
|
if (namingId) ids.add(namingId)
|
|
171
177
|
if (aimedRelation?.flyTo) ids.add(aimedRelation.flyTo)
|
|
178
|
+
for (const id of pointedFileIds) ids.add(id)
|
|
172
179
|
if (ghostKey) {
|
|
173
180
|
for (const id of ghostKey.split('|')) ids.add(id)
|
|
174
181
|
}
|
|
175
182
|
return ids
|
|
176
|
-
}, [aimedRelation?.flyTo, ghostKey, namingId, selectedId])
|
|
183
|
+
}, [aimedRelation?.flyTo, ghostKey, namingId, pointedFileIds, selectedId])
|
|
177
184
|
const keepFolderPaths = useMemo(() => {
|
|
178
185
|
const paths = new Set<string>()
|
|
179
186
|
if (selectedFolder) paths.add(selectedFolder)
|
|
180
187
|
if (namingIslandId) paths.add(namingIslandId)
|
|
188
|
+
for (const path of pointedFolderPaths) paths.add(path)
|
|
181
189
|
return paths
|
|
182
|
-
}, [namingIslandId, selectedFolder])
|
|
190
|
+
}, [namingIslandId, pointedFolderPaths, selectedFolder])
|
|
183
191
|
const originLod = useMemo(() => {
|
|
184
192
|
if (mapping) return null
|
|
185
193
|
return computeWalkLod({
|
|
@@ -254,6 +262,7 @@ export function World({
|
|
|
254
262
|
highlightKind={
|
|
255
263
|
mapping ? highlightedFolders[folder.path] ?? null : null
|
|
256
264
|
}
|
|
265
|
+
pointed={pointedFolders.has(folder.path)}
|
|
257
266
|
labelVisible={!lod || lod.folderLabels.has(folder.path)}
|
|
258
267
|
onCommitName={
|
|
259
268
|
folder.path === namingIslandId && onCommitIslandName
|
|
@@ -285,14 +294,22 @@ export function World({
|
|
|
285
294
|
const changeKind = fileChangeKind(file.id, planned, created, deleted)
|
|
286
295
|
const naming = file.id === namingId
|
|
287
296
|
const aimed = file.id === aimedRelation?.flyTo
|
|
297
|
+
const pointed = pointedFiles.has(file.id)
|
|
288
298
|
const detailed =
|
|
289
|
-
selected ||
|
|
299
|
+
selected ||
|
|
300
|
+
isRelated ||
|
|
301
|
+
isPlanned ||
|
|
302
|
+
naming ||
|
|
303
|
+
aimed ||
|
|
304
|
+
pointed ||
|
|
305
|
+
Boolean(changeKind)
|
|
290
306
|
if (lod && !lod.files.has(file.id)) return null
|
|
291
307
|
const dimmed =
|
|
292
308
|
hasFocus &&
|
|
293
309
|
!selected &&
|
|
294
310
|
!isRelated &&
|
|
295
311
|
!changeKind &&
|
|
312
|
+
!pointed &&
|
|
296
313
|
!patchLinked.has(file.id) &&
|
|
297
314
|
!folderFileIds.has(file.id)
|
|
298
315
|
if (lod && !detailed && !lod.labels.has(file.id)) {
|
|
@@ -310,6 +327,7 @@ export function World({
|
|
|
310
327
|
changeKind={changeKind}
|
|
311
328
|
added={created.has(file.id) || file.userCreated}
|
|
312
329
|
aimed={aimed}
|
|
330
|
+
pointed={pointed}
|
|
313
331
|
dimmed={dimmed}
|
|
314
332
|
naming={naming}
|
|
315
333
|
mapMode={mapping}
|
|
@@ -347,6 +365,7 @@ export function World({
|
|
|
347
365
|
planned={false}
|
|
348
366
|
changeKind="add"
|
|
349
367
|
added
|
|
368
|
+
pointed={pointedFiles.has(file.id)}
|
|
350
369
|
dimmed={false}
|
|
351
370
|
mapMode={mapping}
|
|
352
371
|
labelVisible
|
|
@@ -225,6 +225,14 @@ export type BlueprintNote = {
|
|
|
225
225
|
note: string
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
export type BlueprintPointerKind = 'file' | 'folder' | 'function' | 'variable'
|
|
229
|
+
|
|
230
|
+
export type BlueprintPointer = {
|
|
231
|
+
kind: BlueprintPointerKind
|
|
232
|
+
path: string
|
|
233
|
+
name?: string
|
|
234
|
+
}
|
|
235
|
+
|
|
228
236
|
export type AimedRelation = {
|
|
229
237
|
from: string
|
|
230
238
|
to: string
|
|
@@ -275,6 +283,7 @@ export type SharedBlueprint = {
|
|
|
275
283
|
addedVariables: PatchSymbolAddition[]
|
|
276
284
|
addedImports: PatchImportAddition[]
|
|
277
285
|
notes: BlueprintNote[]
|
|
286
|
+
pointers: BlueprintPointer[]
|
|
278
287
|
}
|
|
279
288
|
|
|
280
289
|
export type AgentIntentBundle = {
|
|
@@ -341,4 +350,5 @@ export type AgentIntent = {
|
|
|
341
350
|
blueprintVariables: PatchSymbolAddition[]
|
|
342
351
|
blueprintImports: PatchImportAddition[]
|
|
343
352
|
blueprintNotes: BlueprintNote[]
|
|
353
|
+
blueprintPointers: BlueprintPointer[]
|
|
344
354
|
}
|
|
@@ -2,6 +2,7 @@ import { Component, type ReactNode } from 'react'
|
|
|
2
2
|
|
|
3
3
|
type Props = {
|
|
4
4
|
children: ReactNode
|
|
5
|
+
fallback?: ReactNode
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
type State = {
|
|
@@ -21,6 +22,7 @@ export class CanvasErrorBoundary extends Component<Props, State> {
|
|
|
21
22
|
|
|
22
23
|
render() {
|
|
23
24
|
if (this.state.failed) {
|
|
25
|
+
if (this.props.fallback !== undefined) return this.props.fallback
|
|
24
26
|
return (
|
|
25
27
|
<div className="canvas-error">
|
|
26
28
|
<div className="hud-gate-card">
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function EyeIcon({
|
|
2
|
+
size = 18,
|
|
3
|
+
title,
|
|
4
|
+
}: {
|
|
5
|
+
size?: number
|
|
6
|
+
title?: string
|
|
7
|
+
}) {
|
|
8
|
+
return (
|
|
9
|
+
<svg
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
width={size}
|
|
12
|
+
height={size}
|
|
13
|
+
fill="none"
|
|
14
|
+
stroke="currentColor"
|
|
15
|
+
strokeWidth="2"
|
|
16
|
+
strokeLinecap="round"
|
|
17
|
+
strokeLinejoin="round"
|
|
18
|
+
aria-hidden={title ? undefined : true}
|
|
19
|
+
role={title ? 'img' : undefined}
|
|
20
|
+
>
|
|
21
|
+
{title ? <title>{title}</title> : null}
|
|
22
|
+
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" />
|
|
23
|
+
<circle cx="12" cy="12" r="3" />
|
|
24
|
+
</svg>
|
|
25
|
+
)
|
|
26
|
+
}
|