@jkwd/inbase 0.1.4 → 0.1.5

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.
@@ -11,8 +11,10 @@ import { editorFileUri, openInEditor } from './scripts/open-editor.mjs'
11
11
  import {
12
12
  answerBlueprint,
13
13
  continueDiff,
14
+ discardInactiveDiffSessions,
14
15
  inspectTargetFile,
15
16
  invokeStep,
17
+ listSessionIntents,
16
18
  readActiveSession,
17
19
  requestReplan,
18
20
  sendBlueprint,
@@ -45,6 +47,17 @@ function readBody(req: IncomingMessage) {
45
47
  })
46
48
  }
47
49
 
50
+ function rescanTarget(when: string) {
51
+ const scan = spawnSync(process.execPath, [scanScript], {
52
+ cwd: here,
53
+ encoding: 'utf8',
54
+ env: scanEnv,
55
+ })
56
+ if (scan.status !== 0) {
57
+ console.error(scan.stderr || scan.stdout || `scan failed ${when}`)
58
+ }
59
+ }
60
+
48
61
  function knownFileIds() {
49
62
  try {
50
63
  const graph = JSON.parse(fs.readFileSync(codebaseFile, 'utf8')) as {
@@ -68,6 +81,8 @@ function jsonFilePlugin(): Plugin {
68
81
  return {
69
82
  name: 'visual-coder-json-files',
70
83
  configureServer(server) {
84
+ discardInactiveDiffSessions(dataDir, targetRoot)
85
+ rescanTarget('after discarding inactive sessions')
71
86
  server.middlewares.use('/api/user-context', (req, res, next) => {
72
87
  if (req.method === 'GET') {
73
88
  sendJson(res, 200, readUserContext())
@@ -91,12 +106,22 @@ function jsonFilePlugin(): Plugin {
91
106
  server.middlewares.use('/api/agent-intent', (req, res, next) => {
92
107
  if (req.method === 'GET') {
93
108
  const url = new URL(req.url ?? '/', 'http://visual-coder.local')
94
- const sessionId = url.searchParams.get('sessionId') ?? readActiveSession(dataDir)
109
+ const sessionId = url.searchParams.get('sessionId')
95
110
  const diffId = url.searchParams.get('diffId') ?? undefined
96
- const intent = sessionId
97
- ? sessionIntent(dataDir, sessionId, knownFileIds(), diffId)
98
- : null
99
- sendJson(res, 200, intent ?? { ...emptyIntent })
111
+ if (sessionId) {
112
+ const intent = sessionIntent(
113
+ dataDir,
114
+ sessionId,
115
+ knownFileIds(),
116
+ diffId,
117
+ )
118
+ sendJson(res, 200, intent ?? { ...emptyIntent })
119
+ return
120
+ }
121
+ sendJson(res, 200, {
122
+ focusedSessionId: readActiveSession(dataDir),
123
+ intents: listSessionIntents(dataDir, knownFileIds()),
124
+ })
100
125
  return
101
126
  }
102
127
 
@@ -193,28 +218,14 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
193
218
  return
194
219
  }
195
220
  invokeStep(dataDir, body.sessionId, body.step as number, targetRoot)
196
- const scan = spawnSync(process.execPath, [scanScript], {
197
- cwd: here,
198
- encoding: 'utf8',
199
- env: scanEnv,
200
- })
201
- if (scan.status !== 0) {
202
- console.error(scan.stderr || scan.stdout || 'scan failed after invoking step')
203
- }
221
+ rescanTarget('after invoking step')
204
222
  } else if (action === 'continue') {
205
223
  if (!body.diffId) {
206
224
  sendJson(res, 400, { error: 'diffId is required for continue' })
207
225
  return
208
226
  }
209
227
  continueDiff(dataDir, targetRoot, body.sessionId, body.diffId)
210
- const scan = spawnSync(process.execPath, [scanScript], {
211
- cwd: here,
212
- encoding: 'utf8',
213
- env: scanEnv,
214
- })
215
- if (scan.status !== 0) {
216
- console.error(scan.stderr || scan.stdout || 'scan failed after applying patch')
217
- }
228
+ rescanTarget('after applying patch')
218
229
  } else if (action === 'instruct') {
219
230
  if (!body.diffId) {
220
231
  sendJson(res, 400, { error: 'diffId is required for instruct' })
@@ -248,6 +259,7 @@ async function decideIntent(req: IncomingMessage, res: ServerResponse) {
248
259
  })
249
260
  } else {
250
261
  stopSession(dataDir, body.sessionId, targetRoot)
262
+ rescanTarget('after stopping session')
251
263
  }
252
264
  const next = sessionIntent(dataDir, body.sessionId, knownFileIds())
253
265
  sendJson(res, 200, next ?? { ...emptyIntent })
package/bin/session.mjs CHANGED
@@ -52,6 +52,12 @@ export async function waitForBlueprint(args) {
52
52
 
53
53
  const started = Date.now()
54
54
  const initial = store.readManifest(config.dataDir, sessionId)
55
+ if (store.isWorkflowStopped(config.dataDir, sessionId)) {
56
+ console.error(
57
+ 'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
58
+ )
59
+ process.exit(2)
60
+ }
55
61
  if (!initial) {
56
62
  console.error(`No workflow session found for ${sessionId}`)
57
63
  process.exit(1)
@@ -68,6 +74,7 @@ export async function waitForBlueprint(args) {
68
74
  }
69
75
 
70
76
  while (Date.now() - started < timeoutMs) {
77
+ store.touchSessionConnection(config.dataDir, sessionId)
71
78
  const manifest = store.readManifest(config.dataDir, sessionId)
72
79
  if (!manifest || manifest.phase === 'stopped') {
73
80
  console.error(
@@ -81,7 +88,7 @@ export async function waitForBlueprint(args) {
81
88
  const islands = blueprint.userCreatedIslands ?? []
82
89
  console.log(
83
90
  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.`
91
+ ? `VISUAL_CODER_BLUEPRINT_READY The user sent ${blocks.length} file(s) and ${islands.length} island(s) for this chat. 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.`
85
92
  : 'VISUAL_CODER_BLUEPRINT_READY The user skipped the blueprint. Continue without user-placed files or islands.',
86
93
  )
87
94
  console.log('VISUAL_CODER_BLUEPRINT_START')
@@ -131,6 +138,12 @@ export async function waitForApproval(args) {
131
138
  const started = Date.now()
132
139
  const initial = store.readManifest(config.dataDir, sessionId)
133
140
  const initialDiff = initial?.diffs?.at(-1)
141
+ if (store.isWorkflowStopped(config.dataDir, sessionId)) {
142
+ console.error(
143
+ 'VISUAL_CODER_STOPPED The workflow was stopped. Do not modify project files.',
144
+ )
145
+ process.exit(2)
146
+ }
134
147
  if (!initial) {
135
148
  console.error(`No workflow session found for ${sessionId}`)
136
149
  process.exit(1)
@@ -144,6 +157,7 @@ export async function waitForApproval(args) {
144
157
  )
145
158
 
146
159
  while (Date.now() - started < timeoutMs) {
160
+ store.touchSessionConnection(config.dataDir, sessionId)
147
161
  const manifest = store.readManifest(config.dataDir, sessionId)
148
162
  if (!manifest) {
149
163
  console.error(
@@ -173,7 +187,7 @@ export async function waitForApproval(args) {
173
187
  ? `\nVISUAL_CODER_INSTRUCTION_START\n${manifest.pendingInstruction}\nVISUAL_CODER_INSTRUCTION_END`
174
188
  : ''
175
189
  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}`,
190
+ `VISUAL_CODER_REPLAN Keep accepted steps before step ${manifest.currentStep}. Replace the plan from step ${manifest.currentStep} onward using the instruction below. 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}`,
177
191
  )
178
192
  process.exit(4)
179
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jkwd/inbase",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
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",
@@ -48,12 +48,17 @@ npx inbase wait-for-blueprint --session "<current-cursor-chat-id>"
48
48
  3. Read the handshake output between `VISUAL_CODER_BLUEPRINT_START` and
49
49
  `VISUAL_CODER_BLUEPRINT_END`, or read
50
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.
51
+ If `enabled` is true, **the blueprint is leading**. Treat
52
+ `userCreatedBlocks`, `userCreatedIslands`, `addedFunctions`,
53
+ `addedVariables`, and `addedImports` as the source of truth for this chat.
54
+ Create those paths and add those symbols even if they are not on disk.
55
+ They belong to this chat only.
56
+ Do not omit, rename, relocate, or replace a blueprint file, island, symbol,
57
+ or import. Extra edits to existing files are allowed when needed to finish
58
+ the feature. Extra new files that are not in the blueprint are a deviation.
59
+ If the user request, viewpoint, a later instruction, or your own plan would
60
+ differ from the blueprint, **stop and ask the user in chat** before
61
+ reporting the plan. Do not silently deviate.
57
62
  4. Read `.inbase/user-context.json` for viewpoint only.
58
63
  5. Use the user's viewpoint only when `followLook` is true:
59
64
  - `island` is where they are standing
@@ -62,8 +67,8 @@ npx inbase wait-for-blueprint --session "<current-cursor-chat-id>"
62
67
  - `filesOnIsland` is the rest of that folder
63
68
  Prefer those files while `followLook` is true, unless the request clearly
64
69
  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.
70
+ and choose files from the request itself. Viewpoint never overrides the
71
+ blueprint: still follow this session's blueprint when `enabled` is true.
67
72
  6. List **all** steps needed to finish the feature. Keep steps small enough that
68
73
  one patch is one landscape change (usually one new file, or a few related
69
74
  edits).
@@ -136,10 +141,12 @@ npx inbase wait-for-approval --session "<current-cursor-chat-id>"
136
141
  an earlier diff. Follow the text between
137
142
  `VISUAL_CODER_INSTRUCTION_START` and `VISUAL_CODER_INSTRUCTION_END`, read
138
143
  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.
144
+ `addedFunctions`, `addedVariables`, `addedImports`). The blueprint stays
145
+ leading. If the new instruction would differ from it, ask the user before
146
+ replacing the plan. Read `user-context.json` (follow the viewpoint only if
147
+ `followLook` is true), replace the plan from the current step onward using
148
+ `inbase report-plan`, then wait for the user to invoke the first revised
149
+ step.
143
150
  - Exit `2` (`VISUAL_CODER_STOPPED`) or `3` (timeout): make no further
144
151
  project changes.
145
152
 
@@ -154,8 +161,9 @@ npx inbase propose-patch --session "<current-cursor-chat-id>" --clear
154
161
 
155
162
  - Skip `inbase start-session` once this skill applies
156
163
  - 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
164
+ - Treat the chat request, viewpoint, or your own plan as overriding an enabled blueprint
165
+ - Skip, rename, relocate, or replace this session's `blueprint.json` files, islands, functions, variables, or imports when `enabled` is true
166
+ - Silently differ from the blueprint; ask the user first
159
167
  - Read global `user-context.json` for placed files; those live on the session blueprint
160
168
  - Follow the user's look when `followLook` is false
161
169
  - Write, edit, create, or delete project files directly