@jkwd/inbase 0.1.18 → 0.1.20
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 +3 -3
- package/apps/explorer/scripts/patch-lib.d.ts +2 -0
- package/apps/explorer/scripts/patch-lib.mjs +2 -0
- package/apps/explorer/scripts/session-store.d.ts +45 -0
- package/apps/explorer/scripts/session-store.mjs +281 -5
- package/apps/explorer/src/App.tsx +114 -4
- package/apps/explorer/src/agentIntent.ts +76 -1
- package/apps/explorer/src/index.css +65 -0
- package/apps/explorer/src/scene/FileBlock.tsx +27 -0
- package/apps/explorer/src/scene/FolderArea.tsx +21 -0
- package/apps/explorer/src/scene/MapView.tsx +1 -11
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +16 -3
- package/apps/explorer/src/scene/World.tsx +22 -4
- package/apps/explorer/src/types.ts +16 -0
- package/apps/explorer/src/ui/EyeIcon.tsx +26 -0
- package/apps/explorer/src/ui/HUD.tsx +377 -26
- package/apps/explorer/src/ui/MapContextMenu.tsx +18 -1
- package/apps/explorer/src/userCreated.ts +97 -0
- package/apps/explorer/vite.config.ts +18 -1
- package/bin/session.mjs +41 -11
- package/package.json +1 -1
- package/skill/commands/inbase.md +1 -1
- package/skill/inbase/SKILL.md +24 -23
|
@@ -29,17 +29,22 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
defaultBlockSpot,
|
|
31
31
|
dropBlueprintFileNotes,
|
|
32
|
+
dropBlueprintFilePointers,
|
|
32
33
|
dropBlueprintSymbolNote,
|
|
34
|
+
dropBlueprintSymbolPointer,
|
|
35
|
+
findBlueprintPointer,
|
|
33
36
|
isBlueprintSymbolName,
|
|
34
37
|
namedCreatedBlocks,
|
|
35
38
|
namedCreatedIslands,
|
|
36
39
|
parseBlueprintImport,
|
|
37
40
|
parseBlueprintNotes,
|
|
41
|
+
parseBlueprintPointers,
|
|
38
42
|
parseUserCreatedBlocks,
|
|
39
43
|
parseUserCreatedIslands,
|
|
40
44
|
resolveCreatedFile,
|
|
41
45
|
resolveCreatedIsland,
|
|
42
46
|
setBlueprintNote,
|
|
47
|
+
toggleBlueprintPointer,
|
|
43
48
|
withBlueprintIntent,
|
|
44
49
|
withUserCreatedGraph,
|
|
45
50
|
withUserCreatedLayout,
|
|
@@ -51,6 +56,8 @@ import {
|
|
|
51
56
|
type AimedRelation,
|
|
52
57
|
type BlueprintNote,
|
|
53
58
|
type BlueprintNoteKind,
|
|
59
|
+
type BlueprintPointer,
|
|
60
|
+
type BlueprintPointerKind,
|
|
54
61
|
type CodebaseGraph,
|
|
55
62
|
type FlyTo,
|
|
56
63
|
type PatchImportAddition,
|
|
@@ -200,6 +207,9 @@ function Explorer({
|
|
|
200
207
|
PatchImportAddition[]
|
|
201
208
|
>([])
|
|
202
209
|
const [blueprintNotes, setBlueprintNotes] = useState<BlueprintNote[]>([])
|
|
210
|
+
const [blueprintPointers, setBlueprintPointers] = useState<BlueprintPointer[]>(
|
|
211
|
+
[],
|
|
212
|
+
)
|
|
203
213
|
const [blueprintHidden, setBlueprintHidden] = useState(false)
|
|
204
214
|
const userBlocksRef = useRef(userBlocks)
|
|
205
215
|
const userIslandsRef = useRef(userIslands)
|
|
@@ -207,6 +217,7 @@ function Explorer({
|
|
|
207
217
|
const blueprintVariablesRef = useRef(blueprintVariables)
|
|
208
218
|
const blueprintImportsRef = useRef(blueprintImports)
|
|
209
219
|
const blueprintNotesRef = useRef(blueprintNotes)
|
|
220
|
+
const blueprintPointersRef = useRef(blueprintPointers)
|
|
210
221
|
const notesDirty = useRef(false)
|
|
211
222
|
const blueprintPersistGen = useRef(0)
|
|
212
223
|
const notePersistTimer = useRef<number | null>(null)
|
|
@@ -216,6 +227,7 @@ function Explorer({
|
|
|
216
227
|
blueprintVariablesRef.current = blueprintVariables
|
|
217
228
|
blueprintImportsRef.current = blueprintImports
|
|
218
229
|
blueprintNotesRef.current = blueprintNotes
|
|
230
|
+
blueprintPointersRef.current = blueprintPointers
|
|
219
231
|
const namingId = userBlocks.find((block) => block.naming)?.id ?? null
|
|
220
232
|
const namingIslandId = userIslands.find((island) => island.naming)?.id ?? null
|
|
221
233
|
const naming = Boolean(namingId || namingIslandId)
|
|
@@ -296,11 +308,15 @@ function Explorer({
|
|
|
296
308
|
for (const item of blueprintVariables) ids.add(item.file)
|
|
297
309
|
for (const item of blueprintImports) ids.add(item.file)
|
|
298
310
|
for (const note of blueprintNotes) ids.add(note.file)
|
|
311
|
+
for (const pointer of blueprintPointers) {
|
|
312
|
+
if (pointer.kind !== 'folder') ids.add(pointer.path)
|
|
313
|
+
}
|
|
299
314
|
return [...ids]
|
|
300
315
|
}, [
|
|
301
316
|
blueprintFunctions,
|
|
302
317
|
blueprintImports,
|
|
303
318
|
blueprintNotes,
|
|
319
|
+
blueprintPointers,
|
|
304
320
|
blueprintVariables,
|
|
305
321
|
changeSet.creates,
|
|
306
322
|
changeSet.deletes,
|
|
@@ -314,8 +330,11 @@ function Explorer({
|
|
|
314
330
|
if (island.path) paths.add(island.path)
|
|
315
331
|
else if (island.id) paths.add(island.id)
|
|
316
332
|
}
|
|
333
|
+
for (const pointer of blueprintPointers) {
|
|
334
|
+
if (pointer.kind === 'folder') paths.add(pointer.path)
|
|
335
|
+
}
|
|
317
336
|
return [...paths]
|
|
318
|
-
}, [changeSet.createFolders, userIslands])
|
|
337
|
+
}, [blueprintPointers, changeSet.createFolders, userIslands])
|
|
319
338
|
const hasChangeSet =
|
|
320
339
|
changeFileIds.length > 0 || changeFolderPaths.length > 0
|
|
321
340
|
const changePathGraph = useMemo(() => {
|
|
@@ -475,10 +494,11 @@ function Explorer({
|
|
|
475
494
|
|
|
476
495
|
const flyAlongRelation = useCallback(
|
|
477
496
|
(fromId: string, toId: string) => {
|
|
497
|
+
if (mode !== 'walk') return
|
|
478
498
|
const [x, z] = walkPos.current
|
|
479
499
|
travelToFile(relationTravelTarget(fromId, toId, x, z, layout.files), true)
|
|
480
500
|
},
|
|
481
|
-
[layout.files, travelToFile],
|
|
501
|
+
[layout.files, mode, travelToFile],
|
|
482
502
|
)
|
|
483
503
|
|
|
484
504
|
const runWorkflowAction = useCallback(
|
|
@@ -510,6 +530,7 @@ function Explorer({
|
|
|
510
530
|
addedVariables: blueprintVariables,
|
|
511
531
|
addedImports: blueprintImports,
|
|
512
532
|
notes: blueprintNotes,
|
|
533
|
+
pointers: blueprintPointers,
|
|
513
534
|
}
|
|
514
535
|
: {}),
|
|
515
536
|
},
|
|
@@ -533,6 +554,7 @@ function Explorer({
|
|
|
533
554
|
blueprintFunctions,
|
|
534
555
|
blueprintImports,
|
|
535
556
|
blueprintNotes,
|
|
557
|
+
blueprintPointers,
|
|
536
558
|
blueprintVariables,
|
|
537
559
|
intents,
|
|
538
560
|
onRefreshGraph,
|
|
@@ -617,6 +639,7 @@ function Explorer({
|
|
|
617
639
|
variables: PatchSymbolAddition[] = blueprintVariablesRef.current,
|
|
618
640
|
imports: PatchImportAddition[] = blueprintImportsRef.current,
|
|
619
641
|
notes: BlueprintNote[] = blueprintNotesRef.current,
|
|
642
|
+
pointers: BlueprintPointer[] = blueprintPointersRef.current,
|
|
620
643
|
) => {
|
|
621
644
|
if (notePersistTimer.current != null) {
|
|
622
645
|
window.clearTimeout(notePersistTimer.current)
|
|
@@ -631,6 +654,7 @@ function Explorer({
|
|
|
631
654
|
addedVariables: variables,
|
|
632
655
|
addedImports: imports,
|
|
633
656
|
notes,
|
|
657
|
+
pointers,
|
|
634
658
|
}).finally(() => {
|
|
635
659
|
if (gen !== blueprintPersistGen.current) return
|
|
636
660
|
if (notePersistTimer.current != null) return
|
|
@@ -663,6 +687,7 @@ function Explorer({
|
|
|
663
687
|
addedVariables: blueprintVariablesRef.current,
|
|
664
688
|
addedImports: blueprintImportsRef.current,
|
|
665
689
|
notes: blueprintNotesRef.current,
|
|
690
|
+
pointers: blueprintPointersRef.current,
|
|
666
691
|
})
|
|
667
692
|
notesDirty.current = false
|
|
668
693
|
}
|
|
@@ -683,6 +708,28 @@ function Explorer({
|
|
|
683
708
|
[persistBlueprintSoon],
|
|
684
709
|
)
|
|
685
710
|
|
|
711
|
+
const applyBlueprintPointer = useCallback(
|
|
712
|
+
(next: {
|
|
713
|
+
kind: BlueprintPointerKind
|
|
714
|
+
path: string
|
|
715
|
+
name?: string
|
|
716
|
+
}) => {
|
|
717
|
+
const pointers = toggleBlueprintPointer(blueprintPointersRef.current, next)
|
|
718
|
+
blueprintPointersRef.current = pointers
|
|
719
|
+
setBlueprintPointers(pointers)
|
|
720
|
+
persistBlueprint(
|
|
721
|
+
userBlocksRef.current,
|
|
722
|
+
userIslandsRef.current,
|
|
723
|
+
blueprintFunctionsRef.current,
|
|
724
|
+
blueprintVariablesRef.current,
|
|
725
|
+
blueprintImportsRef.current,
|
|
726
|
+
blueprintNotesRef.current,
|
|
727
|
+
pointers,
|
|
728
|
+
)
|
|
729
|
+
},
|
|
730
|
+
[persistBlueprint],
|
|
731
|
+
)
|
|
732
|
+
|
|
686
733
|
const placeBlock = useCallback(
|
|
687
734
|
(spot: { x: number; z: number; folder: string }) => {
|
|
688
735
|
if (!canPlace) return
|
|
@@ -831,10 +878,23 @@ function Explorer({
|
|
|
831
878
|
if (!selected || selected.naming) return false
|
|
832
879
|
const next = userBlocks.filter((block) => block.id !== selectedId)
|
|
833
880
|
const notes = dropBlueprintFileNotes(blueprintNotesRef.current, [selectedId])
|
|
881
|
+
const pointers = dropBlueprintFilePointers(blueprintPointersRef.current, [
|
|
882
|
+
selectedId,
|
|
883
|
+
])
|
|
834
884
|
blueprintNotesRef.current = notes
|
|
885
|
+
blueprintPointersRef.current = pointers
|
|
835
886
|
setUserBlocks(next)
|
|
836
887
|
setBlueprintNotes(notes)
|
|
837
|
-
|
|
888
|
+
setBlueprintPointers(pointers)
|
|
889
|
+
persistBlueprint(
|
|
890
|
+
next,
|
|
891
|
+
userIslands,
|
|
892
|
+
undefined,
|
|
893
|
+
undefined,
|
|
894
|
+
undefined,
|
|
895
|
+
notes,
|
|
896
|
+
pointers,
|
|
897
|
+
)
|
|
838
898
|
setSelectedId(null)
|
|
839
899
|
return true
|
|
840
900
|
}, [canPlace, persistBlueprint, selectedId, userBlocks, userIslands])
|
|
@@ -999,9 +1059,17 @@ function Explorer({
|
|
|
999
1059
|
'function',
|
|
1000
1060
|
name,
|
|
1001
1061
|
)
|
|
1062
|
+
const pointers = dropBlueprintSymbolPointer(
|
|
1063
|
+
blueprintPointersRef.current,
|
|
1064
|
+
fileId,
|
|
1065
|
+
'function',
|
|
1066
|
+
name,
|
|
1067
|
+
)
|
|
1002
1068
|
blueprintNotesRef.current = notes
|
|
1069
|
+
blueprintPointersRef.current = pointers
|
|
1003
1070
|
setBlueprintFunctions(next)
|
|
1004
1071
|
setBlueprintNotes(notes)
|
|
1072
|
+
setBlueprintPointers(pointers)
|
|
1005
1073
|
persistBlueprint(
|
|
1006
1074
|
userBlocks,
|
|
1007
1075
|
userIslands,
|
|
@@ -1009,6 +1077,7 @@ function Explorer({
|
|
|
1009
1077
|
blueprintVariables,
|
|
1010
1078
|
blueprintImports,
|
|
1011
1079
|
notes,
|
|
1080
|
+
pointers,
|
|
1012
1081
|
)
|
|
1013
1082
|
},
|
|
1014
1083
|
[
|
|
@@ -1034,9 +1103,17 @@ function Explorer({
|
|
|
1034
1103
|
'variable',
|
|
1035
1104
|
name,
|
|
1036
1105
|
)
|
|
1106
|
+
const pointers = dropBlueprintSymbolPointer(
|
|
1107
|
+
blueprintPointersRef.current,
|
|
1108
|
+
fileId,
|
|
1109
|
+
'variable',
|
|
1110
|
+
name,
|
|
1111
|
+
)
|
|
1037
1112
|
blueprintNotesRef.current = notes
|
|
1113
|
+
blueprintPointersRef.current = pointers
|
|
1038
1114
|
setBlueprintVariables(next)
|
|
1039
1115
|
setBlueprintNotes(notes)
|
|
1116
|
+
setBlueprintPointers(pointers)
|
|
1040
1117
|
persistBlueprint(
|
|
1041
1118
|
userBlocks,
|
|
1042
1119
|
userIslands,
|
|
@@ -1044,6 +1121,7 @@ function Explorer({
|
|
|
1044
1121
|
next,
|
|
1045
1122
|
blueprintImports,
|
|
1046
1123
|
notes,
|
|
1124
|
+
pointers,
|
|
1047
1125
|
)
|
|
1048
1126
|
},
|
|
1049
1127
|
[
|
|
@@ -1221,6 +1299,11 @@ function Explorer({
|
|
|
1221
1299
|
setBlueprintFunctions(bundle.blueprint.addedFunctions)
|
|
1222
1300
|
setBlueprintVariables(bundle.blueprint.addedVariables)
|
|
1223
1301
|
setBlueprintImports(bundle.blueprint.addedImports)
|
|
1302
|
+
if (!notesDirty.current) {
|
|
1303
|
+
const nextPointers = parseBlueprintPointers(bundle.blueprint.pointers)
|
|
1304
|
+
blueprintPointersRef.current = nextPointers
|
|
1305
|
+
setBlueprintPointers(nextPointers)
|
|
1306
|
+
}
|
|
1224
1307
|
if (!notesDirty.current && !isKeyboardIsolated()) {
|
|
1225
1308
|
const nextNotes = parseBlueprintNotes(bundle.blueprint.notes)
|
|
1226
1309
|
blueprintNotesRef.current = nextNotes
|
|
@@ -1304,7 +1387,8 @@ function Explorer({
|
|
|
1304
1387
|
blueprintFunctions.length > 0 ||
|
|
1305
1388
|
blueprintVariables.length > 0 ||
|
|
1306
1389
|
blueprintImports.length > 0 ||
|
|
1307
|
-
blueprintNotes.length > 0
|
|
1390
|
+
blueprintNotes.length > 0 ||
|
|
1391
|
+
blueprintPointers.length > 0
|
|
1308
1392
|
const blueprintCanCleanup =
|
|
1309
1393
|
userBlocks.some((block) => !block.naming && knownFileIds.has(block.id)) ||
|
|
1310
1394
|
userIslands.some(
|
|
@@ -1324,7 +1408,9 @@ function Explorer({
|
|
|
1324
1408
|
setBlueprintVariables([])
|
|
1325
1409
|
setBlueprintImports([])
|
|
1326
1410
|
blueprintNotesRef.current = []
|
|
1411
|
+
blueprintPointersRef.current = []
|
|
1327
1412
|
setBlueprintNotes([])
|
|
1413
|
+
setBlueprintPointers([])
|
|
1328
1414
|
void persistBlueprintClear()
|
|
1329
1415
|
}, [])
|
|
1330
1416
|
|
|
@@ -1411,6 +1497,20 @@ function Explorer({
|
|
|
1411
1497
|
userCreatedBlocks={visibleBlocks}
|
|
1412
1498
|
userCreatedIslands={visibleIslands}
|
|
1413
1499
|
overlayBlocks={overlayBlocks}
|
|
1500
|
+
pointedFileIds={
|
|
1501
|
+
blueprintHidden
|
|
1502
|
+
? undefined
|
|
1503
|
+
: blueprintPointers.flatMap((item) =>
|
|
1504
|
+
item.kind === 'folder' ? [] : [item.path],
|
|
1505
|
+
)
|
|
1506
|
+
}
|
|
1507
|
+
pointedFolderPaths={
|
|
1508
|
+
blueprintHidden
|
|
1509
|
+
? undefined
|
|
1510
|
+
: blueprintPointers.flatMap((item) =>
|
|
1511
|
+
item.kind === 'folder' ? [item.path] : [],
|
|
1512
|
+
)
|
|
1513
|
+
}
|
|
1414
1514
|
mapGraph={
|
|
1415
1515
|
changePathsOnly && hasChangeSet ? changePathGraph : null
|
|
1416
1516
|
}
|
|
@@ -1469,6 +1569,7 @@ function Explorer({
|
|
|
1469
1569
|
blueprintVariables={blueprintVariables}
|
|
1470
1570
|
blueprintImports={blueprintImports}
|
|
1471
1571
|
blueprintNotes={blueprintNotes}
|
|
1572
|
+
blueprintPointers={blueprintPointers}
|
|
1472
1573
|
onAddBlueprintFunction={addBlueprintFunction}
|
|
1473
1574
|
onAddBlueprintVariable={addBlueprintVariable}
|
|
1474
1575
|
onAddBlueprintImport={addBlueprintImport}
|
|
@@ -1476,6 +1577,7 @@ function Explorer({
|
|
|
1476
1577
|
onRemoveBlueprintVariable={removeBlueprintVariable}
|
|
1477
1578
|
onRemoveBlueprintImport={removeBlueprintImport}
|
|
1478
1579
|
onSetBlueprintNote={applyBlueprintNote}
|
|
1580
|
+
onToggleBlueprintPointer={applyBlueprintPointer}
|
|
1479
1581
|
onMapAddFile={placeBlockOnFolder}
|
|
1480
1582
|
onMapAddFolder={placeIslandOnFolder}
|
|
1481
1583
|
onInspectFile={inspectFile}
|
|
@@ -1492,8 +1594,16 @@ function Explorer({
|
|
|
1492
1594
|
/>
|
|
1493
1595
|
<MapContextMenu
|
|
1494
1596
|
menu={mapMenu}
|
|
1597
|
+
pointed={
|
|
1598
|
+
mapMenu
|
|
1599
|
+
? findBlueprintPointer(blueprintPointers, 'folder', mapMenu.folder)
|
|
1600
|
+
: false
|
|
1601
|
+
}
|
|
1495
1602
|
onAddFile={placeBlockOnFolder}
|
|
1496
1603
|
onAddFolder={placeIslandOnFolder}
|
|
1604
|
+
onPointToFolder={(folder) =>
|
|
1605
|
+
applyBlueprintPointer({ kind: 'folder', path: folder })
|
|
1606
|
+
}
|
|
1497
1607
|
onClose={() => setMapMenu(null)}
|
|
1498
1608
|
/>
|
|
1499
1609
|
</>
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AgentIntent,
|
|
3
3
|
AgentIntentBundle,
|
|
4
4
|
BlueprintNote,
|
|
5
|
+
BlueprintPointer,
|
|
5
6
|
PatchImport,
|
|
6
7
|
PatchImportAddition,
|
|
7
8
|
PatchSymbolAddition,
|
|
@@ -11,6 +12,7 @@ import type {
|
|
|
11
12
|
} from './types'
|
|
12
13
|
import {
|
|
13
14
|
parseBlueprintNotes,
|
|
15
|
+
parseBlueprintPointers,
|
|
14
16
|
parseUserCreatedBlocks,
|
|
15
17
|
parseUserCreatedIslands,
|
|
16
18
|
} from './userCreated'
|
|
@@ -65,6 +67,26 @@ function normalizeAck(
|
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
function normalizeContextFiles(value: unknown): NonNullable<AgentIntent['contextFiles']> {
|
|
71
|
+
if (!Array.isArray(value)) return []
|
|
72
|
+
return value.flatMap((item) => {
|
|
73
|
+
if (!item || typeof item !== 'object') return []
|
|
74
|
+
const id = (item as { id?: unknown }).id
|
|
75
|
+
const name = (item as { name?: unknown }).name
|
|
76
|
+
const mimeType = (item as { mimeType?: unknown }).mimeType
|
|
77
|
+
const size = (item as { size?: unknown }).size
|
|
78
|
+
if (
|
|
79
|
+
typeof id !== 'string' ||
|
|
80
|
+
typeof name !== 'string' ||
|
|
81
|
+
typeof mimeType !== 'string' ||
|
|
82
|
+
typeof size !== 'number'
|
|
83
|
+
) {
|
|
84
|
+
return []
|
|
85
|
+
}
|
|
86
|
+
return [{ id, name, mimeType, size }]
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
68
90
|
export const emptyIntent: AgentIntent = {
|
|
69
91
|
updatedAt: null,
|
|
70
92
|
showMap: false,
|
|
@@ -101,6 +123,7 @@ export const emptyIntent: AgentIntent = {
|
|
|
101
123
|
listening: false,
|
|
102
124
|
lastAck: null,
|
|
103
125
|
initialInstruction: null,
|
|
126
|
+
contextFiles: [],
|
|
104
127
|
creationMode: false,
|
|
105
128
|
canEnterBlueprint: false,
|
|
106
129
|
blueprintHidden: false,
|
|
@@ -112,6 +135,7 @@ export const emptyIntent: AgentIntent = {
|
|
|
112
135
|
blueprintVariables: [],
|
|
113
136
|
blueprintImports: [],
|
|
114
137
|
blueprintNotes: [],
|
|
138
|
+
blueprintPointers: [],
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
@@ -155,6 +179,7 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
|
155
179
|
lastAck: normalizeAck(data?.lastAck),
|
|
156
180
|
initialInstruction:
|
|
157
181
|
typeof data?.initialInstruction === 'string' ? data.initialInstruction : null,
|
|
182
|
+
contextFiles: normalizeContextFiles(data?.contextFiles),
|
|
158
183
|
creationMode: Boolean(data?.creationMode),
|
|
159
184
|
canEnterBlueprint: Boolean(data?.canEnterBlueprint),
|
|
160
185
|
blueprintHidden: Boolean(data?.blueprintHidden),
|
|
@@ -170,6 +195,7 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
|
170
195
|
blueprintVariables: normalizeSymbolAdditions(data?.blueprintVariables),
|
|
171
196
|
blueprintImports: normalizeImportAdditions(data?.blueprintImports),
|
|
172
197
|
blueprintNotes: parseBlueprintNotes(data?.blueprintNotes),
|
|
198
|
+
blueprintPointers: parseBlueprintPointers(data?.blueprintPointers),
|
|
173
199
|
}
|
|
174
200
|
}
|
|
175
201
|
|
|
@@ -184,6 +210,7 @@ function normalizeBlueprint(data: Partial<AgentIntentBundle['blueprint']> | null
|
|
|
184
210
|
addedVariables: normalizeSymbolAdditions(data?.addedVariables),
|
|
185
211
|
addedImports: normalizeImportAdditions(data?.addedImports),
|
|
186
212
|
notes: parseBlueprintNotes(data?.notes),
|
|
213
|
+
pointers: parseBlueprintPointers(data?.pointers),
|
|
187
214
|
}
|
|
188
215
|
}
|
|
189
216
|
|
|
@@ -234,13 +261,15 @@ export async function fetchAgentIntents(): Promise<AgentIntentBundle> {
|
|
|
234
261
|
intent.blueprintFunctions.length > 0 ||
|
|
235
262
|
intent.blueprintVariables.length > 0 ||
|
|
236
263
|
intent.blueprintImports.length > 0 ||
|
|
237
|
-
intent.blueprintNotes.length > 0
|
|
264
|
+
intent.blueprintNotes.length > 0 ||
|
|
265
|
+
intent.blueprintPointers.length > 0,
|
|
238
266
|
userCreatedBlocks: intent.userCreatedBlocks,
|
|
239
267
|
userCreatedIslands: intent.userCreatedIslands,
|
|
240
268
|
addedFunctions: intent.blueprintFunctions,
|
|
241
269
|
addedVariables: intent.blueprintVariables,
|
|
242
270
|
addedImports: intent.blueprintImports,
|
|
243
271
|
notes: intent.blueprintNotes,
|
|
272
|
+
pointers: intent.blueprintPointers,
|
|
244
273
|
}),
|
|
245
274
|
}
|
|
246
275
|
}
|
|
@@ -273,6 +302,7 @@ export async function performAgentAction(
|
|
|
273
302
|
addedVariables?: PatchSymbolAddition[]
|
|
274
303
|
addedImports?: PatchImportAddition[]
|
|
275
304
|
notes?: BlueprintNote[]
|
|
305
|
+
pointers?: BlueprintPointer[]
|
|
276
306
|
} = {},
|
|
277
307
|
) {
|
|
278
308
|
const response = await fetch('/api/agent-intent', {
|
|
@@ -296,6 +326,7 @@ export function persistSessionBlueprint(
|
|
|
296
326
|
addedVariables?: PatchSymbolAddition[]
|
|
297
327
|
addedImports?: PatchImportAddition[]
|
|
298
328
|
notes?: BlueprintNote[]
|
|
329
|
+
pointers?: BlueprintPointer[]
|
|
299
330
|
},
|
|
300
331
|
) {
|
|
301
332
|
return fetch('/api/agent-intent', {
|
|
@@ -352,6 +383,50 @@ export function persistInitialInstruction(sessionId: string, instruction: string
|
|
|
352
383
|
})
|
|
353
384
|
}
|
|
354
385
|
|
|
386
|
+
export async function persistAddContextFiles(
|
|
387
|
+
sessionId: string,
|
|
388
|
+
files: Array<{ name: string; mimeType: string; contentBase64: string }>,
|
|
389
|
+
) {
|
|
390
|
+
const response = await fetch('/api/agent-intent', {
|
|
391
|
+
method: 'POST',
|
|
392
|
+
headers: { 'Content-Type': 'application/json' },
|
|
393
|
+
body: JSON.stringify({
|
|
394
|
+
action: 'add_context_files',
|
|
395
|
+
sessionId,
|
|
396
|
+
files,
|
|
397
|
+
}),
|
|
398
|
+
})
|
|
399
|
+
if (!response.ok) {
|
|
400
|
+
const detail = await response.text()
|
|
401
|
+
let message = detail || 'Could not attach files'
|
|
402
|
+
try {
|
|
403
|
+
const parsed = JSON.parse(detail) as { error?: string }
|
|
404
|
+
if (parsed?.error) message = parsed.error
|
|
405
|
+
} catch {
|
|
406
|
+
// Use the raw body when it is not JSON.
|
|
407
|
+
}
|
|
408
|
+
throw new Error(message)
|
|
409
|
+
}
|
|
410
|
+
return normalize((await response.json()) as AgentIntent)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export async function persistRemoveContextFile(sessionId: string, fileId: string) {
|
|
414
|
+
const response = await fetch('/api/agent-intent', {
|
|
415
|
+
method: 'POST',
|
|
416
|
+
headers: { 'Content-Type': 'application/json' },
|
|
417
|
+
body: JSON.stringify({
|
|
418
|
+
action: 'remove_context_file',
|
|
419
|
+
sessionId,
|
|
420
|
+
fileId,
|
|
421
|
+
}),
|
|
422
|
+
})
|
|
423
|
+
if (!response.ok) {
|
|
424
|
+
const detail = await response.text()
|
|
425
|
+
throw new Error(detail || 'Could not remove file')
|
|
426
|
+
}
|
|
427
|
+
return normalize((await response.json()) as AgentIntent)
|
|
428
|
+
}
|
|
429
|
+
|
|
355
430
|
export function persistSessionFocus(sessionId: string) {
|
|
356
431
|
fetch('/api/agent-intent', {
|
|
357
432
|
method: 'POST',
|
|
@@ -1133,6 +1133,71 @@ button {
|
|
|
1133
1133
|
margin-top: 0;
|
|
1134
1134
|
}
|
|
1135
1135
|
|
|
1136
|
+
.hud-context {
|
|
1137
|
+
display: grid;
|
|
1138
|
+
gap: 8px;
|
|
1139
|
+
margin-top: 8px;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.hud-context-drop {
|
|
1143
|
+
width: 100%;
|
|
1144
|
+
min-height: 52px;
|
|
1145
|
+
padding: 10px 8px;
|
|
1146
|
+
color: #8b95a5;
|
|
1147
|
+
background: var(--vc-surface);
|
|
1148
|
+
border: 1px dashed #3a4250;
|
|
1149
|
+
cursor: pointer;
|
|
1150
|
+
font: 12px/1.4 Inter, ui-sans-serif, system-ui, sans-serif;
|
|
1151
|
+
text-align: center;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.hud-context-drop:hover,
|
|
1155
|
+
.hud-context-drop:focus-visible,
|
|
1156
|
+
.hud-context-drop[data-over='true'] {
|
|
1157
|
+
color: #e7ebf2;
|
|
1158
|
+
border-color: #d6b56a;
|
|
1159
|
+
outline: none;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
.hud-context-drop[data-busy='true'],
|
|
1163
|
+
.hud-context-drop:disabled {
|
|
1164
|
+
cursor: wait;
|
|
1165
|
+
opacity: 0.7;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
.hud-context-list {
|
|
1169
|
+
display: grid;
|
|
1170
|
+
gap: 4px;
|
|
1171
|
+
margin: 0;
|
|
1172
|
+
padding: 0;
|
|
1173
|
+
list-style: none;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.hud-context-list li {
|
|
1177
|
+
display: grid;
|
|
1178
|
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
1179
|
+
align-items: center;
|
|
1180
|
+
gap: 6px;
|
|
1181
|
+
color: #e7ebf2;
|
|
1182
|
+
font-size: 11px;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.hud-context-name {
|
|
1186
|
+
overflow: hidden;
|
|
1187
|
+
text-overflow: ellipsis;
|
|
1188
|
+
white-space: nowrap;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
.hud-context-size {
|
|
1192
|
+
color: #8b95a5;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
.hud-context-error {
|
|
1196
|
+
margin: 0;
|
|
1197
|
+
color: #ff8a9b;
|
|
1198
|
+
font-size: 11px;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1136
1201
|
.hud-instruction textarea {
|
|
1137
1202
|
width: 100%;
|
|
1138
1203
|
resize: vertical;
|
|
@@ -2,6 +2,7 @@ import { memo, Suspense } from 'react'
|
|
|
2
2
|
import { Billboard, Edges, Html, Text } from '@react-three/drei'
|
|
3
3
|
import { CHANGE_HIGHLIGHT, CONFIG, dimColor, fileColor, FILE_SELECTION, MAP_SELECTION, type ChangeKind } from '../theme'
|
|
4
4
|
import { NameInput } from '../ui/NameInput'
|
|
5
|
+
import { EyeIcon } from '../ui/EyeIcon'
|
|
5
6
|
import { MapSelectBorder } from './MapSelectBorder'
|
|
6
7
|
import type { FileNode } from '../types'
|
|
7
8
|
import type { PlacedFile } from '../types'
|
|
@@ -30,6 +31,7 @@ type FileBlockProps = {
|
|
|
30
31
|
highlightMapChange?: boolean
|
|
31
32
|
previewLabels?: boolean
|
|
32
33
|
labelVisible?: boolean
|
|
34
|
+
pointed?: boolean
|
|
33
35
|
onCommitName?: (name: string) => void
|
|
34
36
|
onCancelName?: () => void
|
|
35
37
|
}
|
|
@@ -93,6 +95,7 @@ export const FileBlock = memo(function FileBlock({
|
|
|
93
95
|
highlightMapChange = mapMode,
|
|
94
96
|
previewLabels = false,
|
|
95
97
|
labelVisible = true,
|
|
98
|
+
pointed = false,
|
|
96
99
|
onCommitName,
|
|
97
100
|
onCancelName,
|
|
98
101
|
}: FileBlockProps) {
|
|
@@ -191,6 +194,30 @@ export const FileBlock = memo(function FileBlock({
|
|
|
191
194
|
{mapMode && !naming && mark && (
|
|
192
195
|
<MapChangeMark mark={mark} width={width} depth={depth} height={height} />
|
|
193
196
|
)}
|
|
197
|
+
{pointed && !naming && (
|
|
198
|
+
<Html
|
|
199
|
+
position={
|
|
200
|
+
mapMode
|
|
201
|
+
? mark
|
|
202
|
+
? [width * 0.28, height / 2 + 0.16, -depth * 0.28]
|
|
203
|
+
: [0, height / 2 + 0.12, 0]
|
|
204
|
+
: [0, height / 2 + (planned || highlight ? 0.92 : 0.74), 0]
|
|
205
|
+
}
|
|
206
|
+
center
|
|
207
|
+
occlude={false}
|
|
208
|
+
style={{ pointerEvents: 'none' }}
|
|
209
|
+
zIndexRange={[40, 0]}
|
|
210
|
+
>
|
|
211
|
+
<div
|
|
212
|
+
className="blueprint-eye"
|
|
213
|
+
data-map={mapMode ? 'true' : 'false'}
|
|
214
|
+
role="img"
|
|
215
|
+
aria-label="Keep in mind"
|
|
216
|
+
>
|
|
217
|
+
<EyeIcon size={mapMode ? 16 : 18} title="Keep in mind" />
|
|
218
|
+
</div>
|
|
219
|
+
</Html>
|
|
220
|
+
)}
|
|
194
221
|
{naming && onCommitName && onCancelName && (
|
|
195
222
|
<Html
|
|
196
223
|
position={
|
|
@@ -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]}
|
|
@@ -22,7 +22,6 @@ type MapViewProps = {
|
|
|
22
22
|
onLand: (x: number, z: number) => void
|
|
23
23
|
onSelect: (fileId: string | null) => void
|
|
24
24
|
onSelectFolder: (folderPath: string | null) => void
|
|
25
|
-
onTravelTo: (fromId: string, toId: string) => void
|
|
26
25
|
onBlueprintMenu?: (menu: MapBlueprintMenu) => void
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -36,7 +35,6 @@ export function MapView({
|
|
|
36
35
|
onLand,
|
|
37
36
|
onSelect,
|
|
38
37
|
onSelectFolder,
|
|
39
|
-
onTravelTo,
|
|
40
38
|
onBlueprintMenu,
|
|
41
39
|
}: MapViewProps) {
|
|
42
40
|
const size = useThree((state) => state.size)
|
|
@@ -157,18 +155,11 @@ export function MapView({
|
|
|
157
155
|
|
|
158
156
|
const pick = pickAt(event.clientX, event.clientY)
|
|
159
157
|
if (!pick) return
|
|
160
|
-
const {
|
|
158
|
+
const { fileHit } = pick
|
|
161
159
|
if (fileHit) {
|
|
162
160
|
onSelect(fileHit.object.userData.fileId as string)
|
|
163
161
|
return
|
|
164
162
|
}
|
|
165
|
-
if (relationHit) {
|
|
166
|
-
onTravelTo(
|
|
167
|
-
relationHit.object.userData.relationFrom as string,
|
|
168
|
-
relationHit.object.userData.relationTo as string,
|
|
169
|
-
)
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
163
|
|
|
173
164
|
const hit = new THREE.Vector3()
|
|
174
165
|
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)
|
|
@@ -286,7 +277,6 @@ export function MapView({
|
|
|
286
277
|
onBlueprintMenu,
|
|
287
278
|
onSelect,
|
|
288
279
|
onSelectFolder,
|
|
289
|
-
onTravelTo,
|
|
290
280
|
scene,
|
|
291
281
|
selectedFolder,
|
|
292
282
|
])
|