@jkwd/inbase 0.1.0
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 +76 -0
- package/apps/explorer/index.html +12 -0
- package/apps/explorer/package.json +28 -0
- package/apps/explorer/scripts/js-source.mjs +188 -0
- package/apps/explorer/scripts/patch-lib.d.ts +115 -0
- package/apps/explorer/scripts/patch-lib.mjs +472 -0
- package/apps/explorer/scripts/scan-target.mjs +188 -0
- package/apps/explorer/scripts/session-store.d.ts +156 -0
- package/apps/explorer/scripts/session-store.mjs +809 -0
- package/apps/explorer/scripts/target-config.d.ts +8 -0
- package/apps/explorer/scripts/target-config.mjs +42 -0
- package/apps/explorer/src/App.tsx +941 -0
- package/apps/explorer/src/agentIntent.ts +182 -0
- package/apps/explorer/src/codebase.ts +15 -0
- package/apps/explorer/src/index.css +632 -0
- package/apps/explorer/src/layout.ts +508 -0
- package/apps/explorer/src/main.tsx +16 -0
- package/apps/explorer/src/scene/BlockPlacer.tsx +87 -0
- package/apps/explorer/src/scene/Bridge.tsx +290 -0
- package/apps/explorer/src/scene/FileBlock.tsx +256 -0
- package/apps/explorer/src/scene/FolderArea.tsx +96 -0
- package/apps/explorer/src/scene/IslandPlacer.tsx +40 -0
- package/apps/explorer/src/scene/MapSelectBorder.tsx +57 -0
- package/apps/explorer/src/scene/MapView.tsx +247 -0
- package/apps/explorer/src/scene/Player.tsx +245 -0
- package/apps/explorer/src/scene/RelationLines.tsx +223 -0
- package/apps/explorer/src/scene/SelectionController.tsx +89 -0
- package/apps/explorer/src/scene/UserContextTracker.tsx +152 -0
- package/apps/explorer/src/scene/World.tsx +323 -0
- package/apps/explorer/src/theme.ts +111 -0
- package/apps/explorer/src/types.ts +245 -0
- package/apps/explorer/src/ui/CanvasErrorBoundary.tsx +38 -0
- package/apps/explorer/src/ui/HUD.tsx +1090 -0
- package/apps/explorer/src/ui/NameInput.tsx +45 -0
- package/apps/explorer/src/userContext.ts +73 -0
- package/apps/explorer/src/userCreated.ts +354 -0
- package/apps/explorer/src/vite-env.d.ts +1 -0
- package/apps/explorer/tsconfig.json +21 -0
- package/apps/explorer/vite.config.ts +295 -0
- package/bin/inbase.mjs +170 -0
- package/bin/project.mjs +94 -0
- package/bin/session.mjs +241 -0
- package/package.json +63 -0
- package/skill/inbase/SKILL.md +167 -0
package/bin/session.mjs
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
import { explorerRoot, takeFlagValue, takeFlagValues } from './project.mjs'
|
|
5
|
+
|
|
6
|
+
async function loadExplorer() {
|
|
7
|
+
const storePath = pathToFileURL(
|
|
8
|
+
path.join(explorerRoot, 'scripts/session-store.mjs'),
|
|
9
|
+
).href
|
|
10
|
+
const patchPath = pathToFileURL(
|
|
11
|
+
path.join(explorerRoot, 'scripts/patch-lib.mjs'),
|
|
12
|
+
).href
|
|
13
|
+
const configPath = pathToFileURL(
|
|
14
|
+
path.join(explorerRoot, 'scripts/target-config.mjs'),
|
|
15
|
+
).href
|
|
16
|
+
const [store, patchLib, config] = await Promise.all([
|
|
17
|
+
import(storePath),
|
|
18
|
+
import(patchPath),
|
|
19
|
+
import(configPath),
|
|
20
|
+
])
|
|
21
|
+
return { store, patchLib, config }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function usage(name, example) {
|
|
25
|
+
console.error(`Usage: inbase ${name} ${example}`)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function startSession(args) {
|
|
30
|
+
const { store, config } = await loadExplorer()
|
|
31
|
+
const sessionId = takeFlagValue(args, '--session')
|
|
32
|
+
const feature = takeFlagValue(args, '--feature')
|
|
33
|
+
if (!sessionId) usage('start-session', '--session <cursor-chat-id> [--feature "name"]')
|
|
34
|
+
|
|
35
|
+
const manifest = store.startSession(config.dataDir, { sessionId, feature })
|
|
36
|
+
if (manifest.phase === 'blueprint_ask' || manifest.phase === 'blueprint') {
|
|
37
|
+
console.log(
|
|
38
|
+
`VISUAL_CODER_BLUEPRINT_WAIT Session ${sessionId} is visible in the visualizer (${manifest.phase}). Wait with inbase wait-for-blueprint before drafting the plan.`,
|
|
39
|
+
)
|
|
40
|
+
} else {
|
|
41
|
+
console.log(
|
|
42
|
+
`VISUAL_CODER_PREPARING Session ${sessionId} is visible in the visualizer (${manifest.phase}). Draft the plan next with inbase report-plan.`,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function waitForBlueprint(args) {
|
|
48
|
+
const { store, config } = await loadExplorer()
|
|
49
|
+
const sessionId = takeFlagValue(args, '--session')
|
|
50
|
+
const timeoutMs = Number(takeFlagValue(args, '--timeout') ?? 600000)
|
|
51
|
+
if (!sessionId) usage('wait-for-blueprint', '--session <cursor-chat-id> [--timeout ms]')
|
|
52
|
+
|
|
53
|
+
const started = Date.now()
|
|
54
|
+
const initial = store.readManifest(config.dataDir, sessionId)
|
|
55
|
+
if (!initial) {
|
|
56
|
+
console.error(`No workflow session found for ${sessionId}`)
|
|
57
|
+
process.exit(1)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (initial.phase === 'blueprint_ask' || initial.phase === 'blueprint') {
|
|
61
|
+
console.log(
|
|
62
|
+
initial.phase === 'blueprint_ask'
|
|
63
|
+
? 'Waiting for the user to choose Setup blueprint: Yes or No...'
|
|
64
|
+
: 'Waiting for the user to send the blueprint...',
|
|
65
|
+
)
|
|
66
|
+
} else {
|
|
67
|
+
console.log(`Blueprint handshake already finished for session ${sessionId}.`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
while (Date.now() - started < timeoutMs) {
|
|
71
|
+
const manifest = store.readManifest(config.dataDir, sessionId)
|
|
72
|
+
if (!manifest || manifest.phase === 'stopped') {
|
|
73
|
+
console.error(
|
|
74
|
+
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
75
|
+
)
|
|
76
|
+
process.exit(2)
|
|
77
|
+
}
|
|
78
|
+
if (manifest.phase !== 'blueprint_ask' && manifest.phase !== 'blueprint') {
|
|
79
|
+
const blueprint = store.readBlueprint(config.dataDir, sessionId)
|
|
80
|
+
const blocks = blueprint.userCreatedBlocks ?? []
|
|
81
|
+
const islands = blueprint.userCreatedIslands ?? []
|
|
82
|
+
console.log(
|
|
83
|
+
blueprint.enabled
|
|
84
|
+
? `VISUAL_CODER_BLUEPRINT_READY The user sent ${blocks.length} file(s) and ${islands.length} island(s) for this chat. Create those paths in the plan even if they are not on disk.`
|
|
85
|
+
: 'VISUAL_CODER_BLUEPRINT_READY The user skipped the blueprint. Continue without user-placed files or islands.',
|
|
86
|
+
)
|
|
87
|
+
console.log('VISUAL_CODER_BLUEPRINT_START')
|
|
88
|
+
console.log(JSON.stringify(blueprint, null, 2))
|
|
89
|
+
console.log('VISUAL_CODER_BLUEPRINT_END')
|
|
90
|
+
process.exit(0)
|
|
91
|
+
}
|
|
92
|
+
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.error('Timed out waiting for the blueprint handshake. Do not modify files.')
|
|
96
|
+
process.exit(3)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function reportPlan(args) {
|
|
100
|
+
const { store, config } = await loadExplorer()
|
|
101
|
+
const sessionParsed = takeFlagValues(args, '--session')
|
|
102
|
+
const featureParsed = takeFlagValues(sessionParsed.rest, '--feature')
|
|
103
|
+
const stepsParsed = takeFlagValues(featureParsed.rest, '--steps')
|
|
104
|
+
const sessionId = sessionParsed.values[0]
|
|
105
|
+
const existing = sessionId ? store.readManifest(config.dataDir, sessionId) : null
|
|
106
|
+
const feature = featureParsed.values[0] ?? existing?.feature
|
|
107
|
+
|
|
108
|
+
if (!sessionId || !feature || stepsParsed.values.length === 0) {
|
|
109
|
+
usage(
|
|
110
|
+
'report-plan',
|
|
111
|
+
'--session <cursor-chat-id> --feature "name" --steps "one" [--steps "two"]',
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const manifest = store.reportPlan(config.dataDir, {
|
|
116
|
+
sessionId,
|
|
117
|
+
feature,
|
|
118
|
+
stepTitles: stepsParsed.values,
|
|
119
|
+
})
|
|
120
|
+
console.log(
|
|
121
|
+
`VISUAL_CODER_PLAN_READY Reported ${manifest.steps.length} plan step(s) for session ${sessionId}. Wait for the user to invoke step ${manifest.currentStep}.`,
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export async function waitForApproval(args) {
|
|
126
|
+
const { store, config } = await loadExplorer()
|
|
127
|
+
const sessionId = takeFlagValue(args, '--session')
|
|
128
|
+
const timeoutMs = Number(takeFlagValue(args, '--timeout') ?? 600000)
|
|
129
|
+
if (!sessionId) usage('wait-for-approval', '--session <cursor-chat-id> [--timeout ms]')
|
|
130
|
+
|
|
131
|
+
const started = Date.now()
|
|
132
|
+
const initial = store.readManifest(config.dataDir, sessionId)
|
|
133
|
+
const initialDiff = initial?.diffs?.at(-1)
|
|
134
|
+
if (!initial) {
|
|
135
|
+
console.error(`No workflow session found for ${sessionId}`)
|
|
136
|
+
process.exit(1)
|
|
137
|
+
}
|
|
138
|
+
console.log(
|
|
139
|
+
initial.phase === 'plan_ready'
|
|
140
|
+
? `Waiting for the user to invoke step ${initial.currentStep}...`
|
|
141
|
+
: initial.phase === 'review' && initialDiff
|
|
142
|
+
? `Waiting for the user to run the next step after ${initialDiff.id}...`
|
|
143
|
+
: `Waiting for the visual workflow in session ${sessionId}...`,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
while (Date.now() - started < timeoutMs) {
|
|
147
|
+
const manifest = store.readManifest(config.dataDir, sessionId)
|
|
148
|
+
if (!manifest) {
|
|
149
|
+
console.error(
|
|
150
|
+
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
151
|
+
)
|
|
152
|
+
process.exit(2)
|
|
153
|
+
}
|
|
154
|
+
const current = initialDiff
|
|
155
|
+
? manifest.diffs.find((entry) => entry.id === initialDiff.id)
|
|
156
|
+
: null
|
|
157
|
+
|
|
158
|
+
if (manifest.phase === 'finished') {
|
|
159
|
+
console.log(
|
|
160
|
+
`VISUAL_CODER_FINISHED The final step was applied. Feature is done. Run inbase propose-patch --session ${sessionId} --clear, then tell the user it is finished.`,
|
|
161
|
+
)
|
|
162
|
+
process.exit(5)
|
|
163
|
+
}
|
|
164
|
+
if (manifest.phase === 'working') {
|
|
165
|
+
const next = manifest.steps.find((step) => step.index === manifest.currentStep)
|
|
166
|
+
console.log(
|
|
167
|
+
`VISUAL_CODER_EXECUTE Step ${manifest.currentStep} is invoked${next ? `: ${next.title}` : ''}. Implement only this step, publish its incremental diff with inbase propose-patch --session ${sessionId}, then wait again.`,
|
|
168
|
+
)
|
|
169
|
+
process.exit(0)
|
|
170
|
+
}
|
|
171
|
+
if (manifest.phase === 'replanning') {
|
|
172
|
+
const instruction = manifest.pendingInstruction
|
|
173
|
+
? `\nVISUAL_CODER_INSTRUCTION_START\n${manifest.pendingInstruction}\nVISUAL_CODER_INSTRUCTION_END`
|
|
174
|
+
: ''
|
|
175
|
+
console.log(
|
|
176
|
+
`VISUAL_CODER_REPLAN Keep accepted steps before step ${manifest.currentStep}. Replace the plan from step ${manifest.currentStep} onward using the instruction below. Report the revised tail with inbase report-plan, then wait for invocation.${instruction}`,
|
|
177
|
+
)
|
|
178
|
+
process.exit(4)
|
|
179
|
+
}
|
|
180
|
+
if (manifest.phase === 'stopped' || current?.status === 'rejected') {
|
|
181
|
+
console.error(
|
|
182
|
+
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
183
|
+
)
|
|
184
|
+
process.exit(2)
|
|
185
|
+
}
|
|
186
|
+
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.error('Timed out waiting for visualizer review. Do not modify files.')
|
|
190
|
+
process.exit(3)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function proposePatch(args) {
|
|
194
|
+
const { store, patchLib, config } = await loadExplorer()
|
|
195
|
+
const clear = args.includes('--clear')
|
|
196
|
+
const withoutClear = args.filter((arg) => arg !== '--clear')
|
|
197
|
+
const sessionParsed = takeFlagValues(withoutClear, '--session')
|
|
198
|
+
const patchFile = sessionParsed.rest[0]
|
|
199
|
+
const sessionId = sessionParsed.values[0]
|
|
200
|
+
const cwd = process.cwd()
|
|
201
|
+
|
|
202
|
+
if (clear) {
|
|
203
|
+
if (!sessionId) usage('propose-patch', '--session <cursor-chat-id> --clear')
|
|
204
|
+
store.stopSession(config.dataDir, sessionId)
|
|
205
|
+
console.log(
|
|
206
|
+
`Cleared session ${sessionId}; stored diffs and blueprint drafts were removed.`,
|
|
207
|
+
)
|
|
208
|
+
process.exit(0)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!sessionId || !patchFile) {
|
|
212
|
+
usage('propose-patch', '--session <cursor-chat-id> <file.patch|->')
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let patchText = ''
|
|
216
|
+
if (patchFile && patchFile !== '-') {
|
|
217
|
+
patchText = fs.readFileSync(path.resolve(cwd, patchFile), 'utf8')
|
|
218
|
+
} else if (patchFile === '-') {
|
|
219
|
+
patchText = fs.readFileSync(0, 'utf8')
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!patchText.trim()) {
|
|
223
|
+
console.error('No unified diff provided. Pass a .patch file or use stdin.')
|
|
224
|
+
process.exit(1)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const parsed = patchLib.parseUnifiedPatch(patchText)
|
|
228
|
+
if (parsed.entries.length === 0) {
|
|
229
|
+
console.error('Patch did not contain any file changes.')
|
|
230
|
+
process.exit(1)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const { entry, manifest } = store.appendDiff(config.dataDir, config.targetRoot, {
|
|
234
|
+
sessionId,
|
|
235
|
+
patchText,
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
console.log(
|
|
239
|
+
`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.`,
|
|
240
|
+
)
|
|
241
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jkwd/inbase",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A first-person 3D map of a codebase, with a visual coding workflow for Cursor.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/jk-wd/inbase"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/jk-wd/inbase",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/jk-wd/inbase/issues"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"inbase": "bin/inbase.mjs"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/inbase.mjs",
|
|
19
|
+
"bin/project.mjs",
|
|
20
|
+
"bin/session.mjs",
|
|
21
|
+
"skill",
|
|
22
|
+
"apps/explorer/index.html",
|
|
23
|
+
"apps/explorer/package.json",
|
|
24
|
+
"apps/explorer/tsconfig.json",
|
|
25
|
+
"apps/explorer/vite.config.ts",
|
|
26
|
+
"apps/explorer/src/*.ts",
|
|
27
|
+
"apps/explorer/src/*.tsx",
|
|
28
|
+
"apps/explorer/src/*.css",
|
|
29
|
+
"apps/explorer/src/scene",
|
|
30
|
+
"apps/explorer/src/ui",
|
|
31
|
+
"apps/explorer/scripts/js-source.mjs",
|
|
32
|
+
"apps/explorer/scripts/patch-lib.d.ts",
|
|
33
|
+
"apps/explorer/scripts/patch-lib.mjs",
|
|
34
|
+
"apps/explorer/scripts/scan-target.mjs",
|
|
35
|
+
"apps/explorer/scripts/session-store.d.ts",
|
|
36
|
+
"apps/explorer/scripts/session-store.mjs",
|
|
37
|
+
"apps/explorer/scripts/target-config.d.ts",
|
|
38
|
+
"apps/explorer/scripts/target-config.mjs"
|
|
39
|
+
],
|
|
40
|
+
"workspaces": [
|
|
41
|
+
"apps/*"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"dev": "npm run dev -w @visual-coder/explorer",
|
|
45
|
+
"dev:target": "npm run dev -w @visual-coder/example-target",
|
|
46
|
+
"build": "npm run build -w @visual-coder/explorer",
|
|
47
|
+
"scan": "npm run scan -w @visual-coder/explorer",
|
|
48
|
+
"inbase": "node bin/inbase.mjs",
|
|
49
|
+
"test": "npm test -w @visual-coder/explorer && node --test bin/*.test.mjs"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@react-three/drei": "^9.117.3",
|
|
56
|
+
"@react-three/fiber": "^8.17.10",
|
|
57
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
58
|
+
"react": "^18.3.1",
|
|
59
|
+
"react-dom": "^18.3.1",
|
|
60
|
+
"three": "^0.170.0",
|
|
61
|
+
"vite": "^6.0.3"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: inbase
|
|
3
|
+
description: >-
|
|
4
|
+
Grounds source-file changes in the Inbase visual map. Use when creating,
|
|
5
|
+
editing, or deleting application source files in this repository. Lists every
|
|
6
|
+
feature step, then works only via patch files. Do not use for git, docs-only,
|
|
7
|
+
lockfiles, or questions.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Inbase visual edits
|
|
11
|
+
|
|
12
|
+
Apply this skill **whenever the work is file changes in this repository**.
|
|
13
|
+
Skip it for git, lockfiles, `.inbase`, `.cursor`, or questions with no code
|
|
14
|
+
changes.
|
|
15
|
+
|
|
16
|
+
The LLM uses a plan-first loop. It reports the complete plan before writing a
|
|
17
|
+
patch, waits for the user to invoke the highlighted step, publishes only that
|
|
18
|
+
step's diff, then waits for **Run step** on the following step or an alternative
|
|
19
|
+
instruction. Always work via patch files. Do not Write, StrReplace, or Delete
|
|
20
|
+
project files.
|
|
21
|
+
|
|
22
|
+
Every Cursor chat has an explicit session ID. Pass that same ID to every
|
|
23
|
+
command. The visualizer stores immutable diffs under `.inbase/diff-sessions/<session-id>/diffs/`.
|
|
24
|
+
|
|
25
|
+
Inbase must already be running (`inbase run` or `npx inbase run`). Prefer
|
|
26
|
+
`npx inbase` so the local package is used.
|
|
27
|
+
|
|
28
|
+
## Required sequence
|
|
29
|
+
|
|
30
|
+
1. As soon as this skill applies, start the visual session so the explorer can
|
|
31
|
+
offer a blueprint handshake. Do this before reading context or listing steps:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx inbase start-session --session "<current-cursor-chat-id>"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
2. **Stop and wait for the blueprint handshake**. Do not report a plan and do
|
|
38
|
+
not write a patch until this prints `VISUAL_CODER_BLUEPRINT_READY`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx inbase wait-for-blueprint --session "<current-cursor-chat-id>"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The explorer asks **Setup blueprint: Yes vs No**.
|
|
45
|
+
- **No**: skip placement; continue without user-placed files or islands.
|
|
46
|
+
- **Yes**: the user places files (`Space`) and islands (`B`), then clicks
|
|
47
|
+
**Send blueprint**.
|
|
48
|
+
3. Read the handshake output between `VISUAL_CODER_BLUEPRINT_START` and
|
|
49
|
+
`VISUAL_CODER_BLUEPRINT_END`, or read
|
|
50
|
+
`.inbase/diff-sessions/<session-id>/blueprint.json`.
|
|
51
|
+
If `enabled` is true, always create `userCreatedBlocks` and
|
|
52
|
+
`userCreatedIslands` at the given path/folder. Those files and folders do
|
|
53
|
+
not exist on disk yet. They belong to this chat only.
|
|
54
|
+
Also honor `addedFunctions`, `addedVariables`, and `addedImports`: add those
|
|
55
|
+
symbols and imports to the named files. They are blueprint intentions, not
|
|
56
|
+
files that already exist on disk.
|
|
57
|
+
4. Read `.inbase/user-context.json` for viewpoint only.
|
|
58
|
+
5. Use the user's viewpoint only when `followLook` is true:
|
|
59
|
+
- `island` is where they are standing
|
|
60
|
+
- `lookingAt` / `lookingAtFiles` are the blocks they are looking at
|
|
61
|
+
- `selected` is the block they clicked
|
|
62
|
+
- `filesOnIsland` is the rest of that folder
|
|
63
|
+
Prefer those files while `followLook` is true, unless the request clearly
|
|
64
|
+
needs something else. If `followLook` is false or missing, ignore viewpoint
|
|
65
|
+
and choose files from the request itself. Still include this session's
|
|
66
|
+
blueprint files and islands when `enabled` is true.
|
|
67
|
+
6. List **all** steps needed to finish the feature. Keep steps small enough that
|
|
68
|
+
one patch is one landscape change (usually one new file, or a few related
|
|
69
|
+
edits).
|
|
70
|
+
7. Report the plan before making a diff:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx inbase report-plan \
|
|
74
|
+
--session "<current-cursor-chat-id>" \
|
|
75
|
+
--feature "short feature name" \
|
|
76
|
+
--steps "Add Clock component" \
|
|
77
|
+
--steps "Show Clock on Home"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
8. **Stop and wait for invocation**:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx inbase wait-for-approval --session "<current-cursor-chat-id>"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Do not write a patch until this prints `VISUAL_CODER_EXECUTE`.
|
|
87
|
+
9. Implement only the invoked step as a unified diff. Paths are relative to the
|
|
88
|
+
project root (same ids as `codebase.json`):
|
|
89
|
+
|
|
90
|
+
```diff
|
|
91
|
+
--- /dev/null
|
|
92
|
+
+++ b/src/components/Clock.tsx
|
|
93
|
+
@@ -0,0 +1,5 @@
|
|
94
|
+
+export function Clock() {
|
|
95
|
+
+ return <time>00:00</time>
|
|
96
|
+
+}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```diff
|
|
100
|
+
--- a/src/pages/Home.tsx
|
|
101
|
+
+++ b/src/pages/Home.tsx
|
|
102
|
+
@@ -1,3 +1,4 @@
|
|
103
|
+
+import { Clock } from '../components/Clock'
|
|
104
|
+
import { Counter } from '../components/Counter'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Write that diff to a new `.patch` file, then publish it:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx inbase propose-patch \
|
|
111
|
+
--session "<current-cursor-chat-id>" \
|
|
112
|
+
/tmp/step.patch
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The patch path or stdin is required. Never write or replace a patch already
|
|
116
|
+
stored in the session folder.
|
|
117
|
+
|
|
118
|
+
10. **Stop.** Do not apply the patch and do not edit project files directly.
|
|
119
|
+
11. Wait until the user clicks **Run step** on the next step, sends an alternative instruction,
|
|
120
|
+
or stops the workflow:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx inbase wait-for-approval --session "<current-cursor-chat-id>"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
12. Read the wait command output:
|
|
127
|
+
|
|
128
|
+
- Exit `0` (`VISUAL_CODER_EXECUTE`): the highlighted step was invoked. Build
|
|
129
|
+
only that step, publish its incremental diff with `inbase propose-patch`,
|
|
130
|
+
then wait again.
|
|
131
|
+
- Exit `5` (`VISUAL_CODER_FINISHED`): that was the last step. The visualizer
|
|
132
|
+
already applied the final patch and removed stored session diffs and
|
|
133
|
+
blueprint drafts. Optionally run `--clear` if anything remains, tell the
|
|
134
|
+
user the feature is done, and **stop**. Do not propose another patch.
|
|
135
|
+
- Exit `4` (`VISUAL_CODER_REPLAN`): do **not** apply files and do not rewrite
|
|
136
|
+
an earlier diff. Follow the text between
|
|
137
|
+
`VISUAL_CODER_INSTRUCTION_START` and `VISUAL_CODER_INSTRUCTION_END`, read
|
|
138
|
+
this session's `blueprint.json` when it is enabled (files, islands,
|
|
139
|
+
`addedFunctions`, `addedVariables`, `addedImports`), read
|
|
140
|
+
`user-context.json` (follow the viewpoint only if `followLook` is true),
|
|
141
|
+
replace the plan from the current step onward using `inbase report-plan`,
|
|
142
|
+
then wait for the user to invoke the first revised step.
|
|
143
|
+
- Exit `2` (`VISUAL_CODER_STOPPED`) or `3` (timeout): make no further
|
|
144
|
+
project changes.
|
|
145
|
+
|
|
146
|
+
13. After a finished handshake, the explorer already removed stored session
|
|
147
|
+
diffs and blueprint drafts. Optionally run:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx inbase propose-patch --session "<current-cursor-chat-id>" --clear
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Do not
|
|
154
|
+
|
|
155
|
+
- Skip `inbase start-session` once this skill applies
|
|
156
|
+
- Skip `inbase wait-for-blueprint` or report a plan before `VISUAL_CODER_BLUEPRINT_READY`
|
|
157
|
+
- Skip this session's `blueprint.json` `userCreatedBlocks` or `userCreatedIslands` when `enabled` is true
|
|
158
|
+
- Skip `addedFunctions`, `addedVariables`, or `addedImports` from that blueprint when `enabled` is true
|
|
159
|
+
- Read global `user-context.json` for placed files; those live on the session blueprint
|
|
160
|
+
- Follow the user's look when `followLook` is false
|
|
161
|
+
- Write, edit, create, or delete project files directly
|
|
162
|
+
- Announce file lists instead of a patch
|
|
163
|
+
- Write a patch before its plan step is invoked
|
|
164
|
+
- Propose the next step before the user clicks **Run step**
|
|
165
|
+
- Propose another patch after `VISUAL_CODER_FINISHED`
|
|
166
|
+
- Reuse, overwrite, or expand an existing session diff
|
|
167
|
+
- Use this flow for git, lockfiles, or other non-source work
|