@jkwd/inbase 0.1.15 → 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 +255 -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 +41 -10
- 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/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 {
|
|
@@ -27,14 +28,18 @@ import {
|
|
|
27
28
|
} from './userContext'
|
|
28
29
|
import {
|
|
29
30
|
defaultBlockSpot,
|
|
31
|
+
dropBlueprintFileNotes,
|
|
32
|
+
dropBlueprintSymbolNote,
|
|
30
33
|
isBlueprintSymbolName,
|
|
31
34
|
namedCreatedBlocks,
|
|
32
35
|
namedCreatedIslands,
|
|
33
36
|
parseBlueprintImport,
|
|
37
|
+
parseBlueprintNotes,
|
|
34
38
|
parseUserCreatedBlocks,
|
|
35
39
|
parseUserCreatedIslands,
|
|
36
40
|
resolveCreatedFile,
|
|
37
41
|
resolveCreatedIsland,
|
|
42
|
+
setBlueprintNote,
|
|
38
43
|
withBlueprintIntent,
|
|
39
44
|
withUserCreatedGraph,
|
|
40
45
|
withUserCreatedLayout,
|
|
@@ -44,6 +49,8 @@ import {
|
|
|
44
49
|
llmIsMakingChanges,
|
|
45
50
|
type AgentIntent,
|
|
46
51
|
type AimedRelation,
|
|
52
|
+
type BlueprintNote,
|
|
53
|
+
type BlueprintNoteKind,
|
|
47
54
|
type CodebaseGraph,
|
|
48
55
|
type FlyTo,
|
|
49
56
|
type PatchImportAddition,
|
|
@@ -166,7 +173,7 @@ function Explorer({
|
|
|
166
173
|
intents.find((item) => item.sessionId === focusedSessionId) ??
|
|
167
174
|
intents[0] ??
|
|
168
175
|
emptyIntent
|
|
169
|
-
const canPlace =
|
|
176
|
+
const canPlace = true
|
|
170
177
|
const llmBusy = intents.some(llmIsMakingChanges)
|
|
171
178
|
const llmPreviewing = intent.preview || isPatchPreview(intent.status)
|
|
172
179
|
const showingBranchChanges =
|
|
@@ -192,6 +199,23 @@ function Explorer({
|
|
|
192
199
|
const [blueprintImports, setBlueprintImports] = useState<
|
|
193
200
|
PatchImportAddition[]
|
|
194
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
|
|
195
219
|
const namingId = userBlocks.find((block) => block.naming)?.id ?? null
|
|
196
220
|
const namingIslandId = userIslands.find((island) => island.naming)?.id ?? null
|
|
197
221
|
const naming = Boolean(namingId || namingIslandId)
|
|
@@ -212,10 +236,30 @@ function Explorer({
|
|
|
212
236
|
plannedCreates,
|
|
213
237
|
previewing,
|
|
214
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
|
+
)
|
|
215
259
|
const displayGraph = useMemo(
|
|
216
260
|
() =>
|
|
217
261
|
withBlueprintIntent(
|
|
218
|
-
withUserCreatedGraph(previewGraph,
|
|
262
|
+
withUserCreatedGraph(previewGraph, pendingBlocks, visibleIslands),
|
|
219
263
|
blueprintFunctions,
|
|
220
264
|
blueprintVariables,
|
|
221
265
|
blueprintImports,
|
|
@@ -224,23 +268,23 @@ function Explorer({
|
|
|
224
268
|
blueprintFunctions,
|
|
225
269
|
blueprintImports,
|
|
226
270
|
blueprintVariables,
|
|
271
|
+
pendingBlocks,
|
|
227
272
|
previewGraph,
|
|
228
|
-
|
|
229
|
-
userIslands,
|
|
273
|
+
visibleIslands,
|
|
230
274
|
],
|
|
231
275
|
)
|
|
232
276
|
const layout = useMemo(() => {
|
|
233
277
|
const world = layoutWorld(
|
|
234
|
-
withUserCreatedGraph(previewGraph, [],
|
|
278
|
+
withUserCreatedGraph(previewGraph, [], visibleIslands),
|
|
235
279
|
)
|
|
236
280
|
if (previewing) markCreatedFolders(world, changeSet.createFolders ?? [])
|
|
237
|
-
return withUserCreatedLayout(world,
|
|
281
|
+
return withUserCreatedLayout(world, pendingBlocks, visibleIslands)
|
|
238
282
|
}, [
|
|
239
283
|
changeSet.createFolders,
|
|
284
|
+
pendingBlocks,
|
|
240
285
|
previewGraph,
|
|
241
286
|
previewing,
|
|
242
|
-
|
|
243
|
-
userIslands,
|
|
287
|
+
visibleIslands,
|
|
244
288
|
])
|
|
245
289
|
const changeFileIds = useMemo(() => {
|
|
246
290
|
const ids = new Set<string>()
|
|
@@ -251,10 +295,12 @@ function Explorer({
|
|
|
251
295
|
for (const item of blueprintFunctions) ids.add(item.file)
|
|
252
296
|
for (const item of blueprintVariables) ids.add(item.file)
|
|
253
297
|
for (const item of blueprintImports) ids.add(item.file)
|
|
298
|
+
for (const note of blueprintNotes) ids.add(note.file)
|
|
254
299
|
return [...ids]
|
|
255
300
|
}, [
|
|
256
301
|
blueprintFunctions,
|
|
257
302
|
blueprintImports,
|
|
303
|
+
blueprintNotes,
|
|
258
304
|
blueprintVariables,
|
|
259
305
|
changeSet.creates,
|
|
260
306
|
changeSet.deletes,
|
|
@@ -316,7 +362,6 @@ function Explorer({
|
|
|
316
362
|
const lastIntentSig = useRef<string | null>(null)
|
|
317
363
|
const viewedDiffId = useRef<Record<string, string | null>>({})
|
|
318
364
|
const browsingHistory = useRef<Record<string, boolean>>({})
|
|
319
|
-
const loadedBlueprintSession = useRef<string | null>(null)
|
|
320
365
|
const seenSessionIds = useRef<Set<string>>(new Set())
|
|
321
366
|
|
|
322
367
|
const applyIntent = useCallback((next: AgentIntent, sessionId?: string) => {
|
|
@@ -464,6 +509,7 @@ function Explorer({
|
|
|
464
509
|
addedFunctions: blueprintFunctions,
|
|
465
510
|
addedVariables: blueprintVariables,
|
|
466
511
|
addedImports: blueprintImports,
|
|
512
|
+
notes: blueprintNotes,
|
|
467
513
|
}
|
|
468
514
|
: {}),
|
|
469
515
|
},
|
|
@@ -486,6 +532,7 @@ function Explorer({
|
|
|
486
532
|
applyIntent,
|
|
487
533
|
blueprintFunctions,
|
|
488
534
|
blueprintImports,
|
|
535
|
+
blueprintNotes,
|
|
489
536
|
blueprintVariables,
|
|
490
537
|
intents,
|
|
491
538
|
onRefreshGraph,
|
|
@@ -538,16 +585,7 @@ function Explorer({
|
|
|
538
585
|
useEffect(() => {
|
|
539
586
|
const onKey = (event: KeyboardEvent) => {
|
|
540
587
|
if (event.repeat || event.code !== 'KeyM') return
|
|
541
|
-
|
|
542
|
-
if (
|
|
543
|
-
target instanceof HTMLElement &&
|
|
544
|
-
(target.tagName === 'TEXTAREA' ||
|
|
545
|
-
target.tagName === 'INPUT' ||
|
|
546
|
-
target.tagName === 'SELECT' ||
|
|
547
|
-
target.isContentEditable)
|
|
548
|
-
) {
|
|
549
|
-
return
|
|
550
|
-
}
|
|
588
|
+
if (shouldIgnoreShortcut(event)) return
|
|
551
589
|
event.preventDefault()
|
|
552
590
|
toggleMap()
|
|
553
591
|
}
|
|
@@ -571,98 +609,78 @@ function Explorer({
|
|
|
571
609
|
}
|
|
572
610
|
}, [])
|
|
573
611
|
|
|
574
|
-
useEffect(() => {
|
|
575
|
-
if (!intent.sessionId) {
|
|
576
|
-
loadedBlueprintSession.current = null
|
|
577
|
-
setUserBlocks([])
|
|
578
|
-
setUserIslands([])
|
|
579
|
-
setBlueprintFunctions([])
|
|
580
|
-
setBlueprintVariables([])
|
|
581
|
-
setBlueprintImports([])
|
|
582
|
-
return
|
|
583
|
-
}
|
|
584
|
-
const knownFiles = new Set(graph.files.map((file) => file.id))
|
|
585
|
-
const knownFolders = new Set(graph.folders.map((folder) => folder.path))
|
|
586
|
-
const nextBlocks = parseUserCreatedBlocks(intent.userCreatedBlocks).filter(
|
|
587
|
-
(block) => !knownFiles.has(block.id),
|
|
588
|
-
)
|
|
589
|
-
const nextIslands = parseUserCreatedIslands(intent.userCreatedIslands).filter(
|
|
590
|
-
(island) => !knownFolders.has(island.path),
|
|
591
|
-
)
|
|
592
|
-
const switched = loadedBlueprintSession.current !== intent.sessionId
|
|
593
|
-
if (switched) {
|
|
594
|
-
loadedBlueprintSession.current = intent.sessionId
|
|
595
|
-
setUserBlocks(nextBlocks)
|
|
596
|
-
setUserIslands(nextIslands)
|
|
597
|
-
setBlueprintFunctions(intent.blueprintFunctions)
|
|
598
|
-
setBlueprintVariables(intent.blueprintVariables)
|
|
599
|
-
setBlueprintImports(intent.blueprintImports)
|
|
600
|
-
return
|
|
601
|
-
}
|
|
602
|
-
if (intent.creationMode) {
|
|
603
|
-
setUserBlocks((current) =>
|
|
604
|
-
current.some((block) => block.naming) || current.length > 0
|
|
605
|
-
? current
|
|
606
|
-
: nextBlocks,
|
|
607
|
-
)
|
|
608
|
-
setUserIslands((current) =>
|
|
609
|
-
current.some((island) => island.naming) || current.length > 0
|
|
610
|
-
? current
|
|
611
|
-
: nextIslands,
|
|
612
|
-
)
|
|
613
|
-
setBlueprintFunctions((current) =>
|
|
614
|
-
current.length > 0 ? current : intent.blueprintFunctions,
|
|
615
|
-
)
|
|
616
|
-
setBlueprintVariables((current) =>
|
|
617
|
-
current.length > 0 ? current : intent.blueprintVariables,
|
|
618
|
-
)
|
|
619
|
-
setBlueprintImports((current) =>
|
|
620
|
-
current.length > 0 ? current : intent.blueprintImports,
|
|
621
|
-
)
|
|
622
|
-
return
|
|
623
|
-
}
|
|
624
|
-
setUserBlocks(nextBlocks)
|
|
625
|
-
setUserIslands(nextIslands)
|
|
626
|
-
setBlueprintFunctions(intent.blueprintFunctions)
|
|
627
|
-
setBlueprintVariables(intent.blueprintVariables)
|
|
628
|
-
setBlueprintImports(intent.blueprintImports)
|
|
629
|
-
}, [
|
|
630
|
-
intent.blueprintFunctions,
|
|
631
|
-
intent.blueprintImports,
|
|
632
|
-
intent.blueprintVariables,
|
|
633
|
-
intent.creationMode,
|
|
634
|
-
intent.sessionId,
|
|
635
|
-
intent.userCreatedBlocks,
|
|
636
|
-
intent.userCreatedIslands,
|
|
637
|
-
graph,
|
|
638
|
-
])
|
|
639
|
-
|
|
640
612
|
const persistBlueprint = useCallback(
|
|
641
613
|
(
|
|
642
|
-
blocks: UserCreatedBlock[] =
|
|
643
|
-
islands: UserCreatedIsland[] =
|
|
644
|
-
functions: PatchSymbolAddition[] =
|
|
645
|
-
variables: PatchSymbolAddition[] =
|
|
646
|
-
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,
|
|
647
620
|
) => {
|
|
648
|
-
if (
|
|
649
|
-
|
|
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, {
|
|
650
628
|
userCreatedBlocks: namedCreatedBlocks(blocks),
|
|
651
629
|
userCreatedIslands: namedCreatedIslands(islands),
|
|
652
630
|
addedFunctions: functions,
|
|
653
631
|
addedVariables: variables,
|
|
654
632
|
addedImports: imports,
|
|
633
|
+
notes,
|
|
634
|
+
}).finally(() => {
|
|
635
|
+
if (gen !== blueprintPersistGen.current) return
|
|
636
|
+
if (notePersistTimer.current != null) return
|
|
637
|
+
notesDirty.current = false
|
|
655
638
|
})
|
|
656
639
|
},
|
|
657
|
-
[
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
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],
|
|
666
684
|
)
|
|
667
685
|
|
|
668
686
|
const placeBlock = useCallback(
|
|
@@ -812,8 +830,11 @@ function Explorer({
|
|
|
812
830
|
const selected = userBlocks.find((block) => block.id === selectedId)
|
|
813
831
|
if (!selected || selected.naming) return false
|
|
814
832
|
const next = userBlocks.filter((block) => block.id !== selectedId)
|
|
833
|
+
const notes = dropBlueprintFileNotes(blueprintNotesRef.current, [selectedId])
|
|
834
|
+
blueprintNotesRef.current = notes
|
|
815
835
|
setUserBlocks(next)
|
|
816
|
-
|
|
836
|
+
setBlueprintNotes(notes)
|
|
837
|
+
persistBlueprint(next, userIslands, undefined, undefined, undefined, notes)
|
|
817
838
|
setSelectedId(null)
|
|
818
839
|
return true
|
|
819
840
|
}, [canPlace, persistBlueprint, selectedId, userBlocks, userIslands])
|
|
@@ -972,8 +993,23 @@ function Explorer({
|
|
|
972
993
|
const next = blueprintFunctions.filter(
|
|
973
994
|
(item) => !(item.file === fileId && item.name === name),
|
|
974
995
|
)
|
|
996
|
+
const notes = dropBlueprintSymbolNote(
|
|
997
|
+
blueprintNotesRef.current,
|
|
998
|
+
fileId,
|
|
999
|
+
'function',
|
|
1000
|
+
name,
|
|
1001
|
+
)
|
|
1002
|
+
blueprintNotesRef.current = notes
|
|
975
1003
|
setBlueprintFunctions(next)
|
|
976
|
-
|
|
1004
|
+
setBlueprintNotes(notes)
|
|
1005
|
+
persistBlueprint(
|
|
1006
|
+
userBlocks,
|
|
1007
|
+
userIslands,
|
|
1008
|
+
next,
|
|
1009
|
+
blueprintVariables,
|
|
1010
|
+
blueprintImports,
|
|
1011
|
+
notes,
|
|
1012
|
+
)
|
|
977
1013
|
},
|
|
978
1014
|
[
|
|
979
1015
|
blueprintFunctions,
|
|
@@ -992,8 +1028,23 @@ function Explorer({
|
|
|
992
1028
|
const next = blueprintVariables.filter(
|
|
993
1029
|
(item) => !(item.file === fileId && item.name === name),
|
|
994
1030
|
)
|
|
1031
|
+
const notes = dropBlueprintSymbolNote(
|
|
1032
|
+
blueprintNotesRef.current,
|
|
1033
|
+
fileId,
|
|
1034
|
+
'variable',
|
|
1035
|
+
name,
|
|
1036
|
+
)
|
|
1037
|
+
blueprintNotesRef.current = notes
|
|
995
1038
|
setBlueprintVariables(next)
|
|
996
|
-
|
|
1039
|
+
setBlueprintNotes(notes)
|
|
1040
|
+
persistBlueprint(
|
|
1041
|
+
userBlocks,
|
|
1042
|
+
userIslands,
|
|
1043
|
+
blueprintFunctions,
|
|
1044
|
+
next,
|
|
1045
|
+
blueprintImports,
|
|
1046
|
+
notes,
|
|
1047
|
+
)
|
|
997
1048
|
},
|
|
998
1049
|
[
|
|
999
1050
|
blueprintFunctions,
|
|
@@ -1037,6 +1088,7 @@ function Explorer({
|
|
|
1037
1088
|
if (!namingId && !namingIslandId) return
|
|
1038
1089
|
const onKey = (event: KeyboardEvent) => {
|
|
1039
1090
|
if (event.code !== 'Escape') return
|
|
1091
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1040
1092
|
event.preventDefault()
|
|
1041
1093
|
if (namingId) cancelBlockName(namingId)
|
|
1042
1094
|
if (namingIslandId) cancelIslandName(namingIslandId)
|
|
@@ -1052,16 +1104,7 @@ function Explorer({
|
|
|
1052
1104
|
useEffect(() => {
|
|
1053
1105
|
const onKey = (event: KeyboardEvent) => {
|
|
1054
1106
|
if (event.repeat || event.code !== 'Backspace') return
|
|
1055
|
-
|
|
1056
|
-
if (
|
|
1057
|
-
target instanceof HTMLElement &&
|
|
1058
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1059
|
-
target.tagName === 'INPUT' ||
|
|
1060
|
-
target.tagName === 'SELECT' ||
|
|
1061
|
-
target.isContentEditable)
|
|
1062
|
-
) {
|
|
1063
|
-
return
|
|
1064
|
-
}
|
|
1107
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1065
1108
|
if (!deleteSelectedCreatedBlock()) return
|
|
1066
1109
|
event.preventDefault()
|
|
1067
1110
|
}
|
|
@@ -1101,16 +1144,7 @@ function Explorer({
|
|
|
1101
1144
|
useEffect(() => {
|
|
1102
1145
|
const onKey = (event: KeyboardEvent) => {
|
|
1103
1146
|
if (event.repeat || event.code !== 'KeyK') return
|
|
1104
|
-
|
|
1105
|
-
if (
|
|
1106
|
-
target instanceof HTMLElement &&
|
|
1107
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1108
|
-
target.tagName === 'INPUT' ||
|
|
1109
|
-
target.tagName === 'SELECT' ||
|
|
1110
|
-
target.isContentEditable)
|
|
1111
|
-
) {
|
|
1112
|
-
return
|
|
1113
|
-
}
|
|
1147
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1114
1148
|
event.preventDefault()
|
|
1115
1149
|
toggleImportedBy()
|
|
1116
1150
|
}
|
|
@@ -1121,16 +1155,7 @@ function Explorer({
|
|
|
1121
1155
|
useEffect(() => {
|
|
1122
1156
|
const onKey = (event: KeyboardEvent) => {
|
|
1123
1157
|
if (event.repeat || event.code !== 'KeyG') return
|
|
1124
|
-
|
|
1125
|
-
if (
|
|
1126
|
-
target instanceof HTMLElement &&
|
|
1127
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1128
|
-
target.tagName === 'INPUT' ||
|
|
1129
|
-
target.tagName === 'SELECT' ||
|
|
1130
|
-
target.isContentEditable)
|
|
1131
|
-
) {
|
|
1132
|
-
return
|
|
1133
|
-
}
|
|
1158
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1134
1159
|
if (!canToggleBranchChanges) return
|
|
1135
1160
|
event.preventDefault()
|
|
1136
1161
|
toggleShowBranchChanges()
|
|
@@ -1164,16 +1189,7 @@ function Explorer({
|
|
|
1164
1189
|
if (mode !== 'map' || !hasChangeSet) return
|
|
1165
1190
|
const onKey = (event: KeyboardEvent) => {
|
|
1166
1191
|
if (event.repeat || event.code !== 'KeyC') return
|
|
1167
|
-
|
|
1168
|
-
if (
|
|
1169
|
-
target instanceof HTMLElement &&
|
|
1170
|
-
(target.tagName === 'TEXTAREA' ||
|
|
1171
|
-
target.tagName === 'INPUT' ||
|
|
1172
|
-
target.tagName === 'SELECT' ||
|
|
1173
|
-
target.isContentEditable)
|
|
1174
|
-
) {
|
|
1175
|
-
return
|
|
1176
|
-
}
|
|
1192
|
+
if (shouldIgnoreShortcut(event)) return
|
|
1177
1193
|
event.preventDefault()
|
|
1178
1194
|
toggleChangePathsOnly()
|
|
1179
1195
|
}
|
|
@@ -1187,6 +1203,29 @@ function Explorer({
|
|
|
1187
1203
|
try {
|
|
1188
1204
|
const bundle = await fetchAgentIntents()
|
|
1189
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
|
+
}
|
|
1190
1229
|
setNextAttachSessionId(bundle.nextAttachSessionId)
|
|
1191
1230
|
const merged: AgentIntent[] = []
|
|
1192
1231
|
for (const next of bundle.intents) {
|
|
@@ -1259,6 +1298,64 @@ function Explorer({
|
|
|
1259
1298
|
...blueprintImportEdges,
|
|
1260
1299
|
]
|
|
1261
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])
|
|
1262
1359
|
|
|
1263
1360
|
return (
|
|
1264
1361
|
<>
|
|
@@ -1309,8 +1406,11 @@ function Explorer({
|
|
|
1309
1406
|
onBlueprintMenu={canPlace ? setMapMenu : undefined}
|
|
1310
1407
|
onCommitName={commitBlockName}
|
|
1311
1408
|
onCancelName={cancelBlockName}
|
|
1312
|
-
|
|
1313
|
-
|
|
1409
|
+
onCommitIslandName={commitIslandName}
|
|
1410
|
+
onCancelIslandName={cancelIslandName}
|
|
1411
|
+
userCreatedBlocks={visibleBlocks}
|
|
1412
|
+
userCreatedIslands={visibleIslands}
|
|
1413
|
+
overlayBlocks={overlayBlocks}
|
|
1314
1414
|
mapGraph={
|
|
1315
1415
|
changePathsOnly && hasChangeSet ? changePathGraph : null
|
|
1316
1416
|
}
|
|
@@ -1368,12 +1468,14 @@ function Explorer({
|
|
|
1368
1468
|
blueprintFunctions={blueprintFunctions}
|
|
1369
1469
|
blueprintVariables={blueprintVariables}
|
|
1370
1470
|
blueprintImports={blueprintImports}
|
|
1471
|
+
blueprintNotes={blueprintNotes}
|
|
1371
1472
|
onAddBlueprintFunction={addBlueprintFunction}
|
|
1372
1473
|
onAddBlueprintVariable={addBlueprintVariable}
|
|
1373
1474
|
onAddBlueprintImport={addBlueprintImport}
|
|
1374
1475
|
onRemoveBlueprintFunction={removeBlueprintFunction}
|
|
1375
1476
|
onRemoveBlueprintVariable={removeBlueprintVariable}
|
|
1376
1477
|
onRemoveBlueprintImport={removeBlueprintImport}
|
|
1478
|
+
onSetBlueprintNote={applyBlueprintNote}
|
|
1377
1479
|
onMapAddFile={placeBlockOnFolder}
|
|
1378
1480
|
onMapAddFolder={placeIslandOnFolder}
|
|
1379
1481
|
onInspectFile={inspectFile}
|
|
@@ -1381,6 +1483,12 @@ function Explorer({
|
|
|
1381
1483
|
plannedIds={plannedIds}
|
|
1382
1484
|
createdIds={plannedCreates}
|
|
1383
1485
|
deletedIds={deletedIds}
|
|
1486
|
+
blueprintHidden={blueprintHidden}
|
|
1487
|
+
blueprintHasContent={blueprintHasContent}
|
|
1488
|
+
blueprintCanCleanup={blueprintCanCleanup}
|
|
1489
|
+
onToggleBlueprintHidden={toggleBlueprintHidden}
|
|
1490
|
+
onClearBlueprint={clearSharedBlueprint}
|
|
1491
|
+
onCleanupBlueprint={cleanupSharedBlueprint}
|
|
1384
1492
|
/>
|
|
1385
1493
|
<MapContextMenu
|
|
1386
1494
|
menu={mapMenu}
|