@jkwd/inbase 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/apps/explorer/scripts/patch-lib.d.ts +2 -0
- package/apps/explorer/scripts/patch-lib.mjs +2 -0
- package/apps/explorer/scripts/session-store.d.ts +45 -0
- package/apps/explorer/scripts/session-store.mjs +281 -5
- package/apps/explorer/src/App.tsx +114 -4
- package/apps/explorer/src/agentIntent.ts +76 -1
- package/apps/explorer/src/index.css +65 -0
- package/apps/explorer/src/scene/FileBlock.tsx +27 -0
- package/apps/explorer/src/scene/FolderArea.tsx +21 -0
- package/apps/explorer/src/scene/MapView.tsx +1 -11
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +16 -3
- package/apps/explorer/src/scene/World.tsx +22 -4
- package/apps/explorer/src/types.ts +16 -0
- package/apps/explorer/src/ui/EyeIcon.tsx +26 -0
- package/apps/explorer/src/ui/HUD.tsx +377 -26
- package/apps/explorer/src/ui/MapContextMenu.tsx +18 -1
- package/apps/explorer/src/userCreated.ts +97 -0
- package/apps/explorer/vite.config.ts +18 -1
- package/bin/session.mjs +41 -11
- package/package.json +1 -1
- package/skill/commands/inbase.md +1 -1
- package/skill/inbase/SKILL.md +24 -23
|
@@ -10,15 +10,19 @@ export type MapContextMenuState = {
|
|
|
10
10
|
|
|
11
11
|
type MapContextMenuProps = {
|
|
12
12
|
menu: MapContextMenuState | null
|
|
13
|
+
pointed?: boolean
|
|
13
14
|
onAddFile: (folder: string) => void
|
|
14
15
|
onAddFolder: (folder: string) => void
|
|
16
|
+
onPointToFolder?: (folder: string) => void
|
|
15
17
|
onClose: () => void
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export function MapContextMenu({
|
|
19
21
|
menu,
|
|
22
|
+
pointed = false,
|
|
20
23
|
onAddFile,
|
|
21
24
|
onAddFolder,
|
|
25
|
+
onPointToFolder,
|
|
22
26
|
onClose,
|
|
23
27
|
}: MapContextMenuProps) {
|
|
24
28
|
useEffect(() => {
|
|
@@ -48,7 +52,7 @@ export function MapContextMenu({
|
|
|
48
52
|
|
|
49
53
|
const pad = 8
|
|
50
54
|
const width = 176
|
|
51
|
-
const height = 84
|
|
55
|
+
const height = onPointToFolder ? 126 : 84
|
|
52
56
|
const left = Math.min(
|
|
53
57
|
Math.max(pad, menu.x),
|
|
54
58
|
window.innerWidth - width - pad,
|
|
@@ -85,6 +89,19 @@ export function MapContextMenu({
|
|
|
85
89
|
>
|
|
86
90
|
Add folder
|
|
87
91
|
</button>
|
|
92
|
+
{onPointToFolder && (
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
95
|
+
role="menuitem"
|
|
96
|
+
aria-pressed={pointed}
|
|
97
|
+
onClick={() => {
|
|
98
|
+
onPointToFolder(menu.folder)
|
|
99
|
+
onClose()
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
{pointed ? 'Stop pointing' : 'Point to folder'}
|
|
103
|
+
</button>
|
|
104
|
+
)}
|
|
88
105
|
</div>,
|
|
89
106
|
document.body,
|
|
90
107
|
)
|
|
@@ -3,6 +3,8 @@ import { folderOfFile, folderParent } from './layout'
|
|
|
3
3
|
import type {
|
|
4
4
|
BlueprintNote,
|
|
5
5
|
BlueprintNoteKind,
|
|
6
|
+
BlueprintPointer,
|
|
7
|
+
BlueprintPointerKind,
|
|
6
8
|
CodebaseGraph,
|
|
7
9
|
FileNode,
|
|
8
10
|
PatchImportAddition,
|
|
@@ -437,6 +439,101 @@ export function dropBlueprintSymbolNote(
|
|
|
437
439
|
)
|
|
438
440
|
}
|
|
439
441
|
|
|
442
|
+
export function blueprintPointerKey(
|
|
443
|
+
pointer: Pick<BlueprintPointer, 'kind' | 'path' | 'name'>,
|
|
444
|
+
) {
|
|
445
|
+
return pointer.kind === 'file' || pointer.kind === 'folder'
|
|
446
|
+
? `${pointer.kind}:${pointer.path}`
|
|
447
|
+
: `${pointer.kind}:${pointer.path}:${pointer.name ?? ''}`
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function parseBlueprintPointer(value: unknown): BlueprintPointer | null {
|
|
451
|
+
if (!value || typeof value !== 'object') return null
|
|
452
|
+
const item = value as Partial<BlueprintPointer>
|
|
453
|
+
const path = typeof item.path === 'string' ? item.path.trim() : ''
|
|
454
|
+
if (!path) return null
|
|
455
|
+
if (item.kind === 'file' || item.kind === 'folder') {
|
|
456
|
+
return { kind: item.kind, path }
|
|
457
|
+
}
|
|
458
|
+
if (item.kind !== 'function' && item.kind !== 'variable') return null
|
|
459
|
+
const name = typeof item.name === 'string' ? item.name.trim() : ''
|
|
460
|
+
if (!name) return null
|
|
461
|
+
return { kind: item.kind, path, name }
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function parseBlueprintPointers(value: unknown): BlueprintPointer[] {
|
|
465
|
+
if (!Array.isArray(value)) return []
|
|
466
|
+
const seen = new Set<string>()
|
|
467
|
+
const pointers: BlueprintPointer[] = []
|
|
468
|
+
for (const item of value) {
|
|
469
|
+
const parsed = parseBlueprintPointer(item)
|
|
470
|
+
if (!parsed) continue
|
|
471
|
+
const key = blueprintPointerKey(parsed)
|
|
472
|
+
if (seen.has(key)) continue
|
|
473
|
+
seen.add(key)
|
|
474
|
+
pointers.push(parsed)
|
|
475
|
+
}
|
|
476
|
+
return pointers
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export function findBlueprintPointer(
|
|
480
|
+
pointers: BlueprintPointer[],
|
|
481
|
+
kind: BlueprintPointerKind,
|
|
482
|
+
path: string,
|
|
483
|
+
name?: string,
|
|
484
|
+
) {
|
|
485
|
+
return pointers.some((item) =>
|
|
486
|
+
kind === 'file' || kind === 'folder'
|
|
487
|
+
? item.kind === kind && item.path === path
|
|
488
|
+
: item.kind === kind && item.path === path && item.name === name,
|
|
489
|
+
)
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export function toggleBlueprintPointer(
|
|
493
|
+
pointers: BlueprintPointer[],
|
|
494
|
+
next: {
|
|
495
|
+
kind: BlueprintPointerKind
|
|
496
|
+
path: string
|
|
497
|
+
name?: string
|
|
498
|
+
},
|
|
499
|
+
): BlueprintPointer[] {
|
|
500
|
+
const path = next.path.trim()
|
|
501
|
+
if (!path || path.startsWith('draft:')) return pointers
|
|
502
|
+
const key = blueprintPointerKey({ ...next, path })
|
|
503
|
+
const without = pointers.filter((item) => blueprintPointerKey(item) !== key)
|
|
504
|
+
if (without.length !== pointers.length) return without
|
|
505
|
+
if (next.kind === 'file' || next.kind === 'folder') {
|
|
506
|
+
return [...without, { kind: next.kind, path }]
|
|
507
|
+
}
|
|
508
|
+
const name = (next.name ?? '').trim()
|
|
509
|
+
if (!name) return without
|
|
510
|
+
return [...without, { kind: next.kind, path, name }]
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export function dropBlueprintFilePointers(
|
|
514
|
+
pointers: BlueprintPointer[],
|
|
515
|
+
fileIds: Iterable<string>,
|
|
516
|
+
folderPaths: Iterable<string> = [],
|
|
517
|
+
) {
|
|
518
|
+
const files = new Set(fileIds)
|
|
519
|
+
const folders = new Set(folderPaths)
|
|
520
|
+
return pointers.filter((item) =>
|
|
521
|
+
item.kind === 'folder' ? !folders.has(item.path) : !files.has(item.path),
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export function dropBlueprintSymbolPointer(
|
|
526
|
+
pointers: BlueprintPointer[],
|
|
527
|
+
path: string,
|
|
528
|
+
kind: 'function' | 'variable',
|
|
529
|
+
name: string,
|
|
530
|
+
) {
|
|
531
|
+
return pointers.filter(
|
|
532
|
+
(item) =>
|
|
533
|
+
!(item.kind === kind && item.path === path && item.name === name),
|
|
534
|
+
)
|
|
535
|
+
}
|
|
536
|
+
|
|
440
537
|
export function parseBlueprintImport(
|
|
441
538
|
raw: string,
|
|
442
539
|
file: string,
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
sendBlueprint,
|
|
24
24
|
sessionIntent,
|
|
25
25
|
setInitialInstruction,
|
|
26
|
+
addContextFiles,
|
|
27
|
+
removeContextFile,
|
|
26
28
|
setStepByStep,
|
|
27
29
|
setupSession,
|
|
28
30
|
focusSession,
|
|
@@ -112,6 +114,7 @@ function blueprintIntentFields() {
|
|
|
112
114
|
blueprintVariables: blueprint.addedVariables,
|
|
113
115
|
blueprintImports: blueprint.addedImports,
|
|
114
116
|
blueprintNotes: blueprint.notes,
|
|
117
|
+
blueprintPointers: blueprint.pointers,
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
|
|
@@ -265,6 +268,9 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
265
268
|
addedVariables?: unknown[]
|
|
266
269
|
addedImports?: unknown[]
|
|
267
270
|
notes?: unknown[]
|
|
271
|
+
pointers?: unknown[]
|
|
272
|
+
files?: unknown[]
|
|
273
|
+
fileId?: string
|
|
268
274
|
}
|
|
269
275
|
const action = body.action
|
|
270
276
|
const blueprintActions = new Set([
|
|
@@ -288,6 +294,8 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
288
294
|
action !== 'focus' &&
|
|
289
295
|
action !== 'set_step_by_step' &&
|
|
290
296
|
action !== 'set_initial_instruction' &&
|
|
297
|
+
action !== 'add_context_files' &&
|
|
298
|
+
action !== 'remove_context_file' &&
|
|
291
299
|
action !== 'setup_session'
|
|
292
300
|
) {
|
|
293
301
|
sendJson(res, 400, { error: 'invalid workflow action' })
|
|
@@ -342,7 +350,6 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
342
350
|
body.instruction ?? '',
|
|
343
351
|
targetRoot,
|
|
344
352
|
)
|
|
345
|
-
rescanTarget('after withdrawing a patch')
|
|
346
353
|
} else if (action === 'blueprint_yes') {
|
|
347
354
|
answerBlueprint(dataDir, body.sessionId, true)
|
|
348
355
|
} else if (action === 'blueprint_no') {
|
|
@@ -355,6 +362,7 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
355
362
|
addedVariables: body.addedVariables,
|
|
356
363
|
addedImports: body.addedImports,
|
|
357
364
|
notes: body.notes,
|
|
365
|
+
pointers: body.pointers,
|
|
358
366
|
})
|
|
359
367
|
} else if (action === 'blueprint_clear') {
|
|
360
368
|
clearBlueprint(dataDir)
|
|
@@ -370,6 +378,7 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
370
378
|
addedVariables: body.addedVariables,
|
|
371
379
|
addedImports: body.addedImports,
|
|
372
380
|
notes: body.notes,
|
|
381
|
+
pointers: body.pointers,
|
|
373
382
|
})
|
|
374
383
|
} else if (action === 'setup_session') {
|
|
375
384
|
const manifest = setupSession(dataDir, {
|
|
@@ -381,6 +390,14 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
|
|
|
381
390
|
return
|
|
382
391
|
} else if (action === 'set_initial_instruction') {
|
|
383
392
|
setInitialInstruction(dataDir, body.sessionId, body.instruction ?? '')
|
|
393
|
+
} else if (action === 'add_context_files') {
|
|
394
|
+
addContextFiles(dataDir, body.sessionId, body.files ?? [])
|
|
395
|
+
} else if (action === 'remove_context_file') {
|
|
396
|
+
if (!body.fileId) {
|
|
397
|
+
sendJson(res, 400, { error: 'fileId is required' })
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
removeContextFile(dataDir, body.sessionId, body.fileId)
|
|
384
401
|
} else if (action === 'focus') {
|
|
385
402
|
focusSession(dataDir, body.sessionId)
|
|
386
403
|
} else if (action === 'set_step_by_step') {
|
package/bin/session.mjs
CHANGED
|
@@ -122,21 +122,37 @@ function emitApprovalHandshake(store, dataDir, sessionId, manifest, initialDiff)
|
|
|
122
122
|
if (manifest.phase === 'working') {
|
|
123
123
|
const next = manifest.steps.find((step) => step.index === manifest.currentStep)
|
|
124
124
|
const title = next?.title
|
|
125
|
+
const guidance =
|
|
126
|
+
typeof manifest.pendingInstruction === 'string'
|
|
127
|
+
? manifest.pendingInstruction.trim()
|
|
128
|
+
: ''
|
|
129
|
+
const updating = Boolean(guidance)
|
|
125
130
|
signalAck(
|
|
126
131
|
store,
|
|
127
132
|
dataDir,
|
|
128
133
|
sessionId,
|
|
129
134
|
'execute',
|
|
130
|
-
|
|
131
|
-
?
|
|
132
|
-
:
|
|
135
|
+
updating
|
|
136
|
+
? 'a new instruction'
|
|
137
|
+
: title
|
|
138
|
+
? `step ${manifest.currentStep} — ${title}`
|
|
139
|
+
: `step ${manifest.currentStep}`,
|
|
133
140
|
)
|
|
141
|
+
const instruction = updating
|
|
142
|
+
? `\nVISUAL_CODER_INSTRUCTION_START\n${guidance}\nVISUAL_CODER_INSTRUCTION_END`
|
|
143
|
+
: ''
|
|
134
144
|
const continuing = (manifest.diffs?.length ?? 0) > 0
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
if (updating) {
|
|
146
|
+
console.log(
|
|
147
|
+
`VISUAL_CODER_EXECUTE Update the current proposal for step ${manifest.currentStep}${title ? `: ${title}` : ''}. Live files already contain that proposal — do not reset them. Follow the instruction between VISUAL_CODER_INSTRUCTION_START and END, edit those live files, then inbase propose-patch --session ${sessionId} with no patch file. Do not report a new plan.${instruction}`,
|
|
148
|
+
)
|
|
149
|
+
} else {
|
|
150
|
+
console.log(
|
|
151
|
+
continuing
|
|
152
|
+
? `VISUAL_CODER_EXECUTE Step ${manifest.currentStep} is invoked${title ? `: ${title}` : ''}. Continue immediately: edit live files for this step only, then inbase propose-patch --session ${sessionId} with no patch file. Do not explore, re-plan, or run wait-for-blueprint.`
|
|
153
|
+
: `VISUAL_CODER_EXECUTE Step ${manifest.currentStep} is invoked${title ? `: ${title}` : ''}. Re-read the shared blueprint.json before implementing; the user can place files and islands at any time. Edit the live project files for this step only (Write, StrReplace, Delete). Then record the step with inbase propose-patch --session ${sessionId} — no patch file. Inbase diffs those edits against the invoke snapshot and stores the patch. Do not write a unified diff yourself.`,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
140
156
|
process.exit(0)
|
|
141
157
|
}
|
|
142
158
|
if (manifest.phase === 'replanning') {
|
|
@@ -145,13 +161,13 @@ function emitApprovalHandshake(store, dataDir, sessionId, manifest, initialDiff)
|
|
|
145
161
|
dataDir,
|
|
146
162
|
sessionId,
|
|
147
163
|
'replan',
|
|
148
|
-
`revise the
|
|
164
|
+
`revise the current proposal for step ${manifest.currentStep}`,
|
|
149
165
|
)
|
|
150
166
|
const instruction = manifest.pendingInstruction
|
|
151
167
|
? `\nVISUAL_CODER_INSTRUCTION_START\n${manifest.pendingInstruction}\nVISUAL_CODER_INSTRUCTION_END`
|
|
152
168
|
: ''
|
|
153
169
|
console.log(
|
|
154
|
-
`VISUAL_CODER_REPLAN
|
|
170
|
+
`VISUAL_CODER_REPLAN Live files still contain the current proposal for step ${manifest.currentStep}. Do not reset them. Follow the instruction between VISUAL_CODER_INSTRUCTION_START and END, edit those live files, then inbase propose-patch. Do not report a new plan.${instruction}`,
|
|
155
171
|
)
|
|
156
172
|
process.exit(4)
|
|
157
173
|
}
|
|
@@ -179,7 +195,7 @@ export async function attachSession(args) {
|
|
|
179
195
|
console.log(`VISUAL_CODER_SESSION ${manifest.sessionId}`)
|
|
180
196
|
printAck('attached', manifest.name || manifest.sessionId)
|
|
181
197
|
console.log(
|
|
182
|
-
`VISUAL_CODER_ATTACHED Attached to the next waiting visualizer session ${manifest.name || manifest.sessionId} (${manifest.phase}). Use --session ${manifest.sessionId} for every later command. Run inbase wait-for-blueprint --session ${manifest.sessionId} to read the optional blueprint and
|
|
198
|
+
`VISUAL_CODER_ATTACHED Attached to the next waiting visualizer session ${manifest.name || manifest.sessionId} (${manifest.phase}). Use --session ${manifest.sessionId} for every later command. Run inbase wait-for-blueprint --session ${manifest.sessionId} to read the optional blueprint, instruction, and attached files; it does not wait.`,
|
|
183
199
|
)
|
|
184
200
|
}
|
|
185
201
|
|
|
@@ -243,6 +259,20 @@ export async function waitForBlueprint(args) {
|
|
|
243
259
|
console.log(instruction)
|
|
244
260
|
console.log('VISUAL_CODER_INSTRUCTION_END')
|
|
245
261
|
}
|
|
262
|
+
const attached = store.contextFileHandshake(config.dataDir, sessionId)
|
|
263
|
+
if (attached.files.length > 0) {
|
|
264
|
+
console.log(
|
|
265
|
+
'Honor the user\'s attached context files. Read each path with your file tools before planning. They are session-only attachments, not project files to create. Use any printed VISUAL_CODER_CONTEXT_FILE contents directly.',
|
|
266
|
+
)
|
|
267
|
+
console.log('VISUAL_CODER_CONTEXT_FILES_START')
|
|
268
|
+
console.log(JSON.stringify(attached.files, null, 2))
|
|
269
|
+
console.log('VISUAL_CODER_CONTEXT_FILES_END')
|
|
270
|
+
for (const file of attached.texts) {
|
|
271
|
+
console.log(`VISUAL_CODER_CONTEXT_FILE_START ${file.name}`)
|
|
272
|
+
console.log(file.content)
|
|
273
|
+
console.log('VISUAL_CODER_CONTEXT_FILE_END')
|
|
274
|
+
}
|
|
275
|
+
}
|
|
246
276
|
process.exit(0)
|
|
247
277
|
}
|
|
248
278
|
|
package/package.json
CHANGED
package/skill/commands/inbase.md
CHANGED
|
@@ -14,4 +14,4 @@ npx inbase attach
|
|
|
14
14
|
|
|
15
15
|
2. Read `VISUAL_CODER_SESSION` from the output. That id is the session to use for every later `inbase` command.
|
|
16
16
|
|
|
17
|
-
3. Continue the Inbase visual edits skill from `wait-for-blueprint` onward with that `--session` id. `/inbase` already started the session. `wait-for-blueprint` only reads the optional blueprint and
|
|
17
|
+
3. Continue the Inbase visual edits skill from `wait-for-blueprint` onward with that `--session` id. `/inbase` already started the session. `wait-for-blueprint` only reads the optional blueprint, instruction, and attached files; it does not wait.
|
package/skill/inbase/SKILL.md
CHANGED
|
@@ -43,8 +43,8 @@ over the recorded diffs.
|
|
|
43
43
|
live project files with Write, StrReplace, and Delete for that step only. Then
|
|
44
44
|
run `inbase propose-patch` with no patch file. Inbase diffs the working tree
|
|
45
45
|
against the snapshot taken at invoke and stores that patch. A later instruction
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
updates that live proposal; edit those files, then propose-patch again. Wait
|
|
47
|
+
for **Accept proposal** before the next step. Do not write a unified diff yourself.
|
|
48
48
|
|
|
49
49
|
The visualizer stores immutable diffs under
|
|
50
50
|
`.inbase/diff-sessions/<session-id>/diffs/`. Inbase must already be running
|
|
@@ -85,7 +85,7 @@ new plan.
|
|
|
85
85
|
## Required sequence
|
|
86
86
|
|
|
87
87
|
1. **Read the current layout**. `/inbase` already started the session. Run
|
|
88
|
-
this once to load the optional blueprint and
|
|
88
|
+
this once to load the optional blueprint, instruction, and attached files — it returns
|
|
89
89
|
immediately. Do not wait for the user to send a blueprint. Then report a
|
|
90
90
|
plan.
|
|
91
91
|
|
|
@@ -98,7 +98,11 @@ npx inbase wait-for-blueprint --session "<session-id>"
|
|
|
98
98
|
keep placing at any time.
|
|
99
99
|
If `wait-for-blueprint` prints `VISUAL_CODER_INSTRUCTION_START` /
|
|
100
100
|
`VISUAL_CODER_INSTRUCTION_END`, that text is the user's request for this
|
|
101
|
-
session.
|
|
101
|
+
session. If it prints `VISUAL_CODER_CONTEXT_FILES_START` /
|
|
102
|
+
`VISUAL_CODER_CONTEXT_FILES_END`, those are session-only files the user
|
|
103
|
+
dropped as initial context. Read each `path` (and any printed
|
|
104
|
+
`VISUAL_CODER_CONTEXT_FILE` contents). They are not project files to create.
|
|
105
|
+
Plan from that instruction, attached files, and the blueprint together. The
|
|
102
106
|
instruction does not override an enabled blueprint; if they conflict,
|
|
103
107
|
ask the user.
|
|
104
108
|
3. Read the handshake output between `VISUAL_CODER_BLUEPRINT_START` and
|
|
@@ -176,11 +180,15 @@ npx inbase wait-for-approval --session "<session-id>"
|
|
|
176
180
|
12. Read the wait command output. Reply in chat with the `VISUAL_CODER_ACK`
|
|
177
181
|
line first, then:
|
|
178
182
|
|
|
179
|
-
- Exit `0` (`VISUAL_CODER_ACK execute` / `VISUAL_CODER_EXECUTE`):
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
- Exit `0` (`VISUAL_CODER_ACK execute` / `VISUAL_CODER_EXECUTE`): follow
|
|
184
|
+
the printed `VISUAL_CODER_EXECUTE` line. If it says **Update the current
|
|
185
|
+
proposal**, edit those live files, record with `inbase propose-patch` (no
|
|
186
|
+
patch file), then wait again for **Accept proposal**. Do not start the
|
|
187
|
+
next step and do not report a new plan. Otherwise the highlighted step
|
|
188
|
+
was invoked: implement that step now — do not explore, re-plan, or run
|
|
189
|
+
`wait-for-blueprint`. Re-read the shared `blueprint.json` if you need
|
|
190
|
+
placed files. Edit live files for that step only, record with
|
|
191
|
+
`inbase propose-patch` (no patch file), then wait again.
|
|
184
192
|
- Exit `6` (`VISUAL_CODER_ACK blueprint` / `VISUAL_CODER_BLUEPRINT`): the
|
|
185
193
|
shared blueprint changed. Follow the latest files, islands, functions,
|
|
186
194
|
variables, and imports. Do not omit, rename, relocate, or replace them.
|
|
@@ -191,19 +199,12 @@ npx inbase wait-for-approval --session "<session-id>"
|
|
|
191
199
|
stored session diffs. The shared blueprint remains. Optionally run
|
|
192
200
|
`--clear` if anything remains, tell the user the feature is done, and
|
|
193
201
|
**stop**. Do not propose another patch.
|
|
194
|
-
- Exit `4` (`VISUAL_CODER_ACK replan` / `VISUAL_CODER_REPLAN`):
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
`
|
|
199
|
-
|
|
200
|
-
`addedImports`). The blueprint stays leading. If the new instruction would
|
|
201
|
-
differ from it, ask the user before replacing the plan. Read
|
|
202
|
-
`user-context.json` (follow the viewpoint only if `followLook` is true),
|
|
203
|
-
replace the plan from the current step onward using `inbase report-plan`,
|
|
204
|
-
then wait for the next `VISUAL_CODER_EXECUTE` before editing again. The
|
|
205
|
-
replacement edits must sit on the accepted live files, not the withdrawn
|
|
206
|
-
proposal.
|
|
202
|
+
- Exit `4` (`VISUAL_CODER_ACK replan` / `VISUAL_CODER_REPLAN`): live files
|
|
203
|
+
still contain the current proposal. Do not reset them and do not report a
|
|
204
|
+
new plan. Follow the text between `VISUAL_CODER_INSTRUCTION_START` and
|
|
205
|
+
`VISUAL_CODER_INSTRUCTION_END`, edit those live files, then
|
|
206
|
+
`inbase propose-patch`. Wait for **Accept proposal**. Do not start the
|
|
207
|
+
next step.
|
|
207
208
|
- Exit `2` (`VISUAL_CODER_ACK stopped` / `VISUAL_CODER_STOPPED`) or `3`
|
|
208
209
|
(`VISUAL_CODER_ACK timeout`): make no further project changes.
|
|
209
210
|
|
|
@@ -220,7 +221,7 @@ npx inbase propose-patch --session "<session-id>" --clear
|
|
|
220
221
|
from **Setup LLM session** in the map
|
|
221
222
|
- Edit files on a direct chat request; reply with the `/skipinbase` line and stop
|
|
222
223
|
- Invent a session id for `/inbase`; run `npx inbase attach` with no `--session`
|
|
223
|
-
- Skip `inbase wait-for-blueprint`; it returns immediately and provides the optional blueprint and
|
|
224
|
+
- Skip `inbase wait-for-blueprint`; it returns immediately and provides the optional blueprint, instruction, and attached files
|
|
224
225
|
- Treat the chat request, viewpoint, or your own plan as overriding an enabled blueprint
|
|
225
226
|
- Skip, rename, relocate, or replace the shared `blueprint.json` files, islands, functions, variables, or imports when `enabled` is true
|
|
226
227
|
- Silently differ from the blueprint; ask the user first
|