@jkwd/inbase 0.1.13 → 0.1.16
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 +2 -2
- package/apps/explorer/scripts/branch-changes.mjs +2 -19
- package/apps/explorer/scripts/patch-lib.d.ts +3 -0
- package/apps/explorer/scripts/patch-lib.mjs +3 -0
- package/apps/explorer/scripts/scan-ignore.mjs +156 -0
- package/apps/explorer/scripts/scan-target.mjs +67 -29
- package/apps/explorer/scripts/session-store.d.ts +24 -3
- package/apps/explorer/scripts/session-store.mjs +180 -74
- package/apps/explorer/src/App.tsx +258 -147
- package/apps/explorer/src/agentIntent.ts +87 -5
- package/apps/explorer/src/index.css +106 -5
- package/apps/explorer/src/keyboard.ts +26 -0
- package/apps/explorer/src/scene/BlockPlacer.tsx +2 -11
- package/apps/explorer/src/scene/FileBlock.tsx +12 -4
- package/apps/explorer/src/scene/FolderArea.tsx +20 -0
- package/apps/explorer/src/scene/IslandPlacer.tsx +2 -11
- package/apps/explorer/src/scene/MapView.tsx +74 -37
- package/apps/explorer/src/scene/Player.tsx +9 -9
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +2 -0
- package/apps/explorer/src/scene/World.tsx +46 -1
- package/apps/explorer/src/types.ts +28 -0
- package/apps/explorer/src/ui/CanvasErrorBoundary.tsx +4 -0
- package/apps/explorer/src/ui/HUD.tsx +435 -99
- package/apps/explorer/src/ui/MapContextMenu.tsx +2 -0
- package/apps/explorer/src/userCreated.ts +98 -0
- package/apps/explorer/vite.config.ts +71 -5
- package/bin/session.mjs +40 -12
- package/package.json +2 -1
- package/skill/commands/inbase.md +1 -1
- package/skill/inbase/SKILL.md +24 -22
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
2
2
|
import { Canvas } from '@react-three/fiber'
|
|
3
|
-
import {
|
|
3
|
+
import { shouldIgnoreShortcut, isKeyboardIsolated } from './keyboard'
|
|
4
|
+
import { emptyIntent, fetchAgentIntent, fetchAgentIntents, inspectTargetFile, performAgentAction, persistBlueprintCleanup, persistBlueprintClear, persistBlueprintHidden, persistSessionBlueprint, persistSessionFocus, setupVisualizerSession } from './agentIntent'
|
|
4
5
|
import { emptyBranchChanges, fetchBranchChanges } from './branchChanges'
|
|
5
6
|
import { fetchCodebase, updateCodebase } from './codebase'
|
|
6
7
|
import {
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
} from './layout'
|
|
15
16
|
import { World } from './scene/World'
|
|
16
17
|
import { HUD } from './ui/HUD'
|
|
18
|
+
import { CanvasErrorBoundary } from './ui/CanvasErrorBoundary'
|
|
17
19
|
import {
|
|
18
20
|
MapContextMenu,
|
|
19
21
|
type MapContextMenuState,
|
|
@@ -26,14 +28,18 @@ import {
|
|
|
26
28
|
} from './userContext'
|
|
27
29
|
import {
|
|
28
30
|
defaultBlockSpot,
|
|
31
|
+
dropBlueprintFileNotes,
|
|
32
|
+
dropBlueprintSymbolNote,
|
|
29
33
|
isBlueprintSymbolName,
|
|
30
34
|
namedCreatedBlocks,
|
|
31
35
|
namedCreatedIslands,
|
|
32
36
|
parseBlueprintImport,
|
|
37
|
+
parseBlueprintNotes,
|
|
33
38
|
parseUserCreatedBlocks,
|
|
34
39
|
parseUserCreatedIslands,
|
|
35
40
|
resolveCreatedFile,
|
|
36
41
|
resolveCreatedIsland,
|
|
42
|
+
setBlueprintNote,
|
|
37
43
|
withBlueprintIntent,
|
|
38
44
|
withUserCreatedGraph,
|
|
39
45
|
withUserCreatedLayout,
|
|
@@ -43,6 +49,8 @@ import {
|
|
|
43
49
|
llmIsMakingChanges,
|
|
44
50
|
type AgentIntent,
|
|
45
51
|
type AimedRelation,
|
|
52
|
+
type BlueprintNote,
|
|
53
|
+
type BlueprintNoteKind,
|
|
46
54
|
type CodebaseGraph,
|
|
47
55
|
type FlyTo,
|
|
48
56
|
type PatchImportAddition,
|
|
@@ -165,7 +173,7 @@ function Explorer({
|
|
|
165
173
|
intents.find((item) => item.sessionId === focusedSessionId) ??
|
|
166
174
|
intents[0] ??
|
|
167
175
|
emptyIntent
|
|
168
|
-
const canPlace =
|
|
176
|
+
const canPlace = true
|
|
169
177
|
const llmBusy = intents.some(llmIsMakingChanges)
|
|
170
178
|
const llmPreviewing = intent.preview || isPatchPreview(intent.status)
|
|
171
179
|
const showingBranchChanges =
|
|
@@ -191,6 +199,23 @@ function Explorer({
|
|
|
191
199
|
const [blueprintImports, setBlueprintImports] = useState<
|
|
192
200
|
PatchImportAddition[]
|
|
193
201
|
>([])
|
|
202
|
+
const [blueprintNotes, setBlueprintNotes] = useState<BlueprintNote[]>([])
|
|
203
|
+
const [blueprintHidden, setBlueprintHidden] = useState(false)
|
|
204
|
+
const userBlocksRef = useRef(userBlocks)
|
|
205
|
+
const userIslandsRef = useRef(userIslands)
|
|
206
|
+
const blueprintFunctionsRef = useRef(blueprintFunctions)
|
|
207
|
+
const blueprintVariablesRef = useRef(blueprintVariables)
|
|
208
|
+
const blueprintImportsRef = useRef(blueprintImports)
|
|
209
|
+
const blueprintNotesRef = useRef(blueprintNotes)
|
|
210
|
+
const notesDirty = useRef(false)
|
|
211
|
+
const blueprintPersistGen = useRef(0)
|
|
212
|
+
const notePersistTimer = useRef<number | null>(null)
|
|
213
|
+
userBlocksRef.current = userBlocks
|
|
214
|
+
userIslandsRef.current = userIslands
|
|
215
|
+
blueprintFunctionsRef.current = blueprintFunctions
|
|
216
|
+
blueprintVariablesRef.current = blueprintVariables
|
|
217
|
+
blueprintImportsRef.current = blueprintImports
|
|
218
|
+
blueprintNotesRef.current = blueprintNotes
|
|
194
219
|
const namingId = userBlocks.find((block) => block.naming)?.id ?? null
|
|
195
220
|
const namingIslandId = userIslands.find((island) => island.naming)?.id ?? null
|
|
196
221
|
const naming = Boolean(namingId || namingIslandId)
|
|
@@ -211,10 +236,30 @@ function Explorer({
|
|
|
211
236
|
plannedCreates,
|
|
212
237
|
previewing,
|
|
213
238
|
])
|
|
239
|
+
const knownFileIds = useMemo(
|
|
240
|
+
() => new Set(previewGraph.files.map((file) => file.id)),
|
|
241
|
+
[previewGraph],
|
|
242
|
+
)
|
|
243
|
+
const knownFolderPaths = useMemo(
|
|
244
|
+
() => new Set(previewGraph.folders.map((folder) => folder.path)),
|
|
245
|
+
[previewGraph],
|
|
246
|
+
)
|
|
247
|
+
const visibleBlocks = blueprintHidden
|
|
248
|
+
? userBlocks.filter((block) => block.naming)
|
|
249
|
+
: userBlocks
|
|
250
|
+
const visibleIslands = blueprintHidden
|
|
251
|
+
? userIslands.filter((island) => island.naming)
|
|
252
|
+
: userIslands
|
|
253
|
+
const pendingBlocks = visibleBlocks.filter(
|
|
254
|
+
(block) => block.naming || !knownFileIds.has(block.id),
|
|
255
|
+
)
|
|
256
|
+
const overlayBlocks = visibleBlocks.filter(
|
|
257
|
+
(block) => !block.naming && knownFileIds.has(block.id),
|
|
258
|
+
)
|
|
214
259
|
const displayGraph = useMemo(
|
|
215
260
|
() =>
|
|
216
261
|
withBlueprintIntent(
|
|
217
|
-
withUserCreatedGraph(previewGraph,
|
|
262
|
+
withUserCreatedGraph(previewGraph, pendingBlocks, visibleIslands),
|
|
218
263
|
blueprintFunctions,
|
|
219
264
|
blueprintVariables,
|
|
220
265
|
blueprintImports,
|
|
@@ -223,23 +268,23 @@ function Explorer({
|
|
|
223
268
|
blueprintFunctions,
|
|
224
269
|
blueprintImports,
|
|
225
270
|
blueprintVariables,
|
|
271
|
+
pendingBlocks,
|
|
226
272
|
previewGraph,
|
|
227
|
-
|
|
228
|
-
userIslands,
|
|
273
|
+
visibleIslands,
|
|
229
274
|
],
|
|
230
275
|
)
|
|
231
276
|
const layout = useMemo(() => {
|
|
232
277
|
const world = layoutWorld(
|
|
233
|
-
withUserCreatedGraph(previewGraph, [],
|
|
278
|
+
withUserCreatedGraph(previewGraph, [], visibleIslands),
|
|
234
279
|
)
|
|
235
280
|
if (previewing) markCreatedFolders(world, changeSet.createFolders ?? [])
|
|
236
|
-
return withUserCreatedLayout(world,
|
|
281
|
+
return withUserCreatedLayout(world, pendingBlocks, visibleIslands)
|
|
237
282
|
}, [
|
|
238
283
|
changeSet.createFolders,
|
|
284
|
+
pendingBlocks,
|
|
239
285
|
previewGraph,
|
|
240
286
|
previewing,
|
|
241
|
-
|
|
242
|
-
userIslands,
|
|
287
|
+
visibleIslands,
|
|
243
288
|
])
|
|
244
289
|
const changeFileIds = useMemo(() => {
|
|
245
290
|
const ids = new Set<string>()
|
|
@@ -250,10 +295,12 @@ function Explorer({
|
|
|
250
295
|
for (const item of blueprintFunctions) ids.add(item.file)
|
|
251
296
|
for (const item of blueprintVariables) ids.add(item.file)
|
|
252
297
|
for (const item of blueprintImports) ids.add(item.file)
|
|
298
|
+
for (const note of blueprintNotes) ids.add(note.file)
|
|
253
299
|
return [...ids]
|
|
254
300
|
}, [
|
|
255
301
|
blueprintFunctions,
|
|
256
302
|
blueprintImports,
|
|
303
|
+
blueprintNotes,
|
|
257
304
|
blueprintVariables,
|
|
258
305
|
changeSet.creates,
|
|
259
306
|
changeSet.deletes,
|
|
@@ -315,7 +362,6 @@ function Explorer({
|
|
|
315
362
|
const lastIntentSig = useRef<string | null>(null)
|
|
316
363
|
const viewedDiffId = useRef<Record<string, string | null>>({})
|
|
317
364
|
const browsingHistory = useRef<Record<string, boolean>>({})
|
|
318
|
-
const loadedBlueprintSession = useRef<string | null>(null)
|
|
319
365
|
const seenSessionIds = useRef<Set<string>>(new Set())
|
|
320
366
|
|
|
321
367
|
const applyIntent = useCallback((next: AgentIntent, sessionId?: string) => {
|
|
@@ -463,6 +509,7 @@ function Explorer({
|
|
|
463
509
|
addedFunctions: blueprintFunctions,
|
|
464
510
|
addedVariables: blueprintVariables,
|
|
465
511
|
addedImports: blueprintImports,
|
|
512
|
+
notes: blueprintNotes,
|
|
466
513
|
}
|
|
467
514
|
: {}),
|
|
468
515
|
},
|
|
@@ -485,6 +532,7 @@ function Explorer({
|
|
|
485
532
|
applyIntent,
|
|
486
533
|
blueprintFunctions,
|
|
487
534
|
blueprintImports,
|
|
535
|
+
blueprintNotes,
|
|
488
536
|
blueprintVariables,
|
|
489
537
|
intents,
|
|
490
538
|
onRefreshGraph,
|
|
@@ -537,16 +585,7 @@ function Explorer({
|
|
|
537
585
|
useEffect(() => {
|
|
538
586
|
const onKey = (event: KeyboardEvent) => {
|
|
539
587
|
if (event.repeat || event.code !== 'KeyM') return
|
|
540
|
-
|
|
541
|
-
if (
|
|
542
|
-
target instanceof HTMLElement &&
|
|
543
|
-
(target.tagName === 'TEXTAREA' ||
|
|
544
|
-
target.tagName === 'INPUT' ||
|
|
545
|
-
target.tagName === 'SELECT' ||
|
|
546
|
-
target.isContentEditable)
|
|
547
|
-
) {
|
|
548
|
-
return
|
|
549
|
-
}
|
|
588
|
+
if (shouldIgnoreShortcut(event)) return
|
|
550
589
|
event.preventDefault()
|
|
551
590
|
toggleMap()
|
|
552
591
|
}
|
|
@@ -570,98 +609,78 @@ function Explorer({
|
|
|
570
609
|
}
|
|
571
610
|
}, [])
|
|
572
611
|
|
|
573
|
-
useEffect(() => {
|
|
574
|
-
if (!intent.sessionId) {
|
|
575
|
-
loadedBlueprintSession.current = null
|
|
576
|
-
setUserBlocks([])
|
|
577
|
-
setUserIslands([])
|
|
578
|
-
setBlueprintFunctions([])
|
|
579
|
-
setBlueprintVariables([])
|
|
580
|
-
setBlueprintImports([])
|
|
581
|
-
return
|
|
582
|
-
}
|
|
583
|
-
const knownFiles = new Set(graph.files.map((file) => file.id))
|
|
584
|
-
const knownFolders = new Set(graph.folders.map((folder) => folder.path))
|
|
585
|
-
const nextBlocks = parseUserCreatedBlocks(intent.userCreatedBlocks).filter(
|
|
586
|
-
(block) => !knownFiles.has(block.id),
|
|
587
|
-
)
|
|
588
|
-
const nextIslands = parseUserCreatedIslands(intent.userCreatedIslands).filter(
|
|
589
|
-
(island) => !knownFolders.has(island.path),
|
|
590
|
-
)
|
|
591
|
-
const switched = loadedBlueprintSession.current !== intent.sessionId
|
|
592
|
-
if (switched) {
|
|
593
|
-
loadedBlueprintSession.current = intent.sessionId
|
|
594
|
-
setUserBlocks(nextBlocks)
|
|
595
|
-
setUserIslands(nextIslands)
|
|
596
|
-
setBlueprintFunctions(intent.blueprintFunctions)
|
|
597
|
-
setBlueprintVariables(intent.blueprintVariables)
|
|
598
|
-
setBlueprintImports(intent.blueprintImports)
|
|
599
|
-
return
|
|
600
|
-
}
|
|
601
|
-
if (intent.creationMode) {
|
|
602
|
-
setUserBlocks((current) =>
|
|
603
|
-
current.some((block) => block.naming) || current.length > 0
|
|
604
|
-
? current
|
|
605
|
-
: nextBlocks,
|
|
606
|
-
)
|
|
607
|
-
setUserIslands((current) =>
|
|
608
|
-
current.some((island) => island.naming) || current.length > 0
|
|
609
|
-
? current
|
|
610
|
-
: nextIslands,
|
|
611
|
-
)
|
|
612
|
-
setBlueprintFunctions((current) =>
|
|
613
|
-
current.length > 0 ? current : intent.blueprintFunctions,
|
|
614
|
-
)
|
|
615
|
-
setBlueprintVariables((current) =>
|
|
616
|
-
current.length > 0 ? current : intent.blueprintVariables,
|
|
617
|
-
)
|
|
618
|
-
setBlueprintImports((current) =>
|
|
619
|
-
current.length > 0 ? current : intent.blueprintImports,
|
|
620
|
-
)
|
|
621
|
-
return
|
|
622
|
-
}
|
|
623
|
-
setUserBlocks(nextBlocks)
|
|
624
|
-
setUserIslands(nextIslands)
|
|
625
|
-
setBlueprintFunctions(intent.blueprintFunctions)
|
|
626
|
-
setBlueprintVariables(intent.blueprintVariables)
|
|
627
|
-
setBlueprintImports(intent.blueprintImports)
|
|
628
|
-
}, [
|
|
629
|
-
intent.blueprintFunctions,
|
|
630
|
-
intent.blueprintImports,
|
|
631
|
-
intent.blueprintVariables,
|
|
632
|
-
intent.creationMode,
|
|
633
|
-
intent.sessionId,
|
|
634
|
-
intent.userCreatedBlocks,
|
|
635
|
-
intent.userCreatedIslands,
|
|
636
|
-
graph,
|
|
637
|
-
])
|
|
638
|
-
|
|
639
612
|
const persistBlueprint = useCallback(
|
|
640
613
|
(
|
|
641
|
-
blocks: UserCreatedBlock[] =
|
|
642
|
-
islands: UserCreatedIsland[] =
|
|
643
|
-
functions: PatchSymbolAddition[] =
|
|
644
|
-
variables: PatchSymbolAddition[] =
|
|
645
|
-
imports: PatchImportAddition[] =
|
|
614
|
+
blocks: UserCreatedBlock[] = userBlocksRef.current,
|
|
615
|
+
islands: UserCreatedIsland[] = userIslandsRef.current,
|
|
616
|
+
functions: PatchSymbolAddition[] = blueprintFunctionsRef.current,
|
|
617
|
+
variables: PatchSymbolAddition[] = blueprintVariablesRef.current,
|
|
618
|
+
imports: PatchImportAddition[] = blueprintImportsRef.current,
|
|
619
|
+
notes: BlueprintNote[] = blueprintNotesRef.current,
|
|
646
620
|
) => {
|
|
647
|
-
if (
|
|
648
|
-
|
|
621
|
+
if (notePersistTimer.current != null) {
|
|
622
|
+
window.clearTimeout(notePersistTimer.current)
|
|
623
|
+
notePersistTimer.current = null
|
|
624
|
+
}
|
|
625
|
+
const gen = ++blueprintPersistGen.current
|
|
626
|
+
notesDirty.current = true
|
|
627
|
+
void persistSessionBlueprint(intent.sessionId, {
|
|
649
628
|
userCreatedBlocks: namedCreatedBlocks(blocks),
|
|
650
629
|
userCreatedIslands: namedCreatedIslands(islands),
|
|
651
630
|
addedFunctions: functions,
|
|
652
631
|
addedVariables: variables,
|
|
653
632
|
addedImports: imports,
|
|
633
|
+
notes,
|
|
634
|
+
}).finally(() => {
|
|
635
|
+
if (gen !== blueprintPersistGen.current) return
|
|
636
|
+
if (notePersistTimer.current != null) return
|
|
637
|
+
notesDirty.current = false
|
|
654
638
|
})
|
|
655
639
|
},
|
|
656
|
-
[
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
640
|
+
[intent.sessionId],
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
const persistBlueprintSoon = useCallback(() => {
|
|
644
|
+
notesDirty.current = true
|
|
645
|
+
if (notePersistTimer.current != null) {
|
|
646
|
+
window.clearTimeout(notePersistTimer.current)
|
|
647
|
+
}
|
|
648
|
+
notePersistTimer.current = window.setTimeout(() => {
|
|
649
|
+
persistBlueprint()
|
|
650
|
+
}, 400)
|
|
651
|
+
}, [persistBlueprint])
|
|
652
|
+
|
|
653
|
+
useEffect(() => {
|
|
654
|
+
return () => {
|
|
655
|
+
if (notePersistTimer.current == null) return
|
|
656
|
+
window.clearTimeout(notePersistTimer.current)
|
|
657
|
+
notePersistTimer.current = null
|
|
658
|
+
if (!notesDirty.current) return
|
|
659
|
+
persistSessionBlueprint(intent.sessionId, {
|
|
660
|
+
userCreatedBlocks: namedCreatedBlocks(userBlocksRef.current),
|
|
661
|
+
userCreatedIslands: namedCreatedIslands(userIslandsRef.current),
|
|
662
|
+
addedFunctions: blueprintFunctionsRef.current,
|
|
663
|
+
addedVariables: blueprintVariablesRef.current,
|
|
664
|
+
addedImports: blueprintImportsRef.current,
|
|
665
|
+
notes: blueprintNotesRef.current,
|
|
666
|
+
})
|
|
667
|
+
notesDirty.current = false
|
|
668
|
+
}
|
|
669
|
+
}, [intent.sessionId])
|
|
670
|
+
|
|
671
|
+
const applyBlueprintNote = useCallback(
|
|
672
|
+
(next: {
|
|
673
|
+
file: string
|
|
674
|
+
kind: BlueprintNoteKind
|
|
675
|
+
name?: string
|
|
676
|
+
note: string
|
|
677
|
+
}) => {
|
|
678
|
+
const notes = setBlueprintNote(blueprintNotesRef.current, next)
|
|
679
|
+
blueprintNotesRef.current = notes
|
|
680
|
+
setBlueprintNotes(notes)
|
|
681
|
+
persistBlueprintSoon()
|
|
682
|
+
},
|
|
683
|
+
[persistBlueprintSoon],
|
|
665
684
|
)
|
|
666
685
|
|
|
667
686
|
const placeBlock = useCallback(
|
|
@@ -811,8 +830,11 @@ function Explorer({
|
|
|
811
830
|
const selected = userBlocks.find((block) => block.id === selectedId)
|
|
812
831
|
if (!selected || selected.naming) return false
|
|
813
832
|
const next = userBlocks.filter((block) => block.id !== selectedId)
|
|
833
|
+
const notes = dropBlueprintFileNotes(blueprintNotesRef.current, [selectedId])
|
|
834
|
+
blueprintNotesRef.current = notes
|
|
814
835
|
setUserBlocks(next)
|
|
815
|
-
|
|
836
|
+
setBlueprintNotes(notes)
|
|
837
|
+
persistBlueprint(next, userIslands, undefined, undefined, undefined, notes)
|
|
816
838
|
setSelectedId(null)
|
|
817
839
|
return true
|
|
818
840
|
}, [canPlace, persistBlueprint, selectedId, userBlocks, userIslands])
|
|
@@ -971,8 +993,23 @@ function Explorer({
|
|
|
971
993
|
const next = blueprintFunctions.filter(
|
|
972
994
|
(item) => !(item.file === fileId && item.name === name),
|
|
973
995
|
)
|
|
996
|
+
const notes = dropBlueprintSymbolNote(
|
|
997
|
+
blueprintNotesRef.current,
|
|
998
|
+
fileId,
|
|
999
|
+
'function',
|
|
1000
|
+
name,
|
|
1001
|
+
)
|
|
1002
|
+
blueprintNotesRef.current = notes
|
|
974
1003
|
setBlueprintFunctions(next)
|
|
975
|
-
|
|
1004
|
+
setBlueprintNotes(notes)
|
|
1005
|
+
persistBlueprint(
|
|
1006
|
+
userBlocks,
|
|
1007
|
+
userIslands,
|
|
1008
|
+
next,
|
|
1009
|
+
blueprintVariables,
|
|
1010
|
+
blueprintImports,
|
|
1011
|
+
notes,
|
|
1012
|
+
)
|
|
976
1013
|
},
|
|
977
1014
|
[
|
|
978
1015
|
blueprintFunctions,
|
|
@@ -991,8 +1028,23 @@ function Explorer({
|
|
|
991
1028
|
const next = blueprintVariables.filter(
|
|
992
1029
|
(item) => !(item.file === fileId && item.name === name),
|
|
993
1030
|
)
|
|
1031
|
+
const notes = dropBlueprintSymbolNote(
|
|
1032
|
+
blueprintNotesRef.current,
|
|
1033
|
+
fileId,
|
|
1034
|
+
'variable',
|
|
1035
|
+
name,
|
|
1036
|
+
)
|
|
1037
|
+
blueprintNotesRef.current = notes
|
|
994
1038
|
setBlueprintVariables(next)
|
|
995
|
-
|
|
1039
|
+
setBlueprintNotes(notes)
|
|
1040
|
+
persistBlueprint(
|
|
1041
|
+
userBlocks,
|
|
1042
|
+
userIslands,
|
|
1043
|
+
blueprintFunctions,
|
|
1044
|
+
next,
|
|
1045
|
+
blueprintImports,
|
|
1046
|
+
notes,
|
|
1047
|
+
)
|
|
996
1048
|
},
|
|
997
1049
|
[
|
|
998
1050
|
blueprintFunctions,
|
|
@@ -1036,6 +1088,7 @@ function Explorer({
|
|
|
1036
1088
|
if (!namingId && !namingIslandId) return
|
|
1037
1089
|
const onKey = (event: KeyboardEvent) => {
|
|
1038
1090
|
if (event.code !== 'Escape') return
|
|
1091
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1039
1092
|
event.preventDefault()
|
|
1040
1093
|
if (namingId) cancelBlockName(namingId)
|
|
1041
1094
|
if (namingIslandId) cancelIslandName(namingIslandId)
|
|
@@ -1051,16 +1104,7 @@ function Explorer({
|
|
|
1051
1104
|
useEffect(() => {
|
|
1052
1105
|
const onKey = (event: KeyboardEvent) => {
|
|
1053
1106
|
if (event.repeat || event.code !== 'Backspace') return
|
|
1054
|
-
|
|
1055
|
-
if (
|
|
1056
|
-
target instanceof HTMLElement &&
|
|
1057
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1058
|
-
target.tagName === 'INPUT' ||
|
|
1059
|
-
target.tagName === 'SELECT' ||
|
|
1060
|
-
target.isContentEditable)
|
|
1061
|
-
) {
|
|
1062
|
-
return
|
|
1063
|
-
}
|
|
1107
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1064
1108
|
if (!deleteSelectedCreatedBlock()) return
|
|
1065
1109
|
event.preventDefault()
|
|
1066
1110
|
}
|
|
@@ -1100,16 +1144,7 @@ function Explorer({
|
|
|
1100
1144
|
useEffect(() => {
|
|
1101
1145
|
const onKey = (event: KeyboardEvent) => {
|
|
1102
1146
|
if (event.repeat || event.code !== 'KeyK') return
|
|
1103
|
-
|
|
1104
|
-
if (
|
|
1105
|
-
target instanceof HTMLElement &&
|
|
1106
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1107
|
-
target.tagName === 'INPUT' ||
|
|
1108
|
-
target.tagName === 'SELECT' ||
|
|
1109
|
-
target.isContentEditable)
|
|
1110
|
-
) {
|
|
1111
|
-
return
|
|
1112
|
-
}
|
|
1147
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1113
1148
|
event.preventDefault()
|
|
1114
1149
|
toggleImportedBy()
|
|
1115
1150
|
}
|
|
@@ -1120,16 +1155,7 @@ function Explorer({
|
|
|
1120
1155
|
useEffect(() => {
|
|
1121
1156
|
const onKey = (event: KeyboardEvent) => {
|
|
1122
1157
|
if (event.repeat || event.code !== 'KeyG') return
|
|
1123
|
-
|
|
1124
|
-
if (
|
|
1125
|
-
target instanceof HTMLElement &&
|
|
1126
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1127
|
-
target.tagName === 'INPUT' ||
|
|
1128
|
-
target.tagName === 'SELECT' ||
|
|
1129
|
-
target.isContentEditable)
|
|
1130
|
-
) {
|
|
1131
|
-
return
|
|
1132
|
-
}
|
|
1158
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1133
1159
|
if (!canToggleBranchChanges) return
|
|
1134
1160
|
event.preventDefault()
|
|
1135
1161
|
toggleShowBranchChanges()
|
|
@@ -1163,16 +1189,7 @@ function Explorer({
|
|
|
1163
1189
|
if (mode !== 'map' || !hasChangeSet) return
|
|
1164
1190
|
const onKey = (event: KeyboardEvent) => {
|
|
1165
1191
|
if (event.repeat || event.code !== 'KeyC') return
|
|
1166
|
-
|
|
1167
|
-
if (
|
|
1168
|
-
target instanceof HTMLElement &&
|
|
1169
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1170
|
-
target.tagName === 'INPUT' ||
|
|
1171
|
-
target.tagName === 'SELECT' ||
|
|
1172
|
-
target.isContentEditable)
|
|
1173
|
-
) {
|
|
1174
|
-
return
|
|
1175
|
-
}
|
|
1192
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1176
1193
|
event.preventDefault()
|
|
1177
1194
|
toggleChangePathsOnly()
|
|
1178
1195
|
}
|
|
@@ -1186,6 +1203,29 @@ function Explorer({
|
|
|
1186
1203
|
try {
|
|
1187
1204
|
const bundle = await fetchAgentIntents()
|
|
1188
1205
|
if (cancelled) return
|
|
1206
|
+
setBlueprintHidden(Boolean(bundle.blueprint.hidden))
|
|
1207
|
+
const nextBlocks = parseUserCreatedBlocks(bundle.blueprint.userCreatedBlocks)
|
|
1208
|
+
const nextIslands = parseUserCreatedIslands(bundle.blueprint.userCreatedIslands)
|
|
1209
|
+
setUserBlocks((current) => {
|
|
1210
|
+
const drafts = current.filter((block) => block.naming)
|
|
1211
|
+
if (drafts.length === 0) return nextBlocks
|
|
1212
|
+
const namedIds = new Set(drafts.map((block) => block.id))
|
|
1213
|
+
return [...nextBlocks.filter((block) => !namedIds.has(block.id)), ...drafts]
|
|
1214
|
+
})
|
|
1215
|
+
setUserIslands((current) => {
|
|
1216
|
+
const drafts = current.filter((island) => island.naming)
|
|
1217
|
+
if (drafts.length === 0) return nextIslands
|
|
1218
|
+
const namedIds = new Set(drafts.map((island) => island.id))
|
|
1219
|
+
return [...nextIslands.filter((island) => !namedIds.has(island.id)), ...drafts]
|
|
1220
|
+
})
|
|
1221
|
+
setBlueprintFunctions(bundle.blueprint.addedFunctions)
|
|
1222
|
+
setBlueprintVariables(bundle.blueprint.addedVariables)
|
|
1223
|
+
setBlueprintImports(bundle.blueprint.addedImports)
|
|
1224
|
+
if (!notesDirty.current && !isKeyboardIsolated()) {
|
|
1225
|
+
const nextNotes = parseBlueprintNotes(bundle.blueprint.notes)
|
|
1226
|
+
blueprintNotesRef.current = nextNotes
|
|
1227
|
+
setBlueprintNotes(nextNotes)
|
|
1228
|
+
}
|
|
1189
1229
|
setNextAttachSessionId(bundle.nextAttachSessionId)
|
|
1190
1230
|
const merged: AgentIntent[] = []
|
|
1191
1231
|
for (const next of bundle.intents) {
|
|
@@ -1258,10 +1298,69 @@ function Explorer({
|
|
|
1258
1298
|
...blueprintImportEdges,
|
|
1259
1299
|
]
|
|
1260
1300
|
const deletedIds = previewing ? changeSet.deletes : []
|
|
1301
|
+
const blueprintHasContent =
|
|
1302
|
+
namedCreatedBlocks(userBlocks).length > 0 ||
|
|
1303
|
+
namedCreatedIslands(userIslands).length > 0 ||
|
|
1304
|
+
blueprintFunctions.length > 0 ||
|
|
1305
|
+
blueprintVariables.length > 0 ||
|
|
1306
|
+
blueprintImports.length > 0 ||
|
|
1307
|
+
blueprintNotes.length > 0
|
|
1308
|
+
const blueprintCanCleanup =
|
|
1309
|
+
userBlocks.some((block) => !block.naming && knownFileIds.has(block.id)) ||
|
|
1310
|
+
userIslands.some(
|
|
1311
|
+
(island) => !island.naming && knownFolderPaths.has(island.path),
|
|
1312
|
+
)
|
|
1313
|
+
|
|
1314
|
+
const toggleBlueprintHidden = useCallback(() => {
|
|
1315
|
+
const next = !blueprintHidden
|
|
1316
|
+
setBlueprintHidden(next)
|
|
1317
|
+
void persistBlueprintHidden(next).catch(() => setBlueprintHidden(!next))
|
|
1318
|
+
}, [blueprintHidden])
|
|
1319
|
+
|
|
1320
|
+
const clearSharedBlueprint = useCallback(() => {
|
|
1321
|
+
setUserBlocks([])
|
|
1322
|
+
setUserIslands([])
|
|
1323
|
+
setBlueprintFunctions([])
|
|
1324
|
+
setBlueprintVariables([])
|
|
1325
|
+
setBlueprintImports([])
|
|
1326
|
+
blueprintNotesRef.current = []
|
|
1327
|
+
setBlueprintNotes([])
|
|
1328
|
+
void persistBlueprintClear()
|
|
1329
|
+
}, [])
|
|
1330
|
+
|
|
1331
|
+
const cleanupSharedBlueprint = useCallback(() => {
|
|
1332
|
+
const files = knownFileIds
|
|
1333
|
+
const folders = knownFolderPaths
|
|
1334
|
+
const removed = new Set(
|
|
1335
|
+
userBlocks
|
|
1336
|
+
.filter((block) => !block.naming && files.has(block.id))
|
|
1337
|
+
.map((block) => block.id),
|
|
1338
|
+
)
|
|
1339
|
+
setUserBlocks((current) =>
|
|
1340
|
+
current.filter((block) => block.naming || !files.has(block.id)),
|
|
1341
|
+
)
|
|
1342
|
+
setUserIslands((current) =>
|
|
1343
|
+
current.filter((island) => island.naming || !folders.has(island.path)),
|
|
1344
|
+
)
|
|
1345
|
+
setBlueprintFunctions((current) =>
|
|
1346
|
+
current.filter((item) => !removed.has(item.file)),
|
|
1347
|
+
)
|
|
1348
|
+
setBlueprintVariables((current) =>
|
|
1349
|
+
current.filter((item) => !removed.has(item.file)),
|
|
1350
|
+
)
|
|
1351
|
+
setBlueprintImports((current) =>
|
|
1352
|
+
current.filter((item) => !removed.has(item.file)),
|
|
1353
|
+
)
|
|
1354
|
+
const notes = dropBlueprintFileNotes(blueprintNotesRef.current, removed)
|
|
1355
|
+
blueprintNotesRef.current = notes
|
|
1356
|
+
setBlueprintNotes(notes)
|
|
1357
|
+
void persistBlueprintCleanup()
|
|
1358
|
+
}, [knownFileIds, knownFolderPaths, userBlocks])
|
|
1261
1359
|
|
|
1262
1360
|
return (
|
|
1263
1361
|
<>
|
|
1264
1362
|
<div className="stage">
|
|
1363
|
+
<CanvasErrorBoundary>
|
|
1265
1364
|
<Canvas
|
|
1266
1365
|
shadows={false}
|
|
1267
1366
|
dpr={[1, 1.5]}
|
|
@@ -1307,8 +1406,11 @@ function Explorer({
|
|
|
1307
1406
|
onBlueprintMenu={canPlace ? setMapMenu : undefined}
|
|
1308
1407
|
onCommitName={commitBlockName}
|
|
1309
1408
|
onCancelName={cancelBlockName}
|
|
1310
|
-
|
|
1311
|
-
|
|
1409
|
+
onCommitIslandName={commitIslandName}
|
|
1410
|
+
onCancelIslandName={cancelIslandName}
|
|
1411
|
+
userCreatedBlocks={visibleBlocks}
|
|
1412
|
+
userCreatedIslands={visibleIslands}
|
|
1413
|
+
overlayBlocks={overlayBlocks}
|
|
1312
1414
|
mapGraph={
|
|
1313
1415
|
changePathsOnly && hasChangeSet ? changePathGraph : null
|
|
1314
1416
|
}
|
|
@@ -1317,6 +1419,7 @@ function Explorer({
|
|
|
1317
1419
|
}
|
|
1318
1420
|
/>
|
|
1319
1421
|
</Canvas>
|
|
1422
|
+
</CanvasErrorBoundary>
|
|
1320
1423
|
</div>
|
|
1321
1424
|
<HUD
|
|
1322
1425
|
graph={displayGraph}
|
|
@@ -1365,12 +1468,14 @@ function Explorer({
|
|
|
1365
1468
|
blueprintFunctions={blueprintFunctions}
|
|
1366
1469
|
blueprintVariables={blueprintVariables}
|
|
1367
1470
|
blueprintImports={blueprintImports}
|
|
1471
|
+
blueprintNotes={blueprintNotes}
|
|
1368
1472
|
onAddBlueprintFunction={addBlueprintFunction}
|
|
1369
1473
|
onAddBlueprintVariable={addBlueprintVariable}
|
|
1370
1474
|
onAddBlueprintImport={addBlueprintImport}
|
|
1371
1475
|
onRemoveBlueprintFunction={removeBlueprintFunction}
|
|
1372
1476
|
onRemoveBlueprintVariable={removeBlueprintVariable}
|
|
1373
1477
|
onRemoveBlueprintImport={removeBlueprintImport}
|
|
1478
|
+
onSetBlueprintNote={applyBlueprintNote}
|
|
1374
1479
|
onMapAddFile={placeBlockOnFolder}
|
|
1375
1480
|
onMapAddFolder={placeIslandOnFolder}
|
|
1376
1481
|
onInspectFile={inspectFile}
|
|
@@ -1378,6 +1483,12 @@ function Explorer({
|
|
|
1378
1483
|
plannedIds={plannedIds}
|
|
1379
1484
|
createdIds={plannedCreates}
|
|
1380
1485
|
deletedIds={deletedIds}
|
|
1486
|
+
blueprintHidden={blueprintHidden}
|
|
1487
|
+
blueprintHasContent={blueprintHasContent}
|
|
1488
|
+
blueprintCanCleanup={blueprintCanCleanup}
|
|
1489
|
+
onToggleBlueprintHidden={toggleBlueprintHidden}
|
|
1490
|
+
onClearBlueprint={clearSharedBlueprint}
|
|
1491
|
+
onCleanupBlueprint={cleanupSharedBlueprint}
|
|
1381
1492
|
/>
|
|
1382
1493
|
<MapContextMenu
|
|
1383
1494
|
menu={mapMenu}
|