@akanjs/cli 2.3.9-rc.5 → 2.3.9-rc.7

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.
@@ -4807,11 +4807,17 @@ var createWorkflowApplyReport = ({
4807
4807
  recommendedValidationCommands,
4808
4808
  commands = [],
4809
4809
  diagnostics = [],
4810
+ postApplyChecks = [],
4810
4811
  recommendations = [],
4811
4812
  nextActions = [],
4812
4813
  plan
4813
4814
  }) => {
4814
4815
  const validationCommands = recommendedValidationCommands ?? commands;
4816
+ const orderedNextActions = uniqueBy(nextActions, (action) => action.command).sort((left, right) => {
4817
+ const leftRepair = left.command.startsWith("akan workflow explain") ? 0 : 1;
4818
+ const rightRepair = right.command.startsWith("akan workflow explain") ? 0 : 1;
4819
+ return leftRepair - rightRepair;
4820
+ });
4815
4821
  return {
4816
4822
  schemaVersion: 1,
4817
4823
  workflow,
@@ -4823,8 +4829,9 @@ var createWorkflowApplyReport = ({
4823
4829
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
4824
4830
  commands: uniqueBy(validationCommands, (command) => command.command),
4825
4831
  diagnostics,
4832
+ postApplyChecks,
4826
4833
  recommendations: uniqueBy(recommendations, (recommendation) => `${recommendation.kind}:${recommendation.code}`),
4827
- nextActions: uniqueBy(nextActions, (action) => action.command),
4834
+ nextActions: orderedNextActions.slice(0, 3),
4828
4835
  plan
4829
4836
  };
4830
4837
  };
@@ -5048,6 +5055,7 @@ var createRepairReport = ({
5048
5055
  });
5049
5056
  // pkgs/@akanjs/devkit/workflow/executor.ts
5050
5057
  import { capitalize as capitalize2 } from "akanjs/common";
5058
+ import ts4 from "typescript";
5051
5059
 
5052
5060
  // pkgs/@akanjs/devkit/workflow/primitive.ts
5053
5061
  var createPrimitiveWriteReport = ({
@@ -5334,7 +5342,14 @@ var fieldExpression = (typeName, defaultValue, options = {}) => {
5334
5342
  const typeExpression = normalizeFieldType(typeName);
5335
5343
  const defaultExpression = coerceFieldDefault(options.enumValues ? "enum" : typeExpression, defaultValue, options).expression;
5336
5344
  const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
5337
- return `field(${typeExpression}${defaultOption})`;
5345
+ return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
5346
+ };
5347
+ var viaBuilderParameterName = (content, className) => {
5348
+ const classIndex = content.indexOf(`export class ${className} extends via`);
5349
+ if (classIndex < 0)
5350
+ return null;
5351
+ const signature = content.slice(classIndex, content.indexOf("=>", classIndex));
5352
+ return /via\(\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(signature)?.[1] ?? null;
5338
5353
  };
5339
5354
  var insertIntoObject = (content, className, line) => {
5340
5355
  const classIndex = content.indexOf(`export class ${className} extends via`);
@@ -5422,19 +5437,69 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
5422
5437
  ${enumClass}`;
5423
5438
  return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
5424
5439
  };
5440
+ var findMatchingBrace = (content, openIndex) => {
5441
+ let depth = 0;
5442
+ let quote = null;
5443
+ let escaped = false;
5444
+ for (let index = openIndex;index < content.length; index++) {
5445
+ const char = content[index];
5446
+ if (quote) {
5447
+ if (escaped) {
5448
+ escaped = false;
5449
+ continue;
5450
+ }
5451
+ if (char === "\\") {
5452
+ escaped = true;
5453
+ continue;
5454
+ }
5455
+ if (char === quote)
5456
+ quote = null;
5457
+ continue;
5458
+ }
5459
+ if (char === '"' || char === "'" || char === "`") {
5460
+ quote = char;
5461
+ continue;
5462
+ }
5463
+ if (char === "{")
5464
+ depth += 1;
5465
+ if (char === "}") {
5466
+ depth -= 1;
5467
+ if (depth === 0)
5468
+ return index;
5469
+ }
5470
+ }
5471
+ return -1;
5472
+ };
5473
+ var dictionaryModelFieldLine = (fieldName) => {
5474
+ const label = bilingualLabelForField(fieldName);
5475
+ const desc = bilingualDescriptionForField(fieldName);
5476
+ return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
5477
+ };
5425
5478
  var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
5426
5479
  if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
5427
5480
  return content;
5428
- const label = bilingualLabelForField(fieldName);
5429
- const desc = bilingualDescriptionForField(fieldName);
5430
- const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => ({`);
5481
+ const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => (`);
5431
5482
  if (modelIndex < 0)
5432
5483
  return null;
5433
- const objectEndIndex = content.indexOf(" }))", modelIndex);
5484
+ const objectStartIndex = content.indexOf("{", modelIndex);
5485
+ if (objectStartIndex < 0)
5486
+ return null;
5487
+ const objectEndIndex = findMatchingBrace(content, objectStartIndex);
5434
5488
  if (objectEndIndex < 0)
5435
5489
  return null;
5436
- return `${content.slice(0, objectEndIndex)} ${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),
5437
- ${content.slice(objectEndIndex)}`;
5490
+ const fieldLine = dictionaryModelFieldLine(fieldName);
5491
+ const body = content.slice(objectStartIndex + 1, objectEndIndex);
5492
+ if (body.trim().length === 0) {
5493
+ return `${content.slice(0, objectStartIndex + 1)}
5494
+ ${fieldLine}
5495
+ ${content.slice(objectEndIndex)}`;
5496
+ }
5497
+ const insertion = body.endsWith(`
5498
+ `) ? ` ${fieldLine}
5499
+ ` : `
5500
+ ${fieldLine}
5501
+ `;
5502
+ return `${content.slice(0, objectEndIndex)}${insertion}${content.slice(objectEndIndex)}`;
5438
5503
  };
5439
5504
  var ensureConstantTypeImport = (content, constantPath, typeName) => {
5440
5505
  if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
@@ -5521,6 +5586,95 @@ var workflowStringInput = (value) => typeof value === "string" ? value : null;
5521
5586
  var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
5522
5587
  var workflowStringArrayInput = (value) => Array.isArray(value) ? value : null;
5523
5588
  var workflowBooleanInput = (value) => typeof value === "boolean" ? value : null;
5589
+ var postApplyDiagnostic = (code, message, target) => ({
5590
+ severity: "error",
5591
+ code,
5592
+ message,
5593
+ failureScope: "source-change",
5594
+ context: { target }
5595
+ });
5596
+ var sourceKindForPath = (filePath) => {
5597
+ if (filePath.endsWith(".tsx"))
5598
+ return ts4.ScriptKind.TSX;
5599
+ if (filePath.endsWith(".ts"))
5600
+ return ts4.ScriptKind.TS;
5601
+ return null;
5602
+ };
5603
+ var checkPathCasing = async (workspace, filePath) => {
5604
+ const segments = filePath.split("/").filter(Boolean);
5605
+ let current = ".";
5606
+ for (const segment of segments) {
5607
+ const entries = await workspace.readdir(current);
5608
+ if (entries.includes(segment)) {
5609
+ current = current === "." ? segment : `${current}/${segment}`;
5610
+ continue;
5611
+ }
5612
+ const caseInsensitiveMatch = entries.find((entry) => entry.toLowerCase() === segment.toLowerCase());
5613
+ return caseInsensitiveMatch ? {
5614
+ code: "workflow-path-casing-mismatch",
5615
+ message: `Reported path segment "${segment}" does not match actual casing "${caseInsensitiveMatch}" in ${filePath}.`
5616
+ } : {
5617
+ code: "workflow-path-missing",
5618
+ message: `Reported path does not exist: ${filePath}.`
5619
+ };
5620
+ }
5621
+ return null;
5622
+ };
5623
+ var checkTypeScriptSyntax = async (workspace, filePath) => {
5624
+ const scriptKind = sourceKindForPath(filePath);
5625
+ if (!scriptKind)
5626
+ return null;
5627
+ const content = await workspace.readFile(filePath);
5628
+ const source = ts4.createSourceFile(filePath, content, ts4.ScriptTarget.Latest, true, scriptKind);
5629
+ const diagnostic = source.parseDiagnostics[0];
5630
+ if (!diagnostic)
5631
+ return null;
5632
+ const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
5633
+ const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
5634
+ return {
5635
+ code: "workflow-post-apply-syntax-error",
5636
+ message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts4.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
5637
+ };
5638
+ };
5639
+ var checkChangedFile = async (workspace, file) => {
5640
+ if (file.action === "remove")
5641
+ return { postApplyChecks: [] };
5642
+ const diagnostics = [];
5643
+ const checks = [];
5644
+ const pathIssue = await checkPathCasing(workspace, file.path);
5645
+ if (pathIssue) {
5646
+ diagnostics.push(postApplyDiagnostic(pathIssue.code, pathIssue.message, file.path));
5647
+ checks.push({ ...pathIssue, target: file.path, status: "failed" });
5648
+ return { diagnostics, postApplyChecks: checks };
5649
+ }
5650
+ const syntaxIssue = await checkTypeScriptSyntax(workspace, file.path);
5651
+ if (syntaxIssue) {
5652
+ diagnostics.push(postApplyDiagnostic(syntaxIssue.code, syntaxIssue.message, file.path));
5653
+ checks.push({ ...syntaxIssue, target: file.path, status: "failed" });
5654
+ return { diagnostics, postApplyChecks: checks };
5655
+ }
5656
+ checks.push({
5657
+ code: "workflow-post-apply-file-valid",
5658
+ target: file.path,
5659
+ status: "passed",
5660
+ message: "Changed file exists with exact casing and parses as source when applicable."
5661
+ });
5662
+ return { postApplyChecks: checks };
5663
+ };
5664
+ var checkRecommendationPath = async (workspace, recommendation) => {
5665
+ if (!recommendation.target || recommendation.target.includes("*") || recommendation.target.startsWith("<"))
5666
+ return null;
5667
+ const pathIssue = await checkPathCasing(workspace, recommendation.target);
5668
+ if (!pathIssue)
5669
+ return null;
5670
+ return {
5671
+ severity: "warning",
5672
+ code: "workflow-recommendation-path-unverified",
5673
+ message: `${pathIssue.message} Recommendation "${recommendation.code}" should not be treated as an exact file target until the path is corrected.`,
5674
+ failureScope: "source-change",
5675
+ context: { target: recommendation.target }
5676
+ };
5677
+ };
5524
5678
  var resolveWorkflowSys = async (workspace, target) => {
5525
5679
  if (!target)
5526
5680
  return null;
@@ -5665,14 +5819,17 @@ var createWorkflowStepRegistry = ({
5665
5819
  };
5666
5820
  class WorkflowExecutor {
5667
5821
  registry;
5668
- constructor(registry) {
5822
+ workspace;
5823
+ constructor(registry, workspace) {
5669
5824
  this.registry = registry;
5825
+ this.workspace = workspace;
5670
5826
  }
5671
5827
  async apply(plan) {
5672
5828
  const changedFiles = [];
5673
5829
  const generatedFiles = [];
5674
5830
  const recommendedValidationCommands = [];
5675
5831
  const diagnostics = [...plan.diagnostics];
5832
+ const postApplyChecks = [];
5676
5833
  const recommendations = [...plan.recommendations];
5677
5834
  const nextActions = [];
5678
5835
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
@@ -5683,6 +5840,7 @@ class WorkflowExecutor {
5683
5840
  generatedFiles,
5684
5841
  recommendedValidationCommands,
5685
5842
  diagnostics,
5843
+ postApplyChecks,
5686
5844
  recommendations,
5687
5845
  nextActions,
5688
5846
  plan
@@ -5716,6 +5874,15 @@ class WorkflowExecutor {
5716
5874
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
5717
5875
  break;
5718
5876
  }
5877
+ if (this.workspace && !diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
5878
+ for (const file of changedFiles) {
5879
+ const result = await checkChangedFile(this.workspace, file);
5880
+ postApplyChecks.push(...result.postApplyChecks ?? []);
5881
+ diagnostics.push(...result.diagnostics ?? []);
5882
+ }
5883
+ const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
5884
+ diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
5885
+ }
5719
5886
  return createWorkflowApplyReport({
5720
5887
  workflow: plan.workflow,
5721
5888
  mode: "apply",
@@ -5723,6 +5890,7 @@ class WorkflowExecutor {
5723
5890
  generatedFiles,
5724
5891
  recommendedValidationCommands,
5725
5892
  diagnostics,
5893
+ postApplyChecks,
5726
5894
  recommendations,
5727
5895
  nextActions,
5728
5896
  plan
@@ -6112,19 +6280,29 @@ var renderRecommendation = (recommendation) => {
6112
6280
  return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
6113
6281
  };
6114
6282
  var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
6283
+ var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
6115
6284
  var renderWorkflowApplyReport = (report) => {
6116
6285
  const manualReviewItems = [
6117
6286
  ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
6118
6287
  ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
6119
6288
  ];
6120
6289
  const validationBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "workspace-config" || diagnostic.failureScope === "environment")).map(renderDiagnostic);
6290
+ const sourceBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")).map(renderDiagnostic);
6121
6291
  return [
6122
6292
  `# Workflow Apply: ${report.workflow}`,
6123
6293
  "",
6124
6294
  `- Mode: ${report.mode}`,
6125
6295
  `- Status: ${report.status}`,
6296
+ `- Source-change status: ${applySourceStatus(report)}`,
6297
+ `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
6126
6298
  ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
6127
6299
  "",
6300
+ "## Apply Checks",
6301
+ ...report.postApplyChecks?.length ? report.postApplyChecks.map((check) => `- [${check.status}] ${check.code} ${check.target}: ${check.message}`) : ["- not run"],
6302
+ "",
6303
+ "## Source Change Blockers",
6304
+ ...sourceBlockers.length ? sourceBlockers : ["- none"],
6305
+ "",
6128
6306
  "## Automatically Modified",
6129
6307
  ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6130
6308
  "",
@@ -6147,7 +6325,7 @@ var renderWorkflowApplyReport = (report) => {
6147
6325
  ...report.diagnostics.length ? report.diagnostics.map(renderDiagnostic) : ["- none"],
6148
6326
  "",
6149
6327
  "## Recommendations",
6150
- ...report.recommendations.length ? report.recommendations.map(renderRecommendation) : ["- none"],
6328
+ ...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
6151
6329
  "",
6152
6330
  "## Next Actions",
6153
6331
  ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
@@ -6166,10 +6344,16 @@ var renderWorkflowValidationRunReport = (report) => [
6166
6344
  `- Overall status: ${report.overallStatus}`,
6167
6345
  "",
6168
6346
  "## Status Summary",
6169
- `- Required source-change validation: ${report.summary.sourceChange}`,
6170
- `- Generated sync validation: ${report.summary.generatedSync}`,
6171
- `- Workspace configuration validation: ${report.summary.workspaceConfig}`,
6172
- `- Environment validation: ${report.summary.environment}`,
6347
+ `- Source-change: ${report.summary.sourceChange}`,
6348
+ `- Generated sync: ${report.summary.generatedSync}`,
6349
+ `- Workspace config: ${report.summary.workspaceConfig}`,
6350
+ `- Environment: ${report.summary.environment}`,
6351
+ "",
6352
+ "## Source Change Diagnostics",
6353
+ ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
6354
+ "",
6355
+ "## Existing Workspace Blockers",
6356
+ ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
6173
6357
  "",
6174
6358
  "## Known Blockers",
6175
6359
  ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
@@ -7245,7 +7429,7 @@ var collapseIndex = (relPathNoExt) => {
7245
7429
 
7246
7430
  // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
7247
7431
  import path14 from "path";
7248
- import ts4 from "typescript";
7432
+ import ts5 from "typescript";
7249
7433
  var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
7250
7434
  const akanConfig2 = await app.getConfig();
7251
7435
  const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
@@ -7486,11 +7670,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
7486
7670
  };
7487
7671
  var findImportStatements = (source2) => {
7488
7672
  const statements = [];
7489
- const sourceFile2 = ts4.createSourceFile("barrel-imports.tsx", source2, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
7673
+ const sourceFile2 = ts5.createSourceFile("barrel-imports.tsx", source2, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
7490
7674
  for (const statement of sourceFile2.statements) {
7491
- if (!ts4.isImportDeclaration(statement))
7675
+ if (!ts5.isImportDeclaration(statement))
7492
7676
  continue;
7493
- if (!ts4.isStringLiteral(statement.moduleSpecifier))
7677
+ if (!ts5.isStringLiteral(statement.moduleSpecifier))
7494
7678
  continue;
7495
7679
  const importClause = statement.importClause;
7496
7680
  if (!importClause)
@@ -8485,7 +8669,7 @@ import path22 from "path";
8485
8669
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
8486
8670
  import fs3 from "fs";
8487
8671
  import path21 from "path";
8488
- import ts5 from "typescript";
8672
+ import ts6 from "typescript";
8489
8673
 
8490
8674
  class PagesEntrySourceGenerator {
8491
8675
  #pageEntries;
@@ -8529,7 +8713,7 @@ ${entries.join(`
8529
8713
  static #hasAsyncDefaultExport(moduleAbsPath) {
8530
8714
  try {
8531
8715
  const source2 = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
8532
- const sourceFile2 = ts5.createSourceFile(moduleAbsPath, source2, ts5.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
8716
+ const sourceFile2 = ts6.createSourceFile(moduleAbsPath, source2, ts6.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
8533
8717
  return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
8534
8718
  } catch {
8535
8719
  return false;
@@ -8539,31 +8723,31 @@ ${entries.join(`
8539
8723
  const asyncBindings = new Map;
8540
8724
  let defaultIdentifier = null;
8541
8725
  for (const statement of sourceFile2.statements) {
8542
- if (ts5.isFunctionDeclaration(statement)) {
8543
- if (PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.DefaultKeyword)) {
8544
- return PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword);
8726
+ if (ts6.isFunctionDeclaration(statement)) {
8727
+ if (PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.DefaultKeyword)) {
8728
+ return PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword);
8545
8729
  }
8546
8730
  if (statement.name) {
8547
- asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword));
8731
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword));
8548
8732
  }
8549
8733
  continue;
8550
8734
  }
8551
- if (ts5.isVariableStatement(statement)) {
8735
+ if (ts6.isVariableStatement(statement)) {
8552
8736
  for (const declaration of statement.declarationList.declarations) {
8553
- if (!ts5.isIdentifier(declaration.name))
8737
+ if (!ts6.isIdentifier(declaration.name))
8554
8738
  continue;
8555
8739
  asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
8556
8740
  }
8557
8741
  continue;
8558
8742
  }
8559
- if (ts5.isExportAssignment(statement)) {
8743
+ if (ts6.isExportAssignment(statement)) {
8560
8744
  if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
8561
8745
  return true;
8562
- if (ts5.isIdentifier(statement.expression))
8746
+ if (ts6.isIdentifier(statement.expression))
8563
8747
  defaultIdentifier = statement.expression.text;
8564
8748
  continue;
8565
8749
  }
8566
- if (ts5.isExportDeclaration(statement) && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
8750
+ if (ts6.isExportDeclaration(statement) && statement.exportClause && ts6.isNamedExports(statement.exportClause)) {
8567
8751
  const exportClause = statement.exportClause;
8568
8752
  for (const specifier of exportClause.elements) {
8569
8753
  if (specifier.name.text !== "default")
@@ -8575,13 +8759,13 @@ ${entries.join(`
8575
8759
  return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
8576
8760
  }
8577
8761
  static #hasModifier(node, kind) {
8578
- return ts5.canHaveModifiers(node) && (ts5.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
8762
+ return ts6.canHaveModifiers(node) && (ts6.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
8579
8763
  }
8580
8764
  static #isAsyncFunctionExpression(node) {
8581
- return Boolean(node && (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts5.SyntaxKind.AsyncKeyword));
8765
+ return Boolean(node && (ts6.isArrowFunction(node) || ts6.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts6.SyntaxKind.AsyncKeyword));
8582
8766
  }
8583
8767
  static #scriptKind(moduleAbsPath) {
8584
- return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts5.ScriptKind.TSX : ts5.ScriptKind.TS;
8768
+ return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts6.ScriptKind.TSX : ts6.ScriptKind.TS;
8585
8769
  }
8586
8770
  }
8587
8771
 
@@ -9500,7 +9684,7 @@ import {
9500
9684
  } from "fontaine";
9501
9685
  import { createFont, woff2 } from "fonteditor-core";
9502
9686
  import subsetFont from "subset-font";
9503
- import ts6 from "typescript";
9687
+ import ts7 from "typescript";
9504
9688
  var FONT_URL_PREFIX = "/_akan/fonts";
9505
9689
  var DEFAULT_FONT_SUBSETS = ["latin"];
9506
9690
 
@@ -9565,17 +9749,17 @@ class FontOptimizer {
9565
9749
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
9566
9750
  }
9567
9751
  #extractFontsExport(source2, filePath) {
9568
- const sourceFile2 = ts6.createSourceFile(filePath, source2, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
9752
+ const sourceFile2 = ts7.createSourceFile(filePath, source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
9569
9753
  const fonts = [];
9570
9754
  for (const statement of sourceFile2.statements) {
9571
- if (!ts6.isVariableStatement(statement))
9755
+ if (!ts7.isVariableStatement(statement))
9572
9756
  continue;
9573
- const modifiers = ts6.canHaveModifiers(statement) ? ts6.getModifiers(statement) : undefined;
9574
- const isExported = modifiers?.some((modifier) => modifier.kind === ts6.SyntaxKind.ExportKeyword) ?? false;
9757
+ const modifiers = ts7.canHaveModifiers(statement) ? ts7.getModifiers(statement) : undefined;
9758
+ const isExported = modifiers?.some((modifier) => modifier.kind === ts7.SyntaxKind.ExportKeyword) ?? false;
9575
9759
  if (!isExported)
9576
9760
  continue;
9577
9761
  for (const declaration of statement.declarationList.declarations) {
9578
- if (!ts6.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9762
+ if (!ts7.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9579
9763
  continue;
9580
9764
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
9581
9765
  if (Array.isArray(value)) {
@@ -9586,20 +9770,20 @@ class FontOptimizer {
9586
9770
  return fonts;
9587
9771
  }
9588
9772
  #literalToValue(node) {
9589
- if (ts6.isStringLiteralLike(node))
9773
+ if (ts7.isStringLiteralLike(node))
9590
9774
  return node.text;
9591
- if (ts6.isNumericLiteral(node))
9775
+ if (ts7.isNumericLiteral(node))
9592
9776
  return Number(node.text);
9593
- if (node.kind === ts6.SyntaxKind.TrueKeyword)
9777
+ if (node.kind === ts7.SyntaxKind.TrueKeyword)
9594
9778
  return true;
9595
- if (node.kind === ts6.SyntaxKind.FalseKeyword)
9779
+ if (node.kind === ts7.SyntaxKind.FalseKeyword)
9596
9780
  return false;
9597
- if (ts6.isArrayLiteralExpression(node))
9781
+ if (ts7.isArrayLiteralExpression(node))
9598
9782
  return node.elements.map((element) => this.#literalToValue(element));
9599
- if (ts6.isObjectLiteralExpression(node)) {
9783
+ if (ts7.isObjectLiteralExpression(node)) {
9600
9784
  const obj = {};
9601
9785
  for (const prop of node.properties) {
9602
- if (!ts6.isPropertyAssignment(prop))
9786
+ if (!ts7.isPropertyAssignment(prop))
9603
9787
  continue;
9604
9788
  const name = this.#getPropertyName(prop.name);
9605
9789
  if (!name)
@@ -9608,13 +9792,13 @@ class FontOptimizer {
9608
9792
  }
9609
9793
  return obj;
9610
9794
  }
9611
- if (ts6.isAsExpression(node) || ts6.isSatisfiesExpression(node) || ts6.isParenthesizedExpression(node)) {
9795
+ if (ts7.isAsExpression(node) || ts7.isSatisfiesExpression(node) || ts7.isParenthesizedExpression(node)) {
9612
9796
  return this.#literalToValue(node.expression);
9613
9797
  }
9614
9798
  return;
9615
9799
  }
9616
9800
  #getPropertyName(name) {
9617
- if (ts6.isIdentifier(name) || ts6.isStringLiteral(name) || ts6.isNumericLiteral(name))
9801
+ if (ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
9618
9802
  return name.text;
9619
9803
  return null;
9620
9804
  }
@@ -13089,7 +13273,7 @@ import { capitalize as capitalize8 } from "akanjs/common";
13089
13273
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
13090
13274
  import { readFileSync as readFileSync4, realpathSync } from "fs";
13091
13275
  import ora2 from "ora";
13092
- import * as ts7 from "typescript";
13276
+ import * as ts8 from "typescript";
13093
13277
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
13094
13278
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
13095
13279
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -13122,10 +13306,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
13122
13306
  return importSpecifiers;
13123
13307
  };
13124
13308
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
13125
- const configFile = ts7.readConfigFile(tsConfigPath, (path40) => {
13126
- return ts7.sys.readFile(path40);
13309
+ const configFile = ts8.readConfigFile(tsConfigPath, (path40) => {
13310
+ return ts8.sys.readFile(path40);
13127
13311
  });
13128
- return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13312
+ return ts8.parseJsonConfigFileContent(configFile.config, ts8.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13129
13313
  };
13130
13314
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
13131
13315
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -13140,7 +13324,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13140
13324
  for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
13141
13325
  if (!importPath.startsWith("."))
13142
13326
  continue;
13143
- const resolved = ts7.resolveModuleName(importPath, filePath, parsedConfig.options, ts7.sys).resolvedModule?.resolvedFileName;
13327
+ const resolved = ts8.resolveModuleName(importPath, filePath, parsedConfig.options, ts8.sys).resolvedModule?.resolvedFileName;
13144
13328
  if (resolved && !allFilesToAnalyze.has(resolved)) {
13145
13329
  allFilesToAnalyze.add(resolved);
13146
13330
  collectImported(resolved);
@@ -13157,7 +13341,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13157
13341
  var createTsProgram = (filePaths, options) => {
13158
13342
  const spinner = ora2("Creating TypeScript program for all files...");
13159
13343
  spinner.start();
13160
- const program2 = ts7.createProgram(Array.from(filePaths), options);
13344
+ const program2 = ts8.createProgram(Array.from(filePaths), options);
13161
13345
  const checker = program2.getTypeChecker();
13162
13346
  spinner.succeed("TypeScript program created.");
13163
13347
  return {
@@ -13197,17 +13381,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13197
13381
  function visit(node) {
13198
13382
  if (!source2)
13199
13383
  return;
13200
- if (ts7.isPropertyAccessExpression(node)) {
13384
+ if (ts8.isPropertyAccessExpression(node)) {
13201
13385
  const left = node.expression;
13202
13386
  const right = node.name;
13203
- const { line } = ts7.getLineAndCharacterOfPosition(source2, node.getStart());
13204
- if (ts7.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
13387
+ const { line } = ts8.getLineAndCharacterOfPosition(source2, node.getStart());
13388
+ if (ts8.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
13205
13389
  const symbol = getCachedSymbol(right);
13206
13390
  if (symbol?.declarations && symbol.declarations.length > 0) {
13207
13391
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
13208
13392
  const property = propertyMap.get(key);
13209
13393
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
13210
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts7.sys.getCurrentDirectory()}/`, "");
13394
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts8.sys.getCurrentDirectory()}/`, "");
13211
13395
  if (!symbolFilePath)
13212
13396
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
13213
13397
  if (property) {
@@ -13231,10 +13415,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13231
13415
  }
13232
13416
  }
13233
13417
  }
13234
- } else if (ts7.isImportDeclaration(node) && ts7.isStringLiteral(node.moduleSpecifier)) {
13418
+ } else if (ts8.isImportDeclaration(node) && ts8.isStringLiteral(node.moduleSpecifier)) {
13235
13419
  const importPath = node.moduleSpecifier.text;
13236
13420
  if (importPath.startsWith(".")) {
13237
- const resolved = ts7.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts7.sys).resolvedModule?.resolvedFileName;
13421
+ const resolved = ts8.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts8.sys).resolvedModule?.resolvedFileName;
13238
13422
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
13239
13423
  const property = propertyMap.get(moduleName);
13240
13424
  const isScalar = importPath.includes("_");
@@ -13249,7 +13433,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13249
13433
  }
13250
13434
  }
13251
13435
  }
13252
- ts7.forEachChild(node, visit);
13436
+ ts8.forEachChild(node, visit);
13253
13437
  }
13254
13438
  visit(source2);
13255
13439
  }
package/index.js CHANGED
@@ -4805,11 +4805,17 @@ var createWorkflowApplyReport = ({
4805
4805
  recommendedValidationCommands,
4806
4806
  commands = [],
4807
4807
  diagnostics = [],
4808
+ postApplyChecks = [],
4808
4809
  recommendations = [],
4809
4810
  nextActions = [],
4810
4811
  plan
4811
4812
  }) => {
4812
4813
  const validationCommands = recommendedValidationCommands ?? commands;
4814
+ const orderedNextActions = uniqueBy(nextActions, (action) => action.command).sort((left, right) => {
4815
+ const leftRepair = left.command.startsWith("akan workflow explain") ? 0 : 1;
4816
+ const rightRepair = right.command.startsWith("akan workflow explain") ? 0 : 1;
4817
+ return leftRepair - rightRepair;
4818
+ });
4813
4819
  return {
4814
4820
  schemaVersion: 1,
4815
4821
  workflow,
@@ -4821,8 +4827,9 @@ var createWorkflowApplyReport = ({
4821
4827
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
4822
4828
  commands: uniqueBy(validationCommands, (command) => command.command),
4823
4829
  diagnostics,
4830
+ postApplyChecks,
4824
4831
  recommendations: uniqueBy(recommendations, (recommendation) => `${recommendation.kind}:${recommendation.code}`),
4825
- nextActions: uniqueBy(nextActions, (action) => action.command),
4832
+ nextActions: orderedNextActions.slice(0, 3),
4826
4833
  plan
4827
4834
  };
4828
4835
  };
@@ -5046,6 +5053,7 @@ var createRepairReport = ({
5046
5053
  });
5047
5054
  // pkgs/@akanjs/devkit/workflow/executor.ts
5048
5055
  import { capitalize as capitalize2 } from "akanjs/common";
5056
+ import ts4 from "typescript";
5049
5057
 
5050
5058
  // pkgs/@akanjs/devkit/workflow/primitive.ts
5051
5059
  var createPrimitiveWriteReport = ({
@@ -5332,7 +5340,14 @@ var fieldExpression = (typeName, defaultValue, options = {}) => {
5332
5340
  const typeExpression = normalizeFieldType(typeName);
5333
5341
  const defaultExpression = coerceFieldDefault(options.enumValues ? "enum" : typeExpression, defaultValue, options).expression;
5334
5342
  const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
5335
- return `field(${typeExpression}${defaultOption})`;
5343
+ return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
5344
+ };
5345
+ var viaBuilderParameterName = (content, className) => {
5346
+ const classIndex = content.indexOf(`export class ${className} extends via`);
5347
+ if (classIndex < 0)
5348
+ return null;
5349
+ const signature = content.slice(classIndex, content.indexOf("=>", classIndex));
5350
+ return /via\(\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(signature)?.[1] ?? null;
5336
5351
  };
5337
5352
  var insertIntoObject = (content, className, line) => {
5338
5353
  const classIndex = content.indexOf(`export class ${className} extends via`);
@@ -5420,19 +5435,69 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
5420
5435
  ${enumClass}`;
5421
5436
  return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
5422
5437
  };
5438
+ var findMatchingBrace = (content, openIndex) => {
5439
+ let depth = 0;
5440
+ let quote = null;
5441
+ let escaped = false;
5442
+ for (let index = openIndex;index < content.length; index++) {
5443
+ const char = content[index];
5444
+ if (quote) {
5445
+ if (escaped) {
5446
+ escaped = false;
5447
+ continue;
5448
+ }
5449
+ if (char === "\\") {
5450
+ escaped = true;
5451
+ continue;
5452
+ }
5453
+ if (char === quote)
5454
+ quote = null;
5455
+ continue;
5456
+ }
5457
+ if (char === '"' || char === "'" || char === "`") {
5458
+ quote = char;
5459
+ continue;
5460
+ }
5461
+ if (char === "{")
5462
+ depth += 1;
5463
+ if (char === "}") {
5464
+ depth -= 1;
5465
+ if (depth === 0)
5466
+ return index;
5467
+ }
5468
+ }
5469
+ return -1;
5470
+ };
5471
+ var dictionaryModelFieldLine = (fieldName) => {
5472
+ const label = bilingualLabelForField(fieldName);
5473
+ const desc = bilingualDescriptionForField(fieldName);
5474
+ return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
5475
+ };
5423
5476
  var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
5424
5477
  if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
5425
5478
  return content;
5426
- const label = bilingualLabelForField(fieldName);
5427
- const desc = bilingualDescriptionForField(fieldName);
5428
- const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => ({`);
5479
+ const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => (`);
5429
5480
  if (modelIndex < 0)
5430
5481
  return null;
5431
- const objectEndIndex = content.indexOf(" }))", modelIndex);
5482
+ const objectStartIndex = content.indexOf("{", modelIndex);
5483
+ if (objectStartIndex < 0)
5484
+ return null;
5485
+ const objectEndIndex = findMatchingBrace(content, objectStartIndex);
5432
5486
  if (objectEndIndex < 0)
5433
5487
  return null;
5434
- return `${content.slice(0, objectEndIndex)} ${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),
5435
- ${content.slice(objectEndIndex)}`;
5488
+ const fieldLine = dictionaryModelFieldLine(fieldName);
5489
+ const body = content.slice(objectStartIndex + 1, objectEndIndex);
5490
+ if (body.trim().length === 0) {
5491
+ return `${content.slice(0, objectStartIndex + 1)}
5492
+ ${fieldLine}
5493
+ ${content.slice(objectEndIndex)}`;
5494
+ }
5495
+ const insertion = body.endsWith(`
5496
+ `) ? ` ${fieldLine}
5497
+ ` : `
5498
+ ${fieldLine}
5499
+ `;
5500
+ return `${content.slice(0, objectEndIndex)}${insertion}${content.slice(objectEndIndex)}`;
5436
5501
  };
5437
5502
  var ensureConstantTypeImport = (content, constantPath, typeName) => {
5438
5503
  if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
@@ -5519,6 +5584,95 @@ var workflowStringInput = (value) => typeof value === "string" ? value : null;
5519
5584
  var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
5520
5585
  var workflowStringArrayInput = (value) => Array.isArray(value) ? value : null;
5521
5586
  var workflowBooleanInput = (value) => typeof value === "boolean" ? value : null;
5587
+ var postApplyDiagnostic = (code, message, target) => ({
5588
+ severity: "error",
5589
+ code,
5590
+ message,
5591
+ failureScope: "source-change",
5592
+ context: { target }
5593
+ });
5594
+ var sourceKindForPath = (filePath) => {
5595
+ if (filePath.endsWith(".tsx"))
5596
+ return ts4.ScriptKind.TSX;
5597
+ if (filePath.endsWith(".ts"))
5598
+ return ts4.ScriptKind.TS;
5599
+ return null;
5600
+ };
5601
+ var checkPathCasing = async (workspace, filePath) => {
5602
+ const segments = filePath.split("/").filter(Boolean);
5603
+ let current = ".";
5604
+ for (const segment of segments) {
5605
+ const entries = await workspace.readdir(current);
5606
+ if (entries.includes(segment)) {
5607
+ current = current === "." ? segment : `${current}/${segment}`;
5608
+ continue;
5609
+ }
5610
+ const caseInsensitiveMatch = entries.find((entry) => entry.toLowerCase() === segment.toLowerCase());
5611
+ return caseInsensitiveMatch ? {
5612
+ code: "workflow-path-casing-mismatch",
5613
+ message: `Reported path segment "${segment}" does not match actual casing "${caseInsensitiveMatch}" in ${filePath}.`
5614
+ } : {
5615
+ code: "workflow-path-missing",
5616
+ message: `Reported path does not exist: ${filePath}.`
5617
+ };
5618
+ }
5619
+ return null;
5620
+ };
5621
+ var checkTypeScriptSyntax = async (workspace, filePath) => {
5622
+ const scriptKind = sourceKindForPath(filePath);
5623
+ if (!scriptKind)
5624
+ return null;
5625
+ const content = await workspace.readFile(filePath);
5626
+ const source = ts4.createSourceFile(filePath, content, ts4.ScriptTarget.Latest, true, scriptKind);
5627
+ const diagnostic = source.parseDiagnostics[0];
5628
+ if (!diagnostic)
5629
+ return null;
5630
+ const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
5631
+ const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
5632
+ return {
5633
+ code: "workflow-post-apply-syntax-error",
5634
+ message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts4.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
5635
+ };
5636
+ };
5637
+ var checkChangedFile = async (workspace, file) => {
5638
+ if (file.action === "remove")
5639
+ return { postApplyChecks: [] };
5640
+ const diagnostics = [];
5641
+ const checks = [];
5642
+ const pathIssue = await checkPathCasing(workspace, file.path);
5643
+ if (pathIssue) {
5644
+ diagnostics.push(postApplyDiagnostic(pathIssue.code, pathIssue.message, file.path));
5645
+ checks.push({ ...pathIssue, target: file.path, status: "failed" });
5646
+ return { diagnostics, postApplyChecks: checks };
5647
+ }
5648
+ const syntaxIssue = await checkTypeScriptSyntax(workspace, file.path);
5649
+ if (syntaxIssue) {
5650
+ diagnostics.push(postApplyDiagnostic(syntaxIssue.code, syntaxIssue.message, file.path));
5651
+ checks.push({ ...syntaxIssue, target: file.path, status: "failed" });
5652
+ return { diagnostics, postApplyChecks: checks };
5653
+ }
5654
+ checks.push({
5655
+ code: "workflow-post-apply-file-valid",
5656
+ target: file.path,
5657
+ status: "passed",
5658
+ message: "Changed file exists with exact casing and parses as source when applicable."
5659
+ });
5660
+ return { postApplyChecks: checks };
5661
+ };
5662
+ var checkRecommendationPath = async (workspace, recommendation) => {
5663
+ if (!recommendation.target || recommendation.target.includes("*") || recommendation.target.startsWith("<"))
5664
+ return null;
5665
+ const pathIssue = await checkPathCasing(workspace, recommendation.target);
5666
+ if (!pathIssue)
5667
+ return null;
5668
+ return {
5669
+ severity: "warning",
5670
+ code: "workflow-recommendation-path-unverified",
5671
+ message: `${pathIssue.message} Recommendation "${recommendation.code}" should not be treated as an exact file target until the path is corrected.`,
5672
+ failureScope: "source-change",
5673
+ context: { target: recommendation.target }
5674
+ };
5675
+ };
5522
5676
  var resolveWorkflowSys = async (workspace, target) => {
5523
5677
  if (!target)
5524
5678
  return null;
@@ -5663,14 +5817,17 @@ var createWorkflowStepRegistry = ({
5663
5817
  };
5664
5818
  class WorkflowExecutor {
5665
5819
  registry;
5666
- constructor(registry) {
5820
+ workspace;
5821
+ constructor(registry, workspace) {
5667
5822
  this.registry = registry;
5823
+ this.workspace = workspace;
5668
5824
  }
5669
5825
  async apply(plan) {
5670
5826
  const changedFiles = [];
5671
5827
  const generatedFiles = [];
5672
5828
  const recommendedValidationCommands = [];
5673
5829
  const diagnostics = [...plan.diagnostics];
5830
+ const postApplyChecks = [];
5674
5831
  const recommendations = [...plan.recommendations];
5675
5832
  const nextActions = [];
5676
5833
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
@@ -5681,6 +5838,7 @@ class WorkflowExecutor {
5681
5838
  generatedFiles,
5682
5839
  recommendedValidationCommands,
5683
5840
  diagnostics,
5841
+ postApplyChecks,
5684
5842
  recommendations,
5685
5843
  nextActions,
5686
5844
  plan
@@ -5714,6 +5872,15 @@ class WorkflowExecutor {
5714
5872
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
5715
5873
  break;
5716
5874
  }
5875
+ if (this.workspace && !diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
5876
+ for (const file of changedFiles) {
5877
+ const result = await checkChangedFile(this.workspace, file);
5878
+ postApplyChecks.push(...result.postApplyChecks ?? []);
5879
+ diagnostics.push(...result.diagnostics ?? []);
5880
+ }
5881
+ const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
5882
+ diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
5883
+ }
5717
5884
  return createWorkflowApplyReport({
5718
5885
  workflow: plan.workflow,
5719
5886
  mode: "apply",
@@ -5721,6 +5888,7 @@ class WorkflowExecutor {
5721
5888
  generatedFiles,
5722
5889
  recommendedValidationCommands,
5723
5890
  diagnostics,
5891
+ postApplyChecks,
5724
5892
  recommendations,
5725
5893
  nextActions,
5726
5894
  plan
@@ -6110,19 +6278,29 @@ var renderRecommendation = (recommendation) => {
6110
6278
  return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
6111
6279
  };
6112
6280
  var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
6281
+ var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
6113
6282
  var renderWorkflowApplyReport = (report) => {
6114
6283
  const manualReviewItems = [
6115
6284
  ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
6116
6285
  ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
6117
6286
  ];
6118
6287
  const validationBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "workspace-config" || diagnostic.failureScope === "environment")).map(renderDiagnostic);
6288
+ const sourceBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")).map(renderDiagnostic);
6119
6289
  return [
6120
6290
  `# Workflow Apply: ${report.workflow}`,
6121
6291
  "",
6122
6292
  `- Mode: ${report.mode}`,
6123
6293
  `- Status: ${report.status}`,
6294
+ `- Source-change status: ${applySourceStatus(report)}`,
6295
+ `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
6124
6296
  ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
6125
6297
  "",
6298
+ "## Apply Checks",
6299
+ ...report.postApplyChecks?.length ? report.postApplyChecks.map((check) => `- [${check.status}] ${check.code} ${check.target}: ${check.message}`) : ["- not run"],
6300
+ "",
6301
+ "## Source Change Blockers",
6302
+ ...sourceBlockers.length ? sourceBlockers : ["- none"],
6303
+ "",
6126
6304
  "## Automatically Modified",
6127
6305
  ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6128
6306
  "",
@@ -6145,7 +6323,7 @@ var renderWorkflowApplyReport = (report) => {
6145
6323
  ...report.diagnostics.length ? report.diagnostics.map(renderDiagnostic) : ["- none"],
6146
6324
  "",
6147
6325
  "## Recommendations",
6148
- ...report.recommendations.length ? report.recommendations.map(renderRecommendation) : ["- none"],
6326
+ ...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
6149
6327
  "",
6150
6328
  "## Next Actions",
6151
6329
  ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
@@ -6164,10 +6342,16 @@ var renderWorkflowValidationRunReport = (report) => [
6164
6342
  `- Overall status: ${report.overallStatus}`,
6165
6343
  "",
6166
6344
  "## Status Summary",
6167
- `- Required source-change validation: ${report.summary.sourceChange}`,
6168
- `- Generated sync validation: ${report.summary.generatedSync}`,
6169
- `- Workspace configuration validation: ${report.summary.workspaceConfig}`,
6170
- `- Environment validation: ${report.summary.environment}`,
6345
+ `- Source-change: ${report.summary.sourceChange}`,
6346
+ `- Generated sync: ${report.summary.generatedSync}`,
6347
+ `- Workspace config: ${report.summary.workspaceConfig}`,
6348
+ `- Environment: ${report.summary.environment}`,
6349
+ "",
6350
+ "## Source Change Diagnostics",
6351
+ ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
6352
+ "",
6353
+ "## Existing Workspace Blockers",
6354
+ ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
6171
6355
  "",
6172
6356
  "## Known Blockers",
6173
6357
  ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
@@ -7243,7 +7427,7 @@ var collapseIndex = (relPathNoExt) => {
7243
7427
 
7244
7428
  // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
7245
7429
  import path14 from "path";
7246
- import ts4 from "typescript";
7430
+ import ts5 from "typescript";
7247
7431
  var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
7248
7432
  const akanConfig2 = await app.getConfig();
7249
7433
  const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
@@ -7484,11 +7668,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
7484
7668
  };
7485
7669
  var findImportStatements = (source2) => {
7486
7670
  const statements = [];
7487
- const sourceFile2 = ts4.createSourceFile("barrel-imports.tsx", source2, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
7671
+ const sourceFile2 = ts5.createSourceFile("barrel-imports.tsx", source2, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
7488
7672
  for (const statement of sourceFile2.statements) {
7489
- if (!ts4.isImportDeclaration(statement))
7673
+ if (!ts5.isImportDeclaration(statement))
7490
7674
  continue;
7491
- if (!ts4.isStringLiteral(statement.moduleSpecifier))
7675
+ if (!ts5.isStringLiteral(statement.moduleSpecifier))
7492
7676
  continue;
7493
7677
  const importClause = statement.importClause;
7494
7678
  if (!importClause)
@@ -8483,7 +8667,7 @@ import path22 from "path";
8483
8667
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
8484
8668
  import fs3 from "fs";
8485
8669
  import path21 from "path";
8486
- import ts5 from "typescript";
8670
+ import ts6 from "typescript";
8487
8671
 
8488
8672
  class PagesEntrySourceGenerator {
8489
8673
  #pageEntries;
@@ -8527,7 +8711,7 @@ ${entries.join(`
8527
8711
  static #hasAsyncDefaultExport(moduleAbsPath) {
8528
8712
  try {
8529
8713
  const source2 = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
8530
- const sourceFile2 = ts5.createSourceFile(moduleAbsPath, source2, ts5.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
8714
+ const sourceFile2 = ts6.createSourceFile(moduleAbsPath, source2, ts6.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
8531
8715
  return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
8532
8716
  } catch {
8533
8717
  return false;
@@ -8537,31 +8721,31 @@ ${entries.join(`
8537
8721
  const asyncBindings = new Map;
8538
8722
  let defaultIdentifier = null;
8539
8723
  for (const statement of sourceFile2.statements) {
8540
- if (ts5.isFunctionDeclaration(statement)) {
8541
- if (PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.DefaultKeyword)) {
8542
- return PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword);
8724
+ if (ts6.isFunctionDeclaration(statement)) {
8725
+ if (PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.DefaultKeyword)) {
8726
+ return PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword);
8543
8727
  }
8544
8728
  if (statement.name) {
8545
- asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword));
8729
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword));
8546
8730
  }
8547
8731
  continue;
8548
8732
  }
8549
- if (ts5.isVariableStatement(statement)) {
8733
+ if (ts6.isVariableStatement(statement)) {
8550
8734
  for (const declaration of statement.declarationList.declarations) {
8551
- if (!ts5.isIdentifier(declaration.name))
8735
+ if (!ts6.isIdentifier(declaration.name))
8552
8736
  continue;
8553
8737
  asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
8554
8738
  }
8555
8739
  continue;
8556
8740
  }
8557
- if (ts5.isExportAssignment(statement)) {
8741
+ if (ts6.isExportAssignment(statement)) {
8558
8742
  if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
8559
8743
  return true;
8560
- if (ts5.isIdentifier(statement.expression))
8744
+ if (ts6.isIdentifier(statement.expression))
8561
8745
  defaultIdentifier = statement.expression.text;
8562
8746
  continue;
8563
8747
  }
8564
- if (ts5.isExportDeclaration(statement) && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
8748
+ if (ts6.isExportDeclaration(statement) && statement.exportClause && ts6.isNamedExports(statement.exportClause)) {
8565
8749
  const exportClause = statement.exportClause;
8566
8750
  for (const specifier of exportClause.elements) {
8567
8751
  if (specifier.name.text !== "default")
@@ -8573,13 +8757,13 @@ ${entries.join(`
8573
8757
  return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
8574
8758
  }
8575
8759
  static #hasModifier(node, kind) {
8576
- return ts5.canHaveModifiers(node) && (ts5.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
8760
+ return ts6.canHaveModifiers(node) && (ts6.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
8577
8761
  }
8578
8762
  static #isAsyncFunctionExpression(node) {
8579
- return Boolean(node && (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts5.SyntaxKind.AsyncKeyword));
8763
+ return Boolean(node && (ts6.isArrowFunction(node) || ts6.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts6.SyntaxKind.AsyncKeyword));
8580
8764
  }
8581
8765
  static #scriptKind(moduleAbsPath) {
8582
- return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts5.ScriptKind.TSX : ts5.ScriptKind.TS;
8766
+ return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts6.ScriptKind.TSX : ts6.ScriptKind.TS;
8583
8767
  }
8584
8768
  }
8585
8769
 
@@ -9498,7 +9682,7 @@ import {
9498
9682
  } from "fontaine";
9499
9683
  import { createFont, woff2 } from "fonteditor-core";
9500
9684
  import subsetFont from "subset-font";
9501
- import ts6 from "typescript";
9685
+ import ts7 from "typescript";
9502
9686
  var FONT_URL_PREFIX = "/_akan/fonts";
9503
9687
  var DEFAULT_FONT_SUBSETS = ["latin"];
9504
9688
 
@@ -9563,17 +9747,17 @@ class FontOptimizer {
9563
9747
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
9564
9748
  }
9565
9749
  #extractFontsExport(source2, filePath) {
9566
- const sourceFile2 = ts6.createSourceFile(filePath, source2, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
9750
+ const sourceFile2 = ts7.createSourceFile(filePath, source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
9567
9751
  const fonts = [];
9568
9752
  for (const statement of sourceFile2.statements) {
9569
- if (!ts6.isVariableStatement(statement))
9753
+ if (!ts7.isVariableStatement(statement))
9570
9754
  continue;
9571
- const modifiers = ts6.canHaveModifiers(statement) ? ts6.getModifiers(statement) : undefined;
9572
- const isExported = modifiers?.some((modifier) => modifier.kind === ts6.SyntaxKind.ExportKeyword) ?? false;
9755
+ const modifiers = ts7.canHaveModifiers(statement) ? ts7.getModifiers(statement) : undefined;
9756
+ const isExported = modifiers?.some((modifier) => modifier.kind === ts7.SyntaxKind.ExportKeyword) ?? false;
9573
9757
  if (!isExported)
9574
9758
  continue;
9575
9759
  for (const declaration of statement.declarationList.declarations) {
9576
- if (!ts6.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9760
+ if (!ts7.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9577
9761
  continue;
9578
9762
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
9579
9763
  if (Array.isArray(value)) {
@@ -9584,20 +9768,20 @@ class FontOptimizer {
9584
9768
  return fonts;
9585
9769
  }
9586
9770
  #literalToValue(node) {
9587
- if (ts6.isStringLiteralLike(node))
9771
+ if (ts7.isStringLiteralLike(node))
9588
9772
  return node.text;
9589
- if (ts6.isNumericLiteral(node))
9773
+ if (ts7.isNumericLiteral(node))
9590
9774
  return Number(node.text);
9591
- if (node.kind === ts6.SyntaxKind.TrueKeyword)
9775
+ if (node.kind === ts7.SyntaxKind.TrueKeyword)
9592
9776
  return true;
9593
- if (node.kind === ts6.SyntaxKind.FalseKeyword)
9777
+ if (node.kind === ts7.SyntaxKind.FalseKeyword)
9594
9778
  return false;
9595
- if (ts6.isArrayLiteralExpression(node))
9779
+ if (ts7.isArrayLiteralExpression(node))
9596
9780
  return node.elements.map((element) => this.#literalToValue(element));
9597
- if (ts6.isObjectLiteralExpression(node)) {
9781
+ if (ts7.isObjectLiteralExpression(node)) {
9598
9782
  const obj = {};
9599
9783
  for (const prop of node.properties) {
9600
- if (!ts6.isPropertyAssignment(prop))
9784
+ if (!ts7.isPropertyAssignment(prop))
9601
9785
  continue;
9602
9786
  const name = this.#getPropertyName(prop.name);
9603
9787
  if (!name)
@@ -9606,13 +9790,13 @@ class FontOptimizer {
9606
9790
  }
9607
9791
  return obj;
9608
9792
  }
9609
- if (ts6.isAsExpression(node) || ts6.isSatisfiesExpression(node) || ts6.isParenthesizedExpression(node)) {
9793
+ if (ts7.isAsExpression(node) || ts7.isSatisfiesExpression(node) || ts7.isParenthesizedExpression(node)) {
9610
9794
  return this.#literalToValue(node.expression);
9611
9795
  }
9612
9796
  return;
9613
9797
  }
9614
9798
  #getPropertyName(name) {
9615
- if (ts6.isIdentifier(name) || ts6.isStringLiteral(name) || ts6.isNumericLiteral(name))
9799
+ if (ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
9616
9800
  return name.text;
9617
9801
  return null;
9618
9802
  }
@@ -13087,7 +13271,7 @@ import { capitalize as capitalize8 } from "akanjs/common";
13087
13271
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
13088
13272
  import { readFileSync as readFileSync4, realpathSync } from "fs";
13089
13273
  import ora2 from "ora";
13090
- import * as ts7 from "typescript";
13274
+ import * as ts8 from "typescript";
13091
13275
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
13092
13276
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
13093
13277
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -13120,10 +13304,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
13120
13304
  return importSpecifiers;
13121
13305
  };
13122
13306
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
13123
- const configFile = ts7.readConfigFile(tsConfigPath, (path40) => {
13124
- return ts7.sys.readFile(path40);
13307
+ const configFile = ts8.readConfigFile(tsConfigPath, (path40) => {
13308
+ return ts8.sys.readFile(path40);
13125
13309
  });
13126
- return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13310
+ return ts8.parseJsonConfigFileContent(configFile.config, ts8.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13127
13311
  };
13128
13312
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
13129
13313
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -13138,7 +13322,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13138
13322
  for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
13139
13323
  if (!importPath.startsWith("."))
13140
13324
  continue;
13141
- const resolved = ts7.resolveModuleName(importPath, filePath, parsedConfig.options, ts7.sys).resolvedModule?.resolvedFileName;
13325
+ const resolved = ts8.resolveModuleName(importPath, filePath, parsedConfig.options, ts8.sys).resolvedModule?.resolvedFileName;
13142
13326
  if (resolved && !allFilesToAnalyze.has(resolved)) {
13143
13327
  allFilesToAnalyze.add(resolved);
13144
13328
  collectImported(resolved);
@@ -13155,7 +13339,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13155
13339
  var createTsProgram = (filePaths, options) => {
13156
13340
  const spinner = ora2("Creating TypeScript program for all files...");
13157
13341
  spinner.start();
13158
- const program2 = ts7.createProgram(Array.from(filePaths), options);
13342
+ const program2 = ts8.createProgram(Array.from(filePaths), options);
13159
13343
  const checker = program2.getTypeChecker();
13160
13344
  spinner.succeed("TypeScript program created.");
13161
13345
  return {
@@ -13195,17 +13379,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13195
13379
  function visit(node) {
13196
13380
  if (!source2)
13197
13381
  return;
13198
- if (ts7.isPropertyAccessExpression(node)) {
13382
+ if (ts8.isPropertyAccessExpression(node)) {
13199
13383
  const left = node.expression;
13200
13384
  const right = node.name;
13201
- const { line } = ts7.getLineAndCharacterOfPosition(source2, node.getStart());
13202
- if (ts7.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
13385
+ const { line } = ts8.getLineAndCharacterOfPosition(source2, node.getStart());
13386
+ if (ts8.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
13203
13387
  const symbol = getCachedSymbol(right);
13204
13388
  if (symbol?.declarations && symbol.declarations.length > 0) {
13205
13389
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
13206
13390
  const property = propertyMap.get(key);
13207
13391
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
13208
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts7.sys.getCurrentDirectory()}/`, "");
13392
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts8.sys.getCurrentDirectory()}/`, "");
13209
13393
  if (!symbolFilePath)
13210
13394
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
13211
13395
  if (property) {
@@ -13229,10 +13413,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13229
13413
  }
13230
13414
  }
13231
13415
  }
13232
- } else if (ts7.isImportDeclaration(node) && ts7.isStringLiteral(node.moduleSpecifier)) {
13416
+ } else if (ts8.isImportDeclaration(node) && ts8.isStringLiteral(node.moduleSpecifier)) {
13233
13417
  const importPath = node.moduleSpecifier.text;
13234
13418
  if (importPath.startsWith(".")) {
13235
- const resolved = ts7.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts7.sys).resolvedModule?.resolvedFileName;
13419
+ const resolved = ts8.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts8.sys).resolvedModule?.resolvedFileName;
13236
13420
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
13237
13421
  const property = propertyMap.get(moduleName);
13238
13422
  const isScalar = importPath.includes("_");
@@ -13247,7 +13431,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13247
13431
  }
13248
13432
  }
13249
13433
  }
13250
- ts7.forEachChild(node, visit);
13434
+ ts8.forEachChild(node, visit);
13251
13435
  }
13252
13436
  visit(source2);
13253
13437
  }
@@ -15813,6 +15997,7 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
15813
15997
  }
15814
15998
  let constantContent = await sys3.readFile(constantPath);
15815
15999
  let dictionaryContent = await sys3.readFile(dictionaryPath);
16000
+ const fieldBuilderName = viaBuilderParameterName(constantContent, inputClassName) ?? "field";
15816
16001
  if (new RegExp(`\\b${input7.field}\\s*:`).test(constantContent)) {
15817
16002
  diagnostics.push({
15818
16003
  severity: "error",
@@ -15850,7 +16035,7 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
15850
16035
  if (defaultCoercion.diagnostic)
15851
16036
  diagnostics.push(defaultCoercion.diagnostic);
15852
16037
  }
15853
- const nextConstantContent = insertIntoObject(constantContent, inputClassName, `${input7.field}: ${fieldExpression(input7.type, input7.defaultValue, { enumValues })},`);
16038
+ const nextConstantContent = insertIntoObject(constantContent, inputClassName, `${input7.field}: ${fieldExpression(input7.type, input7.defaultValue, { enumValues, builderName: fieldBuilderName })},`);
15854
16039
  const nextConstantContentWithLight = nextConstantContent && input7.includeInLight ? insertLightProjectionField(nextConstantContent, moduleClassName, input7.field) : nextConstantContent;
15855
16040
  const nextDictionaryContent = insertDictionaryModelField(dictionaryContent, moduleClassName, input7.field);
15856
16041
  if (nextConstantContentWithLight && (input7.type === "Int" || input7.type === "Float") && new RegExp(`\\b${input7.field}\\s*:\\s*field\\(${input7.type}, \\{ default: "`, "m").test(nextConstantContentWithLight)) {
@@ -17088,7 +17273,7 @@ class WorkflowRunner extends runner("workflow") {
17088
17273
  ], plan2);
17089
17274
  return await renderApplyReport(report);
17090
17275
  }
17091
- return await renderApplyReport(await new WorkflowExecutor(registry).apply(plan2));
17276
+ return await renderApplyReport(await new WorkflowExecutor(registry, workspace).apply(plan2));
17092
17277
  }
17093
17278
  async validate(runIdOrPlan, {
17094
17279
  format = "markdown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "2.3.9-rc.5",
3
+ "version": "2.3.9-rc.7",
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.5",
37
+ "akanjs": "2.3.9-rc.7",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "daisyui": "5.5.23",
@@ -9,7 +9,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
9
9
  return `
10
10
  import { via } from "akanjs/constant";
11
11
 
12
- export class ${dict.Model}Input extends via((_field) => ({
12
+ export class ${dict.Model}Input extends via((field) => ({
13
13
  })) {}
14
14
 
15
15
  export class ${dict.Model}Object extends via(${dict.Model}Input, (field) => ({})) {}