vectorforce 0.1.0 → 0.2.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/.agents/agents/AGENTS.md +12 -0
- package/.agents/agents/vectorforce-architect.md +35 -0
- package/.agents/agents/vectorforce-auditor.md +25 -0
- package/.agents/agents/vectorforce-samples-builder.md +30 -0
- package/.agents/mcp_config.json +3 -9
- package/.codex/config.toml +0 -3
- package/AGENTS.md +93 -21
- package/README.md +65 -40
- package/bin/vf.js +418 -15
- package/musecode.json +2 -6
- package/package.json +3 -2
- package/src/mcp/harness-config.js +93 -45
- package/src/providers/llm-provider.js +21 -6
- package/src/studio/server.js +312 -4
- package/studio/dist/assets/index-C0_eVpV1.js +9 -0
- package/studio/dist/assets/index-CxTK-2ty.css +2 -0
- package/studio/dist/index.html +2 -2
- package/studio/dist/assets/index-DTKNBk3V.css +0 -2
- package/studio/dist/assets/index-X-wHcJ6r.js +0 -9
package/bin/vf.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { resolve, join, dirname } from 'node:path';
|
|
3
|
+
import { homedir, hostname } from 'node:os';
|
|
4
|
+
import { resolve, join, dirname, basename } from 'node:path';
|
|
5
5
|
import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import {
|
|
7
7
|
SqliteStore,
|
|
@@ -232,8 +232,12 @@ function parseFlags(args) {
|
|
|
232
232
|
flags.decisions.push({
|
|
233
233
|
id: parts[0] || 'DEC',
|
|
234
234
|
title: parts[1] || parts[0],
|
|
235
|
-
rationale: parts
|
|
235
|
+
rationale: parts.slice(2).join(':') || 'Approved architecture decision'
|
|
236
236
|
});
|
|
237
|
+
} else if (arg === '--harness' && args[i + 1]) {
|
|
238
|
+
flags.harness = args[++i];
|
|
239
|
+
} else if (arg === '--author' && args[i + 1]) {
|
|
240
|
+
flags.author = args[++i];
|
|
237
241
|
} else if (arg === '--next' && args[i + 1]) {
|
|
238
242
|
flags.nextSteps.push(args[++i]);
|
|
239
243
|
} else if (arg === '--doc' && args[i + 1]) {
|
|
@@ -260,11 +264,53 @@ function parseFlags(args) {
|
|
|
260
264
|
flags.workspace = resolve(args[++i]);
|
|
261
265
|
} else if (arg === '--db' && args[i + 1]) {
|
|
262
266
|
flags.db = resolve(args[++i]);
|
|
267
|
+
} else if ((arg === '--url' || arg === '--remote') && args[i + 1]) {
|
|
268
|
+
flags.url = args[++i];
|
|
269
|
+
} else if (arg === '--key' && args[i + 1]) {
|
|
270
|
+
flags.key = args[++i];
|
|
271
|
+
} else if (arg === '--project' && args[i + 1]) {
|
|
272
|
+
flags.project = args[++i];
|
|
263
273
|
}
|
|
264
274
|
}
|
|
265
275
|
return flags;
|
|
266
276
|
}
|
|
267
277
|
|
|
278
|
+
function getRemoteConfig(cwd) {
|
|
279
|
+
const defaultUrl = process.env.VF_CLOUD_URL || 'https://omprakash-pce2011--vectorforce-cloud-vectorforce-cloud-web.modal.run';
|
|
280
|
+
const defaultKey = process.env.VF_SUBSCRIPTION_KEY || 'vf_live_sub_98a7bc65f012e4d9';
|
|
281
|
+
const cfgPath = join(cwd, '.vectorforce', 'config.json');
|
|
282
|
+
try {
|
|
283
|
+
if (existsSync(cfgPath)) {
|
|
284
|
+
const parsed = JSON.parse(readFileSync(cfgPath, 'utf8'));
|
|
285
|
+
return {
|
|
286
|
+
remoteUrl: (parsed.remoteUrl || defaultUrl).replace(/\/+$/, ''),
|
|
287
|
+
subscriptionKey: parsed.subscriptionKey || defaultKey,
|
|
288
|
+
remoteProjectId: parsed.remoteProjectId || 'proj-bistro-pos'
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
} catch {}
|
|
292
|
+
return {
|
|
293
|
+
remoteUrl: defaultUrl.replace(/\/+$/, ''),
|
|
294
|
+
subscriptionKey: defaultKey,
|
|
295
|
+
remoteProjectId: 'proj-bistro-pos'
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function saveRemoteConfig(cwd, updates) {
|
|
300
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
301
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
302
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
303
|
+
let existing = {};
|
|
304
|
+
try {
|
|
305
|
+
if (existsSync(cfgPath)) {
|
|
306
|
+
existing = JSON.parse(readFileSync(cfgPath, 'utf8'));
|
|
307
|
+
}
|
|
308
|
+
} catch {}
|
|
309
|
+
const merged = { ...existing, ...updates };
|
|
310
|
+
writeFileSync(cfgPath, JSON.stringify(merged, null, 2), 'utf8');
|
|
311
|
+
return merged;
|
|
312
|
+
}
|
|
313
|
+
|
|
268
314
|
async function main() {
|
|
269
315
|
const args = process.argv.slice(2);
|
|
270
316
|
const command = args[0] || 'help';
|
|
@@ -282,8 +328,20 @@ async function main() {
|
|
|
282
328
|
try {
|
|
283
329
|
switch (command) {
|
|
284
330
|
case 'init': {
|
|
285
|
-
const name = args[1]
|
|
331
|
+
const name = args[1] && !args[1].startsWith('--') ? args[1] : null;
|
|
286
332
|
const project = projectService.initProject(cwd, name);
|
|
333
|
+
HarnessConfig.installAntigravity(cwd);
|
|
334
|
+
HarnessConfig.installCommandCode(cwd);
|
|
335
|
+
HarnessConfig.installMuseCode(cwd);
|
|
336
|
+
HarnessConfig.installCodex(cwd);
|
|
337
|
+
const agentsMdPath = join(cwd, 'AGENTS.md');
|
|
338
|
+
if (!existsSync(agentsMdPath)) {
|
|
339
|
+
writeFileSync(
|
|
340
|
+
agentsMdPath,
|
|
341
|
+
`# Agent Continuity Protocol — ${project.name}\n\nThis repository uses **VectorForce** ("Git for AI Context") across Google Antigravity, Meta Muse, Claude Code, Command Code, and OpenAI Codex.\n\n## Workflow\n1. **Start/Resume Task**: Run \`vf tasks active\`, \`vf drift --task <id>\`, and \`vf resume --task <id> --dest <harness>\` (or MCP tools \`list_tasks\`, \`check_workspace_drift\`, \`get_resume_briefing\`, \`reason_about_task\`).\n2. **Save Checkpoint Before Switching IDE**: Run \`vf checkpoint --task <id> --summary "<summary>" --goal "<goal>" --constraint "<constraint>" --decision "<ID>:<Title>:<Rationale>" --next "<next>" --doc "AGENTS.md"\` (or MCP tool \`save_checkpoint\`).\n`,
|
|
342
|
+
'utf8'
|
|
343
|
+
);
|
|
344
|
+
}
|
|
287
345
|
console.log(`Initialized VectorForce project: ${project.name} (${project.project_id})`);
|
|
288
346
|
break;
|
|
289
347
|
}
|
|
@@ -300,12 +358,14 @@ async function main() {
|
|
|
300
358
|
console.log(`Task marked as completed: ${task.title} (${task.task_id}) [${task.status}]`);
|
|
301
359
|
break;
|
|
302
360
|
}
|
|
303
|
-
const
|
|
361
|
+
const isCreateSub = sub === 'create' || sub === 'add';
|
|
362
|
+
const rawArgs = isCreateSub ? args.slice(2) : args.slice(1);
|
|
363
|
+
const taskId = rawArgs[0];
|
|
304
364
|
if (!taskId) {
|
|
305
365
|
console.error('Error: task id required (e.g. vf task feat-sqlite "Implement SQLite store")');
|
|
306
366
|
process.exit(1);
|
|
307
367
|
}
|
|
308
|
-
const title =
|
|
368
|
+
const title = rawArgs.slice(1).join(' ') || taskId;
|
|
309
369
|
const task = projectService.createTask(cwd, taskId, title);
|
|
310
370
|
console.log(`Task registered: ${task.title} (${task.task_id}) [${task.status}]`);
|
|
311
371
|
break;
|
|
@@ -362,8 +422,8 @@ async function main() {
|
|
|
362
422
|
nextSteps: flags.nextSteps,
|
|
363
423
|
requestedDocuments: flags.docs,
|
|
364
424
|
includeGit: flags.includeGit,
|
|
365
|
-
authorName: process.env.USER || 'developer',
|
|
366
|
-
authorHarness: 'cli'
|
|
425
|
+
authorName: flags.author || process.env.VF_AUTHOR || process.env.USER || 'developer',
|
|
426
|
+
authorHarness: flags.harness || process.env.VF_HARNESS || 'cli'
|
|
367
427
|
});
|
|
368
428
|
console.log(`Checkpoint saved: ${receipt.reference_id} [${receipt.status}]`);
|
|
369
429
|
if (receipt.warnings.length > 0) {
|
|
@@ -508,21 +568,41 @@ async function main() {
|
|
|
508
568
|
const installed = [];
|
|
509
569
|
if (target === 'antigravity' || target === 'all') {
|
|
510
570
|
const p = HarnessConfig.installAntigravity(cwd);
|
|
511
|
-
installed.push(`Antigravity -> ${p}`);
|
|
571
|
+
installed.push(`Google Antigravity -> ${p} (+ ~/.gemini/antigravity/mcp_config.json)`);
|
|
512
572
|
}
|
|
513
|
-
if (target === 'command-code' || target === 'cmd' || target === 'all') {
|
|
573
|
+
if (target === 'command-code' || target === 'cmd' || target === 'claude' || target === 'claude-code' || target === 'all') {
|
|
514
574
|
const p = HarnessConfig.installCommandCode(cwd);
|
|
515
|
-
installed.push(`Command Code -> ${p}`);
|
|
575
|
+
installed.push(`Command Code / Claude Code -> .mcp.json & ${p}`);
|
|
516
576
|
}
|
|
517
577
|
if (target === 'muse' || target === 'muse-code' || target === 'all') {
|
|
518
578
|
const p = HarnessConfig.installMuseCode(cwd);
|
|
519
|
-
installed.push(`Muse
|
|
579
|
+
installed.push(`Meta Muse -> ${p} (+ ~/.config/muse/settings.json)`);
|
|
520
580
|
}
|
|
521
581
|
if (target === 'codex' || target === 'all') {
|
|
522
582
|
const p = HarnessConfig.installCodex(cwd);
|
|
523
|
-
installed.push(`Codex -> ${p}`);
|
|
583
|
+
installed.push(`Codex -> ${p} (+ ~/.codex/config.toml)`);
|
|
524
584
|
}
|
|
525
585
|
console.log(`\n✔ Configured harness integration(s):\n - ${installed.join('\n - ')}`);
|
|
586
|
+
console.log(`\n💡 Next step: Restart or reload your AI agent, then ask in chat:\n "List active VectorForce tasks and check workspace drift"`);
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (sub === 'doctor' || sub === 'check') {
|
|
591
|
+
const checks = [
|
|
592
|
+
{ name: 'SQLite Database (.vectorforce/vectorforce.db)', ok: existsSync(getDbPath(cwd)), path: getDbPath(cwd) },
|
|
593
|
+
{ name: 'Agent Protocol Rules (AGENTS.md)', ok: existsSync(join(cwd, 'AGENTS.md')), path: join(cwd, 'AGENTS.md') },
|
|
594
|
+
{ name: 'Google Antigravity (.agents/mcp_config.json)', ok: existsSync(join(cwd, '.agents', 'mcp_config.json')), path: join(cwd, '.agents', 'mcp_config.json') },
|
|
595
|
+
{ name: 'Claude Code & Command Code (.mcp.json)', ok: existsSync(join(cwd, '.mcp.json')), path: join(cwd, '.mcp.json') },
|
|
596
|
+
{ name: 'Meta Muse (.muse/mcp_config.json)', ok: existsSync(join(cwd, '.muse', 'mcp_config.json')), path: join(cwd, '.muse', 'mcp_config.json') },
|
|
597
|
+
{ name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')), path: join(cwd, '.codex', 'config.toml') }
|
|
598
|
+
];
|
|
599
|
+
console.log(`\nVectorForce Workspace & MCP Health Check (${cwd}):\n`);
|
|
600
|
+
for (const c of checks) {
|
|
601
|
+
console.log(` ${c.ok ? '✔ [READY] ' : '○ [MISSING]'} ${c.name}`);
|
|
602
|
+
}
|
|
603
|
+
console.log(`\nHow to verify inside your AI agent chat:`);
|
|
604
|
+
console.log(` Ask: "Check active VectorForce tasks and workspace drift"`);
|
|
605
|
+
console.log(` Your agent will automatically call MCP tools: list_tasks & check_workspace_drift\n`);
|
|
526
606
|
break;
|
|
527
607
|
}
|
|
528
608
|
|
|
@@ -590,6 +670,32 @@ async function main() {
|
|
|
590
670
|
break;
|
|
591
671
|
}
|
|
592
672
|
|
|
673
|
+
if (sub === 'fireworks') {
|
|
674
|
+
const key = args[2];
|
|
675
|
+
const model = args[3] || 'accounts/fireworks/models/muse-spark-open';
|
|
676
|
+
if (!key) {
|
|
677
|
+
console.error('Usage: node bin/vf.js config fireworks <API_KEY> [MODEL]');
|
|
678
|
+
process.exit(1);
|
|
679
|
+
}
|
|
680
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
681
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
682
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
683
|
+
let existing = {};
|
|
684
|
+
if (existsSync(cfgPath)) {
|
|
685
|
+
try { existing = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch {}
|
|
686
|
+
}
|
|
687
|
+
existing.VF_LLM_PROVIDER = 'fireworks';
|
|
688
|
+
existing.FIREWORKS_API_KEY = key;
|
|
689
|
+
existing.VF_FIREWORKS_MODEL = model;
|
|
690
|
+
existing.VF_FIREWORKS_BASE_URL = 'https://api.fireworks.ai/inference/v1';
|
|
691
|
+
writeFileSync(cfgPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
692
|
+
console.log(`\n✔ Configured Fireworks AI (Meta Muse Spark Open) in ${cfgPath}`);
|
|
693
|
+
console.log(` Provider: fireworks`);
|
|
694
|
+
console.log(` Model: ${model}`);
|
|
695
|
+
console.log(` Base URL: https://api.fireworks.ai/inference/v1`);
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
|
|
593
699
|
if (sub === 'muse') {
|
|
594
700
|
const key = args[2];
|
|
595
701
|
const model = args[3] || 'muse-spark-1.3';
|
|
@@ -615,6 +721,108 @@ async function main() {
|
|
|
615
721
|
break;
|
|
616
722
|
}
|
|
617
723
|
|
|
724
|
+
if (sub === 'ollama') {
|
|
725
|
+
const model = args[2] || 'llama3.1:8b';
|
|
726
|
+
const baseUrl = args[3] || 'http://127.0.0.1:11434';
|
|
727
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
728
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
729
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
730
|
+
let existing = {};
|
|
731
|
+
if (existsSync(cfgPath)) {
|
|
732
|
+
try { existing = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch {}
|
|
733
|
+
}
|
|
734
|
+
existing.VF_LLM_PROVIDER = 'ollama';
|
|
735
|
+
existing.VF_OLLAMA_MODEL = model;
|
|
736
|
+
existing.VF_OLLAMA_BASE_URL = baseUrl;
|
|
737
|
+
writeFileSync(cfgPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
738
|
+
console.log(`\n✔ Configured Local Ollama in ${cfgPath}`);
|
|
739
|
+
console.log(` Provider: ollama (100% Local & Private)`);
|
|
740
|
+
console.log(` Model: ${model}`);
|
|
741
|
+
console.log(` Base URL: ${baseUrl}`);
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (sub === 'openai' || sub === 'codex') {
|
|
746
|
+
const key = args[2];
|
|
747
|
+
const model = args[3] || 'o3-mini';
|
|
748
|
+
const baseUrl = args[4] || 'https://api.openai.com/v1';
|
|
749
|
+
if (!key) {
|
|
750
|
+
console.error('Usage: node bin/vf.js config openai <API_KEY> [MODEL] [BASE_URL]');
|
|
751
|
+
process.exit(1);
|
|
752
|
+
}
|
|
753
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
754
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
755
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
756
|
+
let existing = {};
|
|
757
|
+
if (existsSync(cfgPath)) {
|
|
758
|
+
try { existing = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch {}
|
|
759
|
+
}
|
|
760
|
+
existing.VF_LLM_PROVIDER = 'openai';
|
|
761
|
+
existing.VF_LLM_API_KEY = key;
|
|
762
|
+
existing.VF_LLM_MODEL = model;
|
|
763
|
+
existing.VF_LLM_BASE_URL = baseUrl;
|
|
764
|
+
writeFileSync(cfgPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
765
|
+
console.log(`\n✔ Configured OpenAI in ${cfgPath}`);
|
|
766
|
+
console.log(` Provider: openai`);
|
|
767
|
+
console.log(` Model: ${model}`);
|
|
768
|
+
console.log(` Base URL: ${baseUrl}`);
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (sub === 'anthropic') {
|
|
773
|
+
const key = args[2];
|
|
774
|
+
const model = args[3] || 'claude-sonnet-4-20250514';
|
|
775
|
+
const baseUrl = args[4] || 'https://api.anthropic.com/v1';
|
|
776
|
+
if (!key) {
|
|
777
|
+
console.error('Usage: node bin/vf.js config anthropic <API_KEY> [MODEL] [BASE_URL]');
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
781
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
782
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
783
|
+
let existing = {};
|
|
784
|
+
if (existsSync(cfgPath)) {
|
|
785
|
+
try { existing = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch {}
|
|
786
|
+
}
|
|
787
|
+
existing.VF_LLM_PROVIDER = 'anthropic';
|
|
788
|
+
existing.VF_LLM_API_KEY = key;
|
|
789
|
+
existing.VF_LLM_MODEL = model;
|
|
790
|
+
existing.VF_LLM_BASE_URL = baseUrl;
|
|
791
|
+
writeFileSync(cfgPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
792
|
+
console.log(`\n✔ Configured Anthropic in ${cfgPath}`);
|
|
793
|
+
console.log(` Provider: anthropic`);
|
|
794
|
+
console.log(` Model: ${model}`);
|
|
795
|
+
console.log(` Base URL: ${baseUrl}`);
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (sub === 'byok') {
|
|
800
|
+
const baseUrl = args[2];
|
|
801
|
+
const key = args[3];
|
|
802
|
+
const model = args[4] || 'llama-3.3-70b-versatile';
|
|
803
|
+
if (!baseUrl || !key) {
|
|
804
|
+
console.error('Usage: node bin/vf.js config byok <BASE_URL> <API_KEY> [MODEL]');
|
|
805
|
+
process.exit(1);
|
|
806
|
+
}
|
|
807
|
+
const vfDir = join(cwd, '.vectorforce');
|
|
808
|
+
mkdirSync(vfDir, { recursive: true, mode: 0o700 });
|
|
809
|
+
const cfgPath = join(vfDir, 'config.json');
|
|
810
|
+
let existing = {};
|
|
811
|
+
if (existsSync(cfgPath)) {
|
|
812
|
+
try { existing = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch {}
|
|
813
|
+
}
|
|
814
|
+
existing.VF_LLM_PROVIDER = 'byok';
|
|
815
|
+
existing.VF_LLM_BASE_URL = baseUrl;
|
|
816
|
+
existing.VF_LLM_API_KEY = key;
|
|
817
|
+
existing.VF_LLM_MODEL = model;
|
|
818
|
+
writeFileSync(cfgPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
819
|
+
console.log(`\n✔ Configured Custom BYOK Endpoint in ${cfgPath}`);
|
|
820
|
+
console.log(` Provider: byok`);
|
|
821
|
+
console.log(` Model: ${model}`);
|
|
822
|
+
console.log(` Base URL: ${baseUrl}`);
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
|
|
618
826
|
if (sub === 'show' || sub === 'status') {
|
|
619
827
|
const cfg = resolveLlmConfig(process.env, {}, cwd);
|
|
620
828
|
console.log('\nVectorForce AI Reasoning Configuration:');
|
|
@@ -703,18 +911,213 @@ VectorForce Harness Configuration:
|
|
|
703
911
|
break;
|
|
704
912
|
}
|
|
705
913
|
|
|
914
|
+
case 'remote': {
|
|
915
|
+
const sub = args[1] || 'show';
|
|
916
|
+
if (sub === 'set' || sub === 'add') {
|
|
917
|
+
const urlArg = args[2] && !args[2].startsWith('--') ? args[2] : flags.url;
|
|
918
|
+
if (!urlArg) {
|
|
919
|
+
console.error('Usage: vf remote set <CLOUD_URL> [--key <SUBSCRIPTION_KEY>] [--project <PROJECT_ID>]');
|
|
920
|
+
process.exit(1);
|
|
921
|
+
}
|
|
922
|
+
const saved = saveRemoteConfig(cwd, {
|
|
923
|
+
remoteUrl: urlArg.replace(/\/+$/, ''),
|
|
924
|
+
...(flags.key ? { subscriptionKey: flags.key } : {}),
|
|
925
|
+
...(flags.project ? { remoteProjectId: flags.project } : {})
|
|
926
|
+
});
|
|
927
|
+
console.log(`✔ Remote VectorForce Cloud configured in .vectorforce/config.json:`);
|
|
928
|
+
console.log(` Remote URL: ${saved.remoteUrl}`);
|
|
929
|
+
console.log(` Project ID: ${saved.remoteProjectId || 'proj-bistro-pos'}`);
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
const remote = getRemoteConfig(cwd);
|
|
933
|
+
console.log(`\nVectorForce Cloud Remote (${cwd}):`);
|
|
934
|
+
console.log(` Remote URL: ${remote.remoteUrl}`);
|
|
935
|
+
console.log(` Remote Project: ${remote.remoteProjectId}`);
|
|
936
|
+
console.log(` Subscription Key: ${remote.subscriptionKey.slice(0, 12)}...`);
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
case 'push': {
|
|
941
|
+
const remote = getRemoteConfig(cwd);
|
|
942
|
+
const targetUrl = (flags.url || remote.remoteUrl).replace(/\/+$/, '');
|
|
943
|
+
const remoteProjectId = flags.project || remote.remoteProjectId || 'proj-bistro-pos';
|
|
944
|
+
const project = projectService.getProjectForWorkspace(cwd);
|
|
945
|
+
const tasks = store.listTasks(project.project_id);
|
|
946
|
+
const machineId = `${hostname()}-local`;
|
|
947
|
+
|
|
948
|
+
console.log(`🔄 Pushing local context (${project.name}) -> ${targetUrl} ...`);
|
|
949
|
+
|
|
950
|
+
for (const t of tasks) {
|
|
951
|
+
if (flags.task && t.task_id !== flags.task) continue;
|
|
952
|
+
await fetch(`${targetUrl}/api/cloud/tasks`, {
|
|
953
|
+
method: 'POST',
|
|
954
|
+
headers: {
|
|
955
|
+
'Content-Type': 'application/json',
|
|
956
|
+
Authorization: `Bearer ${remote.subscriptionKey}`
|
|
957
|
+
},
|
|
958
|
+
body: JSON.stringify({
|
|
959
|
+
projectId: remoteProjectId,
|
|
960
|
+
taskId: t.task_id,
|
|
961
|
+
title: t.title || t.task_id,
|
|
962
|
+
assignee: `${process.env.USER || 'developer'}@local-mac`,
|
|
963
|
+
role: `Local Workspace (${basename(cwd)})`,
|
|
964
|
+
priority: 'P0',
|
|
965
|
+
machineId,
|
|
966
|
+
harness: flags.harness || 'antigravity'
|
|
967
|
+
})
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const checkpoints = store.getCheckpoints(project.project_id, { limit: 50 });
|
|
972
|
+
let pushedCount = 0;
|
|
973
|
+
let lastResp = null;
|
|
974
|
+
|
|
975
|
+
for (const cp of checkpoints) {
|
|
976
|
+
if (flags.task && cp.task_id !== flags.task) continue;
|
|
977
|
+
const res = await fetch(`${targetUrl}/api/cloud/sync/push`, {
|
|
978
|
+
method: 'POST',
|
|
979
|
+
headers: {
|
|
980
|
+
'Content-Type': 'application/json',
|
|
981
|
+
Authorization: `Bearer ${remote.subscriptionKey}`
|
|
982
|
+
},
|
|
983
|
+
body: JSON.stringify({
|
|
984
|
+
projectId: remoteProjectId,
|
|
985
|
+
taskId: cp.task_id,
|
|
986
|
+
senderMachineId: machineId,
|
|
987
|
+
recipientMachineId: 'computer-2-meta-muse-cloud',
|
|
988
|
+
authorName: `${cp.author?.name || process.env.USER || 'developer'} (${basename(cwd)})`,
|
|
989
|
+
authorHarness: cp.author?.harness || 'antigravity',
|
|
990
|
+
summary: cp.summary,
|
|
991
|
+
goals: cp.claims?.goals || [],
|
|
992
|
+
constraints: cp.claims?.constraints || [],
|
|
993
|
+
decisions: cp.claims?.decisions || [],
|
|
994
|
+
nextSteps: cp.claims?.next_steps || []
|
|
995
|
+
})
|
|
996
|
+
});
|
|
997
|
+
lastResp = await res.json();
|
|
998
|
+
pushedCount++;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
console.log(`✔ Pushed ${pushedCount} checkpoint(s) [E2EE AES-256-GCM + X25519 + Ed25519] to ${targetUrl}`);
|
|
1002
|
+
if (lastResp?.checkpoint_id) {
|
|
1003
|
+
console.log(` Latest Cloud Checkpoint: ${lastResp.checkpoint_id}`);
|
|
1004
|
+
}
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
case 'pull': {
|
|
1009
|
+
const remote = getRemoteConfig(cwd);
|
|
1010
|
+
const targetUrl = (flags.url || remote.remoteUrl).replace(/\/+$/, '');
|
|
1011
|
+
const remoteProjectId = flags.project || remote.remoteProjectId || 'proj-bistro-pos';
|
|
1012
|
+
|
|
1013
|
+
console.log(`🔓 Pulling & Decrypting latest context from ${targetUrl} ...`);
|
|
1014
|
+
const res = await fetch(`${targetUrl}/api/cloud/sync/pull`, {
|
|
1015
|
+
method: 'POST',
|
|
1016
|
+
headers: {
|
|
1017
|
+
'Content-Type': 'application/json',
|
|
1018
|
+
Authorization: `Bearer ${remote.subscriptionKey}`
|
|
1019
|
+
},
|
|
1020
|
+
body: JSON.stringify({
|
|
1021
|
+
projectId: remoteProjectId,
|
|
1022
|
+
taskId: flags.task || undefined
|
|
1023
|
+
})
|
|
1024
|
+
});
|
|
1025
|
+
const data = await res.json();
|
|
1026
|
+
if (!res.ok || data.verified === false) {
|
|
1027
|
+
console.error(`Error pulling from remote: ${data.error || res.statusText}`);
|
|
1028
|
+
process.exit(1);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
const payload = data.decrypted_on_computer_2?.payload;
|
|
1032
|
+
if (payload) {
|
|
1033
|
+
let project;
|
|
1034
|
+
try {
|
|
1035
|
+
project = projectService.getProjectForWorkspace(cwd);
|
|
1036
|
+
} catch {
|
|
1037
|
+
project = projectService.initProject(cwd, basename(cwd));
|
|
1038
|
+
}
|
|
1039
|
+
const targetTaskId = flags.task || payload.task_id || 'cloud-sync-task';
|
|
1040
|
+
if (!store.getTask(project.project_id, targetTaskId)) {
|
|
1041
|
+
store.createTask(project.project_id, targetTaskId, `Synced Task: ${targetTaskId}`);
|
|
1042
|
+
}
|
|
1043
|
+
const leaves = store.getLeafCheckpoints(project.project_id, targetTaskId);
|
|
1044
|
+
const parentId = leaves.length > 0 ? leaves[0].checkpoint_id : undefined;
|
|
1045
|
+
|
|
1046
|
+
const receipt = checkpointService.captureCheckpoint({
|
|
1047
|
+
workspacePath: cwd,
|
|
1048
|
+
taskId: targetTaskId,
|
|
1049
|
+
parentId,
|
|
1050
|
+
authorName: payload.author?.name || 'cloud-sync',
|
|
1051
|
+
authorHarness: payload.author?.harness || 'muse-code',
|
|
1052
|
+
summary: `[Pulled from Cloud] ${payload.summary}`,
|
|
1053
|
+
goals: payload.claims?.goals?.length ? payload.claims.goals : ['Continue cloud-synced task'],
|
|
1054
|
+
constraints: payload.claims?.constraints || [],
|
|
1055
|
+
decisions: payload.claims?.decisions || [],
|
|
1056
|
+
nextSteps: payload.claims?.next_steps?.length ? payload.claims.next_steps : ['Inspect pulled context'],
|
|
1057
|
+
requestedDocuments: ['AGENTS.md'],
|
|
1058
|
+
includeGit: true
|
|
1059
|
+
});
|
|
1060
|
+
console.log(`✔ Verified Ed25519 signature, decrypted (X25519 + AES-256-GCM), and reconciled into local SQLite!`);
|
|
1061
|
+
console.log(` Local Checkpoint Committed: ${receipt.reference_id} [${receipt.status}]`);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (data.muse_reasoning) {
|
|
1065
|
+
console.log(`\n🧠 Cloud AI Briefing (${data.muse_reasoning.model}):`);
|
|
1066
|
+
console.log(` Summary: ${data.muse_reasoning.where_computer_1_left_off}`);
|
|
1067
|
+
for (const step of data.muse_reasoning.recommended_next_actions_for_computer_2 || []) {
|
|
1068
|
+
console.log(` Next -> ${step}`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
case 'recap':
|
|
1075
|
+
case 'timeline': {
|
|
1076
|
+
const flags = parseFlags(args.slice(1));
|
|
1077
|
+
const days = flags.days ? parseInt(flags.days, 10) : 7;
|
|
1078
|
+
const recap = briefingService.generateRecap({
|
|
1079
|
+
workspacePath: cwd,
|
|
1080
|
+
days,
|
|
1081
|
+
taskId: flags.task,
|
|
1082
|
+
destination: flags.dest || 'cli'
|
|
1083
|
+
});
|
|
1084
|
+
console.log(recap.recapText);
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
case 'doctor':
|
|
1089
|
+
case 'status': {
|
|
1090
|
+
const checks = [
|
|
1091
|
+
{ name: 'SQLite Database (.vectorforce/vectorforce.db)', ok: existsSync(getDbPath(cwd)) },
|
|
1092
|
+
{ name: 'Agent Protocol Rules (AGENTS.md)', ok: existsSync(join(cwd, 'AGENTS.md')) },
|
|
1093
|
+
{ name: 'Google Antigravity (.agents/mcp_config.json)', ok: existsSync(join(cwd, '.agents', 'mcp_config.json')) },
|
|
1094
|
+
{ name: 'Claude Code & Command Code (.mcp.json)', ok: existsSync(join(cwd, '.mcp.json')) },
|
|
1095
|
+
{ name: 'Meta Muse (.muse/mcp_config.json or musecode.json)', ok: existsSync(join(cwd, '.muse', 'mcp_config.json')) || existsSync(join(cwd, 'musecode.json')) },
|
|
1096
|
+
{ name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')) }
|
|
1097
|
+
];
|
|
1098
|
+
console.log(`\nVectorForce Workspace & MCP Status (${cwd}):\n`);
|
|
1099
|
+
for (const c of checks) {
|
|
1100
|
+
console.log(` ${c.ok ? '✔ [READY] ' : '○ [MISSING]'} ${c.name}`);
|
|
1101
|
+
}
|
|
1102
|
+
console.log(`\n💡 How it works:`);
|
|
1103
|
+
console.log(` 1. You do NOT need to run "vf mcp" manually.`);
|
|
1104
|
+
console.log(` 2. Your AI agent (Antigravity, Claude Code, Command Code, Muse, Codex) reads its config file above and automatically spawns "vf mcp" over stdio.`);
|
|
1105
|
+
console.log(` 3. To verify in your AI chat, ask: "List active VectorForce tasks and check workspace drift"\n`);
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
706
1109
|
case 'studio':
|
|
707
1110
|
case 'ui': {
|
|
708
1111
|
const flags = parseFlags(args.slice(1));
|
|
709
1112
|
const port = flags.port || 3210;
|
|
710
1113
|
const studio = createStudioServer({
|
|
711
|
-
dbPath: getDbPath(),
|
|
1114
|
+
dbPath: getDbPath(cwd),
|
|
712
1115
|
workspacePath: cwd,
|
|
713
1116
|
port
|
|
714
1117
|
});
|
|
715
1118
|
const url = await studio.start();
|
|
716
1119
|
console.log(`\n🚀 VectorForce Studio is running at: ${url}`);
|
|
717
|
-
console.log(` Connected to SQLite: ${getDbPath()}`);
|
|
1120
|
+
console.log(` Connected to SQLite: ${getDbPath(cwd)}`);
|
|
718
1121
|
console.log(` Interactive Topology & AI Memory: ${url}`);
|
|
719
1122
|
console.log(` Press Ctrl+C to stop.\n`);
|
|
720
1123
|
|
package/musecode.json
CHANGED
|
@@ -4,14 +4,10 @@
|
|
|
4
4
|
"command": "node",
|
|
5
5
|
"args": [
|
|
6
6
|
"/Users/omprakashprajapat/AgentAI/VectorForce/bin/vf.js",
|
|
7
|
-
"mcp"
|
|
8
|
-
"--workspace",
|
|
9
|
-
"/Users/omprakashprajapat/AgentAI/VectorForce"
|
|
7
|
+
"mcp"
|
|
10
8
|
],
|
|
11
9
|
"env": {
|
|
12
|
-
"VF_HARNESS": "muse-code"
|
|
13
|
-
"VF_WORKSPACE": "/Users/omprakashprajapat/AgentAI/VectorForce",
|
|
14
|
-
"VF_DB_PATH": "/Users/omprakashprajapat/AgentAI/VectorForce/.vectorforce/vectorforce.db"
|
|
10
|
+
"VF_HARNESS": "muse-code"
|
|
15
11
|
}
|
|
16
12
|
}
|
|
17
13
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vectorforce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Portable engineering context platform - Git for AI context",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"vectorforce": "bin/vf.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"test": "node --test test/**/*.test.js"
|
|
12
|
+
"test": "node --test \"test/**/*.test.js\"",
|
|
13
|
+
"test:practical": "node scripts/practical-test-env.js"
|
|
13
14
|
},
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=22.5.0"
|