@jkwd/inbase 0.1.4 → 0.1.5
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 -1
- package/apps/explorer/scripts/session-store.d.ts +20 -0
- package/apps/explorer/scripts/session-store.mjs +318 -32
- package/apps/explorer/src/App.tsx +154 -85
- package/apps/explorer/src/agentIntent.ts +33 -1
- package/apps/explorer/src/index.css +217 -2
- package/apps/explorer/src/layout.ts +46 -0
- package/apps/explorer/src/scene/FileBlock.tsx +110 -145
- package/apps/explorer/src/scene/FolderArea.tsx +17 -4
- package/apps/explorer/src/scene/MapSelectBorder.tsx +3 -1
- package/apps/explorer/src/scene/MapView.tsx +10 -12
- package/apps/explorer/src/scene/Player.tsx +27 -0
- package/apps/explorer/src/scene/RelationLines.tsx +36 -32
- package/apps/explorer/src/scene/SelectionController.tsx +21 -3
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +451 -0
- package/apps/explorer/src/scene/World.tsx +16 -35
- package/apps/explorer/src/theme.ts +7 -1
- package/apps/explorer/src/types.ts +12 -0
- package/apps/explorer/src/ui/HUD.tsx +662 -358
- package/apps/explorer/vite.config.ts +33 -21
- package/bin/session.mjs +16 -2
- package/package.json +1 -1
- package/skill/inbase/SKILL.md +22 -14
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
2
2
|
import { Canvas } from '@react-three/fiber'
|
|
3
|
-
import { emptyIntent, fetchAgentIntent, inspectTargetFile, performAgentAction, persistSessionBlueprint } from './agentIntent'
|
|
3
|
+
import { emptyIntent, fetchAgentIntent, fetchAgentIntents, inspectTargetFile, performAgentAction, persistSessionBlueprint } from './agentIntent'
|
|
4
4
|
import { fetchCodebase } from './codebase'
|
|
5
5
|
import {
|
|
6
6
|
layoutWorld,
|
|
@@ -100,7 +100,17 @@ function Explorer({
|
|
|
100
100
|
graph: CodebaseGraph
|
|
101
101
|
onRefreshGraph: () => Promise<void>
|
|
102
102
|
}) {
|
|
103
|
-
const [
|
|
103
|
+
const [intents, setIntents] = useState<AgentIntent[]>([])
|
|
104
|
+
const [focusedSessionId, setFocusedSessionId] = useState<string | null>(null)
|
|
105
|
+
const intent =
|
|
106
|
+
intents.find((item) => item.sessionId === focusedSessionId) ??
|
|
107
|
+
intents[0] ??
|
|
108
|
+
emptyIntent
|
|
109
|
+
const creationIntent =
|
|
110
|
+
intents.find((item) => item.creationMode) ??
|
|
111
|
+
intents.find((item) => item.status === 'blueprint') ??
|
|
112
|
+
null
|
|
113
|
+
const creationMode = Boolean(creationIntent?.creationMode)
|
|
104
114
|
const previewing = intent.preview || isPatchPreview(intent.status)
|
|
105
115
|
const plannedCreates = previewing ? intent.creates : []
|
|
106
116
|
const [userBlocks, setUserBlocks] = useState<UserCreatedBlock[]>([])
|
|
@@ -172,12 +182,30 @@ function Explorer({
|
|
|
172
182
|
const [followLook, setFollowLook] = useState(false)
|
|
173
183
|
const [importedBy, setImportedBy] = useState(false)
|
|
174
184
|
const lastIntentSig = useRef<string | null>(null)
|
|
175
|
-
const viewedDiffId = useRef<string | null
|
|
176
|
-
const browsingHistory = useRef(
|
|
185
|
+
const viewedDiffId = useRef<Record<string, string | null>>({})
|
|
186
|
+
const browsingHistory = useRef<Record<string, boolean>>({})
|
|
177
187
|
|
|
178
|
-
const applyIntent = useCallback((next: AgentIntent) => {
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
const applyIntent = useCallback((next: AgentIntent, sessionId?: string) => {
|
|
189
|
+
const targetId = next.sessionId ?? sessionId ?? null
|
|
190
|
+
setIntents((current) => {
|
|
191
|
+
const nextList =
|
|
192
|
+
!targetId || next.status === 'idle' || !next.sessionId
|
|
193
|
+
? current.filter((item) => item.sessionId !== targetId)
|
|
194
|
+
: current.some((item) => item.sessionId === targetId)
|
|
195
|
+
? current.map((item) => (item.sessionId === targetId ? next : item))
|
|
196
|
+
: [...current, next]
|
|
197
|
+
setFocusedSessionId((currentFocus) => {
|
|
198
|
+
if (
|
|
199
|
+
currentFocus &&
|
|
200
|
+
nextList.some((item) => item.sessionId === currentFocus)
|
|
201
|
+
) {
|
|
202
|
+
return currentFocus
|
|
203
|
+
}
|
|
204
|
+
return nextList[0]?.sessionId ?? null
|
|
205
|
+
})
|
|
206
|
+
return nextList
|
|
207
|
+
})
|
|
208
|
+
if (targetId && next.sessionId) viewedDiffId.current[targetId] = next.diffId
|
|
181
209
|
}, [])
|
|
182
210
|
|
|
183
211
|
const rememberWalk = useCallback((x: number, z: number) => {
|
|
@@ -244,23 +272,25 @@ function Explorer({
|
|
|
244
272
|
|
|
245
273
|
const runWorkflowAction = useCallback(
|
|
246
274
|
async (
|
|
275
|
+
sessionId: string,
|
|
247
276
|
action: WorkflowAction,
|
|
248
277
|
options: { instruction?: string; step?: number } = {},
|
|
249
278
|
) => {
|
|
250
|
-
|
|
279
|
+
const current = intents.find((item) => item.sessionId === sessionId)
|
|
280
|
+
if (!current?.sessionId) return
|
|
251
281
|
if (
|
|
252
282
|
(action === 'continue' || action === 'instruct') &&
|
|
253
|
-
(!
|
|
283
|
+
(!current.diffId || !current.isActiveDiff)
|
|
254
284
|
) {
|
|
255
285
|
return
|
|
256
286
|
}
|
|
257
287
|
try {
|
|
258
288
|
const next = await performAgentAction(
|
|
259
289
|
action,
|
|
260
|
-
|
|
290
|
+
current.sessionId,
|
|
261
291
|
{
|
|
262
292
|
...options,
|
|
263
|
-
diffId:
|
|
293
|
+
diffId: current.diffId ?? undefined,
|
|
264
294
|
...(action === 'blueprint_send'
|
|
265
295
|
? {
|
|
266
296
|
userCreatedBlocks: namedCreatedBlocks(userBlocks),
|
|
@@ -272,9 +302,9 @@ function Explorer({
|
|
|
272
302
|
: {}),
|
|
273
303
|
},
|
|
274
304
|
)
|
|
275
|
-
browsingHistory.current = false
|
|
276
|
-
lastIntentSig.current =
|
|
277
|
-
applyIntent(next)
|
|
305
|
+
browsingHistory.current[sessionId] = false
|
|
306
|
+
lastIntentSig.current = null
|
|
307
|
+
applyIntent(next, sessionId)
|
|
278
308
|
if (action === 'invoke' || action === 'continue' || action === 'stop') {
|
|
279
309
|
await onRefreshGraph()
|
|
280
310
|
}
|
|
@@ -287,9 +317,7 @@ function Explorer({
|
|
|
287
317
|
blueprintFunctions,
|
|
288
318
|
blueprintImports,
|
|
289
319
|
blueprintVariables,
|
|
290
|
-
|
|
291
|
-
intent.isActiveDiff,
|
|
292
|
-
intent.sessionId,
|
|
320
|
+
intents,
|
|
293
321
|
onRefreshGraph,
|
|
294
322
|
userBlocks,
|
|
295
323
|
userIslands,
|
|
@@ -297,28 +325,29 @@ function Explorer({
|
|
|
297
325
|
)
|
|
298
326
|
|
|
299
327
|
const navigateDiff = useCallback(
|
|
300
|
-
async (diffId: string) => {
|
|
328
|
+
async (sessionId: string, diffId: string) => {
|
|
329
|
+
const current = intents.find((item) => item.sessionId === sessionId)
|
|
330
|
+
if (!current) return
|
|
301
331
|
try {
|
|
302
|
-
const latest =
|
|
303
|
-
browsingHistory.current = diffId !== latest
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
// Still show the historical preview if disk replay failed.
|
|
312
|
-
}
|
|
332
|
+
const latest = current.chain.at(-1)?.id
|
|
333
|
+
browsingHistory.current[sessionId] = diffId !== latest
|
|
334
|
+
try {
|
|
335
|
+
await inspectTargetFile({
|
|
336
|
+
sessionId,
|
|
337
|
+
diffId,
|
|
338
|
+
})
|
|
339
|
+
} catch {
|
|
340
|
+
// Still show the historical preview if disk replay failed.
|
|
313
341
|
}
|
|
314
|
-
const next = await fetchAgentIntent(diffId)
|
|
315
|
-
lastIntentSig.current =
|
|
316
|
-
applyIntent(next)
|
|
342
|
+
const next = await fetchAgentIntent(sessionId, diffId)
|
|
343
|
+
lastIntentSig.current = null
|
|
344
|
+
applyIntent(next, sessionId)
|
|
345
|
+
setFocusedSessionId(sessionId)
|
|
317
346
|
} catch {
|
|
318
347
|
// Keep the current chain position if navigation failed.
|
|
319
348
|
}
|
|
320
349
|
},
|
|
321
|
-
[applyIntent,
|
|
350
|
+
[applyIntent, intents],
|
|
322
351
|
)
|
|
323
352
|
|
|
324
353
|
const inspectFile = useCallback(
|
|
@@ -370,7 +399,7 @@ function Explorer({
|
|
|
370
399
|
}, [])
|
|
371
400
|
|
|
372
401
|
useEffect(() => {
|
|
373
|
-
if (!
|
|
402
|
+
if (!creationIntent?.sessionId) {
|
|
374
403
|
setUserBlocks([])
|
|
375
404
|
setUserIslands([])
|
|
376
405
|
setBlueprintFunctions([])
|
|
@@ -380,13 +409,13 @@ function Explorer({
|
|
|
380
409
|
}
|
|
381
410
|
const knownFiles = new Set(graph.files.map((file) => file.id))
|
|
382
411
|
const knownFolders = new Set(graph.folders.map((folder) => folder.path))
|
|
383
|
-
const nextBlocks = parseUserCreatedBlocks(
|
|
412
|
+
const nextBlocks = parseUserCreatedBlocks(creationIntent.userCreatedBlocks).filter(
|
|
384
413
|
(block) => !knownFiles.has(block.id),
|
|
385
414
|
)
|
|
386
|
-
const nextIslands = parseUserCreatedIslands(
|
|
415
|
+
const nextIslands = parseUserCreatedIslands(creationIntent.userCreatedIslands).filter(
|
|
387
416
|
(island) => !knownFolders.has(island.path),
|
|
388
417
|
)
|
|
389
|
-
if (
|
|
418
|
+
if (creationIntent.creationMode) {
|
|
390
419
|
setUserBlocks((current) =>
|
|
391
420
|
current.some((block) => block.naming) || current.length > 0
|
|
392
421
|
? current
|
|
@@ -398,28 +427,29 @@ function Explorer({
|
|
|
398
427
|
: nextIslands,
|
|
399
428
|
)
|
|
400
429
|
setBlueprintFunctions((current) =>
|
|
401
|
-
current.length > 0 ? current :
|
|
430
|
+
current.length > 0 ? current : creationIntent.blueprintFunctions,
|
|
402
431
|
)
|
|
403
432
|
setBlueprintVariables((current) =>
|
|
404
|
-
current.length > 0 ? current :
|
|
433
|
+
current.length > 0 ? current : creationIntent.blueprintVariables,
|
|
405
434
|
)
|
|
406
435
|
setBlueprintImports((current) =>
|
|
407
|
-
current.length > 0 ? current :
|
|
436
|
+
current.length > 0 ? current : creationIntent.blueprintImports,
|
|
408
437
|
)
|
|
409
438
|
return
|
|
410
439
|
}
|
|
411
440
|
setUserBlocks(nextBlocks)
|
|
412
441
|
setUserIslands(nextIslands)
|
|
413
|
-
setBlueprintFunctions(
|
|
414
|
-
setBlueprintVariables(
|
|
415
|
-
setBlueprintImports(
|
|
442
|
+
setBlueprintFunctions(creationIntent.blueprintFunctions)
|
|
443
|
+
setBlueprintVariables(creationIntent.blueprintVariables)
|
|
444
|
+
setBlueprintImports(creationIntent.blueprintImports)
|
|
416
445
|
}, [
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
446
|
+
creationIntent?.blueprintFunctions,
|
|
447
|
+
creationIntent?.blueprintImports,
|
|
448
|
+
creationIntent?.blueprintVariables,
|
|
449
|
+
creationIntent?.creationMode,
|
|
450
|
+
creationIntent?.sessionId,
|
|
451
|
+
creationIntent?.userCreatedBlocks,
|
|
452
|
+
creationIntent?.userCreatedIslands,
|
|
423
453
|
graph,
|
|
424
454
|
])
|
|
425
455
|
|
|
@@ -431,8 +461,8 @@ function Explorer({
|
|
|
431
461
|
variables: PatchSymbolAddition[] = blueprintVariables,
|
|
432
462
|
imports: PatchImportAddition[] = blueprintImports,
|
|
433
463
|
) => {
|
|
434
|
-
if (!
|
|
435
|
-
persistSessionBlueprint(
|
|
464
|
+
if (!creationIntent?.sessionId || !creationIntent.creationMode) return
|
|
465
|
+
persistSessionBlueprint(creationIntent.sessionId, {
|
|
436
466
|
userCreatedBlocks: namedCreatedBlocks(blocks),
|
|
437
467
|
userCreatedIslands: namedCreatedIslands(islands),
|
|
438
468
|
addedFunctions: functions,
|
|
@@ -444,8 +474,8 @@ function Explorer({
|
|
|
444
474
|
blueprintFunctions,
|
|
445
475
|
blueprintImports,
|
|
446
476
|
blueprintVariables,
|
|
447
|
-
|
|
448
|
-
|
|
477
|
+
creationIntent?.creationMode,
|
|
478
|
+
creationIntent?.sessionId,
|
|
449
479
|
userBlocks,
|
|
450
480
|
userIslands,
|
|
451
481
|
],
|
|
@@ -453,7 +483,7 @@ function Explorer({
|
|
|
453
483
|
|
|
454
484
|
const placeBlock = useCallback(
|
|
455
485
|
(spot: { x: number; z: number; folder: string }) => {
|
|
456
|
-
if (!
|
|
486
|
+
if (!creationMode) return
|
|
457
487
|
setUserBlocks((current) => {
|
|
458
488
|
if (current.some((block) => block.naming)) return current
|
|
459
489
|
return [
|
|
@@ -471,12 +501,12 @@ function Explorer({
|
|
|
471
501
|
})
|
|
472
502
|
document.exitPointerLock()
|
|
473
503
|
},
|
|
474
|
-
[
|
|
504
|
+
[creationMode],
|
|
475
505
|
)
|
|
476
506
|
|
|
477
507
|
const placeBlockOnFolder = useCallback(
|
|
478
508
|
(folderPath: string) => {
|
|
479
|
-
if (!
|
|
509
|
+
if (!creationMode) return
|
|
480
510
|
const fileCount = displayGraph.files.filter(
|
|
481
511
|
(file) => file.folder === folderPath,
|
|
482
512
|
).length
|
|
@@ -484,7 +514,7 @@ function Explorer({
|
|
|
484
514
|
if (!spot) return
|
|
485
515
|
placeBlock(spot)
|
|
486
516
|
},
|
|
487
|
-
[displayGraph.files,
|
|
517
|
+
[displayGraph.files, creationMode, layout, placeBlock],
|
|
488
518
|
)
|
|
489
519
|
|
|
490
520
|
const commitBlockName = useCallback(
|
|
@@ -521,7 +551,7 @@ function Explorer({
|
|
|
521
551
|
|
|
522
552
|
const placeIsland = useCallback(
|
|
523
553
|
(parent: string) => {
|
|
524
|
-
if (!
|
|
554
|
+
if (!creationMode) return
|
|
525
555
|
setUserIslands((current) => {
|
|
526
556
|
if (current.some((island) => island.naming)) return current
|
|
527
557
|
return [
|
|
@@ -537,15 +567,15 @@ function Explorer({
|
|
|
537
567
|
})
|
|
538
568
|
document.exitPointerLock()
|
|
539
569
|
},
|
|
540
|
-
[
|
|
570
|
+
[creationMode],
|
|
541
571
|
)
|
|
542
572
|
|
|
543
573
|
const placeIslandOnFolder = useCallback(
|
|
544
574
|
(parent: string) => {
|
|
545
|
-
if (!
|
|
575
|
+
if (!creationMode) return
|
|
546
576
|
placeIsland(parent)
|
|
547
577
|
},
|
|
548
|
-
[
|
|
578
|
+
[creationMode, placeIsland],
|
|
549
579
|
)
|
|
550
580
|
|
|
551
581
|
const commitIslandName = useCallback(
|
|
@@ -579,7 +609,7 @@ function Explorer({
|
|
|
579
609
|
}, [])
|
|
580
610
|
|
|
581
611
|
const deleteSelectedCreatedBlock = useCallback(() => {
|
|
582
|
-
if (!
|
|
612
|
+
if (!creationMode || !selectedId) return false
|
|
583
613
|
const selected = userBlocks.find((block) => block.id === selectedId)
|
|
584
614
|
if (!selected || selected.naming) return false
|
|
585
615
|
const next = userBlocks.filter((block) => block.id !== selectedId)
|
|
@@ -587,7 +617,7 @@ function Explorer({
|
|
|
587
617
|
persistBlueprint(next, userIslands)
|
|
588
618
|
setSelectedId(null)
|
|
589
619
|
return true
|
|
590
|
-
}, [
|
|
620
|
+
}, [creationMode, persistBlueprint, selectedId, userBlocks, userIslands])
|
|
591
621
|
|
|
592
622
|
const selectFile = useCallback(
|
|
593
623
|
(fileId: string | null) => {
|
|
@@ -596,9 +626,9 @@ function Explorer({
|
|
|
596
626
|
setSelectedFolder(null)
|
|
597
627
|
setSelectedTick((tick) => tick + 1)
|
|
598
628
|
}
|
|
599
|
-
if (fileId &&
|
|
629
|
+
if (fileId && creationMode) document.exitPointerLock()
|
|
600
630
|
},
|
|
601
|
-
[
|
|
631
|
+
[creationMode],
|
|
602
632
|
)
|
|
603
633
|
|
|
604
634
|
const selectFolder = useCallback((folderPath: string | null) => {
|
|
@@ -608,7 +638,7 @@ function Explorer({
|
|
|
608
638
|
|
|
609
639
|
const addBlueprintFunction = useCallback(
|
|
610
640
|
(fileId: string, rawName: string) => {
|
|
611
|
-
if (!
|
|
641
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
612
642
|
const name = rawName.trim()
|
|
613
643
|
if (!isBlueprintSymbolName(name)) return false
|
|
614
644
|
const exists =
|
|
@@ -631,7 +661,7 @@ function Explorer({
|
|
|
631
661
|
blueprintImports,
|
|
632
662
|
blueprintVariables,
|
|
633
663
|
displayGraph.files,
|
|
634
|
-
|
|
664
|
+
creationMode,
|
|
635
665
|
persistBlueprint,
|
|
636
666
|
userBlocks,
|
|
637
667
|
userIslands,
|
|
@@ -640,7 +670,7 @@ function Explorer({
|
|
|
640
670
|
|
|
641
671
|
const addBlueprintVariable = useCallback(
|
|
642
672
|
(fileId: string, rawName: string) => {
|
|
643
|
-
if (!
|
|
673
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
644
674
|
const name = rawName.trim()
|
|
645
675
|
if (!isBlueprintSymbolName(name)) return false
|
|
646
676
|
const exists =
|
|
@@ -663,7 +693,7 @@ function Explorer({
|
|
|
663
693
|
blueprintImports,
|
|
664
694
|
blueprintVariables,
|
|
665
695
|
displayGraph.files,
|
|
666
|
-
|
|
696
|
+
creationMode,
|
|
667
697
|
persistBlueprint,
|
|
668
698
|
userBlocks,
|
|
669
699
|
userIslands,
|
|
@@ -672,7 +702,7 @@ function Explorer({
|
|
|
672
702
|
|
|
673
703
|
const addBlueprintImport = useCallback(
|
|
674
704
|
(fileId: string, raw: string) => {
|
|
675
|
-
if (!
|
|
705
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
676
706
|
const parsed = parseBlueprintImport(
|
|
677
707
|
raw,
|
|
678
708
|
fileId,
|
|
@@ -702,7 +732,7 @@ function Explorer({
|
|
|
702
732
|
blueprintImports,
|
|
703
733
|
blueprintVariables,
|
|
704
734
|
displayGraph.files,
|
|
705
|
-
|
|
735
|
+
creationMode,
|
|
706
736
|
persistBlueprint,
|
|
707
737
|
userBlocks,
|
|
708
738
|
userIslands,
|
|
@@ -711,7 +741,7 @@ function Explorer({
|
|
|
711
741
|
|
|
712
742
|
const removeBlueprintFunction = useCallback(
|
|
713
743
|
(fileId: string, name: string) => {
|
|
714
|
-
if (!
|
|
744
|
+
if (!creationMode) return
|
|
715
745
|
const next = blueprintFunctions.filter(
|
|
716
746
|
(item) => !(item.file === fileId && item.name === name),
|
|
717
747
|
)
|
|
@@ -722,7 +752,7 @@ function Explorer({
|
|
|
722
752
|
blueprintFunctions,
|
|
723
753
|
blueprintImports,
|
|
724
754
|
blueprintVariables,
|
|
725
|
-
|
|
755
|
+
creationMode,
|
|
726
756
|
persistBlueprint,
|
|
727
757
|
userBlocks,
|
|
728
758
|
userIslands,
|
|
@@ -731,7 +761,7 @@ function Explorer({
|
|
|
731
761
|
|
|
732
762
|
const removeBlueprintVariable = useCallback(
|
|
733
763
|
(fileId: string, name: string) => {
|
|
734
|
-
if (!
|
|
764
|
+
if (!creationMode) return
|
|
735
765
|
const next = blueprintVariables.filter(
|
|
736
766
|
(item) => !(item.file === fileId && item.name === name),
|
|
737
767
|
)
|
|
@@ -742,7 +772,7 @@ function Explorer({
|
|
|
742
772
|
blueprintFunctions,
|
|
743
773
|
blueprintImports,
|
|
744
774
|
blueprintVariables,
|
|
745
|
-
|
|
775
|
+
creationMode,
|
|
746
776
|
persistBlueprint,
|
|
747
777
|
userBlocks,
|
|
748
778
|
userIslands,
|
|
@@ -751,7 +781,7 @@ function Explorer({
|
|
|
751
781
|
|
|
752
782
|
const removeBlueprintImport = useCallback(
|
|
753
783
|
(fileId: string, name: string, from: string) => {
|
|
754
|
-
if (!
|
|
784
|
+
if (!creationMode) return
|
|
755
785
|
const next = blueprintImports.filter(
|
|
756
786
|
(item) =>
|
|
757
787
|
!(item.file === fileId && item.name === name && item.from === from),
|
|
@@ -769,7 +799,7 @@ function Explorer({
|
|
|
769
799
|
blueprintFunctions,
|
|
770
800
|
blueprintImports,
|
|
771
801
|
blueprintVariables,
|
|
772
|
-
|
|
802
|
+
creationMode,
|
|
773
803
|
persistBlueprint,
|
|
774
804
|
userBlocks,
|
|
775
805
|
userIslands,
|
|
@@ -844,15 +874,45 @@ function Explorer({
|
|
|
844
874
|
let cancelled = false
|
|
845
875
|
const poll = async () => {
|
|
846
876
|
try {
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
)
|
|
850
|
-
|
|
877
|
+
const bundle = await fetchAgentIntents()
|
|
878
|
+
const merged: AgentIntent[] = []
|
|
879
|
+
for (const next of bundle.intents) {
|
|
880
|
+
const sessionId = next.sessionId
|
|
881
|
+
if (
|
|
882
|
+
sessionId &&
|
|
883
|
+
browsingHistory.current[sessionId] &&
|
|
884
|
+
viewedDiffId.current[sessionId]
|
|
885
|
+
) {
|
|
886
|
+
merged.push(
|
|
887
|
+
await fetchAgentIntent(sessionId, viewedDiffId.current[sessionId] ?? undefined),
|
|
888
|
+
)
|
|
889
|
+
} else {
|
|
890
|
+
merged.push(next)
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
const signature = JSON.stringify(merged.map(intentSignature))
|
|
851
894
|
if (cancelled || signature === lastIntentSig.current) {
|
|
852
895
|
return
|
|
853
896
|
}
|
|
854
897
|
lastIntentSig.current = signature
|
|
855
|
-
|
|
898
|
+
setIntents(merged)
|
|
899
|
+
for (const next of merged) {
|
|
900
|
+
if (next.sessionId && !browsingHistory.current[next.sessionId]) {
|
|
901
|
+
viewedDiffId.current[next.sessionId] = next.diffId
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
setFocusedSessionId((current) => {
|
|
905
|
+
if (current && merged.some((item) => item.sessionId === current)) {
|
|
906
|
+
return current
|
|
907
|
+
}
|
|
908
|
+
if (
|
|
909
|
+
bundle.focusedSessionId &&
|
|
910
|
+
merged.some((item) => item.sessionId === bundle.focusedSessionId)
|
|
911
|
+
) {
|
|
912
|
+
return bundle.focusedSessionId
|
|
913
|
+
}
|
|
914
|
+
return merged[0]?.sessionId ?? null
|
|
915
|
+
})
|
|
856
916
|
} catch {
|
|
857
917
|
// Explorer may be running without the intent endpoint yet.
|
|
858
918
|
}
|
|
@@ -865,7 +925,7 @@ function Explorer({
|
|
|
865
925
|
cancelled = true
|
|
866
926
|
window.clearInterval(timer)
|
|
867
927
|
}
|
|
868
|
-
}, [
|
|
928
|
+
}, [])
|
|
869
929
|
|
|
870
930
|
const plannedIds = previewing ? [...intent.files, ...intent.creates] : []
|
|
871
931
|
const blueprintImportEdges = blueprintImports.flatMap((item) => {
|
|
@@ -883,6 +943,7 @@ function Explorer({
|
|
|
883
943
|
<div className="stage">
|
|
884
944
|
<Canvas
|
|
885
945
|
shadows={false}
|
|
946
|
+
dpr={[1, 1.5]}
|
|
886
947
|
gl={{ antialias: true, toneMappingExposure: 1.25 }}
|
|
887
948
|
camera={{
|
|
888
949
|
position: layout.spawn,
|
|
@@ -919,8 +980,8 @@ function Explorer({
|
|
|
919
980
|
importedBy={importedBy}
|
|
920
981
|
namingId={namingId}
|
|
921
982
|
namingIslandId={namingIslandId}
|
|
922
|
-
onPlaceBlock={
|
|
923
|
-
onPlaceIsland={
|
|
983
|
+
onPlaceBlock={creationMode ? placeBlock : undefined}
|
|
984
|
+
onPlaceIsland={creationMode ? placeIsland : undefined}
|
|
924
985
|
onCommitName={commitBlockName}
|
|
925
986
|
onCancelName={cancelBlockName}
|
|
926
987
|
userCreatedBlocks={userBlocks}
|
|
@@ -930,14 +991,19 @@ function Explorer({
|
|
|
930
991
|
</div>
|
|
931
992
|
<HUD
|
|
932
993
|
graph={displayGraph}
|
|
994
|
+
layout={layout}
|
|
933
995
|
mode={mode}
|
|
934
996
|
locked={locked}
|
|
935
997
|
selectedId={selectedId}
|
|
936
998
|
selectedTick={selectedTick}
|
|
937
999
|
selectedFolder={selectedFolder}
|
|
1000
|
+
landAt={landAt}
|
|
938
1001
|
aimedRelation={aimedRelation}
|
|
939
1002
|
currentFolder={currentFolder}
|
|
940
1003
|
intent={intent}
|
|
1004
|
+
intents={intents}
|
|
1005
|
+
focusedSessionId={focusedSessionId}
|
|
1006
|
+
onFocusSession={setFocusedSessionId}
|
|
941
1007
|
onWorkflowAction={runWorkflowAction}
|
|
942
1008
|
onNavigateDiff={navigateDiff}
|
|
943
1009
|
onOpenMap={openMap}
|
|
@@ -966,6 +1032,9 @@ function Explorer({
|
|
|
966
1032
|
onMapAddFile={placeBlockOnFolder}
|
|
967
1033
|
onMapAddFolder={placeIslandOnFolder}
|
|
968
1034
|
onInspectFile={inspectFile}
|
|
1035
|
+
plannedIds={plannedIds}
|
|
1036
|
+
createdIds={plannedCreates}
|
|
1037
|
+
deletedIds={deletedIds}
|
|
969
1038
|
/>
|
|
970
1039
|
</>
|
|
971
1040
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentIntent,
|
|
3
|
+
AgentIntentBundle,
|
|
3
4
|
PatchImport,
|
|
4
5
|
PatchImportAddition,
|
|
5
6
|
PatchSymbolAddition,
|
|
@@ -124,8 +125,39 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
export async function
|
|
128
|
+
export async function fetchAgentIntents(): Promise<AgentIntentBundle> {
|
|
128
129
|
const query = new URLSearchParams({ t: String(Date.now()) })
|
|
130
|
+
const response = await fetch(`/api/agent-intent?${query}`)
|
|
131
|
+
if (!response.ok) return { focusedSessionId: null, intents: [] }
|
|
132
|
+
const data = (await response.json()) as {
|
|
133
|
+
focusedSessionId?: string | null
|
|
134
|
+
intents?: unknown
|
|
135
|
+
sessionId?: string | null
|
|
136
|
+
} & Partial<AgentIntent>
|
|
137
|
+
if (Array.isArray(data.intents)) {
|
|
138
|
+
return {
|
|
139
|
+
focusedSessionId:
|
|
140
|
+
typeof data.focusedSessionId === 'string' ? data.focusedSessionId : null,
|
|
141
|
+
intents: data.intents
|
|
142
|
+
.map((intent) => normalize(intent as Partial<AgentIntent>))
|
|
143
|
+
.filter((intent) => Boolean(intent.sessionId)),
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const intent = normalize(data)
|
|
147
|
+
return {
|
|
148
|
+
focusedSessionId: intent.sessionId,
|
|
149
|
+
intents: intent.sessionId ? [intent] : [],
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function fetchAgentIntent(
|
|
154
|
+
sessionId: string,
|
|
155
|
+
diffId?: string,
|
|
156
|
+
): Promise<AgentIntent> {
|
|
157
|
+
const query = new URLSearchParams({
|
|
158
|
+
t: String(Date.now()),
|
|
159
|
+
sessionId,
|
|
160
|
+
})
|
|
129
161
|
if (diffId) query.set('diffId', diffId)
|
|
130
162
|
const response = await fetch(`/api/agent-intent?${query}`)
|
|
131
163
|
if (!response.ok) return emptyIntent
|