@jkwd/inbase 0.1.3 → 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/open-editor.d.ts +6 -0
- package/apps/explorer/scripts/open-editor.mjs +219 -0
- package/apps/explorer/scripts/session-store.d.ts +51 -1
- package/apps/explorer/scripts/session-store.mjs +461 -48
- package/apps/explorer/src/App.tsx +178 -78
- package/apps/explorer/src/agentIntent.ts +54 -1
- package/apps/explorer/src/index.css +238 -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 +41 -18
- 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 +19 -50
- package/apps/explorer/src/theme.ts +10 -1
- package/apps/explorer/src/types.ts +12 -0
- package/apps/explorer/src/ui/HUD.tsx +699 -390
- package/apps/explorer/vite.config.ts +72 -22
- package/bin/session.mjs +17 -3
- package/package.json +3 -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, 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[]>([])
|
|
@@ -163,6 +173,7 @@ function Explorer({
|
|
|
163
173
|
])
|
|
164
174
|
const walkPos = useRef<[number, number]>([layout.spawn[0], layout.spawn[2]])
|
|
165
175
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
|
176
|
+
const [selectedTick, setSelectedTick] = useState(0)
|
|
166
177
|
const [selectedFolder, setSelectedFolder] = useState<string | null>(null)
|
|
167
178
|
const [aimedRelation, setAimedRelation] = useState<AimedRelation | null>(null)
|
|
168
179
|
const [flyTo, setFlyTo] = useState<FlyTo | null>(null)
|
|
@@ -171,12 +182,30 @@ function Explorer({
|
|
|
171
182
|
const [followLook, setFollowLook] = useState(false)
|
|
172
183
|
const [importedBy, setImportedBy] = useState(false)
|
|
173
184
|
const lastIntentSig = useRef<string | null>(null)
|
|
174
|
-
const viewedDiffId = useRef<string | null
|
|
175
|
-
const browsingHistory = useRef(
|
|
185
|
+
const viewedDiffId = useRef<Record<string, string | null>>({})
|
|
186
|
+
const browsingHistory = useRef<Record<string, boolean>>({})
|
|
176
187
|
|
|
177
|
-
const applyIntent = useCallback((next: AgentIntent) => {
|
|
178
|
-
|
|
179
|
-
|
|
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
|
|
180
209
|
}, [])
|
|
181
210
|
|
|
182
211
|
const rememberWalk = useCallback((x: number, z: number) => {
|
|
@@ -243,23 +272,25 @@ function Explorer({
|
|
|
243
272
|
|
|
244
273
|
const runWorkflowAction = useCallback(
|
|
245
274
|
async (
|
|
275
|
+
sessionId: string,
|
|
246
276
|
action: WorkflowAction,
|
|
247
277
|
options: { instruction?: string; step?: number } = {},
|
|
248
278
|
) => {
|
|
249
|
-
|
|
279
|
+
const current = intents.find((item) => item.sessionId === sessionId)
|
|
280
|
+
if (!current?.sessionId) return
|
|
250
281
|
if (
|
|
251
282
|
(action === 'continue' || action === 'instruct') &&
|
|
252
|
-
(!
|
|
283
|
+
(!current.diffId || !current.isActiveDiff)
|
|
253
284
|
) {
|
|
254
285
|
return
|
|
255
286
|
}
|
|
256
287
|
try {
|
|
257
288
|
const next = await performAgentAction(
|
|
258
289
|
action,
|
|
259
|
-
|
|
290
|
+
current.sessionId,
|
|
260
291
|
{
|
|
261
292
|
...options,
|
|
262
|
-
diffId:
|
|
293
|
+
diffId: current.diffId ?? undefined,
|
|
263
294
|
...(action === 'blueprint_send'
|
|
264
295
|
? {
|
|
265
296
|
userCreatedBlocks: namedCreatedBlocks(userBlocks),
|
|
@@ -271,10 +302,10 @@ function Explorer({
|
|
|
271
302
|
: {}),
|
|
272
303
|
},
|
|
273
304
|
)
|
|
274
|
-
browsingHistory.current = false
|
|
275
|
-
lastIntentSig.current =
|
|
276
|
-
applyIntent(next)
|
|
277
|
-
if (action === 'invoke' || action === 'continue') {
|
|
305
|
+
browsingHistory.current[sessionId] = false
|
|
306
|
+
lastIntentSig.current = null
|
|
307
|
+
applyIntent(next, sessionId)
|
|
308
|
+
if (action === 'invoke' || action === 'continue' || action === 'stop') {
|
|
278
309
|
await onRefreshGraph()
|
|
279
310
|
}
|
|
280
311
|
} catch {
|
|
@@ -286,9 +317,7 @@ function Explorer({
|
|
|
286
317
|
blueprintFunctions,
|
|
287
318
|
blueprintImports,
|
|
288
319
|
blueprintVariables,
|
|
289
|
-
|
|
290
|
-
intent.isActiveDiff,
|
|
291
|
-
intent.sessionId,
|
|
320
|
+
intents,
|
|
292
321
|
onRefreshGraph,
|
|
293
322
|
userBlocks,
|
|
294
323
|
userIslands,
|
|
@@ -296,18 +325,44 @@ function Explorer({
|
|
|
296
325
|
)
|
|
297
326
|
|
|
298
327
|
const navigateDiff = useCallback(
|
|
299
|
-
async (diffId: string) => {
|
|
328
|
+
async (sessionId: string, diffId: string) => {
|
|
329
|
+
const current = intents.find((item) => item.sessionId === sessionId)
|
|
330
|
+
if (!current) return
|
|
300
331
|
try {
|
|
301
|
-
const latest =
|
|
302
|
-
browsingHistory.current = diffId !== latest
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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.
|
|
341
|
+
}
|
|
342
|
+
const next = await fetchAgentIntent(sessionId, diffId)
|
|
343
|
+
lastIntentSig.current = null
|
|
344
|
+
applyIntent(next, sessionId)
|
|
345
|
+
setFocusedSessionId(sessionId)
|
|
306
346
|
} catch {
|
|
307
347
|
// Keep the current chain position if navigation failed.
|
|
308
348
|
}
|
|
309
349
|
},
|
|
310
|
-
[applyIntent,
|
|
350
|
+
[applyIntent, intents],
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
const inspectFile = useCallback(
|
|
354
|
+
async (fileId: string) => {
|
|
355
|
+
try {
|
|
356
|
+
await inspectTargetFile({
|
|
357
|
+
sessionId: intent.sessionId,
|
|
358
|
+
diffId: intent.diffId,
|
|
359
|
+
fileId,
|
|
360
|
+
})
|
|
361
|
+
} catch {
|
|
362
|
+
// Keep the current view if the editor could not open the file.
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
[intent.diffId, intent.sessionId],
|
|
311
366
|
)
|
|
312
367
|
|
|
313
368
|
useEffect(() => {
|
|
@@ -344,7 +399,7 @@ function Explorer({
|
|
|
344
399
|
}, [])
|
|
345
400
|
|
|
346
401
|
useEffect(() => {
|
|
347
|
-
if (!
|
|
402
|
+
if (!creationIntent?.sessionId) {
|
|
348
403
|
setUserBlocks([])
|
|
349
404
|
setUserIslands([])
|
|
350
405
|
setBlueprintFunctions([])
|
|
@@ -354,13 +409,13 @@ function Explorer({
|
|
|
354
409
|
}
|
|
355
410
|
const knownFiles = new Set(graph.files.map((file) => file.id))
|
|
356
411
|
const knownFolders = new Set(graph.folders.map((folder) => folder.path))
|
|
357
|
-
const nextBlocks = parseUserCreatedBlocks(
|
|
412
|
+
const nextBlocks = parseUserCreatedBlocks(creationIntent.userCreatedBlocks).filter(
|
|
358
413
|
(block) => !knownFiles.has(block.id),
|
|
359
414
|
)
|
|
360
|
-
const nextIslands = parseUserCreatedIslands(
|
|
415
|
+
const nextIslands = parseUserCreatedIslands(creationIntent.userCreatedIslands).filter(
|
|
361
416
|
(island) => !knownFolders.has(island.path),
|
|
362
417
|
)
|
|
363
|
-
if (
|
|
418
|
+
if (creationIntent.creationMode) {
|
|
364
419
|
setUserBlocks((current) =>
|
|
365
420
|
current.some((block) => block.naming) || current.length > 0
|
|
366
421
|
? current
|
|
@@ -372,28 +427,29 @@ function Explorer({
|
|
|
372
427
|
: nextIslands,
|
|
373
428
|
)
|
|
374
429
|
setBlueprintFunctions((current) =>
|
|
375
|
-
current.length > 0 ? current :
|
|
430
|
+
current.length > 0 ? current : creationIntent.blueprintFunctions,
|
|
376
431
|
)
|
|
377
432
|
setBlueprintVariables((current) =>
|
|
378
|
-
current.length > 0 ? current :
|
|
433
|
+
current.length > 0 ? current : creationIntent.blueprintVariables,
|
|
379
434
|
)
|
|
380
435
|
setBlueprintImports((current) =>
|
|
381
|
-
current.length > 0 ? current :
|
|
436
|
+
current.length > 0 ? current : creationIntent.blueprintImports,
|
|
382
437
|
)
|
|
383
438
|
return
|
|
384
439
|
}
|
|
385
440
|
setUserBlocks(nextBlocks)
|
|
386
441
|
setUserIslands(nextIslands)
|
|
387
|
-
setBlueprintFunctions(
|
|
388
|
-
setBlueprintVariables(
|
|
389
|
-
setBlueprintImports(
|
|
442
|
+
setBlueprintFunctions(creationIntent.blueprintFunctions)
|
|
443
|
+
setBlueprintVariables(creationIntent.blueprintVariables)
|
|
444
|
+
setBlueprintImports(creationIntent.blueprintImports)
|
|
390
445
|
}, [
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
446
|
+
creationIntent?.blueprintFunctions,
|
|
447
|
+
creationIntent?.blueprintImports,
|
|
448
|
+
creationIntent?.blueprintVariables,
|
|
449
|
+
creationIntent?.creationMode,
|
|
450
|
+
creationIntent?.sessionId,
|
|
451
|
+
creationIntent?.userCreatedBlocks,
|
|
452
|
+
creationIntent?.userCreatedIslands,
|
|
397
453
|
graph,
|
|
398
454
|
])
|
|
399
455
|
|
|
@@ -405,8 +461,8 @@ function Explorer({
|
|
|
405
461
|
variables: PatchSymbolAddition[] = blueprintVariables,
|
|
406
462
|
imports: PatchImportAddition[] = blueprintImports,
|
|
407
463
|
) => {
|
|
408
|
-
if (!
|
|
409
|
-
persistSessionBlueprint(
|
|
464
|
+
if (!creationIntent?.sessionId || !creationIntent.creationMode) return
|
|
465
|
+
persistSessionBlueprint(creationIntent.sessionId, {
|
|
410
466
|
userCreatedBlocks: namedCreatedBlocks(blocks),
|
|
411
467
|
userCreatedIslands: namedCreatedIslands(islands),
|
|
412
468
|
addedFunctions: functions,
|
|
@@ -418,8 +474,8 @@ function Explorer({
|
|
|
418
474
|
blueprintFunctions,
|
|
419
475
|
blueprintImports,
|
|
420
476
|
blueprintVariables,
|
|
421
|
-
|
|
422
|
-
|
|
477
|
+
creationIntent?.creationMode,
|
|
478
|
+
creationIntent?.sessionId,
|
|
423
479
|
userBlocks,
|
|
424
480
|
userIslands,
|
|
425
481
|
],
|
|
@@ -427,7 +483,7 @@ function Explorer({
|
|
|
427
483
|
|
|
428
484
|
const placeBlock = useCallback(
|
|
429
485
|
(spot: { x: number; z: number; folder: string }) => {
|
|
430
|
-
if (!
|
|
486
|
+
if (!creationMode) return
|
|
431
487
|
setUserBlocks((current) => {
|
|
432
488
|
if (current.some((block) => block.naming)) return current
|
|
433
489
|
return [
|
|
@@ -445,12 +501,12 @@ function Explorer({
|
|
|
445
501
|
})
|
|
446
502
|
document.exitPointerLock()
|
|
447
503
|
},
|
|
448
|
-
[
|
|
504
|
+
[creationMode],
|
|
449
505
|
)
|
|
450
506
|
|
|
451
507
|
const placeBlockOnFolder = useCallback(
|
|
452
508
|
(folderPath: string) => {
|
|
453
|
-
if (!
|
|
509
|
+
if (!creationMode) return
|
|
454
510
|
const fileCount = displayGraph.files.filter(
|
|
455
511
|
(file) => file.folder === folderPath,
|
|
456
512
|
).length
|
|
@@ -458,7 +514,7 @@ function Explorer({
|
|
|
458
514
|
if (!spot) return
|
|
459
515
|
placeBlock(spot)
|
|
460
516
|
},
|
|
461
|
-
[displayGraph.files,
|
|
517
|
+
[displayGraph.files, creationMode, layout, placeBlock],
|
|
462
518
|
)
|
|
463
519
|
|
|
464
520
|
const commitBlockName = useCallback(
|
|
@@ -495,7 +551,7 @@ function Explorer({
|
|
|
495
551
|
|
|
496
552
|
const placeIsland = useCallback(
|
|
497
553
|
(parent: string) => {
|
|
498
|
-
if (!
|
|
554
|
+
if (!creationMode) return
|
|
499
555
|
setUserIslands((current) => {
|
|
500
556
|
if (current.some((island) => island.naming)) return current
|
|
501
557
|
return [
|
|
@@ -511,15 +567,15 @@ function Explorer({
|
|
|
511
567
|
})
|
|
512
568
|
document.exitPointerLock()
|
|
513
569
|
},
|
|
514
|
-
[
|
|
570
|
+
[creationMode],
|
|
515
571
|
)
|
|
516
572
|
|
|
517
573
|
const placeIslandOnFolder = useCallback(
|
|
518
574
|
(parent: string) => {
|
|
519
|
-
if (!
|
|
575
|
+
if (!creationMode) return
|
|
520
576
|
placeIsland(parent)
|
|
521
577
|
},
|
|
522
|
-
[
|
|
578
|
+
[creationMode, placeIsland],
|
|
523
579
|
)
|
|
524
580
|
|
|
525
581
|
const commitIslandName = useCallback(
|
|
@@ -553,7 +609,7 @@ function Explorer({
|
|
|
553
609
|
}, [])
|
|
554
610
|
|
|
555
611
|
const deleteSelectedCreatedBlock = useCallback(() => {
|
|
556
|
-
if (!
|
|
612
|
+
if (!creationMode || !selectedId) return false
|
|
557
613
|
const selected = userBlocks.find((block) => block.id === selectedId)
|
|
558
614
|
if (!selected || selected.naming) return false
|
|
559
615
|
const next = userBlocks.filter((block) => block.id !== selectedId)
|
|
@@ -561,15 +617,18 @@ function Explorer({
|
|
|
561
617
|
persistBlueprint(next, userIslands)
|
|
562
618
|
setSelectedId(null)
|
|
563
619
|
return true
|
|
564
|
-
}, [
|
|
620
|
+
}, [creationMode, persistBlueprint, selectedId, userBlocks, userIslands])
|
|
565
621
|
|
|
566
622
|
const selectFile = useCallback(
|
|
567
623
|
(fileId: string | null) => {
|
|
568
624
|
setSelectedId(fileId)
|
|
569
|
-
if (fileId)
|
|
570
|
-
|
|
625
|
+
if (fileId) {
|
|
626
|
+
setSelectedFolder(null)
|
|
627
|
+
setSelectedTick((tick) => tick + 1)
|
|
628
|
+
}
|
|
629
|
+
if (fileId && creationMode) document.exitPointerLock()
|
|
571
630
|
},
|
|
572
|
-
[
|
|
631
|
+
[creationMode],
|
|
573
632
|
)
|
|
574
633
|
|
|
575
634
|
const selectFolder = useCallback((folderPath: string | null) => {
|
|
@@ -579,7 +638,7 @@ function Explorer({
|
|
|
579
638
|
|
|
580
639
|
const addBlueprintFunction = useCallback(
|
|
581
640
|
(fileId: string, rawName: string) => {
|
|
582
|
-
if (!
|
|
641
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
583
642
|
const name = rawName.trim()
|
|
584
643
|
if (!isBlueprintSymbolName(name)) return false
|
|
585
644
|
const exists =
|
|
@@ -602,7 +661,7 @@ function Explorer({
|
|
|
602
661
|
blueprintImports,
|
|
603
662
|
blueprintVariables,
|
|
604
663
|
displayGraph.files,
|
|
605
|
-
|
|
664
|
+
creationMode,
|
|
606
665
|
persistBlueprint,
|
|
607
666
|
userBlocks,
|
|
608
667
|
userIslands,
|
|
@@ -611,7 +670,7 @@ function Explorer({
|
|
|
611
670
|
|
|
612
671
|
const addBlueprintVariable = useCallback(
|
|
613
672
|
(fileId: string, rawName: string) => {
|
|
614
|
-
if (!
|
|
673
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
615
674
|
const name = rawName.trim()
|
|
616
675
|
if (!isBlueprintSymbolName(name)) return false
|
|
617
676
|
const exists =
|
|
@@ -634,7 +693,7 @@ function Explorer({
|
|
|
634
693
|
blueprintImports,
|
|
635
694
|
blueprintVariables,
|
|
636
695
|
displayGraph.files,
|
|
637
|
-
|
|
696
|
+
creationMode,
|
|
638
697
|
persistBlueprint,
|
|
639
698
|
userBlocks,
|
|
640
699
|
userIslands,
|
|
@@ -643,7 +702,7 @@ function Explorer({
|
|
|
643
702
|
|
|
644
703
|
const addBlueprintImport = useCallback(
|
|
645
704
|
(fileId: string, raw: string) => {
|
|
646
|
-
if (!
|
|
705
|
+
if (!creationMode || fileId.startsWith('draft:')) return false
|
|
647
706
|
const parsed = parseBlueprintImport(
|
|
648
707
|
raw,
|
|
649
708
|
fileId,
|
|
@@ -673,7 +732,7 @@ function Explorer({
|
|
|
673
732
|
blueprintImports,
|
|
674
733
|
blueprintVariables,
|
|
675
734
|
displayGraph.files,
|
|
676
|
-
|
|
735
|
+
creationMode,
|
|
677
736
|
persistBlueprint,
|
|
678
737
|
userBlocks,
|
|
679
738
|
userIslands,
|
|
@@ -682,7 +741,7 @@ function Explorer({
|
|
|
682
741
|
|
|
683
742
|
const removeBlueprintFunction = useCallback(
|
|
684
743
|
(fileId: string, name: string) => {
|
|
685
|
-
if (!
|
|
744
|
+
if (!creationMode) return
|
|
686
745
|
const next = blueprintFunctions.filter(
|
|
687
746
|
(item) => !(item.file === fileId && item.name === name),
|
|
688
747
|
)
|
|
@@ -693,7 +752,7 @@ function Explorer({
|
|
|
693
752
|
blueprintFunctions,
|
|
694
753
|
blueprintImports,
|
|
695
754
|
blueprintVariables,
|
|
696
|
-
|
|
755
|
+
creationMode,
|
|
697
756
|
persistBlueprint,
|
|
698
757
|
userBlocks,
|
|
699
758
|
userIslands,
|
|
@@ -702,7 +761,7 @@ function Explorer({
|
|
|
702
761
|
|
|
703
762
|
const removeBlueprintVariable = useCallback(
|
|
704
763
|
(fileId: string, name: string) => {
|
|
705
|
-
if (!
|
|
764
|
+
if (!creationMode) return
|
|
706
765
|
const next = blueprintVariables.filter(
|
|
707
766
|
(item) => !(item.file === fileId && item.name === name),
|
|
708
767
|
)
|
|
@@ -713,7 +772,7 @@ function Explorer({
|
|
|
713
772
|
blueprintFunctions,
|
|
714
773
|
blueprintImports,
|
|
715
774
|
blueprintVariables,
|
|
716
|
-
|
|
775
|
+
creationMode,
|
|
717
776
|
persistBlueprint,
|
|
718
777
|
userBlocks,
|
|
719
778
|
userIslands,
|
|
@@ -722,7 +781,7 @@ function Explorer({
|
|
|
722
781
|
|
|
723
782
|
const removeBlueprintImport = useCallback(
|
|
724
783
|
(fileId: string, name: string, from: string) => {
|
|
725
|
-
if (!
|
|
784
|
+
if (!creationMode) return
|
|
726
785
|
const next = blueprintImports.filter(
|
|
727
786
|
(item) =>
|
|
728
787
|
!(item.file === fileId && item.name === name && item.from === from),
|
|
@@ -740,7 +799,7 @@ function Explorer({
|
|
|
740
799
|
blueprintFunctions,
|
|
741
800
|
blueprintImports,
|
|
742
801
|
blueprintVariables,
|
|
743
|
-
|
|
802
|
+
creationMode,
|
|
744
803
|
persistBlueprint,
|
|
745
804
|
userBlocks,
|
|
746
805
|
userIslands,
|
|
@@ -815,15 +874,45 @@ function Explorer({
|
|
|
815
874
|
let cancelled = false
|
|
816
875
|
const poll = async () => {
|
|
817
876
|
try {
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
)
|
|
821
|
-
|
|
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))
|
|
822
894
|
if (cancelled || signature === lastIntentSig.current) {
|
|
823
895
|
return
|
|
824
896
|
}
|
|
825
897
|
lastIntentSig.current = signature
|
|
826
|
-
|
|
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
|
+
})
|
|
827
916
|
} catch {
|
|
828
917
|
// Explorer may be running without the intent endpoint yet.
|
|
829
918
|
}
|
|
@@ -836,7 +925,7 @@ function Explorer({
|
|
|
836
925
|
cancelled = true
|
|
837
926
|
window.clearInterval(timer)
|
|
838
927
|
}
|
|
839
|
-
}, [
|
|
928
|
+
}, [])
|
|
840
929
|
|
|
841
930
|
const plannedIds = previewing ? [...intent.files, ...intent.creates] : []
|
|
842
931
|
const blueprintImportEdges = blueprintImports.flatMap((item) => {
|
|
@@ -854,6 +943,7 @@ function Explorer({
|
|
|
854
943
|
<div className="stage">
|
|
855
944
|
<Canvas
|
|
856
945
|
shadows={false}
|
|
946
|
+
dpr={[1, 1.5]}
|
|
857
947
|
gl={{ antialias: true, toneMappingExposure: 1.25 }}
|
|
858
948
|
camera={{
|
|
859
949
|
position: layout.spawn,
|
|
@@ -890,8 +980,8 @@ function Explorer({
|
|
|
890
980
|
importedBy={importedBy}
|
|
891
981
|
namingId={namingId}
|
|
892
982
|
namingIslandId={namingIslandId}
|
|
893
|
-
onPlaceBlock={
|
|
894
|
-
onPlaceIsland={
|
|
983
|
+
onPlaceBlock={creationMode ? placeBlock : undefined}
|
|
984
|
+
onPlaceIsland={creationMode ? placeIsland : undefined}
|
|
895
985
|
onCommitName={commitBlockName}
|
|
896
986
|
onCancelName={cancelBlockName}
|
|
897
987
|
userCreatedBlocks={userBlocks}
|
|
@@ -901,13 +991,19 @@ function Explorer({
|
|
|
901
991
|
</div>
|
|
902
992
|
<HUD
|
|
903
993
|
graph={displayGraph}
|
|
994
|
+
layout={layout}
|
|
904
995
|
mode={mode}
|
|
905
996
|
locked={locked}
|
|
906
997
|
selectedId={selectedId}
|
|
998
|
+
selectedTick={selectedTick}
|
|
907
999
|
selectedFolder={selectedFolder}
|
|
1000
|
+
landAt={landAt}
|
|
908
1001
|
aimedRelation={aimedRelation}
|
|
909
1002
|
currentFolder={currentFolder}
|
|
910
1003
|
intent={intent}
|
|
1004
|
+
intents={intents}
|
|
1005
|
+
focusedSessionId={focusedSessionId}
|
|
1006
|
+
onFocusSession={setFocusedSessionId}
|
|
911
1007
|
onWorkflowAction={runWorkflowAction}
|
|
912
1008
|
onNavigateDiff={navigateDiff}
|
|
913
1009
|
onOpenMap={openMap}
|
|
@@ -935,6 +1031,10 @@ function Explorer({
|
|
|
935
1031
|
onRemoveBlueprintImport={removeBlueprintImport}
|
|
936
1032
|
onMapAddFile={placeBlockOnFolder}
|
|
937
1033
|
onMapAddFolder={placeIslandOnFolder}
|
|
1034
|
+
onInspectFile={inspectFile}
|
|
1035
|
+
plannedIds={plannedIds}
|
|
1036
|
+
createdIds={plannedCreates}
|
|
1037
|
+
deletedIds={deletedIds}
|
|
938
1038
|
/>
|
|
939
1039
|
</>
|
|
940
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
|
|
@@ -180,3 +212,24 @@ export function persistSessionBlueprint(
|
|
|
180
212
|
// Keep local drafts if the session handshake is no longer open.
|
|
181
213
|
})
|
|
182
214
|
}
|
|
215
|
+
|
|
216
|
+
export async function inspectTargetFile(payload: {
|
|
217
|
+
sessionId?: string | null
|
|
218
|
+
diffId?: string | null
|
|
219
|
+
fileId?: string
|
|
220
|
+
}) {
|
|
221
|
+
const response = await fetch('/api/inspect-file', {
|
|
222
|
+
method: 'POST',
|
|
223
|
+
headers: { 'Content-Type': 'application/json' },
|
|
224
|
+
body: JSON.stringify(payload),
|
|
225
|
+
})
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
const detail = await response.text()
|
|
228
|
+
throw new Error(detail || 'Could not inspect file')
|
|
229
|
+
}
|
|
230
|
+
return (await response.json()) as {
|
|
231
|
+
path: string | null
|
|
232
|
+
uri: string | null
|
|
233
|
+
opened: boolean
|
|
234
|
+
}
|
|
235
|
+
}
|