@jkwd/inbase 0.1.9 → 0.1.11
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/LICENSE +21 -0
- package/README.md +23 -7
- package/apps/explorer/package.json +1 -0
- package/apps/explorer/scripts/branch-changes.d.ts +24 -0
- package/apps/explorer/scripts/branch-changes.mjs +237 -0
- package/apps/explorer/scripts/js-source.mjs +12 -15
- package/apps/explorer/scripts/patch-lib.d.ts +6 -0
- package/apps/explorer/scripts/patch-lib.mjs +6 -0
- package/apps/explorer/scripts/scan-target.mjs +46 -13
- package/apps/explorer/scripts/session-store.d.ts +64 -1
- package/apps/explorer/scripts/session-store.mjs +369 -88
- package/apps/explorer/scripts/tree-diff.mjs +121 -0
- package/apps/explorer/src/App.tsx +215 -86
- package/apps/explorer/src/agentIntent.ts +78 -0
- package/apps/explorer/src/branchChanges.ts +54 -0
- package/apps/explorer/src/index.css +152 -10
- package/apps/explorer/src/scene/FileBlock.tsx +55 -5
- package/apps/explorer/src/types.ts +46 -0
- package/apps/explorer/src/ui/HUD.tsx +670 -158
- package/apps/explorer/src/userContext.ts +11 -0
- package/apps/explorer/vite.config.ts +65 -5
- package/bin/inbase.mjs +23 -4
- package/bin/project.mjs +62 -4
- package/bin/session.mjs +215 -125
- package/package.json +20 -2
- package/skill/commands/inbase.md +17 -0
- package/skill/commands/skipinbase.md +9 -0
- package/skill/inbase/SKILL.md +142 -89
|
@@ -45,10 +45,26 @@ function normalizeImportAdditions(value: unknown): PatchImportAddition[] {
|
|
|
45
45
|
})
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function normalizeAck(
|
|
49
|
+
value: unknown,
|
|
50
|
+
): AgentIntent['lastAck'] {
|
|
51
|
+
if (!value || typeof value !== 'object') return null
|
|
52
|
+
const kind = (value as { kind?: unknown }).kind
|
|
53
|
+
if (typeof kind !== 'string' || kind.trim() === '') return null
|
|
54
|
+
const detail = (value as { detail?: unknown }).detail
|
|
55
|
+
const at = (value as { at?: unknown }).at
|
|
56
|
+
return {
|
|
57
|
+
kind,
|
|
58
|
+
detail: typeof detail === 'string' ? detail : '',
|
|
59
|
+
at: typeof at === 'string' ? at : null,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
export const emptyIntent: AgentIntent = {
|
|
49
64
|
updatedAt: null,
|
|
50
65
|
showMap: false,
|
|
51
66
|
status: 'idle',
|
|
67
|
+
name: null,
|
|
52
68
|
feature: null,
|
|
53
69
|
steps: [],
|
|
54
70
|
step: null,
|
|
@@ -75,6 +91,11 @@ export const emptyIntent: AgentIntent = {
|
|
|
75
91
|
phase: null,
|
|
76
92
|
working: false,
|
|
77
93
|
stalledWait: false,
|
|
94
|
+
llmIdle: false,
|
|
95
|
+
awaitingAttach: false,
|
|
96
|
+
listening: false,
|
|
97
|
+
lastAck: null,
|
|
98
|
+
initialInstruction: null,
|
|
78
99
|
creationMode: false,
|
|
79
100
|
canEnterBlueprint: false,
|
|
80
101
|
blueprintSessionId: null,
|
|
@@ -90,6 +111,7 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
|
90
111
|
updatedAt: data?.updatedAt ?? null,
|
|
91
112
|
showMap: Boolean(data?.showMap),
|
|
92
113
|
status: data?.status ?? 'idle',
|
|
114
|
+
name: data?.name ?? null,
|
|
93
115
|
feature: data?.feature ?? null,
|
|
94
116
|
steps: Array.isArray(data?.steps) ? data.steps : [],
|
|
95
117
|
step: typeof data?.step === 'number' ? data.step : null,
|
|
@@ -119,6 +141,12 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
|
|
|
119
141
|
phase: data?.phase ?? null,
|
|
120
142
|
working: Boolean(data?.working),
|
|
121
143
|
stalledWait: Boolean(data?.stalledWait),
|
|
144
|
+
llmIdle: Boolean(data?.llmIdle),
|
|
145
|
+
awaitingAttach: Boolean(data?.awaitingAttach),
|
|
146
|
+
listening: Boolean(data?.listening),
|
|
147
|
+
lastAck: normalizeAck(data?.lastAck),
|
|
148
|
+
initialInstruction:
|
|
149
|
+
typeof data?.initialInstruction === 'string' ? data.initialInstruction : null,
|
|
122
150
|
creationMode: Boolean(data?.creationMode),
|
|
123
151
|
canEnterBlueprint: Boolean(data?.canEnterBlueprint),
|
|
124
152
|
blueprintSessionId:
|
|
@@ -222,6 +250,56 @@ export function persistSessionBlueprint(
|
|
|
222
250
|
})
|
|
223
251
|
}
|
|
224
252
|
|
|
253
|
+
export function persistInitialInstruction(sessionId: string, instruction: string) {
|
|
254
|
+
fetch('/api/agent-intent', {
|
|
255
|
+
method: 'POST',
|
|
256
|
+
headers: { 'Content-Type': 'application/json' },
|
|
257
|
+
body: JSON.stringify({
|
|
258
|
+
action: 'set_initial_instruction',
|
|
259
|
+
sessionId,
|
|
260
|
+
instruction,
|
|
261
|
+
}),
|
|
262
|
+
}).catch(() => {
|
|
263
|
+
// Keep the local instruction if the session handshake is no longer open.
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function persistSessionFocus(sessionId: string) {
|
|
268
|
+
fetch('/api/agent-intent', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
headers: { 'Content-Type': 'application/json' },
|
|
271
|
+
body: JSON.stringify({
|
|
272
|
+
action: 'focus',
|
|
273
|
+
sessionId,
|
|
274
|
+
}),
|
|
275
|
+
}).catch(() => {
|
|
276
|
+
// Keep the local focused session if the server could not record it.
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export async function setupVisualizerSession(name?: string) {
|
|
281
|
+
const response = await fetch('/api/agent-intent', {
|
|
282
|
+
method: 'POST',
|
|
283
|
+
headers: { 'Content-Type': 'application/json' },
|
|
284
|
+
body: JSON.stringify({
|
|
285
|
+
action: 'setup_session',
|
|
286
|
+
name,
|
|
287
|
+
}),
|
|
288
|
+
})
|
|
289
|
+
if (!response.ok) {
|
|
290
|
+
const detail = await response.text()
|
|
291
|
+
let message = detail || 'Could not set up the LLM session'
|
|
292
|
+
try {
|
|
293
|
+
const parsed = JSON.parse(detail) as { error?: string }
|
|
294
|
+
if (parsed?.error) message = parsed.error
|
|
295
|
+
} catch {
|
|
296
|
+
// Use the raw body when it is not JSON.
|
|
297
|
+
}
|
|
298
|
+
throw new Error(message)
|
|
299
|
+
}
|
|
300
|
+
return normalize((await response.json()) as AgentIntent)
|
|
301
|
+
}
|
|
302
|
+
|
|
225
303
|
export async function inspectTargetFile(payload: {
|
|
226
304
|
sessionId?: string | null
|
|
227
305
|
diffId?: string | null
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { BranchChanges } from './types'
|
|
2
|
+
|
|
3
|
+
export const emptyBranchChanges: BranchChanges = {
|
|
4
|
+
available: false,
|
|
5
|
+
branch: null,
|
|
6
|
+
base: null,
|
|
7
|
+
files: [],
|
|
8
|
+
creates: [],
|
|
9
|
+
deletes: [],
|
|
10
|
+
createFolders: [],
|
|
11
|
+
createLines: {},
|
|
12
|
+
imports: [],
|
|
13
|
+
addedFunctions: [],
|
|
14
|
+
addedVariables: [],
|
|
15
|
+
addedImports: [],
|
|
16
|
+
changedFunctions: [],
|
|
17
|
+
changedVariables: [],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalize(data: Partial<BranchChanges> | null | undefined): BranchChanges {
|
|
21
|
+
return {
|
|
22
|
+
available: Boolean(data?.available),
|
|
23
|
+
branch: typeof data?.branch === 'string' ? data.branch : null,
|
|
24
|
+
base: typeof data?.base === 'string' ? data.base : null,
|
|
25
|
+
files: Array.isArray(data?.files) ? data.files : [],
|
|
26
|
+
creates: Array.isArray(data?.creates) ? data.creates : [],
|
|
27
|
+
deletes: Array.isArray(data?.deletes) ? data.deletes : [],
|
|
28
|
+
createFolders: Array.isArray(data?.createFolders) ? data.createFolders : [],
|
|
29
|
+
createLines:
|
|
30
|
+
data?.createLines && typeof data.createLines === 'object'
|
|
31
|
+
? data.createLines
|
|
32
|
+
: {},
|
|
33
|
+
imports: Array.isArray(data?.imports) ? data.imports : [],
|
|
34
|
+
addedFunctions: Array.isArray(data?.addedFunctions) ? data.addedFunctions : [],
|
|
35
|
+
addedVariables: Array.isArray(data?.addedVariables) ? data.addedVariables : [],
|
|
36
|
+
addedImports: Array.isArray(data?.addedImports) ? data.addedImports : [],
|
|
37
|
+
changedFunctions: Array.isArray(data?.changedFunctions)
|
|
38
|
+
? data.changedFunctions
|
|
39
|
+
: [],
|
|
40
|
+
changedVariables: Array.isArray(data?.changedVariables)
|
|
41
|
+
? data.changedVariables
|
|
42
|
+
: [],
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function fetchBranchChanges(): Promise<BranchChanges> {
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch(`/api/branch-changes?t=${Date.now()}`)
|
|
49
|
+
if (!response.ok) return emptyBranchChanges
|
|
50
|
+
return normalize((await response.json()) as BranchChanges)
|
|
51
|
+
} catch {
|
|
52
|
+
return emptyBranchChanges
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -251,6 +251,19 @@ button {
|
|
|
251
251
|
background: rgba(25, 28, 34, 0.94);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
.map-change-mark {
|
|
255
|
+
pointer-events: none;
|
|
256
|
+
user-select: none;
|
|
257
|
+
color: #f4f7fb;
|
|
258
|
+
font-size: 32px;
|
|
259
|
+
font-weight: 800;
|
|
260
|
+
line-height: 1;
|
|
261
|
+
letter-spacing: 0;
|
|
262
|
+
-webkit-text-stroke: 0.09em #11151c;
|
|
263
|
+
paint-order: stroke fill;
|
|
264
|
+
text-shadow: 0 0 0.12em #11151c;
|
|
265
|
+
}
|
|
266
|
+
|
|
254
267
|
.map-you-are-here {
|
|
255
268
|
display: grid;
|
|
256
269
|
justify-items: center;
|
|
@@ -443,6 +456,11 @@ button {
|
|
|
443
456
|
flex: none;
|
|
444
457
|
}
|
|
445
458
|
|
|
459
|
+
.hud-icon-button[aria-disabled='true'] {
|
|
460
|
+
opacity: 0.55;
|
|
461
|
+
cursor: default;
|
|
462
|
+
}
|
|
463
|
+
|
|
446
464
|
.hud-tooltip {
|
|
447
465
|
position: absolute;
|
|
448
466
|
right: 0;
|
|
@@ -533,6 +551,24 @@ button {
|
|
|
533
551
|
overflow-y: auto;
|
|
534
552
|
}
|
|
535
553
|
|
|
554
|
+
.hud-session-tabs {
|
|
555
|
+
display: flex;
|
|
556
|
+
gap: 6px;
|
|
557
|
+
flex: 0 0 auto;
|
|
558
|
+
pointer-events: auto;
|
|
559
|
+
overflow-x: auto;
|
|
560
|
+
max-width: 100%;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.hud-session-tab {
|
|
564
|
+
flex: 1 1 0;
|
|
565
|
+
min-width: 0;
|
|
566
|
+
overflow: hidden;
|
|
567
|
+
text-overflow: ellipsis;
|
|
568
|
+
white-space: nowrap;
|
|
569
|
+
font-size: 13px;
|
|
570
|
+
}
|
|
571
|
+
|
|
536
572
|
.hud-left-stack .hud-panel-planned {
|
|
537
573
|
position: relative;
|
|
538
574
|
top: auto;
|
|
@@ -553,10 +589,6 @@ button {
|
|
|
553
589
|
flex: 0 0 auto;
|
|
554
590
|
}
|
|
555
591
|
|
|
556
|
-
.hud-left-stack .hud-panel-planned[data-focused='false'] {
|
|
557
|
-
opacity: 0.86;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
592
|
.hud-left-stack .hud-panel-planned[data-focused='true'] {
|
|
561
593
|
box-shadow: 0 0 0 1px #9ad8ff;
|
|
562
594
|
}
|
|
@@ -628,6 +660,11 @@ button {
|
|
|
628
660
|
margin: -4px 0 8px;
|
|
629
661
|
}
|
|
630
662
|
|
|
663
|
+
.hud-panel-chrome-heading {
|
|
664
|
+
min-width: 0;
|
|
665
|
+
flex: 1 1 auto;
|
|
666
|
+
}
|
|
667
|
+
|
|
631
668
|
.hud-panel[data-minimized='true'] {
|
|
632
669
|
overflow: hidden;
|
|
633
670
|
padding-bottom: 12px;
|
|
@@ -649,6 +686,24 @@ button {
|
|
|
649
686
|
white-space: nowrap;
|
|
650
687
|
}
|
|
651
688
|
|
|
689
|
+
.hud-panel-planned .hud-panel-chrome-title {
|
|
690
|
+
color: #e7ebf2;
|
|
691
|
+
font-size: 14px;
|
|
692
|
+
letter-spacing: 0.02em;
|
|
693
|
+
text-transform: none;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.hud-panel-chrome-subtitle {
|
|
697
|
+
overflow: hidden;
|
|
698
|
+
color: #8b95a5;
|
|
699
|
+
font-size: 10px;
|
|
700
|
+
font-weight: 600;
|
|
701
|
+
letter-spacing: 0.08em;
|
|
702
|
+
text-transform: uppercase;
|
|
703
|
+
text-overflow: ellipsis;
|
|
704
|
+
white-space: nowrap;
|
|
705
|
+
}
|
|
706
|
+
|
|
652
707
|
.hud-mode-switch {
|
|
653
708
|
display: flex;
|
|
654
709
|
align-items: center;
|
|
@@ -874,24 +929,28 @@ button {
|
|
|
874
929
|
min-width: 0;
|
|
875
930
|
}
|
|
876
931
|
|
|
877
|
-
.hud-steps li[data-
|
|
932
|
+
.hud-steps li[data-active='true']:not([data-done='true']) {
|
|
878
933
|
color: #ffffff;
|
|
879
934
|
}
|
|
880
935
|
|
|
881
|
-
.hud-steps li[data-
|
|
936
|
+
.hud-steps li[data-active='true']:not([data-done='true']) .hud-step-title {
|
|
882
937
|
color: #ffffff;
|
|
883
938
|
text-decoration: underline;
|
|
884
939
|
text-underline-offset: 3px;
|
|
885
940
|
}
|
|
886
941
|
|
|
887
|
-
.hud-steps li[data-current='true']:not([data-next='true']):not([data-done='true']) {
|
|
888
|
-
color: #9ad8ff;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
942
|
.hud-steps li[data-done='true'],
|
|
892
943
|
.hud-steps li[data-done='true'] .hud-step-title {
|
|
893
944
|
color: #3dff78;
|
|
894
945
|
font-weight: 600;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
.hud-steps li[data-done='true'][data-active='true'] .hud-step-title {
|
|
949
|
+
text-decoration: underline;
|
|
950
|
+
text-underline-offset: 3px;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.hud-steps li[data-done='true']:not([data-active='true']) .hud-step-title {
|
|
895
954
|
text-decoration: none;
|
|
896
955
|
}
|
|
897
956
|
|
|
@@ -922,6 +981,52 @@ button {
|
|
|
922
981
|
font-size: 11px;
|
|
923
982
|
}
|
|
924
983
|
|
|
984
|
+
.hud-setup {
|
|
985
|
+
display: grid;
|
|
986
|
+
gap: 16px;
|
|
987
|
+
margin-top: 12px;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
.hud-setup-heading {
|
|
991
|
+
display: flex;
|
|
992
|
+
align-items: center;
|
|
993
|
+
flex-wrap: wrap;
|
|
994
|
+
gap: 8px;
|
|
995
|
+
margin: 0 0 8px;
|
|
996
|
+
color: #8b95a5;
|
|
997
|
+
font-size: 11px;
|
|
998
|
+
font-weight: 600;
|
|
999
|
+
letter-spacing: 0.08em;
|
|
1000
|
+
text-transform: uppercase;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
.hud-setup-tag {
|
|
1004
|
+
padding: 2px 6px;
|
|
1005
|
+
border: 1px solid #3a4250;
|
|
1006
|
+
border-radius: 3px;
|
|
1007
|
+
color: #8b95a5;
|
|
1008
|
+
font-size: 10px;
|
|
1009
|
+
font-weight: 600;
|
|
1010
|
+
letter-spacing: 0.04em;
|
|
1011
|
+
text-transform: none;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
.hud-setup-tag[data-ready='true'] {
|
|
1015
|
+
border-color: #5d9ec4;
|
|
1016
|
+
color: #d7eef8;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
.hud-setup-section p {
|
|
1020
|
+
margin: 0;
|
|
1021
|
+
color: #b7c0ce;
|
|
1022
|
+
font-size: 12px;
|
|
1023
|
+
line-height: 1.45;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.hud-setup-section .hud-instruction {
|
|
1027
|
+
margin-top: 0;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
925
1030
|
.hud-instruction textarea {
|
|
926
1031
|
width: 100%;
|
|
927
1032
|
resize: vertical;
|
|
@@ -947,6 +1052,43 @@ button {
|
|
|
947
1052
|
font-size: 12px;
|
|
948
1053
|
}
|
|
949
1054
|
|
|
1055
|
+
.hud-live {
|
|
1056
|
+
display: flex;
|
|
1057
|
+
align-items: center;
|
|
1058
|
+
flex-wrap: wrap;
|
|
1059
|
+
gap: 9px;
|
|
1060
|
+
margin: 2px 0 10px;
|
|
1061
|
+
padding: 8px 10px;
|
|
1062
|
+
border-radius: 8px;
|
|
1063
|
+
background: rgba(154, 216, 255, 0.08);
|
|
1064
|
+
border: 1px solid rgba(154, 216, 255, 0.22);
|
|
1065
|
+
color: #d7eef8;
|
|
1066
|
+
font-size: 12px;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
.hud-live[data-busy='false'] {
|
|
1070
|
+
background: rgba(255, 255, 255, 0.04);
|
|
1071
|
+
border-color: rgba(255, 255, 255, 0.12);
|
|
1072
|
+
color: #c5d0d8;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
.hud-live[data-flash='true'] {
|
|
1076
|
+
animation: hud-live-flash 0.65s ease;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.hud-live .hud-button {
|
|
1080
|
+
margin-left: auto;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
@keyframes hud-live-flash {
|
|
1084
|
+
from {
|
|
1085
|
+
background: rgba(154, 216, 255, 0.32);
|
|
1086
|
+
}
|
|
1087
|
+
to {
|
|
1088
|
+
background: rgba(154, 216, 255, 0.08);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
950
1092
|
.hud-working .hud-button {
|
|
951
1093
|
margin-left: auto;
|
|
952
1094
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Suspense } from 'react'
|
|
1
|
+
import { Suspense, useRef } from 'react'
|
|
2
2
|
import { Billboard, Edges, Html, Text } from '@react-three/drei'
|
|
3
|
+
import { useFrame, useThree } from '@react-three/fiber'
|
|
3
4
|
import { CHANGE_HIGHLIGHT, CONFIG, dimColor, fileColor, FILE_SELECTION, MAP_SELECTION, type ChangeKind } from '../theme'
|
|
4
5
|
import { NameInput } from '../ui/NameInput'
|
|
5
6
|
import { MapSelectBorder } from './MapSelectBorder'
|
|
@@ -40,6 +41,50 @@ function fileLabel(name: string, changeKind: ChangeKind | null, added: boolean)
|
|
|
40
41
|
return name
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
function changeMark(changeKind: ChangeKind | null, added: boolean) {
|
|
45
|
+
if (changeKind === 'remove') return 'D'
|
|
46
|
+
if (changeKind === 'add' || added) return 'A'
|
|
47
|
+
if (changeKind === 'edit') return 'U'
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function MapChangeMark({
|
|
52
|
+
mark,
|
|
53
|
+
width,
|
|
54
|
+
depth,
|
|
55
|
+
height,
|
|
56
|
+
}: {
|
|
57
|
+
mark: string
|
|
58
|
+
width: number
|
|
59
|
+
depth: number
|
|
60
|
+
height: number
|
|
61
|
+
}) {
|
|
62
|
+
const camera = useThree((state) => state.camera)
|
|
63
|
+
const markRef = useRef<HTMLDivElement>(null)
|
|
64
|
+
|
|
65
|
+
useFrame(() => {
|
|
66
|
+
const el = markRef.current
|
|
67
|
+
if (!el) return
|
|
68
|
+
const zoom = 'zoom' in camera ? Number(camera.zoom) : 1
|
|
69
|
+
const px = Math.min(width, depth) * 0.78 * zoom
|
|
70
|
+
el.style.fontSize = `${Math.max(px, 1)}px`
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Html
|
|
75
|
+
position={[0, height / 2 + 0.12, 0]}
|
|
76
|
+
center
|
|
77
|
+
occlude={false}
|
|
78
|
+
zIndexRange={[120, 100]}
|
|
79
|
+
style={{ pointerEvents: 'none' }}
|
|
80
|
+
>
|
|
81
|
+
<div ref={markRef} className="map-change-mark">
|
|
82
|
+
{mark}
|
|
83
|
+
</div>
|
|
84
|
+
</Html>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
43
88
|
export function FileBlock({
|
|
44
89
|
file,
|
|
45
90
|
placed,
|
|
@@ -63,9 +108,11 @@ export function FileBlock({
|
|
|
63
108
|
changeKind && highlightMapChange && !selected
|
|
64
109
|
? CHANGE_HIGHLIGHT[changeKind]
|
|
65
110
|
: null
|
|
66
|
-
const
|
|
111
|
+
const isAdded = added || Boolean(file.userCreated)
|
|
112
|
+
const color = isAdded ? '#7ec8e8' : fileColor(file.language)
|
|
67
113
|
const muted = dimColor(color, 0.32)
|
|
68
|
-
const label = fileLabel(file.name, changeKind,
|
|
114
|
+
const label = fileLabel(file.name, changeKind, isAdded)
|
|
115
|
+
const mark = changeMark(changeKind, isAdded)
|
|
69
116
|
const labelColor = aimed
|
|
70
117
|
? '#9ad8ff'
|
|
71
118
|
: highlight
|
|
@@ -105,7 +152,7 @@ export function FileBlock({
|
|
|
105
152
|
? FILE_SELECTION.emissive
|
|
106
153
|
: related
|
|
107
154
|
? '#1f4a44'
|
|
108
|
-
:
|
|
155
|
+
: isAdded
|
|
109
156
|
? '#2a5064'
|
|
110
157
|
: dimmed
|
|
111
158
|
? muted
|
|
@@ -120,7 +167,7 @@ export function FileBlock({
|
|
|
120
167
|
? 0.55
|
|
121
168
|
: related
|
|
122
169
|
? 0.18
|
|
123
|
-
:
|
|
170
|
+
: isAdded
|
|
124
171
|
? 0.22
|
|
125
172
|
: dimmed
|
|
126
173
|
? 0.08
|
|
@@ -148,6 +195,9 @@ export function FileBlock({
|
|
|
148
195
|
userData={{ fileId: file.id }}
|
|
149
196
|
/>
|
|
150
197
|
)}
|
|
198
|
+
{mapMode && !naming && mark && (
|
|
199
|
+
<MapChangeMark mark={mark} width={width} depth={depth} height={height} />
|
|
200
|
+
)}
|
|
151
201
|
{naming && onCommitName && onCancelName && (
|
|
152
202
|
<Html
|
|
153
203
|
position={[0, height / 2 + 0.42, 0]}
|
|
@@ -114,6 +114,7 @@ export type UserContext = {
|
|
|
114
114
|
z: number
|
|
115
115
|
}
|
|
116
116
|
followLook?: boolean
|
|
117
|
+
showBranchChanges?: boolean
|
|
117
118
|
userCreatedBlocks?: UserCreatedBlock[]
|
|
118
119
|
userCreatedIslands?: UserCreatedIsland[]
|
|
119
120
|
}
|
|
@@ -160,6 +161,40 @@ export function canStopSession(intent: {
|
|
|
160
161
|
return Boolean(intent.sessionId) && intent.status !== 'idle'
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
export function llmIsMakingChanges(intent: {
|
|
165
|
+
working: boolean
|
|
166
|
+
preview: boolean
|
|
167
|
+
status: AgentIntentStatus
|
|
168
|
+
}) {
|
|
169
|
+
return (
|
|
170
|
+
intent.working ||
|
|
171
|
+
intent.preview ||
|
|
172
|
+
intent.status === 'preparing' ||
|
|
173
|
+
intent.status === 'working' ||
|
|
174
|
+
intent.status === 'replanning' ||
|
|
175
|
+
intent.status === 'pending' ||
|
|
176
|
+
intent.status === 'extend' ||
|
|
177
|
+
intent.status === 'extended'
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type BranchChanges = {
|
|
182
|
+
available: boolean
|
|
183
|
+
branch: string | null
|
|
184
|
+
base: string | null
|
|
185
|
+
files: string[]
|
|
186
|
+
creates: string[]
|
|
187
|
+
deletes: string[]
|
|
188
|
+
createFolders: string[]
|
|
189
|
+
createLines: Record<string, number>
|
|
190
|
+
imports: PatchImport[]
|
|
191
|
+
addedFunctions: PatchSymbolAddition[]
|
|
192
|
+
addedVariables: PatchSymbolAddition[]
|
|
193
|
+
addedImports: PatchImportAddition[]
|
|
194
|
+
changedFunctions: PatchSymbolAddition[]
|
|
195
|
+
changedVariables: PatchSymbolAddition[]
|
|
196
|
+
}
|
|
197
|
+
|
|
163
198
|
export type PlanStep = {
|
|
164
199
|
index: number
|
|
165
200
|
title: string
|
|
@@ -215,6 +250,7 @@ export type WorkflowAction =
|
|
|
215
250
|
| 'blueprint_no'
|
|
216
251
|
| 'blueprint_send'
|
|
217
252
|
| 'blueprint_update'
|
|
253
|
+
| 'focus'
|
|
218
254
|
| 'set_step_by_step'
|
|
219
255
|
|
|
220
256
|
export type AgentIntentBundle = {
|
|
@@ -226,6 +262,7 @@ export type AgentIntent = {
|
|
|
226
262
|
updatedAt: string | null
|
|
227
263
|
showMap: boolean
|
|
228
264
|
status: AgentIntentStatus
|
|
265
|
+
name: string | null
|
|
229
266
|
feature: string | null
|
|
230
267
|
steps: PlanStep[]
|
|
231
268
|
step: number | null
|
|
@@ -252,6 +289,15 @@ export type AgentIntent = {
|
|
|
252
289
|
phase: WorkflowPhase | null
|
|
253
290
|
working: boolean
|
|
254
291
|
stalledWait: boolean
|
|
292
|
+
llmIdle?: boolean
|
|
293
|
+
awaitingAttach?: boolean
|
|
294
|
+
listening?: boolean
|
|
295
|
+
lastAck?: {
|
|
296
|
+
kind: string
|
|
297
|
+
detail: string
|
|
298
|
+
at: string | null
|
|
299
|
+
} | null
|
|
300
|
+
initialInstruction?: string | null
|
|
255
301
|
creationMode: boolean
|
|
256
302
|
canEnterBlueprint: boolean
|
|
257
303
|
blueprintSessionId: string | null
|