@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.
Files changed (2) hide show
  1. package/dist/index.js +81 -8
  2. 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(directory, "src", "types.ts");
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 "../types";
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 fileName = basename(file, ".intent");
343
- const outFile = join3(outDir, `${fileName}.ts`);
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.2",
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.2",
33
- "@intend-it/core": "^2.0.2",
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
  },