@jkwd/inbase 0.1.5 → 0.1.7

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.
@@ -58,17 +58,83 @@ function importLabels(items: PatchImportAddition[]) {
58
58
  function PanelList({
59
59
  title,
60
60
  items,
61
+ tone,
61
62
  }: {
62
63
  title: string
63
64
  items: Array<{ key: string; label: string }>
65
+ tone?: 'add' | 'edit' | 'remove'
64
66
  }) {
65
67
  if (items.length === 0) return null
68
+ const titleClass =
69
+ tone === 'add'
70
+ ? 'hud-section-title hud-section-title-add'
71
+ : tone === 'edit'
72
+ ? 'hud-section-title hud-section-title-edit'
73
+ : tone === 'remove'
74
+ ? 'hud-section-title hud-section-title-remove'
75
+ : 'hud-section-title'
76
+ const itemClass =
77
+ tone === 'add'
78
+ ? 'hud-file-add'
79
+ : tone === 'edit'
80
+ ? 'hud-file-edit'
81
+ : tone === 'remove'
82
+ ? 'hud-file-remove'
83
+ : undefined
66
84
  return (
67
85
  <>
68
- <div className="hud-section-title">{title}</div>
86
+ <div className={titleClass}>{title}</div>
69
87
  <ul>
70
88
  {items.map((item) => (
71
- <li key={item.key}>{item.label}</li>
89
+ <li className={itemClass} key={item.key}>
90
+ {item.label}
91
+ </li>
92
+ ))}
93
+ </ul>
94
+ </>
95
+ )
96
+ }
97
+
98
+ function symbolChangeClass(kind: 'add' | 'edit' | null | undefined) {
99
+ if (kind === 'add') return 'hud-file-add'
100
+ if (kind === 'edit') return 'hud-file-edit'
101
+ return undefined
102
+ }
103
+
104
+ function extraAddedSymbols(
105
+ existing: Array<{ name: string }>,
106
+ added: PatchSymbolAddition[],
107
+ ) {
108
+ const have = new Set(existing.map((item) => item.name))
109
+ return added.filter((item) => !have.has(item.name))
110
+ }
111
+
112
+ function PatchSymbolChanges({
113
+ title,
114
+ added,
115
+ changed,
116
+ }: {
117
+ title: string
118
+ added: PatchSymbolAddition[]
119
+ changed: PatchSymbolAddition[]
120
+ }) {
121
+ if (added.length === 0 && changed.length === 0) return null
122
+ const addedNames = new Set(added.map((item) => item.name))
123
+ return (
124
+ <>
125
+ <div className="hud-section-title">{title}</div>
126
+ <ul>
127
+ {changed
128
+ .filter((item) => !addedNames.has(item.name))
129
+ .map((item) => (
130
+ <li className="hud-file-edit" key={`edit-${item.file}:${item.name}`}>
131
+ {item.name}
132
+ </li>
133
+ ))}
134
+ {added.map((item) => (
135
+ <li className="hud-file-add" key={`add-${item.file}:${item.name}`}>
136
+ {item.name}
137
+ </li>
72
138
  ))}
73
139
  </ul>
74
140
  </>
@@ -174,7 +240,7 @@ type SessionPanelProps = {
174
240
  onWorkflowAction: (
175
241
  sessionId: string,
176
242
  action: WorkflowAction,
177
- options?: { instruction?: string; step?: number },
243
+ options?: { instruction?: string; step?: number; stepByStep?: boolean },
178
244
  ) => void
179
245
  onNavigateDiff: (sessionId: string, diffId: string) => void
180
246
  }
@@ -208,9 +274,12 @@ function SessionPanel({
208
274
  typeof intent.step === 'number' &&
209
275
  intent.steps.length > 0 &&
210
276
  intent.step >= intent.steps.length
277
+ const stepByStep = intent.stepByStep !== false
211
278
  const addedFunctions = intent.addedFunctions ?? []
212
279
  const addedVariables = intent.addedVariables ?? []
213
280
  const addedImports = intent.addedImports ?? []
281
+ const changedFunctions = intent.changedFunctions ?? []
282
+ const changedVariables = intent.changedVariables ?? []
214
283
  const doneSteps = new Set(
215
284
  intent.status === 'finished'
216
285
  ? intent.steps.map((step) => step.index)
@@ -247,7 +316,7 @@ function SessionPanel({
247
316
 
248
317
  const act = (
249
318
  action: WorkflowAction,
250
- options?: { instruction?: string; step?: number },
319
+ options?: { instruction?: string; step?: number; stepByStep?: boolean },
251
320
  ) => onWorkflowAction(sessionId, action, options)
252
321
 
253
322
  return (
@@ -268,6 +337,24 @@ function SessionPanel({
268
337
  />
269
338
  {!minimized && (
270
339
  <>
340
+ <label className="hud-mode-switch">
341
+ <span>Step by step</span>
342
+ <button
343
+ className="hud-switch"
344
+ type="button"
345
+ role="switch"
346
+ aria-checked={stepByStep}
347
+ aria-label="Step by step"
348
+ onKeyDown={(event) => event.stopPropagation()}
349
+ onClick={() => act('set_step_by_step', { stepByStep: !stepByStep })}
350
+ />
351
+ </label>
352
+ {!stepByStep && (
353
+ <p className="hud-mode-hint">
354
+ LLM implements the full plan. You can still walk the diffs, then
355
+ Complete.
356
+ </p>
357
+ )}
271
358
  {intent.feature && <p className="hud-feature">{intent.feature}</p>}
272
359
  {askingBlueprint ? (
273
360
  <>
@@ -346,7 +433,9 @@ function SessionPanel({
346
433
  <span>
347
434
  {intent.status === 'replanning'
348
435
  ? 'Updating the remaining plan from your instruction…'
349
- : `Implementing ${stepLabel.toLowerCase()}…`}
436
+ : intent.stalledWait
437
+ ? 'The LLM is still waiting on this step…'
438
+ : `Implementing ${stepLabel.toLowerCase()}…`}
350
439
  </span>
351
440
  <button
352
441
  className="hud-button hud-button-reject"
@@ -383,7 +472,9 @@ function SessionPanel({
383
472
  <span className="hud-step-index">{step.index}.</span>
384
473
  <span className="hud-step-main">
385
474
  <span className="hud-step-title">{step.title}</span>
386
- {((canRunNext && nextStep?.index === step.index) ||
475
+ {((stepByStep &&
476
+ canRunNext &&
477
+ nextStep?.index === step.index) ||
387
478
  (canComplete && step.index === intent.step)) && (
388
479
  <button
389
480
  className="hud-button hud-button-approve hud-run-step"
@@ -443,6 +534,8 @@ function SessionPanel({
443
534
  addedFunctions.length > 0 ||
444
535
  addedVariables.length > 0 ||
445
536
  addedImports.length > 0 ||
537
+ changedFunctions.length > 0 ||
538
+ changedVariables.length > 0 ||
446
539
  (intent.imports ?? []).length > 0)
447
540
  }
448
541
  >
@@ -503,12 +596,24 @@ function SessionPanel({
503
596
  </>
504
597
  )}
505
598
  <PanelList
506
- title="Functions"
599
+ title="Changed functions"
600
+ items={symbolLabels(changedFunctions)}
601
+ tone="edit"
602
+ />
603
+ <PanelList
604
+ title="Added functions"
507
605
  items={symbolLabels(addedFunctions)}
606
+ tone="add"
607
+ />
608
+ <PanelList
609
+ title="Changed variables"
610
+ items={symbolLabels(changedVariables)}
611
+ tone="edit"
508
612
  />
509
613
  <PanelList
510
- title="Variables"
614
+ title="Added variables"
511
615
  items={symbolLabels(addedVariables)}
616
+ tone="add"
512
617
  />
513
618
  {addedImports.length > 0 && (
514
619
  <PanelList title="Imports" items={importLabels(addedImports)} />
@@ -594,9 +699,11 @@ type HUDProps = {
594
699
  locked: boolean
595
700
  selectedId: string | null
596
701
  selectedTick?: number
702
+ inspectTick?: number
597
703
  selectedFolder?: string | null
598
704
  landAt: [number, number]
599
705
  aimedRelation: AimedRelation | null
706
+ aimedFileId?: string | null
600
707
  currentFolder: string
601
708
  intent: AgentIntent
602
709
  intents?: AgentIntent[]
@@ -605,7 +712,7 @@ type HUDProps = {
605
712
  onWorkflowAction: (
606
713
  sessionId: string,
607
714
  action: WorkflowAction,
608
- options?: { instruction?: string; step?: number },
715
+ options?: { instruction?: string; step?: number; stepByStep?: boolean },
609
716
  ) => void
610
717
  onNavigateDiff: (sessionId: string, diffId: string) => void
611
718
  onOpenMap: () => void
@@ -614,6 +721,9 @@ type HUDProps = {
614
721
  onToggleFollowLook: () => void
615
722
  importedBy: boolean
616
723
  onToggleImportedBy: () => void
724
+ changePathsOnly?: boolean
725
+ hasChangeSet?: boolean
726
+ onToggleChangePathsOnly?: () => void
617
727
  naming?: boolean
618
728
  namingIsland?: boolean
619
729
  onCommitIslandName?: (name: string) => void
@@ -634,6 +744,7 @@ type HUDProps = {
634
744
  onMapAddFile?: (folderPath: string) => void
635
745
  onMapAddFolder?: (folderPath: string) => void
636
746
  onInspectFile?: (fileId: string) => void
747
+ onInspectBlock?: (fileId: string) => void
637
748
  plannedIds?: string[]
638
749
  createdIds?: string[]
639
750
  deletedIds?: string[]
@@ -646,9 +757,11 @@ export function HUD({
646
757
  locked,
647
758
  selectedId,
648
759
  selectedTick = 0,
760
+ inspectTick = 0,
649
761
  selectedFolder = null,
650
762
  landAt,
651
763
  aimedRelation,
764
+ aimedFileId = null,
652
765
  currentFolder,
653
766
  intent,
654
767
  intents,
@@ -662,6 +775,9 @@ export function HUD({
662
775
  onToggleFollowLook,
663
776
  importedBy,
664
777
  onToggleImportedBy,
778
+ changePathsOnly = false,
779
+ hasChangeSet = false,
780
+ onToggleChangePathsOnly,
665
781
  naming = false,
666
782
  namingIsland = false,
667
783
  onCommitIslandName,
@@ -678,6 +794,7 @@ export function HUD({
678
794
  onMapAddFile,
679
795
  onMapAddFolder,
680
796
  onInspectFile,
797
+ onInspectBlock,
681
798
  plannedIds = [],
682
799
  createdIds = [],
683
800
  deletedIds = [],
@@ -716,6 +833,8 @@ export function HUD({
716
833
  const addedFunctions = intent.addedFunctions ?? []
717
834
  const addedVariables = intent.addedVariables ?? []
718
835
  const addedImports = intent.addedImports ?? []
836
+ const changedFunctions = intent.changedFunctions ?? []
837
+ const changedVariables = intent.changedVariables ?? []
719
838
  const selectedAddedFunctions = selected
720
839
  ? addedFunctions.filter((item) => item.file === selected.id)
721
840
  : []
@@ -725,6 +844,12 @@ export function HUD({
725
844
  const selectedAddedImports = selected
726
845
  ? addedImports.filter((item) => item.file === selected.id)
727
846
  : []
847
+ const selectedChangedFunctions = selected
848
+ ? changedFunctions.filter((item) => item.file === selected.id)
849
+ : []
850
+ const selectedChangedVariables = selected
851
+ ? changedVariables.filter((item) => item.file === selected.id)
852
+ : []
728
853
  const selectedClasses = selected
729
854
  ? selected.symbols.filter((symbol) => symbol.kind === 'class')
730
855
  : []
@@ -734,6 +859,26 @@ export function HUD({
734
859
  const selectedVariables = selected
735
860
  ? selected.symbols.filter((symbol) => symbol.kind === 'variable')
736
861
  : []
862
+ const functionChange = new Map<string, 'add' | 'edit'>([
863
+ ...selectedChangedFunctions.map(
864
+ (item) => [item.name, 'edit'] as const,
865
+ ),
866
+ ...selectedAddedFunctions.map((item) => [item.name, 'add'] as const),
867
+ ])
868
+ const variableChange = new Map<string, 'add' | 'edit'>([
869
+ ...selectedChangedVariables.map(
870
+ (item) => [item.name, 'edit'] as const,
871
+ ),
872
+ ...selectedAddedVariables.map((item) => [item.name, 'add'] as const),
873
+ ])
874
+ const extraAddedFunctions = extraAddedSymbols(
875
+ selectedFunctions,
876
+ selectedAddedFunctions,
877
+ )
878
+ const extraAddedVariables = extraAddedSymbols(
879
+ selectedVariables,
880
+ selectedAddedVariables,
881
+ )
737
882
  const selectedBlueprintFunctions = selected
738
883
  ? blueprintFunctions.filter((item) => item.file === selected.id)
739
884
  : []
@@ -781,13 +926,33 @@ export function HUD({
781
926
  }, [selectedId, selectedFolder])
782
927
 
783
928
  useEffect(() => {
929
+ if (mode === 'walk') return
784
930
  if (selectedId) setInfoVisible(true)
785
- }, [selectedId, selectedTick])
931
+ }, [mode, selectedId, selectedTick])
932
+
933
+ useEffect(() => {
934
+ if (inspectTick > 0) {
935
+ setInfoVisible(true)
936
+ setInfoMinimized(false)
937
+ }
938
+ }, [inspectTick])
786
939
 
787
940
  useEffect(() => {
788
941
  if (selectedFolder) setInfoVisible(true)
789
942
  }, [selectedFolder])
790
943
 
944
+ useEffect(() => {
945
+ if (!locked) return
946
+ setInfoVisible(false)
947
+ setInfoMinimized(false)
948
+ }, [locked])
949
+
950
+ const infoOpen = infoVisible && Boolean(selected || selectedFolderNode)
951
+
952
+ useEffect(() => {
953
+ if (infoOpen) document.exitPointerLock()
954
+ }, [infoOpen])
955
+
791
956
  useEffect(() => {
792
957
  const onKey = (event: KeyboardEvent) => {
793
958
  if (event.repeat || event.code !== 'KeyI') return
@@ -802,14 +967,22 @@ export function HUD({
802
967
  return
803
968
  }
804
969
  event.preventDefault()
805
- setInfoVisible((visible) => {
806
- if (!visible) setInfoMinimized(false)
807
- return !visible
808
- })
970
+ if (infoVisible) {
971
+ setInfoVisible(false)
972
+ setInfoMinimized(false)
973
+ return
974
+ }
975
+ const blockId = aimedFileId ?? selectedId
976
+ if (mode === 'walk') {
977
+ if (!blockId) return
978
+ onInspectBlock?.(blockId)
979
+ }
980
+ setInfoMinimized(false)
981
+ setInfoVisible(true)
809
982
  }
810
983
  window.addEventListener('keydown', onKey)
811
984
  return () => window.removeEventListener('keydown', onKey)
812
- }, [])
985
+ }, [aimedFileId, infoVisible, mode, onInspectBlock, selectedId])
813
986
 
814
987
  useEffect(() => {
815
988
  if (!mapping) return
@@ -879,7 +1052,7 @@ export function HUD({
879
1052
  , <kbd>Space</kbd> place a file, <kbd>B</kbd> place an island
880
1053
  </>
881
1054
  ) : null}
882
- , click a block for info.
1055
+ , double-click a block or press <kbd>I</kbd> for info.
883
1056
  </p>
884
1057
  </div>
885
1058
  </div>
@@ -987,13 +1160,45 @@ export function HUD({
987
1160
  Inspect file
988
1161
  </button>
989
1162
  )}
1163
+ {previewing &&
1164
+ (selectedChangedFunctions.length > 0 ||
1165
+ selectedAddedFunctions.length > 0 ||
1166
+ selectedChangedVariables.length > 0 ||
1167
+ selectedAddedVariables.length > 0 ||
1168
+ selectedAddedImports.length > 0) && (
1169
+ <>
1170
+ <div className="hud-section-title hud-section-title-edit">
1171
+ LLM changes
1172
+ </div>
1173
+ <PatchSymbolChanges
1174
+ title="Functions"
1175
+ added={selectedAddedFunctions}
1176
+ changed={selectedChangedFunctions}
1177
+ />
1178
+ <PatchSymbolChanges
1179
+ title="Vars"
1180
+ added={selectedAddedVariables}
1181
+ changed={selectedChangedVariables}
1182
+ />
1183
+ <PanelList
1184
+ title="Imports"
1185
+ items={importLabels(selectedAddedImports)}
1186
+ tone="add"
1187
+ />
1188
+ </>
1189
+ )}
990
1190
  {selectedClasses.length > 0 && (
991
1191
  <>
992
1192
  <div className="hud-section-title">Classes</div>
993
1193
  <ul>
994
1194
  {selectedClasses.map((symbol) => (
995
1195
  <li key={`class-${symbol.name}`}>
996
- <span className={symbol.intended ? 'hud-intended' : undefined}>
1196
+ <span
1197
+ className={
1198
+ symbolChangeClass(functionChange.get(symbol.name)) ??
1199
+ (symbol.intended ? 'hud-intended' : undefined)
1200
+ }
1201
+ >
997
1202
  {symbol.name}
998
1203
  </span>
999
1204
  </li>
@@ -1003,13 +1208,19 @@ export function HUD({
1003
1208
  )}
1004
1209
  <div className="hud-section-title">Functions</div>
1005
1210
  {selectedFunctions.length === 0 &&
1211
+ extraAddedFunctions.length === 0 &&
1006
1212
  selectedBlueprintFunctions.length === 0 ? (
1007
1213
  <p>No functions</p>
1008
1214
  ) : (
1009
1215
  <ul>
1010
1216
  {selectedFunctions.map((symbol) => (
1011
1217
  <li key={`fn-${symbol.name}`}>
1012
- <span className={symbol.intended ? 'hud-intended' : undefined}>
1218
+ <span
1219
+ className={
1220
+ symbolChangeClass(functionChange.get(symbol.name)) ??
1221
+ (symbol.intended ? 'hud-intended' : undefined)
1222
+ }
1223
+ >
1013
1224
  {symbol.name}
1014
1225
  </span>
1015
1226
  {canEditBlueprint && symbol.intended && (
@@ -1026,6 +1237,11 @@ export function HUD({
1026
1237
  )}
1027
1238
  </li>
1028
1239
  ))}
1240
+ {extraAddedFunctions.map((item) => (
1241
+ <li key={`fn-add-${item.name}`}>
1242
+ <span className="hud-file-add">{item.name}</span>
1243
+ </li>
1244
+ ))}
1029
1245
  </ul>
1030
1246
  )}
1031
1247
  {canEditBlueprint && onAddBlueprintFunction && (
@@ -1036,13 +1252,19 @@ export function HUD({
1036
1252
  )}
1037
1253
  <div className="hud-section-title">Vars</div>
1038
1254
  {selectedVariables.length === 0 &&
1255
+ extraAddedVariables.length === 0 &&
1039
1256
  selectedBlueprintVariables.length === 0 ? (
1040
1257
  <p>No vars</p>
1041
1258
  ) : (
1042
1259
  <ul>
1043
1260
  {selectedVariables.map((symbol) => (
1044
1261
  <li key={`var-${symbol.name}`}>
1045
- <span className={symbol.intended ? 'hud-intended' : undefined}>
1262
+ <span
1263
+ className={
1264
+ symbolChangeClass(variableChange.get(symbol.name)) ??
1265
+ (symbol.intended ? 'hud-intended' : undefined)
1266
+ }
1267
+ >
1046
1268
  {symbol.name}
1047
1269
  </span>
1048
1270
  {canEditBlueprint && symbol.intended && (
@@ -1059,6 +1281,11 @@ export function HUD({
1059
1281
  )}
1060
1282
  </li>
1061
1283
  ))}
1284
+ {extraAddedVariables.map((item) => (
1285
+ <li key={`var-add-${item.name}`}>
1286
+ <span className="hud-file-add">{item.name}</span>
1287
+ </li>
1288
+ ))}
1062
1289
  </ul>
1063
1290
  )}
1064
1291
  {canEditBlueprint && onAddBlueprintVariable && (
@@ -1067,22 +1294,6 @@ export function HUD({
1067
1294
  onAdd={(name) => onAddBlueprintVariable(selected.id, name)}
1068
1295
  />
1069
1296
  )}
1070
- {previewing && (
1071
- <>
1072
- <PanelList
1073
- title="Added functions"
1074
- items={symbolLabels(selectedAddedFunctions)}
1075
- />
1076
- <PanelList
1077
- title="Added variables"
1078
- items={symbolLabels(selectedAddedVariables)}
1079
- />
1080
- <PanelList
1081
- title="Added imports"
1082
- items={importLabels(selectedAddedImports)}
1083
- />
1084
- </>
1085
- )}
1086
1297
  <div className="hud-section-title">
1087
1298
  {importedBy ? 'Imported by' : 'Imports'}
1088
1299
  </div>
@@ -1201,7 +1412,7 @@ export function HUD({
1201
1412
  <ul>
1202
1413
  {folderFiles.map((file) => (
1203
1414
  <li key={file.id}>
1204
- <span>{file.path || file.id}</span>
1415
+ <span>{file.name}</span>
1205
1416
  {canInspectFile(file.id, file.userCreated) && (
1206
1417
  <button
1207
1418
  className="hud-item-inspect"
@@ -1277,6 +1488,13 @@ export function HUD({
1277
1488
  )}
1278
1489
  <span>Click a line to fly there</span>
1279
1490
  <span>Ctrl-click an island to walk</span>
1491
+ {hasChangeSet && (
1492
+ <span>
1493
+ {changePathsOnly
1494
+ ? 'C show all paths'
1495
+ : 'C show only changed paths'}
1496
+ </span>
1497
+ )}
1280
1498
  {selected?.userCreated && creatingBlueprint && (
1281
1499
  <span>Backspace delete</span>
1282
1500
  )}
@@ -1311,7 +1529,7 @@ export function HUD({
1311
1529
  {selected?.userCreated && creatingBlueprint && (
1312
1530
  <span>Backspace delete</span>
1313
1531
  )}
1314
- <span>Click a block for info</span>
1532
+ <span>Double-click a block for info</span>
1315
1533
  <span>Aim a line to fly</span>
1316
1534
  <span>{infoVisible ? 'I hide info' : 'I show info'}</span>
1317
1535
  {infoVisible && <span>↑↓ scroll info</span>}
@@ -1331,6 +1549,45 @@ export function HUD({
1331
1549
  )}
1332
1550
  </div>
1333
1551
  <div className="hud-icon-row">
1552
+ {mapping && hasChangeSet && onToggleChangePathsOnly && (
1553
+ <button
1554
+ className="hud-button hud-icon-button"
1555
+ data-active={changePathsOnly}
1556
+ aria-label={
1557
+ changePathsOnly
1558
+ ? 'Show all folder paths'
1559
+ : 'Show only changed paths'
1560
+ }
1561
+ aria-keyshortcuts="C"
1562
+ aria-pressed={changePathsOnly}
1563
+ type="button"
1564
+ onClick={onToggleChangePathsOnly}
1565
+ >
1566
+ <svg
1567
+ viewBox="0 0 24 24"
1568
+ width="18"
1569
+ height="18"
1570
+ fill="none"
1571
+ stroke="currentColor"
1572
+ strokeWidth="2"
1573
+ strokeLinecap="round"
1574
+ strokeLinejoin="round"
1575
+ aria-hidden="true"
1576
+ >
1577
+ <circle cx="12" cy="5" r="2.4" />
1578
+ <path d="M12 7.4v4.2" />
1579
+ <path d="M12 11.6 6.2 16" />
1580
+ <path d="M12 11.6 17.8 16" />
1581
+ <circle cx="6.2" cy="18" r="2.1" />
1582
+ <circle cx="17.8" cy="18" r="2.1" />
1583
+ </svg>
1584
+ <span className="hud-tooltip">
1585
+ {changePathsOnly
1586
+ ? 'C show all paths'
1587
+ : 'C show only changed paths'}
1588
+ </span>
1589
+ </button>
1590
+ )}
1334
1591
  {mapping && (
1335
1592
  <button
1336
1593
  className="hud-button hud-icon-button"
@@ -19,6 +19,7 @@ import {
19
19
  requestReplan,
20
20
  sendBlueprint,
21
21
  sessionIntent,
22
+ setStepByStep,
22
23
  stopSession,
23
24
  updateBlueprint,
24
25
  } from './scripts/session-store.mjs'
@@ -180,6 +181,7 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
180
181
  diffId?: string
181
182
  instruction?: string
182
183
  step?: number
184
+ stepByStep?: boolean
183
185
  userCreatedBlocks?: unknown[]
184
186
  userCreatedIslands?: unknown[]
185
187
  addedFunctions?: unknown[]
@@ -195,7 +197,8 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
195
197
  action !== 'blueprint_yes' &&
196
198
  action !== 'blueprint_no' &&
197
199
  action !== 'blueprint_send' &&
198
- action !== 'blueprint_update'
200
+ action !== 'blueprint_update' &&
201
+ action !== 'set_step_by_step'
199
202
  ) {
200
203
  sendJson(res, 400, { error: 'invalid workflow action' })
201
204
  return
@@ -257,6 +260,13 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
257
260
  addedVariables: body.addedVariables,
258
261
  addedImports: body.addedImports,
259
262
  })
263
+ } else if (action === 'set_step_by_step') {
264
+ if (typeof body.stepByStep !== 'boolean') {
265
+ sendJson(res, 400, { error: 'stepByStep is required' })
266
+ return
267
+ }
268
+ setStepByStep(dataDir, body.sessionId, body.stepByStep, targetRoot)
269
+ rescanTarget('after changing step-by-step mode')
260
270
  } else {
261
271
  stopSession(dataDir, body.sessionId, targetRoot)
262
272
  rescanTarget('after stopping session')
package/bin/session.mjs CHANGED
@@ -125,7 +125,9 @@ export async function reportPlan(args) {
125
125
  stepTitles: stepsParsed.values,
126
126
  })
127
127
  console.log(
128
- `VISUAL_CODER_PLAN_READY Reported ${manifest.steps.length} plan step(s) for session ${sessionId}. Wait for the user to invoke step ${manifest.currentStep}.`,
128
+ manifest.phase === 'working'
129
+ ? `VISUAL_CODER_PLAN_READY Reported ${manifest.steps.length} plan step(s) for session ${sessionId}. Step by step is off, so step ${manifest.currentStep} is already invoked. Implement it, then wait again.`
130
+ : `VISUAL_CODER_PLAN_READY Reported ${manifest.steps.length} plan step(s) for session ${sessionId}. Wait for the user to invoke step ${manifest.currentStep}.`,
129
131
  )
130
132
  }
131
133
 
@@ -148,16 +150,21 @@ export async function waitForApproval(args) {
148
150
  console.error(`No workflow session found for ${sessionId}`)
149
151
  process.exit(1)
150
152
  }
153
+ store.autoAdvance(config.dataDir, sessionId, config.targetRoot)
154
+ const afterAdvance = store.readManifest(config.dataDir, sessionId) ?? initial
151
155
  console.log(
152
- initial.phase === 'plan_ready'
153
- ? `Waiting for the user to invoke step ${initial.currentStep}...`
154
- : initial.phase === 'review' && initialDiff
155
- ? `Waiting for the user to run the next step after ${initialDiff.id}...`
156
+ afterAdvance.phase === 'plan_ready'
157
+ ? `Waiting for the user to invoke step ${afterAdvance.currentStep}...`
158
+ : afterAdvance.phase === 'review' && afterAdvance.diffs?.at(-1)
159
+ ? afterAdvance.stepByStep === false
160
+ ? `Waiting for the finish step after ${afterAdvance.diffs.at(-1).id}...`
161
+ : `Waiting for the user to run the next step after ${afterAdvance.diffs.at(-1).id}...`
156
162
  : `Waiting for the visual workflow in session ${sessionId}...`,
157
163
  )
158
164
 
159
165
  while (Date.now() - started < timeoutMs) {
160
166
  store.touchSessionConnection(config.dataDir, sessionId)
167
+ store.autoAdvance(config.dataDir, sessionId, config.targetRoot)
161
168
  const manifest = store.readManifest(config.dataDir, sessionId)
162
169
  if (!manifest) {
163
170
  console.error(
@@ -249,7 +256,12 @@ export async function proposePatch(args) {
249
256
  patchText,
250
257
  })
251
258
 
259
+ const last = entry.step >= manifest.steps.length
252
260
  console.log(
253
- `VISUAL_CODER_STEP_READY Published diff ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Wait for Continue or an alternative instruction.`,
261
+ manifest.phase === 'working'
262
+ ? `VISUAL_CODER_STEP_READY Published diff ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Step by step is off, so the next step is already invoked. Wait again.`
263
+ : last
264
+ ? `VISUAL_CODER_STEP_READY Published diff ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Walk the diffs, then Complete to finish.`
265
+ : `VISUAL_CODER_STEP_READY Published diff ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Wait for Continue or an alternative instruction.`,
254
266
  )
255
267
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jkwd/inbase",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "A first-person 3D map of a codebase, with a visual coding workflow for Cursor.",
5
5
  "repository": {
6
6
  "type": "git",