@jkwd/inbase 0.1.10 → 0.1.12
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 +22 -9
- 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 +5 -0
- package/apps/explorer/scripts/patch-lib.mjs +5 -0
- package/apps/explorer/scripts/scan-target.mjs +46 -13
- package/apps/explorer/scripts/session-store.d.ts +58 -1
- package/apps/explorer/scripts/session-store.mjs +276 -52
- package/apps/explorer/scripts/tree-diff.mjs +121 -0
- package/apps/explorer/src/App.tsx +170 -32
- package/apps/explorer/src/agentIntent.ts +63 -0
- package/apps/explorer/src/branchChanges.ts +54 -0
- package/apps/explorer/src/index.css +153 -0
- package/apps/explorer/src/scene/FileBlock.tsx +55 -5
- package/apps/explorer/src/scene/MapView.tsx +32 -1
- package/apps/explorer/src/scene/World.tsx +6 -1
- package/apps/explorer/src/types.ts +44 -0
- package/apps/explorer/src/ui/HUD.tsx +583 -96
- package/apps/explorer/src/ui/MapContextMenu.tsx +89 -0
- package/apps/explorer/src/userContext.ts +11 -0
- package/apps/explorer/src/userCreated.ts +50 -0
- package/apps/explorer/vite.config.ts +61 -7
- package/bin/inbase.mjs +23 -4
- package/bin/project.mjs +62 -4
- package/bin/session.mjs +231 -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 +143 -112
package/bin/session.mjs
CHANGED
|
@@ -26,81 +26,217 @@ function usage(name, example) {
|
|
|
26
26
|
process.exit(1)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
function printAck(kind, detail) {
|
|
30
|
+
console.log(`VISUAL_CODER_ACK ${kind}: ${detail}`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createManifestGate(manifestPath, watch = fs.watch) {
|
|
34
|
+
const dir = path.dirname(manifestPath)
|
|
35
|
+
let wake = () => {}
|
|
36
|
+
let watcher = null
|
|
37
|
+
|
|
38
|
+
const dropWatcher = () => {
|
|
39
|
+
try {
|
|
40
|
+
watcher?.close()
|
|
41
|
+
} catch {
|
|
42
|
+
// Already closed after an error, or never opened.
|
|
43
|
+
}
|
|
44
|
+
watcher = null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
watcher = watch(dir, () => wake())
|
|
49
|
+
watcher?.on?.('error', () => {
|
|
50
|
+
// EMFILE and sandbox limits must not crash wait-for-approval. Poll instead.
|
|
51
|
+
dropWatcher()
|
|
52
|
+
wake()
|
|
53
|
+
})
|
|
54
|
+
} catch {
|
|
55
|
+
dropWatcher()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
wait(ms) {
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
const timer = setTimeout(resolve, ms)
|
|
62
|
+
wake = () => {
|
|
63
|
+
clearTimeout(timer)
|
|
64
|
+
resolve()
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
},
|
|
68
|
+
close() {
|
|
69
|
+
dropWatcher()
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function signalAck(store, dataDir, sessionId, kind, detail) {
|
|
75
|
+
printAck(kind, detail)
|
|
76
|
+
try {
|
|
77
|
+
store.recordSessionAck(dataDir, sessionId, kind, detail)
|
|
78
|
+
} catch {
|
|
79
|
+
// Session folder may already be gone.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function waitingMessage(sessionId, manifest) {
|
|
84
|
+
if (manifest.phase === 'plan_ready') {
|
|
85
|
+
return `Waiting for the user to invoke step ${manifest.currentStep}...`
|
|
86
|
+
}
|
|
87
|
+
if (manifest.phase === 'review' && manifest.diffs?.at(-1)) {
|
|
88
|
+
return manifest.stepByStep === false
|
|
89
|
+
? `Waiting for the user to accept the proposal after ${manifest.diffs.at(-1).id}...`
|
|
90
|
+
: `Waiting for the user to accept the proposal on ${manifest.diffs.at(-1).id}...`
|
|
91
|
+
}
|
|
92
|
+
return `Waiting for the visual workflow in session ${sessionId}...`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function emitStopped(store, dataDir, sessionId) {
|
|
96
|
+
if (store && dataDir && sessionId) {
|
|
97
|
+
signalAck(store, dataDir, sessionId, 'stopped', 'the workflow was stopped')
|
|
98
|
+
} else {
|
|
99
|
+
printAck('stopped', 'the workflow was stopped')
|
|
100
|
+
}
|
|
101
|
+
console.error(
|
|
102
|
+
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
103
|
+
)
|
|
104
|
+
process.exit(2)
|
|
105
|
+
}
|
|
34
106
|
|
|
35
|
-
|
|
36
|
-
|
|
107
|
+
function emitApprovalHandshake(store, dataDir, sessionId, manifest, initialDiff) {
|
|
108
|
+
const current = initialDiff
|
|
109
|
+
? manifest?.diffs.find((entry) => entry.id === initialDiff.id)
|
|
110
|
+
: null
|
|
111
|
+
if (!manifest || manifest.phase === 'stopped' || current?.status === 'rejected') {
|
|
112
|
+
emitStopped(store, dataDir, sessionId)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
if (manifest.phase === 'finished') {
|
|
116
|
+
signalAck(store, dataDir, sessionId, 'finished', 'the final step was accepted')
|
|
37
117
|
console.log(
|
|
38
|
-
`
|
|
118
|
+
`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.`,
|
|
39
119
|
)
|
|
40
|
-
|
|
120
|
+
process.exit(5)
|
|
121
|
+
}
|
|
122
|
+
if (manifest.phase === 'working') {
|
|
123
|
+
const next = manifest.steps.find((step) => step.index === manifest.currentStep)
|
|
124
|
+
const title = next?.title
|
|
125
|
+
signalAck(
|
|
126
|
+
store,
|
|
127
|
+
dataDir,
|
|
128
|
+
sessionId,
|
|
129
|
+
'execute',
|
|
130
|
+
title
|
|
131
|
+
? `step ${manifest.currentStep} — ${title}`
|
|
132
|
+
: `step ${manifest.currentStep}`,
|
|
133
|
+
)
|
|
134
|
+
const continuing = (manifest.diffs?.length ?? 0) > 0
|
|
41
135
|
console.log(
|
|
42
|
-
|
|
136
|
+
continuing
|
|
137
|
+
? `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.`
|
|
138
|
+
: `VISUAL_CODER_EXECUTE Step ${manifest.currentStep} is invoked${title ? `: ${title}` : ''}. Re-read this session's blueprint.json before implementing; the user can place files and islands on any step. 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.`,
|
|
43
139
|
)
|
|
140
|
+
process.exit(0)
|
|
141
|
+
}
|
|
142
|
+
if (manifest.phase === 'replanning') {
|
|
143
|
+
signalAck(
|
|
144
|
+
store,
|
|
145
|
+
dataDir,
|
|
146
|
+
sessionId,
|
|
147
|
+
'replan',
|
|
148
|
+
`revise the plan from step ${manifest.currentStep}`,
|
|
149
|
+
)
|
|
150
|
+
const instruction = manifest.pendingInstruction
|
|
151
|
+
? `\nVISUAL_CODER_INSTRUCTION_START\n${manifest.pendingInstruction}\nVISUAL_CODER_INSTRUCTION_END`
|
|
152
|
+
: ''
|
|
153
|
+
console.log(
|
|
154
|
+
`VISUAL_CODER_REPLAN Keep accepted patch files before step ${manifest.currentStep}. Disk is baseline + accepted patches. Do not edit project files until the next EXECUTE. The session blueprint remains leading; if this instruction would differ from it, ask the user before replacing the plan. Report the revised tail with inbase report-plan, then wait for invocation.${instruction}`,
|
|
155
|
+
)
|
|
156
|
+
process.exit(4)
|
|
44
157
|
}
|
|
45
158
|
}
|
|
46
159
|
|
|
160
|
+
export async function startSession(args) {
|
|
161
|
+
const { store, config } = await loadExplorer()
|
|
162
|
+
const sessionId = takeFlagValue(args, '--session')
|
|
163
|
+
const name = takeFlagValue(args, '--name') || takeFlagValue(args, '--feature')
|
|
164
|
+
const feature = takeFlagValue(args, '--feature')
|
|
165
|
+
if (!sessionId || !name) {
|
|
166
|
+
usage('start-session', '--session <cursor-chat-id> --name "short name"')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const manifest = store.startSession(config.dataDir, { sessionId, name, feature })
|
|
170
|
+
console.log(
|
|
171
|
+
`VISUAL_CODER_BLUEPRINT_WAIT Session ${manifest.name || sessionId} is visible in the visualizer (${manifest.phase}). Wait with inbase wait-for-blueprint before drafting the plan. A running visualizer does not skip this handshake.`,
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function attachSession(args) {
|
|
176
|
+
const { store, config } = await loadExplorer()
|
|
177
|
+
const sessionId = takeFlagValue(args, '--session')
|
|
178
|
+
const manifest = store.attachSession(config.dataDir, sessionId)
|
|
179
|
+
console.log(`VISUAL_CODER_SESSION ${manifest.sessionId}`)
|
|
180
|
+
printAck('attached', manifest.name || manifest.sessionId)
|
|
181
|
+
console.log(
|
|
182
|
+
`VISUAL_CODER_ATTACHED Attached to the focused 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 instruction; it does not wait.`,
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
47
186
|
export async function waitForBlueprint(args) {
|
|
48
187
|
const { store, config } = await loadExplorer()
|
|
49
188
|
const sessionId = takeFlagValue(args, '--session')
|
|
50
|
-
|
|
51
|
-
if (!sessionId) usage('wait-for-blueprint', '--session <cursor-chat-id> [--timeout ms]')
|
|
189
|
+
if (!sessionId) usage('wait-for-blueprint', '--session <cursor-chat-id>')
|
|
52
190
|
|
|
53
|
-
const started = Date.now()
|
|
54
|
-
const initial = store.readManifest(config.dataDir, sessionId)
|
|
55
191
|
if (store.isWorkflowStopped(config.dataDir, sessionId)) {
|
|
56
|
-
|
|
57
|
-
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
58
|
-
)
|
|
59
|
-
process.exit(2)
|
|
192
|
+
emitStopped(store, config.dataDir, sessionId)
|
|
60
193
|
}
|
|
194
|
+
const initial = store.readManifest(config.dataDir, sessionId)
|
|
61
195
|
if (!initial) {
|
|
62
196
|
console.error(`No workflow session found for ${sessionId}`)
|
|
63
197
|
process.exit(1)
|
|
64
198
|
}
|
|
65
199
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
} else {
|
|
73
|
-
console.log(`Blueprint handshake already finished for session ${sessionId}.`)
|
|
200
|
+
store.touchSessionConnection(config.dataDir, sessionId)
|
|
201
|
+
store.maybeStartVisualizerHandshake(config.dataDir, sessionId)
|
|
202
|
+
const manifest = store.readManifest(config.dataDir, sessionId)
|
|
203
|
+
if (!manifest || manifest.phase === 'stopped') {
|
|
204
|
+
emitStopped(store, config.dataDir, sessionId)
|
|
74
205
|
}
|
|
75
206
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
207
|
+
const blueprint = store.readBlueprint(config.dataDir, sessionId)
|
|
208
|
+
const blocks = blueprint.userCreatedBlocks ?? []
|
|
209
|
+
const islands = blueprint.userCreatedIslands ?? []
|
|
210
|
+
signalAck(
|
|
211
|
+
store,
|
|
212
|
+
config.dataDir,
|
|
213
|
+
sessionId,
|
|
214
|
+
'blueprint',
|
|
215
|
+
blueprint.enabled
|
|
216
|
+
? `${blocks.length} file(s), ${islands.length} island(s)`
|
|
217
|
+
: 'none',
|
|
218
|
+
)
|
|
219
|
+
console.log(
|
|
220
|
+
blueprint.enabled
|
|
221
|
+
? `VISUAL_CODER_BLUEPRINT_READY The session started with ${blocks.length} file(s) and ${islands.length} island(s). The blueprint is leading: create those paths and honor addedFunctions, addedVariables, and addedImports even if they are not on disk. Do not omit, rename, relocate, or replace them. Extra new files not in the blueprint are a deviation. If you would differ from the blueprint, ask the user first; do not silently deviate. The user can still place files and islands on later steps; re-read this session's blueprint.json before each step.`
|
|
222
|
+
: 'VISUAL_CODER_BLUEPRINT_READY The session started without a blueprint. They can still place files and islands on later steps; re-read this session\'s blueprint.json before each step. Continue without user-placed files until that file is enabled.',
|
|
223
|
+
)
|
|
224
|
+
console.log('VISUAL_CODER_BLUEPRINT_START')
|
|
225
|
+
console.log(JSON.stringify(blueprint, null, 2))
|
|
226
|
+
console.log('VISUAL_CODER_BLUEPRINT_END')
|
|
227
|
+
const instruction =
|
|
228
|
+
typeof manifest.initialInstruction === 'string'
|
|
229
|
+
? manifest.initialInstruction.trim()
|
|
230
|
+
: ''
|
|
231
|
+
if (instruction) {
|
|
232
|
+
console.log(
|
|
233
|
+
'Honor the user\'s initial instruction between VISUAL_CODER_INSTRUCTION_START and END together with the blueprint.',
|
|
234
|
+
)
|
|
235
|
+
console.log('VISUAL_CODER_INSTRUCTION_START')
|
|
236
|
+
console.log(instruction)
|
|
237
|
+
console.log('VISUAL_CODER_INSTRUCTION_END')
|
|
100
238
|
}
|
|
101
|
-
|
|
102
|
-
console.error('Timed out waiting for the blueprint handshake. Do not modify files.')
|
|
103
|
-
process.exit(3)
|
|
239
|
+
process.exit(0)
|
|
104
240
|
}
|
|
105
241
|
|
|
106
242
|
export async function reportPlan(args) {
|
|
@@ -123,10 +259,11 @@ export async function reportPlan(args) {
|
|
|
123
259
|
sessionId,
|
|
124
260
|
feature,
|
|
125
261
|
stepTitles: stepsParsed.values,
|
|
262
|
+
targetRoot: config.targetRoot,
|
|
126
263
|
})
|
|
127
264
|
console.log(
|
|
128
265
|
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.
|
|
266
|
+
? `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. Edit the live files for that step, then inbase propose-patch --session ${sessionId} with no patch file.`
|
|
130
267
|
: `VISUAL_CODER_PLAN_READY Reported ${manifest.steps.length} plan step(s) for session ${sessionId}. Wait for the user to invoke step ${manifest.currentStep}.`,
|
|
131
268
|
)
|
|
132
269
|
}
|
|
@@ -141,72 +278,36 @@ export async function waitForApproval(args) {
|
|
|
141
278
|
const initial = store.readManifest(config.dataDir, sessionId)
|
|
142
279
|
const initialDiff = initial?.diffs?.at(-1)
|
|
143
280
|
if (store.isWorkflowStopped(config.dataDir, sessionId)) {
|
|
144
|
-
|
|
145
|
-
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
146
|
-
)
|
|
147
|
-
process.exit(2)
|
|
281
|
+
emitStopped(store, config.dataDir, sessionId)
|
|
148
282
|
}
|
|
149
283
|
if (!initial) {
|
|
150
284
|
console.error(`No workflow session found for ${sessionId}`)
|
|
151
285
|
process.exit(1)
|
|
152
286
|
}
|
|
153
287
|
store.autoAdvance(config.dataDir, sessionId, config.targetRoot)
|
|
154
|
-
const afterAdvance = store.readManifest(config.dataDir, sessionId) ?? initial
|
|
155
|
-
console.log(
|
|
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 user to accept the proposal after ${afterAdvance.diffs.at(-1).id}...`
|
|
161
|
-
: `Waiting for the user to accept the proposal on ${afterAdvance.diffs.at(-1).id}...`
|
|
162
|
-
: `Waiting for the visual workflow in session ${sessionId}...`,
|
|
163
|
-
)
|
|
164
288
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`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.`,
|
|
182
|
-
)
|
|
183
|
-
process.exit(5)
|
|
184
|
-
}
|
|
185
|
-
if (manifest.phase === 'working') {
|
|
186
|
-
const next = manifest.steps.find((step) => step.index === manifest.currentStep)
|
|
187
|
-
console.log(
|
|
188
|
-
`VISUAL_CODER_EXECUTE Step ${manifest.currentStep} is invoked${next ? `: ${next.title}` : ''}. Re-read this session's blueprint.json before implementing; the user can place files and islands on any step. Patch files are the source of truth: write only this step's unified diff against the current live files (baseline + accepted patches), publish it with inbase propose-patch --session ${sessionId}, then wait again. Do not Write, StrReplace, or Delete project files.`,
|
|
189
|
-
)
|
|
190
|
-
process.exit(0)
|
|
191
|
-
}
|
|
192
|
-
if (manifest.phase === 'replanning') {
|
|
193
|
-
const instruction = manifest.pendingInstruction
|
|
194
|
-
? `\nVISUAL_CODER_INSTRUCTION_START\n${manifest.pendingInstruction}\nVISUAL_CODER_INSTRUCTION_END`
|
|
195
|
-
: ''
|
|
196
|
-
console.log(
|
|
197
|
-
`VISUAL_CODER_REPLAN Keep accepted patch files before step ${manifest.currentStep}. Replace the withdrawn step with a new patch against those live files, not against the withdrawn proposal. Do not edit project files. The session blueprint remains leading; if this instruction would differ from it, ask the user before replacing the plan. Report the revised tail with inbase report-plan, then wait for invocation.${instruction}`,
|
|
198
|
-
)
|
|
199
|
-
process.exit(4)
|
|
289
|
+
const { manifest: manifestPath } = store.sessionPaths(config.dataDir, sessionId)
|
|
290
|
+
const gate = createManifestGate(manifestPath)
|
|
291
|
+
let lastWaiting = null
|
|
292
|
+
try {
|
|
293
|
+
while (Date.now() - started < timeoutMs) {
|
|
294
|
+
store.touchSessionConnection(config.dataDir, sessionId)
|
|
295
|
+
store.autoAdvance(config.dataDir, sessionId, config.targetRoot)
|
|
296
|
+
const manifest = store.readManifest(config.dataDir, sessionId)
|
|
297
|
+
emitApprovalHandshake(store, config.dataDir, sessionId, manifest, initialDiff)
|
|
298
|
+
if (!manifest) continue
|
|
299
|
+
const waiting = waitingMessage(sessionId, manifest)
|
|
300
|
+
if (waiting !== lastWaiting) {
|
|
301
|
+
console.log(waiting)
|
|
302
|
+
lastWaiting = waiting
|
|
303
|
+
}
|
|
304
|
+
await gate.wait(50)
|
|
200
305
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
|
|
204
|
-
)
|
|
205
|
-
process.exit(2)
|
|
206
|
-
}
|
|
207
|
-
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
306
|
+
} finally {
|
|
307
|
+
gate.close()
|
|
208
308
|
}
|
|
209
309
|
|
|
310
|
+
signalAck(store, config.dataDir, sessionId, 'timeout', 'no visualizer signal')
|
|
210
311
|
console.error('Timed out waiting for visualizer review. Do not modify files.')
|
|
211
312
|
process.exit(3)
|
|
212
313
|
}
|
|
@@ -229,39 +330,44 @@ export async function proposePatch(args) {
|
|
|
229
330
|
process.exit(0)
|
|
230
331
|
}
|
|
231
332
|
|
|
232
|
-
if (!sessionId
|
|
233
|
-
usage('propose-patch', '--session <cursor-chat-id>
|
|
333
|
+
if (!sessionId) {
|
|
334
|
+
usage('propose-patch', '--session <cursor-chat-id> [file.patch|-]')
|
|
234
335
|
}
|
|
235
336
|
|
|
236
|
-
let patchText
|
|
337
|
+
let patchText
|
|
237
338
|
if (patchFile && patchFile !== '-') {
|
|
238
339
|
patchText = fs.readFileSync(path.resolve(cwd, patchFile), 'utf8')
|
|
239
340
|
} else if (patchFile === '-') {
|
|
240
341
|
patchText = fs.readFileSync(0, 'utf8')
|
|
241
342
|
}
|
|
242
343
|
|
|
243
|
-
if (!patchText.trim()) {
|
|
244
|
-
console.error('No unified diff provided. Pass a .patch file or
|
|
344
|
+
if (patchFile && !patchText.trim()) {
|
|
345
|
+
console.error('No unified diff provided. Pass a .patch file, use stdin, or omit the file to record live edits.')
|
|
245
346
|
process.exit(1)
|
|
246
347
|
}
|
|
247
348
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
349
|
+
let recorded
|
|
350
|
+
try {
|
|
351
|
+
recorded = store.appendDiff(config.dataDir, config.targetRoot, {
|
|
352
|
+
sessionId,
|
|
353
|
+
...(patchText !== undefined ? { patchText } : {}),
|
|
354
|
+
})
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error(error instanceof Error ? error.message : error)
|
|
251
357
|
process.exit(1)
|
|
252
358
|
}
|
|
359
|
+
const { entry, manifest } = recorded
|
|
253
360
|
|
|
254
|
-
const
|
|
255
|
-
sessionId,
|
|
256
|
-
|
|
257
|
-
})
|
|
361
|
+
const parsed = patchLib.parseUnifiedPatch(
|
|
362
|
+
store.readDiff(config.dataDir, sessionId, entry),
|
|
363
|
+
)
|
|
258
364
|
|
|
259
365
|
const last = entry.step >= manifest.steps.length
|
|
260
366
|
console.log(
|
|
261
367
|
manifest.phase === 'working'
|
|
262
|
-
? `VISUAL_CODER_STEP_READY
|
|
368
|
+
? `VISUAL_CODER_STEP_READY Recorded live edits as patch ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Do not keep editing until the next EXECUTE. Step by step is off, so the next step is already invoked. Wait again.`
|
|
263
369
|
: last
|
|
264
|
-
? `VISUAL_CODER_STEP_READY
|
|
265
|
-
: `VISUAL_CODER_STEP_READY
|
|
370
|
+
? `VISUAL_CODER_STEP_READY Recorded live edits as patch ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Do not keep editing. Walk the diffs, then Accept proposal to finish.`
|
|
371
|
+
: `VISUAL_CODER_STEP_READY Recorded live edits as patch ${entry.id} for session ${sessionId}, step ${entry.step}/${manifest.steps.length}: ${parsed.files.length} changed, ${parsed.creates.length} added. Immediately run wait-for-approval. Do not explore or plan. Accept proposal invokes the next step; when EXECUTE returns, implement that step at once.`,
|
|
266
372
|
)
|
|
267
373
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jkwd/inbase",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "A first-person 3D map of a codebase, with a visual coding workflow for Cursor.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Joris Kuijper",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"inbase",
|
|
9
|
+
"codebase",
|
|
10
|
+
"visualization",
|
|
11
|
+
"3d",
|
|
12
|
+
"first-person",
|
|
13
|
+
"cursor",
|
|
14
|
+
"devtools",
|
|
15
|
+
"llm"
|
|
16
|
+
],
|
|
5
17
|
"repository": {
|
|
6
18
|
"type": "git",
|
|
7
19
|
"url": "https://github.com/jk-wd/inbase"
|
|
@@ -10,6 +22,9 @@
|
|
|
10
22
|
"bugs": {
|
|
11
23
|
"url": "https://github.com/jk-wd/inbase/issues"
|
|
12
24
|
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
13
28
|
"type": "module",
|
|
14
29
|
"bin": {
|
|
15
30
|
"inbase": "bin/inbase.mjs"
|
|
@@ -28,6 +43,8 @@
|
|
|
28
43
|
"apps/explorer/src/*.css",
|
|
29
44
|
"apps/explorer/src/scene",
|
|
30
45
|
"apps/explorer/src/ui",
|
|
46
|
+
"apps/explorer/scripts/branch-changes.d.ts",
|
|
47
|
+
"apps/explorer/scripts/branch-changes.mjs",
|
|
31
48
|
"apps/explorer/scripts/js-source.mjs",
|
|
32
49
|
"apps/explorer/scripts/open-editor.d.ts",
|
|
33
50
|
"apps/explorer/scripts/open-editor.mjs",
|
|
@@ -37,7 +54,8 @@
|
|
|
37
54
|
"apps/explorer/scripts/session-store.d.ts",
|
|
38
55
|
"apps/explorer/scripts/session-store.mjs",
|
|
39
56
|
"apps/explorer/scripts/target-config.d.ts",
|
|
40
|
-
"apps/explorer/scripts/target-config.mjs"
|
|
57
|
+
"apps/explorer/scripts/target-config.mjs",
|
|
58
|
+
"apps/explorer/scripts/tree-diff.mjs"
|
|
41
59
|
],
|
|
42
60
|
"workspaces": [
|
|
43
61
|
"apps/*"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Attach this chat to the focused Inbase visualizer session
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The user invoked `/inbase`. This is how a chat joins the visualizer session that **Setup LLM session** already created.
|
|
6
|
+
|
|
7
|
+
Do **not** ask for a session id. Do **not** run `inbase start-session`. Do **not** print the "direct chat interaction not allowed" message.
|
|
8
|
+
|
|
9
|
+
1. Attach to the focused visualizer session:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx inbase attach
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
2. Read `VISUAL_CODER_SESSION` from the output. That id is the session to use for every later `inbase` command.
|
|
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 instruction; it does not wait.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bypass Inbase and do the request directly in this chat
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The user invoked `/skipinbase`. Do **not** start or attach an Inbase visual session. Do **not** print the "direct chat interaction not allowed" message.
|
|
6
|
+
|
|
7
|
+
Fulfill this request directly, without the Inbase plan/patch loop:
|
|
8
|
+
|
|
9
|
+
$ARGUMENTS
|