alys-akusa 0.1.2 → 0.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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +239 -44
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Alys CLI
2
2
 
3
- Alys is the authenticated CLI for Akusa-managed dataset generation.
3
+ Alys is the authenticated CLI for terminal-native dataset generation.
4
4
 
5
5
  ```bash
6
6
  npm install -g alys-akusa
package/dist/index.cjs CHANGED
@@ -4928,6 +4928,8 @@ function printBanner() {
4928
4928
  function printHelp() {
4929
4929
  printBanner();
4930
4930
  console.log(`
4931
+ Alys runs in your terminal. The dashboard tracks what it generates.
4932
+
4931
4933
  Usage:
4932
4934
  npx alys-akusa
4933
4935
  npx alys-akusa login
@@ -5014,7 +5016,7 @@ async function requestJson(pathname, init = {}, token) {
5014
5016
  const response = await fetch(apiUrl(pathname), { ...init, headers });
5015
5017
  const payload = await response.json().catch(() => ({}));
5016
5018
  if (!response.ok) {
5017
- const message = typeof payload?.error === "string" ? payload.error : `Alys API request failed (${response.status}).`;
5019
+ const message = typeof payload?.error === "string" ? payload.error : `Alys request failed (${response.status}).`;
5018
5020
  throw new CliApiError(message, response.status, payload);
5019
5021
  }
5020
5022
  return payload;
@@ -5078,6 +5080,19 @@ function parseDepth(value) {
5078
5080
  if (value === "shallow" || value === "medium" || value === "deep") return value;
5079
5081
  return void 0;
5080
5082
  }
5083
+ function normalizeTopicInput(value) {
5084
+ if (typeof value !== "string") return "";
5085
+ let topic = value.replace(/\[[^\]]+\][^\n\r]*/g, "").replace(/\s+/g, " ").trim();
5086
+ const commandMatch = topic.match(/^(?:npx\s+)?(?:alys-akusa(?:@latest)?|alys)\s+generate\s+(.+)$/i);
5087
+ if (commandMatch) {
5088
+ topic = commandMatch[1].trim();
5089
+ }
5090
+ const quoted = topic.match(/^"([^"]+)"|^'([^']+)'/);
5091
+ if (quoted) {
5092
+ return (quoted[1] || quoted[2] || "").trim();
5093
+ }
5094
+ return topic.replace(/\s+--(?:format|type|datasets|depth|sources|rows|workspace)\s+\S.*$/i, "").replace(/\s+--(?:verify|no-verify|yes)\b.*$/i, "").trim();
5095
+ }
5081
5096
  function resolveHome(p) {
5082
5097
  if (p.startsWith("~/")) return import_node_path.default.join(import_node_os.default.homedir(), p.slice(2));
5083
5098
  return p;
@@ -5085,14 +5100,94 @@ function resolveHome(p) {
5085
5100
  function formatInt(value) {
5086
5101
  return new Intl.NumberFormat("en-US").format(value);
5087
5102
  }
5103
+ function formatPercent(value) {
5104
+ if (!Number.isFinite(value) || value <= 0) return "pending";
5105
+ return `${Math.round(value * 100)}%`;
5106
+ }
5107
+ function formatScore(value) {
5108
+ if (!Number.isFinite(value) || value <= 0) return "pending";
5109
+ return `${Math.round(value)}/100`;
5110
+ }
5111
+ function average(values) {
5112
+ const filtered = values.filter((value) => Number.isFinite(value) && value > 0);
5113
+ return filtered.length ? filtered.reduce((sum, value) => sum + value, 0) / filtered.length : 0;
5114
+ }
5115
+ function truncate(value, max = 88) {
5116
+ const normalized = value.replace(/\s+/g, " ").trim();
5117
+ return normalized.length > max ? `${normalized.slice(0, max - 1)}\u2026` : normalized;
5118
+ }
5119
+ function getMetrics(dataset) {
5120
+ const metrics = dataset.manifest.metrics;
5121
+ return metrics && typeof metrics === "object" ? metrics : {};
5122
+ }
5123
+ function getSummary(dataset) {
5124
+ const summary = dataset.manifest.generationSummary;
5125
+ return summary && typeof summary === "object" ? summary : {};
5126
+ }
5127
+ function getQualityMetrics(dataset) {
5128
+ const metrics = dataset.manifest.qualityMetrics;
5129
+ return metrics && typeof metrics === "object" ? metrics : {};
5130
+ }
5131
+ function getEvaluation(dataset) {
5132
+ const evaluation = dataset.manifest.evaluation;
5133
+ return evaluation && typeof evaluation === "object" ? evaluation : {};
5134
+ }
5135
+ function printStage(code, status, label, metric) {
5136
+ const tint = status === "DONE" || status === "OK" ? "green" : status === "WARN" ? "yellow" : "cyan";
5137
+ const prefix = `${paint(`[${code.padEnd(4).slice(0, 4)}]`, "gray")} ${paint(status.padEnd(4), tint)}`;
5138
+ console.log(`${prefix} ${label}${metric ? ` ${paint(metric, "gray")}` : ""}`);
5139
+ }
5140
+ async function withSpinner(label, task) {
5141
+ if (!process.stdout.isTTY) {
5142
+ printStage("RUN", "RUN", label);
5143
+ return task;
5144
+ }
5145
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
5146
+ let index = 0;
5147
+ process.stdout.write(`${paint(frames[index], "yellow")} ${label}`);
5148
+ const interval = setInterval(() => {
5149
+ index = (index + 1) % frames.length;
5150
+ process.stdout.write(`\r${paint(frames[index], "yellow")} ${label}`);
5151
+ }, 90);
5152
+ try {
5153
+ const result = await task;
5154
+ clearInterval(interval);
5155
+ process.stdout.write(`\r${paint("\u2713", "green")} ${label}
5156
+ `);
5157
+ return result;
5158
+ } catch (error) {
5159
+ clearInterval(interval);
5160
+ process.stdout.write(`\r${paint("\xD7", "red")} ${label}
5161
+ `);
5162
+ throw error;
5163
+ }
5164
+ }
5165
+ function previewRecord(dataset) {
5166
+ const file = dataset.files.find((item) => item.format === "jsonl" || item.format === "instruction" || item.format === "rag");
5167
+ const firstLine = file?.content.split(/\r?\n/).find((line) => line.trim().length > 0);
5168
+ if (!firstLine) return null;
5169
+ try {
5170
+ const parsed = JSON.parse(firstLine);
5171
+ const input = typeof parsed.input === "string" ? parsed.input : typeof parsed.instruction === "string" ? parsed.instruction : typeof parsed.question === "string" ? parsed.question : "";
5172
+ const output = typeof parsed.output === "string" ? parsed.output : typeof parsed.answer === "string" ? parsed.answer : typeof parsed.completion === "string" ? parsed.completion : typeof parsed.text === "string" ? parsed.text : "";
5173
+ if (!input && !output) return null;
5174
+ const metadata = parsed.metadata && typeof parsed.metadata === "object" ? parsed.metadata : {};
5175
+ const explanation = Array.isArray(metadata.acceptance_explanation) ? metadata.acceptance_explanation.filter((item) => typeof item === "string") : Array.isArray(metadata.acceptance_reasons) ? metadata.acceptance_reasons.filter((item) => typeof item === "string") : [];
5176
+ return { input: truncate(input, 92), output: truncate(output, 120), why: explanation.slice(0, 2).map((item) => truncate(item, 112)) };
5177
+ } catch {
5178
+ return null;
5179
+ }
5180
+ }
5088
5181
  function depthMultiplier(depth) {
5089
5182
  if (depth === "deep") return 1.6;
5090
5183
  if (depth === "shallow") return 0.75;
5091
5184
  return 1;
5092
5185
  }
5093
5186
  function printUsage(profile) {
5094
- const name = profile.user.name || profile.user.email || "Alys user";
5095
- console.log(paint(`Signed in as ${name}`, "white"));
5187
+ const name = profile.user.name || "Alys user";
5188
+ const email = profile.user.email;
5189
+ const account = email && email !== name ? `${name} <${email}>` : name;
5190
+ console.log(paint(`Account: ${account}`, "white"));
5096
5191
  console.log(
5097
5192
  profile.usage.isUnlimited ? paint("Generations: unlimited", "green") : paint(`Generations: ${profile.usage.used}/${profile.usage.limit} used, ${profile.usage.remaining} remaining`, "yellow")
5098
5193
  );
@@ -5102,9 +5197,13 @@ function printRunPlan(args) {
5102
5197
  const effectiveSources = Math.max(1, Math.floor(args.sourceLimit * multiplier));
5103
5198
  const effectiveRows = Math.max(1, Math.floor(args.targetRows * multiplier));
5104
5199
  const totalRows = effectiveRows * args.datasetCount;
5105
- console.log(paint("\n\u250C\u2500 Alys API run plan \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510", "gray"));
5200
+ const name = args.profile.user.name || "Alys user";
5201
+ const email = args.profile.user.email;
5202
+ const account = email && email !== name ? `${name} <${email}>` : name;
5203
+ console.log(paint("\n\u250C\u2500 Alys run plan \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510", "gray"));
5106
5204
  console.log(`${paint("\u2502", "gray")} Topic ${paint(args.topic.slice(0, 58), "white")}`);
5107
- console.log(`${paint("\u2502", "gray")} Type ${paint(args.datasetType, "cyan")} Depth ${paint(args.depth, "cyan")} Mode ${paint("Akusa API", "yellow")}`);
5205
+ console.log(`${paint("\u2502", "gray")} Account ${paint(account.slice(0, 58), "white")}`);
5206
+ console.log(`${paint("\u2502", "gray")} Type ${paint(args.datasetType, "cyan")} Depth ${paint(args.depth, "cyan")} Mode ${paint("Alys runtime", "yellow")}`);
5108
5207
  console.log(`${paint("\u2502", "gray")} Datasets ${formatInt(args.datasetCount)} / ${MAX_DATASETS_PER_RUN} max Rows/dataset ${formatInt(effectiveRows)}`);
5109
5208
  console.log(`${paint("\u2502", "gray")} Total rows ${paint(formatInt(totalRows), "green")} Formats ${args.exportFormats.join(", ")}`);
5110
5209
  console.log(`${paint("\u2502", "gray")} Credits ${args.profile.usage.isUnlimited ? "Unlimited" : `${args.profile.usage.remaining ?? 0} remaining before run`}`);
@@ -5121,7 +5220,7 @@ async function confirmRun(args) {
5121
5220
  const response = await (0, import_prompts.default)({
5122
5221
  type: "toggle",
5123
5222
  name: "continueRun",
5124
- message: "Generate through the Alys API?",
5223
+ message: "Start this Alys run?",
5125
5224
  initial: true,
5126
5225
  active: "Yes",
5127
5226
  inactive: "No"
@@ -5144,6 +5243,108 @@ async function writeGeneratedDatasets(workspaceRoot, datasets) {
5144
5243
  );
5145
5244
  }
5146
5245
  }
5246
+ function printGenerationSummary(response, workspaceRoot) {
5247
+ const root = resolveHome(workspaceRoot);
5248
+ const totals = response.datasets.reduce(
5249
+ (acc, dataset) => {
5250
+ const metrics = getMetrics(dataset);
5251
+ const summary = getSummary(dataset);
5252
+ acc.records += Number(metrics.recordsGenerated ?? summary.recordsAccepted ?? 0);
5253
+ acc.sources += Number(metrics.sourcesDiscovered ?? 0);
5254
+ acc.documents += Number(metrics.documentsExtracted ?? 0);
5255
+ acc.findings += Number(metrics.findingsVerified ?? 0);
5256
+ acc.duplicates += Number(metrics.duplicatesRemoved ?? summary.duplicatesRemoved ?? 0);
5257
+ const quality = getQualityMetrics(dataset);
5258
+ acc.contradictions += Number(quality.contradictionResolutionCount ?? 0);
5259
+ acc.lowTrustFiltered += Number(quality.lowTrustSourceFilterRate ?? 0);
5260
+ acc.citationCoverage.push(Number(quality.citationCoverage ?? 0));
5261
+ acc.uniqueness.push(Number(quality.recordUniqueness ?? 0));
5262
+ acc.relevance.push(Number(quality.relevanceScore ?? 0));
5263
+ const suitability = getEvaluation(dataset).suitability ?? getEvaluation(dataset).summary?.scores ?? {};
5264
+ acc.ragSuitability.push(Number(suitability.ragSuitability ?? 0));
5265
+ acc.instructionTuning.push(Number(suitability.instructionTuning ?? 0));
5266
+ acc.factualGrounding.push(Number(suitability.factualGrounding ?? 0));
5267
+ acc.humanUsefulness.push(Number(suitability.humanUsefulness ?? 0));
5268
+ const confidence2 = Number(metrics.averageConfidence ?? summary.averageConfidence ?? 0);
5269
+ if (confidence2 > 0) acc.confidences.push(confidence2);
5270
+ return acc;
5271
+ },
5272
+ {
5273
+ records: 0,
5274
+ sources: 0,
5275
+ documents: 0,
5276
+ findings: 0,
5277
+ duplicates: 0,
5278
+ contradictions: 0,
5279
+ lowTrustFiltered: 0,
5280
+ confidences: [],
5281
+ citationCoverage: [],
5282
+ uniqueness: [],
5283
+ relevance: [],
5284
+ ragSuitability: [],
5285
+ instructionTuning: [],
5286
+ factualGrounding: [],
5287
+ humanUsefulness: []
5288
+ }
5289
+ );
5290
+ const confidence = totals.confidences.length ? totals.confidences.reduce((sum, value) => sum + value, 0) / totals.confidences.length : 0;
5291
+ const citationCoverage = average(totals.citationCoverage);
5292
+ const uniqueness = average(totals.uniqueness);
5293
+ const relevance = average(totals.relevance);
5294
+ const ragSuitability = average(totals.ragSuitability);
5295
+ const instructionTuning = average(totals.instructionTuning);
5296
+ const factualGrounding = average(totals.factualGrounding);
5297
+ const humanUsefulness = average(totals.humanUsefulness);
5298
+ console.log("");
5299
+ console.log(paint("Alys run complete", "green"));
5300
+ printStage("SRC", "DONE", "Authoritative sources ranked", formatInt(totals.sources));
5301
+ printStage("SRC", "DONE", "Low-trust source filter applied", `${Math.round(totals.lowTrustFiltered / Math.max(1, response.datasets.length) * 100)}% avg filtered`);
5302
+ printStage("EXT", "DONE", "Source documents normalized", formatInt(totals.documents));
5303
+ printStage("CHK", "DONE", "Findings verified", formatInt(totals.findings));
5304
+ printStage("CHK", "DONE", "Contradictory claims resolved", formatInt(totals.contradictions));
5305
+ printStage("DED", "DONE", "Duplicate candidates removed", formatInt(totals.duplicates));
5306
+ printStage("GEN", "DONE", "Canonical records accepted", formatInt(totals.records));
5307
+ printStage("EVAL", "DONE", "Average confidence", formatPercent(confidence));
5308
+ printStage("EVAL", "DONE", "Citation coverage", formatPercent(citationCoverage));
5309
+ printStage("EVAL", "DONE", "Record uniqueness", formatPercent(uniqueness));
5310
+ printStage("EVAL", "DONE", "Topic relevance", formatPercent(relevance));
5311
+ printStage("EVAL", "DONE", "RAG suitability", formatScore(ragSuitability));
5312
+ printStage("EVAL", "DONE", "Instruction tuning suitability", formatScore(instructionTuning));
5313
+ printStage("EVAL", "DONE", "Factual grounding", formatScore(factualGrounding));
5314
+ printStage("EVAL", "DONE", "Human usefulness proxy", formatScore(humanUsefulness));
5315
+ printStage("OUT", "DONE", "Exports written", root);
5316
+ console.log("");
5317
+ console.log(paint("Datasets", "white"));
5318
+ for (const dataset of response.datasets) {
5319
+ const metrics = getMetrics(dataset);
5320
+ const summary = getSummary(dataset);
5321
+ const quality = getQualityMetrics(dataset);
5322
+ const suitability = getEvaluation(dataset).suitability ?? getEvaluation(dataset).summary?.scores ?? {};
5323
+ const records = Number(metrics.recordsGenerated ?? summary.recordsAccepted ?? 0);
5324
+ const sources = Number(metrics.sourcesDiscovered ?? 0);
5325
+ const confidenceValue = Number(metrics.averageConfidence ?? summary.averageConfidence ?? 0);
5326
+ const outputDir = import_node_path.default.join(root, "datasets", dataset.id);
5327
+ console.log(`${paint("\u2022", "yellow")} ${paint(dataset.id, "white")} ${formatInt(records)} records ${formatInt(sources)} sources ${formatPercent(confidenceValue)} confidence`);
5328
+ console.log(` ${truncate(dataset.topic, 110)}`);
5329
+ console.log(` ${paint(outputDir, "cyan")}`);
5330
+ console.log(` quality ${formatPercent(Number(quality.citationCoverage ?? 0))} citations \xB7 ${formatPercent(Number(quality.recordUniqueness ?? 0))} unique \xB7 ${formatPercent(Number(quality.sourceDiversity ?? 0))} source diversity`);
5331
+ console.log(` suitability RAG ${formatScore(Number(suitability.ragSuitability ?? 0))} \xB7 tuning ${formatScore(Number(suitability.instructionTuning ?? 0))} \xB7 usefulness ${formatScore(Number(suitability.humanUsefulness ?? 0))}`);
5332
+ const preview = previewRecord(dataset);
5333
+ if (preview) {
5334
+ console.log(paint(" preview", "gray"));
5335
+ if (preview.input) console.log(` in ${paint(preview.input, "gray")}`);
5336
+ if (preview.output) console.log(` out ${preview.output}`);
5337
+ for (const reason of preview.why) {
5338
+ console.log(` why ${paint(reason, "gray")}`);
5339
+ }
5340
+ }
5341
+ }
5342
+ console.log("");
5343
+ console.log(
5344
+ response.usage.isUnlimited ? paint("Generations remaining: unlimited", "green") : paint(`Generations remaining: ${response.usage.remaining ?? 0}`, "yellow")
5345
+ );
5346
+ console.log(paint(`Dashboard: ${appUrl()}/dashboard`, "cyan"));
5347
+ }
5147
5348
  async function handleStatus() {
5148
5349
  printBanner();
5149
5350
  const { profile } = await ensureAuthenticated();
@@ -5171,6 +5372,9 @@ async function handleLogout() {
5171
5372
  }
5172
5373
  async function handleGenerate(args, command) {
5173
5374
  const { config, profile } = await ensureAuthenticated();
5375
+ printBanner();
5376
+ printUsage(profile);
5377
+ console.log("");
5174
5378
  const { values, positionals } = (0, import_node_util.parseArgs)({
5175
5379
  args: command === "generate" ? args.slice(1) : args,
5176
5380
  allowPositionals: true,
@@ -5187,13 +5391,13 @@ async function handleGenerate(args, command) {
5187
5391
  yes: { type: "boolean" }
5188
5392
  }
5189
5393
  });
5190
- const topicFromArgs = positionals.join(" ").trim();
5191
- const topic = topicFromArgs ? topicFromArgs : (await (0, import_prompts.default)({
5394
+ const topicFromArgs = normalizeTopicInput(positionals.join(" "));
5395
+ const topic = topicFromArgs ? topicFromArgs : normalizeTopicInput((await (0, import_prompts.default)({
5192
5396
  type: "text",
5193
5397
  name: "topic",
5194
5398
  message: "What do you want to generate?",
5195
5399
  validate: (v) => v.trim().length ? true : "Please enter a topic."
5196
- })).topic;
5400
+ })).topic);
5197
5401
  if (!topic) throw new Error("Missing topic.");
5198
5402
  const datasetType = parseDatasetType(values.type) ?? (await (0, import_prompts.default)({
5199
5403
  type: "select",
@@ -5265,13 +5469,11 @@ async function handleGenerate(args, command) {
5265
5469
  const verificationEnabled = values.verify === true ? true : values["no-verify"] === true ? false : (await (0, import_prompts.default)({
5266
5470
  type: "toggle",
5267
5471
  name: "verificationEnabled",
5268
- message: "Enable verification + debate swarm?",
5472
+ message: "Enable verification checks?",
5269
5473
  initial: true,
5270
5474
  active: "Yes",
5271
5475
  inactive: "No"
5272
5476
  })).verificationEnabled;
5273
- printBanner();
5274
- printUsage(profile);
5275
5477
  printRunPlan({
5276
5478
  topic,
5277
5479
  datasetType,
@@ -5292,39 +5494,32 @@ async function handleGenerate(args, command) {
5292
5494
  console.log(paint("Run cancelled. No generations spent.", "green"));
5293
5495
  return;
5294
5496
  }
5295
- console.log(`${paint("[AUTH]", "gray")} ${paint("OK ", "green")} Usage linked to ${appUrl()}`);
5296
- console.log(`${paint("[API ]", "gray")} ${paint("RUN ", "yellow")} Generating datasets through Akusa API...`);
5297
- const response = await requestJson(
5298
- "/api/cli/generate",
5299
- {
5300
- method: "POST",
5301
- body: JSON.stringify({
5302
- topic,
5303
- datasetType,
5304
- datasetCount,
5305
- formats: exportFormats,
5306
- sourceLimit,
5307
- targetRows,
5308
- depth,
5309
- verificationEnabled
5310
- })
5311
- },
5312
- config.token
5313
- );
5314
- await writeGeneratedDatasets(workspaceRoot, response.datasets);
5315
- console.log(`${paint("[API ]", "gray")} ${paint("DONE", "green")} Generation complete`);
5316
- console.log(`${paint("[OUT ]", "gray")} ${paint("DONE", "green")} Files written to ${resolveHome(workspaceRoot)}`);
5317
- console.log(paint("\nDatasets generated", "green"));
5318
- for (const dataset of response.datasets) {
5319
- const records = Number(dataset.manifest?.metrics && typeof dataset.manifest.metrics === "object" ? dataset.manifest.metrics.recordsGenerated ?? 0 : 0);
5320
- console.log(`${paint("\u2022", "yellow")} ${dataset.id} records: ${formatInt(records)}`);
5321
- console.log(` ${import_node_path.default.join(resolveHome(workspaceRoot), "datasets", dataset.id)}`);
5322
- }
5323
- console.log("");
5324
- console.log(
5325
- response.usage.isUnlimited ? paint("Generations remaining: unlimited", "green") : paint(`Generations remaining: ${response.usage.remaining ?? 0}`, "yellow")
5497
+ console.log(paint("Runtime", "white"));
5498
+ printStage("AUTH", "OK", "Usage linked", appUrl());
5499
+ printStage("PLAN", "OK", "Generations reserved only after successful completion", `${datasetCount} requested`);
5500
+ printStage("SRC", "RUN", "Research pipeline starting", `${sourceLimit} source target`);
5501
+ const response = await withSpinner(
5502
+ "Alys research runtime executing",
5503
+ requestJson(
5504
+ "/api/cli/generate",
5505
+ {
5506
+ method: "POST",
5507
+ body: JSON.stringify({
5508
+ topic,
5509
+ datasetType,
5510
+ datasetCount,
5511
+ formats: exportFormats,
5512
+ sourceLimit,
5513
+ targetRows,
5514
+ depth,
5515
+ verificationEnabled
5516
+ })
5517
+ },
5518
+ config.token
5519
+ )
5326
5520
  );
5327
- console.log(paint(`Dashboard: ${appUrl()}/dashboard`, "cyan"));
5521
+ await withSpinner("Writing local exports", writeGeneratedDatasets(workspaceRoot, response.datasets));
5522
+ printGenerationSummary(response, workspaceRoot);
5328
5523
  }
5329
5524
  function printFailure(error) {
5330
5525
  const message = error instanceof Error ? error.message : "Alys failed.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alys-akusa",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "description": "Alys local CLI runtime for autonomous dataset generation.",
6
6
  "license": "UNLICENSED",