vectorforce 0.3.4 → 0.3.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.
- package/CHANGELOG.md +12 -1
- package/package.json +1 -1
- package/src/studio/server.js +104 -18
- package/studio/dist/assets/{index-C0_eVpV1.js → index-Cizk5468.js} +1 -1
- package/studio/dist/assets/index-w62XkQKM.css +2 -0
- package/studio/dist/index.html +2 -2
- package/studio/dist/assets/index-CxTK-2ty.css +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## [
|
|
10
|
+
## [0.3.5] - 2026-11-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Dynamic project semantic topology layout and AST import dependency edge mapping in Studio `/api/graph`.
|
|
14
|
+
- Live workspace AST entity symbols extraction and allowlisted document evidence collection (SHA-256 digests and file sizes) in `/api/memory`.
|
|
15
|
+
- Task scope selector and live Git branch/commit/dirty badges in the Studio header.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Studio Project Graph and Memory views now dynamically reflect the active workspace repository rather than fallback mock structures.
|
|
19
|
+
- Dashboard metric cards (Health Score, AI Reasoning, Ontology & Memory, Provenance Chain) and recent checkpoint cards are now interactive and route to their respective views (`timeline`, `settings`, `memory`, `graph`).
|
|
20
|
+
|
|
21
|
+
## [0.3.4] - 2026-11-04
|
|
11
22
|
|
|
12
23
|
### Fixed
|
|
13
24
|
- Cross-platform MCP availability: generated harness configs now use the absolute Node.js runtime (`process.execPath`) with `"type": "stdio"` instead of bare `node`, so GUI-launched clients on Windows, macOS, and Linux can spawn `vf mcp` even when `node` is not on their PATH.
|
package/package.json
CHANGED
package/src/studio/server.js
CHANGED
|
@@ -13,6 +13,7 @@ import { ReasoningService } from '../operations/reasoning-service.js';
|
|
|
13
13
|
import { CodeIndexProvider } from '../providers/code-index-provider.js';
|
|
14
14
|
import { LlmProvider, resolveLlmConfig } from '../providers/llm-provider.js';
|
|
15
15
|
import { GitProvider } from '../providers/git-provider.js';
|
|
16
|
+
import { DocumentProvider } from '../providers/document-provider.js';
|
|
16
17
|
import { HarnessConfig } from '../mcp/harness-config.js';
|
|
17
18
|
|
|
18
19
|
export function createStudioServer({
|
|
@@ -136,7 +137,7 @@ export function createStudioServer({
|
|
|
136
137
|
const allConstraints = new Set();
|
|
137
138
|
|
|
138
139
|
for (const cp of checkpoints) {
|
|
139
|
-
if (cp.claims
|
|
140
|
+
if (cp.claims?.decisions) {
|
|
140
141
|
for (const d of cp.claims.decisions) {
|
|
141
142
|
if (!seenDecisions.has(d.id)) {
|
|
142
143
|
seenDecisions.add(d.id);
|
|
@@ -144,18 +145,58 @@ export function createStudioServer({
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
|
-
if (cp.claims
|
|
148
|
+
if (cp.claims?.constraints) {
|
|
148
149
|
for (const c of cp.claims.constraints) {
|
|
149
150
|
allConstraints.add(c);
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
// Collect allowlisted docs details (sizes, hashes) safely
|
|
156
|
+
let docDetails = [];
|
|
157
|
+
try {
|
|
158
|
+
const collected = DocumentProvider.collect(workspacePath, allowedDocs, allowedDocs);
|
|
159
|
+
docDetails = (collected.documents || []).map(d => ({
|
|
160
|
+
path: d.relative_path,
|
|
161
|
+
size: d.size_bytes ? (d.size_bytes < 1024 ? `${d.size_bytes} B` : `${(d.size_bytes / 1024).toFixed(1)} kB`) : '0 B',
|
|
162
|
+
hash: d.sha256_hash ? d.sha256_hash.slice(0, 10) + '...' : 'tracked',
|
|
163
|
+
status: 'Verified'
|
|
164
|
+
}));
|
|
165
|
+
for (const g of (collected.gaps || [])) {
|
|
166
|
+
docDetails.push({
|
|
167
|
+
path: g.relative_path,
|
|
168
|
+
size: 'Missing',
|
|
169
|
+
hash: 'N/A',
|
|
170
|
+
status: 'File Missing'
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
docDetails = (allowedDocs || []).map(p => ({ path: p, size: 'Tracked', hash: 'allowlisted', status: 'Verified' }));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Extract real top AST symbols from code index
|
|
178
|
+
const topSymbols = [];
|
|
179
|
+
for (const f of codeIndex.files) {
|
|
180
|
+
if (f.symbols) {
|
|
181
|
+
for (const c of (f.symbols.classes || [])) {
|
|
182
|
+
topSymbols.push({ name: c, type: 'Class', file: f.path });
|
|
183
|
+
}
|
|
184
|
+
for (const fn of (f.symbols.functions || [])) {
|
|
185
|
+
topSymbols.push({ name: fn, type: 'Function', file: f.path });
|
|
186
|
+
}
|
|
187
|
+
for (const exp of (f.symbols.exports || [])) {
|
|
188
|
+
topSymbols.push({ name: exp, type: 'Export', file: f.path });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
154
193
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
155
194
|
res.end(JSON.stringify({
|
|
156
195
|
filesIndexed: codeIndex.files.length,
|
|
157
196
|
symbolsIndexed: codeIndex.files.reduce((acc, f) => acc + ((f.symbols?.functions?.length || 0) + (f.symbols?.classes?.length || 0) + (f.symbols?.exports?.length || 0)), 0),
|
|
158
197
|
allowedDocuments: allowedDocs,
|
|
198
|
+
allowedDocsList: docDetails,
|
|
199
|
+
topSymbols: topSymbols.slice(0, 30),
|
|
159
200
|
decisions: allDecisions,
|
|
160
201
|
constraints: Array.from(allConstraints),
|
|
161
202
|
totalCheckpoints: checkpoints.length
|
|
@@ -188,6 +229,12 @@ export function createStudioServer({
|
|
|
188
229
|
const codeIndex = CodeIndexProvider.build(workspacePath);
|
|
189
230
|
const checkpoints = store.getCheckpoints(project.project_id);
|
|
190
231
|
const changedFiles = new Set(GitProvider.collectChangedFiles(workspacePath).files || []);
|
|
232
|
+
const requestedTaskId = url.searchParams.get('taskId') || null;
|
|
233
|
+
|
|
234
|
+
// If a task is selected, get its allowlisted docs or touched files
|
|
235
|
+
const taskCheckpoints = requestedTaskId
|
|
236
|
+
? checkpoints.filter(cp => cp.task_id === requestedTaskId)
|
|
237
|
+
: checkpoints;
|
|
191
238
|
|
|
192
239
|
// Dynamically cluster code files by architectural module
|
|
193
240
|
const moduleMap = new Map();
|
|
@@ -207,7 +254,7 @@ export function createStudioServer({
|
|
|
207
254
|
} else if (file.path.startsWith('bin/')) {
|
|
208
255
|
modId = 'cli';
|
|
209
256
|
} else {
|
|
210
|
-
modId = '
|
|
257
|
+
modId = parts.length > 1 ? parts[0] : 'root';
|
|
211
258
|
}
|
|
212
259
|
|
|
213
260
|
if (!moduleMap.has(modId)) {
|
|
@@ -221,15 +268,26 @@ export function createStudioServer({
|
|
|
221
268
|
'core': 'Core Hashes & Errors',
|
|
222
269
|
'cli': 'Unified CLI Interface',
|
|
223
270
|
'studio-ui': 'React Studio Frontend',
|
|
224
|
-
'tests': 'Automated Test Suite
|
|
225
|
-
'wiki': 'Architecture Wiki
|
|
226
|
-
'
|
|
271
|
+
'tests': 'Automated Test Suite',
|
|
272
|
+
'wiki': 'Architecture Wiki',
|
|
273
|
+
'root': 'Project Root & Config',
|
|
274
|
+
'backend': 'Backend Services',
|
|
275
|
+
'frontend': 'Frontend Application',
|
|
276
|
+
'api': 'API Routes & Handlers',
|
|
277
|
+
'models': 'Data Models & Schemas',
|
|
278
|
+
'controllers': 'Controllers',
|
|
279
|
+
'routes': 'Router Layer',
|
|
280
|
+
'services': 'Domain Services',
|
|
281
|
+
'utils': 'Utility Helpers'
|
|
227
282
|
};
|
|
283
|
+
const capitalizedMod = modId.charAt(0).toUpperCase() + modId.slice(1);
|
|
228
284
|
moduleMap.set(modId, {
|
|
229
285
|
id: modId,
|
|
230
|
-
name: prettyNames[modId] ||
|
|
231
|
-
category: (modId === 'policy' || modId === 'storage'
|
|
232
|
-
|
|
286
|
+
name: prettyNames[modId] || capitalizedMod,
|
|
287
|
+
category: (modId === 'policy' || modId === 'storage' || modId === 'auth' || modId === 'security') ? 'Security' :
|
|
288
|
+
(modId === 'providers' || modId === 'ai' || modId === 'llm') ? 'AI / Copilot' :
|
|
289
|
+
(modId === 'mcp' || modId === 'api' || modId === 'routes') ? 'Integration' : 'Core',
|
|
290
|
+
owner: project.name || 'Workspace',
|
|
233
291
|
files: [],
|
|
234
292
|
drift: false,
|
|
235
293
|
dependencies: new Set(),
|
|
@@ -259,23 +317,51 @@ export function createStudioServer({
|
|
|
259
317
|
|
|
260
318
|
// Link real ADR decisions from checkpoints
|
|
261
319
|
const allDecisions = [];
|
|
262
|
-
for (const cp of
|
|
320
|
+
for (const cp of taskCheckpoints) {
|
|
263
321
|
if (cp.claims?.decisions) {
|
|
264
322
|
for (const d of cp.claims.decisions) {
|
|
265
|
-
allDecisions.push(`${d.id}: ${d.title}`);
|
|
323
|
+
allDecisions.push(`${d.id}: ${d.title || d.rationale || ''}`);
|
|
266
324
|
}
|
|
267
325
|
}
|
|
268
326
|
}
|
|
269
327
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
328
|
+
// Compute clean 2D grid coordinates for modules
|
|
329
|
+
const modArray = Array.from(moduleMap.values());
|
|
330
|
+
const cols = Math.min(3, Math.max(2, Math.ceil(Math.sqrt(modArray.length))));
|
|
331
|
+
const colWidth = 270;
|
|
332
|
+
const rowHeight = 160;
|
|
333
|
+
const startX = 40;
|
|
334
|
+
const startY = 40;
|
|
335
|
+
|
|
336
|
+
const connections = [];
|
|
337
|
+
for (const [fromMod, mod] of moduleMap.entries()) {
|
|
338
|
+
for (const toMod of mod.dependencies) {
|
|
339
|
+
connections.push({ from: fromMod, to: toMod });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const modules = modArray.map((m, idx) => {
|
|
344
|
+
const col = idx % cols;
|
|
345
|
+
const row = Math.floor(idx / cols);
|
|
346
|
+
return {
|
|
347
|
+
...m,
|
|
348
|
+
x: startX + col * colWidth,
|
|
349
|
+
y: startY + row * rowHeight,
|
|
350
|
+
status: m.drift ? 'Drift Detected' : 'Verified',
|
|
351
|
+
dependencies: Array.from(m.dependencies),
|
|
352
|
+
decisions: allDecisions.slice(0, 3),
|
|
353
|
+
files: m.files.length,
|
|
354
|
+
description: `${m.files.length} file${m.files.length === 1 ? '' : 's'} · ${m.symbolsCount} symbols indexed.`
|
|
355
|
+
};
|
|
356
|
+
});
|
|
276
357
|
|
|
277
358
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
278
|
-
res.end(JSON.stringify({
|
|
359
|
+
res.end(JSON.stringify({
|
|
360
|
+
modules,
|
|
361
|
+
connections,
|
|
362
|
+
activeTask: requestedTaskId,
|
|
363
|
+
totalFiles: codeIndex.files.length
|
|
364
|
+
}));
|
|
279
365
|
return;
|
|
280
366
|
}
|
|
281
367
|
|