@akanjs/cli 2.3.9-rc.1 → 2.3.9-rc.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.
@@ -2809,7 +2809,7 @@ class Executor {
2809
2809
  this.logger.verbose(`Remove directory ${readPath}`);
2810
2810
  return this;
2811
2811
  }
2812
- async writeFile(filePath, content, { overwrite = true } = {}) {
2812
+ async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
2813
2813
  const writePath = this.getPath(filePath);
2814
2814
  const dir = path7.dirname(writePath);
2815
2815
  if (!await FileSys.dirExists(dir))
@@ -2827,7 +2827,8 @@ class Executor {
2827
2827
  }
2828
2828
  } else {
2829
2829
  await FileSys.writeText(writePath, contentStr);
2830
- this.logger.rawLog(chalk4.green(`File Create: ${filePath}`));
2830
+ if (!silent)
2831
+ this.logger.rawLog(chalk4.green(`File Create: ${filePath}`));
2831
2832
  }
2832
2833
  return { filePath: writePath, content: contentStr };
2833
2834
  }
@@ -3491,14 +3492,15 @@ class AppExecutor extends SysExecutor {
3491
3492
  getCommandEnv(env = {}) {
3492
3493
  const basePort = 8282;
3493
3494
  const portOffset = WorkspaceExecutor.getBaseDevEnv().portOffset;
3494
- const PORT = basePort ? (basePort + portOffset).toString() : undefined;
3495
+ const PORT = (basePort + portOffset).toString();
3495
3496
  const AKAN_PUBLIC_SERVER_PORT = portOffset ? (8282 + portOffset).toString() : undefined;
3496
3497
  return {
3497
3498
  ...process.env,
3498
3499
  AKAN_PUBLIC_APP_NAME: this.name,
3499
3500
  AKAN_WORKSPACE_ROOT: this.workspace.workspaceRoot,
3500
3501
  NODE_NO_WARNINGS: "1",
3501
- ...PORT ? { PORT, AKAN_PUBLIC_CLIENT_PORT: PORT } : {},
3502
+ PORT,
3503
+ AKAN_PUBLIC_CLIENT_PORT: PORT,
3502
3504
  ...AKAN_PUBLIC_SERVER_PORT ? { AKAN_PUBLIC_SERVER_PORT } : {},
3503
3505
  ...env
3504
3506
  };
@@ -11886,6 +11888,15 @@ var createWorkflowPlan = (spec, rawInputs) => {
11886
11888
  }
11887
11889
  inputs[name] = value;
11888
11890
  }
11891
+ const fieldType = inputs.type;
11892
+ if (spec.name === "add-field" && typeof fieldType === "string" && (fieldType.toLowerCase() === "number" || fieldType.toLowerCase() === "numeric")) {
11893
+ diagnostics.push({
11894
+ severity: "error",
11895
+ code: "primitive-field-type-unsupported",
11896
+ input: "type",
11897
+ message: `Field type "${fieldType}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`
11898
+ });
11899
+ }
11889
11900
  return {
11890
11901
  schemaVersion: 1,
11891
11902
  workflow: spec.name,
@@ -11971,29 +11982,37 @@ var createWorkflowApplyReport = ({
11971
11982
  mode,
11972
11983
  changedFiles = [],
11973
11984
  generatedFiles: generatedFiles2 = [],
11985
+ appliedCommands = [],
11986
+ recommendedValidationCommands,
11974
11987
  commands = [],
11975
11988
  diagnostics = [],
11976
11989
  nextActions = [],
11977
11990
  plan
11978
- }) => ({
11979
- schemaVersion: 1,
11980
- workflow,
11981
- mode,
11982
- status: workflowStatus(diagnostics),
11983
- changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
11984
- generatedFiles: uniqueBy(generatedFiles2, (file) => `${file.action}:${file.path}:${file.reason}`),
11985
- commands: uniqueBy(commands, (command3) => command3.command),
11986
- diagnostics,
11987
- nextActions: uniqueBy(nextActions, (action) => action.command),
11988
- plan
11989
- });
11991
+ }) => {
11992
+ const validationCommands2 = recommendedValidationCommands ?? commands;
11993
+ return {
11994
+ schemaVersion: 1,
11995
+ workflow,
11996
+ mode,
11997
+ status: workflowStatus(diagnostics),
11998
+ changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
11999
+ generatedFiles: uniqueBy(generatedFiles2, (file) => `${file.action}:${file.path}:${file.reason}`),
12000
+ appliedCommands: uniqueBy(appliedCommands, (command3) => command3.command),
12001
+ recommendedValidationCommands: uniqueBy(validationCommands2, (command3) => command3.command),
12002
+ commands: uniqueBy(validationCommands2, (command3) => command3.command),
12003
+ diagnostics,
12004
+ nextActions: uniqueBy(nextActions, (action) => action.command),
12005
+ plan
12006
+ };
12007
+ };
11990
12008
  var resolveWorkflowCommand = (command3, plan) => {
11991
12009
  const target = typeof plan.inputs.app === "string" ? plan.inputs.app : "<app-or-lib>";
11992
12010
  return command3.replaceAll("<app-or-lib-or-pkg>", target).replaceAll("<app-or-lib>", target).replaceAll("<app-name>", target);
11993
12011
  };
11994
12012
  var workflowCommandsForPlan = (plan) => plan.validation.map((validation) => ({
11995
12013
  command: resolveWorkflowCommand(validation.command, plan),
11996
- reason: validation.reason
12014
+ reason: validation.reason,
12015
+ kind: validation.kind
11997
12016
  }));
11998
12017
  var workflowRunsDir = ".akan/workflows/runs";
11999
12018
  var createWorkflowRunId = (prefix = "run") => `${prefix}-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -12006,7 +12025,7 @@ var workflowRunArtifactPath = (runId) => `${workflowRunsDir}/${runId}.json`;
12006
12025
  var writeWorkflowRunArtifact = async (workspace, artifact) => {
12007
12026
  const runId = getRunId(artifact);
12008
12027
  const artifactPath = workflowRunArtifactPath(runId);
12009
- await workspace.writeFile(artifactPath, jsonText(artifact));
12028
+ await workspace.writeFile(artifactPath, jsonText(artifact), { silent: true });
12010
12029
  return { runId, path: artifactPath };
12011
12030
  };
12012
12031
  var readWorkflowRunArtifact = async (workspace, runId) => {
@@ -12033,7 +12052,10 @@ var createWorkflowValidationRunReport = async ({
12033
12052
  {
12034
12053
  severity: "error",
12035
12054
  code: "workflow-validation-command-failed",
12036
- message: `Validation command failed: ${result.command}`
12055
+ message: `Validation command failed: ${result.command}`,
12056
+ command: result.command,
12057
+ kind: result.kind,
12058
+ failureScope: result.failureScope
12037
12059
  }
12038
12060
  ] : []);
12039
12061
  return {
@@ -12216,8 +12238,11 @@ var renderWorkflowApplyReport = (report) => [
12216
12238
  "## Generated Files",
12217
12239
  ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12218
12240
  "",
12219
- "## Commands",
12220
- ...report.commands.length ? report.commands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12241
+ "## Applied Commands",
12242
+ ...report.appliedCommands.length ? report.appliedCommands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12243
+ "",
12244
+ "## Recommended Validation Commands",
12245
+ ...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12221
12246
  "",
12222
12247
  "## Diagnostics",
12223
12248
  ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
@@ -12235,7 +12260,10 @@ var renderWorkflowValidationRunReport = (report) => [
12235
12260
  `- Status: ${report.status}`,
12236
12261
  "",
12237
12262
  "## Commands",
12238
- ...report.commands.length ? report.commands.map((command3) => `- [${command3.status}] \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12263
+ ...report.commands.length ? report.commands.map((command3) => {
12264
+ const scope = command3.failureScope ? ` (${command3.failureScope})` : "";
12265
+ return `- [${command3.status}] \`${command3.command}\`${scope}: ${command3.reason}`;
12266
+ }) : ["- none"],
12239
12267
  "",
12240
12268
  "## Diagnostics",
12241
12269
  ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
@@ -12305,7 +12333,7 @@ class WorkflowExecutor {
12305
12333
  async apply(plan) {
12306
12334
  const changedFiles = [];
12307
12335
  const generatedFiles2 = [];
12308
- const commands = [];
12336
+ const recommendedValidationCommands = [];
12309
12337
  const diagnostics = [...plan.diagnostics];
12310
12338
  const nextActions = [];
12311
12339
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
@@ -12314,13 +12342,13 @@ class WorkflowExecutor {
12314
12342
  mode: "apply",
12315
12343
  changedFiles,
12316
12344
  generatedFiles: generatedFiles2,
12317
- commands,
12345
+ recommendedValidationCommands,
12318
12346
  diagnostics,
12319
12347
  nextActions,
12320
12348
  plan
12321
12349
  });
12322
12350
  }
12323
- commands.push(...workflowCommandsForPlan(plan));
12351
+ recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
12324
12352
  nextActions.push(...workflowCommandsForPlan(plan));
12325
12353
  for (const step of plan.steps) {
12326
12354
  const runner2 = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
@@ -12341,7 +12369,7 @@ class WorkflowExecutor {
12341
12369
  continue;
12342
12370
  changedFiles.push(...result.changedFiles ?? []);
12343
12371
  generatedFiles2.push(...result.generatedFiles ?? []);
12344
- commands.push(...result.commands ?? []);
12372
+ recommendedValidationCommands.push(...result.commands ?? []);
12345
12373
  diagnostics.push(...result.diagnostics ?? []);
12346
12374
  nextActions.push(...result.nextActions ?? []);
12347
12375
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
@@ -12352,7 +12380,7 @@ class WorkflowExecutor {
12352
12380
  mode: "apply",
12353
12381
  changedFiles,
12354
12382
  generatedFiles: generatedFiles2,
12355
- commands,
12383
+ recommendedValidationCommands,
12356
12384
  diagnostics,
12357
12385
  nextActions,
12358
12386
  plan
@@ -12438,14 +12466,34 @@ var scalarChangedFiles = (sys3, scalarName, files) => Object.values(files).map((
12438
12466
  var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
12439
12467
  var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
12440
12468
  var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
12441
- var fieldExpression = (typeName, defaultValue) => {
12469
+ var normalizeFieldType = (typeName) => {
12442
12470
  const normalizedTypes = {
12443
12471
  string: "String",
12444
- number: "Number",
12445
12472
  boolean: "Boolean",
12446
- date: "Date"
12473
+ date: "Date",
12474
+ int: "Int",
12475
+ integer: "Int",
12476
+ float: "Float",
12477
+ double: "Float",
12478
+ decimal: "Float"
12447
12479
  };
12448
- const typeExpression = normalizedTypes[typeName.toLowerCase()] ?? typeName;
12480
+ return normalizedTypes[typeName.toLowerCase()] ?? typeName;
12481
+ };
12482
+ var ensureBaseTypeImport = (content, typeName) => {
12483
+ if (typeName !== "Int" && typeName !== "Float")
12484
+ return content;
12485
+ if (new RegExp(`import \\{[^}]*\\b${typeName}\\b[^}]*\\} from "akanjs/base";`).test(content))
12486
+ return content;
12487
+ const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
12488
+ if (baseImport) {
12489
+ const names = baseImport[1].split(",").map((name) => name.trim()).filter(Boolean);
12490
+ return content.replace(baseImport[0], `import { ${[...names, typeName].sort().join(", ")} } from "akanjs/base";`);
12491
+ }
12492
+ return `import { ${typeName} } from "akanjs/base";
12493
+ ${content}`;
12494
+ };
12495
+ var fieldExpression = (typeName, defaultValue) => {
12496
+ const typeExpression = normalizeFieldType(typeName);
12449
12497
  const defaultOption = defaultValue ? `, { default: ${JSON.stringify(defaultValue)} }` : "";
12450
12498
  return `field(${typeExpression}${defaultOption})`;
12451
12499
  };
package/index.js CHANGED
@@ -2807,7 +2807,7 @@ class Executor {
2807
2807
  this.logger.verbose(`Remove directory ${readPath}`);
2808
2808
  return this;
2809
2809
  }
2810
- async writeFile(filePath, content, { overwrite = true } = {}) {
2810
+ async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
2811
2811
  const writePath = this.getPath(filePath);
2812
2812
  const dir = path7.dirname(writePath);
2813
2813
  if (!await FileSys.dirExists(dir))
@@ -2825,7 +2825,8 @@ class Executor {
2825
2825
  }
2826
2826
  } else {
2827
2827
  await FileSys.writeText(writePath, contentStr);
2828
- this.logger.rawLog(chalk4.green(`File Create: ${filePath}`));
2828
+ if (!silent)
2829
+ this.logger.rawLog(chalk4.green(`File Create: ${filePath}`));
2829
2830
  }
2830
2831
  return { filePath: writePath, content: contentStr };
2831
2832
  }
@@ -3489,14 +3490,15 @@ class AppExecutor extends SysExecutor {
3489
3490
  getCommandEnv(env = {}) {
3490
3491
  const basePort = 8282;
3491
3492
  const portOffset = WorkspaceExecutor.getBaseDevEnv().portOffset;
3492
- const PORT = basePort ? (basePort + portOffset).toString() : undefined;
3493
+ const PORT = (basePort + portOffset).toString();
3493
3494
  const AKAN_PUBLIC_SERVER_PORT = portOffset ? (8282 + portOffset).toString() : undefined;
3494
3495
  return {
3495
3496
  ...process.env,
3496
3497
  AKAN_PUBLIC_APP_NAME: this.name,
3497
3498
  AKAN_WORKSPACE_ROOT: this.workspace.workspaceRoot,
3498
3499
  NODE_NO_WARNINGS: "1",
3499
- ...PORT ? { PORT, AKAN_PUBLIC_CLIENT_PORT: PORT } : {},
3500
+ PORT,
3501
+ AKAN_PUBLIC_CLIENT_PORT: PORT,
3500
3502
  ...AKAN_PUBLIC_SERVER_PORT ? { AKAN_PUBLIC_SERVER_PORT } : {},
3501
3503
  ...env
3502
3504
  };
@@ -11884,6 +11886,15 @@ var createWorkflowPlan = (spec, rawInputs) => {
11884
11886
  }
11885
11887
  inputs[name] = value;
11886
11888
  }
11889
+ const fieldType = inputs.type;
11890
+ if (spec.name === "add-field" && typeof fieldType === "string" && (fieldType.toLowerCase() === "number" || fieldType.toLowerCase() === "numeric")) {
11891
+ diagnostics.push({
11892
+ severity: "error",
11893
+ code: "primitive-field-type-unsupported",
11894
+ input: "type",
11895
+ message: `Field type "${fieldType}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`
11896
+ });
11897
+ }
11887
11898
  return {
11888
11899
  schemaVersion: 1,
11889
11900
  workflow: spec.name,
@@ -11969,29 +11980,37 @@ var createWorkflowApplyReport = ({
11969
11980
  mode,
11970
11981
  changedFiles = [],
11971
11982
  generatedFiles: generatedFiles2 = [],
11983
+ appliedCommands = [],
11984
+ recommendedValidationCommands,
11972
11985
  commands = [],
11973
11986
  diagnostics = [],
11974
11987
  nextActions = [],
11975
11988
  plan
11976
- }) => ({
11977
- schemaVersion: 1,
11978
- workflow,
11979
- mode,
11980
- status: workflowStatus(diagnostics),
11981
- changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
11982
- generatedFiles: uniqueBy(generatedFiles2, (file) => `${file.action}:${file.path}:${file.reason}`),
11983
- commands: uniqueBy(commands, (command3) => command3.command),
11984
- diagnostics,
11985
- nextActions: uniqueBy(nextActions, (action) => action.command),
11986
- plan
11987
- });
11989
+ }) => {
11990
+ const validationCommands2 = recommendedValidationCommands ?? commands;
11991
+ return {
11992
+ schemaVersion: 1,
11993
+ workflow,
11994
+ mode,
11995
+ status: workflowStatus(diagnostics),
11996
+ changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
11997
+ generatedFiles: uniqueBy(generatedFiles2, (file) => `${file.action}:${file.path}:${file.reason}`),
11998
+ appliedCommands: uniqueBy(appliedCommands, (command3) => command3.command),
11999
+ recommendedValidationCommands: uniqueBy(validationCommands2, (command3) => command3.command),
12000
+ commands: uniqueBy(validationCommands2, (command3) => command3.command),
12001
+ diagnostics,
12002
+ nextActions: uniqueBy(nextActions, (action) => action.command),
12003
+ plan
12004
+ };
12005
+ };
11988
12006
  var resolveWorkflowCommand = (command3, plan) => {
11989
12007
  const target = typeof plan.inputs.app === "string" ? plan.inputs.app : "<app-or-lib>";
11990
12008
  return command3.replaceAll("<app-or-lib-or-pkg>", target).replaceAll("<app-or-lib>", target).replaceAll("<app-name>", target);
11991
12009
  };
11992
12010
  var workflowCommandsForPlan = (plan) => plan.validation.map((validation) => ({
11993
12011
  command: resolveWorkflowCommand(validation.command, plan),
11994
- reason: validation.reason
12012
+ reason: validation.reason,
12013
+ kind: validation.kind
11995
12014
  }));
11996
12015
  var workflowRunsDir = ".akan/workflows/runs";
11997
12016
  var createWorkflowRunId = (prefix = "run") => `${prefix}-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -12004,7 +12023,7 @@ var workflowRunArtifactPath = (runId) => `${workflowRunsDir}/${runId}.json`;
12004
12023
  var writeWorkflowRunArtifact = async (workspace, artifact) => {
12005
12024
  const runId = getRunId(artifact);
12006
12025
  const artifactPath = workflowRunArtifactPath(runId);
12007
- await workspace.writeFile(artifactPath, jsonText(artifact));
12026
+ await workspace.writeFile(artifactPath, jsonText(artifact), { silent: true });
12008
12027
  return { runId, path: artifactPath };
12009
12028
  };
12010
12029
  var readWorkflowRunArtifact = async (workspace, runId) => {
@@ -12031,7 +12050,10 @@ var createWorkflowValidationRunReport = async ({
12031
12050
  {
12032
12051
  severity: "error",
12033
12052
  code: "workflow-validation-command-failed",
12034
- message: `Validation command failed: ${result.command}`
12053
+ message: `Validation command failed: ${result.command}`,
12054
+ command: result.command,
12055
+ kind: result.kind,
12056
+ failureScope: result.failureScope
12035
12057
  }
12036
12058
  ] : []);
12037
12059
  return {
@@ -12214,8 +12236,11 @@ var renderWorkflowApplyReport = (report) => [
12214
12236
  "## Generated Files",
12215
12237
  ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12216
12238
  "",
12217
- "## Commands",
12218
- ...report.commands.length ? report.commands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12239
+ "## Applied Commands",
12240
+ ...report.appliedCommands.length ? report.appliedCommands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12241
+ "",
12242
+ "## Recommended Validation Commands",
12243
+ ...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12219
12244
  "",
12220
12245
  "## Diagnostics",
12221
12246
  ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
@@ -12233,7 +12258,10 @@ var renderWorkflowValidationRunReport = (report) => [
12233
12258
  `- Status: ${report.status}`,
12234
12259
  "",
12235
12260
  "## Commands",
12236
- ...report.commands.length ? report.commands.map((command3) => `- [${command3.status}] \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12261
+ ...report.commands.length ? report.commands.map((command3) => {
12262
+ const scope = command3.failureScope ? ` (${command3.failureScope})` : "";
12263
+ return `- [${command3.status}] \`${command3.command}\`${scope}: ${command3.reason}`;
12264
+ }) : ["- none"],
12237
12265
  "",
12238
12266
  "## Diagnostics",
12239
12267
  ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
@@ -12303,7 +12331,7 @@ class WorkflowExecutor {
12303
12331
  async apply(plan) {
12304
12332
  const changedFiles = [];
12305
12333
  const generatedFiles2 = [];
12306
- const commands = [];
12334
+ const recommendedValidationCommands = [];
12307
12335
  const diagnostics = [...plan.diagnostics];
12308
12336
  const nextActions = [];
12309
12337
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
@@ -12312,13 +12340,13 @@ class WorkflowExecutor {
12312
12340
  mode: "apply",
12313
12341
  changedFiles,
12314
12342
  generatedFiles: generatedFiles2,
12315
- commands,
12343
+ recommendedValidationCommands,
12316
12344
  diagnostics,
12317
12345
  nextActions,
12318
12346
  plan
12319
12347
  });
12320
12348
  }
12321
- commands.push(...workflowCommandsForPlan(plan));
12349
+ recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
12322
12350
  nextActions.push(...workflowCommandsForPlan(plan));
12323
12351
  for (const step of plan.steps) {
12324
12352
  const runner2 = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
@@ -12339,7 +12367,7 @@ class WorkflowExecutor {
12339
12367
  continue;
12340
12368
  changedFiles.push(...result.changedFiles ?? []);
12341
12369
  generatedFiles2.push(...result.generatedFiles ?? []);
12342
- commands.push(...result.commands ?? []);
12370
+ recommendedValidationCommands.push(...result.commands ?? []);
12343
12371
  diagnostics.push(...result.diagnostics ?? []);
12344
12372
  nextActions.push(...result.nextActions ?? []);
12345
12373
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
@@ -12350,7 +12378,7 @@ class WorkflowExecutor {
12350
12378
  mode: "apply",
12351
12379
  changedFiles,
12352
12380
  generatedFiles: generatedFiles2,
12353
- commands,
12381
+ recommendedValidationCommands,
12354
12382
  diagnostics,
12355
12383
  nextActions,
12356
12384
  plan
@@ -12436,14 +12464,34 @@ var scalarChangedFiles = (sys3, scalarName, files) => Object.values(files).map((
12436
12464
  var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
12437
12465
  var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
12438
12466
  var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
12439
- var fieldExpression = (typeName, defaultValue) => {
12467
+ var normalizeFieldType = (typeName) => {
12440
12468
  const normalizedTypes = {
12441
12469
  string: "String",
12442
- number: "Number",
12443
12470
  boolean: "Boolean",
12444
- date: "Date"
12471
+ date: "Date",
12472
+ int: "Int",
12473
+ integer: "Int",
12474
+ float: "Float",
12475
+ double: "Float",
12476
+ decimal: "Float"
12445
12477
  };
12446
- const typeExpression = normalizedTypes[typeName.toLowerCase()] ?? typeName;
12478
+ return normalizedTypes[typeName.toLowerCase()] ?? typeName;
12479
+ };
12480
+ var ensureBaseTypeImport = (content, typeName) => {
12481
+ if (typeName !== "Int" && typeName !== "Float")
12482
+ return content;
12483
+ if (new RegExp(`import \\{[^}]*\\b${typeName}\\b[^}]*\\} from "akanjs/base";`).test(content))
12484
+ return content;
12485
+ const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
12486
+ if (baseImport) {
12487
+ const names = baseImport[1].split(",").map((name) => name.trim()).filter(Boolean);
12488
+ return content.replace(baseImport[0], `import { ${[...names, typeName].sort().join(", ")} } from "akanjs/base";`);
12489
+ }
12490
+ return `import { ${typeName} } from "akanjs/base";
12491
+ ${content}`;
12492
+ };
12493
+ var fieldExpression = (typeName, defaultValue) => {
12494
+ const typeExpression = normalizeFieldType(typeName);
12447
12495
  const defaultOption = defaultValue ? `, { default: ${JSON.stringify(defaultValue)} }` : "";
12448
12496
  return `field(${typeExpression}${defaultOption})`;
12449
12497
  };
@@ -14194,6 +14242,9 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
14194
14242
  // pkgs/@akanjs/cli/context/context.script.ts
14195
14243
  import { Logger as Logger17 } from "akanjs/common";
14196
14244
 
14245
+ // pkgs/@akanjs/cli/context/context.runner.ts
14246
+ import path43 from "path";
14247
+
14197
14248
  // pkgs/@akanjs/cli/module/module.script.ts
14198
14249
  import { input as input6 } from "@inquirer/prompts";
14199
14250
  import { capitalize as capitalize8, randomPicks } from "akanjs/common";
@@ -14833,6 +14884,8 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
14833
14884
  }
14834
14885
  async addFieldToSources(workspace, input7, { enumValues }) {
14835
14886
  const sys3 = await this.resolveSys(workspace, input7.app);
14887
+ const ambiguousNumberTypes = new Set(["number", "numeric"]);
14888
+ const normalizedType = input7.type ? normalizeFieldType(input7.type) : null;
14836
14889
  const diagnostics = compactDiagnostics([
14837
14890
  !sys3 && { severity: "error", code: "primitive-target-missing", message: "Target app or library was not found." },
14838
14891
  !input7.module && {
@@ -14853,7 +14906,13 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
14853
14906
  message: "Type is required.",
14854
14907
  input: "type"
14855
14908
  },
14856
- enumValues && enumValues.length === 0 ? { severity: "error", code: "primitive-input-missing", message: "Enum values are required.", input: "values" } : null
14909
+ enumValues && enumValues.length === 0 ? { severity: "error", code: "primitive-input-missing", message: "Enum values are required.", input: "values" } : null,
14910
+ input7.type && ambiguousNumberTypes.has(input7.type.toLowerCase()) ? {
14911
+ severity: "error",
14912
+ code: "primitive-field-type-unsupported",
14913
+ message: `Field type "${input7.type}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`,
14914
+ input: "type"
14915
+ } : null
14857
14916
  ]);
14858
14917
  if (!sys3 || !input7.module || !input7.field || !input7.type || diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
14859
14918
  return createPrimitiveWriteReport({
@@ -14923,6 +14982,10 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
14923
14982
  dictionaryContent = enumDictionary;
14924
14983
  }
14925
14984
  }
14985
+ if (!enumValues && normalizedType) {
14986
+ input7.type = normalizedType;
14987
+ constantContent = ensureBaseTypeImport(constantContent, input7.type);
14988
+ }
14926
14989
  const nextConstantContent = insertIntoObject(constantContent, inputClassName, `${input7.field}: ${fieldExpression(input7.type, input7.defaultValue)},`);
14927
14990
  const nextDictionaryContent = insertDictionaryModelField(dictionaryContent, moduleClassName, input7.field);
14928
14991
  if (!nextConstantContent) {
@@ -15310,8 +15373,12 @@ var moduleInput = {
15310
15373
  }
15311
15374
  };
15312
15375
  var baseValidation = [
15313
- { command: "akan sync <app-or-lib>", reason: "Refresh generated Akan files from source conventions." },
15314
- { command: "akan lint <app-or-lib-or-pkg>", reason: "Validate formatting, imports, and static lint rules." }
15376
+ { command: "akan sync <app-or-lib>", reason: "Refresh generated Akan files from source conventions.", kind: "sync" },
15377
+ {
15378
+ command: "akan lint <app-or-lib-or-pkg>",
15379
+ reason: "Validate formatting, imports, and static lint rules.",
15380
+ kind: "lint"
15381
+ }
15315
15382
  ];
15316
15383
 
15317
15384
  // pkgs/@akanjs/cli/workflows/addEnumField.ts
@@ -15381,7 +15448,7 @@ var addEnumFieldWorkflowSpec = {
15381
15448
  ],
15382
15449
  validation: [
15383
15450
  ...baseValidation,
15384
- { command: "akan typecheck <app-name>", reason: "Validate enum usage across module surfaces." }
15451
+ { command: "akan typecheck <app-name>", reason: "Validate enum usage across module surfaces.", kind: "typecheck" }
15385
15452
  ],
15386
15453
  completionCriteria: ["Enum values are represented.", "Labels and options exist.", "Sync, lint, and typecheck pass."]
15387
15454
  };
@@ -15396,7 +15463,11 @@ var addFieldWorkflowSpec = {
15396
15463
  ...sysInputs,
15397
15464
  ...moduleInput,
15398
15465
  field: { type: "string", required: true, description: "Name of the field to add." },
15399
- type: { type: "string", required: true, description: "Field type or scalar name." },
15466
+ type: {
15467
+ type: "string",
15468
+ required: true,
15469
+ description: "Field type or scalar name. Use Int for integer fields or Float for decimal fields; do not use Number."
15470
+ },
15400
15471
  values: { type: "string-list", description: "Comma-separated enum values when type is enum." },
15401
15472
  default: { type: "string", description: "Optional default value for the field." }
15402
15473
  },
@@ -15461,7 +15532,8 @@ var addFieldWorkflowSpec = {
15461
15532
  ...baseValidation,
15462
15533
  {
15463
15534
  command: "akan typecheck <app-name>",
15464
- reason: "Validate cross-surface TypeScript contracts after field changes."
15535
+ reason: "Validate cross-surface TypeScript contracts after field changes.",
15536
+ kind: "typecheck"
15465
15537
  }
15466
15538
  ],
15467
15539
  completionCriteria: [
@@ -15538,7 +15610,11 @@ var addMutationWorkflowSpec = {
15538
15610
  ],
15539
15611
  validation: [
15540
15612
  ...baseValidation,
15541
- { command: "akan typecheck <app-name>", reason: "Validate mutation contracts across service and signal." }
15613
+ {
15614
+ command: "akan typecheck <app-name>",
15615
+ reason: "Validate mutation contracts across service and signal.",
15616
+ kind: "typecheck"
15617
+ }
15542
15618
  ],
15543
15619
  completionCriteria: ["Service and signal contracts align.", "Generated files are refreshed.", "Validation passes."]
15544
15620
  };
@@ -15609,7 +15685,8 @@ var addSliceWorkflowSpec = {
15609
15685
  ...baseValidation,
15610
15686
  {
15611
15687
  command: "akan build <app-name>",
15612
- reason: "Validate page and list surfaces when a slice changes app behavior."
15688
+ reason: "Validate page and list surfaces when a slice changes app behavior.",
15689
+ kind: "custom"
15613
15690
  }
15614
15691
  ],
15615
15692
  completionCriteria: [
@@ -15828,7 +15905,36 @@ var failedApplyReport = (workflow2, diagnostics, plan) => createWorkflowApplyRep
15828
15905
  plan: plan ?? failedPlan(workflow2, diagnostics)
15829
15906
  });
15830
15907
  var commandForShell2 = (command3) => command3.startsWith("akan ") ? `bun run ${command3}` : command3;
15908
+ var inferValidationKind = (command3) => {
15909
+ if (command3.kind)
15910
+ return command3.kind;
15911
+ if (/\bakan\s+sync\b/.test(command3.command))
15912
+ return "sync";
15913
+ if (/\bakan\s+lint\b/.test(command3.command))
15914
+ return "lint";
15915
+ if (/\bakan\s+typecheck\b/.test(command3.command))
15916
+ return "typecheck";
15917
+ if (/\bakan\s+doctor\b/.test(command3.command))
15918
+ return "doctor";
15919
+ return "custom";
15920
+ };
15921
+ var classifyValidationFailure = (command3, error) => {
15922
+ const output = `${error.stdout ?? ""}
15923
+ ${error.stderr ?? ""}
15924
+ ${error.message ?? ""}`.toLowerCase();
15925
+ if (error.code === 127 || output.includes("command not found") || output.includes("bun: command not found")) {
15926
+ return "environment";
15927
+ }
15928
+ if (output.includes("biome.json") || output.includes("biome configuration") || output.includes("configuration file") || output.includes("invalid configuration") || output.includes("failed to load")) {
15929
+ return "workspace-config";
15930
+ }
15931
+ const kind = inferValidationKind(command3);
15932
+ if (kind === "lint" || kind === "typecheck" || kind === "sync")
15933
+ return "source-change";
15934
+ return "unknown";
15935
+ };
15831
15936
  var defaultValidationExecutor = (workspace) => async (command3) => {
15937
+ const kind = inferValidationKind(command3);
15832
15938
  try {
15833
15939
  const stdout = await workspace.spawn("bash", ["-lc", commandForShell2(command3.command)], {
15834
15940
  cwd: workspace.workspaceRoot
@@ -15836,6 +15942,7 @@ var defaultValidationExecutor = (workspace) => async (command3) => {
15836
15942
  return {
15837
15943
  command: command3.command,
15838
15944
  reason: command3.reason,
15945
+ kind,
15839
15946
  status: "passed",
15840
15947
  exitCode: 0,
15841
15948
  stdout
@@ -15845,8 +15952,10 @@ var defaultValidationExecutor = (workspace) => async (command3) => {
15845
15952
  return {
15846
15953
  command: command3.command,
15847
15954
  reason: command3.reason,
15955
+ kind,
15848
15956
  status: "failed",
15849
15957
  exitCode: commandError.code ?? 1,
15958
+ failureScope: classifyValidationFailure(command3, commandError),
15850
15959
  stdout: commandError.stdout,
15851
15960
  stderr: commandError.stderr ?? commandError.message
15852
15961
  };
@@ -16060,6 +16169,21 @@ var stringProperty = { type: "string" };
16060
16169
  var booleanProperty = { type: "boolean" };
16061
16170
  var objectProperty = { type: "object", additionalProperties: true };
16062
16171
  var parseJsonOutput = (output) => JSON.parse(output);
16172
+ var slugPart = (value) => typeof value === "string" ? value.trim().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() : "";
16173
+ var defaultWorkflowPlanPath = (workflow2, inputs) => {
16174
+ const slug = [
16175
+ slugPart(workflow2),
16176
+ slugPart(inputs.app),
16177
+ slugPart(inputs.module),
16178
+ slugPart(inputs.field),
16179
+ slugPart(inputs.scalar),
16180
+ slugPart(inputs.surface),
16181
+ slugPart(inputs.mutation),
16182
+ slugPart(inputs.slice)
16183
+ ].filter(Boolean).join("-");
16184
+ return `.akan/workflows/plans/${slug || "workflow-plan"}.json`;
16185
+ };
16186
+ var workspacePath = (workspace, filePath) => path43.isAbsolute(filePath) ? filePath : path43.join(workspace.workspaceRoot, filePath);
16063
16187
  var stringArg = (args, key) => {
16064
16188
  const value = args[key];
16065
16189
  if (typeof value !== "string" || !value)
@@ -16112,7 +16236,7 @@ var planMcpTools = [
16112
16236
  name: "plan_workflow",
16113
16237
  inputSchema: {
16114
16238
  type: "object",
16115
- properties: { workflow: stringProperty, inputs: objectProperty },
16239
+ properties: { workflow: stringProperty, inputs: objectProperty, out: stringProperty },
16116
16240
  required: ["workflow"]
16117
16241
  }
16118
16242
  }
@@ -16238,6 +16362,8 @@ class ContextRunner extends runner("context") {
16238
16362
  "akan workflow report <run-id> --format json",
16239
16363
  "akan doctor --strict --format json"
16240
16364
  ],
16365
+ validationFailureScopes: ["workspace-config", "environment", "source-change", "unknown"],
16366
+ applyReportFields: ["appliedCommands", "recommendedValidationCommands", "commands"],
16241
16367
  repairCommands: [
16242
16368
  "akan repair generated --app <app-or-lib> --format json",
16243
16369
  "akan repair format --target <app-or-lib-or-pkg> --format json",
@@ -16250,18 +16376,27 @@ class ContextRunner extends runner("context") {
16250
16376
  return parseJsonOutput(new WorkflowRunner().list({ format: "json" }));
16251
16377
  if (name === "explain_workflow")
16252
16378
  return parseJsonOutput(new WorkflowRunner().explain(stringArg(args, "workflow"), { format: "json" }));
16253
- if (name === "plan_workflow")
16254
- return parseJsonOutput(await new WorkflowRunner().plan(stringArg(args, "workflow"), workflowInputsArg(args), {
16255
- format: "json"
16379
+ if (name === "plan_workflow") {
16380
+ const workflow2 = stringArg(args, "workflow");
16381
+ const inputs = workflowInputsArg(args);
16382
+ const planPath = typeof args.out === "string" && args.out ? args.out : defaultWorkflowPlanPath(workflow2, inputs);
16383
+ const plan = parseJsonOutput(await new WorkflowRunner().plan(workflow2, inputs, {
16384
+ format: "json",
16385
+ out: workspacePath(workspace, planPath)
16256
16386
  }));
16387
+ return { ...plan, planPath };
16388
+ }
16257
16389
  if (name === "apply_workflow")
16258
- return parseJsonOutput(await new WorkflowRunner().apply(stringArg(args, "planPath"), {
16390
+ return parseJsonOutput(await new WorkflowRunner().apply(workspacePath(workspace, stringArg(args, "planPath")), {
16259
16391
  format: "json",
16260
16392
  dryRun: !!args.dryRun,
16261
16393
  registry: createCliWorkflowStepRegistry(workspace)
16262
16394
  }));
16263
16395
  if (name === "run_validation")
16264
- return parseJsonOutput(await new WorkflowRunner().validate(stringArg(args, "runIdOrPlan"), { format: "json", workspace }));
16396
+ return parseJsonOutput(await new WorkflowRunner().validate(workspacePath(workspace, stringArg(args, "runIdOrPlan")), {
16397
+ format: "json",
16398
+ workspace
16399
+ }));
16265
16400
  if (name === "repair_generated")
16266
16401
  return parseJsonOutput(await new RepairRunner().repair("generated", { workspace, app: stringArg(args, "app"), format: "json" }));
16267
16402
  if (name === "repair_imports")
@@ -16427,7 +16562,7 @@ ${payload}`);
16427
16562
  "create-unit": "`akan create-unit --app <app> --module <module>` creates a module Unit component.",
16428
16563
  "create-template": "`akan create-template --app <app> --module <module>` creates a module Template component.",
16429
16564
  "create-ui": "`akan create-ui --app <app-or-lib> --module <module> --surface <view|unit|template> --format json` creates one UI surface and returns a primitive write report.",
16430
- "add-field": "`akan add-field --app <app-or-lib> --module <module> --field <field> --type <type> --format json` updates source constant/dictionary files and reports sync/lint next actions.",
16565
+ "add-field": "`akan add-field --app <app-or-lib> --module <module> --field <field> --type <String|Boolean|Date|Int|Float|scalar> --format json` updates source constant/dictionary files. Use Int or Float for numeric fields, not Number.",
16431
16566
  "add-enum-field": "`akan add-enum-field --app <app-or-lib> --module <module> --field <field> --values a,b --format json` adds an enum field to source constant/dictionary files without editing generated files.",
16432
16567
  sync: "`akan sync <app-or-lib>` refreshes generated Akan files from source conventions.",
16433
16568
  lint: "`akan lint <app-or-lib-or-pkg>` runs Biome linting after preparing generated files.",
@@ -16451,6 +16586,7 @@ ${payload}`);
16451
16586
  "repair module-shape": "`akan repair module-shape --app <app-or-lib> --module <module> --format json` reports missing module source files and source-safe next actions.",
16452
16587
  agent: "`akan agent install <target>` writes editor-specific agent rules with overwrite protection.",
16453
16588
  mcp: "`akan mcp --mode readonly|plan|apply` starts the Akan MCP server over stdio with an explicit permission mode.",
16589
+ "mcp-call": '`akan mcp-call <tool> --mode plan --args \'{"workflow":"add-field","inputs":{"app":"demo"}}\'` calls one MCP tool through the same runner path for debugging.',
16454
16590
  "mcp-install": "`akan mcp-install cursor --mode readonly|plan|apply` installs the Akan MCP server config for Cursor."
16455
16591
  };
16456
16592
  return explanations[command3] ?? `No detailed explanation is available for ${command3}. Run \`akan --help\` for command help.`;
@@ -16475,6 +16611,22 @@ class ContextScript extends script("context", [ContextRunner]) {
16475
16611
  async mcp(workspace, { mode = "readonly" } = {}) {
16476
16612
  await this.contextRunner.runMcp(workspace, { mode });
16477
16613
  }
16614
+ async mcpCall(workspace, tool, {
16615
+ mode = "readonly",
16616
+ args = null,
16617
+ format = "json"
16618
+ } = {}) {
16619
+ let parsedArgs = {};
16620
+ if (args) {
16621
+ const parsed = JSON.parse(args);
16622
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
16623
+ throw new Error("MCP call args must be a JSON object.");
16624
+ }
16625
+ parsedArgs = parsed;
16626
+ }
16627
+ const result = await this.contextRunner.callMcpTool(workspace, tool, parsedArgs, { mode });
16628
+ Logger17.rawLog(format === "json" ? jsonText(result) : String(result));
16629
+ }
16478
16630
  }
16479
16631
 
16480
16632
  // pkgs/@akanjs/cli/context/context.command.ts
@@ -16509,6 +16661,21 @@ class ContextCommand extends command("context", [ContextScript], ({ public: targ
16509
16661
  enum: ["readonly", "plan", "apply"]
16510
16662
  }).with(Workspace).exec(async function(mode, workspace) {
16511
16663
  await this.contextScript.mcp(workspace, { mode });
16664
+ }),
16665
+ mcpCall: target({ desc: "Call one Akan MCP tool for debugging without stdio JSON-RPC" }).arg("tool", String, { desc: "MCP tool name" }).option("mode", String, {
16666
+ desc: "MCP permission mode",
16667
+ default: "readonly",
16668
+ enum: ["readonly", "plan", "apply"]
16669
+ }).option("args", String, { desc: "JSON object to pass as MCP tool arguments", nullable: true }).option("format", String, {
16670
+ desc: "output format",
16671
+ default: "json",
16672
+ enum: ["json"]
16673
+ }).with(Workspace).exec(async function(tool, mode, args, format, workspace) {
16674
+ await this.contextScript.mcpCall(workspace, tool, {
16675
+ mode,
16676
+ args,
16677
+ format
16678
+ });
16512
16679
  })
16513
16680
  })) {
16514
16681
  }
@@ -16537,14 +16704,14 @@ class GuidelinePrompt extends Prompter {
16537
16704
  async#getScanFilePaths(matchPattern, { avoidDirs = ["node_modules", ".next"], filterText } = {}) {
16538
16705
  const glob = new Bun.Glob(matchPattern);
16539
16706
  const paths = [];
16540
- for await (const path43 of glob.scan({ cwd: this.workspace.workspaceRoot, absolute: true })) {
16541
- if (avoidDirs.some((dir) => path43.includes(dir)))
16707
+ for await (const path44 of glob.scan({ cwd: this.workspace.workspaceRoot, absolute: true })) {
16708
+ if (avoidDirs.some((dir) => path44.includes(dir)))
16542
16709
  continue;
16543
- const fileContent = await FileSys.readText(path43);
16710
+ const fileContent = await FileSys.readText(path44);
16544
16711
  const textFilter = filterText ? new RegExp(filterText) : null;
16545
16712
  if (filterText && !textFilter?.test(fileContent))
16546
16713
  continue;
16547
- paths.push(path43);
16714
+ paths.push(path44);
16548
16715
  }
16549
16716
  return paths;
16550
16717
  }
@@ -16864,7 +17031,7 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
16864
17031
 
16865
17032
  // pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
16866
17033
  import { mkdir as mkdir13, rm as rm6 } from "fs/promises";
16867
- import path43 from "path";
17034
+ import path44 from "path";
16868
17035
  import { Logger as Logger19 } from "akanjs/common";
16869
17036
  var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
16870
17037
  var containerName = "akan-verdaccio";
@@ -16882,8 +17049,8 @@ class LocalRegistryRunner extends runner("localRegistry") {
16882
17049
  Logger19.info(`Local registry is already running at ${registry}`);
16883
17050
  return registry;
16884
17051
  } catch {}
16885
- const configPath2 = path43.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
16886
- const storagePath = path43.join(workspace.workspaceRoot, ".akan/verdaccio/storage");
17052
+ const configPath2 = path44.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
17053
+ const storagePath = path44.join(workspace.workspaceRoot, ".akan/verdaccio/storage");
16887
17054
  await mkdir13(storagePath, { recursive: true });
16888
17055
  await workspace.spawn("docker", [
16889
17056
  "run",
@@ -16906,13 +17073,13 @@ class LocalRegistryRunner extends runner("localRegistry") {
16906
17073
  try {
16907
17074
  await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
16908
17075
  } catch {}
16909
- await rm6(path43.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
17076
+ await rm6(path44.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
16910
17077
  Logger19.info("Local registry storage has been reset");
16911
17078
  }
16912
17079
  async smoke(workspace, { registryUrl } = {}) {
16913
17080
  const registry = this.getRegistryUrl(registryUrl);
16914
- const smokeRoot = path43.join(workspace.workspaceRoot, ".akan/e2e");
16915
- await rm6(path43.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
17081
+ const smokeRoot = path44.join(workspace.workspaceRoot, ".akan/e2e");
17082
+ await rm6(path44.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
16916
17083
  await workspace.spawn(process.execPath, [
16917
17084
  "dist/pkgs/create-akan-workspace/index.js",
16918
17085
  smokeRepoName,
@@ -16929,12 +17096,12 @@ class LocalRegistryRunner extends runner("localRegistry") {
16929
17096
  stdio: "inherit"
16930
17097
  });
16931
17098
  await workspace.spawn("akan", ["typecheck", smokeAppName], {
16932
- cwd: path43.join(smokeRoot, smokeRepoName),
17099
+ cwd: path44.join(smokeRoot, smokeRepoName),
16933
17100
  env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
16934
17101
  stdio: "inherit"
16935
17102
  });
16936
17103
  await workspace.spawn("akan", ["build", smokeAppName], {
16937
- cwd: path43.join(smokeRoot, smokeRepoName),
17104
+ cwd: path44.join(smokeRoot, smokeRepoName),
16938
17105
  env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
16939
17106
  stdio: "inherit"
16940
17107
  });
@@ -17249,11 +17416,11 @@ class WorkflowCommand extends command("workflow", [WorkflowScript], ({ public: t
17249
17416
  }
17250
17417
 
17251
17418
  // pkgs/@akanjs/cli/workspace/workspace.script.ts
17252
- import path45 from "path";
17419
+ import path46 from "path";
17253
17420
  import { Logger as Logger25 } from "akanjs/common";
17254
17421
 
17255
17422
  // pkgs/@akanjs/cli/workspace/workspace.runner.ts
17256
- import path44 from "path";
17423
+ import path45 from "path";
17257
17424
  var defaultWorkspacePeerDependencies = new Set([
17258
17425
  "@react-spring/web",
17259
17426
  "@use-gesture/react",
@@ -17304,7 +17471,7 @@ class WorkspaceRunner extends runner("workspace") {
17304
17471
  owner = ""
17305
17472
  }) {
17306
17473
  const cwdPath = process.cwd();
17307
- const workspaceRoot = path44.join(cwdPath, dirname2, repoName);
17474
+ const workspaceRoot = path45.join(cwdPath, dirname2, repoName);
17308
17475
  const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
17309
17476
  const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
17310
17477
  const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname2}/${repoName}...`);
@@ -17360,9 +17527,9 @@ class WorkspaceRunner extends runner("workspace") {
17360
17527
  }
17361
17528
  async#getCliPackageJson() {
17362
17529
  const packageJsonCandidates = [
17363
- path44.join(import.meta.dir, "../package.json"),
17364
- path44.join(import.meta.dir, "package.json"),
17365
- path44.join(path44.dirname(Bun.main), "package.json")
17530
+ path45.join(import.meta.dir, "../package.json"),
17531
+ path45.join(import.meta.dir, "package.json"),
17532
+ path45.join(path45.dirname(Bun.main), "package.json")
17366
17533
  ];
17367
17534
  try {
17368
17535
  packageJsonCandidates.unshift(Bun.resolveSync("@akanjs/cli/package.json", import.meta.dir));
@@ -17378,9 +17545,9 @@ class WorkspaceRunner extends runner("workspace") {
17378
17545
  }
17379
17546
  async#getAkanPackageJson() {
17380
17547
  const packageJsonCandidates = [
17381
- path44.join(import.meta.dir, "../../../akanjs/package.json"),
17382
- path44.join(process.cwd(), "pkgs/akanjs/package.json"),
17383
- path44.join(path44.dirname(Bun.main), "node_modules/akanjs/package.json")
17548
+ path45.join(import.meta.dir, "../../../akanjs/package.json"),
17549
+ path45.join(process.cwd(), "pkgs/akanjs/package.json"),
17550
+ path45.join(path45.dirname(Bun.main), "node_modules/akanjs/package.json")
17384
17551
  ];
17385
17552
  try {
17386
17553
  packageJsonCandidates.unshift(Bun.resolveSync("akanjs/package.json", import.meta.dir));
@@ -17394,13 +17561,13 @@ class WorkspaceRunner extends runner("workspace") {
17394
17561
  }
17395
17562
  let current = import.meta.dir;
17396
17563
  for (let depth = 0;depth < 6; depth++) {
17397
- const packageJsonPath = path44.join(current, "package.json");
17564
+ const packageJsonPath = path45.join(current, "package.json");
17398
17565
  if (await Bun.file(packageJsonPath).exists()) {
17399
17566
  const packageJson = await FileSys.readJson(packageJsonPath);
17400
17567
  if (packageJson.name === "akanjs")
17401
17568
  return packageJson;
17402
17569
  }
17403
- const parent = path44.dirname(current);
17570
+ const parent = path45.dirname(current);
17404
17571
  if (parent === current)
17405
17572
  break;
17406
17573
  current = parent;
@@ -17477,10 +17644,10 @@ class WorkspaceScript extends script("workspace", [
17477
17644
  } catch (_) {
17478
17645
  gitSpinner.fail("Git repository initialization failed. It's not fatal, you can commit manually");
17479
17646
  }
17480
- const workspacePath = path45.join(dirname2, repoName);
17647
+ const workspacePath2 = path46.join(dirname2, repoName);
17481
17648
  Logger25.rawLog(`
17482
17649
  \uD83C\uDF89 Welcome aboard! Workspace created in ${dirname2}/${repoName}`);
17483
- Logger25.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
17650
+ Logger25.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath2} && akan start ${appName}\` to start the development server.`);
17484
17651
  Logger25.rawLog(`
17485
17652
  \uD83D\uDC4B Happy coding!`);
17486
17653
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "2.3.9-rc.1",
3
+ "version": "2.3.9-rc.2",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/openai": "^1.4.6",
35
35
  "@tailwindcss/node": "^4.3.0",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "2.3.9-rc.1",
37
+ "akanjs": "2.3.9-rc.2",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "daisyui": "5.5.23",
@@ -8,8 +8,25 @@
8
8
  "lint": "akan lint",
9
9
  "typecheck": "akan typecheck",
10
10
  "test": "akan test",
11
- "setup:agent": "akan agent install all",
12
- "build": "akan build"
11
+ "build": "akan build",
12
+ "setup:agent": "akan agent install all --force",
13
+ "agent:setup": "akan agent install all --force",
14
+ "agent:doctor": "akan doctor --strict --format json",
15
+ "agent:context": "akan context --format json",
16
+ "agent:mcp:readonly": "akan mcp-install cursor --mode readonly --force",
17
+ "agent:mcp:plan": "akan mcp-install cursor --mode plan --force",
18
+ "agent:mcp:apply": "akan mcp-install cursor --mode apply --force",
19
+ "agent:workflows": "akan workflow list",
20
+ "agent:sample:context": "akan context --format markdown --app <%= appName %> --module project",
21
+ "agent:sample:service": "akan create-service billing <%= appName %> --format json",
22
+ "agent:sample:module": "akan create-module project <%= appName %> --page=true --format json",
23
+ "agent:sample:field": "akan add-field --app <%= appName %> --module project --field budget --type Int --default 0 --format json",
24
+ "agent:sample:status": "akan add-enum-field --app <%= appName %> --module project --field status --values draft,active,archived --default draft --format json",
25
+ "agent:sample:sync": "akan sync <%= appName %>",
26
+ "agent:sample:check": "akan doctor --strict --format json",
27
+ "agent:sample:workflow:explain": "akan workflow explain add-field",
28
+ "agent:sample:workflow:plan": "akan workflow plan add-field --app <%= appName %> --module task --field priority --type enum --values low,medium,high --default medium --format json --out .akan/workflows/plans/task-priority.json",
29
+ "agent:sample:workflow:dry-run": "akan workflow apply .akan/workflows/plans/task-priority.json --dry-run --format json"
13
30
  },
14
31
  "dependencies": {},
15
32
  "devDependencies": {},