@akanjs/cli 2.3.9-rc.4 → 2.3.9-rc.6

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.
@@ -3396,28 +3396,28 @@ class SysExecutor extends Executor {
3396
3396
  return scalarModules;
3397
3397
  }
3398
3398
  async getViewComponents() {
3399
- const viewComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.View.tsx`).exists());
3399
+ const viewComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.View.tsx`).exists());
3400
3400
  return viewComponents;
3401
3401
  }
3402
3402
  async getUnitComponents() {
3403
- const unitComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`).exists());
3403
+ const unitComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Unit.tsx`).exists());
3404
3404
  return unitComponents;
3405
3405
  }
3406
3406
  async getTemplateComponents() {
3407
- const templateComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`).exists());
3407
+ const templateComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Template.tsx`).exists());
3408
3408
  return templateComponents;
3409
3409
  }
3410
3410
  async getViewsSourceCode() {
3411
3411
  const viewComponents = await this.getViewComponents();
3412
- return Promise.all(viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${viewComponent}.View.tsx`)));
3412
+ return Promise.all(viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${capitalize(viewComponent)}.View.tsx`)));
3413
3413
  }
3414
3414
  async getUnitsSourceCode() {
3415
3415
  const unitComponents = await this.getUnitComponents();
3416
- return Promise.all(unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${unitComponent}.Unit.tsx`)));
3416
+ return Promise.all(unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${capitalize(unitComponent)}.Unit.tsx`)));
3417
3417
  }
3418
3418
  async getTemplatesSourceCode() {
3419
3419
  const templateComponents = await this.getTemplateComponents();
3420
- return Promise.all(templateComponents.map((templateComponent) => this.getLocalFile(`lib/${templateComponent}/${templateComponent}.Template.tsx`)));
3420
+ return Promise.all(templateComponents.map((templateComponent) => this.getLocalFile(`lib/${templateComponent}/${capitalize(templateComponent)}.Template.tsx`)));
3421
3421
  }
3422
3422
  async getScalarConstantFiles() {
3423
3423
  const scalarModules = await this.getScalarModules();
@@ -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
  };
@@ -4889,6 +4896,12 @@ var statusForScope = (commands, diagnostics, scopes, expectedScope) => {
4889
4896
  return "unknown";
4890
4897
  return hasScopeFailure(scopes, expectedScope, diagnostics) ? "failed" : "passed";
4891
4898
  };
4899
+ var statusForValidationKind = (commands, kind) => {
4900
+ const matching = commands.filter((command) => command.kind === kind);
4901
+ if (matching.length === 0)
4902
+ return "unknown";
4903
+ return matching.some((command) => command.status === "failed") ? "failed" : "passed";
4904
+ };
4892
4905
  var createKnownBlockers = (commands, diagnostics) => {
4893
4906
  const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
4894
4907
  code: `workflow-validation-${command.failureScope}`,
@@ -4922,7 +4935,17 @@ var createValidationStatuses = (commands, diagnostics) => {
4922
4935
  const sourceStatus = statusForScope(commands, diagnostics, scopes, "source-change");
4923
4936
  const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
4924
4937
  const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
4925
- return { sourceStatus, workspaceStatus, overallStatus };
4938
+ return {
4939
+ sourceStatus,
4940
+ workspaceStatus,
4941
+ overallStatus,
4942
+ summary: {
4943
+ sourceChange: sourceStatus,
4944
+ generatedSync: statusForValidationKind(commands, "sync"),
4945
+ workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
4946
+ environment: statusForScope(commands, diagnostics, scopes, "environment")
4947
+ }
4948
+ };
4926
4949
  };
4927
4950
  var createWorkflowValidationRunReport = async ({
4928
4951
  runId = createWorkflowRunId("validation"),
@@ -5032,221 +5055,7 @@ var createRepairReport = ({
5032
5055
  });
5033
5056
  // pkgs/@akanjs/devkit/workflow/executor.ts
5034
5057
  import { capitalize as capitalize2 } from "akanjs/common";
5035
- var workflowStepKey = (workflow, stepId) => `${workflow}:${stepId}`;
5036
- var primitiveReportToWorkflowStepResult = (report) => ({
5037
- changedFiles: report.changedFiles,
5038
- generatedFiles: report.generatedFiles,
5039
- commands: report.validationCommands,
5040
- diagnostics: report.diagnostics,
5041
- recommendations: [],
5042
- nextActions: report.nextActions
5043
- });
5044
- var workflowStringInput = (value) => typeof value === "string" ? value : null;
5045
- var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
5046
- var resolveWorkflowSys = async (workspace, target) => {
5047
- if (!target)
5048
- return null;
5049
- const [apps, libs] = await workspace.getSyss();
5050
- if (apps.includes(target))
5051
- return AppExecutor.from(workspace, target);
5052
- if (libs.includes(target))
5053
- return LibExecutor.from(workspace, target);
5054
- return null;
5055
- };
5056
- var targetMissing = (input2 = "app") => ({
5057
- severity: "error",
5058
- code: "workflow-target-missing",
5059
- input: input2,
5060
- message: "Workflow target app or library was not found."
5061
- });
5062
- var inputMissing = (input2) => ({
5063
- severity: "error",
5064
- code: "workflow-input-missing",
5065
- input: input2,
5066
- message: `Workflow input "${input2}" is required for apply.`
5067
- });
5068
- var unsupportedInput = (input2, message) => ({
5069
- severity: "error",
5070
- code: "workflow-input-unsupported",
5071
- input: input2,
5072
- message
5073
- });
5074
- var addFieldUiSurfaceInspection = (plan) => {
5075
- const app = workflowStringInput(plan.inputs.app);
5076
- const module = workflowStringInput(plan.inputs.module) ?? "<module>";
5077
- const field = workflowStringInput(plan.inputs.field) ?? "<field>";
5078
- const typeName = workflowStringInput(plan.inputs.type);
5079
- const isNumeric = typeName === "Int" || typeName === "Float" || typeName === "integer" || typeName === "float";
5080
- const moduleClassName = capitalize2(module);
5081
- const target = `${app ? `apps/${app}` : "*"}/lib/${module}/${moduleClassName}.Template.tsx`;
5082
- return {
5083
- recommendations: [
5084
- {
5085
- code: "add-field-ui-surface-review",
5086
- kind: "manual-action",
5087
- target,
5088
- action: isNumeric ? `Review ${moduleClassName} Template/Unit/View/Store surfaces before adding ${field}; confirm the local Field.Text numeric parser/formatter, validation rule, and dictionary label pattern.` : `Add ${field} to ${moduleClassName} UI surfaces only when the local Field.* pattern is clear.`,
5089
- confidence: "medium",
5090
- message: isNumeric ? `No UI file was modified automatically because a safe numeric input component pattern is not yet detected for ${module}.${field}.` : `Review Template/Unit/View/Store surfaces for ${module}.${field}; no UI file was modified automatically.`
5091
- }
5092
- ],
5093
- nextActions: [
5094
- {
5095
- command: `akan workflow explain ${plan.workflow}`,
5096
- reason: "Review UI surface guidance before manually editing ambiguous UI files."
5097
- }
5098
- ]
5099
- };
5100
- };
5101
- var createWorkflowStepRegistry = ({
5102
- workspace,
5103
- createModule,
5104
- createScalar,
5105
- createUi,
5106
- addField,
5107
- addEnumField
5108
- }) => {
5109
- const inspect = async () => {
5110
- return;
5111
- };
5112
- const commandOnly = async () => {
5113
- return;
5114
- };
5115
- return {
5116
- inspectSystem: inspect,
5117
- inspectModule: inspect,
5118
- syncTarget: commandOnly,
5119
- lintTarget: commandOnly,
5120
- [workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
5121
- const app = workflowStringInput(plan.inputs.app);
5122
- const module = workflowStringInput(plan.inputs.module);
5123
- const sys2 = await resolveWorkflowSys(workspace, app);
5124
- if (!sys2 || !module)
5125
- return { diagnostics: [!sys2 ? targetMissing() : inputMissing("module")] };
5126
- return primitiveReportToWorkflowStepResult(await createModule(sys2, module));
5127
- },
5128
- [workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
5129
- const app = workflowStringInput(plan.inputs.app);
5130
- const scalar = workflowStringInput(plan.inputs.scalar);
5131
- const sys2 = await resolveWorkflowSys(workspace, app);
5132
- if (!sys2 || !scalar)
5133
- return { diagnostics: [!sys2 ? targetMissing() : inputMissing("scalar")] };
5134
- return primitiveReportToWorkflowStepResult(await createScalar(sys2, scalar));
5135
- },
5136
- [workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
5137
- const surface = workflowStringInput(plan.inputs.surface);
5138
- if (surface !== "view" && surface !== "unit" && surface !== "template") {
5139
- return {
5140
- diagnostics: [
5141
- unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
5142
- ]
5143
- };
5144
- }
5145
- return primitiveReportToWorkflowStepResult(await createUi({
5146
- app: workflowStringInput(plan.inputs.app),
5147
- module: workflowStringInput(plan.inputs.module),
5148
- surface
5149
- }));
5150
- },
5151
- [workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
5152
- if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
5153
- return primitiveReportToWorkflowStepResult(await addEnumField({
5154
- app: workflowStringInput(plan.inputs.app),
5155
- module: workflowStringInput(plan.inputs.module),
5156
- field: workflowStringInput(plan.inputs.field),
5157
- values: workflowStringListInput(plan.inputs.values),
5158
- defaultValue: workflowStringInput(plan.inputs.default)
5159
- }));
5160
- }
5161
- return primitiveReportToWorkflowStepResult(await addField({
5162
- app: workflowStringInput(plan.inputs.app),
5163
- module: workflowStringInput(plan.inputs.module),
5164
- field: workflowStringInput(plan.inputs.field),
5165
- type: workflowStringInput(plan.inputs.type),
5166
- defaultValue: workflowStringInput(plan.inputs.default)
5167
- }));
5168
- },
5169
- [workflowStepKey("add-field", "update-dictionary")]: inspect,
5170
- [workflowStepKey("add-field", "update-ui-surfaces")]: async (_step, plan) => addFieldUiSurfaceInspection(plan),
5171
- [workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
5172
- app: workflowStringInput(plan.inputs.app),
5173
- module: workflowStringInput(plan.inputs.module),
5174
- field: workflowStringInput(plan.inputs.field),
5175
- values: workflowStringListInput(plan.inputs.values),
5176
- defaultValue: workflowStringInput(plan.inputs.default)
5177
- })),
5178
- [workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
5179
- [workflowStepKey("add-enum-field", "update-option")]: inspect
5180
- };
5181
- };
5182
- class WorkflowExecutor {
5183
- registry;
5184
- constructor(registry) {
5185
- this.registry = registry;
5186
- }
5187
- async apply(plan) {
5188
- const changedFiles = [];
5189
- const generatedFiles = [];
5190
- const recommendedValidationCommands = [];
5191
- const diagnostics = [...plan.diagnostics];
5192
- const recommendations = [...plan.recommendations];
5193
- const nextActions = [];
5194
- if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
5195
- return createWorkflowApplyReport({
5196
- workflow: plan.workflow,
5197
- mode: "apply",
5198
- changedFiles,
5199
- generatedFiles,
5200
- recommendedValidationCommands,
5201
- diagnostics,
5202
- recommendations,
5203
- nextActions,
5204
- plan
5205
- });
5206
- }
5207
- recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
5208
- nextActions.push(...workflowCommandsForPlan(plan));
5209
- for (const step of plan.steps) {
5210
- const runner = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
5211
- if (!runner) {
5212
- diagnostics.push({
5213
- severity: "error",
5214
- code: "workflow-step-unsupported",
5215
- message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
5216
- });
5217
- nextActions.push({
5218
- command: `akan workflow explain ${plan.workflow}`,
5219
- reason: "Review the unsupported workflow step before retrying apply."
5220
- });
5221
- break;
5222
- }
5223
- const result = await runner(step, plan);
5224
- if (!result)
5225
- continue;
5226
- changedFiles.push(...result.changedFiles ?? []);
5227
- generatedFiles.push(...result.generatedFiles ?? []);
5228
- recommendedValidationCommands.push(...result.commands ?? []);
5229
- diagnostics.push(...result.diagnostics ?? []);
5230
- recommendations.push(...result.recommendations ?? []);
5231
- nextActions.push(...result.nextActions ?? []);
5232
- if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
5233
- break;
5234
- }
5235
- return createWorkflowApplyReport({
5236
- workflow: plan.workflow,
5237
- mode: "apply",
5238
- changedFiles,
5239
- generatedFiles,
5240
- recommendedValidationCommands,
5241
- diagnostics,
5242
- recommendations,
5243
- nextActions,
5244
- plan
5245
- });
5246
- }
5247
- }
5248
- // pkgs/@akanjs/devkit/workflow/plan.ts
5249
- import { capitalize as capitalize3 } from "akanjs/common";
5058
+ import ts4 from "typescript";
5250
5059
 
5251
5060
  // pkgs/@akanjs/devkit/workflow/primitive.ts
5252
5061
  var createPrimitiveWriteReport = ({
@@ -5298,6 +5107,23 @@ var sourceFile = (sys2, path10, action, reason) => ({
5298
5107
  action,
5299
5108
  reason
5300
5109
  });
5110
+ var moduleComponentName = (moduleName) => `${moduleName.slice(0, 1).toUpperCase()}${moduleName.slice(1)}`;
5111
+ var moduleSourcePaths = (moduleName) => {
5112
+ const componentName = moduleComponentName(moduleName);
5113
+ return {
5114
+ abstract: `lib/${moduleName}/${moduleName}.abstract.md`,
5115
+ constant: `lib/${moduleName}/${moduleName}.constant.ts`,
5116
+ dictionary: `lib/${moduleName}/${moduleName}.dictionary.ts`,
5117
+ service: `lib/${moduleName}/${moduleName}.service.ts`,
5118
+ signal: `lib/${moduleName}/${moduleName}.signal.ts`,
5119
+ store: `lib/${moduleName}/${moduleName}.store.ts`,
5120
+ template: `lib/${moduleName}/${componentName}.Template.tsx`,
5121
+ unit: `lib/${moduleName}/${componentName}.Unit.tsx`,
5122
+ util: `lib/${moduleName}/${componentName}.Util.tsx`,
5123
+ view: `lib/${moduleName}/${componentName}.View.tsx`,
5124
+ zone: `lib/${moduleName}/${componentName}.Zone.tsx`
5125
+ };
5126
+ };
5301
5127
  var generatedFilesForSync = (sys2, reason = "Generated files may change after sync.") => generatedFilePathsForTarget(getSysRoot(sys2), reason);
5302
5128
  var validationCommandsForTarget = (target) => [
5303
5129
  { command: `akan sync ${target}`, reason: "Refresh generated Akan files from source conventions." },
@@ -5324,6 +5150,50 @@ var createPassedPrimitiveReport = ({
5324
5150
  var scalarChangedFiles = (sys2, scalarName, files) => Object.values(files).map((file) => sourceFile(sys2, `lib/__scalar/${scalarName}/${file.filename}`, "create", "Scalar source file was created."));
5325
5151
  var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
5326
5152
  var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
5153
+ var koLabels = {
5154
+ amount: "\uAE08\uC561",
5155
+ budget: "\uC608\uC0B0",
5156
+ category: "\uCE74\uD14C\uACE0\uB9AC",
5157
+ content: "\uB0B4\uC6A9",
5158
+ count: "\uAC1C\uC218",
5159
+ createdAt: "\uC0DD\uC131\uC77C",
5160
+ date: "\uB0A0\uC9DC",
5161
+ description: "\uC124\uBA85",
5162
+ due: "\uB9C8\uAC10\uC77C",
5163
+ dueAt: "\uB9C8\uAC10\uC77C",
5164
+ email: "\uC774\uBA54\uC77C",
5165
+ enabled: "\uD65C\uC131\uD654",
5166
+ endAt: "\uC885\uB8CC\uC77C",
5167
+ id: "ID",
5168
+ name: "\uC774\uB984",
5169
+ owner: "\uB2F4\uB2F9\uC790",
5170
+ priority: "\uC6B0\uC120\uC21C\uC704",
5171
+ project: "\uD504\uB85C\uC81D\uD2B8",
5172
+ rating: "\uD3C9\uC810",
5173
+ startAt: "\uC2DC\uC791\uC77C",
5174
+ status: "\uC0C1\uD0DC",
5175
+ title: "\uC81C\uBAA9",
5176
+ updatedAt: "\uC218\uC815\uC77C"
5177
+ };
5178
+ var splitFieldWords = (fieldName) => fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").split(/\s+/).map((word) => word.trim()).filter(Boolean);
5179
+ var koLabelForField = (fieldName) => {
5180
+ if (koLabels[fieldName])
5181
+ return koLabels[fieldName];
5182
+ const words = splitFieldWords(fieldName);
5183
+ const translated = words.map((word) => koLabels[word] ?? koLabels[lowerlize(word)] ?? null);
5184
+ return translated.every(Boolean) ? translated.join(" ") : null;
5185
+ };
5186
+ var bilingualLabelForField = (fieldName) => {
5187
+ const en = titleize(fieldName);
5188
+ return { en, ko: koLabelForField(fieldName) ?? en };
5189
+ };
5190
+ var bilingualDescriptionForField = (fieldName) => {
5191
+ const label = bilingualLabelForField(fieldName);
5192
+ return {
5193
+ en: `Enter ${label.en.toLowerCase()}.`,
5194
+ ko: `${label.ko} \uAC12\uC744 \uC785\uB825\uD569\uB2C8\uB2E4.`
5195
+ };
5196
+ };
5327
5197
  var normalizeFieldType = (typeName) => {
5328
5198
  const normalizedTypes = {
5329
5199
  string: "String",
@@ -5351,6 +5221,15 @@ var ensureBaseTypeImport = (content, typeName) => {
5351
5221
  ${content}`;
5352
5222
  };
5353
5223
  var numericDefault = (typeName, rawDefault) => {
5224
+ if (typeof rawDefault === "number") {
5225
+ if (!Number.isFinite(rawDefault))
5226
+ return null;
5227
+ if (typeName === "Int" && !Number.isInteger(rawDefault))
5228
+ return null;
5229
+ return String(rawDefault);
5230
+ }
5231
+ if (typeof rawDefault !== "string")
5232
+ return null;
5354
5233
  const trimmed = rawDefault.trim();
5355
5234
  if (!trimmed || !Number.isFinite(Number(trimmed)))
5356
5235
  return null;
@@ -5358,16 +5237,41 @@ var numericDefault = (typeName, rawDefault) => {
5358
5237
  return null;
5359
5238
  return trimmed;
5360
5239
  };
5361
- var coerceFieldDefault = (typeName, defaultValue) => {
5362
- if (defaultValue === undefined || defaultValue === null || defaultValue === "")
5363
- return { expression: null };
5364
- const normalizedType = normalizeFieldType(typeName);
5240
+ var booleanDefault = (rawDefault) => {
5241
+ if (typeof rawDefault === "boolean")
5242
+ return String(rawDefault);
5243
+ if (typeof rawDefault !== "string")
5244
+ return null;
5245
+ const lowered = rawDefault.trim().toLowerCase();
5246
+ return lowered === "true" || lowered === "false" ? lowered : null;
5247
+ };
5248
+ var dateDefault = (rawDefault) => {
5249
+ if (typeof rawDefault === "number" && Number.isFinite(rawDefault))
5250
+ return `new Date(${rawDefault})`;
5251
+ if (typeof rawDefault !== "string")
5252
+ return null;
5253
+ const trimmed = rawDefault.trim();
5254
+ if (!trimmed)
5255
+ return null;
5256
+ if (trimmed === "now")
5257
+ return "new Date()";
5258
+ if (!Number.isNaN(Date.parse(trimmed)))
5259
+ return `new Date(${JSON.stringify(trimmed)})`;
5260
+ return null;
5261
+ };
5262
+ var coerceFieldDefault = (typeName, defaultValue, options = {}) => {
5263
+ const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
5264
+ if (defaultValue === undefined || defaultValue === null || defaultValue === "") {
5265
+ return { expression: null, normalized: false, normalizedType };
5266
+ }
5365
5267
  if (normalizedType === "Int" || normalizedType === "Float") {
5366
5268
  const expression = numericDefault(normalizedType, defaultValue);
5367
5269
  if (expression !== null)
5368
- return { expression };
5270
+ return { expression, normalized: typeof defaultValue === "string", normalizedType };
5369
5271
  return {
5370
5272
  expression: null,
5273
+ normalized: false,
5274
+ normalizedType,
5371
5275
  diagnostic: {
5372
5276
  severity: "error",
5373
5277
  code: "primitive-default-value-invalid",
@@ -5378,11 +5282,13 @@ var coerceFieldDefault = (typeName, defaultValue) => {
5378
5282
  };
5379
5283
  }
5380
5284
  if (normalizedType === "Boolean") {
5381
- const lowered = defaultValue.trim().toLowerCase();
5382
- if (lowered === "true" || lowered === "false")
5383
- return { expression: lowered };
5285
+ const expression = booleanDefault(defaultValue);
5286
+ if (expression !== null)
5287
+ return { expression, normalized: typeof defaultValue === "string", normalizedType };
5384
5288
  return {
5385
5289
  expression: null,
5290
+ normalized: false,
5291
+ normalizedType,
5386
5292
  diagnostic: {
5387
5293
  severity: "error",
5388
5294
  code: "primitive-default-value-invalid",
@@ -5392,13 +5298,58 @@ var coerceFieldDefault = (typeName, defaultValue) => {
5392
5298
  }
5393
5299
  };
5394
5300
  }
5395
- return { expression: JSON.stringify(defaultValue) };
5301
+ if (normalizedType === "Date") {
5302
+ const expression = dateDefault(defaultValue);
5303
+ if (expression !== null)
5304
+ return { expression, normalized: true, normalizedType };
5305
+ return {
5306
+ expression: null,
5307
+ normalized: false,
5308
+ normalizedType,
5309
+ diagnostic: {
5310
+ severity: "error",
5311
+ code: "primitive-default-value-invalid",
5312
+ input: "default",
5313
+ failureScope: "source-change",
5314
+ message: `Default value for Date must be "now", a timestamp, or a parseable date string. Received: ${JSON.stringify(defaultValue)}.`
5315
+ }
5316
+ };
5317
+ }
5318
+ if (normalizedType === "enum") {
5319
+ if (typeof defaultValue === "string" && options.enumValues?.includes(defaultValue)) {
5320
+ return { expression: JSON.stringify(defaultValue), normalized: false, normalizedType };
5321
+ }
5322
+ return {
5323
+ expression: null,
5324
+ normalized: false,
5325
+ normalizedType,
5326
+ diagnostic: {
5327
+ severity: "error",
5328
+ code: "primitive-default-value-invalid",
5329
+ input: "default",
5330
+ failureScope: "source-change",
5331
+ message: `Default value for enum must be one of: ${(options.enumValues ?? []).join(", ")}. Received: ${JSON.stringify(defaultValue)}.`
5332
+ }
5333
+ };
5334
+ }
5335
+ return {
5336
+ expression: JSON.stringify(String(defaultValue)),
5337
+ normalized: typeof defaultValue !== "string",
5338
+ normalizedType
5339
+ };
5396
5340
  };
5397
- var fieldExpression = (typeName, defaultValue) => {
5341
+ var fieldExpression = (typeName, defaultValue, options = {}) => {
5398
5342
  const typeExpression = normalizeFieldType(typeName);
5399
- const defaultExpression = coerceFieldDefault(typeExpression, defaultValue).expression;
5343
+ const defaultExpression = coerceFieldDefault(options.enumValues ? "enum" : typeExpression, defaultValue, options).expression;
5400
5344
  const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
5401
- 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;
5402
5353
  };
5403
5354
  var insertIntoObject = (content, className, line) => {
5404
5355
  const classIndex = content.indexOf(`export class ${className} extends via`);
@@ -5416,74 +5367,538 @@ var insertIntoObject = (content, className, line) => {
5416
5367
  `;
5417
5368
  return `${prefix}${insertion}${suffix}`;
5418
5369
  };
5419
- var ensureEnumImport = (content) => {
5420
- if (content.includes("enumOf"))
5421
- return content;
5422
- const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
5423
- if (baseImport) {
5424
- const names = baseImport[1]?.split(",").map((name) => name.trim()) ?? [];
5425
- return content.replace(baseImport[0], `import { ${[...names, "enumOf"].sort().join(", ")} } from "akanjs/base";`);
5370
+ var insertLightProjectionField = (content, moduleClassName, fieldName) => {
5371
+ const classIndex = content.indexOf(`export class Light${moduleClassName} extends via`);
5372
+ if (classIndex < 0)
5373
+ return null;
5374
+ const arrayMatch = /\[([\s\S]*?)\]\s+as const/.exec(content.slice(classIndex));
5375
+ if (!arrayMatch || arrayMatch.index === undefined)
5376
+ return null;
5377
+ const arrayStart = classIndex + arrayMatch.index;
5378
+ const arrayEnd = arrayStart + arrayMatch[0].length;
5379
+ const fields = [...arrayMatch[1].matchAll(/"([^"]+)"/g)].map((match) => match[1]).filter(Boolean);
5380
+ if (fields.includes(fieldName))
5381
+ return content;
5382
+ const nextFields = [...fields, fieldName];
5383
+ const nextArray = nextFields.length === 0 ? "[] as const" : `[
5384
+ ${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
5385
+ `)}
5386
+ ] as const`;
5387
+ return `${content.slice(0, arrayStart)}${nextArray}${content.slice(arrayEnd)}`;
5388
+ };
5389
+ var insertTemplateField = ({
5390
+ content,
5391
+ moduleName,
5392
+ moduleClassName,
5393
+ fieldName,
5394
+ component
5395
+ }) => {
5396
+ if (content.includes(`l("${moduleName}.${fieldName}")`) || content.includes(`.${fieldName}`))
5397
+ return content;
5398
+ const layoutEndIndex = content.indexOf(" </Layout.Template>");
5399
+ if (layoutEndIndex < 0)
5400
+ return null;
5401
+ const formName = `${moduleName}Form`;
5402
+ if (!content.includes(`const ${formName} = st.use.${moduleName}Form();`))
5403
+ return null;
5404
+ const fieldSetter = `st.do.set${moduleComponentName(fieldName)}On${moduleClassName}`;
5405
+ const fieldBlock = ` <${component}
5406
+ label={l("${moduleName}.${fieldName}")}
5407
+ desc={l("${moduleName}.${fieldName}.desc")}
5408
+ value={${formName}.${fieldName}}
5409
+ onChange={${fieldSetter}}
5410
+ />
5411
+ `;
5412
+ return `${content.slice(0, layoutEndIndex)}${fieldBlock}${content.slice(layoutEndIndex)}`;
5413
+ };
5414
+ var ensureEnumImport = (content) => {
5415
+ if (content.includes("enumOf"))
5416
+ return content;
5417
+ const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
5418
+ if (baseImport) {
5419
+ const names = baseImport[1]?.split(",").map((name) => name.trim()) ?? [];
5420
+ return content.replace(baseImport[0], `import { ${[...names, "enumOf"].sort().join(", ")} } from "akanjs/base";`);
5421
+ }
5422
+ return `import { enumOf } from "akanjs/base";
5423
+ ${content}`;
5424
+ };
5425
+ var insertEnumClass = (content, enumClassName, enumName, values) => {
5426
+ if (content.includes(`export class ${enumClassName} extends enumOf`))
5427
+ return content;
5428
+ const enumClass = `export class ${enumClassName} extends enumOf("${enumName}", [
5429
+ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
5430
+ `)}
5431
+ ] as const) {}
5432
+
5433
+ `;
5434
+ const firstClassIndex = content.indexOf("export class ");
5435
+ if (firstClassIndex < 0)
5436
+ return `${content}
5437
+ ${enumClass}`;
5438
+ return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
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
+ };
5478
+ var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
5479
+ if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
5480
+ return content;
5481
+ const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => (`);
5482
+ if (modelIndex < 0)
5483
+ return null;
5484
+ const objectStartIndex = content.indexOf("{", modelIndex);
5485
+ if (objectStartIndex < 0)
5486
+ return null;
5487
+ const objectEndIndex = findMatchingBrace(content, objectStartIndex);
5488
+ if (objectEndIndex < 0)
5489
+ return null;
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)}`;
5503
+ };
5504
+ var ensureConstantTypeImport = (content, constantPath, typeName) => {
5505
+ if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
5506
+ return content;
5507
+ const importPattern = new RegExp(`import type \\{ ([^}]+) \\} from "${constantPath}";`);
5508
+ const existingImport = content.match(importPattern);
5509
+ if (existingImport !== null) {
5510
+ const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
5511
+ return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
5512
+ }
5513
+ return `import type { ${typeName} } from "${constantPath}";
5514
+ ${content}`;
5515
+ };
5516
+ var insertDictionaryEnum = (content, enumClassName, enumName, values) => {
5517
+ if (content.includes(`.enum<${enumClassName}>("${enumName}"`))
5518
+ return content;
5519
+ const enumBlock = ` .enum<${enumClassName}>("${enumName}", (t) => ({
5520
+ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${JSON.stringify(titleize(value))}]),`).join(`
5521
+ `)}
5522
+ }))
5523
+ `;
5524
+ const chainEndIndex = content.lastIndexOf(";");
5525
+ const insertBeforeIndex = [content.indexOf(".error("), content.indexOf(".translate("), chainEndIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
5526
+ if (insertBeforeIndex === undefined)
5527
+ return null;
5528
+ return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
5529
+ };
5530
+ var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
5531
+
5532
+ // pkgs/@akanjs/devkit/workflow/uiPolicy.ts
5533
+ var addFieldUiPolicyForType = (typeName) => {
5534
+ const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
5535
+ if (normalizedType === "Int" || normalizedType === "Float") {
5536
+ return {
5537
+ normalizedType,
5538
+ component: "Field.Number",
5539
+ confidence: "high",
5540
+ autoTemplateSupported: true
5541
+ };
5542
+ }
5543
+ if (normalizedType === "Date") {
5544
+ return {
5545
+ normalizedType,
5546
+ component: "Field.Date",
5547
+ confidence: "high",
5548
+ autoTemplateSupported: true
5549
+ };
5550
+ }
5551
+ if (normalizedType === "Boolean" || normalizedType === "enum") {
5552
+ return {
5553
+ normalizedType,
5554
+ component: "Field.ToggleSelect",
5555
+ confidence: "medium",
5556
+ autoTemplateSupported: false
5557
+ };
5558
+ }
5559
+ if (normalizedType === "String") {
5560
+ return {
5561
+ normalizedType,
5562
+ component: "Field.Text",
5563
+ confidence: "high",
5564
+ autoTemplateSupported: true
5565
+ };
5566
+ }
5567
+ return {
5568
+ normalizedType,
5569
+ component: "Field.Text",
5570
+ confidence: "low",
5571
+ autoTemplateSupported: false
5572
+ };
5573
+ };
5574
+
5575
+ // pkgs/@akanjs/devkit/workflow/executor.ts
5576
+ var workflowStepKey = (workflow, stepId) => `${workflow}:${stepId}`;
5577
+ var primitiveReportToWorkflowStepResult = (report) => ({
5578
+ changedFiles: report.changedFiles,
5579
+ generatedFiles: report.generatedFiles,
5580
+ commands: report.validationCommands,
5581
+ diagnostics: report.diagnostics,
5582
+ recommendations: [],
5583
+ nextActions: report.nextActions
5584
+ });
5585
+ var workflowStringInput = (value) => typeof value === "string" ? value : null;
5586
+ var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
5587
+ var workflowStringArrayInput = (value) => Array.isArray(value) ? value : null;
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
+ };
5678
+ var resolveWorkflowSys = async (workspace, target) => {
5679
+ if (!target)
5680
+ return null;
5681
+ const [apps, libs] = await workspace.getSyss();
5682
+ if (apps.includes(target))
5683
+ return AppExecutor.from(workspace, target);
5684
+ if (libs.includes(target))
5685
+ return LibExecutor.from(workspace, target);
5686
+ return null;
5687
+ };
5688
+ var targetMissing = (input2 = "app") => ({
5689
+ severity: "error",
5690
+ code: "workflow-target-missing",
5691
+ input: input2,
5692
+ message: "Workflow target app or library was not found."
5693
+ });
5694
+ var inputMissing = (input2) => ({
5695
+ severity: "error",
5696
+ code: "workflow-input-missing",
5697
+ input: input2,
5698
+ message: `Workflow input "${input2}" is required for apply.`
5699
+ });
5700
+ var unsupportedInput = (input2, message) => ({
5701
+ severity: "error",
5702
+ code: "workflow-input-unsupported",
5703
+ input: input2,
5704
+ message
5705
+ });
5706
+ var addFieldUiSurfaceInspection = (plan) => {
5707
+ const app = workflowStringInput(plan.inputs.app);
5708
+ const module = workflowStringInput(plan.inputs.module) ?? "<module>";
5709
+ const field = workflowStringInput(plan.inputs.field) ?? "<field>";
5710
+ const typeName = workflowStringInput(plan.inputs.type);
5711
+ const policy = addFieldUiPolicyForType(typeName ?? "String");
5712
+ const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
5713
+ const templateRequested = surfaces?.includes("template") ?? false;
5714
+ const moduleClassName = capitalize2(module);
5715
+ const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
5716
+ return {
5717
+ recommendations: [
5718
+ {
5719
+ code: "add-field-ui-surface-review",
5720
+ kind: "manual-action",
5721
+ target,
5722
+ action: templateRequested ? `Template was requested for ${field}. If no Template file changed, auto-edit was skipped because the file was missing, the generated ${module}Form/Layout.Template pattern was not found, or ${policy.component} needs option binding. Candidate position: inside Layout.Template near the existing Field components.` : `Template was not selected, so UI files are intentionally left unchanged. Candidate positions if you expose it later: Layout.Template field list for editing, Light${moduleClassName} projection for list/card data, and Unit/View card sections for display.`,
5723
+ confidence: "medium",
5724
+ message: `Review UI surfaces for ${module}.${field}; recommended component is ${policy.component}, with manual reasons and candidate positions in action.`
5725
+ }
5726
+ ],
5727
+ nextActions: [
5728
+ {
5729
+ command: `akan workflow explain ${plan.workflow}`,
5730
+ reason: "Review UI surface guidance before manually editing ambiguous UI files."
5731
+ }
5732
+ ]
5733
+ };
5734
+ };
5735
+ var createWorkflowStepRegistry = ({
5736
+ workspace,
5737
+ createModule,
5738
+ createScalar,
5739
+ createUi,
5740
+ addField,
5741
+ addEnumField
5742
+ }) => {
5743
+ const inspect = async () => {
5744
+ return;
5745
+ };
5746
+ const commandOnly = async () => {
5747
+ return;
5748
+ };
5749
+ return {
5750
+ inspectSystem: inspect,
5751
+ inspectModule: inspect,
5752
+ syncTarget: commandOnly,
5753
+ lintTarget: commandOnly,
5754
+ [workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
5755
+ const app = workflowStringInput(plan.inputs.app);
5756
+ const module = workflowStringInput(plan.inputs.module);
5757
+ const sys2 = await resolveWorkflowSys(workspace, app);
5758
+ if (!sys2 || !module)
5759
+ return { diagnostics: [!sys2 ? targetMissing() : inputMissing("module")] };
5760
+ return primitiveReportToWorkflowStepResult(await createModule(sys2, module));
5761
+ },
5762
+ [workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
5763
+ const app = workflowStringInput(plan.inputs.app);
5764
+ const scalar = workflowStringInput(plan.inputs.scalar);
5765
+ const sys2 = await resolveWorkflowSys(workspace, app);
5766
+ if (!sys2 || !scalar)
5767
+ return { diagnostics: [!sys2 ? targetMissing() : inputMissing("scalar")] };
5768
+ return primitiveReportToWorkflowStepResult(await createScalar(sys2, scalar));
5769
+ },
5770
+ [workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
5771
+ const surface = workflowStringInput(plan.inputs.surface);
5772
+ if (surface !== "view" && surface !== "unit" && surface !== "template") {
5773
+ return {
5774
+ diagnostics: [
5775
+ unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
5776
+ ]
5777
+ };
5778
+ }
5779
+ return primitiveReportToWorkflowStepResult(await createUi({
5780
+ app: workflowStringInput(plan.inputs.app),
5781
+ module: workflowStringInput(plan.inputs.module),
5782
+ surface
5783
+ }));
5784
+ },
5785
+ [workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
5786
+ if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
5787
+ return primitiveReportToWorkflowStepResult(await addEnumField({
5788
+ app: workflowStringInput(plan.inputs.app),
5789
+ module: workflowStringInput(plan.inputs.module),
5790
+ field: workflowStringInput(plan.inputs.field),
5791
+ values: workflowStringListInput(plan.inputs.values),
5792
+ defaultValue: workflowStringInput(plan.inputs.default),
5793
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
5794
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
5795
+ }));
5796
+ }
5797
+ return primitiveReportToWorkflowStepResult(await addField({
5798
+ app: workflowStringInput(plan.inputs.app),
5799
+ module: workflowStringInput(plan.inputs.module),
5800
+ field: workflowStringInput(plan.inputs.field),
5801
+ type: workflowStringInput(plan.inputs.type),
5802
+ defaultValue: workflowStringInput(plan.inputs.default),
5803
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
5804
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
5805
+ }));
5806
+ },
5807
+ [workflowStepKey("add-field", "update-dictionary")]: inspect,
5808
+ [workflowStepKey("add-field", "update-ui-surfaces")]: async (_step, plan) => addFieldUiSurfaceInspection(plan),
5809
+ [workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
5810
+ app: workflowStringInput(plan.inputs.app),
5811
+ module: workflowStringInput(plan.inputs.module),
5812
+ field: workflowStringInput(plan.inputs.field),
5813
+ values: workflowStringListInput(plan.inputs.values),
5814
+ defaultValue: workflowStringInput(plan.inputs.default)
5815
+ })),
5816
+ [workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
5817
+ [workflowStepKey("add-enum-field", "update-option")]: inspect
5818
+ };
5819
+ };
5820
+ class WorkflowExecutor {
5821
+ registry;
5822
+ workspace;
5823
+ constructor(registry, workspace) {
5824
+ this.registry = registry;
5825
+ this.workspace = workspace;
5426
5826
  }
5427
- return `import { enumOf } from "akanjs/base";
5428
- ${content}`;
5429
- };
5430
- var insertEnumClass = (content, enumClassName, enumName, values) => {
5431
- if (content.includes(`export class ${enumClassName} extends enumOf`))
5432
- return content;
5433
- const enumClass = `export class ${enumClassName} extends enumOf("${enumName}", [
5434
- ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
5435
- `)}
5436
- ] as const) {}
5437
-
5438
- `;
5439
- const firstClassIndex = content.indexOf("export class ");
5440
- if (firstClassIndex < 0)
5441
- return `${content}
5442
- ${enumClass}`;
5443
- return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
5444
- };
5445
- var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
5446
- if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
5447
- return content;
5448
- const label = titleize(fieldName);
5449
- const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => ({`);
5450
- if (modelIndex < 0)
5451
- return null;
5452
- const objectEndIndex = content.indexOf(" }))", modelIndex);
5453
- if (objectEndIndex < 0)
5454
- return null;
5455
- return `${content.slice(0, objectEndIndex)} ${fieldName}: t([${JSON.stringify(label)}, ${JSON.stringify(label)}]).desc([${JSON.stringify(label)}, ${JSON.stringify(label)}]),
5456
- ${content.slice(objectEndIndex)}`;
5457
- };
5458
- var ensureConstantTypeImport = (content, constantPath, typeName) => {
5459
- if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
5460
- return content;
5461
- const importPattern = new RegExp(`import type \\{ ([^}]+) \\} from "${constantPath}";`);
5462
- const existingImport = content.match(importPattern);
5463
- if (existingImport !== null) {
5464
- const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
5465
- return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
5827
+ async apply(plan) {
5828
+ const changedFiles = [];
5829
+ const generatedFiles = [];
5830
+ const recommendedValidationCommands = [];
5831
+ const diagnostics = [...plan.diagnostics];
5832
+ const postApplyChecks = [];
5833
+ const recommendations = [...plan.recommendations];
5834
+ const nextActions = [];
5835
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
5836
+ return createWorkflowApplyReport({
5837
+ workflow: plan.workflow,
5838
+ mode: "apply",
5839
+ changedFiles,
5840
+ generatedFiles,
5841
+ recommendedValidationCommands,
5842
+ diagnostics,
5843
+ postApplyChecks,
5844
+ recommendations,
5845
+ nextActions,
5846
+ plan
5847
+ });
5848
+ }
5849
+ recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
5850
+ nextActions.push(...workflowCommandsForPlan(plan));
5851
+ for (const step of plan.steps) {
5852
+ const runner = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
5853
+ if (!runner) {
5854
+ diagnostics.push({
5855
+ severity: "error",
5856
+ code: "workflow-step-unsupported",
5857
+ message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
5858
+ });
5859
+ nextActions.push({
5860
+ command: `akan workflow explain ${plan.workflow}`,
5861
+ reason: "Review the unsupported workflow step before retrying apply."
5862
+ });
5863
+ break;
5864
+ }
5865
+ const result = await runner(step, plan);
5866
+ if (!result)
5867
+ continue;
5868
+ changedFiles.push(...result.changedFiles ?? []);
5869
+ generatedFiles.push(...result.generatedFiles ?? []);
5870
+ recommendedValidationCommands.push(...result.commands ?? []);
5871
+ diagnostics.push(...result.diagnostics ?? []);
5872
+ recommendations.push(...result.recommendations ?? []);
5873
+ nextActions.push(...result.nextActions ?? []);
5874
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
5875
+ break;
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
+ }
5886
+ return createWorkflowApplyReport({
5887
+ workflow: plan.workflow,
5888
+ mode: "apply",
5889
+ changedFiles,
5890
+ generatedFiles,
5891
+ recommendedValidationCommands,
5892
+ diagnostics,
5893
+ postApplyChecks,
5894
+ recommendations,
5895
+ nextActions,
5896
+ plan
5897
+ });
5466
5898
  }
5467
- return `import type { ${typeName} } from "${constantPath}";
5468
- ${content}`;
5469
- };
5470
- var insertDictionaryEnum = (content, enumClassName, enumName, values) => {
5471
- if (content.includes(`.enum<${enumClassName}>("${enumName}"`))
5472
- return content;
5473
- const enumBlock = ` .enum<${enumClassName}>("${enumName}", (t) => ({
5474
- ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${JSON.stringify(titleize(value))}]),`).join(`
5475
- `)}
5476
- }))
5477
- `;
5478
- const chainEndIndex = content.lastIndexOf(";");
5479
- const insertBeforeIndex = [content.indexOf(".error("), content.indexOf(".translate("), chainEndIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
5480
- if (insertBeforeIndex === undefined)
5481
- return null;
5482
- return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
5483
- };
5484
- var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
5485
-
5899
+ }
5486
5900
  // pkgs/@akanjs/devkit/workflow/plan.ts
5901
+ import { capitalize as capitalize3 } from "akanjs/common";
5487
5902
  var surfaceModes = new Set(["infer", "include", "skip"]);
5488
5903
  var parseStringList = (value) => {
5489
5904
  if (Array.isArray(value)) {
@@ -5501,6 +5916,18 @@ var normalizeInputValue = (name, spec, value) => {
5501
5916
  const values = parseStringList(value);
5502
5917
  return values && values.length > 0 ? values : null;
5503
5918
  }
5919
+ if (spec.type === "boolean") {
5920
+ if (typeof value === "boolean")
5921
+ return value;
5922
+ if (typeof value !== "string")
5923
+ return null;
5924
+ const lowered = value.trim().toLowerCase();
5925
+ if (lowered === "true")
5926
+ return true;
5927
+ if (lowered === "false")
5928
+ return false;
5929
+ return null;
5930
+ }
5504
5931
  if (typeof value === "string" && surfaceModes.has(value))
5505
5932
  return value;
5506
5933
  throw new Error(`Unsupported workflow input value for ${name}`);
@@ -5508,17 +5935,45 @@ var normalizeInputValue = (name, spec, value) => {
5508
5935
  var listWorkflowSpecs = (specs) => [...specs].sort((a, b) => a.name.localeCompare(b.name));
5509
5936
  var getWorkflowSpec = (specs, name) => specs.find((spec) => spec.name === name) ?? null;
5510
5937
  var compactWorkflowInputs = (inputs) => Object.fromEntries(Object.entries(inputs).filter(([, value]) => value !== null && value !== ""));
5511
- var addFieldComponentForType = (typeName) => {
5512
- const normalizedType = normalizeFieldType(typeName);
5513
- if (normalizedType === "Boolean")
5514
- return "Field.ToggleSelect";
5515
- if (normalizedType === "Date")
5516
- return "Field.Date";
5517
- if (normalizedType === "Int" || normalizedType === "Float")
5518
- return "manual numeric input review";
5519
- if (typeName.toLowerCase() === "enum")
5520
- return "Field.ToggleSelect";
5521
- return "Field.Text";
5938
+ var addFieldTargetRoot = (app) => app ? `apps/${app}` : "*";
5939
+ var addFieldPaths = (inputs) => {
5940
+ const app = typeof inputs.app === "string" ? inputs.app : null;
5941
+ const module = typeof inputs.module === "string" ? inputs.module : "<module>";
5942
+ const paths = moduleSourcePaths(module);
5943
+ const root = addFieldTargetRoot(app);
5944
+ return {
5945
+ constant: `${root}/${paths.constant}`,
5946
+ dictionary: `${root}/${paths.dictionary}`,
5947
+ template: `${root}/${paths.template}`,
5948
+ unit: `${root}/${paths.unit}`,
5949
+ view: `${root}/${paths.view}`
5950
+ };
5951
+ };
5952
+ var selectedAddFieldSurfaces = (inputs) => Array.isArray(inputs.surfaces) ? new Set(inputs.surfaces) : null;
5953
+ var addFieldDefaultCoercion = (inputs) => {
5954
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
5955
+ const defaultValue = typeof inputs.default === "string" ? inputs.default : null;
5956
+ if (!typeName || defaultValue === null)
5957
+ return null;
5958
+ if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric")
5959
+ return null;
5960
+ const enumValues = Array.isArray(inputs.values) ? inputs.values : null;
5961
+ return coerceFieldDefault(typeName.toLowerCase() === "enum" ? "enum" : typeName, defaultValue, { enumValues });
5962
+ };
5963
+ var createAddFieldDefaultRecommendations = (inputs) => {
5964
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
5965
+ const coercion = addFieldDefaultCoercion(inputs);
5966
+ if (!coercion?.normalized || !coercion.expression)
5967
+ return [];
5968
+ return [
5969
+ {
5970
+ code: "add-field-default-normalized",
5971
+ kind: "manual-action",
5972
+ confidence: "high",
5973
+ message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
5974
+ action: "Review the normalized default in the apply report if this value should stay unset."
5975
+ }
5976
+ ];
5522
5977
  };
5523
5978
  var createAddFieldRecommendations = (inputs) => {
5524
5979
  const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
@@ -5527,16 +5982,18 @@ var createAddFieldRecommendations = (inputs) => {
5527
5982
  const typeName = typeof inputs.type === "string" ? inputs.type : null;
5528
5983
  if (!typeName)
5529
5984
  return [];
5530
- const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
5531
- const constantPath = `*/lib/${module}/${module}.constant.ts`;
5532
- const dictionaryPath = `*/lib/${module}/${module}.dictionary.ts`;
5533
- const templatePath = `*/lib/${module}/${capitalize3(module)}.Template.tsx`;
5985
+ const policy = addFieldUiPolicyForType(typeName);
5986
+ const normalizedType = policy.normalizedType;
5987
+ const paths = addFieldPaths(inputs);
5988
+ const surfaces = selectedAddFieldSurfaces(inputs);
5989
+ const templateRequested = surfaces?.has("template") ?? false;
5990
+ const includeInLight = inputs.includeInLight === true;
5534
5991
  return [
5535
5992
  ...normalizedType === "Int" || normalizedType === "Float" ? [
5536
5993
  {
5537
5994
  code: "add-field-import",
5538
5995
  kind: "import",
5539
- target: constantPath,
5996
+ target: paths.constant,
5540
5997
  confidence: "high",
5541
5998
  message: `Import ${normalizedType} from "akanjs/base" before writing field(${normalizedType}).`
5542
5999
  }
@@ -5544,35 +6001,122 @@ var createAddFieldRecommendations = (inputs) => {
5544
6001
  {
5545
6002
  code: "add-field-placement-constant",
5546
6003
  kind: "placement",
5547
- target: constantPath,
6004
+ target: paths.constant,
5548
6005
  confidence: "high",
5549
6006
  message: `Insert ${field}: field(${normalizedType}) in ${capitalize3(module)}Input.`
5550
6007
  },
5551
6008
  {
5552
6009
  code: "add-field-placement-dictionary",
5553
6010
  kind: "placement",
5554
- target: dictionaryPath,
6011
+ target: paths.dictionary,
5555
6012
  confidence: "high",
5556
6013
  message: `Add dictionary labels for ${module}.${field}.`
5557
6014
  },
5558
6015
  {
5559
6016
  code: "add-field-component",
5560
6017
  kind: "ui-component",
5561
- target: templatePath,
5562
- confidence: normalizedType === "Int" || normalizedType === "Float" ? "low" : "high",
5563
- action: normalizedType === "Int" || normalizedType === "Float" ? "Do not auto-edit UI. Check local Template/Unit/View patterns for Field.Text parsing, formatting, validation rules, and dictionary labels before adding a numeric input." : undefined,
5564
- message: normalizedType === "Int" || normalizedType === "Float" ? `Numeric UI for ${field} (${normalizedType}) requires manual review; a safe numeric input component pattern is not yet detected.` : `Recommended UI component for ${field} (${normalizedType}): ${addFieldComponentForType(typeName)}.`
6018
+ target: paths.template,
6019
+ confidence: policy.confidence,
6020
+ action: templateRequested ? `apply_workflow will try to add ${policy.component} to Template when the existing Template has a safe generated field-list pattern.` : `Recommended component is ${policy.component}. Pass surfaces=["template"] when this field should be rendered in the Template form.`,
6021
+ message: `Recommended UI component for ${field} (${normalizedType}): ${policy.component}.`
5565
6022
  },
6023
+ ...!surfaces ? [
6024
+ {
6025
+ code: "add-field-template-surface-choice",
6026
+ kind: "manual-action",
6027
+ target: paths.template,
6028
+ action: `Choose whether to expose ${field} in Template by passing surfaces=["template"].`,
6029
+ confidence: "medium",
6030
+ message: `Template exposure for ${module}.${field} is not selected yet.`
6031
+ }
6032
+ ] : [],
6033
+ ...!includeInLight ? [
6034
+ {
6035
+ code: "add-field-light-projection-choice",
6036
+ kind: "manual-action",
6037
+ target: paths.constant,
6038
+ action: `Pass includeInLight=true when ${field} should appear in Light${capitalize3(module)} list/card projections.`,
6039
+ confidence: "medium",
6040
+ message: `Light projection exposure for ${module}.${field} is not selected yet.`
6041
+ }
6042
+ ] : [],
6043
+ ...includeInLight ? [
6044
+ {
6045
+ code: "add-field-light-projection",
6046
+ kind: "placement",
6047
+ target: paths.constant,
6048
+ confidence: "high",
6049
+ message: `Add ${field} to Light${capitalize3(module)} projection fields.`
6050
+ }
6051
+ ] : [],
6052
+ ...surfaces && !templateRequested ? [
6053
+ {
6054
+ code: "add-field-ui-surface-skip",
6055
+ kind: "manual-action",
6056
+ target: paths.template,
6057
+ confidence: "medium",
6058
+ message: `Template is not included in surfaces, so ${module}.${field} will not be auto-rendered there.`
6059
+ }
6060
+ ] : [],
5566
6061
  {
5567
6062
  code: "add-field-ui-manual-review",
5568
6063
  kind: "manual-action",
5569
- target: templatePath,
5570
- action: `Review ${app}:${module} Template/Unit/View/Store surfaces and add ${field} only where the existing pattern is clear. For numeric fields, confirm parser/formatter behavior and validation before using Field.Text.`,
6064
+ target: paths.template,
6065
+ action: `Review ${app}:${module} UI after apply. Template auto-edit requires a generated ${module}Form hook and Layout.Template field list; Unit/View are not auto-edited because list/card placement depends on local layout. Candidate positions: Layout.Template before the closing tag, Light${capitalize3(module)} projection array for list data, and Unit/View card sections for display.`,
5571
6066
  confidence: "medium",
5572
- message: normalizedType === "Int" || normalizedType === "Float" ? "UI surface edits stay manual because a safe numeric input component pattern is not yet detected." : "UI surface edits are planned as manual-review unless a safe existing field-list pattern is detected."
6067
+ message: "UI manual review includes the reason auto-edit may be skipped and candidate insertion positions."
6068
+ },
6069
+ ...createAddFieldDefaultRecommendations(inputs)
6070
+ ];
6071
+ };
6072
+ var createWorkflowPlanPredictedChanges = (spec, inputs) => {
6073
+ if (spec.name !== "add-field")
6074
+ return spec.predictedChanges;
6075
+ const paths = addFieldPaths(inputs);
6076
+ const surfaces = selectedAddFieldSurfaces(inputs);
6077
+ const includeInLight = inputs.includeInLight === true;
6078
+ return [
6079
+ {
6080
+ target: paths.constant,
6081
+ action: "modify",
6082
+ applyScope: "auto",
6083
+ reason: includeInLight ? "Field shape and Light projection are added." : "Field shape is added."
6084
+ },
6085
+ {
6086
+ target: paths.dictionary,
6087
+ action: "modify",
6088
+ applyScope: "auto",
6089
+ reason: "Field label is added."
6090
+ },
6091
+ ...!surfaces || surfaces.has("template") ? [
6092
+ {
6093
+ target: paths.template,
6094
+ action: "modify",
6095
+ applyScope: surfaces?.has("template") ? "auto" : "manual-review",
6096
+ reason: surfaces?.has("template") ? "Template form is selected for safe-pattern auto insertion." : "Form surface may include the field."
6097
+ }
6098
+ ] : [],
6099
+ {
6100
+ target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/cnst.ts`,
6101
+ action: "sync",
6102
+ applyScope: "generated-sync",
6103
+ reason: "Generated constants may change after sync."
6104
+ },
6105
+ {
6106
+ target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/dict.ts`,
6107
+ action: "sync",
6108
+ applyScope: "generated-sync",
6109
+ reason: "Generated dictionary barrel may change after sync."
5573
6110
  }
5574
6111
  ];
5575
6112
  };
6113
+ var createWorkflowPlanOptionalSurfaces = (spec, inputs) => {
6114
+ const optionalSurfaces = spec.optionalSurfaces ?? {};
6115
+ const surfaces = selectedAddFieldSurfaces(inputs);
6116
+ if (spec.name !== "add-field" || !surfaces)
6117
+ return optionalSurfaces;
6118
+ return Object.fromEntries(Object.entries(optionalSurfaces).map(([surface, mode]) => [surface, surfaces.has(surface) ? "include" : mode]));
6119
+ };
5576
6120
  var createWorkflowPlanRecommendations = (spec, inputs) => [
5577
6121
  {
5578
6122
  code: "workflow-apply-first",
@@ -5636,14 +6180,32 @@ var createWorkflowPlan = (spec, rawInputs) => {
5636
6180
  message: `Field type "${fieldType}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`
5637
6181
  });
5638
6182
  }
6183
+ if (spec.name === "add-field") {
6184
+ const defaultCoercion = addFieldDefaultCoercion(inputs);
6185
+ if (defaultCoercion?.diagnostic) {
6186
+ diagnostics.push({
6187
+ ...defaultCoercion.diagnostic,
6188
+ code: "workflow-default-value-invalid",
6189
+ message: `Plan input default is not valid for ${defaultCoercion.normalizedType}: ${defaultCoercion.diagnostic.message}`
6190
+ });
6191
+ } else if (defaultCoercion?.normalized && defaultCoercion.expression) {
6192
+ diagnostics.push({
6193
+ severity: "warning",
6194
+ code: "workflow-default-value-normalized",
6195
+ input: "default",
6196
+ failureScope: "source-change",
6197
+ message: `Plan input default will be written as ${defaultCoercion.normalizedType} literal ${defaultCoercion.expression}.`
6198
+ });
6199
+ }
6200
+ }
5639
6201
  return {
5640
6202
  schemaVersion: 1,
5641
6203
  workflow: spec.name,
5642
6204
  mode: "plan",
5643
6205
  inputs,
5644
- optionalSurfaces: spec.optionalSurfaces ?? {},
6206
+ optionalSurfaces: createWorkflowPlanOptionalSurfaces(spec, inputs),
5645
6207
  steps: spec.steps,
5646
- predictedChanges: spec.predictedChanges,
6208
+ predictedChanges: createWorkflowPlanPredictedChanges(spec, inputs),
5647
6209
  validation: spec.validation,
5648
6210
  diagnostics,
5649
6211
  recommendations: createWorkflowPlanRecommendations(spec, inputs),
@@ -5712,35 +6274,65 @@ var renderWorkflowPlan = (plan) => [
5712
6274
  ""
5713
6275
  ].join(`
5714
6276
  `);
5715
- var renderWorkflowApplyReport = (report) => [
5716
- `# Workflow Apply: ${report.workflow}`,
5717
- "",
5718
- `- Mode: ${report.mode}`,
5719
- `- Status: ${report.status}`,
5720
- "",
5721
- "## Changed Files",
5722
- ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
5723
- "",
5724
- "## Generated Files",
5725
- ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
5726
- "",
5727
- "## Applied Commands",
5728
- ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
5729
- "",
5730
- "## Recommended Validation Commands",
5731
- ...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
5732
- "",
5733
- "## Diagnostics",
5734
- ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
5735
- "",
5736
- "## Recommendations",
5737
- ...report.recommendations.length ? report.recommendations.map((recommendation) => `- [${recommendation.kind}] ${recommendation.message}`) : ["- none"],
5738
- "",
5739
- "## Next Actions",
5740
- ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
5741
- ""
5742
- ].join(`
6277
+ var renderRecommendation = (recommendation) => {
6278
+ const target = recommendation.target ? ` ${recommendation.target}` : "";
6279
+ const action = recommendation.action ? ` Action: ${recommendation.action}` : "";
6280
+ return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
6281
+ };
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";
6284
+ var renderWorkflowApplyReport = (report) => {
6285
+ const manualReviewItems = [
6286
+ ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
6287
+ ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
6288
+ ];
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);
6291
+ return [
6292
+ `# Workflow Apply: ${report.workflow}`,
6293
+ "",
6294
+ `- Mode: ${report.mode}`,
6295
+ `- Status: ${report.status}`,
6296
+ `- Source-change status: ${applySourceStatus(report)}`,
6297
+ `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
6298
+ ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
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
+ "",
6306
+ "## Automatically Modified",
6307
+ ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6308
+ "",
6309
+ "## Generated Sync",
6310
+ ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6311
+ "",
6312
+ "## Applied Commands",
6313
+ ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
6314
+ "",
6315
+ "## Recommended Validation Commands",
6316
+ ...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
6317
+ "",
6318
+ "## User Review Required",
6319
+ ...manualReviewItems.length ? manualReviewItems : ["- none"],
6320
+ "",
6321
+ "## Validation Blockers",
6322
+ ...validationBlockers.length ? validationBlockers : report.recommendedValidationCommands.length ? ["- none detected during apply; run validation with the validation target for command-level blockers."] : ["- none"],
6323
+ "",
6324
+ "## Diagnostics",
6325
+ ...report.diagnostics.length ? report.diagnostics.map(renderDiagnostic) : ["- none"],
6326
+ "",
6327
+ "## Recommendations",
6328
+ ...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
6329
+ "",
6330
+ "## Next Actions",
6331
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
6332
+ ""
6333
+ ].join(`
5743
6334
  `);
6335
+ };
5744
6336
  var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
5745
6337
  var renderWorkflowValidationRunReport = (report) => [
5746
6338
  `# Workflow Validation: ${report.workflow}`,
@@ -5751,11 +6343,24 @@ var renderWorkflowValidationRunReport = (report) => [
5751
6343
  `- Workspace status: ${report.workspaceStatus}`,
5752
6344
  `- Overall status: ${report.overallStatus}`,
5753
6345
  "",
6346
+ "## Status Summary",
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"],
6357
+ "",
5754
6358
  "## Known Blockers",
5755
6359
  ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
5756
6360
  const command = blocker.command ? ` \`${blocker.command}\`` : "";
5757
6361
  const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
5758
- return `- [${blocker.failureScope}]${command}${count}: ${blocker.message}`;
6362
+ const known = blocker.known ? " known" : "";
6363
+ return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
5759
6364
  }) : ["- none"],
5760
6365
  "",
5761
6366
  "## Commands",
@@ -6824,7 +7429,7 @@ var collapseIndex = (relPathNoExt) => {
6824
7429
 
6825
7430
  // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
6826
7431
  import path14 from "path";
6827
- import ts4 from "typescript";
7432
+ import ts5 from "typescript";
6828
7433
  var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
6829
7434
  const akanConfig2 = await app.getConfig();
6830
7435
  const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
@@ -7065,11 +7670,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
7065
7670
  };
7066
7671
  var findImportStatements = (source2) => {
7067
7672
  const statements = [];
7068
- 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);
7069
7674
  for (const statement of sourceFile2.statements) {
7070
- if (!ts4.isImportDeclaration(statement))
7675
+ if (!ts5.isImportDeclaration(statement))
7071
7676
  continue;
7072
- if (!ts4.isStringLiteral(statement.moduleSpecifier))
7677
+ if (!ts5.isStringLiteral(statement.moduleSpecifier))
7073
7678
  continue;
7074
7679
  const importClause = statement.importClause;
7075
7680
  if (!importClause)
@@ -8064,7 +8669,7 @@ import path22 from "path";
8064
8669
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
8065
8670
  import fs3 from "fs";
8066
8671
  import path21 from "path";
8067
- import ts5 from "typescript";
8672
+ import ts6 from "typescript";
8068
8673
 
8069
8674
  class PagesEntrySourceGenerator {
8070
8675
  #pageEntries;
@@ -8108,7 +8713,7 @@ ${entries.join(`
8108
8713
  static #hasAsyncDefaultExport(moduleAbsPath) {
8109
8714
  try {
8110
8715
  const source2 = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
8111
- 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));
8112
8717
  return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
8113
8718
  } catch {
8114
8719
  return false;
@@ -8118,31 +8723,31 @@ ${entries.join(`
8118
8723
  const asyncBindings = new Map;
8119
8724
  let defaultIdentifier = null;
8120
8725
  for (const statement of sourceFile2.statements) {
8121
- if (ts5.isFunctionDeclaration(statement)) {
8122
- if (PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.DefaultKeyword)) {
8123
- 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);
8124
8729
  }
8125
8730
  if (statement.name) {
8126
- asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword));
8731
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword));
8127
8732
  }
8128
8733
  continue;
8129
8734
  }
8130
- if (ts5.isVariableStatement(statement)) {
8735
+ if (ts6.isVariableStatement(statement)) {
8131
8736
  for (const declaration of statement.declarationList.declarations) {
8132
- if (!ts5.isIdentifier(declaration.name))
8737
+ if (!ts6.isIdentifier(declaration.name))
8133
8738
  continue;
8134
8739
  asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
8135
8740
  }
8136
8741
  continue;
8137
8742
  }
8138
- if (ts5.isExportAssignment(statement)) {
8743
+ if (ts6.isExportAssignment(statement)) {
8139
8744
  if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
8140
8745
  return true;
8141
- if (ts5.isIdentifier(statement.expression))
8746
+ if (ts6.isIdentifier(statement.expression))
8142
8747
  defaultIdentifier = statement.expression.text;
8143
8748
  continue;
8144
8749
  }
8145
- if (ts5.isExportDeclaration(statement) && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
8750
+ if (ts6.isExportDeclaration(statement) && statement.exportClause && ts6.isNamedExports(statement.exportClause)) {
8146
8751
  const exportClause = statement.exportClause;
8147
8752
  for (const specifier of exportClause.elements) {
8148
8753
  if (specifier.name.text !== "default")
@@ -8154,13 +8759,13 @@ ${entries.join(`
8154
8759
  return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
8155
8760
  }
8156
8761
  static #hasModifier(node, kind) {
8157
- 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);
8158
8763
  }
8159
8764
  static #isAsyncFunctionExpression(node) {
8160
- 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));
8161
8766
  }
8162
8767
  static #scriptKind(moduleAbsPath) {
8163
- 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;
8164
8769
  }
8165
8770
  }
8166
8771
 
@@ -9079,7 +9684,7 @@ import {
9079
9684
  } from "fontaine";
9080
9685
  import { createFont, woff2 } from "fonteditor-core";
9081
9686
  import subsetFont from "subset-font";
9082
- import ts6 from "typescript";
9687
+ import ts7 from "typescript";
9083
9688
  var FONT_URL_PREFIX = "/_akan/fonts";
9084
9689
  var DEFAULT_FONT_SUBSETS = ["latin"];
9085
9690
 
@@ -9144,17 +9749,17 @@ class FontOptimizer {
9144
9749
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
9145
9750
  }
9146
9751
  #extractFontsExport(source2, filePath) {
9147
- 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);
9148
9753
  const fonts = [];
9149
9754
  for (const statement of sourceFile2.statements) {
9150
- if (!ts6.isVariableStatement(statement))
9755
+ if (!ts7.isVariableStatement(statement))
9151
9756
  continue;
9152
- const modifiers = ts6.canHaveModifiers(statement) ? ts6.getModifiers(statement) : undefined;
9153
- 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;
9154
9759
  if (!isExported)
9155
9760
  continue;
9156
9761
  for (const declaration of statement.declarationList.declarations) {
9157
- if (!ts6.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9762
+ if (!ts7.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9158
9763
  continue;
9159
9764
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
9160
9765
  if (Array.isArray(value)) {
@@ -9165,20 +9770,20 @@ class FontOptimizer {
9165
9770
  return fonts;
9166
9771
  }
9167
9772
  #literalToValue(node) {
9168
- if (ts6.isStringLiteralLike(node))
9773
+ if (ts7.isStringLiteralLike(node))
9169
9774
  return node.text;
9170
- if (ts6.isNumericLiteral(node))
9775
+ if (ts7.isNumericLiteral(node))
9171
9776
  return Number(node.text);
9172
- if (node.kind === ts6.SyntaxKind.TrueKeyword)
9777
+ if (node.kind === ts7.SyntaxKind.TrueKeyword)
9173
9778
  return true;
9174
- if (node.kind === ts6.SyntaxKind.FalseKeyword)
9779
+ if (node.kind === ts7.SyntaxKind.FalseKeyword)
9175
9780
  return false;
9176
- if (ts6.isArrayLiteralExpression(node))
9781
+ if (ts7.isArrayLiteralExpression(node))
9177
9782
  return node.elements.map((element) => this.#literalToValue(element));
9178
- if (ts6.isObjectLiteralExpression(node)) {
9783
+ if (ts7.isObjectLiteralExpression(node)) {
9179
9784
  const obj = {};
9180
9785
  for (const prop of node.properties) {
9181
- if (!ts6.isPropertyAssignment(prop))
9786
+ if (!ts7.isPropertyAssignment(prop))
9182
9787
  continue;
9183
9788
  const name = this.#getPropertyName(prop.name);
9184
9789
  if (!name)
@@ -9187,13 +9792,13 @@ class FontOptimizer {
9187
9792
  }
9188
9793
  return obj;
9189
9794
  }
9190
- if (ts6.isAsExpression(node) || ts6.isSatisfiesExpression(node) || ts6.isParenthesizedExpression(node)) {
9795
+ if (ts7.isAsExpression(node) || ts7.isSatisfiesExpression(node) || ts7.isParenthesizedExpression(node)) {
9191
9796
  return this.#literalToValue(node.expression);
9192
9797
  }
9193
9798
  return;
9194
9799
  }
9195
9800
  #getPropertyName(name) {
9196
- if (ts6.isIdentifier(name) || ts6.isStringLiteral(name) || ts6.isNumericLiteral(name))
9801
+ if (ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
9197
9802
  return name.text;
9198
9803
  return null;
9199
9804
  }
@@ -12663,10 +13268,12 @@ var NODE_NATIVE_MODULE_SET = new Set([
12663
13268
  ]);
12664
13269
  // pkgs/@akanjs/devkit/getCredentials.ts
12665
13270
  import yaml from "js-yaml";
13271
+ // pkgs/@akanjs/devkit/getModelFileData.ts
13272
+ import { capitalize as capitalize8 } from "akanjs/common";
12666
13273
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
12667
13274
  import { readFileSync as readFileSync4, realpathSync } from "fs";
12668
13275
  import ora2 from "ora";
12669
- import * as ts7 from "typescript";
13276
+ import * as ts8 from "typescript";
12670
13277
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
12671
13278
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
12672
13279
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -12699,10 +13306,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
12699
13306
  return importSpecifiers;
12700
13307
  };
12701
13308
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
12702
- const configFile = ts7.readConfigFile(tsConfigPath, (path40) => {
12703
- return ts7.sys.readFile(path40);
13309
+ const configFile = ts8.readConfigFile(tsConfigPath, (path40) => {
13310
+ return ts8.sys.readFile(path40);
12704
13311
  });
12705
- return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13312
+ return ts8.parseJsonConfigFileContent(configFile.config, ts8.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
12706
13313
  };
12707
13314
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
12708
13315
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -12717,7 +13324,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
12717
13324
  for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
12718
13325
  if (!importPath.startsWith("."))
12719
13326
  continue;
12720
- 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;
12721
13328
  if (resolved && !allFilesToAnalyze.has(resolved)) {
12722
13329
  allFilesToAnalyze.add(resolved);
12723
13330
  collectImported(resolved);
@@ -12734,7 +13341,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
12734
13341
  var createTsProgram = (filePaths, options) => {
12735
13342
  const spinner = ora2("Creating TypeScript program for all files...");
12736
13343
  spinner.start();
12737
- const program2 = ts7.createProgram(Array.from(filePaths), options);
13344
+ const program2 = ts8.createProgram(Array.from(filePaths), options);
12738
13345
  const checker = program2.getTypeChecker();
12739
13346
  spinner.succeed("TypeScript program created.");
12740
13347
  return {
@@ -12774,17 +13381,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
12774
13381
  function visit(node) {
12775
13382
  if (!source2)
12776
13383
  return;
12777
- if (ts7.isPropertyAccessExpression(node)) {
13384
+ if (ts8.isPropertyAccessExpression(node)) {
12778
13385
  const left = node.expression;
12779
13386
  const right = node.name;
12780
- const { line } = ts7.getLineAndCharacterOfPosition(source2, node.getStart());
12781
- 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},`))) {
12782
13389
  const symbol = getCachedSymbol(right);
12783
13390
  if (symbol?.declarations && symbol.declarations.length > 0) {
12784
13391
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
12785
13392
  const property = propertyMap.get(key);
12786
13393
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
12787
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts7.sys.getCurrentDirectory()}/`, "");
13394
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts8.sys.getCurrentDirectory()}/`, "");
12788
13395
  if (!symbolFilePath)
12789
13396
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
12790
13397
  if (property) {
@@ -12808,10 +13415,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
12808
13415
  }
12809
13416
  }
12810
13417
  }
12811
- } else if (ts7.isImportDeclaration(node) && ts7.isStringLiteral(node.moduleSpecifier)) {
13418
+ } else if (ts8.isImportDeclaration(node) && ts8.isStringLiteral(node.moduleSpecifier)) {
12812
13419
  const importPath = node.moduleSpecifier.text;
12813
13420
  if (importPath.startsWith(".")) {
12814
- 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;
12815
13422
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
12816
13423
  const property = propertyMap.get(moduleName);
12817
13424
  const isScalar = importPath.includes("_");
@@ -12826,7 +13433,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
12826
13433
  }
12827
13434
  }
12828
13435
  }
12829
- ts7.forEachChild(node, visit);
13436
+ ts8.forEachChild(node, visit);
12830
13437
  }
12831
13438
  visit(source2);
12832
13439
  }