@intend-it/core 4.0.2 → 4.0.3

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 (3) hide show
  1. package/README.md +23 -12
  2. package/dist/index.js +107 -31
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -114,29 +114,40 @@ interface AIGeneratorOptions {
114
114
  }
115
115
  ```
116
116
 
117
- ## Caching with CAS
117
+ ## 🔒 Build Determinism & Lockfiles
118
118
 
119
- The compiler includes a Content-Addressable Storage system for caching:
119
+ The core package includes a `LockfileManager` that ensures generated code is deterministic and reusable.
120
120
 
121
121
  ```typescript
122
- import { FileSystemCAS, computeHash } from "@intend-it/core";
122
+ import { LockfileManager, computeHash } from "@intend-it/core";
123
123
 
124
- const cas = new FileSystemCAS("./.intend/store");
124
+ const lockManager = new LockfileManager("./intend.lock");
125
125
 
126
- // Check cache
127
- const hash = computeHash(sourceCode, config);
128
- const cached = await cas.get(hash);
126
+ // Calculate hashes
127
+ const sourceHash = computeHash(intentSource);
128
+ const configHash = computeHash(JSON.stringify(config));
129
129
 
130
- if (cached) {
131
- console.log("Cache hit!");
132
- return cached.code;
130
+ // Try to get from lockfile
131
+ const cachedCode = lockManager.getEntry(relativePath, sourceHash, configHash);
132
+
133
+ if (cachedCode) {
134
+ return cachedCode; // Instant build!
133
135
  }
134
136
 
135
- // Generate and cache
137
+ // Generate new code and save to lockfile
136
138
  const result = await generator.generate(ast);
137
- await cas.put(hash, result.code);
139
+ lockManager.setEntry(relativePath, sourceHash, configHash, result.code, {
140
+ model: "gemini-2.0-flash",
141
+ provider: "gemini"
142
+ });
143
+ lockManager.save();
138
144
  ```
139
145
 
146
+ ### Why a Lockfile?
147
+ - **Determinism**: Prevents minor AI fluctuations from changing your production code.
148
+ - **Performance**: Skips expensive LLM calls for unchanged intentions.
149
+ - **Auditability**: Changes to generated code appear in your git diffs, making it easy to review what the AI has changed.
150
+
140
151
  ## Architecture
141
152
 
142
153
  ```
package/dist/index.js CHANGED
@@ -169308,22 +169308,7 @@ Generate ONLY the TypeScript code for this step (no explanations, no markdown).`
169308
169308
  lines.push("");
169309
169309
  }
169310
169310
  lines.push(`Implementation Steps (in order):`);
169311
- context.steps.forEach((step, i) => {
169312
- let line = `${i + 1}. `;
169313
- if (step.type === "Call") {
169314
- const args = step.args.map((a) => a.type === "String" ? JSON.stringify(a.value) : a.value).join(", ");
169315
- line += `Call: ${step.intent}(${args})`;
169316
- } else {
169317
- line += `"${step.instruction}"`;
169318
- }
169319
- if (step.resultVariable) {
169320
- line += ` => const ${step.resultVariable}`;
169321
- if (step.type === "Step" && step.resultType) {
169322
- line += `: ${step.resultType}`;
169323
- }
169324
- }
169325
- lines.push(line);
169326
- });
169311
+ lines.push(this.formatSteps(context.steps, 0));
169327
169312
  lines.push("");
169328
169313
  if (context.ensures.length > 0) {
169329
169314
  lines.push(`Postconditions (must be true at the end):`);
@@ -169360,27 +169345,58 @@ Return ONLY the function body code (no function signature, no markdown).`);
169360
169345
  }
169361
169346
  return type;
169362
169347
  }
169348
+ formatSteps(steps, indentLevel) {
169349
+ const indent = " ".repeat(indentLevel);
169350
+ const lines = [];
169351
+ steps.forEach((step, i) => {
169352
+ let line = `${indent}${i + 1}. `;
169353
+ if (step.type === "Call") {
169354
+ const args = step.args.map((a) => a.type === "String" ? JSON.stringify(a.value) : a.value).join(", ");
169355
+ line += `Call: ${step.intent}(${args})`;
169356
+ } else {
169357
+ line += `"${step.instruction}"`;
169358
+ }
169359
+ if (step.resultVariable) {
169360
+ line += ` => ${step.variableKind || "const"} ${step.resultVariable}`;
169361
+ if (step.type === "Step" && step.resultType) {
169362
+ line += `: ${step.resultType}`;
169363
+ }
169364
+ }
169365
+ lines.push(line);
169366
+ if (step.type === "Step" && step.nestedBody) {
169367
+ lines.push(`${indent} BLOCK START (This step contains a nested logic block):`);
169368
+ lines.push(this.formatSteps(step.nestedBody.steps, indentLevel + 1));
169369
+ lines.push(`${indent} BLOCK END`);
169370
+ }
169371
+ });
169372
+ return lines.join(`
169373
+ `);
169374
+ }
169363
169375
  buildReviewerSystemPrompt() {
169364
- return `You are a senior code reviewer specializing in detecting logical errors in TypeScript.
169376
+ return `You are a pragmatic senior code reviewer specializing in ensuring TypeScript code is functionally correct and safe.
169377
+
169378
+ Your task is to review generated code for logical errors that would cause runtime failures or violate the business intent.
169365
169379
 
169366
- Your task is to review generated function implementations for subtle bugs that pass syntax validation but are logically incorrect.
169380
+ Rules for Approval:
169381
+ - BE PRAGMATIC: If the code is functionally correct and will not crash, APPROVE it.
169382
+ - DO NOT be pedantic about 'step' names. If a step asks to "Call GenerateID" and the code uses "crypto.randomUUID()", this is CORRECT.
169383
+ - DO NOT fail for unused variables (e.g. intermediate variables used in object construction).
169384
+ - DO NOT fail for minor stylistic choices or variable shadowing unless it causes a bug.
169367
169385
 
169368
- Common issues to detect:
169369
- 1. FUNCTION SHADOWING: An inner function with the same name as the outer function, causing the outer to never be called correctly.
169370
- 2. UNUSED VARIABLES: Variables declared but never used or returned.
169371
- 3. MISSING STEP IMPLEMENTATION: Steps mentioned in requirements but not implemented.
169372
- 4. INFINITE LOOPS / RECURSION: Unintended recursive calls or loops with no exit condition.
169373
- 5. TYPE MISMATCHES: Returning wrong type or assigning incompatible types.
169374
- 6. DEAD CODE: Code that can never be reached.
169386
+ Critical Issues to detect (FAIL only for these):
169387
+ 1. BUGGY SHADOWING: An inner variable/function with the same name as the outer, causing a reference error or calling the wrong logic.
169388
+ 2. INFINITE LOOPS: Loops or recursion with no exit condition.
169389
+ 3. LOGIC GAP: The code completely ignores a requirement (e.g. failing to save a record that was requested).
169390
+ 4. CRASH POTENTIAL: Accessing properties of 'undefined' without checks, or unhandled 'null' returns.
169391
+ 5. TYPE CONTRACT VIOLATION: Returning a type that deviates from the signature.
169375
169392
 
169376
169393
  Response Format:
169377
- - If the code is logically correct, respond with exactly: APPROVED
169378
- - If there are issues, respond with:
169394
+ - If functionally correct and safe code, respond with exactly: APPROVED
169395
+ - If there are CRITICAL ISSUES, respond with:
169379
169396
  ISSUES:
169380
- - [Issue 1 description]
169381
- - [Issue 2 description]
169397
+ - [Critical issue description]
169382
169398
  ...
169383
- FIX: [Brief description of what needs to change]`;
169399
+ FIX: [Short description of required fix]`;
169384
169400
  }
169385
169401
  buildReviewerPrompt(context, code) {
169386
169402
  const lines = [];
@@ -170000,7 +170016,8 @@ ${errorMsg}`);
170000
170016
  \uD83D\uDD0D Logic review found issues for ${functionName} (Attempt ${attempts}/${limit}):`);
170001
170017
  console.log(` ${logicIssues.issues.slice(0, 3).join(`
170002
170018
  `)}`);
170003
- console.log(` Retrying with AI auto-correction...
170019
+ console.log(`
170020
+ Retrying with AI auto-correction...
170004
170021
  `);
170005
170022
  prompt += `
170006
170023
 
@@ -170190,6 +170207,64 @@ function computeHash(content, config) {
170190
170207
  hash.update(JSON.stringify(config));
170191
170208
  return hash.digest("hex");
170192
170209
  }
170210
+ // src/lockfile/manager.ts
170211
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
170212
+
170213
+ class LockfileManager {
170214
+ filePath;
170215
+ lockfile;
170216
+ constructor(filePath) {
170217
+ this.filePath = filePath;
170218
+ this.lockfile = this.load();
170219
+ }
170220
+ load() {
170221
+ if (!existsSync2(this.filePath)) {
170222
+ return {
170223
+ version: "1.0",
170224
+ files: {}
170225
+ };
170226
+ }
170227
+ try {
170228
+ const content = readFileSync2(this.filePath, "utf-8");
170229
+ return JSON.parse(content);
170230
+ } catch (error) {
170231
+ console.warn(`Failed to read lockfile at ${this.filePath}. Starting fresh.`);
170232
+ return {
170233
+ version: "1.0",
170234
+ files: {}
170235
+ };
170236
+ }
170237
+ }
170238
+ save() {
170239
+ try {
170240
+ writeFileSync2(this.filePath, JSON.stringify(this.lockfile, null, 2), "utf-8");
170241
+ } catch (error) {
170242
+ throw new Error(`Failed to write lockfile: ${error.message}`);
170243
+ }
170244
+ }
170245
+ getEntry(relativePath, sourceHash, configHash) {
170246
+ const entry = this.lockfile.files[relativePath];
170247
+ if (!entry)
170248
+ return null;
170249
+ if (entry.sourceHash === sourceHash && entry.configHash === configHash) {
170250
+ return entry.generatedCode;
170251
+ }
170252
+ return null;
170253
+ }
170254
+ setEntry(relativePath, sourceHash, configHash, code, metadata) {
170255
+ this.lockfile.files[relativePath] = {
170256
+ sourceHash,
170257
+ configHash,
170258
+ generatedCode: code,
170259
+ model: metadata?.model,
170260
+ provider: metadata?.provider,
170261
+ timestamp: Date.now()
170262
+ };
170263
+ }
170264
+ getLockfile() {
170265
+ return this.lockfile;
170266
+ }
170267
+ }
170193
170268
  export {
170194
170269
  generateTypeScript,
170195
170270
  debugLogger,
@@ -170198,6 +170273,7 @@ export {
170198
170273
  TypeScriptGenerator,
170199
170274
  PromptBuilder,
170200
170275
  OllamaProvider,
170276
+ LockfileManager,
170201
170277
  GeminiProvider,
170202
170278
  GeminiClient,
170203
170279
  FileSystemCAS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intend-it/core",
3
- "version": "4.0.2",
3
+ "version": "4.0.3",
4
4
  "description": "Core compiler and AI integration for the Intend programming language",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@intend-it/parser": "^1.3.2",
38
+ "@intend-it/parser": "^1.3.3",
39
39
  "@google/generative-ai": "^0.21.0"
40
40
  },
41
41
  "devDependencies": {
@@ -43,6 +43,6 @@
43
43
  "typescript": "^5.0.0"
44
44
  },
45
45
  "peerDependencies": {
46
- "@intend-it/parser": ">=1.3.2"
46
+ "@intend-it/parser": ">=1.3.3"
47
47
  }
48
48
  }