@nexart/codemode-sdk 1.7.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -4,6 +4,66 @@ All notable changes to @nexart/codemode-sdk will be documented in this file.
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.8.0] — 2026-01-24
8
+
9
+ ### Added — Agent-First Runtime Authority Layer
10
+
11
+ **Additive, Non-Breaking Release**
12
+
13
+ This release introduces `createRuntime()` — an agent-first API designed for AI coding assistants (Replit, Lovable, Claude Code) to reliably execute deterministic code without rolling their own PRNG/noise implementations.
14
+
15
+ #### New Runtime API (`createRuntime`)
16
+ - **`createRuntime(options)`** — Create a deterministic runtime instance
17
+ - `seed: string | number` — Seed for deterministic randomness
18
+ - `vars?: number[]` — VAR array (0-100 inputs), defaults to zeros
19
+ - `strict?: boolean` — Enable strict mode (default: false)
20
+ - `mode?: 'static' | 'loop'` — Execution mode (default: 'static')
21
+ - `metadata?: Record<string, any>` — Optional user metadata for digest
22
+
23
+ #### Runtime Methods
24
+ - **`random(): number`** — Deterministic random [0, 1) using Mulberry32
25
+ - **`randomInt(min, max): number`** — Deterministic integer in range
26
+ - **`randomRange(min, max): number`** — Deterministic float in range
27
+ - **`noise(x, y?, z?): number`** — Deterministic Perlin noise
28
+ - **`run(fn): T`** — Execute code with optional strict enforcement
29
+ - **`digest(): string`** — Stable hash for verification (FNV-1a)
30
+ - **`getState(): RuntimeState`** — Canonical state snapshot for replay
31
+
32
+ #### Strict Mode Enforcement
33
+ When `strict: true`, the runtime intercepts non-deterministic APIs during `run()`:
34
+ - `Math.random` → Throws with actionable error message
35
+ - `Date.now` → Throws with actionable error message
36
+ - `performance.now` → Throws with actionable error message
37
+
38
+ Error format: `NEXART_STRICT: Non-deterministic API used: {api}. {guidance}`
39
+
40
+ #### Documentation Updates
41
+ - Added "For AI Coding Agents" section at top of README
42
+ - Added "Determinism Contract" with ✅/❌ checklist
43
+ - Added "Why Not Just Use a PRNG?" comparison table
44
+ - Added "Environment Imports" matrix
45
+ - Simplified license section for clarity
46
+
47
+ #### Examples
48
+ - `examples/basic.ts` — Basic usage demonstration
49
+ - `examples/verify.ts` — Determinism verification tests
50
+ - `npm run example:basic` — Run basic example
51
+ - `npm run example:verify` — Run verification tests
52
+
53
+ #### Package Updates
54
+ - Added keywords: deterministic, reproducible, verifiable, replay, canonical, simulation, procedural, seed, prng, ai-agent, strict-mode
55
+ - Updated description for agent discoverability
56
+
57
+ ### Unchanged
58
+
59
+ - No changes to protocol behavior or determinism
60
+ - No changes to protocol version (remains v1.2.0)
61
+ - No changes to existing APIs (executeCodeMode, createEngine, etc.)
62
+ - Default import remains browser-safe
63
+ - Full backward compatibility with v1.7.x
64
+
65
+ ---
66
+
7
67
  ## [1.7.0] — 2026-01-21
8
68
 
9
69
  ### Added — Browser-Safe Entrypoint + Conditional Exports
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # NexArt Code Mode Runtime SDK
2
2
 
3
- **Version: 1.7.0 (Protocol v1.2.0)**
3
+ **Version: 1.8.0 (Protocol v1.2.0)**
4
4
 
5
5
  ╔══════════════════════════════════════════════════════════════════════════════╗
6
6
  ║ @nexart/codemode-sdk — Canonical Execution Surface ║
@@ -9,7 +9,7 @@
9
9
  ║ ║
10
10
  ║ Protocol: nexart ║
11
11
  ║ Engine: codemode ║
12
- ║ SDK Version: 1.7.0 ║
12
+ ║ SDK Version: 1.8.0 ║
13
13
  ║ Protocol Version: 1.2.0 ║
14
14
  ║ Phase: 3 ║
15
15
  ║ Enforcement: HARD ║
@@ -17,12 +17,90 @@
17
17
 
18
18
  ---
19
19
 
20
- ## Commercial Licensing
20
+ ## For AI Coding Agents (Replit / Lovable / Claude Code)
21
21
 
22
- > **Commercial usage of NexArt Protocol requires a license.**
23
- > **Enforcement is not active yet.**
22
+ **ALWAYS use `createRuntime({ seed, strict: true })` for deterministic execution.**
24
23
 
25
- The SDK is currently provided under the MIT License for all usage. A future version may introduce commercial licensing requirements. See [LICENSE.md](./LICENSE.md) for details.
24
+ ```typescript
25
+ import { createRuntime } from "@nexart/codemode-sdk";
26
+
27
+ const runtime = createRuntime({
28
+ seed: "my-artwork-42",
29
+ vars: [50, 75, 25],
30
+ strict: true, // IMPORTANT: Throws on Math.random, Date.now, etc.
31
+ mode: "static"
32
+ });
33
+
34
+ // Use runtime.random() instead of Math.random()
35
+ const value = runtime.random(); // Deterministic [0, 1)
36
+ const intVal = runtime.randomInt(0, 10); // Deterministic integer
37
+ const n = runtime.noise(x, y); // Deterministic Perlin noise
38
+
39
+ // Verify determinism
40
+ console.log(runtime.digest()); // Stable hash for verification
41
+ console.log(runtime.getState()); // Canonical state snapshot
42
+ ```
43
+
44
+ **Strict mode throws actionable errors:**
45
+ - `NEXART_STRICT: Non-deterministic API used: Math.random. Use runtime.random() instead.`
46
+ - `NEXART_STRICT: Non-deterministic API used: Date.now. Pass time as an input or use deterministic counters.`
47
+ - `NEXART_STRICT: Non-deterministic API used: performance.now.`
48
+
49
+ ---
50
+
51
+ ## Determinism Contract
52
+
53
+ ✅ **Guaranteed:**
54
+ - Same `sdkVersion` + `seed` + `vars` → identical output
55
+ - Cross-environment stable digest (browser, Node.js, CI)
56
+ - Seeded PRNG via `runtime.random()` (Mulberry32)
57
+ - Seeded noise via `runtime.noise()` (Perlin)
58
+
59
+ ❌ **Forbidden (blocked in strict mode):**
60
+ - `Math.random()` — use `runtime.random()` instead
61
+ - `Date.now()` — pass time as input or use frame counters
62
+ - `performance.now()` — use deterministic timing
63
+ - External IO during deterministic runs (not supported)
64
+
65
+ ---
66
+
67
+ ## Why Not Just Use a PRNG?
68
+
69
+ | Feature | Plain PRNG | NexArt Runtime |
70
+ |---------|-----------|----------------|
71
+ | Seeded random | ✅ | ✅ |
72
+ | Seeded noise | ❌ (separate lib) | ✅ built-in |
73
+ | Strict mode (blocks entropy) | ❌ | ✅ |
74
+ | Canonical state snapshot | ❌ | ✅ `getState()` |
75
+ | Cross-env stable digest | ❌ | ✅ `digest()` |
76
+ | VAR protocol (0-100 inputs) | ❌ | ✅ |
77
+ | Replay/verification | Manual | Built-in |
78
+ | Error messages for agents | ❌ | ✅ actionable |
79
+
80
+ **The runtime provides a complete determinism layer, not just random numbers.**
81
+
82
+ ---
83
+
84
+ ## Environment Imports
85
+
86
+ | Environment | Import Path |
87
+ |-------------|-------------|
88
+ | Browser / Vite / Next.js / React | `import { createRuntime } from "@nexart/codemode-sdk"` |
89
+ | Node.js (general use) | `import { createRuntime } from "@nexart/codemode-sdk"` |
90
+ | Node.js server rendering (canvas) | `import { executeCodeMode } from "@nexart/codemode-sdk/node"` |
91
+
92
+ **The default import is always browser-safe.** Node-only features (`executeCodeMode`, `runStaticMode`) require explicit `/node` import.
93
+
94
+ ---
95
+
96
+ ## License
97
+
98
+ **Free for:**
99
+ - Experiments and prototypes
100
+ - Personal projects
101
+ - Open-source projects
102
+
103
+ **Commercial production deployments require a license.** See [LICENSING.md](./LICENSING.md) for details.
26
104
 
27
105
  ---
28
106
 
@@ -62,6 +140,54 @@ The answer is: "Whatever @nexart/codemode-sdk does — that is the protocol."
62
140
 
63
141
  ---
64
142
 
143
+ ## What's New in v1.8.0
144
+
145
+ **Agent-First Runtime Authority Layer**
146
+
147
+ This release introduces `createRuntime()` — an agent-first API designed for AI coding assistants to reliably execute deterministic code.
148
+
149
+ ### New Runtime API
150
+ ```typescript
151
+ import { createRuntime } from "@nexart/codemode-sdk";
152
+
153
+ const runtime = createRuntime({
154
+ seed: "my-seed",
155
+ vars: [50, 75],
156
+ strict: true,
157
+ mode: "static",
158
+ metadata: { artist: "demo" }
159
+ });
160
+
161
+ runtime.random(); // Deterministic PRNG
162
+ runtime.randomInt(0, 100); // Deterministic integer
163
+ runtime.noise(x, y, z); // Deterministic Perlin noise
164
+ runtime.digest(); // Stable hash for verification
165
+ runtime.getState(); // Canonical state snapshot
166
+ runtime.run(() => { ... }); // Execute with strict enforcement
167
+ ```
168
+
169
+ ### Strict Mode
170
+ - Throws actionable errors on `Math.random`, `Date.now`, `performance.now`
171
+ - Only applies during `runtime.run()` — non-invasive
172
+ - Error messages guide agents to correct usage
173
+
174
+ ### Agent-First Documentation
175
+ - "For AI Coding Agents" section at top of README
176
+ - Determinism Contract with ✅/❌ checklist
177
+ - PRNG comparison table
178
+ - Environment import matrix
179
+
180
+ ### Examples
181
+ - `npm run example:basic` — Basic usage demonstration
182
+ - `npm run example:verify` — Determinism verification tests
183
+
184
+ ### No Breaking Changes
185
+ - All existing APIs work unchanged
186
+ - Default import remains browser-safe
187
+ - Protocol version unchanged (v1.2.0)
188
+
189
+ ---
190
+
65
191
  ## What's New in v1.7.0
66
192
 
67
193
  **Browser-Safe Entrypoint + Conditional Exports**
@@ -16,6 +16,6 @@ export { createEngine, } from './engine';
16
16
  /**
17
17
  * SDK Identity
18
18
  */
19
- export declare const SDK_VERSION = "1.7.0";
19
+ export declare const SDK_VERSION = "1.8.0";
20
20
  export declare const SDK_NAME = "@nexart/codemode-sdk";
21
21
  //# sourceMappingURL=core-index.d.ts.map
@@ -22,5 +22,5 @@ export { createEngine, } from './engine';
22
22
  /**
23
23
  * SDK Identity
24
24
  */
25
- export const SDK_VERSION = '1.7.0';
25
+ export const SDK_VERSION = '1.8.0';
26
26
  export const SDK_NAME = '@nexart/codemode-sdk';
@@ -2,7 +2,7 @@
2
2
  * @nexart/codemode-sdk/browser — Browser-Safe Entry Point
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
- * ║ BROWSER-SAFE SDK ENTRY POINT (v1.7.0) ║
5
+ * ║ BROWSER-SAFE SDK ENTRY POINT (v1.8.0) ║
6
6
  * ║ ║
7
7
  * ║ This entrypoint exports ONLY browser-safe modules. ║
8
8
  * ║ It does NOT include static-engine or any Node.js dependencies. ║
@@ -10,6 +10,8 @@
10
10
  * ║ Use this for Vite, React, Next.js, or any browser environment. ║
11
11
  * ║ ║
12
12
  * ║ For Node.js/server: import from '@nexart/codemode-sdk/node' ║
13
+ * ║ ║
14
+ * ║ AI AGENTS: Start with createRuntime({ seed, strict: true }) ║
13
15
  * ╚══════════════════════════════════════════════════════════════════════════╝
14
16
  */
15
17
  export type { RenderMode, RuntimeCanvas, EngineConfig, RenderResult, RunOptions, ProgressInfo, Engine, TimeVariables, ProtocolVariables, ProtocolMetadata, ExecuteCodeModeInput, ExecuteCodeModeResult, NexArtBuilderManifest, } from '../types';
@@ -21,7 +23,9 @@ export { runLoopMode, cancelLoopMode, } from '../loop-engine';
21
23
  export { validateCodeModeSource, } from '../execute';
22
24
  export { createEngine, } from '../engine';
23
25
  export { registerBuilderManifest, } from '../builder-manifest';
24
- export declare const SDK_VERSION = "1.7.0";
26
+ export { createRuntime, NexArtRuntime, RUNTIME_VERSION, } from '../runtime';
27
+ export type { RuntimeOptions, RuntimeState, NexArtRuntime as NexArtRuntimeType, } from '../runtime';
28
+ export declare const SDK_VERSION = "1.8.0";
25
29
  export declare const SDK_NAME = "@nexart/codemode-sdk";
26
30
  export declare const SDK_ENTRY = "browser";
27
31
  /**
@@ -33,5 +37,7 @@ export declare const SDK_ENTRY = "browser";
33
37
  * - Use runLoopMode() directly for animations
34
38
  * - For static rendering, use the server-side endpoint
35
39
  * - Or import from '@nexart/codemode-sdk/node' in SSR contexts
40
+ *
41
+ * AI AGENTS: Use createRuntime({ seed, strict: true }) for deterministic execution.
36
42
  */
37
43
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../entry/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,YAAY,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,cAAc,GACf,MAAM,UAAU,CAAC;AAKlB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,SAAS,EACT,eAAe,GAChB,MAAM,eAAe,CAAC;AAKvB,OAAO,EACL,WAAW,EACX,cAAc,GACf,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,YAAY,GACb,MAAM,WAAW,CAAC;AAKnB,OAAO,EACL,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAK7B,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,QAAQ,yBAAyB,CAAC;AAC/C,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC;;;;;;;;;GASG"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../entry/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,YAAY,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,cAAc,GACf,MAAM,UAAU,CAAC;AAKlB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,SAAS,EACT,eAAe,GAChB,MAAM,eAAe,CAAC;AAKvB,OAAO,EACL,WAAW,EACX,cAAc,GACf,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,YAAY,GACb,MAAM,WAAW,CAAC;AAKnB,OAAO,EACL,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EACL,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,IAAI,iBAAiB,GACnC,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,QAAQ,yBAAyB,CAAC;AAC/C,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC;;;;;;;;;;;GAWG"}
@@ -2,7 +2,7 @@
2
2
  * @nexart/codemode-sdk/browser — Browser-Safe Entry Point
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
- * ║ BROWSER-SAFE SDK ENTRY POINT (v1.7.0) ║
5
+ * ║ BROWSER-SAFE SDK ENTRY POINT (v1.8.0) ║
6
6
  * ║ ║
7
7
  * ║ This entrypoint exports ONLY browser-safe modules. ║
8
8
  * ║ It does NOT include static-engine or any Node.js dependencies. ║
@@ -10,6 +10,8 @@
10
10
  * ║ Use this for Vite, React, Next.js, or any browser environment. ║
11
11
  * ║ ║
12
12
  * ║ For Node.js/server: import from '@nexart/codemode-sdk/node' ║
13
+ * ║ ║
14
+ * ║ AI AGENTS: Start with createRuntime({ seed, strict: true }) ║
13
15
  * ╚══════════════════════════════════════════════════════════════════════════╝
14
16
  */
15
17
  export { PROTOCOL_IDENTITY, DEFAULT_VARS, DEFAULT_CONFIG, } from '../types';
@@ -38,9 +40,13 @@ export { createEngine, } from '../engine';
38
40
  // ═══════════════════════════════════════════════════════════════════════════
39
41
  export { registerBuilderManifest, } from '../builder-manifest';
40
42
  // ═══════════════════════════════════════════════════════════════════════════
43
+ // AGENT-FIRST RUNTIME — v1.8.0 (Browser-safe, no Node dependencies)
44
+ // ═══════════════════════════════════════════════════════════════════════════
45
+ export { createRuntime, NexArtRuntime, RUNTIME_VERSION, } from '../runtime';
46
+ // ═══════════════════════════════════════════════════════════════════════════
41
47
  // SDK IDENTITY
42
48
  // ═══════════════════════════════════════════════════════════════════════════
43
- export const SDK_VERSION = '1.7.0';
49
+ export const SDK_VERSION = '1.8.0';
44
50
  export const SDK_NAME = '@nexart/codemode-sdk';
45
51
  export const SDK_ENTRY = 'browser';
46
52
  /**
@@ -52,4 +58,6 @@ export const SDK_ENTRY = 'browser';
52
58
  * - Use runLoopMode() directly for animations
53
59
  * - For static rendering, use the server-side endpoint
54
60
  * - Or import from '@nexart/codemode-sdk/node' in SSR contexts
61
+ *
62
+ * AI AGENTS: Use createRuntime({ seed, strict: true }) for deterministic execution.
55
63
  */
@@ -2,7 +2,7 @@
2
2
  * @nexart/codemode-sdk/node — Node.js Entry Point
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
- * ║ NODE.JS SDK ENTRY POINT (v1.7.0) ║
5
+ * ║ NODE.JS SDK ENTRY POINT (v1.8.0) ║
6
6
  * ║ ║
7
7
  * ║ This entrypoint exports Node.js-specific modules that require: ║
8
8
  * ║ - canvas package (node-canvas) ║
@@ -11,6 +11,8 @@
11
11
  * ║ Use this for server-side rendering, oracles, or CLI tools. ║
12
12
  * ║ ║
13
13
  * ║ For browser/Vite: import from '@nexart/codemode-sdk/browser' ║
14
+ * ║ ║
15
+ * ║ AI AGENTS: Start with createRuntime({ seed, strict: true }) ║
14
16
  * ╚══════════════════════════════════════════════════════════════════════════╝
15
17
  */
16
18
  export * from './browser';
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../entry/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,cAAc,WAAW,CAAC;AAK1B,OAAO,EACL,aAAa,GACd,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EACL,eAAe,GAChB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAClD,eAAO,MAAM,SAAS,SAAS,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../entry/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,cAAc,WAAW,CAAC;AAK1B,OAAO,EACL,aAAa,GACd,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EACL,eAAe,GAChB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAClD,eAAO,MAAM,SAAS,SAAS,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * @nexart/codemode-sdk/node — Node.js Entry Point
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
- * ║ NODE.JS SDK ENTRY POINT (v1.7.0) ║
5
+ * ║ NODE.JS SDK ENTRY POINT (v1.8.0) ║
6
6
  * ║ ║
7
7
  * ║ This entrypoint exports Node.js-specific modules that require: ║
8
8
  * ║ - canvas package (node-canvas) ║
@@ -11,6 +11,8 @@
11
11
  * ║ Use this for server-side rendering, oracles, or CLI tools. ║
12
12
  * ║ ║
13
13
  * ║ For browser/Vite: import from '@nexart/codemode-sdk/browser' ║
14
+ * ║ ║
15
+ * ║ AI AGENTS: Start with createRuntime({ seed, strict: true }) ║
14
16
  * ╚══════════════════════════════════════════════════════════════════════════╝
15
17
  */
16
18
  // ═══════════════════════════════════════════════════════════════════════════
@@ -0,0 +1,52 @@
1
+ /**
2
+ * NexArt Code Mode SDK - Agent-First Runtime Authority Layer
3
+ * Version: 1.8.0 (Protocol v1.2.0)
4
+ *
5
+ * ╔══════════════════════════════════════════════════════════════════════════╗
6
+ * ║ AGENT-FIRST RUNTIME — DETERMINISTIC EXECUTION AUTHORITY ║
7
+ * ║ ║
8
+ * ║ This module provides a high-level runtime API designed for AI agents ║
9
+ * ║ (Replit, Lovable, Claude Code) to reliably execute deterministic code. ║
10
+ * ║ ║
11
+ * ║ Key Features: ║
12
+ * ║ - Deterministic PRNG: runtime.random() (seeded Mulberry32) ║
13
+ * ║ - Deterministic noise: runtime.noise(x, y?, z?) (seeded Perlin) ║
14
+ * ║ - Strict mode: Throws on Math.random, Date.now, performance.now ║
15
+ * ║ - Digest: Stable hash for verification and replay ║
16
+ * ║ - State snapshot: Canonical state for bundles ║
17
+ * ║ ║
18
+ * ║ BROWSER-SAFE: No Node.js dependencies. Works in Vite/Next/React. ║
19
+ * ╚══════════════════════════════════════════════════════════════════════════╝
20
+ */
21
+ export declare const RUNTIME_VERSION = "1.8.0";
22
+ export interface RuntimeOptions {
23
+ seed: string | number;
24
+ vars?: number[];
25
+ strict?: boolean;
26
+ mode?: 'static' | 'loop';
27
+ metadata?: Record<string, unknown>;
28
+ }
29
+ export interface RuntimeState {
30
+ sdkVersion: string;
31
+ seed: number;
32
+ vars: number[];
33
+ mode: 'static' | 'loop';
34
+ metadata?: Record<string, unknown>;
35
+ }
36
+ export interface NexArtRuntime {
37
+ random(): number;
38
+ randomInt(min: number, max: number): number;
39
+ randomRange(min: number, max: number): number;
40
+ noise(x: number, y?: number, z?: number): number;
41
+ run<T>(fn: () => T): T;
42
+ digest(): string;
43
+ getState(): RuntimeState;
44
+ getSeed(): number;
45
+ readonly strict: boolean;
46
+ }
47
+ export declare function createRuntime(options: RuntimeOptions): NexArtRuntime;
48
+ export declare const NexArtRuntime: {
49
+ create: typeof createRuntime;
50
+ VERSION: string;
51
+ };
52
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,IAAI,MAAM,CAAC;IACjB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9C,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjD,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,IAAI,YAAY,CAAC;IACzB,OAAO,IAAI,MAAM,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAqGD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAuHpE;AAED,eAAO,MAAM,aAAa;;;CAGzB,CAAC"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * NexArt Code Mode SDK - Agent-First Runtime Authority Layer
3
+ * Version: 1.8.0 (Protocol v1.2.0)
4
+ *
5
+ * ╔══════════════════════════════════════════════════════════════════════════╗
6
+ * ║ AGENT-FIRST RUNTIME — DETERMINISTIC EXECUTION AUTHORITY ║
7
+ * ║ ║
8
+ * ║ This module provides a high-level runtime API designed for AI agents ║
9
+ * ║ (Replit, Lovable, Claude Code) to reliably execute deterministic code. ║
10
+ * ║ ║
11
+ * ║ Key Features: ║
12
+ * ║ - Deterministic PRNG: runtime.random() (seeded Mulberry32) ║
13
+ * ║ - Deterministic noise: runtime.noise(x, y?, z?) (seeded Perlin) ║
14
+ * ║ - Strict mode: Throws on Math.random, Date.now, performance.now ║
15
+ * ║ - Digest: Stable hash for verification and replay ║
16
+ * ║ - State snapshot: Canonical state for bundles ║
17
+ * ║ ║
18
+ * ║ BROWSER-SAFE: No Node.js dependencies. Works in Vite/Next/React. ║
19
+ * ╚══════════════════════════════════════════════════════════════════════════╝
20
+ */
21
+ export const RUNTIME_VERSION = '1.8.0';
22
+ function hashSeed(seed) {
23
+ if (typeof seed === 'number') {
24
+ return Math.floor(seed) >>> 0;
25
+ }
26
+ let hash = 0;
27
+ for (let i = 0; i < seed.length; i++) {
28
+ const char = seed.charCodeAt(i);
29
+ hash = ((hash << 5) - hash) + char;
30
+ hash = hash >>> 0;
31
+ }
32
+ return hash || 1;
33
+ }
34
+ function createSeededRNG(seed) {
35
+ let a = seed >>> 0;
36
+ return () => {
37
+ a += 0x6D2B79F5;
38
+ let t = Math.imul(a ^ (a >>> 15), a | 1);
39
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
40
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
41
+ };
42
+ }
43
+ function createSeededNoise(seed) {
44
+ const permutation = [];
45
+ const rng = createSeededRNG(seed);
46
+ for (let i = 0; i < 256; i++) {
47
+ permutation[i] = i;
48
+ }
49
+ for (let i = 255; i > 0; i--) {
50
+ const j = Math.floor(rng() * (i + 1));
51
+ [permutation[i], permutation[j]] = [permutation[j], permutation[i]];
52
+ }
53
+ for (let i = 0; i < 256; i++) {
54
+ permutation[256 + i] = permutation[i];
55
+ }
56
+ const fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
57
+ const lerp = (a, b, t) => a + t * (b - a);
58
+ const grad = (hash, x, y, z) => {
59
+ const h = hash & 15;
60
+ const u = h < 8 ? x : y;
61
+ const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
62
+ return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
63
+ };
64
+ return (x, y = 0, z = 0) => {
65
+ const X = Math.floor(x) & 255;
66
+ const Y = Math.floor(y) & 255;
67
+ const Z = Math.floor(z) & 255;
68
+ x -= Math.floor(x);
69
+ y -= Math.floor(y);
70
+ z -= Math.floor(z);
71
+ const u = fade(x);
72
+ const v = fade(y);
73
+ const w = fade(z);
74
+ const A = permutation[X] + Y;
75
+ const AA = permutation[A] + Z;
76
+ const AB = permutation[A + 1] + Z;
77
+ const B = permutation[X + 1] + Y;
78
+ const BA = permutation[B] + Z;
79
+ const BB = permutation[B + 1] + Z;
80
+ return (lerp(lerp(lerp(grad(permutation[AA], x, y, z), grad(permutation[BA], x - 1, y, z), u), lerp(grad(permutation[AB], x, y - 1, z), grad(permutation[BB], x - 1, y - 1, z), u), v), lerp(lerp(grad(permutation[AA + 1], x, y, z - 1), grad(permutation[BA + 1], x - 1, y, z - 1), u), lerp(grad(permutation[AB + 1], x, y - 1, z - 1), grad(permutation[BB + 1], x - 1, y - 1, z - 1), u), v), w) + 1) / 2;
81
+ };
82
+ }
83
+ function stableStringify(obj) {
84
+ if (obj === null)
85
+ return 'null';
86
+ if (obj === undefined)
87
+ return 'undefined';
88
+ if (typeof obj !== 'object')
89
+ return JSON.stringify(obj);
90
+ if (Array.isArray(obj)) {
91
+ return '[' + obj.map(stableStringify).join(',') + ']';
92
+ }
93
+ const keys = Object.keys(obj).sort();
94
+ const pairs = keys.map(k => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
95
+ return '{' + pairs.join(',') + '}';
96
+ }
97
+ function fnv1aHash(str) {
98
+ let hash = 0x811c9dc5;
99
+ for (let i = 0; i < str.length; i++) {
100
+ hash ^= str.charCodeAt(i);
101
+ hash = Math.imul(hash, 0x01000193);
102
+ }
103
+ const h1 = (hash >>> 0).toString(16).padStart(8, '0');
104
+ let hash2 = 0x811c9dc5;
105
+ for (let i = str.length - 1; i >= 0; i--) {
106
+ hash2 ^= str.charCodeAt(i);
107
+ hash2 = Math.imul(hash2, 0x01000193);
108
+ }
109
+ const h2 = (hash2 >>> 0).toString(16).padStart(8, '0');
110
+ return h1 + h2;
111
+ }
112
+ export function createRuntime(options) {
113
+ const numericSeed = hashSeed(options.seed);
114
+ const vars = options.vars ?? [];
115
+ const mode = options.mode ?? 'static';
116
+ const strict = options.strict ?? false;
117
+ const metadata = options.metadata;
118
+ if (vars.length > 10) {
119
+ throw new Error(`[NexArt Runtime] vars array must have 0-10 elements, got ${vars.length}`);
120
+ }
121
+ for (let i = 0; i < vars.length; i++) {
122
+ if (typeof vars[i] !== 'number' || !Number.isFinite(vars[i])) {
123
+ throw new Error(`[NexArt Runtime] vars[${i}] must be a finite number`);
124
+ }
125
+ if (vars[i] < 0 || vars[i] > 100) {
126
+ throw new Error(`[NexArt Runtime] vars[${i}] must be in range 0-100, got ${vars[i]}`);
127
+ }
128
+ }
129
+ const paddedVars = [...vars];
130
+ while (paddedVars.length < 10) {
131
+ paddedVars.push(0);
132
+ }
133
+ const rng = createSeededRNG(numericSeed);
134
+ const noiseFunc = createSeededNoise(numericSeed);
135
+ const state = {
136
+ sdkVersion: RUNTIME_VERSION,
137
+ seed: numericSeed,
138
+ vars: paddedVars,
139
+ mode,
140
+ ...(metadata !== undefined && { metadata }),
141
+ };
142
+ function random() {
143
+ return rng();
144
+ }
145
+ function randomInt(min, max) {
146
+ const range = max - min + 1;
147
+ return Math.floor(rng() * range) + min;
148
+ }
149
+ function randomRange(min, max) {
150
+ return rng() * (max - min) + min;
151
+ }
152
+ function noise(x, y, z) {
153
+ return noiseFunc(x, y ?? 0, z ?? 0);
154
+ }
155
+ function run(fn) {
156
+ if (!strict) {
157
+ return fn();
158
+ }
159
+ const originalMathRandom = Math.random;
160
+ const originalDateNow = Date.now;
161
+ const hasPerformance = typeof performance !== 'undefined' && performance !== null;
162
+ const originalPerformanceNow = hasPerformance ? performance.now : undefined;
163
+ const throwMathRandom = () => {
164
+ throw new Error('NEXART_STRICT: Non-deterministic API used: Math.random. Use runtime.random() instead.');
165
+ };
166
+ const throwDateNow = () => {
167
+ throw new Error('NEXART_STRICT: Non-deterministic API used: Date.now. Pass time as an input or use deterministic counters.');
168
+ };
169
+ const throwPerformanceNow = () => {
170
+ throw new Error('NEXART_STRICT: Non-deterministic API used: performance.now.');
171
+ };
172
+ try {
173
+ Math.random = throwMathRandom;
174
+ Date.now = throwDateNow;
175
+ if (hasPerformance && originalPerformanceNow) {
176
+ performance.now = throwPerformanceNow;
177
+ }
178
+ return fn();
179
+ }
180
+ finally {
181
+ Math.random = originalMathRandom;
182
+ Date.now = originalDateNow;
183
+ if (hasPerformance && originalPerformanceNow) {
184
+ performance.now = originalPerformanceNow;
185
+ }
186
+ }
187
+ }
188
+ function digest() {
189
+ const input = stableStringify({
190
+ sdkVersion: RUNTIME_VERSION,
191
+ seed: numericSeed,
192
+ vars: paddedVars,
193
+ mode,
194
+ ...(metadata !== undefined && { metadata }),
195
+ });
196
+ return fnv1aHash(input);
197
+ }
198
+ function getState() {
199
+ return { ...state, vars: [...state.vars] };
200
+ }
201
+ function getSeed() {
202
+ return numericSeed;
203
+ }
204
+ return Object.freeze({
205
+ random,
206
+ randomInt,
207
+ randomRange,
208
+ noise,
209
+ run,
210
+ digest,
211
+ getState,
212
+ getSeed,
213
+ strict,
214
+ });
215
+ }
216
+ export const NexArtRuntime = {
217
+ create: createRuntime,
218
+ VERSION: RUNTIME_VERSION,
219
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @nexart/codemode-sdk — Basic Example
3
+ *
4
+ * Demonstrates the agent-first runtime API for deterministic execution.
5
+ *
6
+ * Run: npm run example:basic
7
+ */
8
+
9
+ import { createRuntime } from '../runtime';
10
+
11
+ console.log('╔══════════════════════════════════════════════════════════════╗');
12
+ console.log('║ NexArt Code Mode SDK — Basic Example ║');
13
+ console.log('╚══════════════════════════════════════════════════════════════╝');
14
+ console.log();
15
+
16
+ const runtime = createRuntime({
17
+ seed: 'demo-seed-42',
18
+ vars: [50, 75, 25],
19
+ strict: true,
20
+ mode: 'static',
21
+ metadata: { artist: 'demo', project: 'example' }
22
+ });
23
+
24
+ console.log('Runtime State:');
25
+ console.log(JSON.stringify(runtime.getState(), null, 2));
26
+ console.log();
27
+
28
+ console.log('Digest:', runtime.digest());
29
+ console.log('Seed (numeric):', runtime.getSeed());
30
+ console.log('Strict mode:', runtime.strict);
31
+ console.log();
32
+
33
+ console.log('Deterministic random values:');
34
+ const randoms: number[] = [];
35
+ for (let i = 0; i < 5; i++) {
36
+ const val = runtime.random();
37
+ randoms.push(val);
38
+ console.log(` random() #${i + 1}: ${val.toFixed(8)}`);
39
+ }
40
+ console.log();
41
+
42
+ console.log('Deterministic noise values:');
43
+ for (let i = 0; i < 5; i++) {
44
+ const x = i * 0.5;
45
+ const val = runtime.noise(x, 0.5);
46
+ console.log(` noise(${x}, 0.5): ${val.toFixed(8)}`);
47
+ }
48
+ console.log();
49
+
50
+ console.log('Running code in strict mode...');
51
+ const result = runtime.run(() => {
52
+ let sum = 0;
53
+ for (let i = 0; i < 10; i++) {
54
+ sum += runtime.random();
55
+ }
56
+ return sum;
57
+ });
58
+ console.log(` Sum of 10 random values: ${result.toFixed(8)}`);
59
+ console.log();
60
+
61
+ console.log('✅ Basic example completed successfully!');
@@ -0,0 +1,275 @@
1
+ /**
2
+ * @nexart/codemode-sdk — Preflight Release Tests
3
+ *
4
+ * Extended verification tests for v1.8.0 release validation.
5
+ * Tests strict mode restoration, error messages, and cross-env digest parity.
6
+ *
7
+ * Run: npx tsx examples/preflight-test.ts
8
+ */
9
+
10
+ import { createRuntime, RUNTIME_VERSION } from '../runtime';
11
+
12
+ console.log('╔══════════════════════════════════════════════════════════════╗');
13
+ console.log('║ NexArt Code Mode SDK — Preflight Release Tests ║');
14
+ console.log(`║ Version: ${RUNTIME_VERSION.padEnd(52)}║`);
15
+ console.log('╚══════════════════════════════════════════════════════════════╝');
16
+ console.log();
17
+
18
+ let passCount = 0;
19
+ let failCount = 0;
20
+
21
+ function test(name: string, fn: () => boolean): void {
22
+ try {
23
+ const result = fn();
24
+ if (result) {
25
+ console.log(`✅ PASS: ${name}`);
26
+ passCount++;
27
+ } else {
28
+ console.log(`❌ FAIL: ${name}`);
29
+ failCount++;
30
+ }
31
+ } catch (error: any) {
32
+ console.log(`❌ FAIL: ${name} — ${error.message}`);
33
+ failCount++;
34
+ }
35
+ }
36
+
37
+ console.log('TEST GROUP 1: Strict Mode Restoration on Throw');
38
+ console.log('─'.repeat(60));
39
+
40
+ test('Strict mode restores Math.random after user code throws', () => {
41
+ const runtime = createRuntime({ seed: 12345, strict: true });
42
+ const originalMathRandom = Math.random;
43
+
44
+ try {
45
+ runtime.run(() => {
46
+ throw new Error('User code explosion');
47
+ });
48
+ } catch {
49
+ // Expected
50
+ }
51
+
52
+ const restored = Math.random === originalMathRandom;
53
+ if (!restored) {
54
+ console.log(' ⚠️ Math.random was NOT restored after throw');
55
+ }
56
+ return restored;
57
+ });
58
+
59
+ test('Strict mode restores Date.now after user code throws', () => {
60
+ const runtime = createRuntime({ seed: 12345, strict: true });
61
+ const originalDateNow = Date.now;
62
+
63
+ try {
64
+ runtime.run(() => {
65
+ throw new Error('User code explosion');
66
+ });
67
+ } catch {
68
+ // Expected
69
+ }
70
+
71
+ const restored = Date.now === originalDateNow;
72
+ if (!restored) {
73
+ console.log(' ⚠️ Date.now was NOT restored after throw');
74
+ }
75
+ return restored;
76
+ });
77
+
78
+ test('Strict mode restores performance.now after user code throws', () => {
79
+ const runtime = createRuntime({ seed: 12345, strict: true });
80
+ const hasPerformance = typeof performance !== 'undefined' && performance !== null;
81
+
82
+ if (!hasPerformance) {
83
+ console.log(' ℹ️ performance object not available, skipping');
84
+ return true;
85
+ }
86
+
87
+ const originalPerformanceNow = performance.now;
88
+
89
+ try {
90
+ runtime.run(() => {
91
+ throw new Error('User code explosion');
92
+ });
93
+ } catch {
94
+ // Expected
95
+ }
96
+
97
+ const restored = performance.now === originalPerformanceNow;
98
+ if (!restored) {
99
+ console.log(' ⚠️ performance.now was NOT restored after throw');
100
+ }
101
+ return restored;
102
+ });
103
+
104
+ console.log();
105
+ console.log('TEST GROUP 2: Strict Mode Error Messages');
106
+ console.log('─'.repeat(60));
107
+
108
+ test('Math.random error message is actionable', () => {
109
+ const runtime = createRuntime({ seed: 12345, strict: true });
110
+
111
+ try {
112
+ runtime.run(() => Math.random());
113
+ return false;
114
+ } catch (error: any) {
115
+ const expected = 'NEXART_STRICT: Non-deterministic API used: Math.random. Use runtime.random() instead.';
116
+ const match = error.message === expected;
117
+ if (!match) {
118
+ console.log(` Expected: "${expected}"`);
119
+ console.log(` Got: "${error.message}"`);
120
+ }
121
+ return match;
122
+ }
123
+ });
124
+
125
+ test('Date.now error message is actionable', () => {
126
+ const runtime = createRuntime({ seed: 12345, strict: true });
127
+
128
+ try {
129
+ runtime.run(() => Date.now());
130
+ return false;
131
+ } catch (error: any) {
132
+ const expected = 'NEXART_STRICT: Non-deterministic API used: Date.now. Pass time as an input or use deterministic counters.';
133
+ const match = error.message === expected;
134
+ if (!match) {
135
+ console.log(` Expected: "${expected}"`);
136
+ console.log(` Got: "${error.message}"`);
137
+ }
138
+ return match;
139
+ }
140
+ });
141
+
142
+ test('performance.now error message is actionable', () => {
143
+ const runtime = createRuntime({ seed: 12345, strict: true });
144
+ const hasPerformance = typeof performance !== 'undefined' && performance !== null;
145
+
146
+ if (!hasPerformance) {
147
+ console.log(' ℹ️ performance object not available, skipping');
148
+ return true;
149
+ }
150
+
151
+ try {
152
+ runtime.run(() => performance.now());
153
+ return false;
154
+ } catch (error: any) {
155
+ const expected = 'NEXART_STRICT: Non-deterministic API used: performance.now.';
156
+ const match = error.message === expected;
157
+ if (!match) {
158
+ console.log(` Expected: "${expected}"`);
159
+ console.log(` Got: "${error.message}"`);
160
+ }
161
+ return match;
162
+ }
163
+ });
164
+
165
+ console.log();
166
+ console.log('TEST GROUP 3: Digest Determinism');
167
+ console.log('─'.repeat(60));
168
+
169
+ test('Digest is stable across multiple calls', () => {
170
+ const config = { seed: 'stable-digest-test', vars: [10, 20, 30], mode: 'static' as const };
171
+ const runtime1 = createRuntime(config);
172
+ const runtime2 = createRuntime(config);
173
+
174
+ const digest1 = runtime1.digest();
175
+ const digest2 = runtime2.digest();
176
+
177
+ if (digest1 !== digest2) {
178
+ console.log(` Digest 1: ${digest1}`);
179
+ console.log(` Digest 2: ${digest2}`);
180
+ }
181
+ return digest1 === digest2;
182
+ });
183
+
184
+ test('Digest changes when seed changes', () => {
185
+ const runtime1 = createRuntime({ seed: 'seed-a', vars: [10, 20, 30] });
186
+ const runtime2 = createRuntime({ seed: 'seed-b', vars: [10, 20, 30] });
187
+
188
+ return runtime1.digest() !== runtime2.digest();
189
+ });
190
+
191
+ test('Digest changes when vars change', () => {
192
+ const runtime1 = createRuntime({ seed: 'same-seed', vars: [10, 20, 30] });
193
+ const runtime2 = createRuntime({ seed: 'same-seed', vars: [10, 20, 31] });
194
+
195
+ return runtime1.digest() !== runtime2.digest();
196
+ });
197
+
198
+ test('Digest changes when mode changes', () => {
199
+ const runtime1 = createRuntime({ seed: 'same-seed', vars: [10, 20, 30], mode: 'static' });
200
+ const runtime2 = createRuntime({ seed: 'same-seed', vars: [10, 20, 30], mode: 'loop' });
201
+
202
+ return runtime1.digest() !== runtime2.digest();
203
+ });
204
+
205
+ test('Digest is 16-char hex string', () => {
206
+ const runtime = createRuntime({ seed: 'format-test' });
207
+ const digest = runtime.digest();
208
+ const isValidFormat = /^[0-9a-f]{16}$/.test(digest);
209
+ if (!isValidFormat) {
210
+ console.log(` Digest format invalid: "${digest}"`);
211
+ }
212
+ return isValidFormat;
213
+ });
214
+
215
+ console.log();
216
+ console.log('TEST GROUP 4: PRNG Determinism');
217
+ console.log('─'.repeat(60));
218
+
219
+ test('Same seed produces identical random sequence', () => {
220
+ const seq1: number[] = [];
221
+ const seq2: number[] = [];
222
+
223
+ const runtime1 = createRuntime({ seed: 'prng-test' });
224
+ const runtime2 = createRuntime({ seed: 'prng-test' });
225
+
226
+ for (let i = 0; i < 10; i++) {
227
+ seq1.push(runtime1.random());
228
+ seq2.push(runtime2.random());
229
+ }
230
+
231
+ return seq1.every((v, i) => v === seq2[i]);
232
+ });
233
+
234
+ test('Different seeds produce different sequences', () => {
235
+ const runtime1 = createRuntime({ seed: 'seed-x' });
236
+ const runtime2 = createRuntime({ seed: 'seed-y' });
237
+
238
+ return runtime1.random() !== runtime2.random();
239
+ });
240
+
241
+ test('Noise is deterministic for same inputs', () => {
242
+ const runtime1 = createRuntime({ seed: 'noise-test' });
243
+ const runtime2 = createRuntime({ seed: 'noise-test' });
244
+
245
+ const n1 = runtime1.noise(1.5, 2.5, 3.5);
246
+ const n2 = runtime2.noise(1.5, 2.5, 3.5);
247
+
248
+ return n1 === n2;
249
+ });
250
+
251
+ console.log();
252
+ console.log('TEST GROUP 5: Known Digest Values');
253
+ console.log('─'.repeat(60));
254
+
255
+ const knownConfig = { seed: 'known-digest-oracle', vars: [50, 50, 50, 50, 50, 50, 50, 50, 50, 50], mode: 'static' as const };
256
+ const knownRuntime = createRuntime(knownConfig);
257
+ const oracleDigest = knownRuntime.digest();
258
+ console.log(`Oracle digest for cross-env verification: ${oracleDigest}`);
259
+
260
+ test('Oracle digest format valid', () => {
261
+ return /^[0-9a-f]{16}$/.test(oracleDigest);
262
+ });
263
+
264
+ console.log();
265
+ console.log('═'.repeat(60));
266
+ console.log(`RESULTS: ${passCount} passed, ${failCount} failed`);
267
+ console.log('═'.repeat(60));
268
+
269
+ if (failCount > 0) {
270
+ console.log('❌ PREFLIGHT FAILED - DO NOT SHIP');
271
+ process.exit(1);
272
+ } else {
273
+ console.log('✅ PREFLIGHT PASSED - READY TO SHIP');
274
+ process.exit(0);
275
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @nexart/codemode-sdk — Verification Example
3
+ *
4
+ * Demonstrates determinism verification and strict mode error handling.
5
+ *
6
+ * Run: npm run example:verify
7
+ */
8
+
9
+ import { createRuntime } from '../runtime';
10
+
11
+ console.log('╔══════════════════════════════════════════════════════════════╗');
12
+ console.log('║ NexArt Code Mode SDK — Verification Example ║');
13
+ console.log('╚══════════════════════════════════════════════════════════════╝');
14
+ console.log();
15
+
16
+ function generateRandomSequence(seed: string | number, vars: number[], count: number): number[] {
17
+ const runtime = createRuntime({ seed, vars, strict: true });
18
+ const values: number[] = [];
19
+ for (let i = 0; i < count; i++) {
20
+ values.push(runtime.random());
21
+ }
22
+ return values;
23
+ }
24
+
25
+ console.log('TEST 1: Same seed + vars = same output');
26
+ console.log('─'.repeat(50));
27
+
28
+ const seq1 = generateRandomSequence('test-seed', [50, 25], 5);
29
+ const seq2 = generateRandomSequence('test-seed', [50, 25], 5);
30
+
31
+ console.log('Run 1:', seq1.map(v => v.toFixed(6)).join(', '));
32
+ console.log('Run 2:', seq2.map(v => v.toFixed(6)).join(', '));
33
+
34
+ const identical = seq1.every((v, i) => v === seq2[i]);
35
+ console.log(`Result: ${identical ? '✅ PASS' : '❌ FAIL'} — sequences are ${identical ? 'identical' : 'different'}`);
36
+ console.log();
37
+
38
+ console.log('TEST 2: Same seed + vars = same digest');
39
+ console.log('─'.repeat(50));
40
+
41
+ const runtime1 = createRuntime({ seed: 'digest-test', vars: [10, 20, 30] });
42
+ const runtime2 = createRuntime({ seed: 'digest-test', vars: [10, 20, 30] });
43
+
44
+ const digest1 = runtime1.digest();
45
+ const digest2 = runtime2.digest();
46
+
47
+ console.log('Digest 1:', digest1);
48
+ console.log('Digest 2:', digest2);
49
+
50
+ const digestsMatch = digest1 === digest2;
51
+ console.log(`Result: ${digestsMatch ? '✅ PASS' : '❌ FAIL'} — digests are ${digestsMatch ? 'identical' : 'different'}`);
52
+ console.log();
53
+
54
+ console.log('TEST 3: Different vars = different digest');
55
+ console.log('─'.repeat(50));
56
+
57
+ const runtime3 = createRuntime({ seed: 'digest-test', vars: [10, 20, 30] });
58
+ const runtime4 = createRuntime({ seed: 'digest-test', vars: [10, 20, 31] });
59
+
60
+ const digest3 = runtime3.digest();
61
+ const digest4 = runtime4.digest();
62
+
63
+ console.log('Digest (vars [10,20,30]):', digest3);
64
+ console.log('Digest (vars [10,20,31]):', digest4);
65
+
66
+ const digestsDiffer = digest3 !== digest4;
67
+ console.log(`Result: ${digestsDiffer ? '✅ PASS' : '❌ FAIL'} — digests are ${digestsDiffer ? 'different' : 'identical'}`);
68
+ console.log();
69
+
70
+ console.log('TEST 4: Strict mode blocks Math.random');
71
+ console.log('─'.repeat(50));
72
+
73
+ const strictRuntime = createRuntime({ seed: 12345, strict: true });
74
+
75
+ let strictErrorCaught = false;
76
+ let errorMessage = '';
77
+
78
+ try {
79
+ strictRuntime.run(() => {
80
+ return Math.random();
81
+ });
82
+ } catch (error: any) {
83
+ strictErrorCaught = true;
84
+ errorMessage = error.message;
85
+ }
86
+
87
+ console.log('Called Math.random() in strict run...');
88
+ console.log(`Error caught: ${strictErrorCaught}`);
89
+ if (strictErrorCaught) {
90
+ console.log(`Error message: "${errorMessage}"`);
91
+ }
92
+
93
+ const expectedMessage = 'NEXART_STRICT: Non-deterministic API used: Math.random. Use runtime.random() instead.';
94
+ const correctError = errorMessage === expectedMessage;
95
+ console.log(`Result: ${strictErrorCaught && correctError ? '✅ PASS' : '❌ FAIL'} — strict mode ${strictErrorCaught ? 'blocked' : 'did not block'} Math.random`);
96
+ console.log();
97
+
98
+ console.log('TEST 5: Strict mode blocks Date.now');
99
+ console.log('─'.repeat(50));
100
+
101
+ let dateErrorCaught = false;
102
+ let dateErrorMessage = '';
103
+
104
+ try {
105
+ strictRuntime.run(() => {
106
+ return Date.now();
107
+ });
108
+ } catch (error: any) {
109
+ dateErrorCaught = true;
110
+ dateErrorMessage = error.message;
111
+ }
112
+
113
+ console.log('Called Date.now() in strict run...');
114
+ console.log(`Error caught: ${dateErrorCaught}`);
115
+ if (dateErrorCaught) {
116
+ console.log(`Error message: "${dateErrorMessage}"`);
117
+ }
118
+
119
+ const expectedDateMessage = 'NEXART_STRICT: Non-deterministic API used: Date.now. Pass time as an input or use deterministic counters.';
120
+ const correctDateError = dateErrorMessage === expectedDateMessage;
121
+ console.log(`Result: ${dateErrorCaught && correctDateError ? '✅ PASS' : '❌ FAIL'} — strict mode ${dateErrorCaught ? 'blocked' : 'did not block'} Date.now`);
122
+ console.log();
123
+
124
+ console.log('TEST 6: Non-strict mode allows Math.random');
125
+ console.log('─'.repeat(50));
126
+
127
+ const nonStrictRuntime = createRuntime({ seed: 12345, strict: false });
128
+
129
+ let nonStrictResult: number | null = null;
130
+ let nonStrictError = false;
131
+
132
+ try {
133
+ nonStrictResult = nonStrictRuntime.run(() => {
134
+ return Math.random();
135
+ });
136
+ } catch {
137
+ nonStrictError = true;
138
+ }
139
+
140
+ console.log('Called Math.random() in non-strict run...');
141
+ console.log(`Error thrown: ${nonStrictError}`);
142
+ console.log(`Result value: ${nonStrictResult}`);
143
+ console.log(`Result: ${!nonStrictError && nonStrictResult !== null ? '✅ PASS' : '❌ FAIL'} — non-strict mode ${!nonStrictError ? 'allowed' : 'blocked'} Math.random`);
144
+ console.log();
145
+
146
+ const allPassed = identical && digestsMatch && digestsDiffer && strictErrorCaught && correctError && dateErrorCaught && correctDateError && !nonStrictError;
147
+ console.log('═'.repeat(50));
148
+ console.log(allPassed ? '✅ All verification tests passed!' : '❌ Some tests failed');
149
+ console.log('═'.repeat(50));
150
+
151
+ process.exit(allPassed ? 0 : 1);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexart/codemode-sdk",
3
- "version": "1.7.0",
4
- "description": "NexArt Code Mode SDK - Canonical execution engine for deterministic generative art",
3
+ "version": "1.8.0",
4
+ "description": "NexArt Code Mode SDK - Deterministic, reproducible, verifiable generative art runtime. Agent-first design for AI coding assistants.",
5
5
  "type": "module",
6
6
  "main": "./dist/entry/browser.js",
7
7
  "types": "./dist/entry/browser.d.ts",
@@ -35,15 +35,19 @@
35
35
  },
36
36
  "files": [
37
37
  "dist",
38
+ "examples",
38
39
  "README.md",
39
40
  "CHANGELOG.md",
40
41
  "CODE_MODE_PROTOCOL.md",
41
42
  "LICENSE.md",
43
+ "LICENSING.md",
42
44
  "builder.manifest.schema.json"
43
45
  ],
44
46
  "scripts": {
45
47
  "build": "tsc",
46
48
  "test": "npx tsx smoke-test.ts",
49
+ "example:basic": "npx tsx examples/basic.ts",
50
+ "example:verify": "npx tsx examples/verify.ts",
47
51
  "prepublishOnly": "npm run build && npm run test"
48
52
  },
49
53
  "keywords": [
@@ -52,9 +56,21 @@
52
56
  "nft",
53
57
  "p5js",
54
58
  "deterministic",
59
+ "reproducible",
60
+ "verifiable",
61
+ "replay",
62
+ "canonical",
63
+ "simulation",
64
+ "procedural",
65
+ "generative",
66
+ "seed",
67
+ "prng",
68
+ "noise",
55
69
  "codemode",
56
70
  "browser",
57
- "node"
71
+ "node",
72
+ "ai-agent",
73
+ "strict-mode"
58
74
  ],
59
75
  "author": "NexArt",
60
76
  "license": "MIT",