@rupayan10/aios-cli 0.1.0 → 0.1.2

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 +3 -2
  2. package/dist/cli.js +162 -48
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,10 +4,11 @@ Standalone command-line build of FlowScale AIOS. Shares `~/.flowscale` state wit
4
4
 
5
5
  ## Install
6
6
 
7
- Requires **Node ≥ 24** (it ships the built-in `node:sqlite`, so there's nothing to compile):
7
+ Requires **Node ≥ 24** (it ships the built-in `node:sqlite`, so there's nothing to compile).
8
+ It also runs on **Node 22.5+**, where `node:sqlite` is still experimental.
8
9
 
9
10
  ```sh
10
- npm i -g @flowscale/aios-cli
11
+ npm i -g @rupayan10/aios-cli
11
12
  ```
12
13
 
13
14
  Then run `aios` with no arguments (in a terminal) for a guided menu, or any command directly.
package/dist/cli.js CHANGED
@@ -3512,6 +3512,53 @@ var init_esm = __esm({
3512
3512
  }
3513
3513
  });
3514
3514
 
3515
+ // package.json
3516
+ var package_default;
3517
+ var init_package = __esm({
3518
+ "package.json"() {
3519
+ package_default = {
3520
+ name: "@rupayan10/aios-cli",
3521
+ version: "0.1.2",
3522
+ description: "FlowScale AIOS command-line interface",
3523
+ license: "AGPL-3.0-only",
3524
+ bin: {
3525
+ aios: "dist/cli.js"
3526
+ },
3527
+ engines: {
3528
+ node: ">=24"
3529
+ },
3530
+ files: [
3531
+ "dist"
3532
+ ],
3533
+ publishConfig: {
3534
+ access: "public"
3535
+ },
3536
+ scripts: {
3537
+ build: "tsup",
3538
+ prepublishOnly: "npm run build",
3539
+ typecheck: "tsc --noEmit",
3540
+ test: "vitest run",
3541
+ "sync:core": "node --import tsx scripts/sync-core.ts"
3542
+ },
3543
+ dependencies: {
3544
+ "@clack/prompts": "^1.6.0",
3545
+ "@commander-js/extra-typings": "^14.0.0",
3546
+ "adm-zip": "^0.5.17",
3547
+ "cli-table3": "^0.6.5",
3548
+ commander: "^14.0.0"
3549
+ },
3550
+ devDependencies: {
3551
+ "@types/adm-zip": "^0.5.8",
3552
+ "@types/node": "^24.0.0",
3553
+ tsup: "^8.3.0",
3554
+ tsx: "^4.22.4",
3555
+ typescript: "^5.8.3",
3556
+ vitest: "^3.0.0"
3557
+ }
3558
+ };
3559
+ }
3560
+ });
3561
+
3515
3562
  // src/core-ext/paths.ts
3516
3563
  function setHome(dir) {
3517
3564
  override = dir;
@@ -3539,7 +3586,8 @@ function detectNvidiaGpus() {
3539
3586
  try {
3540
3587
  const raw = (0, import_child_process.execSync)(
3541
3588
  "nvidia-smi --query-gpu=index,name,memory.total --format=csv,noheader,nounits",
3542
- { encoding: "utf-8", timeout: 5e3 }
3589
+ // stdio stderr 'ignore': nvidia-smi is optional, so don't leak "command not found" to the parent's stderr.
3590
+ { encoding: "utf-8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }
3543
3591
  ).trim();
3544
3592
  if (!raw) return [];
3545
3593
  return raw.split("\n").map((line) => {
@@ -3557,7 +3605,7 @@ function detectNvidiaGpus() {
3557
3605
  }
3558
3606
  function getGpuNamesFromLspci() {
3559
3607
  try {
3560
- const lspciOutput = (0, import_child_process.execSync)("lspci", { encoding: "utf-8", timeout: 5e3 }).trim();
3608
+ const lspciOutput = (0, import_child_process.execSync)("lspci", { encoding: "utf-8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
3561
3609
  if (!lspciOutput) return [];
3562
3610
  const raw = lspciOutput.split("\n").filter((line) => /vga|3d|display/i.test(line)).join("\n");
3563
3611
  if (!raw) return [];
@@ -3578,7 +3626,9 @@ function detectRocmGpus() {
3578
3626
  try {
3579
3627
  const vramRaw = (0, import_child_process.execSync)("rocm-smi --showmeminfo vram", {
3580
3628
  encoding: "utf-8",
3581
- timeout: 5e3
3629
+ timeout: 5e3,
3630
+ stdio: ["ignore", "pipe", "ignore"]
3631
+ // rocm-smi is optional; suppress its stderr on absence.
3582
3632
  }).trim();
3583
3633
  const vramMap = /* @__PURE__ */ new Map();
3584
3634
  for (const line of vramRaw.split("\n")) {
@@ -5552,14 +5602,92 @@ var init_db_retry = __esm({
5552
5602
  // src/core-ext/db.ts
5553
5603
  function getDb() {
5554
5604
  if (db) return db;
5605
+ (0, import_node_fs.mkdirSync)(flowscaleHome(), { recursive: true });
5555
5606
  const handle = new import_node_sqlite.DatabaseSync(dbPath());
5556
5607
  handle.exec("PRAGMA journal_mode = WAL");
5557
5608
  handle.exec("PRAGMA busy_timeout = 5000");
5558
5609
  handle.exec("PRAGMA synchronous = NORMAL");
5559
5610
  handle.exec("PRAGMA foreign_keys = ON");
5611
+ ensureSchema(handle);
5560
5612
  db = handle;
5561
5613
  return handle;
5562
5614
  }
5615
+ function ensureSchema(handle) {
5616
+ handle.exec(`
5617
+ CREATE TABLE IF NOT EXISTS tools (
5618
+ id TEXT PRIMARY KEY,
5619
+ name TEXT NOT NULL,
5620
+ description TEXT,
5621
+ workflow_json TEXT NOT NULL,
5622
+ workflow_hash TEXT NOT NULL,
5623
+ schema_json TEXT NOT NULL,
5624
+ layout TEXT NOT NULL DEFAULT 'left-right',
5625
+ status TEXT NOT NULL DEFAULT 'dev',
5626
+ output_dir TEXT,
5627
+ comfy_port INTEGER,
5628
+ model_version TEXT,
5629
+ version INTEGER NOT NULL DEFAULT 1,
5630
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
5631
+ deployed_at INTEGER
5632
+ );
5633
+
5634
+ CREATE TABLE IF NOT EXISTS executions (
5635
+ id TEXT PRIMARY KEY,
5636
+ tool_id TEXT NOT NULL REFERENCES tools(id) ON DELETE CASCADE,
5637
+ inputs_json TEXT NOT NULL,
5638
+ outputs_json TEXT,
5639
+ seed INTEGER,
5640
+ prompt_id TEXT,
5641
+ workflow_hash TEXT NOT NULL,
5642
+ status TEXT NOT NULL DEFAULT 'running',
5643
+ error_message TEXT,
5644
+ metadata_json TEXT,
5645
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
5646
+ completed_at INTEGER
5647
+ );
5648
+
5649
+ CREATE INDEX IF NOT EXISTS idx_tools_status ON tools(status);
5650
+ CREATE INDEX IF NOT EXISTS idx_executions_tool_id ON executions(tool_id);
5651
+ CREATE INDEX IF NOT EXISTS idx_executions_created_at ON executions(created_at DESC);
5652
+
5653
+ CREATE TABLE IF NOT EXISTS models (
5654
+ id TEXT PRIMARY KEY,
5655
+ filename TEXT NOT NULL,
5656
+ path TEXT NOT NULL UNIQUE,
5657
+ type TEXT NOT NULL DEFAULT 'other',
5658
+ size_bytes INTEGER,
5659
+ comfy_port INTEGER NOT NULL,
5660
+ scanned_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
5661
+ );
5662
+
5663
+ CREATE INDEX IF NOT EXISTS idx_models_type ON models(type);
5664
+ CREATE INDEX IF NOT EXISTS idx_models_comfy_port ON models(comfy_port);
5665
+ `);
5666
+ const toolCols = handle.prepare("PRAGMA table_info(tools)").all().map((c2) => c2.name);
5667
+ if (!toolCols.includes("engine")) handle.exec("ALTER TABLE tools ADD COLUMN engine TEXT NOT NULL DEFAULT 'comfyui'");
5668
+ if (!toolCols.includes("source")) handle.exec("ALTER TABLE tools ADD COLUMN source TEXT NOT NULL DEFAULT 'comfyui'");
5669
+ if (!toolCols.includes("source_url")) handle.exec("ALTER TABLE tools ADD COLUMN source_url TEXT");
5670
+ if (!toolCols.includes("tool_type")) {
5671
+ try {
5672
+ handle.exec("ALTER TABLE tools ADD COLUMN tool_type TEXT DEFAULT 'custom'");
5673
+ } catch {
5674
+ }
5675
+ }
5676
+ if (!toolCols.includes("last_used_at")) {
5677
+ try {
5678
+ handle.exec("ALTER TABLE tools ADD COLUMN last_used_at INTEGER");
5679
+ } catch {
5680
+ }
5681
+ }
5682
+ const execCols = handle.prepare("PRAGMA table_info(executions)").all().map((c2) => c2.name);
5683
+ if (!execCols.includes("user_id")) handle.exec("ALTER TABLE executions ADD COLUMN user_id TEXT");
5684
+ if (!execCols.includes("comfy_port")) {
5685
+ try {
5686
+ handle.exec("ALTER TABLE executions ADD COLUMN comfy_port INTEGER");
5687
+ } catch {
5688
+ }
5689
+ }
5690
+ }
5563
5691
  function writeTxn(fn) {
5564
5692
  const handle = getDb();
5565
5693
  return retryBusy(() => {
@@ -5577,11 +5705,12 @@ function writeTxn(fn) {
5577
5705
  }
5578
5706
  });
5579
5707
  }
5580
- var import_node_sqlite, db;
5708
+ var import_node_sqlite, import_node_fs, db;
5581
5709
  var init_db = __esm({
5582
5710
  "src/core-ext/db.ts"() {
5583
5711
  "use strict";
5584
5712
  import_node_sqlite = require("node:sqlite");
5713
+ import_node_fs = require("node:fs");
5585
5714
  init_paths();
5586
5715
  init_db_retry();
5587
5716
  }
@@ -5590,7 +5719,6 @@ var init_db = __esm({
5590
5719
  // src/core-ext/repo.ts
5591
5720
  var repo_exports = {};
5592
5721
  __export(repo_exports, {
5593
- FriendlyDbError: () => FriendlyDbError,
5594
5722
  getExecutionById: () => getExecutionById,
5595
5723
  getToolById: () => getToolById,
5596
5724
  getToolBySourceUrl: () => getToolBySourceUrl,
@@ -5604,24 +5732,10 @@ __export(repo_exports, {
5604
5732
  updateExecution: () => updateExecution,
5605
5733
  upsertModels: () => upsertModels
5606
5734
  });
5607
- function rethrowFriendly(err) {
5608
- const message = err instanceof Error ? err.message : String(err);
5609
- if (message.includes("unable to open database file") || message.includes("no such table")) {
5610
- throw new FriendlyDbError(
5611
- `No FlowScale AIOS database found at ${dbPath()}. Run the FlowScale desktop app once to create it, or build a tool first.`
5612
- );
5613
- }
5614
- throw err;
5615
- }
5616
5735
  function listTools() {
5617
- try {
5618
- const stmt = getDb().prepare(
5619
- "SELECT id, name, engine, status, source FROM tools ORDER BY name COLLATE NOCASE"
5620
- );
5621
- return stmt.all();
5622
- } catch (err) {
5623
- rethrowFriendly(err);
5624
- }
5736
+ return getDb().prepare(
5737
+ "SELECT id, name, engine, status, source FROM tools ORDER BY name COLLATE NOCASE"
5738
+ ).all();
5625
5739
  }
5626
5740
  function getToolById(id) {
5627
5741
  const row = getDb().prepare(
@@ -5707,19 +5821,12 @@ function listCompletedExecutions(toolId, limit = 50) {
5707
5821
  const stmt = getDb().prepare(sql);
5708
5822
  return toolId ? stmt.all(toolId, limit) : stmt.all(limit);
5709
5823
  }
5710
- var import_node_crypto, FriendlyDbError, EXEC_COLS;
5824
+ var import_node_crypto, EXEC_COLS;
5711
5825
  var init_repo = __esm({
5712
5826
  "src/core-ext/repo.ts"() {
5713
5827
  "use strict";
5714
5828
  init_db();
5715
- init_paths();
5716
5829
  import_node_crypto = require("node:crypto");
5717
- FriendlyDbError = class extends Error {
5718
- constructor(message) {
5719
- super(message);
5720
- this.name = "FriendlyDbError";
5721
- }
5722
- };
5723
5830
  EXEC_COLS = "id, tool_id AS toolId, user_id AS userId, inputs_json AS inputsJson, workflow_hash AS workflowHash, seed, status, comfy_port AS comfyPort, created_at AS createdAt, completed_at AS completedAt, outputs_json AS outputsJson, error_message AS errorMessage, metadata_json AS metadataJson";
5724
5831
  }
5725
5832
  });
@@ -6243,11 +6350,11 @@ async function saveComfyOutputsToDisk(outputs, comfyPort, toolId, executionId) {
6243
6350
  }
6244
6351
  function saveApiOutputs(executionId, outputs) {
6245
6352
  const outDir = (0, import_node_path2.join)(outputsDir(), executionId);
6246
- (0, import_node_fs.mkdirSync)(outDir, { recursive: true });
6353
+ (0, import_node_fs2.mkdirSync)(outDir, { recursive: true });
6247
6354
  return outputs.map(({ kind, filename, data }) => {
6248
6355
  const safe = (0, import_node_path2.basename)(filename);
6249
6356
  if (!safe || safe === "." || safe === "..") throw new Error(`Invalid output filename: ${filename}`);
6250
- (0, import_node_fs.writeFileSync)((0, import_node_path2.join)(outDir, safe), Buffer.from(data, "base64"));
6357
+ (0, import_node_fs2.writeFileSync)((0, import_node_path2.join)(outDir, safe), Buffer.from(data, "base64"));
6251
6358
  return { kind, filename: safe, path: `/api/executions/${executionId}/outputs/${safe}` };
6252
6359
  });
6253
6360
  }
@@ -6262,12 +6369,12 @@ function resolveOutputDiskPath(storedPath) {
6262
6369
  if (m) return contained((0, import_node_path2.join)(root, m[1], m[2]));
6263
6370
  return null;
6264
6371
  }
6265
- var import_promises, import_node_fs, import_node_path2;
6372
+ var import_promises, import_node_fs2, import_node_path2;
6266
6373
  var init_output_saver = __esm({
6267
6374
  "src/core-ext/output-saver.ts"() {
6268
6375
  "use strict";
6269
6376
  import_promises = require("node:fs/promises");
6270
- import_node_fs = require("node:fs");
6377
+ import_node_fs2 = require("node:fs");
6271
6378
  import_node_path2 = require("node:path");
6272
6379
  init_comfy_url();
6273
6380
  init_paths();
@@ -7152,7 +7259,7 @@ var require_utils2 = __commonJS({
7152
7259
  module2.exports = Utils;
7153
7260
  Utils.prototype.makeDir = function(folder) {
7154
7261
  const self = this;
7155
- function mkdirSync4(fpath) {
7262
+ function mkdirSync5(fpath) {
7156
7263
  let resolvedPath = fpath.split(self.sep)[0];
7157
7264
  fpath.split(self.sep).forEach(function(name) {
7158
7265
  if (!name || name.substr(-1, 1) === ":") return;
@@ -7170,7 +7277,7 @@ var require_utils2 = __commonJS({
7170
7277
  if (stat && stat.isFile()) throw Errors.FILE_IN_THE_WAY(`"${resolvedPath}"`);
7171
7278
  });
7172
7279
  }
7173
- mkdirSync4(folder);
7280
+ mkdirSync5(folder);
7174
7281
  };
7175
7282
  Utils.prototype.writeFileTo = function(path5, content, overwrite, attr) {
7176
7283
  const self = this;
@@ -10021,7 +10128,7 @@ function registerTools(program2) {
10021
10128
  const o2 = build.opts();
10022
10129
  let workflowJson;
10023
10130
  try {
10024
- workflowJson = (0, import_node_fs2.readFileSync)(file, "utf-8");
10131
+ workflowJson = (0, import_node_fs3.readFileSync)(file, "utf-8");
10025
10132
  } catch {
10026
10133
  process.stderr.write(`Workflow file not found: ${file}
10027
10134
  `);
@@ -10167,7 +10274,7 @@ function registerTools(program2) {
10167
10274
  const path5 = v.slice(1);
10168
10275
  let buf;
10169
10276
  try {
10170
- buf = (0, import_node_fs2.readFileSync)(path5);
10277
+ buf = (0, import_node_fs3.readFileSync)(path5);
10171
10278
  } catch {
10172
10279
  process.stderr.write(`Input file not found: ${path5}
10173
10280
  `);
@@ -10226,11 +10333,11 @@ function registerTools(program2) {
10226
10333
  }
10227
10334
  });
10228
10335
  }
10229
- var import_node_fs2;
10336
+ var import_node_fs3;
10230
10337
  var init_tools = __esm({
10231
10338
  "src/commands/tools.ts"() {
10232
10339
  "use strict";
10233
- import_node_fs2 = require("node:fs");
10340
+ import_node_fs3 = require("node:fs");
10234
10341
  init_repo();
10235
10342
  init_render();
10236
10343
  init_execution_runner();
@@ -10543,7 +10650,7 @@ var init_instances = __esm({
10543
10650
  function readInstanceLog(logPath, lines = 200) {
10544
10651
  let content;
10545
10652
  try {
10546
- content = (0, import_node_fs3.readFileSync)(logPath, "utf-8");
10653
+ content = (0, import_node_fs4.readFileSync)(logPath, "utf-8");
10547
10654
  } catch {
10548
10655
  return [];
10549
10656
  }
@@ -10551,11 +10658,11 @@ function readInstanceLog(logPath, lines = 200) {
10551
10658
  if (all.length && all[all.length - 1] === "") all.pop();
10552
10659
  return all.slice(-lines);
10553
10660
  }
10554
- var import_node_fs3;
10661
+ var import_node_fs4;
10555
10662
  var init_comfy_logs = __esm({
10556
10663
  "src/core-ext/comfy-logs.ts"() {
10557
10664
  "use strict";
10558
- import_node_fs3 = require("node:fs");
10665
+ import_node_fs4 = require("node:fs");
10559
10666
  }
10560
10667
  });
10561
10668
 
@@ -10971,7 +11078,7 @@ function registerAssets(program2) {
10971
11078
  process.exitCode = 1;
10972
11079
  return;
10973
11080
  }
10974
- const target = assetsForExecution(row).find((a2) => a2.diskPath && (0, import_node_fs4.existsSync)(a2.diskPath));
11081
+ const target = assetsForExecution(row).find((a2) => a2.diskPath && (0, import_node_fs5.existsSync)(a2.diskPath));
10975
11082
  if (!target?.diskPath) {
10976
11083
  process.stderr.write(`No openable output file found on disk for execution ${executionId}.
10977
11084
  `);
@@ -10983,11 +11090,11 @@ function registerAssets(program2) {
10983
11090
  `);
10984
11091
  });
10985
11092
  }
10986
- var import_node_fs4;
11093
+ var import_node_fs5;
10987
11094
  var init_assets2 = __esm({
10988
11095
  "src/commands/assets.ts"() {
10989
11096
  "use strict";
10990
- import_node_fs4 = require("node:fs");
11097
+ import_node_fs5 = require("node:fs");
10991
11098
  init_repo();
10992
11099
  init_assets();
10993
11100
  init_open_file();
@@ -12131,12 +12238,13 @@ var init_interactive = __esm({
12131
12238
  var cli_exports = {};
12132
12239
  __export(cli_exports, {
12133
12240
  buildProgram: () => buildProgram,
12241
+ formatCliError: () => formatCliError,
12134
12242
  main: () => main
12135
12243
  });
12136
12244
  module.exports = __toCommonJS(cli_exports);
12137
12245
  function buildProgram() {
12138
12246
  const program2 = new Command();
12139
- program2.name("aios").description("FlowScale AIOS command-line interface").option("--home <dir>", "override FLOWSCALE_HOME").option("--verbose", "verbose logging").hook("preAction", (thisCommand) => {
12247
+ program2.name("aios").description("FlowScale AIOS command-line interface").version(package_default.version).option("--home <dir>", "override FLOWSCALE_HOME").option("--verbose", "verbose logging").hook("preAction", (thisCommand) => {
12140
12248
  const opts = thisCommand.opts();
12141
12249
  if (opts.home) setHome(opts.home);
12142
12250
  });
@@ -12158,10 +12266,15 @@ async function main(argv) {
12158
12266
  }
12159
12267
  await buildProgram().parseAsync(argv);
12160
12268
  }
12269
+ function formatCliError(err, argv) {
12270
+ const message = err instanceof Error ? err.message : String(err);
12271
+ return argv.includes("--json") ? JSON.stringify({ error: message }) : message;
12272
+ }
12161
12273
  var isMain;
12162
12274
  var init_cli = __esm({
12163
12275
  "src/cli.ts"() {
12164
12276
  init_esm();
12277
+ init_package();
12165
12278
  init_paths();
12166
12279
  init_gpu();
12167
12280
  init_tools();
@@ -12177,7 +12290,7 @@ var init_cli = __esm({
12177
12290
  isMain = typeof require !== "undefined" && require.main === module;
12178
12291
  if (isMain) {
12179
12292
  main(process.argv).catch((err) => {
12180
- console.error(err instanceof Error ? err.message : String(err));
12293
+ console.error(formatCliError(err, process.argv));
12181
12294
  process.exit(1);
12182
12295
  });
12183
12296
  }
@@ -12187,5 +12300,6 @@ init_cli();
12187
12300
  // Annotate the CommonJS export names for ESM import in node:
12188
12301
  0 && (module.exports = {
12189
12302
  buildProgram,
12303
+ formatCliError,
12190
12304
  main
12191
12305
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rupayan10/aios-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "FlowScale AIOS command-line interface",
5
5
  "license": "AGPL-3.0-only",
6
6
  "bin": {