@intend-it/cli 1.1.2 → 1.1.4
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/dist/index.js +81 -8
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -137,6 +137,7 @@ function printHelp() {
|
|
|
137
137
|
console.log(` ${cmd("--config")} ${dim("<path>")} Path to config file`);
|
|
138
138
|
console.log(` ${cmd("--output")} ${dim("<dir>")} Output directory`);
|
|
139
139
|
console.log(` ${cmd("--provider")} ${dim("<name>")} AI provider ${dim("(gemini | ollama)")}`);
|
|
140
|
+
console.log(` ${cmd("--model")} ${dim("<name>")} AI model name`);
|
|
140
141
|
console.log(` ${cmd("--api-key")} ${dim("<key>")} Gemini API key`);
|
|
141
142
|
console.log(` ${cmd("--force")} Force regeneration (skip cache)`);
|
|
142
143
|
console.log(` ${cmd("--help")} Show this help`);
|
|
@@ -174,7 +175,7 @@ async function initCommand(args) {
|
|
|
174
175
|
text: warn(error2.message)
|
|
175
176
|
});
|
|
176
177
|
}
|
|
177
|
-
const typesPath = join2(
|
|
178
|
+
const typesPath = join2(srcDir, "types.ts");
|
|
178
179
|
if (!existsSync2(typesPath)) {
|
|
179
180
|
const typesContent = `export interface User {
|
|
180
181
|
name: string;
|
|
@@ -182,11 +183,11 @@ async function initCommand(args) {
|
|
|
182
183
|
createdAt: Date;
|
|
183
184
|
}`;
|
|
184
185
|
writeFileSync2(typesPath, typesContent, "utf-8");
|
|
185
|
-
console.log(bullet(`${dim("src/types.ts")} ${dim("(typescript definition)")}`));
|
|
186
|
+
console.log(bullet(`${dim("src/intents/types.ts")} ${dim("(typescript definition)")}`));
|
|
186
187
|
}
|
|
187
188
|
const examplePath = join2(srcDir, "example.intent");
|
|
188
189
|
if (!existsSync2(examplePath)) {
|
|
189
|
-
const exampleContent = `import { User } from "
|
|
190
|
+
const exampleContent = `import { User } from "./types";
|
|
190
191
|
|
|
191
192
|
export intent CreateUser(name: string) -> User {
|
|
192
193
|
step "Generate a random ID" => const id
|
|
@@ -225,9 +226,10 @@ out/
|
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
// src/commands/build.ts
|
|
228
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync2 } from "fs";
|
|
229
|
-
import { join as join3, resolve as resolve3, basename } from "path";
|
|
230
|
-
import { AICodeGenerator, FileSystemCAS, computeHash } from "@intend-it/core";
|
|
229
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync2, copyFileSync } from "fs";
|
|
230
|
+
import { join as join3, resolve as resolve3, dirname, basename } from "path";
|
|
231
|
+
import { AICodeGenerator, FileSystemCAS, computeHash, OllamaProvider } from "@intend-it/core";
|
|
232
|
+
import * as readline from "readline";
|
|
231
233
|
import { parseToAST } from "@intend-it/parser";
|
|
232
234
|
import { readdirSync, statSync } from "fs";
|
|
233
235
|
function findIntentFiles(dir, fileList = []) {
|
|
@@ -247,6 +249,26 @@ function findIntentFiles(dir, fileList = []) {
|
|
|
247
249
|
});
|
|
248
250
|
return fileList;
|
|
249
251
|
}
|
|
252
|
+
function copyResources(src, dest) {
|
|
253
|
+
if (!existsSync3(src))
|
|
254
|
+
return;
|
|
255
|
+
if (!existsSync3(dest))
|
|
256
|
+
mkdirSync2(dest, { recursive: true });
|
|
257
|
+
const entries = readdirSync(src, { withFileTypes: true });
|
|
258
|
+
for (const entry of entries) {
|
|
259
|
+
const srcPath = join3(src, entry.name);
|
|
260
|
+
const destPath = join3(dest, entry.name);
|
|
261
|
+
if (entry.isDirectory()) {
|
|
262
|
+
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
263
|
+
copyResources(srcPath, destPath);
|
|
264
|
+
}
|
|
265
|
+
} else if (entry.isFile()) {
|
|
266
|
+
if (entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
|
|
267
|
+
copyFileSync(srcPath, destPath);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
250
272
|
async function buildCommand(options) {
|
|
251
273
|
const config = loadConfig(options.config);
|
|
252
274
|
if (options.output)
|
|
@@ -255,6 +277,13 @@ async function buildCommand(options) {
|
|
|
255
277
|
config.gemini.apiKey = options.apiKey;
|
|
256
278
|
if (options.provider)
|
|
257
279
|
config.provider = options.provider;
|
|
280
|
+
if (options.model) {
|
|
281
|
+
if (config.provider === "ollama" && config.ollama) {
|
|
282
|
+
config.ollama.model = options.model;
|
|
283
|
+
} else if (config.gemini) {
|
|
284
|
+
config.gemini.model = options.model;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
258
287
|
const sourceDir = resolve3(process.cwd(), config.sourceDir);
|
|
259
288
|
const outDir = resolve3(process.cwd(), config.outDir);
|
|
260
289
|
const providerName = config.provider || "gemini";
|
|
@@ -325,6 +354,42 @@ async function buildCommand(options) {
|
|
|
325
354
|
connectSpinner.fail(error(`Connection failed: ${error2.message}`));
|
|
326
355
|
process.exit(1);
|
|
327
356
|
}
|
|
357
|
+
const provider = generator.getProvider();
|
|
358
|
+
if (provider instanceof OllamaProvider) {
|
|
359
|
+
const ollama = provider;
|
|
360
|
+
if (typeof ollama.checkModelExists === "function") {
|
|
361
|
+
const exists = await ollama.checkModelExists();
|
|
362
|
+
if (!exists) {
|
|
363
|
+
const modelName = config.ollama?.model || "llama3";
|
|
364
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
365
|
+
console.log();
|
|
366
|
+
const answer = await new Promise((resolve4) => {
|
|
367
|
+
rl.question(` ${icons.info} Model '${accent(modelName)}' is not found locally.
|
|
368
|
+
${dim("Do you want to pull it now? [Y/n]")} `, resolve4);
|
|
369
|
+
});
|
|
370
|
+
rl.close();
|
|
371
|
+
if (answer.toLowerCase() === "n") {
|
|
372
|
+
printError("Model missing, cannot proceed.");
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
const pullSpinner = spinner(`Pulling ${modelName}...`).start();
|
|
376
|
+
try {
|
|
377
|
+
await ollama.pullModel((status, completed, total) => {
|
|
378
|
+
if (completed && total) {
|
|
379
|
+
const percent = Math.round(completed / total * 100);
|
|
380
|
+
pullSpinner.text = `Pulling ${modelName}: ${status} ${percent}%`;
|
|
381
|
+
} else {
|
|
382
|
+
pullSpinner.text = `Pulling ${modelName}: ${status}`;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
pullSpinner.succeed(`${modelName} ready`);
|
|
386
|
+
} catch (e) {
|
|
387
|
+
pullSpinner.fail(`Failed to pull model: ${e.message}`);
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
328
393
|
const casDir = resolve3(process.cwd(), ".intend", "store");
|
|
329
394
|
const cas = new FileSystemCAS(casDir);
|
|
330
395
|
let successCount = 0;
|
|
@@ -333,14 +398,18 @@ async function buildCommand(options) {
|
|
|
333
398
|
if (!existsSync3(outDir)) {
|
|
334
399
|
mkdirSync2(outDir, { recursive: true });
|
|
335
400
|
}
|
|
401
|
+
copyResources(sourceDir, outDir);
|
|
336
402
|
newline();
|
|
337
403
|
console.log(heading("Compiling"));
|
|
338
404
|
for (const file of files) {
|
|
339
405
|
if (!fileData.has(file))
|
|
340
406
|
continue;
|
|
341
407
|
const relativePath = file.substring(sourceDir.length + 1);
|
|
342
|
-
const
|
|
343
|
-
const
|
|
408
|
+
const outFile = join3(outDir, relativePath.replace(/\.intent$/, ".ts"));
|
|
409
|
+
const outDirForFile = dirname(outFile);
|
|
410
|
+
if (!existsSync3(outDirForFile)) {
|
|
411
|
+
mkdirSync2(outDirForFile, { recursive: true });
|
|
412
|
+
}
|
|
344
413
|
const fileSpinner = spinner(`${relativePath}`).start();
|
|
345
414
|
const fileStart = Date.now();
|
|
346
415
|
try {
|
|
@@ -456,6 +525,8 @@ async function handleBuild(args2) {
|
|
|
456
525
|
options.apiKey = args2[i + 1];
|
|
457
526
|
if (args2[i] === "--provider")
|
|
458
527
|
options.provider = args2[i + 1];
|
|
528
|
+
if (args2[i] === "--model")
|
|
529
|
+
options.model = args2[i + 1];
|
|
459
530
|
if (args2[i] === "--watch")
|
|
460
531
|
options.watch = true;
|
|
461
532
|
if (args2[i] === "--force")
|
|
@@ -480,6 +551,8 @@ async function handleWatch(args2) {
|
|
|
480
551
|
options.apiKey = args2[i + 1];
|
|
481
552
|
if (args2[i] === "--provider")
|
|
482
553
|
options.provider = args2[i + 1];
|
|
554
|
+
if (args2[i] === "--model")
|
|
555
|
+
options.model = args2[i + 1];
|
|
483
556
|
}
|
|
484
557
|
await watchCommand(options);
|
|
485
558
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intend-it/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "CLI for the Intend programming language",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
],
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@intend-it/parser": "^1.1.
|
|
33
|
-
"@intend-it/core": "^2.0.
|
|
32
|
+
"@intend-it/parser": "^1.1.4",
|
|
33
|
+
"@intend-it/core": "^2.0.4",
|
|
34
34
|
"picocolors": "^1.1.1",
|
|
35
35
|
"ora": "^8.1.1"
|
|
36
36
|
},
|