@akanjs/devkit 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.
@@ -269,11 +269,11 @@ describe("getModelFileData", () => {
269
269
  ].join("\n"),
270
270
  );
271
271
  await write(
272
- path.join(root, "apps/demo/lib/post/post.Unit.tsx"),
272
+ path.join(root, "apps/demo/lib/post/Post.Unit.tsx"),
273
273
  "export default function Unit() { return null; }\n",
274
274
  );
275
275
  await write(
276
- path.join(root, "apps/demo/lib/post/post.View.tsx"),
276
+ path.join(root, "apps/demo/lib/post/Post.View.tsx"),
277
277
  "export default function View() { return null; }\n",
278
278
  );
279
279
 
package/executors.ts CHANGED
@@ -626,14 +626,14 @@ export class Executor {
626
626
  overwrite?: boolean;
627
627
  },
628
628
  dict: { [key: string]: string } = {},
629
- options: { [key: string]: any } = {},
629
+ options: { [key: string]: unknown } = {},
630
630
  ): Promise<FileContent | null> {
631
631
  if (targetPath.endsWith(".ts") || targetPath.endsWith(".tsx")) {
632
632
  const getContent = (await import(templatePath)) as {
633
633
  default: (
634
634
  scanInfo: AppInfo | LibInfo | null,
635
635
  dict: { [key: string]: string },
636
- options?: { [key: string]: any },
636
+ options?: { [key: string]: unknown },
637
637
  ) => Promise<string | null | { filename: string; content: string }>;
638
638
  };
639
639
  const result = await getContent.default(scanInfo ?? null, dict, options);
@@ -686,7 +686,7 @@ export class Executor {
686
686
  template: string;
687
687
  scanInfo?: AppInfo | LibInfo | null;
688
688
  dict?: { [key: string]: string };
689
- options?: { [key: string]: any };
689
+ options?: { [key: string]: unknown };
690
690
  overwrite?: boolean;
691
691
  }): Promise<FileContent[]> {
692
692
  const templateRoot = await this.#resolveTemplateRoot();
@@ -752,7 +752,7 @@ export class Executor {
752
752
  basePath: string;
753
753
  template: string;
754
754
  dict?: { [key: string]: string };
755
- options?: { [key: string]: any };
755
+ options?: { [key: string]: unknown };
756
756
  overwrite?: boolean;
757
757
  }): Promise<FileContent[]> {
758
758
  const dict = {
@@ -827,10 +827,10 @@ export class Executor {
827
827
  filePath: string,
828
828
  { fix = false, dryRun = false }: { fix?: boolean; dryRun?: boolean } = {},
829
829
  ): Promise<{
830
- results: any[]; // ESLint.LintResult[];
830
+ results: unknown[]; // ESLint.LintResult[];
831
831
  message: string;
832
- errors: any[]; // ESLintLinter.LintMessage[];
833
- warnings: any[]; // ESLintLinter.LintMessage[];
832
+ errors: unknown[]; // ESLintLinter.LintMessage[];
833
+ warnings: unknown[]; // ESLintLinter.LintMessage[];
834
834
  }> {
835
835
  const path = this.getPath(filePath);
836
836
  const linter = this.getLinter();
@@ -1225,40 +1225,44 @@ export class SysExecutor extends Executor {
1225
1225
  async getViewComponents() {
1226
1226
  const viewComponents = (await this.readdir("lib"))
1227
1227
  .filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts"))
1228
- .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.View.tsx`).exists());
1228
+ .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.View.tsx`).exists());
1229
1229
  return viewComponents;
1230
1230
  }
1231
1231
 
1232
1232
  async getUnitComponents() {
1233
1233
  const unitComponents = (await this.readdir("lib"))
1234
1234
  .filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts"))
1235
- .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`).exists());
1235
+ .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Unit.tsx`).exists());
1236
1236
  return unitComponents;
1237
1237
  }
1238
1238
  async getTemplateComponents() {
1239
1239
  const templateComponents = (await this.readdir("lib"))
1240
1240
  .filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts"))
1241
- .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`).exists());
1241
+ .filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Template.tsx`).exists());
1242
1242
  return templateComponents;
1243
1243
  }
1244
1244
 
1245
1245
  async getViewsSourceCode() {
1246
1246
  const viewComponents = await this.getViewComponents();
1247
1247
  return Promise.all(
1248
- viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${viewComponent}.View.tsx`)),
1248
+ viewComponents.map((viewComponent) =>
1249
+ this.getLocalFile(`lib/${viewComponent}/${capitalize(viewComponent)}.View.tsx`),
1250
+ ),
1249
1251
  );
1250
1252
  }
1251
1253
  async getUnitsSourceCode() {
1252
1254
  const unitComponents = await this.getUnitComponents();
1253
1255
  return Promise.all(
1254
- unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${unitComponent}.Unit.tsx`)),
1256
+ unitComponents.map((unitComponent) =>
1257
+ this.getLocalFile(`lib/${unitComponent}/${capitalize(unitComponent)}.Unit.tsx`),
1258
+ ),
1255
1259
  );
1256
1260
  }
1257
1261
  async getTemplatesSourceCode() {
1258
1262
  const templateComponents = await this.getTemplateComponents();
1259
1263
  return Promise.all(
1260
1264
  templateComponents.map((templateComponent) =>
1261
- this.getLocalFile(`lib/${templateComponent}/${templateComponent}.Template.tsx`),
1265
+ this.getLocalFile(`lib/${templateComponent}/${capitalize(templateComponent)}.Template.tsx`),
1262
1266
  ),
1263
1267
  );
1264
1268
  }
@@ -1,3 +1,5 @@
1
+ import { capitalize } from "akanjs/common";
2
+
1
3
  interface ModelFileData {
2
4
  moduleType: "lib" | "app";
3
5
  moduleName: string;
@@ -16,9 +18,10 @@ interface ModelFileData {
16
18
  export const getModelFileData = async (modulePath: string, modelName: string): Promise<ModelFileData> => {
17
19
  const moduleType = modulePath.startsWith("apps") ? "app" : "lib";
18
20
  const moduleName = modulePath.split("/")[1] ?? "";
21
+ const modelComponentName = capitalize(modelName);
19
22
  const constantFilePath = `${modulePath}/lib/${modelName}/${modelName}.constant.ts`;
20
- const unitFilePath = `${modulePath}/lib/${modelName}/${modelName}.Unit.tsx`;
21
- const viewFilePath = `${modulePath}/lib/${modelName}/${modelName}.View.tsx`;
23
+ const unitFilePath = `${modulePath}/lib/${modelName}/${modelComponentName}.Unit.tsx`;
24
+ const viewFilePath = `${modulePath}/lib/${modelName}/${modelComponentName}.View.tsx`;
22
25
  const [constantFileStr, unitFileStr, viewFileStr] = await Promise.all([
23
26
  Bun.file(constantFilePath).text(),
24
27
  Bun.file(unitFilePath).text(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/devkit",
3
- "version": "2.3.9-rc.4",
3
+ "version": "2.3.9-rc.6",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -32,7 +32,7 @@
32
32
  "@langchain/openai": "^1.4.6",
33
33
  "@tailwindcss/node": "^4.3.0",
34
34
  "@trapezedev/project": "^7.1.4",
35
- "akanjs": "2.3.9-rc.4",
35
+ "akanjs": "2.3.9-rc.6",
36
36
  "chalk": "^5.6.2",
37
37
  "commander": "^14.0.3",
38
38
  "daisyui": "5.5.23",
@@ -28,6 +28,7 @@ export const createWorkflowApplyReport = ({
28
28
  recommendedValidationCommands,
29
29
  commands = [],
30
30
  diagnostics = [],
31
+ postApplyChecks = [],
31
32
  recommendations = [],
32
33
  nextActions = [],
33
34
  plan,
@@ -41,14 +42,21 @@ export const createWorkflowApplyReport = ({
41
42
  | "appliedCommands"
42
43
  | "recommendedValidationCommands"
43
44
  | "commands"
45
+ | "postApplyChecks"
44
46
  | "recommendations"
45
47
  > & {
46
48
  appliedCommands?: WorkflowApplyCommand[];
47
49
  recommendedValidationCommands?: WorkflowApplyCommand[];
48
50
  commands?: WorkflowApplyCommand[];
51
+ postApplyChecks?: WorkflowApplyReport["postApplyChecks"];
49
52
  recommendations?: WorkflowApplyReport["recommendations"];
50
53
  }): WorkflowApplyReport => {
51
54
  const validationCommands = recommendedValidationCommands ?? commands;
55
+ const orderedNextActions = uniqueBy(nextActions, (action) => action.command).sort((left, right) => {
56
+ const leftRepair = left.command.startsWith("akan workflow explain") ? 0 : 1;
57
+ const rightRepair = right.command.startsWith("akan workflow explain") ? 0 : 1;
58
+ return leftRepair - rightRepair;
59
+ });
52
60
  return {
53
61
  schemaVersion: 1,
54
62
  workflow,
@@ -60,8 +68,9 @@ export const createWorkflowApplyReport = ({
60
68
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
61
69
  commands: uniqueBy(validationCommands, (command) => command.command),
62
70
  diagnostics,
71
+ postApplyChecks,
63
72
  recommendations: uniqueBy(recommendations, (recommendation) => `${recommendation.kind}:${recommendation.code}`),
64
- nextActions: uniqueBy(nextActions, (action) => action.command),
73
+ nextActions: orderedNextActions.slice(0, 3),
65
74
  plan,
66
75
  };
67
76
  };
@@ -186,6 +195,15 @@ const statusForScope = (
186
195
  return hasScopeFailure(scopes, expectedScope, diagnostics) ? "failed" : "passed";
187
196
  };
188
197
 
198
+ const statusForValidationKind = (
199
+ commands: readonly WorkflowValidationCommandResult[],
200
+ kind: WorkflowValidationCommandResult["kind"],
201
+ ): WorkflowValidationStatus => {
202
+ const matching = commands.filter((command) => command.kind === kind);
203
+ if (matching.length === 0) return "unknown";
204
+ return matching.some((command) => command.status === "failed") ? "failed" : "passed";
205
+ };
206
+
189
207
  const createKnownBlockers = (
190
208
  commands: readonly WorkflowValidationCommandResult[],
191
209
  diagnostics: readonly WorkflowDiagnostic[],
@@ -251,7 +269,17 @@ const createValidationStatuses = (
251
269
  : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed"
252
270
  ? "failed"
253
271
  : "passed";
254
- return { sourceStatus, workspaceStatus, overallStatus };
272
+ return {
273
+ sourceStatus,
274
+ workspaceStatus,
275
+ overallStatus,
276
+ summary: {
277
+ sourceChange: sourceStatus,
278
+ generatedSync: statusForValidationKind(commands, "sync"),
279
+ workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
280
+ environment: statusForScope(commands, diagnostics, scopes, "environment"),
281
+ },
282
+ };
255
283
  };
256
284
 
257
285
  export const createWorkflowValidationRunReport = async ({
@@ -1,7 +1,9 @@
1
1
  import { capitalize } from "akanjs/common";
2
+ import ts from "typescript";
2
3
  import type { Sys, Workspace } from "../commandDecorators";
3
4
  import { AppExecutor, LibExecutor } from "../executors";
4
5
  import { createWorkflowApplyReport, workflowCommandsForPlan } from "./artifacts";
6
+ import { moduleSourcePaths } from "./source";
5
7
  import type {
6
8
  PrimitiveChangedFile,
7
9
  PrimitiveGeneratedFile,
@@ -11,11 +13,14 @@ import type {
11
13
  WorkflowDiagnostic,
12
14
  WorkflowInputValue,
13
15
  WorkflowPlan,
16
+ WorkflowPostApplyCheck,
14
17
  WorkflowPrimitiveOperations,
18
+ WorkflowRecommendation,
15
19
  WorkflowStep,
16
20
  WorkflowStepRegistry,
17
21
  WorkflowStepResult,
18
22
  } from "./types";
23
+ import { addFieldUiPolicyForType } from "./uiPolicy";
19
24
 
20
25
  export const workflowStepKey = (workflow: string, stepId: string) => `${workflow}:${stepId}`;
21
26
 
@@ -31,6 +36,105 @@ export const primitiveReportToWorkflowStepResult = (report: PrimitiveWriteReport
31
36
  const workflowStringInput = (value: WorkflowInputValue | undefined) => (typeof value === "string" ? value : null);
32
37
  const workflowStringListInput = (value: WorkflowInputValue | undefined) =>
33
38
  Array.isArray(value) ? value.join(",") : null;
39
+ const workflowStringArrayInput = (value: WorkflowInputValue | undefined) => (Array.isArray(value) ? value : null);
40
+ const workflowBooleanInput = (value: WorkflowInputValue | undefined) => (typeof value === "boolean" ? value : null);
41
+
42
+ const postApplyDiagnostic = (code: string, message: string, target: string): WorkflowDiagnostic => ({
43
+ severity: "error",
44
+ code,
45
+ message,
46
+ failureScope: "source-change",
47
+ context: { target },
48
+ });
49
+
50
+ const sourceKindForPath = (filePath: string) => {
51
+ if (filePath.endsWith(".tsx")) return ts.ScriptKind.TSX;
52
+ if (filePath.endsWith(".ts")) return ts.ScriptKind.TS;
53
+ return null;
54
+ };
55
+
56
+ const checkPathCasing = async (workspace: Workspace, filePath: string) => {
57
+ const segments = filePath.split("/").filter(Boolean);
58
+ let current = ".";
59
+ for (const segment of segments) {
60
+ const entries = await workspace.readdir(current);
61
+ if (entries.includes(segment)) {
62
+ current = current === "." ? segment : `${current}/${segment}`;
63
+ continue;
64
+ }
65
+ const caseInsensitiveMatch = entries.find((entry) => entry.toLowerCase() === segment.toLowerCase());
66
+ return caseInsensitiveMatch
67
+ ? {
68
+ code: "workflow-path-casing-mismatch",
69
+ message: `Reported path segment "${segment}" does not match actual casing "${caseInsensitiveMatch}" in ${filePath}.`,
70
+ }
71
+ : {
72
+ code: "workflow-path-missing",
73
+ message: `Reported path does not exist: ${filePath}.`,
74
+ };
75
+ }
76
+ return null;
77
+ };
78
+
79
+ const checkTypeScriptSyntax = async (workspace: Workspace, filePath: string) => {
80
+ const scriptKind = sourceKindForPath(filePath);
81
+ if (!scriptKind) return null;
82
+ const content = await workspace.readFile(filePath);
83
+ const source = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKind);
84
+ const diagnostic = source.parseDiagnostics[0];
85
+ if (!diagnostic) return null;
86
+ const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
87
+ const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
88
+ return {
89
+ code: "workflow-post-apply-syntax-error",
90
+ message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts.flattenDiagnosticMessageText(
91
+ diagnostic.messageText,
92
+ " ",
93
+ )}`,
94
+ };
95
+ };
96
+
97
+ const checkChangedFile = async (workspace: Workspace, file: PrimitiveChangedFile): Promise<WorkflowStepResult> => {
98
+ if (file.action === "remove") return { postApplyChecks: [] };
99
+ const diagnostics: WorkflowDiagnostic[] = [];
100
+ const checks: WorkflowPostApplyCheck[] = [];
101
+ const pathIssue = await checkPathCasing(workspace, file.path);
102
+ if (pathIssue) {
103
+ diagnostics.push(postApplyDiagnostic(pathIssue.code, pathIssue.message, file.path));
104
+ checks.push({ ...pathIssue, target: file.path, status: "failed" });
105
+ return { diagnostics, postApplyChecks: checks };
106
+ }
107
+ const syntaxIssue = await checkTypeScriptSyntax(workspace, file.path);
108
+ if (syntaxIssue) {
109
+ diagnostics.push(postApplyDiagnostic(syntaxIssue.code, syntaxIssue.message, file.path));
110
+ checks.push({ ...syntaxIssue, target: file.path, status: "failed" });
111
+ return { diagnostics, postApplyChecks: checks };
112
+ }
113
+ checks.push({
114
+ code: "workflow-post-apply-file-valid",
115
+ target: file.path,
116
+ status: "passed",
117
+ message: "Changed file exists with exact casing and parses as source when applicable.",
118
+ });
119
+ return { postApplyChecks: checks };
120
+ };
121
+
122
+ const checkRecommendationPath = async (
123
+ workspace: Workspace,
124
+ recommendation: WorkflowRecommendation,
125
+ ): Promise<WorkflowDiagnostic | null> => {
126
+ if (!recommendation.target || recommendation.target.includes("*") || recommendation.target.startsWith("<"))
127
+ return null;
128
+ const pathIssue = await checkPathCasing(workspace, recommendation.target);
129
+ if (!pathIssue) return null;
130
+ return {
131
+ severity: "warning",
132
+ code: "workflow-recommendation-path-unverified",
133
+ message: `${pathIssue.message} Recommendation "${recommendation.code}" should not be treated as an exact file target until the path is corrected.`,
134
+ failureScope: "source-change",
135
+ context: { target: recommendation.target },
136
+ };
137
+ };
34
138
 
35
139
  const resolveWorkflowSys = async (workspace: Workspace, target: string | null): Promise<Sys | null> => {
36
140
  if (!target) return null;
@@ -66,22 +170,22 @@ const addFieldUiSurfaceInspection = (plan: WorkflowPlan): WorkflowStepResult =>
66
170
  const module = workflowStringInput(plan.inputs.module) ?? "<module>";
67
171
  const field = workflowStringInput(plan.inputs.field) ?? "<field>";
68
172
  const typeName = workflowStringInput(plan.inputs.type);
69
- const isNumeric = typeName === "Int" || typeName === "Float" || typeName === "integer" || typeName === "float";
173
+ const policy = addFieldUiPolicyForType(typeName ?? "String");
174
+ const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
175
+ const templateRequested = surfaces?.includes("template") ?? false;
70
176
  const moduleClassName = capitalize(module);
71
- const target = `${app ? `apps/${app}` : "*"}/lib/${module}/${moduleClassName}.Template.tsx`;
177
+ const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
72
178
  return {
73
179
  recommendations: [
74
180
  {
75
181
  code: "add-field-ui-surface-review",
76
182
  kind: "manual-action",
77
183
  target,
78
- action: isNumeric
79
- ? `Review ${moduleClassName} Template/Unit/View/Store surfaces before adding ${field}; confirm the local Field.Text numeric parser/formatter, validation rule, and dictionary label pattern.`
80
- : `Add ${field} to ${moduleClassName} UI surfaces only when the local Field.* pattern is clear.`,
184
+ action: templateRequested
185
+ ? `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.`
186
+ : `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.`,
81
187
  confidence: "medium",
82
- message: isNumeric
83
- ? `No UI file was modified automatically because a safe numeric input component pattern is not yet detected for ${module}.${field}.`
84
- : `Review Template/Unit/View/Store surfaces for ${module}.${field}; no UI file was modified automatically.`,
188
+ message: `Review UI surfaces for ${module}.${field}; recommended component is ${policy.component}, with manual reasons and candidate positions in action.`,
85
189
  },
86
190
  ],
87
191
  nextActions: [
@@ -149,6 +253,8 @@ export const createWorkflowStepRegistry = ({
149
253
  field: workflowStringInput(plan.inputs.field),
150
254
  values: workflowStringListInput(plan.inputs.values),
151
255
  defaultValue: workflowStringInput(plan.inputs.default),
256
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
257
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight),
152
258
  }),
153
259
  );
154
260
  }
@@ -159,6 +265,8 @@ export const createWorkflowStepRegistry = ({
159
265
  field: workflowStringInput(plan.inputs.field),
160
266
  type: workflowStringInput(plan.inputs.type),
161
267
  defaultValue: workflowStringInput(plan.inputs.default),
268
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
269
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight),
162
270
  }),
163
271
  );
164
272
  },
@@ -189,13 +297,17 @@ export const createWorkflowStepCommandResult = (
189
297
  });
190
298
 
191
299
  export class WorkflowExecutor {
192
- constructor(private readonly registry: WorkflowStepRegistry) {}
300
+ constructor(
301
+ private readonly registry: WorkflowStepRegistry,
302
+ private readonly workspace?: Workspace,
303
+ ) {}
193
304
 
194
305
  async apply(plan: WorkflowPlan) {
195
306
  const changedFiles: PrimitiveChangedFile[] = [];
196
307
  const generatedFiles: PrimitiveGeneratedFile[] = [];
197
308
  const recommendedValidationCommands: WorkflowApplyCommand[] = [];
198
309
  const diagnostics: WorkflowDiagnostic[] = [...plan.diagnostics];
310
+ const postApplyChecks: WorkflowPostApplyCheck[] = [];
199
311
  const recommendations = [...plan.recommendations];
200
312
  const nextActions: PrimitiveNextAction[] = [];
201
313
 
@@ -207,6 +319,7 @@ export class WorkflowExecutor {
207
319
  generatedFiles,
208
320
  recommendedValidationCommands,
209
321
  diagnostics,
322
+ postApplyChecks,
210
323
  recommendations,
211
324
  nextActions,
212
325
  plan,
@@ -243,6 +356,20 @@ export class WorkflowExecutor {
243
356
  if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) break;
244
357
  }
245
358
 
359
+ if (this.workspace && !diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
360
+ for (const file of changedFiles) {
361
+ const result = await checkChangedFile(this.workspace, file);
362
+ postApplyChecks.push(...(result.postApplyChecks ?? []));
363
+ diagnostics.push(...(result.diagnostics ?? []));
364
+ }
365
+ const recommendationDiagnostics = await Promise.all(
366
+ recommendations.map((recommendation) => checkRecommendationPath(this.workspace as Workspace, recommendation)),
367
+ );
368
+ diagnostics.push(
369
+ ...recommendationDiagnostics.filter((diagnostic): diagnostic is WorkflowDiagnostic => !!diagnostic),
370
+ );
371
+ }
372
+
246
373
  return createWorkflowApplyReport({
247
374
  workflow: plan.workflow,
248
375
  mode: "apply",
@@ -250,6 +377,7 @@ export class WorkflowExecutor {
250
377
  generatedFiles,
251
378
  recommendedValidationCommands,
252
379
  diagnostics,
380
+ postApplyChecks,
253
381
  recommendations,
254
382
  nextActions,
255
383
  plan,
package/workflow/index.ts CHANGED
@@ -5,4 +5,5 @@ export * from "./primitive";
5
5
  export * from "./render";
6
6
  export * from "./source";
7
7
  export * from "./types";
8
+ export * from "./uiPolicy";
8
9
  export * from "./utils";