@intend-it/cli 1.1.1 → 1.1.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 (2) hide show
  1. package/dist/index.js +86 -6
  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,14 +175,45 @@ async function initCommand(args) {
174
175
  text: warn(error2.message)
175
176
  });
176
177
  }
178
+ const typesPath = join2(directory, "src", "types.ts");
179
+ if (!existsSync2(typesPath)) {
180
+ const typesContent = `export interface User {
181
+ name: string;
182
+ id: number;
183
+ createdAt: Date;
184
+ }`;
185
+ writeFileSync2(typesPath, typesContent, "utf-8");
186
+ console.log(bullet(`${dim("src/types.ts")} ${dim("(typescript definition)")}`));
187
+ }
177
188
  const examplePath = join2(srcDir, "example.intent");
178
189
  if (!existsSync2(examplePath)) {
179
- const exampleContent = `export intent Greeting(name: string) -> string {
180
- step "Create greeting message" => const message
181
- ensure message is defined
182
- }`;
190
+ const exampleContent = `import { User } from "../types";
191
+
192
+ export intent CreateUser(name: string) -> User {
193
+ step "Generate a random ID" => const id
194
+ step "Create a User object with name, id, and current date" => const user
195
+ return user
196
+ }
197
+
198
+ export entry intent Main() -> void {
199
+ step "Call CreateUser with name 'Intender'" => const user
200
+ step "Log 'Created user:' and the user object to console"
201
+ }
202
+ `;
183
203
  writeFileSync2(examplePath, exampleContent, "utf-8");
184
- console.log(bullet(`${dim("src/intents/example.intent")} ${dim("(example)")}`));
204
+ console.log(bullet(`${dim("src/intents/example.intent")} ${dim("(example intent)")}`));
205
+ }
206
+ const gitignorePath = join2(directory, ".gitignore");
207
+ if (!existsSync2(gitignorePath)) {
208
+ const gitignoreContent = `node_modules/
209
+ dist/
210
+ out/
211
+ .intend/
212
+ .env
213
+ .DS_Store
214
+ `;
215
+ writeFileSync2(gitignorePath, gitignoreContent, "utf-8");
216
+ console.log(bullet(`${dim(".gitignore")} ${dim("(git config)")}`));
185
217
  }
186
218
  newline();
187
219
  printSuccess("Project initialized");
@@ -196,7 +228,8 @@ async function initCommand(args) {
196
228
  // src/commands/build.ts
197
229
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync2 } from "fs";
198
230
  import { join as join3, resolve as resolve3, basename } from "path";
199
- import { AICodeGenerator, FileSystemCAS, computeHash } from "@intend-it/core";
231
+ import { AICodeGenerator, FileSystemCAS, computeHash, OllamaProvider } from "@intend-it/core";
232
+ import * as readline from "readline";
200
233
  import { parseToAST } from "@intend-it/parser";
201
234
  import { readdirSync, statSync } from "fs";
202
235
  function findIntentFiles(dir, fileList = []) {
@@ -224,6 +257,13 @@ async function buildCommand(options) {
224
257
  config.gemini.apiKey = options.apiKey;
225
258
  if (options.provider)
226
259
  config.provider = options.provider;
260
+ if (options.model) {
261
+ if (config.provider === "ollama" && config.ollama) {
262
+ config.ollama.model = options.model;
263
+ } else if (config.gemini) {
264
+ config.gemini.model = options.model;
265
+ }
266
+ }
227
267
  const sourceDir = resolve3(process.cwd(), config.sourceDir);
228
268
  const outDir = resolve3(process.cwd(), config.outDir);
229
269
  const providerName = config.provider || "gemini";
@@ -294,6 +334,42 @@ async function buildCommand(options) {
294
334
  connectSpinner.fail(error(`Connection failed: ${error2.message}`));
295
335
  process.exit(1);
296
336
  }
337
+ const provider = generator.getProvider();
338
+ if (provider instanceof OllamaProvider) {
339
+ const ollama = provider;
340
+ if (typeof ollama.checkModelExists === "function") {
341
+ const exists = await ollama.checkModelExists();
342
+ if (!exists) {
343
+ const modelName = config.ollama?.model || "llama3";
344
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
345
+ console.log();
346
+ const answer = await new Promise((resolve4) => {
347
+ rl.question(` ${icons.info} Model '${accent(modelName)}' is not found locally.
348
+ ${dim("Do you want to pull it now? [Y/n]")} `, resolve4);
349
+ });
350
+ rl.close();
351
+ if (answer.toLowerCase() === "n") {
352
+ printError("Model missing, cannot proceed.");
353
+ process.exit(1);
354
+ }
355
+ const pullSpinner = spinner(`Pulling ${modelName}...`).start();
356
+ try {
357
+ await ollama.pullModel((status, completed, total) => {
358
+ if (completed && total) {
359
+ const percent = Math.round(completed / total * 100);
360
+ pullSpinner.text = `Pulling ${modelName}: ${status} ${percent}%`;
361
+ } else {
362
+ pullSpinner.text = `Pulling ${modelName}: ${status}`;
363
+ }
364
+ });
365
+ pullSpinner.succeed(`${modelName} ready`);
366
+ } catch (e) {
367
+ pullSpinner.fail(`Failed to pull model: ${e.message}`);
368
+ process.exit(1);
369
+ }
370
+ }
371
+ }
372
+ }
297
373
  const casDir = resolve3(process.cwd(), ".intend", "store");
298
374
  const cas = new FileSystemCAS(casDir);
299
375
  let successCount = 0;
@@ -425,6 +501,8 @@ async function handleBuild(args2) {
425
501
  options.apiKey = args2[i + 1];
426
502
  if (args2[i] === "--provider")
427
503
  options.provider = args2[i + 1];
504
+ if (args2[i] === "--model")
505
+ options.model = args2[i + 1];
428
506
  if (args2[i] === "--watch")
429
507
  options.watch = true;
430
508
  if (args2[i] === "--force")
@@ -449,6 +527,8 @@ async function handleWatch(args2) {
449
527
  options.apiKey = args2[i + 1];
450
528
  if (args2[i] === "--provider")
451
529
  options.provider = args2[i + 1];
530
+ if (args2[i] === "--model")
531
+ options.model = args2[i + 1];
452
532
  }
453
533
  await watchCommand(options);
454
534
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intend-it/cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
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.1",
33
- "@intend-it/core": "^2.0.1",
32
+ "@intend-it/parser": "^1.1.3",
33
+ "@intend-it/core": "^2.0.3",
34
34
  "picocolors": "^1.1.1",
35
35
  "ora": "^8.1.1"
36
36
  },