@akanjs/cli 2.3.9-rc.0 → 2.3.9-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/incrementalBuilder.proc.js +855 -14
  2. package/index.js +3760 -1485
  3. package/package.json +2 -2
  4. package/templates/appSample/common/formatters.ts +1 -1
  5. package/templates/appSample/common/validators.ts +1 -1
  6. package/templates/appSample/lib/_noti/noti.dictionary.ts +1 -1
  7. package/templates/appSample/lib/_noti/noti.service.ts +1 -1
  8. package/templates/appSample/lib/_noti/noti.signal.ts +1 -1
  9. package/templates/appSample/lib/_noti/noti.store.ts +1 -1
  10. package/templates/appSample/lib/task/task.abstract.ts +1 -1
  11. package/templates/appSample/lib/task/task.constant.ts +1 -1
  12. package/templates/appSample/lib/task/task.dictionary.ts +1 -1
  13. package/templates/appSample/lib/task/task.document.ts +3 -3
  14. package/templates/appSample/lib/task/task.service.ts +2 -2
  15. package/templates/appSample/lib/task/task.signal.spec.ts +70 -0
  16. package/templates/appSample/lib/task/task.signal.test.ts +20 -0
  17. package/templates/appSample/lib/task/task.signal.ts +2 -2
  18. package/templates/appSample/lib/task/task.store.ts +2 -2
  19. package/templates/appSample/srvkit/AuthGuard.ts +1 -1
  20. package/templates/appSample/srvkit/SessionInternalArg.ts +1 -1
  21. package/templates/appSample/ui/GlobalLoading.tsx +1 -1
  22. package/templates/appSample/ui/QuantityControl.tsx +1 -1
  23. package/templates/appSample/webkit/useDebounce.ts +1 -1
  24. package/templates/lib/useClient.ts +1 -4
  25. package/templates/module/__Model__.Unit.tsx +1 -4
  26. package/templates/workspaceRoot/.cursor/rules/{akan-scan-conventions.mdc.template → akan-sync-conventions.mdc.template} +3 -3
  27. package/templates/workspaceRoot/.cursor/rules/akan.mdc.template +5 -0
  28. package/templates/workspaceRoot/AGENTS.md.template +77 -58
  29. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +51 -0
  30. package/templates/workspaceRoot/docs/GENERATED.md.template +54 -0
  31. package/templates/workspaceRoot/package.json.template +9 -0
  32. package/templates/workspaceRoot/Untitled +0 -1
@@ -4777,17 +4777,91 @@ class AkanAppHost {
4777
4777
  import { readdir } from "fs/promises";
4778
4778
  import path10 from "path";
4779
4779
  import { capitalize as capitalize2 } from "akanjs/common";
4780
+ var resourceList = [
4781
+ { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
4782
+ { uri: "akan://guidelines/framework", name: "Framework guideline", mimeType: "text/markdown" },
4783
+ { uri: "akan://guidelines/modelSignal", name: "Model signal guideline", mimeType: "text/markdown" },
4784
+ { uri: "akan://workspace/summary", name: "Workspace summary", mimeType: "application/json" },
4785
+ { uri: "akan://workspace/apps", name: "Workspace apps", mimeType: "application/json" },
4786
+ { uri: "akan://workspace/modules", name: "Workspace modules", mimeType: "application/json" }
4787
+ ];
4788
+ var cursorMcpConfigPath = ".cursor/mcp.json";
4789
+ var cursorWorkspaceFolder = "$" + "{workspaceFolder}";
4790
+ var createAkanCursorMcpServer = (mode = "readonly") => ({
4791
+ type: "stdio",
4792
+ command: "bash",
4793
+ args: ["-lc", `cd "${cursorWorkspaceFolder}" && akan mcp --mode ${mode}`]
4794
+ });
4795
+ var akanCursorMcpServer = createAkanCursorMcpServer();
4796
+ var renderDoctorText = (result) => {
4797
+ const lines = [`Akan doctor status: ${result.status}`];
4798
+ if (result.diagnostics.length === 0) {
4799
+ lines.push("", "No Akan workspace diagnostics found.");
4800
+ } else {
4801
+ lines.push("", ...result.diagnostics.map((diagnostic) => [
4802
+ `[${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`,
4803
+ diagnostic.path ? ` ${diagnostic.path}` : ""
4804
+ ].filter(Boolean).join(`
4805
+ `)));
4806
+ }
4807
+ lines.push("", "Generated file freshness:", result.generatedFilesFreshness.message, `Refresh: ${result.generatedFilesFreshness.refreshCommand}`, "", "Repair actions:", ...result.repairActions.length ? result.repairActions.map((action) => `- ${action.command}`) : ["- none"], "", "Validation commands:", ...result.validationCommands.map((command) => `- ${command}`));
4808
+ return `${lines.join(`
4809
+ `)}
4810
+ `;
4811
+ };
4780
4812
  var generatedFiles = [
4781
- "cnst.ts",
4782
- "db.ts",
4783
- "dict.ts",
4784
- "option.ts",
4785
- "sig.ts",
4786
- "srv.ts",
4787
- "st.ts",
4788
- "useClient.ts",
4789
- "useServer.ts"
4813
+ "apps/*/client.ts",
4814
+ "apps/*/server.ts",
4815
+ "*/lib/cnst.ts",
4816
+ "*/lib/db.ts",
4817
+ "*/lib/dict.ts",
4818
+ "*/lib/option.ts",
4819
+ "*/lib/sig.ts",
4820
+ "*/lib/srv.ts",
4821
+ "*/lib/st.ts",
4822
+ "*/lib/useClient.ts",
4823
+ "*/lib/useServer.ts",
4824
+ "*/lib/**/index.ts",
4825
+ "*/ui/index.ts",
4826
+ "*/webkit/index.ts",
4827
+ "*/srvkit/index.ts",
4828
+ "*/common/index.ts"
4829
+ ];
4830
+ var validationCommands = [
4831
+ "akan sync <app-or-lib>",
4832
+ "akan lint <app-or-lib-or-pkg>",
4833
+ "akan typecheck <app-name>",
4834
+ "akan test <app-or-lib-or-pkg>",
4835
+ "akan build <app-name>",
4836
+ "akan doctor --strict --format json"
4790
4837
  ];
4838
+ var generatedFilesFreshness = {
4839
+ status: "unknown",
4840
+ message: "Run sync before validation so generated Akan files match the current source conventions.",
4841
+ refreshCommand: "akan sync <app-or-lib>",
4842
+ verifyingCommands: ["akan lint <app-or-lib-or-pkg>", "akan build <app-name>"]
4843
+ };
4844
+ var repairAction = (kind, command, reason, safeToRun) => ({
4845
+ kind,
4846
+ command,
4847
+ reason,
4848
+ safeToRun
4849
+ });
4850
+ var moduleShapeFiles = (module) => {
4851
+ if (module.kind === "service") {
4852
+ return [`${module.name}.dictionary.ts`, `${module.name}.service.ts`, `${module.name}.signal.ts`];
4853
+ }
4854
+ if (module.kind === "scalar")
4855
+ return [`${module.name}.constant.ts`, `${module.name}.dictionary.ts`];
4856
+ return [
4857
+ `${module.name}.constant.ts`,
4858
+ `${module.name}.dictionary.ts`,
4859
+ `${module.name}.service.ts`,
4860
+ `${module.name}.store.ts`,
4861
+ `${module.name}.signal.ts`
4862
+ ];
4863
+ };
4864
+ var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
4791
4865
  var appRootAllowFiles = new Set([
4792
4866
  "akan.app.json",
4793
4867
  "akan.config.ts",
@@ -4945,39 +5019,95 @@ class AkanContextAnalyzer {
4945
5019
  libs,
4946
5020
  pkgs,
4947
5021
  generatedFiles,
4948
- validationCommands: ["akan lint <app-or-lib-or-pkg>", "akan build <app-name>", "akan start <app-name>"]
5022
+ validationCommands
4949
5023
  };
4950
5024
  }
4951
5025
  static async doctor(workspace, { strict = false } = {}) {
4952
5026
  const context = await AkanContextAnalyzer.analyze(workspace);
4953
5027
  const diagnostics = [];
5028
+ const repairActions = [
5029
+ repairAction("generated", "akan repair generated --app <app-or-lib>", "Refresh generated Akan files.", true),
5030
+ repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
5031
+ ];
4954
5032
  for (const app of context.apps) {
4955
5033
  const appPath = path10.join(workspace.workspaceRoot, app.path);
4956
5034
  for (const entry of await safeReadDir(appPath)) {
4957
5035
  const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
4958
5036
  if (!allowed) {
5037
+ const action = repairAction("module-shape", `akan repair module-shape --app ${app.name}`, "Review app root shape and remove or move the unknown entry.", false);
4959
5038
  diagnostics.push({
4960
- severity: "warning",
5039
+ severity: "error",
4961
5040
  code: "app-root-unknown-entry",
4962
5041
  path: `${app.path}/${entry.name}`,
4963
- message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in app root: ${app.path}/${entry.name}`
5042
+ message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in app root: ${app.path}/${entry.name}`,
5043
+ repairActions: [action]
4964
5044
  });
5045
+ repairActions.push(action);
4965
5046
  }
4966
5047
  }
4967
5048
  }
4968
5049
  for (const sys2 of [...context.apps, ...context.libs]) {
4969
5050
  for (const module of sys2.modules) {
4970
5051
  if (!module.abstract.exists) {
5052
+ const action = repairAction("module-shape", `akan repair module-shape --app ${sys2.name} --module ${module.name}`, "Create the missing module abstract or inspect required source files.", false);
4971
5053
  diagnostics.push({
4972
5054
  severity: strict ? "error" : "warning",
4973
5055
  code: "module-abstract-missing",
4974
5056
  path: module.abstract.path,
4975
- message: `${capitalize2(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`
5057
+ message: `${capitalize2(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`,
5058
+ repairActions: [action]
5059
+ });
5060
+ repairActions.push(action);
5061
+ }
5062
+ const missingFiles = moduleShapeFiles(module).filter((filename) => !module.files.includes(filename));
5063
+ if (missingFiles.length) {
5064
+ const action = repairAction("module-shape", `akan repair module-shape --app ${sys2.name} --module ${module.name}`, "Review missing required module source files.", false);
5065
+ diagnostics.push({
5066
+ severity: "error",
5067
+ code: "module-shape-invalid",
5068
+ path: module.path,
5069
+ message: `${capitalize2(module.kind)} module ${sys2.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
5070
+ repairActions: [action]
4976
5071
  });
5072
+ repairActions.push(action);
5073
+ }
5074
+ if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
5075
+ const constantPath = path10.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
5076
+ const dictionaryPath = path10.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
5077
+ const [constantContent, dictionaryContent] = await Promise.all([
5078
+ safeReadText(constantPath),
5079
+ safeReadText(dictionaryPath)
5080
+ ]);
5081
+ if (constantContent && dictionaryContent) {
5082
+ for (const fieldName of constantFieldNames(constantContent)) {
5083
+ if (new RegExp(`\\b${fieldName}\\s*:`).test(dictionaryContent))
5084
+ continue;
5085
+ const action = repairAction("dictionary", `akan repair dictionary --app ${sys2.name} --module ${module.name}`, "Add missing dictionary labels for source constant fields.", false);
5086
+ diagnostics.push({
5087
+ severity: "warning",
5088
+ code: "dictionary-label-missing",
5089
+ path: `${module.path}/${module.name}.dictionary.ts`,
5090
+ message: `Dictionary labels for ${sys2.name}:${module.name}.${fieldName} were not found.`,
5091
+ repairActions: [action]
5092
+ });
5093
+ repairActions.push(action);
5094
+ }
5095
+ }
4977
5096
  }
4978
5097
  }
4979
5098
  }
4980
- return { schemaVersion: 1, strict, diagnostics };
5099
+ return {
5100
+ schemaVersion: 1,
5101
+ repoName: context.repoName,
5102
+ root: context.root,
5103
+ strict,
5104
+ status: diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "passed",
5105
+ diagnostics,
5106
+ generatedFiles: context.generatedFiles,
5107
+ generatedFilesFreshness,
5108
+ validationCommands: context.validationCommands,
5109
+ repairActions
5110
+ };
4981
5111
  }
4982
5112
  static findModules(context, moduleName) {
4983
5113
  const modules = [...context.apps, ...context.libs].flatMap((sys2) => sys2.modules);
@@ -11115,6 +11245,8 @@ var getInternalArgumentValue = async (argMeta, value, workspace) => {
11115
11245
  } else if (sysType === "app") {
11116
11246
  if (value && appNames.includes(value))
11117
11247
  return AppExecutor.from(workspace, value);
11248
+ if (!value && appNames.length === 1 && appNames[0])
11249
+ return AppExecutor.from(workspace, appNames[0]);
11118
11250
  const appName = await select3({ message: `Select the ${sysType} name`, choices: appNames });
11119
11251
  return AppExecutor.from(workspace, appName);
11120
11252
  } else if (sysType === "lib") {
@@ -11690,6 +11822,715 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
11690
11822
  import { useEffect as useEffect3, useState as useState3 } from "react";
11691
11823
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
11692
11824
  "use client";
11825
+ // pkgs/@akanjs/devkit/workflow/index.ts
11826
+ var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
11827
+ ` : ""}`;
11828
+ var surfaceModes = new Set(["infer", "include", "skip"]);
11829
+ var parseStringList = (value) => {
11830
+ if (Array.isArray(value)) {
11831
+ const values = value.filter((item) => typeof item === "string" && item.trim().length > 0);
11832
+ return values.length === value.length ? values : null;
11833
+ }
11834
+ if (typeof value !== "string")
11835
+ return null;
11836
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
11837
+ };
11838
+ var normalizeInputValue = (name, spec, value) => {
11839
+ if (spec.type === "string")
11840
+ return typeof value === "string" && value.length > 0 ? value : null;
11841
+ if (spec.type === "string-list") {
11842
+ const values = parseStringList(value);
11843
+ return values && values.length > 0 ? values : null;
11844
+ }
11845
+ if (typeof value === "string" && surfaceModes.has(value))
11846
+ return value;
11847
+ throw new Error(`Unsupported workflow input value for ${name}`);
11848
+ };
11849
+ var listWorkflowSpecs = (specs) => [...specs].sort((a, b) => a.name.localeCompare(b.name));
11850
+ var getWorkflowSpec = (specs, name) => specs.find((spec) => spec.name === name) ?? null;
11851
+ var compactWorkflowInputs = (inputs) => Object.fromEntries(Object.entries(inputs).filter(([, value]) => value !== null && value !== ""));
11852
+ var createWorkflowPlan = (spec, rawInputs) => {
11853
+ const inputs = {};
11854
+ const diagnostics = [];
11855
+ for (const [name, inputSpec] of Object.entries(spec.inputs)) {
11856
+ const rawValue = rawInputs[name];
11857
+ if (rawValue === undefined || rawValue === null || rawValue === "") {
11858
+ if (inputSpec.required) {
11859
+ diagnostics.push({
11860
+ severity: "error",
11861
+ code: "workflow-input-missing",
11862
+ input: name,
11863
+ message: `Workflow ${spec.name} requires input "${name}".`
11864
+ });
11865
+ }
11866
+ continue;
11867
+ }
11868
+ const value = normalizeInputValue(name, inputSpec, rawValue);
11869
+ if (value === null) {
11870
+ diagnostics.push({
11871
+ severity: "error",
11872
+ code: "workflow-input-invalid",
11873
+ input: name,
11874
+ message: `Workflow ${spec.name} input "${name}" must be ${inputSpec.type}.`
11875
+ });
11876
+ continue;
11877
+ }
11878
+ if (inputSpec.allowedValues && typeof value === "string" && !inputSpec.allowedValues.includes(value)) {
11879
+ diagnostics.push({
11880
+ severity: "error",
11881
+ code: "workflow-input-not-allowed",
11882
+ input: name,
11883
+ message: `Workflow ${spec.name} input "${name}" must be one of: ${inputSpec.allowedValues.join(", ")}.`
11884
+ });
11885
+ continue;
11886
+ }
11887
+ inputs[name] = value;
11888
+ }
11889
+ return {
11890
+ schemaVersion: 1,
11891
+ workflow: spec.name,
11892
+ mode: "plan",
11893
+ inputs,
11894
+ optionalSurfaces: spec.optionalSurfaces ?? {},
11895
+ steps: spec.steps,
11896
+ predictedChanges: spec.predictedChanges,
11897
+ validation: spec.validation,
11898
+ diagnostics,
11899
+ requiresApproval: true
11900
+ };
11901
+ };
11902
+ var renderWorkflowList = (specs) => [
11903
+ "# Akan Workflows",
11904
+ "",
11905
+ ...specs.flatMap((spec) => [`- \`${spec.name}\`: ${spec.description}`, ` - When: ${spec.whenToUse}`]),
11906
+ ""
11907
+ ].join(`
11908
+ `);
11909
+ var renderWorkflowExplain = (spec) => [
11910
+ `# Workflow: ${spec.name}`,
11911
+ "",
11912
+ spec.description,
11913
+ "",
11914
+ "## When To Use",
11915
+ spec.whenToUse,
11916
+ "",
11917
+ "## Inputs",
11918
+ ...Object.entries(spec.inputs).map(([name, input4]) => `- \`${name}\`${input4.required ? " (required)" : ""}: ${input4.description}${input4.allowedValues ? ` Allowed: ${input4.allowedValues.join(", ")}.` : ""}`),
11919
+ "",
11920
+ "## Optional Surfaces",
11921
+ ...Object.entries(spec.optionalSurfaces ?? {}).map(([name, mode]) => `- \`${name}\`: ${mode}`),
11922
+ "",
11923
+ "## Steps",
11924
+ ...spec.steps.map((step, index) => `${index + 1}. \`${step.id}\` (${step.tool}): ${step.description}`),
11925
+ "",
11926
+ "## Validation",
11927
+ ...spec.validation.map((validation) => `- \`${validation.command}\`: ${validation.reason}`),
11928
+ ""
11929
+ ].join(`
11930
+ `);
11931
+ var renderWorkflowPlan = (plan) => [
11932
+ `# Workflow Plan: ${plan.workflow}`,
11933
+ "",
11934
+ `- Mode: ${plan.mode}`,
11935
+ `- Requires approval: ${plan.requiresApproval}`,
11936
+ "",
11937
+ "## Inputs",
11938
+ ...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
11939
+ "",
11940
+ "## Optional Surfaces",
11941
+ ...Object.entries(plan.optionalSurfaces).map(([name, mode]) => `- \`${name}\`: ${mode}`),
11942
+ "",
11943
+ "## Steps",
11944
+ ...plan.steps.map((step, index) => `${index + 1}. \`${step.id}\` (${step.tool}): ${step.description}`),
11945
+ "",
11946
+ "## Predicted Changes",
11947
+ ...plan.predictedChanges.map((change) => `- \`${change.action}\` ${change.target}: ${change.reason}`),
11948
+ "",
11949
+ "## Validation",
11950
+ ...plan.validation.map((validation) => `- \`${validation.command}\`: ${validation.reason}`),
11951
+ "",
11952
+ "## Diagnostics",
11953
+ ...plan.diagnostics.length ? plan.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
11954
+ ""
11955
+ ].join(`
11956
+ `);
11957
+ var workflowStatus = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "passed";
11958
+ var commandStatus = (commands) => commands.some((command3) => command3.status === "failed") ? "failed" : "passed";
11959
+ var uniqueBy = (values, key) => {
11960
+ const seen = new Set;
11961
+ return values.filter((value) => {
11962
+ const itemKey = key(value);
11963
+ if (seen.has(itemKey))
11964
+ return false;
11965
+ seen.add(itemKey);
11966
+ return true;
11967
+ });
11968
+ };
11969
+ var createWorkflowApplyReport = ({
11970
+ workflow,
11971
+ mode,
11972
+ changedFiles = [],
11973
+ generatedFiles: generatedFiles2 = [],
11974
+ commands = [],
11975
+ diagnostics = [],
11976
+ nextActions = [],
11977
+ plan
11978
+ }) => ({
11979
+ schemaVersion: 1,
11980
+ workflow,
11981
+ mode,
11982
+ status: workflowStatus(diagnostics),
11983
+ changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
11984
+ generatedFiles: uniqueBy(generatedFiles2, (file) => `${file.action}:${file.path}:${file.reason}`),
11985
+ commands: uniqueBy(commands, (command3) => command3.command),
11986
+ diagnostics,
11987
+ nextActions: uniqueBy(nextActions, (action) => action.command),
11988
+ plan
11989
+ });
11990
+ var resolveWorkflowCommand = (command3, plan) => {
11991
+ const target = typeof plan.inputs.app === "string" ? plan.inputs.app : "<app-or-lib>";
11992
+ return command3.replaceAll("<app-or-lib-or-pkg>", target).replaceAll("<app-or-lib>", target).replaceAll("<app-name>", target);
11993
+ };
11994
+ var workflowCommandsForPlan = (plan) => plan.validation.map((validation) => ({
11995
+ command: resolveWorkflowCommand(validation.command, plan),
11996
+ reason: validation.reason
11997
+ }));
11998
+ var workflowRunsDir = ".akan/workflows/runs";
11999
+ var createWorkflowRunId = (prefix = "run") => `${prefix}-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(36).slice(2, 8)}`;
12000
+ var getRunId = (artifact) => {
12001
+ if ("runId" in artifact)
12002
+ return artifact.runId;
12003
+ return createWorkflowRunId("mode" in artifact ? artifact.mode : artifact.kind);
12004
+ };
12005
+ var workflowRunArtifactPath = (runId) => `${workflowRunsDir}/${runId}.json`;
12006
+ var writeWorkflowRunArtifact = async (workspace, artifact) => {
12007
+ const runId = getRunId(artifact);
12008
+ const artifactPath = workflowRunArtifactPath(runId);
12009
+ await workspace.writeFile(artifactPath, jsonText(artifact));
12010
+ return { runId, path: artifactPath };
12011
+ };
12012
+ var readWorkflowRunArtifact = async (workspace, runId) => {
12013
+ const artifactPath = workflowRunArtifactPath(runId);
12014
+ if (!await workspace.exists(artifactPath))
12015
+ throw new Error(`Workflow run artifact does not exist: ${artifactPath}`);
12016
+ return await workspace.readJson(artifactPath);
12017
+ };
12018
+ var createWorkflowValidationRunReport = async ({
12019
+ runId = createWorkflowRunId("validation"),
12020
+ workflow,
12021
+ source,
12022
+ plan,
12023
+ commands,
12024
+ execute,
12025
+ diagnostics = [],
12026
+ repairActions = []
12027
+ }) => {
12028
+ const results = [];
12029
+ for (const command3 of commands) {
12030
+ results.push(await execute(command3));
12031
+ }
12032
+ const commandDiagnostics = results.flatMap((result) => result.status === "failed" ? [
12033
+ {
12034
+ severity: "error",
12035
+ code: "workflow-validation-command-failed",
12036
+ message: `Validation command failed: ${result.command}`
12037
+ }
12038
+ ] : []);
12039
+ return {
12040
+ schemaVersion: 1,
12041
+ runId,
12042
+ workflow,
12043
+ mode: "validate",
12044
+ source,
12045
+ status: workflowStatus([...diagnostics, ...commandDiagnostics]) === "failed" ? "failed" : commandStatus(results),
12046
+ commands: results,
12047
+ diagnostics: [...diagnostics, ...commandDiagnostics],
12048
+ repairActions: uniqueBy(repairActions, (action) => action.command),
12049
+ nextActions: results.filter((result) => result.status === "failed").map((result) => ({ command: result.command, reason: "Re-run this validation command after repair." })),
12050
+ plan
12051
+ };
12052
+ };
12053
+ var createDryRunWorkflowApplyReport = (plan) => {
12054
+ const changedFiles = plan.predictedChanges.flatMap((change) => {
12055
+ if (change.action !== "create" && change.action !== "modify")
12056
+ return [];
12057
+ return [
12058
+ {
12059
+ path: change.target,
12060
+ action: change.action,
12061
+ reason: change.reason
12062
+ }
12063
+ ];
12064
+ });
12065
+ const generatedFiles2 = plan.predictedChanges.flatMap((change) => {
12066
+ if (change.action !== "sync")
12067
+ return [];
12068
+ return [
12069
+ {
12070
+ path: change.target,
12071
+ action: "sync",
12072
+ reason: change.reason
12073
+ }
12074
+ ];
12075
+ });
12076
+ const diagnostics = [...plan.diagnostics];
12077
+ return createWorkflowApplyReport({
12078
+ workflow: plan.workflow,
12079
+ mode: "dry-run",
12080
+ changedFiles,
12081
+ generatedFiles: generatedFiles2,
12082
+ commands: workflowCommandsForPlan(plan),
12083
+ diagnostics,
12084
+ nextActions: workflowCommandsForPlan(plan),
12085
+ plan
12086
+ });
12087
+ };
12088
+ var workflowStepKey = (workflow, stepId) => `${workflow}:${stepId}`;
12089
+ var primitiveReportToWorkflowStepResult = (report) => ({
12090
+ changedFiles: report.changedFiles,
12091
+ generatedFiles: report.generatedFiles,
12092
+ commands: report.validationCommands,
12093
+ diagnostics: report.diagnostics,
12094
+ nextActions: report.nextActions
12095
+ });
12096
+ var workflowStringInput = (value) => typeof value === "string" ? value : null;
12097
+ var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
12098
+ var resolveWorkflowSys = async (workspace, target) => {
12099
+ if (!target)
12100
+ return null;
12101
+ const [apps, libs] = await workspace.getSyss();
12102
+ if (apps.includes(target))
12103
+ return AppExecutor.from(workspace, target);
12104
+ if (libs.includes(target))
12105
+ return LibExecutor.from(workspace, target);
12106
+ return null;
12107
+ };
12108
+ var targetMissing = (input4 = "app") => ({
12109
+ severity: "error",
12110
+ code: "workflow-target-missing",
12111
+ input: input4,
12112
+ message: "Workflow target app or library was not found."
12113
+ });
12114
+ var inputMissing = (input4) => ({
12115
+ severity: "error",
12116
+ code: "workflow-input-missing",
12117
+ input: input4,
12118
+ message: `Workflow input "${input4}" is required for apply.`
12119
+ });
12120
+ var unsupportedInput = (input4, message) => ({
12121
+ severity: "error",
12122
+ code: "workflow-input-unsupported",
12123
+ input: input4,
12124
+ message
12125
+ });
12126
+ var createWorkflowStepRegistry = ({
12127
+ workspace,
12128
+ createModule,
12129
+ createScalar,
12130
+ createUi,
12131
+ addField,
12132
+ addEnumField
12133
+ }) => {
12134
+ const inspect = async () => {
12135
+ return;
12136
+ };
12137
+ const commandOnly = async () => {
12138
+ return;
12139
+ };
12140
+ return {
12141
+ inspectSystem: inspect,
12142
+ inspectModule: inspect,
12143
+ syncTarget: commandOnly,
12144
+ lintTarget: commandOnly,
12145
+ [workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
12146
+ const app = workflowStringInput(plan.inputs.app);
12147
+ const module = workflowStringInput(plan.inputs.module);
12148
+ const sys3 = await resolveWorkflowSys(workspace, app);
12149
+ if (!sys3 || !module)
12150
+ return { diagnostics: [!sys3 ? targetMissing() : inputMissing("module")] };
12151
+ return primitiveReportToWorkflowStepResult(await createModule(sys3, module));
12152
+ },
12153
+ [workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
12154
+ const app = workflowStringInput(plan.inputs.app);
12155
+ const scalar = workflowStringInput(plan.inputs.scalar);
12156
+ const sys3 = await resolveWorkflowSys(workspace, app);
12157
+ if (!sys3 || !scalar)
12158
+ return { diagnostics: [!sys3 ? targetMissing() : inputMissing("scalar")] };
12159
+ return primitiveReportToWorkflowStepResult(await createScalar(sys3, scalar));
12160
+ },
12161
+ [workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
12162
+ const surface = workflowStringInput(plan.inputs.surface);
12163
+ if (surface !== "view" && surface !== "unit" && surface !== "template") {
12164
+ return {
12165
+ diagnostics: [
12166
+ unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
12167
+ ]
12168
+ };
12169
+ }
12170
+ return primitiveReportToWorkflowStepResult(await createUi({
12171
+ app: workflowStringInput(plan.inputs.app),
12172
+ module: workflowStringInput(plan.inputs.module),
12173
+ surface
12174
+ }));
12175
+ },
12176
+ [workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
12177
+ if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
12178
+ return primitiveReportToWorkflowStepResult(await addEnumField({
12179
+ app: workflowStringInput(plan.inputs.app),
12180
+ module: workflowStringInput(plan.inputs.module),
12181
+ field: workflowStringInput(plan.inputs.field),
12182
+ values: workflowStringListInput(plan.inputs.values),
12183
+ defaultValue: workflowStringInput(plan.inputs.default)
12184
+ }));
12185
+ }
12186
+ return primitiveReportToWorkflowStepResult(await addField({
12187
+ app: workflowStringInput(plan.inputs.app),
12188
+ module: workflowStringInput(plan.inputs.module),
12189
+ field: workflowStringInput(plan.inputs.field),
12190
+ type: workflowStringInput(plan.inputs.type),
12191
+ defaultValue: workflowStringInput(plan.inputs.default)
12192
+ }));
12193
+ },
12194
+ [workflowStepKey("add-field", "update-dictionary")]: inspect,
12195
+ [workflowStepKey("add-field", "update-ui-surfaces")]: inspect,
12196
+ [workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
12197
+ app: workflowStringInput(plan.inputs.app),
12198
+ module: workflowStringInput(plan.inputs.module),
12199
+ field: workflowStringInput(plan.inputs.field),
12200
+ values: workflowStringListInput(plan.inputs.values),
12201
+ defaultValue: workflowStringInput(plan.inputs.default)
12202
+ })),
12203
+ [workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
12204
+ [workflowStepKey("add-enum-field", "update-option")]: inspect
12205
+ };
12206
+ };
12207
+ var renderWorkflowApplyReport = (report) => [
12208
+ `# Workflow Apply: ${report.workflow}`,
12209
+ "",
12210
+ `- Mode: ${report.mode}`,
12211
+ `- Status: ${report.status}`,
12212
+ "",
12213
+ "## Changed Files",
12214
+ ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12215
+ "",
12216
+ "## Generated Files",
12217
+ ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12218
+ "",
12219
+ "## Commands",
12220
+ ...report.commands.length ? report.commands.map((command3) => `- \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12221
+ "",
12222
+ "## Diagnostics",
12223
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
12224
+ "",
12225
+ "## Next Actions",
12226
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
12227
+ ""
12228
+ ].join(`
12229
+ `);
12230
+ var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
12231
+ var renderWorkflowValidationRunReport = (report) => [
12232
+ `# Workflow Validation: ${report.workflow}`,
12233
+ "",
12234
+ `- Run: ${report.runId}`,
12235
+ `- Status: ${report.status}`,
12236
+ "",
12237
+ "## Commands",
12238
+ ...report.commands.length ? report.commands.map((command3) => `- [${command3.status}] \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12239
+ "",
12240
+ "## Diagnostics",
12241
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
12242
+ "",
12243
+ "## Repair Actions",
12244
+ ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
12245
+ "",
12246
+ "## Next Actions",
12247
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
12248
+ ""
12249
+ ].join(`
12250
+ `);
12251
+ var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
12252
+ var renderWorkflowRunArtifact = (artifact, format = "markdown") => {
12253
+ if ("kind" in artifact)
12254
+ return renderRepairReport(artifact, format);
12255
+ if ("mode" in artifact && artifact.mode === "validate")
12256
+ return renderWorkflowValidation(artifact, format);
12257
+ if ("mode" in artifact && (artifact.mode === "apply" || artifact.mode === "dry-run")) {
12258
+ return renderWorkflowApply(artifact, format);
12259
+ }
12260
+ return jsonText(artifact);
12261
+ };
12262
+ var createRepairReport = ({
12263
+ command: command3,
12264
+ kind,
12265
+ target = null,
12266
+ diagnostics = [],
12267
+ repairActions = [],
12268
+ nextActions = [],
12269
+ commands = []
12270
+ }) => ({
12271
+ schemaVersion: 1,
12272
+ command: command3,
12273
+ kind,
12274
+ target,
12275
+ status: workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed",
12276
+ diagnostics,
12277
+ repairActions: uniqueBy(repairActions, (action) => action.command),
12278
+ nextActions: uniqueBy(nextActions, (action) => action.command),
12279
+ commands
12280
+ });
12281
+ var renderRepairReportMarkdown = (report) => [
12282
+ `# Akan Repair: ${report.kind}`,
12283
+ "",
12284
+ `- Status: ${report.status}`,
12285
+ `- Target: ${report.target ?? "none"}`,
12286
+ "",
12287
+ "## Commands",
12288
+ ...report.commands.length ? report.commands.map((command3) => `- [${command3.status}] \`${command3.command}\`: ${command3.reason}`) : ["- none"],
12289
+ "",
12290
+ "## Diagnostics",
12291
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
12292
+ "",
12293
+ "## Next Actions",
12294
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
12295
+ ""
12296
+ ].join(`
12297
+ `);
12298
+ var renderRepairReport = (report, format = "markdown") => format === "json" ? jsonText(report) : renderRepairReportMarkdown(report);
12299
+
12300
+ class WorkflowExecutor {
12301
+ registry;
12302
+ constructor(registry) {
12303
+ this.registry = registry;
12304
+ }
12305
+ async apply(plan) {
12306
+ const changedFiles = [];
12307
+ const generatedFiles2 = [];
12308
+ const commands = [];
12309
+ const diagnostics = [...plan.diagnostics];
12310
+ const nextActions = [];
12311
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
12312
+ return createWorkflowApplyReport({
12313
+ workflow: plan.workflow,
12314
+ mode: "apply",
12315
+ changedFiles,
12316
+ generatedFiles: generatedFiles2,
12317
+ commands,
12318
+ diagnostics,
12319
+ nextActions,
12320
+ plan
12321
+ });
12322
+ }
12323
+ commands.push(...workflowCommandsForPlan(plan));
12324
+ nextActions.push(...workflowCommandsForPlan(plan));
12325
+ for (const step of plan.steps) {
12326
+ const runner2 = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
12327
+ if (!runner2) {
12328
+ diagnostics.push({
12329
+ severity: "error",
12330
+ code: "workflow-step-unsupported",
12331
+ message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
12332
+ });
12333
+ nextActions.push({
12334
+ command: `akan workflow explain ${plan.workflow}`,
12335
+ reason: "Review the unsupported workflow step before retrying apply."
12336
+ });
12337
+ break;
12338
+ }
12339
+ const result = await runner2(step, plan);
12340
+ if (!result)
12341
+ continue;
12342
+ changedFiles.push(...result.changedFiles ?? []);
12343
+ generatedFiles2.push(...result.generatedFiles ?? []);
12344
+ commands.push(...result.commands ?? []);
12345
+ diagnostics.push(...result.diagnostics ?? []);
12346
+ nextActions.push(...result.nextActions ?? []);
12347
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
12348
+ break;
12349
+ }
12350
+ return createWorkflowApplyReport({
12351
+ workflow: plan.workflow,
12352
+ mode: "apply",
12353
+ changedFiles,
12354
+ generatedFiles: generatedFiles2,
12355
+ commands,
12356
+ diagnostics,
12357
+ nextActions,
12358
+ plan
12359
+ });
12360
+ }
12361
+ }
12362
+ var createPrimitiveWriteReport = ({
12363
+ command: command3,
12364
+ status,
12365
+ changedFiles = [],
12366
+ generatedFiles: generatedFiles2 = [],
12367
+ validationCommands: validationCommands2 = [],
12368
+ diagnostics = [],
12369
+ nextActions = []
12370
+ }) => ({
12371
+ schemaVersion: 1,
12372
+ command: command3,
12373
+ status: status ?? (diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "passed"),
12374
+ changedFiles,
12375
+ generatedFiles: generatedFiles2,
12376
+ validationCommands: validationCommands2,
12377
+ diagnostics,
12378
+ nextActions
12379
+ });
12380
+ var renderPrimitiveWriteReport = (report) => [
12381
+ `# Primitive Write: ${report.command}`,
12382
+ "",
12383
+ `- Status: ${report.status}`,
12384
+ "",
12385
+ "## Changed Files",
12386
+ ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12387
+ "",
12388
+ "## Generated Files",
12389
+ ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
12390
+ "",
12391
+ "## Validation Commands",
12392
+ ...report.validationCommands.length ? report.validationCommands.map((validation) => `- \`${validation.command}\`: ${validation.reason}`) : ["- none"],
12393
+ "",
12394
+ "## Diagnostics",
12395
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
12396
+ "",
12397
+ "## Next Actions",
12398
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
12399
+ ""
12400
+ ].join(`
12401
+ `);
12402
+ var renderPrimitiveReport = (report, format = "markdown") => format === "json" ? jsonText(report) : renderPrimitiveWriteReport(report);
12403
+ var getSysRoot = (sys3) => `${sys3.type}s/${sys3.name}`;
12404
+ var sourceFile = (sys3, path40, action, reason) => ({
12405
+ path: `${getSysRoot(sys3)}/${path40}`,
12406
+ action,
12407
+ reason
12408
+ });
12409
+ var generatedFilesForSync = (sys3, reason = "Generated files may change after sync.") => [
12410
+ { path: `${getSysRoot(sys3)}/lib/cnst.ts`, action: "sync", reason },
12411
+ { path: `${getSysRoot(sys3)}/lib/dict.ts`, action: "sync", reason },
12412
+ { path: `${getSysRoot(sys3)}/lib/option.ts`, action: "sync", reason },
12413
+ { path: `${getSysRoot(sys3)}/lib/index.ts`, action: "sync", reason }
12414
+ ];
12415
+ var validationCommandsForTarget = (target) => [
12416
+ { command: `akan sync ${target}`, reason: "Refresh generated Akan files from source conventions." },
12417
+ { command: `akan lint ${target}`, reason: "Validate formatting, imports, and static lint rules." }
12418
+ ];
12419
+ var nextActionsForTarget = (target) => [
12420
+ { command: `akan sync ${target}`, reason: "Refresh generated Akan files after source changes." },
12421
+ { command: `akan lint ${target}`, reason: "Validate the target after generated files are refreshed." }
12422
+ ];
12423
+ var createPassedPrimitiveReport = ({
12424
+ command: command3,
12425
+ changedFiles,
12426
+ generatedFiles: generatedFiles2,
12427
+ target,
12428
+ nextActions
12429
+ }) => createPrimitiveWriteReport({
12430
+ command: command3,
12431
+ changedFiles,
12432
+ generatedFiles: generatedFiles2 ?? [],
12433
+ validationCommands: validationCommandsForTarget(target),
12434
+ diagnostics: [],
12435
+ nextActions: nextActions ?? nextActionsForTarget(target)
12436
+ });
12437
+ var scalarChangedFiles = (sys3, scalarName, files) => Object.values(files).map((file) => sourceFile(sys3, `lib/__scalar/${scalarName}/${file.filename}`, "create", "Scalar source file was created."));
12438
+ var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
12439
+ var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
12440
+ var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
12441
+ var fieldExpression = (typeName, defaultValue) => {
12442
+ const normalizedTypes = {
12443
+ string: "String",
12444
+ number: "Number",
12445
+ boolean: "Boolean",
12446
+ date: "Date"
12447
+ };
12448
+ const typeExpression = normalizedTypes[typeName.toLowerCase()] ?? typeName;
12449
+ const defaultOption = defaultValue ? `, { default: ${JSON.stringify(defaultValue)} }` : "";
12450
+ return `field(${typeExpression}${defaultOption})`;
12451
+ };
12452
+ var insertIntoObject = (content, className, line) => {
12453
+ const classIndex = content.indexOf(`export class ${className} extends via`);
12454
+ if (classIndex < 0)
12455
+ return null;
12456
+ const objectEndIndex = content.indexOf("}))", classIndex);
12457
+ if (objectEndIndex < 0)
12458
+ return null;
12459
+ const prefix = content.slice(0, objectEndIndex);
12460
+ const suffix = content.slice(objectEndIndex);
12461
+ const insertion = prefix.endsWith(`
12462
+ `) ? ` ${line}
12463
+ ` : `
12464
+ ${line}
12465
+ `;
12466
+ return `${prefix}${insertion}${suffix}`;
12467
+ };
12468
+ var ensureEnumImport = (content) => {
12469
+ if (content.includes("enumOf"))
12470
+ return content;
12471
+ const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
12472
+ if (baseImport) {
12473
+ const names = baseImport[1]?.split(",").map((name) => name.trim()) ?? [];
12474
+ return content.replace(baseImport[0], `import { ${[...names, "enumOf"].sort().join(", ")} } from "akanjs/base";`);
12475
+ }
12476
+ return `import { enumOf } from "akanjs/base";
12477
+ ${content}`;
12478
+ };
12479
+ var insertEnumClass = (content, enumClassName, enumName, values) => {
12480
+ if (content.includes(`export class ${enumClassName} extends enumOf`))
12481
+ return content;
12482
+ const enumClass = `export class ${enumClassName} extends enumOf("${enumName}", [
12483
+ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
12484
+ `)}
12485
+ ] as const) {}
12486
+
12487
+ `;
12488
+ const firstClassIndex = content.indexOf("export class ");
12489
+ if (firstClassIndex < 0)
12490
+ return `${content}
12491
+ ${enumClass}`;
12492
+ return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
12493
+ };
12494
+ var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
12495
+ if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
12496
+ return content;
12497
+ const label = titleize(fieldName);
12498
+ const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => ({`);
12499
+ if (modelIndex < 0)
12500
+ return null;
12501
+ const objectEndIndex = content.indexOf(" }))", modelIndex);
12502
+ if (objectEndIndex < 0)
12503
+ return null;
12504
+ return `${content.slice(0, objectEndIndex)} ${fieldName}: t([${JSON.stringify(label)}, ${JSON.stringify(label)}]).desc([${JSON.stringify(label)}, ${JSON.stringify(label)}]),
12505
+ ${content.slice(objectEndIndex)}`;
12506
+ };
12507
+ var ensureConstantTypeImport = (content, constantPath, typeName) => {
12508
+ if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
12509
+ return content;
12510
+ const importPattern = new RegExp(`import type \\{ ([^}]+) \\} from "${constantPath}";`);
12511
+ const existingImport = content.match(importPattern);
12512
+ if (existingImport !== null) {
12513
+ const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
12514
+ return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
12515
+ }
12516
+ return `import type { ${typeName} } from "${constantPath}";
12517
+ ${content}`;
12518
+ };
12519
+ var insertDictionaryEnum = (content, enumClassName, enumName, values) => {
12520
+ if (content.includes(`.enum<${enumClassName}>("${enumName}"`))
12521
+ return content;
12522
+ const enumBlock = ` .enum<${enumClassName}>("${enumName}", (t) => ({
12523
+ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${JSON.stringify(titleize(value))}]),`).join(`
12524
+ `)}
12525
+ }))
12526
+ `;
12527
+ const chainEndIndex = content.lastIndexOf(";");
12528
+ const insertBeforeIndex = [content.indexOf(".error("), content.indexOf(".translate("), chainEndIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
12529
+ if (insertBeforeIndex === undefined)
12530
+ return null;
12531
+ return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
12532
+ };
12533
+ var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
11693
12534
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
11694
12535
  import { Logger as Logger11 } from "akanjs/common";
11695
12536
  class IncrementalBuilder {