Skip to content

InfinityLoopLabs/CLI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ILL CLI (@infinityloop.labs/ai-cli)

Config-driven CLI runner for template/bootstrap and sync workflows.

What Was Done

  • Moved CLI implementation from legacy code/ layout to root src/ layout.
  • Switched build setup to rollup.config.mjs + TypeScript declarations output in dist/.
  • Added executable CLI entrypoint (dist/cli.js) with aliases: ill, aic, infinity-cli.
  • Kept plugin-based runtime and covered key paths with tests.

Install

As a package dependency:

npm install @infinityloop.labs/ai-cli

Alternative package managers:

yarn add @infinityloop.labs/ai-cli
pnpm add @infinityloop.labs/ai-cli

Global install (optional):

npm install -g @infinityloop.labs/ai-cli

CLI Commands

Show help:

ill --help

Initialize config in current folder:

ill init --repo owner/template-repo --target-repo owner/product-repo --ref main

Sync with template repository using configured command:

ill sync

Run any configured command key:

ill <commandKey> --name MyFeature

Run command keys declared in infinityloop.config.*:

ill addWidget Header
ill addService Auth
ill addOpenApiConfig Billing
ill removeWidget Header
ill removeService Auth
ill removeOpenApiConfig Billing

Extended form:

ill <commandKey> --name MyFeature --config ./infinityloop.config.js --cwd .

Supported command aliases:

  • ill
  • aic
  • infinity-cli

NPM Scripts

  • npm run build - clean, bundle, generate declaration files, set execute bit on CLI output.
  • npm run clean - remove dist/.
  • npm run test - run Node test suite (src/**/*.test.ts).
  • npm run typecheck - TypeScript check without emit.
  • npm run watch - TypeScript watch mode.
  • npm run start - build and run CLI from dist/cli.js.

Config

CLI auto-detects one of:

  • infinityloop.config.js
  • infinityloop.config.mjs
  • infinityloop.config.cjs

commands is a map where each key is a command and value is an array of steps.

module.exports = {
  commands: {
    createWidget: [
      {
        type: "add",
        from: "_templates/react_template/_template/widget",
        to: "generated/widgets/$name",
        replace: [{ Sample: "$name" }, { sample: "$name" }],
      },
    ],
    removeWidget: [
      {
        type: "remove",
        target: "generated/widgets/$name",
      },
    ],
  },
};

Step Types

  • add: copy file/folder from from to to with optional replace.
  • copy: copy file/folder from from to to without substitutions.
  • download: clone template repository and copy into cwd without .git and .github. .gitignore is preserved. Works in non-empty folders by default; set allowNonEmpty: false to require empty target.
  • merge-template: подтягивает снапшот шаблона, строит 3-way patch и накладывает его поверх текущей рабочей копии. По умолчанию CLI предложит выбрать удаляемые файлы в интерактивном режиме. Если удалений быть не должно вовсе, установите allowDeletes: false. Массив protectedPaths (пути относительно корня проекта) позволяет заблокировать удаление конкретных директорий/файлов даже при включённых удалениях.
  • insert: insert line after placeholder in file.
  • replace: replace the first occurrence of search with replace in file.
  • rename: replace tokens in file contents and file/directory names inside target with case preservation (Sample / sample / SAMPLE).
  • remove-line: remove a line from file by text match.
  • remove: delete file/folder at target.
  • read: load variables from a key=value file (for example .cli) and inject them into the command context so subsequent steps can use ${PROJECT_NAME} placeholders.

Template values & variables

  • Fields such as file, placeholder, line, search, and replace accept either a string with $variable / ${variable} placeholders or a function (variables) => string.
  • Available variables:
    • name, namePascal, nameCamel, nameLower, nameSnake, nameKebab, nameScreamingSnake
  • Any extra CLI flag becomes a variable: --store-name=SideMenu exposes ${storeName}, --dry-run sets ${dryRun} to "true", and disabling flags like --no-store / --nostore set ${store} to "false" while ${noStore} becomes "true". Flag names are normalized to camelCase by stripping dashes/underscores, but you can still reference hyphenated names in when expressions (e.g. when: "!no-store").
  • The read step is typically used to load a .cli file with entries like PROJECT_NAME=my-app. Each KEY=VALUE pair becomes available via ${KEY} or ${key} in later steps.
  • For ${variable} syntax, the placeholder casing controls the transform: ${name} lowers the first letter, ${Name} capitalizes it, ${NAME} uppercases the whole string. Plain $variable keeps the stored value.
  • Example:
{
  type: "insert",
  file: "app/features/services/$name/hooks.ts",
  placeholder: "// Services: Start",
  line: "  $nameLower: createAction(${name}Actions),",
}

Conditional execution

  • Every step may declare when, either as a string ("store", "!store") or an array of such strings. All conditions must be truthy for the step to run.
  • Truthiness is based on the variable value: missing/"false"/"0"/empty strings are treated as false, everything else is true. Prefix ! to invert the result.
  • Example: skip store-related insertions when --no-store is provided.
{
  type: "insert",
  when: "!no-store", // executes only when --no-store/--nostore is not provided
  file: "app/store/index.ts",
  placeholder: "// Services: Start",
  line: "  ${name}: ${Name}Reducer,",
}

// merge-template example that blocks deletions but still fetches updates
{
  type: "merge-template",
  repo: TEMPLATE_REPO,
  ref: TEMPLATE_REF,
  allowDeletes: false,
  protectedPaths: [".cli", "app/business"],
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors