vectorforce 0.0.0-stage → 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.
Files changed (37) hide show
  1. package/.agents/agents/AGENTS.md +12 -0
  2. package/.agents/agents/vectorforce-architect.md +35 -0
  3. package/.agents/agents/vectorforce-auditor.md +25 -0
  4. package/.agents/agents/vectorforce-samples-builder.md +30 -0
  5. package/.agents/mcp_config.json +11 -0
  6. package/.codex/config.toml +5 -0
  7. package/AGENTS.md +115 -0
  8. package/LICENSE +21 -0
  9. package/README.md +198 -2
  10. package/bin/vf.js +1159 -0
  11. package/codex.json +14 -0
  12. package/commandcode.json +11 -0
  13. package/musecode.json +14 -0
  14. package/package.json +40 -4
  15. package/src/core/errors.js +45 -0
  16. package/src/core/hash.js +56 -0
  17. package/src/core/types.js +194 -0
  18. package/src/index.js +17 -0
  19. package/src/mcp/harness-config.js +546 -0
  20. package/src/mcp/mcp-server.js +507 -0
  21. package/src/operations/briefing-service.js +313 -0
  22. package/src/operations/checkpoint-service.js +120 -0
  23. package/src/operations/handoff-service.js +343 -0
  24. package/src/operations/project-service.js +132 -0
  25. package/src/operations/reasoning-service.js +356 -0
  26. package/src/policy/authorizer.js +147 -0
  27. package/src/providers/code-index-provider.js +285 -0
  28. package/src/providers/document-provider.js +105 -0
  29. package/src/providers/git-provider.js +98 -0
  30. package/src/providers/llm-provider.js +425 -0
  31. package/src/storage/sqlite-store.js +387 -0
  32. package/src/studio/server.js +764 -0
  33. package/studio/dist/assets/index-C0_eVpV1.js +9 -0
  34. package/studio/dist/assets/index-CxTK-2ty.css +2 -0
  35. package/studio/dist/favicon.svg +1 -0
  36. package/studio/dist/icons.svg +24 -0
  37. package/studio/dist/index.html +17 -0
package/codex.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "vectorforce": {
4
+ "command": "node",
5
+ "args": [
6
+ "/Users/omprakashprajapat/AgentAI/VectorForce/bin/vf.js",
7
+ "mcp"
8
+ ],
9
+ "env": {
10
+ "VF_HARNESS": "codex"
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "vectorforce": {
4
+ "command": "node",
5
+ "args": [
6
+ "/Users/omprakashprajapat/AgentAI/VectorForce/bin/vf.js",
7
+ "mcp"
8
+ ]
9
+ }
10
+ }
11
+ }
package/musecode.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "vectorforce": {
4
+ "command": "node",
5
+ "args": [
6
+ "/Users/omprakashprajapat/AgentAI/VectorForce/bin/vf.js",
7
+ "mcp"
8
+ ],
9
+ "env": {
10
+ "VF_HARNESS": "muse-code"
11
+ }
12
+ }
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "vectorforce",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Portable engineering context platform - Git for AI context",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "vf": "bin/vf.js",
9
+ "vectorforce": "bin/vf.js"
10
+ },
11
+ "scripts": {
12
+ "test": "node --test \"test/**/*.test.js\"",
13
+ "test:practical": "node scripts/practical-test-env.js"
14
+ },
15
+ "engines": {
16
+ "node": ">=22.5.0"
17
+ },
18
+ "files": [
19
+ "bin",
20
+ "src",
21
+ "studio/dist",
22
+ "AGENTS.md",
23
+ "commandcode.json",
24
+ "musecode.json",
25
+ "codex.json",
26
+ ".agents",
27
+ ".codex"
28
+ ],
29
+ "keywords": [
30
+ "context",
31
+ "checkpoints",
32
+ "mcp",
33
+ "antigravity",
34
+ "command-code",
35
+ "codex",
36
+ "ai-agents",
37
+ "reasoning",
38
+ "llama"
39
+ ],
40
+ "author": "",
41
+ "license": "Apache-2.0"
42
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Standardized VectorForce error codes and error class.
3
+ */
4
+
5
+ export const ErrorCode = {
6
+ SCHEMA_VALIDATION_FAILED: 'SCHEMA_VALIDATION_FAILED',
7
+ PROJECT_NOT_INITIALIZED: 'PROJECT_NOT_INITIALIZED',
8
+ PROJECT_ALREADY_EXISTS: 'PROJECT_ALREADY_EXISTS',
9
+ TASK_NOT_FOUND: 'TASK_NOT_FOUND',
10
+ TASK_ALREADY_EXISTS: 'TASK_ALREADY_EXISTS',
11
+ AMBIGUOUS_TASK_SELECTION: 'AMBIGUOUS_TASK_SELECTION',
12
+ PARENT_CHECKPOINT_NOT_FOUND: 'PARENT_CHECKPOINT_NOT_FOUND',
13
+ CROSS_TASK_PARENT_FORBIDDEN: 'CROSS_TASK_PARENT_FORBIDDEN',
14
+ DIVERGENT_HEADS: 'DIVERGENT_HEADS',
15
+ IDEMPOTENT_CONFLICT: 'IDEMPOTENT_CONFLICT',
16
+ POLICY_DENIED: 'POLICY_DENIED',
17
+ PATH_TRAVERSAL_DETECTED: 'PATH_TRAVERSAL_DETECTED',
18
+ DOCUMENT_OUTSIDE_WORKSPACE: 'DOCUMENT_OUTSIDE_WORKSPACE',
19
+ DOCUMENT_TOO_LARGE: 'DOCUMENT_TOO_LARGE',
20
+ TOTAL_DOCUMENTS_TOO_LARGE: 'TOTAL_DOCUMENTS_TOO_LARGE',
21
+ INVALID_DOCUMENT_CONTENT: 'INVALID_DOCUMENT_CONTENT',
22
+ UNAUTHORIZED_DESTINATION: 'UNAUTHORIZED_DESTINATION',
23
+ HANDOFF_VALIDATION_FAILED: 'HANDOFF_VALIDATION_FAILED',
24
+ HANDOFF_INTEGRITY_FAILED: 'HANDOFF_INTEGRITY_FAILED',
25
+ HANDOFF_RECIPIENT_REQUIRED: 'HANDOFF_RECIPIENT_REQUIRED',
26
+ LLM_CONFIG_INVALID: 'LLM_CONFIG_INVALID',
27
+ LLM_UNAVAILABLE: 'LLM_UNAVAILABLE',
28
+ LLM_REQUEST_FAILED: 'LLM_REQUEST_FAILED',
29
+ LLM_RESPONSE_INVALID: 'LLM_RESPONSE_INVALID',
30
+ INTERNAL_STORE_ERROR: 'INTERNAL_STORE_ERROR'
31
+ };
32
+
33
+ export class VectorForceError extends Error {
34
+ /**
35
+ * @param {string} code ErrorCode
36
+ * @param {string} message Human readable explanation
37
+ * @param {object} [details] Optional error details
38
+ */
39
+ constructor(code, message, details = {}) {
40
+ super(`[${code}] ${message}`);
41
+ this.name = 'VectorForceError';
42
+ this.code = code;
43
+ this.details = details;
44
+ }
45
+ }
@@ -0,0 +1,56 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+
3
+ /**
4
+ * Compute SHA-256 hex digest of a string or buffer.
5
+ * @param {string|Buffer} data
6
+ * @returns {string} 64-character lowercase hex string
7
+ */
8
+ export function sha256(data) {
9
+ return createHash('sha256').update(data).digest('hex');
10
+ }
11
+
12
+ /**
13
+ * Generate a random UUIDv4.
14
+ * @returns {string}
15
+ */
16
+ export function generateUuid() {
17
+ return randomUUID();
18
+ }
19
+
20
+ /**
21
+ * Recursively sort keys in an object to produce deterministic JSON.
22
+ * @param {any} value
23
+ * @returns {any}
24
+ */
25
+ export function canonicalizeValue(value) {
26
+ if (value === null || typeof value !== 'object') {
27
+ return value;
28
+ }
29
+ if (Array.isArray(value)) {
30
+ return value.map(canonicalizeValue);
31
+ }
32
+ const sorted = {};
33
+ const keys = Object.keys(value).sort();
34
+ for (const k of keys) {
35
+ sorted[k] = canonicalizeValue(value[k]);
36
+ }
37
+ return sorted;
38
+ }
39
+
40
+ /**
41
+ * Produce deterministic canonical JSON string.
42
+ * @param {any} value
43
+ * @returns {string}
44
+ */
45
+ export function canonicalizeJson(value) {
46
+ return JSON.stringify(canonicalizeValue(value));
47
+ }
48
+
49
+ /**
50
+ * Hash a request payload deterministically for idempotency.
51
+ * @param {any} payload
52
+ * @returns {string} SHA-256 hex
53
+ */
54
+ export function hashRequestPayload(payload) {
55
+ return sha256(canonicalizeJson(payload));
56
+ }
@@ -0,0 +1,194 @@
1
+ import { ErrorCode, VectorForceError } from './errors.js';
2
+
3
+ export const SCHEMA_VERSION_CHECKPOINT = 'vectorforce/checkpoint/v1';
4
+ export const SCHEMA_VERSION_RECEIPT = 'vectorforce/receipt/v1';
5
+ export const SCHEMA_VERSION_HANDOFF = 'vectorforce/handoff/v1';
6
+ export const SCHEMA_VERSION_MANIFEST = 'vectorforce/manifest/v1';
7
+
8
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9
+ const TASK_ID_REGEX = /^[a-z0-9][a-z0-9-_]{1,63}$/;
10
+ const PROJECT_ID_REGEX = /^proj-[a-f0-9]{12,64}$/;
11
+ const SHA256_REGEX = /^[a-f0-9]{64}$/;
12
+ const GIT_SHA_REGEX = /^[a-f0-9]{40}$/;
13
+
14
+ /**
15
+ * Validates a CheckpointRecordV1.
16
+ * Throws VectorForceError if invalid.
17
+ * @param {any} record
18
+ */
19
+ export function validateCheckpoint(record) {
20
+ if (!record || typeof record !== 'object') {
21
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Checkpoint must be an object');
22
+ }
23
+
24
+ if (record.schema_version !== SCHEMA_VERSION_CHECKPOINT) {
25
+ throw new VectorForceError(
26
+ ErrorCode.SCHEMA_VALIDATION_FAILED,
27
+ `Invalid schema_version: expected ${SCHEMA_VERSION_CHECKPOINT}`
28
+ );
29
+ }
30
+
31
+ if (!UUID_REGEX.test(record.checkpoint_id)) {
32
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Invalid checkpoint_id: must be a valid UUID');
33
+ }
34
+
35
+ if (!PROJECT_ID_REGEX.test(record.project_id)) {
36
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Invalid project_id format');
37
+ }
38
+
39
+ if (!TASK_ID_REGEX.test(record.task_id)) {
40
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Invalid task_id: must be lowercase alphanumeric with hyphens/underscores (2-64 chars)');
41
+ }
42
+
43
+ if (record.parent_id !== null && !UUID_REGEX.test(record.parent_id)) {
44
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'parent_id must be null or a valid UUID');
45
+ }
46
+
47
+ if (typeof record.timestamp !== 'string' || isNaN(Date.parse(record.timestamp))) {
48
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Invalid timestamp: must be valid ISO-8601');
49
+ }
50
+
51
+ if (!record.author || typeof record.author !== 'object' || !record.author.name || !record.author.harness) {
52
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'author must contain name and harness');
53
+ }
54
+
55
+ if (typeof record.summary !== 'string' || record.summary.length < 5 || record.summary.length > 1000) {
56
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'summary must be string between 5 and 1000 chars');
57
+ }
58
+
59
+ // Validate Claims
60
+ if (!record.claims || typeof record.claims !== 'object') {
61
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'claims object is required');
62
+ }
63
+ const { goals, constraints, decisions, next_steps, open_questions } = record.claims;
64
+ if (!Array.isArray(goals) || !Array.isArray(constraints) || !Array.isArray(decisions) || !Array.isArray(next_steps)) {
65
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'claims must contain goals, constraints, decisions, and next_steps arrays');
66
+ }
67
+
68
+ // Validate Evidence
69
+ if (!record.evidence || typeof record.evidence !== 'object') {
70
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'evidence object is required');
71
+ }
72
+ const { git, documents, gaps } = record.evidence;
73
+ if (git !== null && git !== undefined) {
74
+ if (!GIT_SHA_REGEX.test(git.commit_hash) || typeof git.is_dirty !== 'boolean') {
75
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Invalid git evidence: commit_hash and is_dirty required');
76
+ }
77
+ }
78
+
79
+ if (documents && !Array.isArray(documents)) {
80
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'documents evidence must be an array');
81
+ }
82
+
83
+ if (documents) {
84
+ for (const doc of documents) {
85
+ if (!doc.path || !SHA256_REGEX.test(doc.sha256) || typeof doc.size_bytes !== 'number' || doc.untrusted_content !== true) {
86
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Document evidence must include path, valid sha256, size_bytes, and untrusted_content: true');
87
+ }
88
+ }
89
+ }
90
+
91
+ if (gaps && !Array.isArray(gaps)) {
92
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'gaps evidence must be an array');
93
+ }
94
+
95
+ return true;
96
+ }
97
+
98
+ /**
99
+ * Validates an OperationReceiptV1.
100
+ * @param {any} receipt
101
+ */
102
+ export function validateReceipt(receipt) {
103
+ if (!receipt || typeof receipt !== 'object') {
104
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'Receipt must be an object');
105
+ }
106
+ if (receipt.schema_version !== SCHEMA_VERSION_RECEIPT) {
107
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, `Invalid receipt schema_version: expected ${SCHEMA_VERSION_RECEIPT}`);
108
+ }
109
+ if (!UUID_REGEX.test(receipt.operation_id)) {
110
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'operation_id must be a valid UUID');
111
+ }
112
+ const validStatuses = ['committed', 'idempotent_replay', 'rejected', 'needs_selection', 'denied'];
113
+ if (!validStatuses.includes(receipt.status)) {
114
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, `Invalid status: ${receipt.status}`);
115
+ }
116
+ if (!SHA256_REGEX.test(receipt.request_hash)) {
117
+ throw new VectorForceError(ErrorCode.SCHEMA_VALIDATION_FAILED, 'request_hash must be a valid SHA-256 hex string');
118
+ }
119
+ return true;
120
+ }
121
+
122
+ /**
123
+ * Validates a HandoffPackageV1.
124
+ * @param {any} handoff
125
+ */
126
+ export function validateHandoff(handoff) {
127
+ if (!handoff || typeof handoff !== 'object') {
128
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'Handoff must be an object');
129
+ }
130
+ if (handoff.schema_version !== SCHEMA_VERSION_HANDOFF) {
131
+ throw new VectorForceError(
132
+ ErrorCode.HANDOFF_VALIDATION_FAILED,
133
+ `Invalid handoff schema_version: expected ${SCHEMA_VERSION_HANDOFF}`
134
+ );
135
+ }
136
+ if (!handoff.package_id || typeof handoff.package_id !== 'string') {
137
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'package_id is required');
138
+ }
139
+ if (typeof handoff.created_at !== 'string' || isNaN(Date.parse(handoff.created_at))) {
140
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'created_at must be valid ISO-8601');
141
+ }
142
+ if (!handoff.origin || typeof handoff.origin !== 'object') {
143
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'origin must be an object');
144
+ }
145
+ if (!handoff.origin.project_name || !handoff.origin.task_id) {
146
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'origin must contain project_name and task_id');
147
+ }
148
+ if (!handoff.disclosure || typeof handoff.disclosure !== 'object' || !handoff.disclosure.recipient) {
149
+ throw new VectorForceError(ErrorCode.HANDOFF_RECIPIENT_REQUIRED, 'disclosure.recipient is required');
150
+ }
151
+ if (!handoff.checkpoint || typeof handoff.checkpoint !== 'object') {
152
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'checkpoint object is required in handoff');
153
+ }
154
+ const { summary, claims, evidence } = handoff.checkpoint;
155
+ if (typeof summary !== 'string' || !claims || !evidence) {
156
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'checkpoint must contain summary, claims, and evidence');
157
+ }
158
+ if (!Array.isArray(claims.goals) || !Array.isArray(claims.constraints) || !Array.isArray(claims.decisions) || !Array.isArray(claims.next_steps)) {
159
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'claims must contain goals, constraints, decisions, and next_steps');
160
+ }
161
+ return true;
162
+ }
163
+
164
+ /**
165
+ * Validates a HandoffManifestV1.
166
+ * @param {any} manifest
167
+ */
168
+ export function validateManifest(manifest) {
169
+ if (!manifest || typeof manifest !== 'object') {
170
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'Manifest must be an object');
171
+ }
172
+ if (manifest.schema_version !== SCHEMA_VERSION_MANIFEST) {
173
+ throw new VectorForceError(
174
+ ErrorCode.HANDOFF_VALIDATION_FAILED,
175
+ `Invalid manifest schema_version: expected ${SCHEMA_VERSION_MANIFEST}`
176
+ );
177
+ }
178
+ if (!manifest.package_id || typeof manifest.package_id !== 'string') {
179
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'Manifest package_id is required');
180
+ }
181
+ if (!Array.isArray(manifest.files) || manifest.files.length === 0) {
182
+ throw new VectorForceError(ErrorCode.HANDOFF_VALIDATION_FAILED, 'Manifest must contain a non-empty files array');
183
+ }
184
+ for (const file of manifest.files) {
185
+ if (!file.path || !SHA256_REGEX.test(file.sha256) || typeof file.size_bytes !== 'number') {
186
+ throw new VectorForceError(
187
+ ErrorCode.HANDOFF_VALIDATION_FAILED,
188
+ 'Manifest file entry must include path, valid sha256, and size_bytes'
189
+ );
190
+ }
191
+ }
192
+ return true;
193
+ }
194
+
package/src/index.js ADDED
@@ -0,0 +1,17 @@
1
+ export * from './core/errors.js';
2
+ export * from './core/hash.js';
3
+ export * from './core/types.js';
4
+ export * from './storage/sqlite-store.js';
5
+ export * from './policy/authorizer.js';
6
+ export * from './providers/git-provider.js';
7
+ export * from './providers/document-provider.js';
8
+ export * from './providers/llm-provider.js';
9
+ export * from './providers/code-index-provider.js';
10
+ export * from './operations/project-service.js';
11
+ export * from './operations/checkpoint-service.js';
12
+ export * from './operations/briefing-service.js';
13
+ export * from './operations/handoff-service.js';
14
+ export * from './operations/reasoning-service.js';
15
+ export * from './mcp/mcp-server.js';
16
+ export * from './mcp/harness-config.js';
17
+ export * from './studio/server.js';