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

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.
@@ -2,7 +2,7 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
5
- import path40 from "path";
5
+ import path42 from "path";
6
6
 
7
7
  // pkgs/@akanjs/devkit/aiEditor.ts
8
8
  import { input, select } from "@inquirer/prompts";
@@ -4777,8 +4777,8 @@ class AkanAppHost {
4777
4777
  }
4778
4778
  // pkgs/@akanjs/devkit/akanContext.ts
4779
4779
  import { readdir } from "fs/promises";
4780
- import path10 from "path";
4781
- import { capitalize as capitalize4 } from "akanjs/common";
4780
+ import path11 from "path";
4781
+ import { capitalize as capitalize3 } from "akanjs/common";
4782
4782
 
4783
4783
  // pkgs/@akanjs/devkit/workflow/utils.ts
4784
4784
  var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
@@ -4798,6 +4798,29 @@ var uniqueBy = (values, key) => {
4798
4798
  var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
4799
4799
 
4800
4800
  // pkgs/@akanjs/devkit/workflow/artifacts.ts
4801
+ var sourceChangeBlocked = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
4802
+ var workflowPlanApproval = {
4803
+ required: true,
4804
+ meaning: "Review this read-only plan before apply_workflow mutates files.",
4805
+ applyTool: "apply_workflow"
4806
+ };
4807
+ var inferNextActionCode = (action, diagnostics) => {
4808
+ if (action.action)
4809
+ return action.action;
4810
+ if (sourceChangeBlocked(diagnostics) && action.command.startsWith("akan workflow explain"))
4811
+ return "blocked";
4812
+ if (action.command.startsWith("akan workflow repair"))
4813
+ return "repair";
4814
+ if (action.command.startsWith("akan workflow explain"))
4815
+ return "manual-review";
4816
+ if (action.command.startsWith("akan "))
4817
+ return "validate";
4818
+ return "answer";
4819
+ };
4820
+ var nextActionPriority = (action, diagnostics) => {
4821
+ const priority = sourceChangeBlocked(diagnostics) ? { blocked: 0, repair: 1, "manual-review": 2, validate: 3, answer: 4 } : { "manual-review": 0, validate: 1, repair: 2, blocked: 3, answer: 4 };
4822
+ return priority[action.action ?? "answer"];
4823
+ };
4801
4824
  var createWorkflowApplyReport = ({
4802
4825
  workflow,
4803
4826
  mode,
@@ -4813,18 +4836,31 @@ var createWorkflowApplyReport = ({
4813
4836
  plan
4814
4837
  }) => {
4815
4838
  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
- });
4839
+ const nextActionsWithIntent = nextActions.map((action) => ({
4840
+ ...action,
4841
+ action: inferNextActionCode(action, diagnostics)
4842
+ }));
4843
+ if (sourceChangeBlocked(diagnostics) && !nextActionsWithIntent.some((action) => action.action === "blocked")) {
4844
+ nextActionsWithIntent.unshift({
4845
+ command: `akan workflow explain ${workflow}`,
4846
+ reason: "Review source-change blockers before running validation.",
4847
+ action: "blocked"
4848
+ });
4849
+ }
4850
+ const orderedNextActions = uniqueBy(nextActionsWithIntent, (action) => action.command).sort((left, right) => nextActionPriority(left, diagnostics) - nextActionPriority(right, diagnostics));
4851
+ const sourceFilesChanged = uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
4852
+ const generatedFilesSynced = uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
4821
4853
  return {
4822
4854
  schemaVersion: 1,
4823
4855
  workflow,
4824
4856
  mode,
4825
4857
  status: workflowStatus(diagnostics),
4826
- changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4827
- generatedFiles: uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4858
+ summary: {
4859
+ sourceFilesChanged,
4860
+ generatedFilesSynced
4861
+ },
4862
+ changedFiles: sourceFilesChanged,
4863
+ generatedFiles: generatedFilesSynced,
4828
4864
  appliedCommands: uniqueBy(appliedCommands, (command) => command.command),
4829
4865
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
4830
4866
  commands: uniqueBy(validationCommands, (command) => command.command),
@@ -4902,6 +4938,52 @@ var statusForValidationKind = (commands, kind) => {
4902
4938
  return "unknown";
4903
4939
  return matching.some((command) => command.status === "failed") ? "failed" : "passed";
4904
4940
  };
4941
+ var statusForCommands = (commands) => {
4942
+ if (commands.length === 0)
4943
+ return "unknown";
4944
+ return commandStatus(commands) === "failed" ? "failed" : "passed";
4945
+ };
4946
+ var statusForDiagnostics = (diagnostics) => {
4947
+ if (diagnostics.length === 0)
4948
+ return "unknown";
4949
+ return workflowStatus(diagnostics) === "failed" ? "failed" : "passed";
4950
+ };
4951
+ var workflowDiagnosticContextPaths = (diagnostics) => uniqueBy(diagnostics.flatMap((diagnostic) => diagnostic.context?.paths ?? []), (filePath) => filePath);
4952
+ var createWorkflowBaselineSummary = (diagnostics, { detailsIncluded = true, knownBlockerCount = 0 } = {}) => {
4953
+ const grouped = new Map;
4954
+ let totalErrors = 0;
4955
+ let totalWarnings = 0;
4956
+ for (const diagnostic of diagnostics) {
4957
+ if (diagnostic.severity === "error")
4958
+ totalErrors += 1;
4959
+ else
4960
+ totalWarnings += 1;
4961
+ const existing = grouped.get(diagnostic.code);
4962
+ if (existing) {
4963
+ existing.count += 1;
4964
+ if (existing.severity !== diagnostic.severity)
4965
+ existing.severity = "mixed";
4966
+ } else {
4967
+ grouped.set(diagnostic.code, {
4968
+ code: diagnostic.code,
4969
+ severity: diagnostic.severity,
4970
+ count: 1,
4971
+ sampleMessage: diagnostic.message
4972
+ });
4973
+ }
4974
+ }
4975
+ const contextPaths = workflowDiagnosticContextPaths(diagnostics);
4976
+ return {
4977
+ status: totalErrors > 0 ? "failed" : diagnostics.length > 0 ? "passed" : "unknown",
4978
+ total: diagnostics.length,
4979
+ totalErrors,
4980
+ totalWarnings,
4981
+ detailsIncluded,
4982
+ knownBlockerCount,
4983
+ byCode: [...grouped.values()],
4984
+ ...contextPaths.length ? { contextPaths } : {}
4985
+ };
4986
+ };
4905
4987
  var createKnownBlockers = (commands, diagnostics) => {
4906
4988
  const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
4907
4989
  code: `workflow-validation-${command.failureScope}`,
@@ -4930,18 +5012,28 @@ var createKnownBlockers = (commands, diagnostics) => {
4930
5012
  }
4931
5013
  return [...grouped.values()];
4932
5014
  };
4933
- var createValidationStatuses = (commands, diagnostics) => {
5015
+ var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
5016
+ const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
4934
5017
  const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
4935
- const sourceStatus = statusForScope(commands, diagnostics, scopes, "source-change");
5018
+ const sourceDiagnostics = [...reportDiagnostics, ...workflowDiagnostics].filter((diagnostic) => diagnostic.failureScope === "source-change" || diagnostic.scope === "workflow" || !diagnostic.failureScope && diagnostic.scope !== "baseline");
5019
+ const sourceScopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(sourceDiagnostics)];
5020
+ const sourceStatus = statusForScope(commands, sourceDiagnostics, sourceScopes, "source-change");
5021
+ const validationCommandsStatus = statusForCommands(commands);
5022
+ const baselineStatus = statusForDiagnostics(baselineDiagnostics);
5023
+ const nonBaselineDiagnostics = [...reportDiagnostics, ...workflowDiagnostics];
4936
5024
  const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
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";
5025
+ const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : validationCommandsStatus === "passed" && baselineStatus === "failed" && workflowStatus(nonBaselineDiagnostics) !== "failed" ? "passed-with-baseline-blockers" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
4938
5026
  return {
4939
5027
  sourceStatus,
4940
5028
  workspaceStatus,
5029
+ validationCommandsStatus,
5030
+ baselineStatus,
4941
5031
  overallStatus,
4942
5032
  summary: {
4943
5033
  sourceChange: sourceStatus,
4944
5034
  generatedSync: statusForValidationKind(commands, "sync"),
5035
+ validationCommands: validationCommandsStatus,
5036
+ baseline: baselineStatus,
4945
5037
  workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
4946
5038
  environment: statusForScope(commands, diagnostics, scopes, "environment")
4947
5039
  }
@@ -4975,7 +5067,8 @@ var createWorkflowValidationRunReport = async ({
4975
5067
  ] : []);
4976
5068
  const reportDiagnostics = [...diagnostics, ...commandDiagnostics];
4977
5069
  const scopedDiagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
4978
- const statuses = createValidationStatuses(results, scopedDiagnostics);
5070
+ const knownBlockers = createKnownBlockers(results, scopedDiagnostics);
5071
+ const statuses = createValidationStatuses(results, reportDiagnostics, baselineDiagnostics, workflowDiagnostics);
4979
5072
  return {
4980
5073
  schemaVersion: 1,
4981
5074
  runId,
@@ -4984,9 +5077,12 @@ var createWorkflowValidationRunReport = async ({
4984
5077
  source,
4985
5078
  status: statuses.overallStatus === "passed" ? "passed" : "failed",
4986
5079
  ...statuses,
4987
- knownBlockers: createKnownBlockers(results, scopedDiagnostics),
5080
+ knownBlockers,
4988
5081
  commands: results,
4989
5082
  diagnostics: reportDiagnostics,
5083
+ baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
5084
+ knownBlockerCount: knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config").length
5085
+ }),
4990
5086
  baselineDiagnostics,
4991
5087
  workflowDiagnostics,
4992
5088
  repairActions: uniqueBy(repairActions, (action) => action.command),
@@ -5054,7 +5150,14 @@ var createRepairReport = ({
5054
5150
  ...syncedAt ? { syncedAt } : {}
5055
5151
  });
5056
5152
  // pkgs/@akanjs/devkit/workflow/executor.ts
5057
- import { capitalize as capitalize2 } from "akanjs/common";
5153
+ import ts6 from "typescript";
5154
+
5155
+ // pkgs/@akanjs/devkit/workflow/moduleIndex.ts
5156
+ import { access } from "fs/promises";
5157
+ import path10 from "path";
5158
+ import ts5 from "typescript";
5159
+
5160
+ // pkgs/@akanjs/devkit/workflow/source.ts
5058
5161
  import ts4 from "typescript";
5059
5162
 
5060
5163
  // pkgs/@akanjs/devkit/workflow/primitive.ts
@@ -5107,7 +5210,7 @@ var sourceFile = (sys2, path10, action, reason) => ({
5107
5210
  action,
5108
5211
  reason
5109
5212
  });
5110
- var moduleComponentName = (moduleName) => `${moduleName.slice(0, 1).toUpperCase()}${moduleName.slice(1)}`;
5213
+ var moduleComponentName = (moduleName) => moduleName.replace(/[-_]+/g, " ").replace(/(?:^|\s+)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "");
5111
5214
  var moduleSourcePaths = (moduleName) => {
5112
5215
  const componentName = moduleComponentName(moduleName);
5113
5216
  return {
@@ -5210,12 +5313,13 @@ var normalizeFieldType = (typeName) => {
5210
5313
  var ensureBaseTypeImport = (content, typeName) => {
5211
5314
  if (typeName !== "Int" && typeName !== "Float")
5212
5315
  return content;
5213
- if (new RegExp(`import \\{[^}]*\\b${typeName}\\b[^}]*\\} from "akanjs/base";`).test(content))
5214
- return content;
5215
- const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
5316
+ const source = sourceFileFor("constant.ts", content);
5317
+ const baseImport = findNamedImport(source, "akanjs/base");
5216
5318
  if (baseImport) {
5217
- const names = baseImport[1].split(",").map((name) => name.trim()).filter(Boolean);
5218
- return content.replace(baseImport[0], `import { ${[...names, typeName].sort().join(", ")} } from "akanjs/base";`);
5319
+ if (baseImport.names.includes(typeName))
5320
+ return content;
5321
+ const nextNames = [...baseImport.names, typeName].sort();
5322
+ return spliceText(content, baseImport.namedBindingsStart, baseImport.namedBindingsEnd, `{ ${nextNames.join(", ")} }`);
5219
5323
  }
5220
5324
  return `import { ${typeName} } from "akanjs/base";
5221
5325
  ${content}`;
@@ -5344,47 +5448,350 @@ var fieldExpression = (typeName, defaultValue, options = {}) => {
5344
5448
  const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
5345
5449
  return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
5346
5450
  };
5347
- var viaBuilderParameterName = (content, className) => {
5348
- const classIndex = content.indexOf(`export class ${className} extends via`);
5349
- if (classIndex < 0)
5451
+ var fieldOrderingPriority = [
5452
+ "id",
5453
+ "name",
5454
+ "title",
5455
+ "status",
5456
+ "category",
5457
+ "description",
5458
+ "content",
5459
+ "startAt",
5460
+ "dueAt",
5461
+ "endAt",
5462
+ "createdAt",
5463
+ "updatedAt"
5464
+ ];
5465
+ var sourceFileFor = (fileName, content, scriptKind = ts4.ScriptKind.TS) => ts4.createSourceFile(fileName, content, ts4.ScriptTarget.Latest, true, scriptKind);
5466
+ var hasParseDiagnostics = (source) => (source.parseDiagnostics ?? []).length > 0;
5467
+ var spliceText = (content, start, end, replacement) => `${content.slice(0, start)}${replacement}${content.slice(end)}`;
5468
+ var lineStartAt = (content, position) => content.lastIndexOf(`
5469
+ `, Math.max(0, position - 1)) + 1;
5470
+ var lineEndAt = (content, position) => {
5471
+ const end = content.indexOf(`
5472
+ `, position);
5473
+ return end < 0 ? content.length : end + 1;
5474
+ };
5475
+ var lineIndentAt = (content, position) => /^[ \t]*/.exec(content.slice(lineStartAt(content, position)))?.[0] ?? "";
5476
+ var nodeName = (node) => {
5477
+ if (!node)
5478
+ return null;
5479
+ if (ts4.isIdentifier(node) || ts4.isStringLiteral(node) || ts4.isNumericLiteral(node))
5480
+ return node.text;
5481
+ return null;
5482
+ };
5483
+ var propertyName = (node) => ts4.isPropertyAssignment(node) || ts4.isShorthandPropertyAssignment(node) || ts4.isMethodDeclaration(node) ? nodeName(node.name) : null;
5484
+ var expressionName = (expression) => {
5485
+ if (ts4.isIdentifier(expression))
5486
+ return expression.text;
5487
+ if (ts4.isPropertyAccessExpression(expression))
5488
+ return expression.name.text;
5489
+ if (ts4.isCallExpression(expression))
5490
+ return expressionName(expression.expression);
5491
+ if (ts4.isAsExpression(expression))
5492
+ return expressionName(expression.expression);
5493
+ return null;
5494
+ };
5495
+ var firstObjectReturnedByArrow = (node) => {
5496
+ if (!ts4.isArrowFunction(node) && !ts4.isFunctionExpression(node))
5497
+ return null;
5498
+ if (ts4.isObjectLiteralExpression(node.body))
5499
+ return node.body;
5500
+ if (ts4.isParenthesizedExpression(node.body) && ts4.isObjectLiteralExpression(node.body.expression)) {
5501
+ return node.body.expression;
5502
+ }
5503
+ if (!ts4.isBlock(node.body))
5504
+ return null;
5505
+ for (const statement of node.body.statements) {
5506
+ if (ts4.isReturnStatement(statement) && statement.expression && ts4.isObjectLiteralExpression(statement.expression)) {
5507
+ return statement.expression;
5508
+ }
5509
+ }
5510
+ return null;
5511
+ };
5512
+ var isViaCall = (expression) => ts4.isCallExpression(expression) && expressionName(expression.expression) === "via";
5513
+ var heritageCall = (node) => {
5514
+ const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
5515
+ const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
5516
+ return expression && ts4.isCallExpression(expression) ? expression : null;
5517
+ };
5518
+ var callExpressionName = (node) => ts4.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
5519
+ var locatedObject = (source, objectLiteral) => ({
5520
+ objectStart: objectLiteral.getStart(source),
5521
+ objectEnd: objectLiteral.getEnd(),
5522
+ fields: objectLiteral.properties.map((property) => {
5523
+ const name = propertyName(property);
5524
+ if (!name)
5525
+ return null;
5526
+ return {
5527
+ name,
5528
+ start: property.getStart(source),
5529
+ fullStart: property.getFullStart(),
5530
+ end: property.getEnd()
5531
+ };
5532
+ }).filter((field) => field !== null)
5533
+ });
5534
+ var findConstantInputObject = (source, className) => {
5535
+ let locator = null;
5536
+ const visit = (node) => {
5537
+ if (locator)
5538
+ return;
5539
+ if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
5540
+ ts4.forEachChild(node, visit);
5541
+ return;
5542
+ }
5543
+ const viaCall = heritageCall(node);
5544
+ const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
5545
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
5546
+ if (objectLiteral)
5547
+ locator = locatedObject(source, objectLiteral);
5548
+ };
5549
+ ts4.forEachChild(source, visit);
5550
+ return locator;
5551
+ };
5552
+ var chainMethodsForCall = (node) => {
5553
+ if (ts4.isAsExpression(node) || ts4.isParenthesizedExpression(node))
5554
+ return chainMethodsForCall(node.expression);
5555
+ if (!ts4.isCallExpression(node))
5556
+ return [];
5557
+ if (ts4.isPropertyAccessExpression(node.expression)) {
5558
+ return [...chainMethodsForCall(node.expression.expression), node.expression.name.text];
5559
+ }
5560
+ const name = expressionName(node.expression);
5561
+ return name ? [name] : [];
5562
+ };
5563
+ var outermostFluentCall = (node) => {
5564
+ let current = node;
5565
+ while (ts4.isPropertyAccessExpression(current.parent) && current.parent.expression === current && ts4.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
5566
+ current = current.parent.parent;
5567
+ }
5568
+ return current;
5569
+ };
5570
+ var protectedDictionaryChainOrder = ["model", "slice", "enum", "error", "translate"];
5571
+ var dictionaryChainOrderValid = (chainMethods) => {
5572
+ const protectedOrder = new Map(protectedDictionaryChainOrder.map((method, index) => [method, index]));
5573
+ let lastOrder = -1;
5574
+ for (const method of chainMethods) {
5575
+ const order = protectedOrder.get(method);
5576
+ if (order === undefined)
5577
+ continue;
5578
+ if (order < lastOrder)
5579
+ return false;
5580
+ lastOrder = order;
5581
+ }
5582
+ return true;
5583
+ };
5584
+ var findDictionaryModelObject = (source, moduleClassName) => {
5585
+ let locator = null;
5586
+ const visit = (node) => {
5587
+ if (locator)
5588
+ return;
5589
+ if (!ts4.isCallExpression(node) || callExpressionName(node) !== "model") {
5590
+ ts4.forEachChild(node, visit);
5591
+ return;
5592
+ }
5593
+ const typeArgument = node.typeArguments?.[0];
5594
+ if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
5595
+ ts4.forEachChild(node, visit);
5596
+ return;
5597
+ }
5598
+ const callback = node.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
5599
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
5600
+ if (objectLiteral) {
5601
+ locator = {
5602
+ ...locatedObject(source, objectLiteral),
5603
+ chainMethods: chainMethodsForCall(outermostFluentCall(node))
5604
+ };
5605
+ }
5606
+ };
5607
+ ts4.forEachChild(source, visit);
5608
+ return locator;
5609
+ };
5610
+ var findLightProjectionArray = (source, moduleClassName) => {
5611
+ let locator = null;
5612
+ const visit = (node) => {
5613
+ if (locator)
5614
+ return;
5615
+ if (!ts4.isClassDeclaration(node) || node.name?.text !== `Light${moduleClassName}`) {
5616
+ ts4.forEachChild(node, visit);
5617
+ return;
5618
+ }
5619
+ const viaCall = heritageCall(node);
5620
+ const projectionArg = viaCall?.arguments.find((arg) => {
5621
+ const expression = ts4.isAsExpression(arg) ? arg.expression : arg;
5622
+ return ts4.isArrayLiteralExpression(expression);
5623
+ });
5624
+ const arrayLiteral = projectionArg ? ts4.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
5625
+ if (!projectionArg || !arrayLiteral || !ts4.isArrayLiteralExpression(arrayLiteral))
5626
+ return;
5627
+ locator = {
5628
+ projectionStart: projectionArg.getStart(source),
5629
+ projectionEnd: projectionArg.getEnd(),
5630
+ fields: arrayLiteral.elements.map((element) => ts4.isStringLiteralLike(element) ? element.text : null).filter((field) => field !== null)
5631
+ };
5632
+ };
5633
+ ts4.forEachChild(source, visit);
5634
+ return locator;
5635
+ };
5636
+ var findNamedImport = (source, moduleSpecifier) => {
5637
+ for (const statement of source.statements) {
5638
+ if (!ts4.isImportDeclaration(statement) || !ts4.isStringLiteral(statement.moduleSpecifier))
5639
+ continue;
5640
+ if (statement.moduleSpecifier.text !== moduleSpecifier)
5641
+ continue;
5642
+ const namedBindings = statement.importClause?.namedBindings;
5643
+ if (!namedBindings || !ts4.isNamedImports(namedBindings))
5644
+ continue;
5645
+ return {
5646
+ names: namedBindings.elements.map((element) => element.name.text),
5647
+ namedBindingsStart: namedBindings.getStart(source),
5648
+ namedBindingsEnd: namedBindings.getEnd()
5649
+ };
5650
+ }
5651
+ return null;
5652
+ };
5653
+ var fieldExpressionBuilder = (property) => {
5654
+ if (!ts4.isPropertyAssignment(property))
5350
5655
  return null;
5351
- const signature = content.slice(classIndex, content.indexOf("=>", classIndex));
5352
- return /via\(\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(signature)?.[1] ?? null;
5656
+ const initializer = ts4.isAsExpression(property.initializer) ? property.initializer.expression : property.initializer;
5657
+ if (!ts4.isCallExpression(initializer))
5658
+ return null;
5659
+ return expressionName(initializer.expression);
5660
+ };
5661
+ var priorityOf = (fieldName) => {
5662
+ const priority = fieldOrderingPriority.indexOf(fieldName);
5663
+ return priority < 0 ? null : priority;
5664
+ };
5665
+ var insertionIndexForFieldOrder = (fieldNames, newFieldName) => {
5666
+ const newPriority = priorityOf(newFieldName);
5667
+ if (newPriority !== null) {
5668
+ const greaterPriorityIndex = fieldNames.findIndex((name) => {
5669
+ const existingPriority = priorityOf(name);
5670
+ return existingPriority !== null && existingPriority > newPriority;
5671
+ });
5672
+ if (greaterPriorityIndex >= 0)
5673
+ return greaterPriorityIndex;
5674
+ const lastPriorityIndex = fieldNames.reduce((lastIndex, name, index) => {
5675
+ const existingPriority = priorityOf(name);
5676
+ return existingPriority !== null ? index : lastIndex;
5677
+ }, -1);
5678
+ return lastPriorityIndex + 1;
5679
+ }
5680
+ const lastNonPriorityIndex = fieldNames.reduce((lastIndex, name, index) => priorityOf(name) === null ? index : lastIndex, -1);
5681
+ return lastNonPriorityIndex >= 0 ? lastNonPriorityIndex + 1 : fieldNames.length;
5682
+ };
5683
+ var insertOrderedFieldLine = (content, locator, fieldName, line, options) => {
5684
+ if (locator.fields.some((field) => field.name === fieldName))
5685
+ return content;
5686
+ const insertIndex = insertionIndexForFieldOrder(locator.fields.map((field) => field.name), fieldName);
5687
+ const formattedLine = line.trim();
5688
+ if (locator.fields.length === 0) {
5689
+ return spliceText(content, locator.objectStart, locator.objectEnd, `{
5690
+ ${options.fieldIndent}${formattedLine}
5691
+ ${options.closingIndent}}`);
5692
+ }
5693
+ const beforeField = locator.fields[insertIndex];
5694
+ if (beforeField) {
5695
+ const leadingComments = ts4.getLeadingCommentRanges(content, beforeField.fullStart) ?? [];
5696
+ const insertAt2 = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
5697
+ const indent2 = lineIndentAt(content, beforeField.start) || options.fieldIndent;
5698
+ return spliceText(content, insertAt2, insertAt2, `${indent2}${formattedLine}
5699
+ `);
5700
+ }
5701
+ const afterField = locator.fields[locator.fields.length - 1];
5702
+ const insertAt = lineEndAt(content, afterField.end);
5703
+ const indent = lineIndentAt(content, afterField.start) || options.fieldIndent;
5704
+ return spliceText(content, insertAt, insertAt, `${indent}${formattedLine}
5705
+ `);
5706
+ };
5707
+ var viaBuilderParameterName = (content, className) => {
5708
+ const source = sourceFileFor("constant.ts", content);
5709
+ let builderName = null;
5710
+ const visit = (node) => {
5711
+ if (builderName !== null)
5712
+ return;
5713
+ if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
5714
+ ts4.forEachChild(node, visit);
5715
+ return;
5716
+ }
5717
+ const viaCall = heritageCall(node);
5718
+ const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
5719
+ if (callback && (ts4.isArrowFunction(callback) || ts4.isFunctionExpression(callback))) {
5720
+ builderName = nodeName(callback.parameters[0]?.name);
5721
+ }
5722
+ };
5723
+ ts4.forEachChild(source, visit);
5724
+ return builderName;
5725
+ };
5726
+ var inspectConstantStructure = (content, className, moduleClassName) => {
5727
+ const source = sourceFileFor("constant.ts", content);
5728
+ const inputObject = findConstantInputObject(source, className);
5729
+ const lightProjection = findLightProjectionArray(source, moduleClassName);
5730
+ const baseImport = findNamedImport(source, "akanjs/base");
5731
+ const fields = [];
5732
+ if (inputObject) {
5733
+ const visit = (node) => {
5734
+ if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
5735
+ ts4.forEachChild(node, visit);
5736
+ return;
5737
+ }
5738
+ const viaCall = heritageCall(node);
5739
+ const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
5740
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
5741
+ if (!objectLiteral)
5742
+ return;
5743
+ fields.push(...objectLiteral.properties.map((property) => {
5744
+ const name = propertyName(property);
5745
+ if (!name)
5746
+ return null;
5747
+ return { name, expressionBuilder: fieldExpressionBuilder(property) };
5748
+ }).filter((field) => field !== null));
5749
+ };
5750
+ ts4.forEachChild(source, visit);
5751
+ }
5752
+ return {
5753
+ parseValid: !hasParseDiagnostics(source),
5754
+ inputObjectFound: inputObject !== null,
5755
+ builderName: viaBuilderParameterName(content, className),
5756
+ fields,
5757
+ lightProjectionFields: lightProjection?.fields ?? [],
5758
+ baseImports: baseImport?.names ?? []
5759
+ };
5760
+ };
5761
+ var inspectDictionaryStructure = (content, moduleClassName) => {
5762
+ const source = sourceFileFor("dictionary.ts", content);
5763
+ const modelObject = findDictionaryModelObject(source, moduleClassName);
5764
+ return {
5765
+ parseValid: !hasParseDiagnostics(source),
5766
+ modelObjectFound: modelObject !== null,
5767
+ chainOrderValid: modelObject ? dictionaryChainOrderValid(modelObject.chainMethods) : false,
5768
+ chainMethods: modelObject?.chainMethods ?? [],
5769
+ fields: modelObject?.fields.map((field) => field.name) ?? []
5770
+ };
5353
5771
  };
5354
5772
  var insertIntoObject = (content, className, line) => {
5355
- const classIndex = content.indexOf(`export class ${className} extends via`);
5356
- if (classIndex < 0)
5773
+ const fieldName = /^([A-Za-z_$][\w$]*)\s*:/.exec(line.trim())?.[1];
5774
+ if (!fieldName)
5357
5775
  return null;
5358
- const objectEndIndex = content.indexOf("}))", classIndex);
5359
- if (objectEndIndex < 0)
5776
+ const source = sourceFileFor("constant.ts", content);
5777
+ const locator = findConstantInputObject(source, className);
5778
+ if (!locator)
5360
5779
  return null;
5361
- const prefix = content.slice(0, objectEndIndex);
5362
- const suffix = content.slice(objectEndIndex);
5363
- const insertion = prefix.endsWith(`
5364
- `) ? ` ${line}
5365
- ` : `
5366
- ${line}
5367
- `;
5368
- return `${prefix}${insertion}${suffix}`;
5780
+ return insertOrderedFieldLine(content, locator, fieldName, line, { fieldIndent: " ", closingIndent: "" });
5369
5781
  };
5370
5782
  var insertLightProjectionField = (content, moduleClassName, fieldName) => {
5371
- const classIndex = content.indexOf(`export class Light${moduleClassName} extends via`);
5372
- if (classIndex < 0)
5783
+ const source = sourceFileFor("constant.ts", content);
5784
+ const locator = findLightProjectionArray(source, moduleClassName);
5785
+ if (!locator)
5373
5786
  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))
5787
+ if (locator.fields.includes(fieldName))
5381
5788
  return content;
5382
- const nextFields = [...fields, fieldName];
5789
+ const nextFields = [...locator.fields, fieldName];
5383
5790
  const nextArray = nextFields.length === 0 ? "[] as const" : `[
5384
5791
  ${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
5385
5792
  `)}
5386
5793
  ] as const`;
5387
- return `${content.slice(0, arrayStart)}${nextArray}${content.slice(arrayEnd)}`;
5794
+ return spliceText(content, locator.projectionStart, locator.projectionEnd, nextArray);
5388
5795
  };
5389
5796
  var insertTemplateField = ({
5390
5797
  content,
@@ -5437,69 +5844,32 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
5437
5844
  ${enumClass}`;
5438
5845
  return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
5439
5846
  };
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
5847
  var dictionaryModelFieldLine = (fieldName) => {
5474
5848
  const label = bilingualLabelForField(fieldName);
5475
5849
  const desc = bilingualDescriptionForField(fieldName);
5476
5850
  return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
5477
5851
  };
5478
5852
  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)
5853
+ const source = sourceFileFor("dictionary.ts", content);
5854
+ const locator = findDictionaryModelObject(source, moduleClassName);
5855
+ if (!locator)
5483
5856
  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)}`;
5857
+ return insertOrderedFieldLine(content, locator, fieldName, dictionaryModelFieldLine(fieldName), {
5858
+ fieldIndent: " ",
5859
+ closingIndent: " "
5860
+ });
5861
+ };
5862
+ var hasConstantInputField = (content, className, fieldName) => {
5863
+ const source = sourceFileFor("constant.ts", content);
5864
+ if (hasParseDiagnostics(source))
5865
+ return false;
5866
+ return findConstantInputObject(source, className)?.fields.some((field) => field.name === fieldName) ?? false;
5867
+ };
5868
+ var hasDictionaryModelField = (content, moduleClassName, fieldName) => {
5869
+ const source = sourceFileFor("dictionary.ts", content);
5870
+ if (hasParseDiagnostics(source))
5871
+ return false;
5872
+ return findDictionaryModelObject(source, moduleClassName)?.fields.some((field) => field.name === fieldName) ?? false;
5503
5873
  };
5504
5874
  var ensureConstantTypeImport = (content, constantPath, typeName) => {
5505
5875
  if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
@@ -5529,6 +5899,401 @@ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${
5529
5899
  };
5530
5900
  var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
5531
5901
 
5902
+ // pkgs/@akanjs/devkit/workflow/moduleIndex.ts
5903
+ var indexFileKinds = [
5904
+ "abstract",
5905
+ "constant",
5906
+ "dictionary",
5907
+ "service",
5908
+ "signal",
5909
+ "store",
5910
+ "template",
5911
+ "unit",
5912
+ "util",
5913
+ "view",
5914
+ "zone"
5915
+ ];
5916
+ var sourceText = async (filePath) => {
5917
+ try {
5918
+ return await Bun.file(filePath).text();
5919
+ } catch {
5920
+ return null;
5921
+ }
5922
+ };
5923
+ var fileExists = async (filePath) => {
5924
+ try {
5925
+ await access(filePath);
5926
+ return true;
5927
+ } catch {
5928
+ return false;
5929
+ }
5930
+ };
5931
+ var sourceFileFor2 = (filePath, content) => ts5.createSourceFile(filePath, content, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TS);
5932
+ var parseDiagnosticsFor = (source, filePath) => {
5933
+ const parseDiagnostics = source.parseDiagnostics ?? [];
5934
+ return parseDiagnostics.map((diagnostic) => ({
5935
+ severity: "error",
5936
+ code: "module-index-typescript-parse-error",
5937
+ message: `TypeScript parse diagnostic TS${diagnostic.code} in ${filePath}: ${ts5.flattenDiagnosticMessageText(diagnostic.messageText, `
5938
+ `)}`,
5939
+ context: { target: filePath, paths: [filePath] }
5940
+ }));
5941
+ };
5942
+ var spanFor = (source, file, node) => {
5943
+ const startOffset = node.getStart(source);
5944
+ const endOffset = node.getEnd();
5945
+ const start = source.getLineAndCharacterOfPosition(startOffset);
5946
+ const end = source.getLineAndCharacterOfPosition(endOffset);
5947
+ return {
5948
+ file,
5949
+ startLine: start.line + 1,
5950
+ endLine: end.line + 1,
5951
+ startOffset,
5952
+ endOffset
5953
+ };
5954
+ };
5955
+ var nodeName2 = (node) => {
5956
+ if (!node)
5957
+ return null;
5958
+ if (ts5.isIdentifier(node) || ts5.isStringLiteral(node) || ts5.isNumericLiteral(node))
5959
+ return node.text;
5960
+ return null;
5961
+ };
5962
+ var propertyName2 = (node) => ts5.isPropertyAssignment(node) || ts5.isShorthandPropertyAssignment(node) || ts5.isMethodDeclaration(node) ? nodeName2(node.name) : null;
5963
+ var expressionName2 = (expression) => {
5964
+ if (ts5.isIdentifier(expression))
5965
+ return expression.text;
5966
+ if (ts5.isPropertyAccessExpression(expression))
5967
+ return expression.name.text;
5968
+ if (ts5.isCallExpression(expression))
5969
+ return expressionName2(expression.expression);
5970
+ if (ts5.isAsExpression(expression))
5971
+ return expressionName2(expression.expression);
5972
+ return null;
5973
+ };
5974
+ var expressionSummary = (expression) => {
5975
+ if (ts5.isAsExpression(expression))
5976
+ return expressionSummary(expression.expression);
5977
+ if (ts5.isIdentifier(expression) || ts5.isPropertyAccessExpression(expression))
5978
+ return expressionName2(expression) ?? "expression";
5979
+ if (ts5.isArrayLiteralExpression(expression))
5980
+ return "array-literal";
5981
+ if (ts5.isObjectLiteralExpression(expression))
5982
+ return "object-literal";
5983
+ if (ts5.isStringLiteralLike(expression))
5984
+ return "string-literal";
5985
+ if (ts5.isNumericLiteral(expression))
5986
+ return "numeric-literal";
5987
+ if (expression.kind === ts5.SyntaxKind.TrueKeyword || expression.kind === ts5.SyntaxKind.FalseKeyword) {
5988
+ return "boolean-literal";
5989
+ }
5990
+ if (ts5.isCallExpression(expression)) {
5991
+ const callee = expressionName2(expression.expression);
5992
+ return callee ? `${callee}(...)` : "call-expression";
5993
+ }
5994
+ return ts5.SyntaxKind[expression.kind] ?? "expression";
5995
+ };
5996
+ var typeSummaryForInitializer = (initializer) => {
5997
+ if (!initializer)
5998
+ return;
5999
+ const expression = ts5.isAsExpression(initializer) ? initializer.expression : initializer;
6000
+ if (!ts5.isCallExpression(expression))
6001
+ return expressionSummary(expression);
6002
+ const callee = expressionName2(expression.expression);
6003
+ const firstArg = expression.arguments[0];
6004
+ const argSummary = firstArg ? expressionSummary(firstArg) : "";
6005
+ return [callee, argSummary ? `(${argSummary})` : ""].filter(Boolean).join("");
6006
+ };
6007
+ var fieldsFromObject = (source, file, objectLiteral, kind) => objectLiteral.properties.map((property, index) => {
6008
+ const name = propertyName2(property);
6009
+ if (!name)
6010
+ return null;
6011
+ const initializer = ts5.isPropertyAssignment(property) ? property.initializer : undefined;
6012
+ return {
6013
+ name,
6014
+ kind,
6015
+ order: index,
6016
+ ...initializer ? { typeSummary: typeSummaryForInitializer(initializer) } : {},
6017
+ sourceSpan: spanFor(source, file, property)
6018
+ };
6019
+ }).filter((field) => field !== null);
6020
+ var firstObjectReturnedByArrow2 = (node) => {
6021
+ if (!ts5.isArrowFunction(node) && !ts5.isFunctionExpression(node))
6022
+ return null;
6023
+ if (ts5.isObjectLiteralExpression(node.body))
6024
+ return node.body;
6025
+ if (ts5.isParenthesizedExpression(node.body) && ts5.isObjectLiteralExpression(node.body.expression)) {
6026
+ return node.body.expression;
6027
+ }
6028
+ if (!ts5.isBlock(node.body))
6029
+ return null;
6030
+ for (const statement of node.body.statements) {
6031
+ if (ts5.isReturnStatement(statement) && statement.expression && ts5.isObjectLiteralExpression(statement.expression)) {
6032
+ return statement.expression;
6033
+ }
6034
+ }
6035
+ return null;
6036
+ };
6037
+ var isViaCall2 = (expression) => ts5.isCallExpression(expression) && expressionName2(expression.expression) === "via";
6038
+ var heritageCall2 = (node) => {
6039
+ const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
6040
+ const expression = heritage.find((clause) => isViaCall2(clause.expression))?.expression;
6041
+ return expression && ts5.isCallExpression(expression) ? expression : null;
6042
+ };
6043
+ var parseConstantIndex = (filePath, content, moduleClassName) => {
6044
+ const source = sourceFileFor2(filePath, content);
6045
+ const diagnostics = parseDiagnosticsFor(source, filePath);
6046
+ const inputClassName = `${moduleClassName}Input`;
6047
+ let inputClass = null;
6048
+ let inputViaFound = false;
6049
+ let inputBuilderFound = false;
6050
+ let inputBuilderObjectFound = false;
6051
+ let builderName = null;
6052
+ let fields = [];
6053
+ let lightProjection;
6054
+ const visit = (node) => {
6055
+ if (!ts5.isClassDeclaration(node) || !node.name) {
6056
+ ts5.forEachChild(node, visit);
6057
+ return;
6058
+ }
6059
+ const className = node.name.text;
6060
+ const viaCall = heritageCall2(node);
6061
+ if (className === inputClassName) {
6062
+ inputClass = node;
6063
+ if (!viaCall)
6064
+ return;
6065
+ inputViaFound = true;
6066
+ const callback = viaCall.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
6067
+ if (callback && (ts5.isArrowFunction(callback) || ts5.isFunctionExpression(callback))) {
6068
+ inputBuilderFound = true;
6069
+ builderName = nodeName2(callback.parameters[0]?.name) ?? null;
6070
+ const objectLiteral = firstObjectReturnedByArrow2(callback);
6071
+ if (objectLiteral) {
6072
+ inputBuilderObjectFound = true;
6073
+ fields = fieldsFromObject(source, filePath, objectLiteral, "constant");
6074
+ }
6075
+ }
6076
+ }
6077
+ if (!viaCall)
6078
+ return;
6079
+ if (className === `Light${moduleClassName}`) {
6080
+ const projectionArg = viaCall.arguments.find((arg) => {
6081
+ const expression = ts5.isAsExpression(arg) ? arg.expression : arg;
6082
+ return ts5.isArrayLiteralExpression(expression);
6083
+ });
6084
+ const arrayLiteral = projectionArg ? ts5.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
6085
+ if (arrayLiteral && ts5.isArrayLiteralExpression(arrayLiteral)) {
6086
+ lightProjection = {
6087
+ className,
6088
+ sourceSpan: spanFor(source, filePath, arrayLiteral),
6089
+ fields: arrayLiteral.elements.map((element, order) => ts5.isStringLiteralLike(element) ? {
6090
+ name: element.text,
6091
+ kind: "lightProjection",
6092
+ order,
6093
+ typeSummary: "string-literal",
6094
+ sourceSpan: spanFor(source, filePath, element)
6095
+ } : null).filter((field) => field !== null)
6096
+ };
6097
+ }
6098
+ }
6099
+ };
6100
+ ts5.forEachChild(source, visit);
6101
+ if (!inputClass) {
6102
+ diagnostics.push({
6103
+ severity: "error",
6104
+ code: "module-index-constant-input-missing",
6105
+ message: `Constant input class ${inputClassName} was not found in ${filePath}.`,
6106
+ context: { target: inputClassName, paths: [filePath] }
6107
+ });
6108
+ } else if (!inputViaFound) {
6109
+ diagnostics.push({
6110
+ severity: "error",
6111
+ code: "module-index-constant-via-missing",
6112
+ message: `Constant input class ${inputClassName} does not extend via(...) in ${filePath}.`,
6113
+ context: { target: inputClassName, paths: [filePath] }
6114
+ });
6115
+ } else if (!inputBuilderFound) {
6116
+ diagnostics.push({
6117
+ severity: "error",
6118
+ code: "module-index-constant-builder-missing",
6119
+ message: `Constant input class ${inputClassName} does not provide a via(...) builder callback in ${filePath}.`,
6120
+ context: { target: inputClassName, paths: [filePath] }
6121
+ });
6122
+ } else if (!inputBuilderObjectFound) {
6123
+ diagnostics.push({
6124
+ severity: "error",
6125
+ code: "module-index-constant-builder-object-missing",
6126
+ message: `Constant input class ${inputClassName} builder does not return an object literal in ${filePath}.`,
6127
+ context: { target: inputClassName, paths: [filePath] }
6128
+ });
6129
+ }
6130
+ return {
6131
+ index: {
6132
+ path: filePath,
6133
+ inputClassName,
6134
+ builderName,
6135
+ fields,
6136
+ ...lightProjection ? { lightProjection } : {},
6137
+ ...inputClass ? { sourceSpan: spanFor(source, filePath, inputClass) } : {}
6138
+ },
6139
+ diagnostics
6140
+ };
6141
+ };
6142
+ var callExpressionName2 = (node) => ts5.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName2(node.expression);
6143
+ var parseDictionaryIndex = (filePath, content, moduleClassName) => {
6144
+ const source = sourceFileFor2(filePath, content);
6145
+ const diagnostics = parseDiagnosticsFor(source, filePath);
6146
+ let index;
6147
+ let modelFound = false;
6148
+ const visit = (node) => {
6149
+ if (modelFound || !ts5.isCallExpression(node)) {
6150
+ ts5.forEachChild(node, visit);
6151
+ return;
6152
+ }
6153
+ if (callExpressionName2(node) !== "model") {
6154
+ ts5.forEachChild(node, visit);
6155
+ return;
6156
+ }
6157
+ const typeArgument = node.typeArguments?.[0];
6158
+ if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
6159
+ ts5.forEachChild(node, visit);
6160
+ return;
6161
+ }
6162
+ modelFound = true;
6163
+ const callback = node.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
6164
+ if (!callback || !ts5.isArrowFunction(callback) && !ts5.isFunctionExpression(callback)) {
6165
+ diagnostics.push({
6166
+ severity: "error",
6167
+ code: "module-index-dictionary-builder-missing",
6168
+ message: `Dictionary .model<${moduleClassName}> branch does not provide a builder callback in ${filePath}.`,
6169
+ context: { target: moduleClassName, paths: [filePath] }
6170
+ });
6171
+ return;
6172
+ }
6173
+ const objectLiteral = firstObjectReturnedByArrow2(callback);
6174
+ if (!objectLiteral) {
6175
+ diagnostics.push({
6176
+ severity: "error",
6177
+ code: "module-index-dictionary-builder-object-missing",
6178
+ message: `Dictionary .model<${moduleClassName}> builder does not return an object literal in ${filePath}.`,
6179
+ context: { target: moduleClassName, paths: [filePath] }
6180
+ });
6181
+ }
6182
+ index = {
6183
+ path: filePath,
6184
+ modelClassName: moduleClassName,
6185
+ translatorName: nodeName2(callback.parameters[0]?.name),
6186
+ fields: objectLiteral ? fieldsFromObject(source, filePath, objectLiteral, "dictionary") : [],
6187
+ sourceSpan: spanFor(source, filePath, node)
6188
+ };
6189
+ };
6190
+ ts5.forEachChild(source, visit);
6191
+ return { index, diagnostics, modelFound };
6192
+ };
6193
+ var expectedFilesFor = (module) => {
6194
+ const paths = moduleSourcePaths(module.name);
6195
+ return indexFileKinds.map((kind) => {
6196
+ const expectedModulePath = paths[kind];
6197
+ const expectedFilename = path10.basename(expectedModulePath);
6198
+ const actualFilename = module.files.find((file) => file === expectedFilename) ?? module.files.find((file) => file.toLowerCase() === expectedFilename.toLowerCase());
6199
+ const present = actualFilename !== undefined;
6200
+ const casing = !present ? "missing" : actualFilename === expectedFilename ? "match" : "mismatch";
6201
+ return {
6202
+ kind,
6203
+ path: `${module.path}/${actualFilename ?? expectedFilename}`,
6204
+ expectedPath: `${module.path}/${expectedFilename}`,
6205
+ filename: actualFilename ?? expectedFilename,
6206
+ expectedFilename,
6207
+ present,
6208
+ casing
6209
+ };
6210
+ });
6211
+ };
6212
+ var diagnosticsForFiles = (files) => files.flatMap((file) => {
6213
+ if (file.kind !== "constant" && file.kind !== "dictionary")
6214
+ return [];
6215
+ if (file.casing === "match")
6216
+ return [];
6217
+ return [
6218
+ {
6219
+ severity: "error",
6220
+ code: file.casing === "missing" ? "module-index-file-missing" : "module-index-file-casing-mismatch",
6221
+ message: file.casing === "missing" ? `Expected ${file.kind} file is missing: ${file.expectedPath}.` : `Expected ${file.expectedPath}, but found ${file.path}.`,
6222
+ context: { target: file.expectedPath, paths: [file.path, file.expectedPath] }
6223
+ }
6224
+ ];
6225
+ });
6226
+ var fieldPresence = (requestedField, constantFields, dictionaryFields, lightFields) => {
6227
+ const names = new Set([
6228
+ ...constantFields.map((field) => field.name),
6229
+ ...dictionaryFields.map((field) => field.name),
6230
+ ...lightFields.map((field) => field.name),
6231
+ ...requestedField ? [requestedField] : []
6232
+ ]);
6233
+ return [...names].sort().map((name) => ({
6234
+ name,
6235
+ requested: requestedField === name,
6236
+ constant: constantFields.some((field) => field.name === name),
6237
+ dictionary: dictionaryFields.some((field) => field.name === name),
6238
+ lightProjection: lightFields.some((field) => field.name === name)
6239
+ }));
6240
+ };
6241
+ var partialPresenceDiagnostics = (presence, module) => presence.filter((field) => field.constant !== field.dictionary || field.lightProjection && (!field.constant || !field.dictionary)).map((field) => ({
6242
+ severity: "warning",
6243
+ code: "module-index-field-presence-partial",
6244
+ message: `${module.sysName}:${module.name}.${field.name} presence differs across constant, dictionary, and lightProjection.`,
6245
+ context: {
6246
+ target: `${module.sysName}:${module.name}.${field.name}`,
6247
+ paths: [`${module.path}/${module.name}.constant.ts`, `${module.path}/${module.name}.dictionary.ts`]
6248
+ }
6249
+ }));
6250
+ var buildAkanModuleContextIndex = async (workspace, module, options = {}) => {
6251
+ const files = expectedFilesFor(module);
6252
+ const diagnostics = diagnosticsForFiles(files);
6253
+ const moduleClassName = moduleComponentName(module.name);
6254
+ const constantFile = files.find((file) => file.kind === "constant");
6255
+ const dictionaryFile = files.find((file) => file.kind === "dictionary");
6256
+ const constantContent = constantFile?.present && constantFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, constantFile.path)) : null;
6257
+ const dictionaryContent = dictionaryFile?.present && dictionaryFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, dictionaryFile.path)) : null;
6258
+ const parsedConstant = constantFile && constantContent ? parseConstantIndex(constantFile.path, constantContent, moduleClassName) : undefined;
6259
+ const constant = parsedConstant?.index;
6260
+ const parsedDictionary = dictionaryFile && dictionaryContent ? parseDictionaryIndex(dictionaryFile.path, dictionaryContent, moduleClassName) : undefined;
6261
+ const dictionary = parsedDictionary?.index;
6262
+ const presence = fieldPresence(options.field, constant?.fields ?? [], dictionary?.fields ?? [], constant?.lightProjection?.fields ?? []);
6263
+ if (constantFile?.present && constantFile.casing === "match" && !await fileExists(path10.join(workspace.workspaceRoot, constantFile.path))) {
6264
+ diagnostics.push({
6265
+ severity: "error",
6266
+ code: "module-index-file-unreadable",
6267
+ message: `Expected constant file could not be read: ${constantFile.path}.`,
6268
+ context: { paths: [constantFile.path] }
6269
+ });
6270
+ }
6271
+ if (parsedConstant)
6272
+ diagnostics.push(...parsedConstant.diagnostics);
6273
+ if (parsedDictionary)
6274
+ diagnostics.push(...parsedDictionary.diagnostics);
6275
+ if (dictionaryFile?.present && dictionaryFile.casing === "match" && !parsedDictionary?.modelFound) {
6276
+ diagnostics.push({
6277
+ severity: "error",
6278
+ code: "module-index-dictionary-model-missing",
6279
+ message: `Dictionary .model<${moduleClassName}> branch was not found in ${dictionaryFile.path}.`,
6280
+ context: { paths: [dictionaryFile.path] }
6281
+ });
6282
+ }
6283
+ diagnostics.push(...partialPresenceDiagnostics(presence, module));
6284
+ return {
6285
+ schemaVersion: 1,
6286
+ app: module.sysName,
6287
+ module: module.name,
6288
+ moduleClassName,
6289
+ files,
6290
+ fieldPresence: presence,
6291
+ ...constant ? { constant } : {},
6292
+ ...dictionary ? { dictionary } : {},
6293
+ diagnostics
6294
+ };
6295
+ };
6296
+
5532
6297
  // pkgs/@akanjs/devkit/workflow/uiPolicy.ts
5533
6298
  var addFieldUiPolicyForType = (typeName) => {
5534
6299
  const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
@@ -5593,11 +6358,18 @@ var postApplyDiagnostic = (code, message, target) => ({
5593
6358
  failureScope: "source-change",
5594
6359
  context: { target }
5595
6360
  });
6361
+ var postApplyWarning = (code, message, target) => ({
6362
+ severity: "warning",
6363
+ code,
6364
+ message,
6365
+ failureScope: "source-change",
6366
+ context: { target }
6367
+ });
5596
6368
  var sourceKindForPath = (filePath) => {
5597
6369
  if (filePath.endsWith(".tsx"))
5598
- return ts4.ScriptKind.TSX;
6370
+ return ts6.ScriptKind.TSX;
5599
6371
  if (filePath.endsWith(".ts"))
5600
- return ts4.ScriptKind.TS;
6372
+ return ts6.ScriptKind.TS;
5601
6373
  return null;
5602
6374
  };
5603
6375
  var checkPathCasing = async (workspace, filePath) => {
@@ -5625,15 +6397,15 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
5625
6397
  if (!scriptKind)
5626
6398
  return null;
5627
6399
  const content = await workspace.readFile(filePath);
5628
- const source = ts4.createSourceFile(filePath, content, ts4.ScriptTarget.Latest, true, scriptKind);
5629
- const diagnostic = source.parseDiagnostics[0];
6400
+ const source = ts6.createSourceFile(filePath, content, ts6.ScriptTarget.Latest, true, scriptKind);
6401
+ const diagnostic = (source.parseDiagnostics ?? [])[0];
5630
6402
  if (!diagnostic)
5631
6403
  return null;
5632
6404
  const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
5633
6405
  const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
5634
6406
  return {
5635
6407
  code: "workflow-post-apply-syntax-error",
5636
- message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts4.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
6408
+ message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts6.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
5637
6409
  };
5638
6410
  };
5639
6411
  var checkChangedFile = async (workspace, file) => {
@@ -5675,6 +6447,111 @@ var checkRecommendationPath = async (workspace, recommendation) => {
5675
6447
  context: { target: recommendation.target }
5676
6448
  };
5677
6449
  };
6450
+ var sourceChangeError = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
6451
+ var fieldCount = (fields, fieldName) => fields.filter((field) => field === fieldName).length;
6452
+ var fieldOrderValid = (fields, fieldName) => {
6453
+ const actualIndex = fields.indexOf(fieldName);
6454
+ if (actualIndex < 0 || fields.lastIndexOf(fieldName) !== actualIndex)
6455
+ return false;
6456
+ const fieldsWithoutRequested = fields.filter((_, index) => index !== actualIndex);
6457
+ return insertionIndexForFieldOrder(fieldsWithoutRequested, fieldName) === actualIndex;
6458
+ };
6459
+ var workflowModuleContext = async (workspace, plan) => {
6460
+ const app = workflowStringInput(plan.inputs.app);
6461
+ const moduleName = workflowStringInput(plan.inputs.module);
6462
+ if (!app || !moduleName)
6463
+ return null;
6464
+ const [apps, libs] = await workspace.getSyss();
6465
+ const sysType = apps.includes(app) ? "app" : libs.includes(app) ? "lib" : null;
6466
+ if (!sysType)
6467
+ return null;
6468
+ const modulePath = `${sysType}s/${app}/lib/${moduleName}`;
6469
+ const files = await workspace.readdir(modulePath);
6470
+ const abstractPath = `${modulePath}/${moduleName}.abstract.md`;
6471
+ return {
6472
+ kind: "domain",
6473
+ name: moduleName,
6474
+ folderName: moduleName,
6475
+ sysName: app,
6476
+ sysType,
6477
+ path: modulePath,
6478
+ abstract: {
6479
+ path: abstractPath,
6480
+ exists: files.includes(`${moduleName}.abstract.md`),
6481
+ headings: []
6482
+ },
6483
+ files
6484
+ };
6485
+ };
6486
+ var structureCheck = (code, target, status, message) => ({
6487
+ code,
6488
+ target,
6489
+ status,
6490
+ message
6491
+ });
6492
+ var checkAddFieldStructure = async (workspace, plan) => {
6493
+ if (plan.workflow !== "add-field" && plan.workflow !== "add-enum-field")
6494
+ return {};
6495
+ const app = workflowStringInput(plan.inputs.app);
6496
+ const moduleName = workflowStringInput(plan.inputs.module);
6497
+ const fieldName = workflowStringInput(plan.inputs.field);
6498
+ const typeName = workflowStringInput(plan.inputs.type);
6499
+ if (!app || !moduleName || !fieldName || !typeName)
6500
+ return {};
6501
+ const moduleContext = await workflowModuleContext(workspace, plan);
6502
+ if (!moduleContext)
6503
+ return {};
6504
+ const paths = moduleSourcePaths(moduleName);
6505
+ const constantPath = `${moduleContext.path}/${paths.constant.replace(`lib/${moduleName}/`, "")}`;
6506
+ const dictionaryPath = `${moduleContext.path}/${paths.dictionary.replace(`lib/${moduleName}/`, "")}`;
6507
+ const moduleClassName = moduleComponentName(moduleName);
6508
+ const inputClassName = `${moduleClassName}Input`;
6509
+ const index = await buildAkanModuleContextIndex(workspace, moduleContext, { field: fieldName });
6510
+ const diagnostics = [];
6511
+ const postApplyChecks = [];
6512
+ const constantContent = await workspace.readFile(constantPath);
6513
+ const constantStructure = inspectConstantStructure(constantContent, inputClassName, moduleClassName);
6514
+ const constantNames = constantStructure.fields.map((field) => field.name);
6515
+ const requestedConstantFields = constantStructure.fields.filter((field) => field.name === fieldName);
6516
+ const normalizedType = typeName.toLowerCase() === "enum" ? typeName : normalizeFieldType(typeName);
6517
+ const constantFailures = [
6518
+ !constantStructure.parseValid ? "constant file does not parse" : null,
6519
+ !constantStructure.inputObjectFound ? `${inputClassName} via builder object was not found` : null,
6520
+ requestedConstantFields.length !== 1 ? `field "${fieldName}" appears ${requestedConstantFields.length} time(s) in ${inputClassName}` : null,
6521
+ constantStructure.builderName && requestedConstantFields[0]?.expressionBuilder && requestedConstantFields[0].expressionBuilder !== constantStructure.builderName ? `field "${fieldName}" uses builder "${requestedConstantFields[0].expressionBuilder}" instead of "${constantStructure.builderName}"` : null,
6522
+ !constantStructure.builderName ? `${inputClassName} via builder parameter was not found` : null,
6523
+ (normalizedType === "Int" || normalizedType === "Float") && !constantStructure.baseImports.includes(normalizedType) ? `missing ${normalizedType} import from "akanjs/base"` : null,
6524
+ workflowBooleanInput(plan.inputs.includeInLight) === true && fieldCount(constantStructure.lightProjectionFields, fieldName) !== 1 ? `field "${fieldName}" is not present exactly once in Light${moduleClassName}` : null,
6525
+ ...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(constantPath)).map((diagnostic) => diagnostic.message)
6526
+ ].filter((failure) => failure !== null);
6527
+ const constantValid = constantFailures.length === 0;
6528
+ postApplyChecks.push(structureCheck(constantValid ? "workflow-post-apply-constant-shape-valid" : "workflow-post-apply-structure-invalid", constantPath, constantValid ? "passed" : "failed", constantValid ? `${inputClassName} keeps via structure, builder usage, imports, and requested field presence.` : constantFailures.join(" ")));
6529
+ if (!constantValid) {
6530
+ diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", constantFailures.join(" "), constantPath));
6531
+ }
6532
+ const dictionaryContent = await workspace.readFile(dictionaryPath);
6533
+ const dictionaryStructure = inspectDictionaryStructure(dictionaryContent, moduleClassName);
6534
+ const dictionaryFailures = [
6535
+ !dictionaryStructure.parseValid ? "dictionary file does not parse" : null,
6536
+ !dictionaryStructure.modelObjectFound ? `.model<${moduleClassName}> object was not found` : null,
6537
+ dictionaryStructure.modelObjectFound && !dictionaryStructure.chainOrderValid ? `.model(), .slice(), .enum(), .error(), and .translate() chain order is broken: ${dictionaryStructure.chainMethods.join(" -> ")}` : null,
6538
+ fieldCount(dictionaryStructure.fields, fieldName) !== 1 ? `field "${fieldName}" appears ${fieldCount(dictionaryStructure.fields, fieldName)} time(s) in .model<${moduleClassName}>` : null,
6539
+ ...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(dictionaryPath)).map((diagnostic) => diagnostic.message)
6540
+ ].filter((failure) => failure !== null);
6541
+ const dictionaryValid = dictionaryFailures.length === 0;
6542
+ postApplyChecks.push(structureCheck(dictionaryValid ? "workflow-post-apply-dictionary-shape-valid" : "workflow-post-apply-structure-invalid", dictionaryPath, dictionaryValid ? "passed" : "failed", dictionaryValid ? `.model<${moduleClassName}> keeps the requested field inside the model object and preserves dictionary chain order.` : dictionaryFailures.join(" ")));
6543
+ if (!dictionaryValid) {
6544
+ diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", dictionaryFailures.join(" "), dictionaryPath));
6545
+ }
6546
+ const constantOrderValid = fieldOrderValid(constantNames, fieldName);
6547
+ const dictionaryOrderValid = fieldOrderValid(dictionaryStructure.fields, fieldName);
6548
+ const orderValid = constantOrderValid && dictionaryOrderValid;
6549
+ postApplyChecks.push(structureCheck("workflow-post-apply-field-order-valid", `${constantPath}, ${dictionaryPath}`, orderValid ? "passed" : "failed", orderValid ? `Field "${fieldName}" follows the shared priority ordering policy.` : `Field "${fieldName}" is present but does not match the shared priority ordering policy.`));
6550
+ if (!orderValid) {
6551
+ diagnostics.push(postApplyWarning("workflow-post-apply-field-order-mismatch", `Field "${fieldName}" is present but does not match the shared priority ordering policy.`, `${constantPath}, ${dictionaryPath}`));
6552
+ }
6553
+ return { diagnostics, postApplyChecks };
6554
+ };
5678
6555
  var resolveWorkflowSys = async (workspace, target) => {
5679
6556
  if (!target)
5680
6557
  return null;
@@ -5711,7 +6588,7 @@ var addFieldUiSurfaceInspection = (plan) => {
5711
6588
  const policy = addFieldUiPolicyForType(typeName ?? "String");
5712
6589
  const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
5713
6590
  const templateRequested = surfaces?.includes("template") ?? false;
5714
- const moduleClassName = capitalize2(module);
6591
+ const moduleClassName = moduleComponentName(module);
5715
6592
  const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
5716
6593
  return {
5717
6594
  recommendations: [
@@ -5719,9 +6596,9 @@ var addFieldUiSurfaceInspection = (plan) => {
5719
6596
  code: "add-field-ui-surface-review",
5720
6597
  kind: "manual-action",
5721
6598
  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.`,
6599
+ action: templateRequested ? `Template was requested for ${field}. If no Template file changed, users will not see the field in the form yet because the file was missing, the generated ${module}Form/Layout.Template pattern was not found, or ${policy.component} needs option binding. Add it inside Layout.Template near existing Field components.` : `Template was not selected, so users will not see ${field} in the form from this apply. If list/card display is needed, include ${field} in Light${moduleClassName} projection data and place it in the local Unit/View card layout.`,
5723
6600
  confidence: "medium",
5724
- message: `Review UI surfaces for ${module}.${field}; recommended component is ${policy.component}, with manual reasons and candidate positions in action.`
6601
+ message: `Review user-visible UI for ${module}.${field}; recommended component is ${policy.component}.`
5725
6602
  }
5726
6603
  ],
5727
6604
  nextActions: [
@@ -5880,6 +6757,11 @@ class WorkflowExecutor {
5880
6757
  postApplyChecks.push(...result.postApplyChecks ?? []);
5881
6758
  diagnostics.push(...result.diagnostics ?? []);
5882
6759
  }
6760
+ if (!sourceChangeError(diagnostics)) {
6761
+ const result = await checkAddFieldStructure(this.workspace, plan);
6762
+ postApplyChecks.push(...result.postApplyChecks ?? []);
6763
+ diagnostics.push(...result.diagnostics ?? []);
6764
+ }
5883
6765
  const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
5884
6766
  diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
5885
6767
  }
@@ -5898,7 +6780,7 @@ class WorkflowExecutor {
5898
6780
  }
5899
6781
  }
5900
6782
  // pkgs/@akanjs/devkit/workflow/plan.ts
5901
- import { capitalize as capitalize3 } from "akanjs/common";
6783
+ import { capitalize as capitalize2 } from "akanjs/common";
5902
6784
  var surfaceModes = new Set(["infer", "include", "skip"]);
5903
6785
  var parseStringList = (value) => {
5904
6786
  if (Array.isArray(value)) {
@@ -5971,10 +6853,48 @@ var createAddFieldDefaultRecommendations = (inputs) => {
5971
6853
  kind: "manual-action",
5972
6854
  confidence: "high",
5973
6855
  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."
6856
+ action: "Review the normalized default in the apply report. To leave the field without a default, omit the default input."
5975
6857
  }
5976
6858
  ];
5977
6859
  };
6860
+ var moneyLikeFieldPattern = /(budget|price|amount|cost|rate|fee|salary|balance)/i;
6861
+ var wholeNumberFieldPattern = /(count|quantity|total|number|index|rank|order|age)/i;
6862
+ var createAddFieldInputRecommendations = (inputs) => {
6863
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
6864
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
6865
+ const recommendations = [];
6866
+ if (!typeName)
6867
+ return recommendations;
6868
+ if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric") {
6869
+ const recommendedType = moneyLikeFieldPattern.test(field) ? "Float" : wholeNumberFieldPattern.test(field) ? "Int" : null;
6870
+ recommendations.push({
6871
+ code: "add-field-type-choice",
6872
+ kind: "input-guidance",
6873
+ confidence: recommendedType ? "high" : "medium",
6874
+ message: recommendedType ? `Use ${recommendedType} for ${field}; Float is recommended for money-like decimal values and Int for whole-number values.` : `Choose Int for whole-number ${field} values or Float for decimal ${field} values.`,
6875
+ action: recommendedType ? `Re-run plan_workflow with type="${recommendedType}".` : 'Re-run plan_workflow with type="Int" or type="Float".'
6876
+ });
6877
+ }
6878
+ if (typeName.toLowerCase() === "enum" && !Array.isArray(inputs.values)) {
6879
+ recommendations.push({
6880
+ code: "add-field-enum-values",
6881
+ kind: "input-guidance",
6882
+ confidence: "high",
6883
+ message: `Enum field ${field} needs values before apply can choose valid dictionary and default behavior.`,
6884
+ action: 'Pass values as an array or comma-separated string, for example values=["draft","done"].'
6885
+ });
6886
+ }
6887
+ if (inputs.default === undefined) {
6888
+ recommendations.push({
6889
+ code: "add-field-default-optional",
6890
+ kind: "input-guidance",
6891
+ confidence: "medium",
6892
+ message: `No default will be written for ${field} because default is omitted.`,
6893
+ action: "Keep default omitted when the field should have no default value."
6894
+ });
6895
+ }
6896
+ return recommendations;
6897
+ };
5978
6898
  var createAddFieldRecommendations = (inputs) => {
5979
6899
  const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
5980
6900
  const module = typeof inputs.module === "string" ? inputs.module : "<module>";
@@ -6003,7 +6923,7 @@ var createAddFieldRecommendations = (inputs) => {
6003
6923
  kind: "placement",
6004
6924
  target: paths.constant,
6005
6925
  confidence: "high",
6006
- message: `Insert ${field}: field(${normalizedType}) in ${capitalize3(module)}Input.`
6926
+ message: `Insert ${field}: field(${normalizedType}) in ${capitalize2(module)}Input.`
6007
6927
  },
6008
6928
  {
6009
6929
  code: "add-field-placement-dictionary",
@@ -6035,9 +6955,9 @@ var createAddFieldRecommendations = (inputs) => {
6035
6955
  code: "add-field-light-projection-choice",
6036
6956
  kind: "manual-action",
6037
6957
  target: paths.constant,
6038
- action: `Pass includeInLight=true when ${field} should appear in Light${capitalize3(module)} list/card projections.`,
6958
+ action: `Pass includeInLight=true when users should see ${field} in list/card data. Without it, the field can exist on ${capitalize2(module)}Input but stay absent from Light${capitalize2(module)} projections.`,
6039
6959
  confidence: "medium",
6040
- message: `Light projection exposure for ${module}.${field} is not selected yet.`
6960
+ message: `${module}.${field} is not selected for list/card projection data.`
6041
6961
  }
6042
6962
  ] : [],
6043
6963
  ...includeInLight ? [
@@ -6046,7 +6966,7 @@ var createAddFieldRecommendations = (inputs) => {
6046
6966
  kind: "placement",
6047
6967
  target: paths.constant,
6048
6968
  confidence: "high",
6049
- message: `Add ${field} to Light${capitalize3(module)} projection fields.`
6969
+ message: `Add ${field} to Light${capitalize2(module)} projection fields.`
6050
6970
  }
6051
6971
  ] : [],
6052
6972
  ...surfaces && !templateRequested ? [
@@ -6055,18 +6975,20 @@ var createAddFieldRecommendations = (inputs) => {
6055
6975
  kind: "manual-action",
6056
6976
  target: paths.template,
6057
6977
  confidence: "medium",
6058
- message: `Template is not included in surfaces, so ${module}.${field} will not be auto-rendered there.`
6978
+ message: `Template form auto-edit is skipped for ${module}.${field} because surfaces does not include "template".`,
6979
+ action: `Pass surfaces=["template"] when users should enter ${field} in the Template form.`
6059
6980
  }
6060
6981
  ] : [],
6061
6982
  {
6062
6983
  code: "add-field-ui-manual-review",
6063
6984
  kind: "manual-action",
6064
6985
  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.`,
6986
+ action: `After apply, verify what users can see: Template form auto-edit only runs when a generated ${module}Form hook and Layout.Template field list are present. Unit/View cards are not auto-edited, so ${field} may be stored on ${capitalize2(module)} but not shown in list/card UI until you place it in the local card layout.`,
6066
6987
  confidence: "medium",
6067
- message: "UI manual review includes the reason auto-edit may be skipped and candidate insertion positions."
6988
+ message: `${app}:${module}.${field} may need UI review for user-visible Template, Unit, and View behavior.`
6068
6989
  },
6069
- ...createAddFieldDefaultRecommendations(inputs)
6990
+ ...createAddFieldDefaultRecommendations(inputs),
6991
+ ...createAddFieldInputRecommendations(inputs)
6070
6992
  ];
6071
6993
  };
6072
6994
  var createWorkflowPlanPredictedChanges = (spec, inputs) => {
@@ -6209,7 +7131,8 @@ var createWorkflowPlan = (spec, rawInputs) => {
6209
7131
  validation: spec.validation,
6210
7132
  diagnostics,
6211
7133
  recommendations: createWorkflowPlanRecommendations(spec, inputs),
6212
- requiresApproval: true
7134
+ requiresApproval: true,
7135
+ approval: workflowPlanApproval
6213
7136
  };
6214
7137
  };
6215
7138
  // pkgs/@akanjs/devkit/workflow/render.ts
@@ -6247,6 +7170,7 @@ var renderWorkflowPlan = (plan) => [
6247
7170
  "",
6248
7171
  `- Mode: ${plan.mode}`,
6249
7172
  `- Requires approval: ${plan.requiresApproval}`,
7173
+ `- Approval: ${plan.approval?.meaning ?? "Review this read-only plan before applying workflow mutations."}`,
6250
7174
  "",
6251
7175
  "## Inputs",
6252
7176
  ...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
@@ -6280,8 +7204,13 @@ var renderRecommendation = (recommendation) => {
6280
7204
  return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
6281
7205
  };
6282
7206
  var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
7207
+ var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
6283
7208
  var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
6284
7209
  var renderWorkflowApplyReport = (report) => {
7210
+ const applySummary = {
7211
+ sourceFilesChanged: report.summary?.sourceFilesChanged ?? report.changedFiles,
7212
+ generatedFilesSynced: report.summary?.generatedFilesSynced ?? report.generatedFiles
7213
+ };
6285
7214
  const manualReviewItems = [
6286
7215
  ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
6287
7216
  ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
@@ -6295,6 +7224,8 @@ var renderWorkflowApplyReport = (report) => {
6295
7224
  `- Status: ${report.status}`,
6296
7225
  `- Source-change status: ${applySourceStatus(report)}`,
6297
7226
  `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
7227
+ `- Source files changed: ${applySummary.sourceFilesChanged.length}`,
7228
+ `- Generated files queued for sync: ${applySummary.generatedFilesSynced.length}`,
6298
7229
  ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
6299
7230
  "",
6300
7231
  "## Apply Checks",
@@ -6304,10 +7235,10 @@ var renderWorkflowApplyReport = (report) => {
6304
7235
  ...sourceBlockers.length ? sourceBlockers : ["- none"],
6305
7236
  "",
6306
7237
  "## Automatically Modified",
6307
- ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7238
+ ...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6308
7239
  "",
6309
7240
  "## Generated Sync",
6310
- ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7241
+ ...applySummary.generatedFilesSynced.length ? applySummary.generatedFilesSynced.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
6311
7242
  "",
6312
7243
  "## Applied Commands",
6313
7244
  ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
@@ -6328,58 +7259,82 @@ var renderWorkflowApplyReport = (report) => {
6328
7259
  ...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
6329
7260
  "",
6330
7261
  "## Next Actions",
6331
- ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7262
+ ...report.nextActions.length ? report.nextActions.slice(0, 3).map(renderNextAction) : ["- none"],
6332
7263
  ""
6333
7264
  ].join(`
6334
7265
  `);
6335
7266
  };
6336
7267
  var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
6337
- var renderWorkflowValidationRunReport = (report) => [
6338
- `# Workflow Validation: ${report.workflow}`,
6339
- "",
6340
- `- Run: ${report.runId}`,
6341
- `- Status: ${report.status}`,
6342
- `- Source status: ${report.sourceStatus}`,
6343
- `- Workspace status: ${report.workspaceStatus}`,
6344
- `- Overall status: ${report.overallStatus}`,
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
- "",
6358
- "## Known Blockers",
6359
- ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
6360
- const command = blocker.command ? ` \`${blocker.command}\`` : "";
6361
- const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
6362
- const known = blocker.known ? " known" : "";
6363
- return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
6364
- }) : ["- none"],
6365
- "",
6366
- "## Commands",
6367
- ...report.commands.length ? report.commands.map((command) => {
6368
- const scope = command.failureScope ? ` (${command.failureScope})` : "";
6369
- return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
6370
- }) : ["- none"],
6371
- "",
6372
- "## Diagnostics",
6373
- ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
6374
- "",
6375
- "## Repair Actions",
6376
- ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
6377
- "",
6378
- "## Next Actions",
6379
- ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
6380
- ""
6381
- ].join(`
7268
+ var renderWorkflowValidationRunReport = (report) => {
7269
+ const baselineSummary = report.baselineSummary ?? {
7270
+ status: report.baselineDiagnostics?.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "unknown",
7271
+ total: report.baselineDiagnostics?.length ?? 0,
7272
+ totalErrors: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "error").length ?? 0,
7273
+ totalWarnings: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "warning").length ?? 0,
7274
+ detailsIncluded: true,
7275
+ knownBlockerCount: report.knownBlockers.filter((blocker) => blocker.known).length,
7276
+ byCode: []
7277
+ };
7278
+ return [
7279
+ `# Workflow Validation: ${report.workflow}`,
7280
+ "",
7281
+ `- Run: ${report.runId}`,
7282
+ `- Status: ${report.status}`,
7283
+ `- Source status: ${report.sourceStatus}`,
7284
+ `- Workspace status: ${report.workspaceStatus}`,
7285
+ `- Validation commands status: ${report.validationCommandsStatus ?? "unknown"}`,
7286
+ `- Baseline status: ${report.baselineStatus ?? baselineSummary.status}`,
7287
+ `- Overall status: ${report.overallStatus}`,
7288
+ "",
7289
+ "## Status Summary",
7290
+ `- Source-change: ${report.summary.sourceChange}`,
7291
+ `- Generated sync: ${report.summary.generatedSync}`,
7292
+ `- Validation commands: ${report.summary.validationCommands ?? "unknown"}`,
7293
+ `- Baseline: ${report.summary.baseline ?? baselineSummary.status}`,
7294
+ `- Workspace config: ${report.summary.workspaceConfig}`,
7295
+ `- Environment: ${report.summary.environment}`,
7296
+ "",
7297
+ "## Source Change Diagnostics",
7298
+ ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7299
+ "",
7300
+ "## Existing Workspace Blockers",
7301
+ `- Status: ${baselineSummary.status}`,
7302
+ `- Errors: ${baselineSummary.totalErrors}`,
7303
+ `- Warnings: ${baselineSummary.totalWarnings}`,
7304
+ ...baselineSummary.byCode.length ? baselineSummary.byCode.map((item) => `- [${item.severity}] ${item.code} (${item.count}x): ${item.sampleMessage}`) : ["- none"],
7305
+ ...baselineSummary.detailsIncluded ? [] : [
7306
+ "- Baseline details are summarized by default. Re-run validation with includeBaselineDetails=true for full baselineDiagnostics."
7307
+ ],
7308
+ "",
7309
+ "## Existing Workspace Blocker Details",
7310
+ ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : baselineSummary.detailsIncluded ? ["- none"] : ["- omitted"],
7311
+ "",
7312
+ "## Known Blockers",
7313
+ ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
7314
+ const command = blocker.command ? ` \`${blocker.command}\`` : "";
7315
+ const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
7316
+ const known = blocker.known ? " known" : "";
7317
+ return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
7318
+ }) : ["- none"],
7319
+ "",
7320
+ "## Commands",
7321
+ ...report.commands.length ? report.commands.map((command) => {
7322
+ const scope = command.failureScope ? ` (${command.failureScope})` : "";
7323
+ return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
7324
+ }) : ["- none"],
7325
+ "",
7326
+ "## Diagnostics",
7327
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7328
+ "",
7329
+ "## Repair Actions",
7330
+ ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7331
+ "",
7332
+ "## Next Actions",
7333
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7334
+ ""
7335
+ ].join(`
6382
7336
  `);
7337
+ };
6383
7338
  var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
6384
7339
  var renderRepairReportMarkdown = (report) => [
6385
7340
  `# Akan Repair: ${report.kind}`,
@@ -6409,6 +7364,70 @@ var renderWorkflowRunArtifact = (artifact, format = "markdown") => {
6409
7364
  }
6410
7365
  return jsonText(artifact);
6411
7366
  };
7367
+ // pkgs/@akanjs/devkit/workflow/rolloutGate.ts
7368
+ var toolingRolloutCandidates = [
7369
+ {
7370
+ packageName: "typescript",
7371
+ status: "allowed",
7372
+ role: "Primary TypeScript Compiler API baseline for AST locator, text splice, and reparse checks.",
7373
+ adoptionGate: "Already present; keep using stable Bun-compatible package builds."
7374
+ },
7375
+ {
7376
+ packageName: "@ttsc/graph",
7377
+ status: "reference-only",
7378
+ role: "Source-free graph shape and lazy resident model reference.",
7379
+ adoptionGate: "Do not add as an Akan runtime dependency without a separate proposal or milestone update."
7380
+ },
7381
+ {
7382
+ packageName: "ts-morph",
7383
+ status: "experiment-only",
7384
+ role: "Prototype candidate for complex object literal insertion, import update, and class traversal.",
7385
+ adoptionGate: "Use only in isolated prototypes until package size and formatting churn are measured."
7386
+ },
7387
+ {
7388
+ packageName: "ast-grep",
7389
+ status: "experiment-only",
7390
+ role: "Prototype candidate for shape detection, CI rules, and migration rules.",
7391
+ adoptionGate: "Use as a local rule/check experiment, not as the edit engine."
7392
+ },
7393
+ {
7394
+ packageName: "recast",
7395
+ status: "experiment-only",
7396
+ role: "Prototype candidate for formatting preservation.",
7397
+ adoptionGate: "Low priority; require proof that formatting churn is lower than the baseline."
7398
+ },
7399
+ {
7400
+ packageName: "typescript-go",
7401
+ status: "blocked",
7402
+ role: "TypeScript-Go toolchain transition placeholder.",
7403
+ adoptionGate: "Out of scope for Season 2 rollout."
7404
+ },
7405
+ {
7406
+ packageName: "@typescript/native-preview",
7407
+ status: "blocked",
7408
+ role: "TypeScript-Go native preview package placeholder.",
7409
+ adoptionGate: "Out of scope for Season 2 rollout."
7410
+ }
7411
+ ];
7412
+ var toolingRolloutGate = {
7413
+ schemaVersion: 1,
7414
+ strategy: "reference-first-dependency-later",
7415
+ dependencyPolicy: "Season 2 keeps new AST and graph tooling as references or isolated experiments until a separate proposal or milestone update approves adoption.",
7416
+ gateConditions: [
7417
+ "Works in Bun runtime and published package artifacts.",
7418
+ "Does not break dist/pkgs package verification.",
7419
+ "Keeps generated source formatting churn limited.",
7420
+ "Reduces add-field regression fixture failures compared with the current TypeScript API baseline.",
7421
+ "Does not move MCP responses toward returning source bodies."
7422
+ ],
7423
+ candidates: toolingRolloutCandidates
7424
+ };
7425
+ var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
7426
+ var restrictedCandidates = new Map;
7427
+ for (const candidate of toolingRolloutCandidates) {
7428
+ if (isRestrictedCandidate(candidate))
7429
+ restrictedCandidates.set(candidate.packageName, candidate);
7430
+ }
6412
7431
  // pkgs/@akanjs/devkit/akanContext.ts
6413
7432
  var resourceList = [
6414
7433
  { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
@@ -6551,7 +7570,7 @@ var planInputString = (plan2, key) => {
6551
7570
  var expandWorkflowTarget = (target, plan2) => {
6552
7571
  const app = planInputString(plan2, "app");
6553
7572
  const module = planInputString(plan2, "module");
6554
- const moduleClass = module ? capitalize4(module) : "<Module>";
7573
+ const moduleClass = module ? capitalize3(module) : "<Module>";
6555
7574
  return target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass);
6556
7575
  };
6557
7576
  var workflowPathsForPlan = (plan2) => plan2.predictedChanges.map((change) => expandWorkflowTarget(change.target, plan2));
@@ -6573,8 +7592,8 @@ var loadWorkflowContextPaths = async (workspace, runIdOrPlan, changedFiles) => {
6573
7592
  const paths = [...changedFiles];
6574
7593
  if (!runIdOrPlan)
6575
7594
  return paths;
6576
- const inputPath = path10.isAbsolute(runIdOrPlan) ? runIdOrPlan : path10.join(workspace.workspaceRoot, runIdOrPlan);
6577
- const artifact = await safeReadJson(inputPath) ?? await safeReadJson(path10.join(workspace.workspaceRoot, workflowRunArtifactPath(runIdOrPlan)));
7595
+ const inputPath = path11.isAbsolute(runIdOrPlan) ? runIdOrPlan : path11.join(workspace.workspaceRoot, runIdOrPlan);
7596
+ const artifact = await safeReadJson(inputPath) ?? await safeReadJson(path11.join(workspace.workspaceRoot, workflowRunArtifactPath(runIdOrPlan)));
6578
7597
  if (artifact && isWorkflowRunArtifact(artifact))
6579
7598
  paths.push(...workflowPathsForArtifact(artifact));
6580
7599
  return [...new Set(paths.filter(Boolean))];
@@ -6592,9 +7611,9 @@ var isWorkflowRelatedDiagnostic = (diagnostic, workflowPaths) => {
6592
7611
  });
6593
7612
  };
6594
7613
  var readGeneratedSyncStates = async (workspace) => {
6595
- const syncDir = path10.join(workspace.workspaceRoot, workflowSyncDir);
7614
+ const syncDir = path11.join(workspace.workspaceRoot, workflowSyncDir);
6596
7615
  const entries = await safeReadDir(syncDir);
6597
- const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(path10.join(syncDir, entry.name))));
7616
+ const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(path11.join(syncDir, entry.name))));
6598
7617
  return states.filter((state) => !!state && state.schemaVersion === 1 && typeof state.target === "string" && typeof state.syncedAt === "string");
6599
7618
  };
6600
7619
  var generatedFreshnessFromStates = async (workspace) => {
@@ -6631,12 +7650,12 @@ var parseAbstractSummary = (relativePath, content, includeContent) => {
6631
7650
  };
6632
7651
  };
6633
7652
  var readFiles = async (dirPath) => (await safeReadDir(dirPath)).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
6634
- var getRelative = (workspace, absolutePath) => path10.relative(workspace.workspaceRoot, absolutePath).replaceAll(path10.sep, "/");
7653
+ var getRelative = (workspace, absolutePath) => path11.relative(workspace.workspaceRoot, absolutePath).replaceAll(path11.sep, "/");
6635
7654
  var createModuleContext = async (workspace, sys2, kind, folderName, moduleName, includeAbstractContent) => {
6636
- const modulePath = kind === "scalar" ? path10.join(sys2.cwdPath, "lib", "__scalar", moduleName) : path10.join(sys2.cwdPath, "lib", folderName);
7655
+ const modulePath = kind === "scalar" ? path11.join(sys2.cwdPath, "lib", "__scalar", moduleName) : path11.join(sys2.cwdPath, "lib", folderName);
6637
7656
  const relativePath = getRelative(workspace, modulePath);
6638
7657
  const abstractPath = `${relativePath}/${moduleName}.abstract.md`;
6639
- const abstractContent = await safeReadText(path10.join(workspace.workspaceRoot, abstractPath));
7658
+ const abstractContent = await safeReadText(path11.join(workspace.workspaceRoot, abstractPath));
6640
7659
  return {
6641
7660
  kind,
6642
7661
  name: moduleName,
@@ -6652,7 +7671,7 @@ var getSysModules = async (workspace, sys2, {
6652
7671
  includeAbstractContent = false,
6653
7672
  module: moduleFilter
6654
7673
  } = {}) => {
6655
- const libPath = path10.join(sys2.cwdPath, "lib");
7674
+ const libPath = path11.join(sys2.cwdPath, "lib");
6656
7675
  const entries = await safeReadDir(libPath);
6657
7676
  const modules = [];
6658
7677
  for (const entry of entries) {
@@ -6666,24 +7685,24 @@ var getSysModules = async (workspace, sys2, {
6666
7685
  const serviceName = entry.name.replace(/^_+/, "");
6667
7686
  if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
6668
7687
  continue;
6669
- if (!await FileSys.fileExists(path10.join(libPath, entry.name, `${serviceName}.service.ts`)))
7688
+ if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${serviceName}.service.ts`)))
6670
7689
  continue;
6671
7690
  modules.push(await createModuleContext(workspace, sys2, "service", entry.name, serviceName, includeAbstractContent));
6672
7691
  } else {
6673
7692
  if (moduleFilter && moduleFilter !== entry.name)
6674
7693
  continue;
6675
- if (!await FileSys.fileExists(path10.join(libPath, entry.name, `${entry.name}.constant.ts`)))
7694
+ if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${entry.name}.constant.ts`)))
6676
7695
  continue;
6677
7696
  modules.push(await createModuleContext(workspace, sys2, "domain", entry.name, entry.name, includeAbstractContent));
6678
7697
  }
6679
7698
  }
6680
- const scalarRoot = path10.join(libPath, "__scalar");
7699
+ const scalarRoot = path11.join(libPath, "__scalar");
6681
7700
  for (const entry of await safeReadDir(scalarRoot)) {
6682
7701
  if (!entry.isDirectory() || entry.name.startsWith("_"))
6683
7702
  continue;
6684
7703
  if (moduleFilter && moduleFilter !== entry.name)
6685
7704
  continue;
6686
- if (!await FileSys.fileExists(path10.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
7705
+ if (!await FileSys.fileExists(path11.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
6687
7706
  continue;
6688
7707
  modules.push(await createModuleContext(workspace, sys2, "scalar", entry.name, entry.name, includeAbstractContent));
6689
7708
  }
@@ -6695,7 +7714,7 @@ var getSysContext = async (workspace, type, name, options) => {
6695
7714
  type,
6696
7715
  name,
6697
7716
  path: `${type}s/${name}`,
6698
- hasConfig: await FileSys.fileExists(path10.join(sys2.cwdPath, "akan.config.ts")),
7717
+ hasConfig: await FileSys.fileExists(path11.join(sys2.cwdPath, "akan.config.ts")),
6699
7718
  modules: await getSysModules(workspace, sys2, {
6700
7719
  includeAbstractContent: options.includeAbstractContent,
6701
7720
  module: options.module
@@ -6706,13 +7725,13 @@ var getSysContext = async (workspace, type, name, options) => {
6706
7725
  class AkanContextAnalyzer {
6707
7726
  static async analyze(workspace, options = {}) {
6708
7727
  const [appNames, libNames, pkgNames] = await workspace.getExecs();
6709
- const rootPackageJson = await safeReadJson(path10.join(workspace.workspaceRoot, "package.json"));
7728
+ const rootPackageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "package.json"));
6710
7729
  const filteredApps = options.app ? appNames.filter((name) => name === options.app) : appNames;
6711
7730
  const [apps, libs, pkgs] = await Promise.all([
6712
7731
  Promise.all(filteredApps.map((name) => getSysContext(workspace, "app", name, options))),
6713
7732
  Promise.all(libNames.map((name) => getSysContext(workspace, "lib", name, options))),
6714
7733
  Promise.all(pkgNames.map(async (name) => {
6715
- const packageJson = await safeReadJson(path10.join(workspace.workspaceRoot, "pkgs", name, "package.json"));
7734
+ const packageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "pkgs", name, "package.json"));
6716
7735
  return {
6717
7736
  name,
6718
7737
  path: `pkgs/${name}`,
@@ -6745,7 +7764,7 @@ class AkanContextAnalyzer {
6745
7764
  repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
6746
7765
  ];
6747
7766
  for (const app of context.apps) {
6748
- const appPath = path10.join(workspace.workspaceRoot, app.path);
7767
+ const appPath = path11.join(workspace.workspaceRoot, app.path);
6749
7768
  for (const entry of await safeReadDir(appPath)) {
6750
7769
  const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
6751
7770
  if (!allowed) {
@@ -6769,7 +7788,7 @@ class AkanContextAnalyzer {
6769
7788
  severity: strict ? "error" : "warning",
6770
7789
  code: "module-abstract-missing",
6771
7790
  path: module.abstract.path,
6772
- message: `${capitalize4(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`,
7791
+ message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`,
6773
7792
  repairActions: [action]
6774
7793
  });
6775
7794
  repairActions.push(action);
@@ -6781,14 +7800,14 @@ class AkanContextAnalyzer {
6781
7800
  severity: "error",
6782
7801
  code: "module-shape-invalid",
6783
7802
  path: module.path,
6784
- message: `${capitalize4(module.kind)} module ${sys2.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
7803
+ message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
6785
7804
  repairActions: [action]
6786
7805
  });
6787
7806
  repairActions.push(action);
6788
7807
  }
6789
7808
  if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
6790
- const constantPath = path10.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
6791
- const dictionaryPath = path10.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
7809
+ const constantPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
7810
+ const dictionaryPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
6792
7811
  const [constantContent, dictionaryContent] = await Promise.all([
6793
7812
  safeReadText(constantPath),
6794
7813
  safeReadText(dictionaryPath)
@@ -6860,6 +7879,543 @@ class AkanContextAnalyzer {
6860
7879
  `;
6861
7880
  }
6862
7881
  }
7882
+ // pkgs/@akanjs/devkit/akanMcpContract.ts
7883
+ import path12 from "path";
7884
+ var emptySchema = { type: "object", properties: {} };
7885
+ var stringProperty = { type: "string" };
7886
+ var booleanProperty = { type: "boolean" };
7887
+ var objectProperty = { type: "object", additionalProperties: true };
7888
+ var stringArrayProperty = { type: "array", items: stringProperty };
7889
+ var inspectAkanContextRequestTypes = [
7890
+ "workspaceOverview",
7891
+ "moduleContext",
7892
+ "fieldInsertionContext",
7893
+ "workflowDiagnostics",
7894
+ "escape"
7895
+ ];
7896
+ var inspectAkanContextRequestTypeProperty = { type: "string", enum: inspectAkanContextRequestTypes };
7897
+ var inspectAkanContextRequestBranches = [
7898
+ {
7899
+ type: "object",
7900
+ properties: { type: { const: "workspaceOverview" } },
7901
+ required: ["type"]
7902
+ },
7903
+ {
7904
+ type: "object",
7905
+ properties: { type: { const: "moduleContext" }, app: stringProperty, module: stringProperty },
7906
+ required: ["type", "app", "module"]
7907
+ },
7908
+ {
7909
+ type: "object",
7910
+ properties: {
7911
+ type: { const: "fieldInsertionContext" },
7912
+ app: stringProperty,
7913
+ module: stringProperty,
7914
+ field: stringProperty,
7915
+ fieldType: stringProperty
7916
+ },
7917
+ required: ["type", "app", "module", "field", "fieldType"]
7918
+ },
7919
+ {
7920
+ type: "object",
7921
+ properties: { type: { const: "workflowDiagnostics" }, runIdOrPlan: stringProperty },
7922
+ required: ["type", "runIdOrPlan"]
7923
+ },
7924
+ {
7925
+ type: "object",
7926
+ properties: { type: { const: "escape" }, reason: stringProperty, nextStep: stringProperty },
7927
+ required: ["type", "reason"]
7928
+ }
7929
+ ];
7930
+ var inspectAkanContextInputSchema = {
7931
+ type: "object",
7932
+ properties: {
7933
+ question: {
7934
+ ...stringProperty,
7935
+ description: "The user-facing question the agent is trying to answer before reading source bodies."
7936
+ },
7937
+ draft: {
7938
+ type: "object",
7939
+ properties: {
7940
+ reason: stringProperty,
7941
+ type: inspectAkanContextRequestTypeProperty
7942
+ },
7943
+ required: ["reason", "type"]
7944
+ },
7945
+ review: {
7946
+ ...stringProperty,
7947
+ description: "A short self-review explaining why this minimal request is sufficient."
7948
+ },
7949
+ request: {
7950
+ type: "object",
7951
+ properties: {
7952
+ type: inspectAkanContextRequestTypeProperty,
7953
+ app: stringProperty,
7954
+ module: stringProperty,
7955
+ field: stringProperty,
7956
+ fieldType: stringProperty,
7957
+ runIdOrPlan: stringProperty,
7958
+ reason: stringProperty,
7959
+ nextStep: stringProperty
7960
+ },
7961
+ required: ["type"],
7962
+ oneOf: inspectAkanContextRequestBranches
7963
+ }
7964
+ },
7965
+ required: ["question", "draft", "review", "request"]
7966
+ };
7967
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7968
+ var slugPart = (value) => typeof value === "string" ? value.trim().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() : "";
7969
+ var optionalString = (args, key) => {
7970
+ const value = args[key];
7971
+ return typeof value === "string" && value ? value : undefined;
7972
+ };
7973
+ var nestedStringArg = (args, key) => {
7974
+ const value = args[key];
7975
+ if (typeof value !== "string" || !value)
7976
+ throw new Error(`MCP tool argument "${key}" is required.`);
7977
+ return value;
7978
+ };
7979
+ var isInspectAkanContextRequestType = (value) => typeof value === "string" && inspectAkanContextRequestTypes.includes(value);
7980
+ var parseJsonOutput = (output) => JSON.parse(output);
7981
+ var workspacePath = (workspace, filePath) => path12.isAbsolute(filePath) ? filePath : path12.join(workspace.workspaceRoot, filePath);
7982
+ var defaultWorkflowPlanPath = (workflow, inputs) => {
7983
+ const slug = [
7984
+ slugPart(workflow),
7985
+ slugPart(inputs.app),
7986
+ slugPart(inputs.module),
7987
+ slugPart(inputs.field),
7988
+ slugPart(inputs.scalar),
7989
+ slugPart(inputs.surface),
7990
+ slugPart(inputs.mutation),
7991
+ slugPart(inputs.slice)
7992
+ ].filter(Boolean).join("-");
7993
+ return `.akan/workflows/plans/${slug || "workflow-plan"}.json`;
7994
+ };
7995
+ var applyFirstPolicy = {
7996
+ mode: "apply-first",
7997
+ directSourceEdits: "fallback-only",
7998
+ applyRequiredWhen: ["plan_workflow returns planPath", "plan_workflow returns next.tool=apply_workflow"],
7999
+ approvalMeaning: "requiresApproval is an agent/user review signal before apply_workflow mutates files; it is not a separate MCP permission gate.",
8000
+ validationRequiredAfterApply: ["validationTarget", "applyReportPath"],
8001
+ fallbackAllowedWhen: [
8002
+ "list_workflows and explain_workflow show no matching workflow",
8003
+ "apply_workflow reports unsupported/no-op/failed diagnostics that require manual action",
8004
+ "recommendations include manual-action follow-up after workflow apply and repairs"
8005
+ ],
8006
+ baselineDiagnosticsPolicy: "Do not fix unrelated baselineDiagnostics unless the user asks."
8007
+ };
8008
+ var stringArg = (args, key) => {
8009
+ const value = args[key];
8010
+ if (typeof value !== "string" || !value)
8011
+ throw new Error(`MCP tool argument "${key}" is required.`);
8012
+ return value;
8013
+ };
8014
+ var workflowInputsArg = (args) => {
8015
+ const value = args.inputs;
8016
+ if (!value || typeof value !== "object" || Array.isArray(value))
8017
+ return {};
8018
+ return value;
8019
+ };
8020
+ var inspectAkanContextPropsArg = (args) => {
8021
+ const question = stringArg(args, "question");
8022
+ const review = stringArg(args, "review");
8023
+ if (!isRecord(args.draft))
8024
+ throw new Error('MCP tool argument "draft" is required.');
8025
+ if (!isRecord(args.request))
8026
+ throw new Error('MCP tool argument "request" is required.');
8027
+ if (!isInspectAkanContextRequestType(args.draft.type)) {
8028
+ throw new Error('MCP tool argument "draft.type" must be a supported inspect_akan_context request type.');
8029
+ }
8030
+ if (!isInspectAkanContextRequestType(args.request.type)) {
8031
+ throw new Error('MCP tool argument "request.type" must be a supported inspect_akan_context request type.');
8032
+ }
8033
+ const draft = { reason: nestedStringArg(args.draft, "reason"), type: args.draft.type };
8034
+ const request = args.request;
8035
+ if (request.type === "workspaceOverview")
8036
+ return { question, draft, review, request: { type: request.type } };
8037
+ if (request.type === "moduleContext")
8038
+ return {
8039
+ question,
8040
+ draft,
8041
+ review,
8042
+ request: {
8043
+ type: request.type,
8044
+ app: nestedStringArg(request, "app"),
8045
+ module: nestedStringArg(request, "module")
8046
+ }
8047
+ };
8048
+ if (request.type === "fieldInsertionContext")
8049
+ return {
8050
+ question,
8051
+ draft,
8052
+ review,
8053
+ request: {
8054
+ type: request.type,
8055
+ app: nestedStringArg(request, "app"),
8056
+ module: nestedStringArg(request, "module"),
8057
+ field: nestedStringArg(request, "field"),
8058
+ fieldType: nestedStringArg(request, "fieldType")
8059
+ }
8060
+ };
8061
+ if (request.type === "workflowDiagnostics")
8062
+ return {
8063
+ question,
8064
+ draft,
8065
+ review,
8066
+ request: { type: request.type, runIdOrPlan: nestedStringArg(request, "runIdOrPlan") }
8067
+ };
8068
+ return {
8069
+ question,
8070
+ draft,
8071
+ review,
8072
+ request: {
8073
+ type: "escape",
8074
+ reason: nestedStringArg(request, "reason"),
8075
+ nextStep: optionalString(request, "nextStep")
8076
+ }
8077
+ };
8078
+ };
8079
+ var inspectDiagnostic = (severity, code, message) => ({ severity, code, message });
8080
+ var moduleEvidence = (module) => ({
8081
+ kind: "module",
8082
+ target: `${module.sysName}:${module.name}`,
8083
+ path: module.path,
8084
+ summary: `${module.kind} module at ${module.path} with ${module.files.length} source file(s).`
8085
+ });
8086
+ var moduleCandidate = (module) => ({
8087
+ app: module.sysName,
8088
+ sysType: module.sysType,
8089
+ module: module.name,
8090
+ kind: module.kind,
8091
+ path: module.path,
8092
+ files: module.files
8093
+ });
8094
+ var readonlyMcpTools = [
8095
+ {
8096
+ name: "inspect_akan_context",
8097
+ description: "Read-only typed context inspection. Use question -> draft -> review -> request before source body reads; choose fieldInsertionContext for add-field evidence and escape when source body or outside evidence is required.",
8098
+ inputSchema: inspectAkanContextInputSchema
8099
+ },
8100
+ {
8101
+ name: "get_workspace_summary",
8102
+ description: "Legacy broad workspace summary. Prefer inspect_akan_context.workspaceOverview for typed source-body-free evidence.",
8103
+ inputSchema: emptySchema
8104
+ },
8105
+ {
8106
+ name: "list_apps",
8107
+ description: "List Akan apps from the workspace context without reading source bodies.",
8108
+ inputSchema: emptySchema
8109
+ },
8110
+ {
8111
+ name: "list_modules",
8112
+ description: "List Akan modules across apps and libs; use inspect_akan_context.moduleContext for typed evidence.",
8113
+ inputSchema: emptySchema
8114
+ },
8115
+ {
8116
+ name: "get_module_context",
8117
+ description: "Legacy broad module context. Pass app in monorepos; prefer inspect_akan_context.moduleContext or fieldInsertionContext for typed add-field evidence.",
8118
+ inputSchema: { type: "object", properties: { app: stringProperty, module: stringProperty }, required: ["module"] }
8119
+ },
8120
+ {
8121
+ name: "get_guideline",
8122
+ description: "Return an Akan agent guideline resource by name.",
8123
+ inputSchema: { type: "object", properties: { name: stringProperty }, required: ["name"] }
8124
+ },
8125
+ {
8126
+ name: "explain_command",
8127
+ description: "Explain one Akan CLI command and its agent-facing workflow policy.",
8128
+ inputSchema: { type: "object", properties: { command: stringProperty }, required: ["command"] }
8129
+ },
8130
+ {
8131
+ name: "doctor_workspace",
8132
+ description: "Report workspace diagnostics, optionally split into baseline and workflow scopes.",
8133
+ inputSchema: {
8134
+ type: "object",
8135
+ properties: {
8136
+ strict: booleanProperty,
8137
+ runIdOrPlan: stringProperty,
8138
+ changedFiles: stringArrayProperty,
8139
+ includeBaselineDetails: booleanProperty
8140
+ }
8141
+ }
8142
+ },
8143
+ {
8144
+ name: "get_validation_contract",
8145
+ description: "Return validation, artifact chain, and apply-first fallback policy.",
8146
+ inputSchema: emptySchema
8147
+ }
8148
+ ];
8149
+ var planMcpTools = [
8150
+ {
8151
+ name: "list_workflows",
8152
+ description: "List available read-only workflow specs before creating a plan.",
8153
+ inputSchema: emptySchema
8154
+ },
8155
+ {
8156
+ name: "explain_workflow",
8157
+ description: "Explain one workflow's inputs, predicted changes, validation, and completion criteria.",
8158
+ inputSchema: { type: "object", properties: { workflow: stringProperty }, required: ["workflow"] }
8159
+ },
8160
+ {
8161
+ name: "plan_workflow",
8162
+ description: "Create a read-only workflow plan after context inspection and return planPath plus next.tool=apply_workflow.",
8163
+ inputSchema: {
8164
+ type: "object",
8165
+ properties: { workflow: stringProperty, inputs: objectProperty, out: stringProperty },
8166
+ required: ["workflow"]
8167
+ }
8168
+ }
8169
+ ];
8170
+ var applyMcpTools = [
8171
+ {
8172
+ name: "apply_workflow",
8173
+ description: "Apply a stored workflow plan before direct edits and return validationTarget for run_validation.",
8174
+ inputSchema: {
8175
+ type: "object",
8176
+ properties: { planPath: stringProperty, dryRun: booleanProperty },
8177
+ required: ["planPath"]
8178
+ }
8179
+ },
8180
+ {
8181
+ name: "run_validation",
8182
+ description: "Validate a plan, apply report, validationTarget, or run artifact.",
8183
+ inputSchema: {
8184
+ type: "object",
8185
+ properties: { runIdOrPlan: stringProperty, includeBaselineDetails: booleanProperty },
8186
+ required: ["runIdOrPlan"]
8187
+ }
8188
+ },
8189
+ {
8190
+ name: "repair_generated",
8191
+ description: "Refresh generated Akan files before direct generated-file edits.",
8192
+ inputSchema: { type: "object", properties: { app: stringProperty }, required: ["app"] }
8193
+ },
8194
+ {
8195
+ name: "repair_imports",
8196
+ description: "Run the import repair path before manual import edits.",
8197
+ inputSchema: { type: "object", properties: { target: stringProperty }, required: ["target"] }
8198
+ },
8199
+ {
8200
+ name: "repair_module_shape",
8201
+ description: "Report module-shape repair actions before direct module file fixes.",
8202
+ inputSchema: {
8203
+ type: "object",
8204
+ properties: { app: stringProperty, module: stringProperty },
8205
+ required: ["app", "module"]
8206
+ }
8207
+ }
8208
+ ];
8209
+ var listAkanMcpTools = (mode = "readonly") => {
8210
+ if (mode === "readonly")
8211
+ return readonlyMcpTools;
8212
+ if (mode === "plan")
8213
+ return [...readonlyMcpTools, ...planMcpTools];
8214
+ return [...readonlyMcpTools, ...planMcpTools, ...applyMcpTools];
8215
+ };
8216
+ var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
8217
+ schemaVersion: 1,
8218
+ reports: ["WorkflowPlan", "WorkflowApplyReport", "WorkflowValidationRunReport", "RepairReport"],
8219
+ modes: {
8220
+ readonly: listTools("readonly").map((tool) => tool.name),
8221
+ plan: listTools("plan").map((tool) => tool.name),
8222
+ apply: listTools("apply").map((tool) => tool.name)
8223
+ },
8224
+ validationCommands: [
8225
+ "akan workflow validate <run-id-or-plan> --format json",
8226
+ "akan workflow report <run-id> --format json",
8227
+ "akan doctor --strict --format json"
8228
+ ],
8229
+ validationFailureScopes: ["workspace-config", "environment", "source-change", "unknown"],
8230
+ artifactChainFields: ["planPath", "applyReportPath", "repairReportPath", "runId", "validationTarget", "next"],
8231
+ diagnosticScopes: ["baseline", "workflow", "unknown"],
8232
+ validationStatuses: {
8233
+ sourceStatus: ["passed", "failed", "unknown"],
8234
+ workspaceStatus: ["passed", "failed", "unknown"],
8235
+ validationCommandsStatus: ["passed", "failed", "unknown"],
8236
+ baselineStatus: ["passed", "failed", "unknown"],
8237
+ overallStatus: [
8238
+ "passed",
8239
+ "failed",
8240
+ "passed-with-baseline-blockers",
8241
+ "blocked-by-workspace-config",
8242
+ "blocked-by-environment"
8243
+ ],
8244
+ baselineSummary: "Default MCP validation output summarizes baseline diagnostics; pass includeBaselineDetails=true for full baselineDiagnostics.",
8245
+ knownBlockers: "Repeated workspace-config/environment failures are summarized before command output."
8246
+ },
8247
+ moduleContextInputs: {
8248
+ module: "required",
8249
+ app: "required"
8250
+ },
8251
+ generatedFreshnessStatuses: ["fresh", "stale", "missing", "unknown"],
8252
+ toolingRolloutGate,
8253
+ directEditFallbackPolicy: applyFirstPolicy,
8254
+ applyReportFields: [
8255
+ "summary",
8256
+ "appliedCommands",
8257
+ "recommendedValidationCommands",
8258
+ "commands",
8259
+ "recommendations",
8260
+ "validationTarget"
8261
+ ],
8262
+ repairCommands: [
8263
+ "akan repair generated --app <app-or-lib> --format json",
8264
+ "akan repair format --target <app-or-lib-or-pkg> --format json",
8265
+ "akan repair imports --target <app-or-lib-or-pkg> --format json",
8266
+ "akan repair dictionary --app <app-or-lib> --module <module> --format json",
8267
+ "akan repair module-shape --app <app-or-lib> --module <module> --format json"
8268
+ ]
8269
+ });
8270
+ var inspectAkanContext = async (workspace, args) => {
8271
+ const props = inspectAkanContextPropsArg(args);
8272
+ const diagnostics = [];
8273
+ if (props.draft.type !== props.request.type) {
8274
+ diagnostics.push(inspectDiagnostic("warning", "inspect-draft-request-mismatch", `Draft chose ${props.draft.type}, but request uses ${props.request.type}.`));
8275
+ }
8276
+ const baseResult = (type, evidence, next, data) => ({
8277
+ schemaVersion: 1,
8278
+ type,
8279
+ question: props.question,
8280
+ diagnostics,
8281
+ evidence,
8282
+ next,
8283
+ ...data ? { data } : {}
8284
+ });
8285
+ if (props.request.type === "escape") {
8286
+ return baseResult("escape", [{ kind: "escape", summary: props.request.reason }], {
8287
+ action: "escape",
8288
+ reason: props.request.reason,
8289
+ ...props.request.nextStep ? { args: { nextStep: props.request.nextStep } } : {}
8290
+ }, { reason: props.request.reason, nextStep: props.request.nextStep ?? null });
8291
+ }
8292
+ if (props.request.type === "workflowDiagnostics") {
8293
+ const doctor = await AkanContextAnalyzer.doctor(workspace, {
8294
+ strict: true,
8295
+ runIdOrPlan: workspacePath(workspace, props.request.runIdOrPlan)
8296
+ });
8297
+ const baselineSummary = createWorkflowBaselineSummary((doctor.baselineDiagnostics ?? []).map((diagnostic) => ({
8298
+ severity: diagnostic.severity,
8299
+ code: diagnostic.code,
8300
+ message: diagnostic.message,
8301
+ scope: diagnostic.scope,
8302
+ context: diagnostic.context
8303
+ })), { detailsIncluded: false });
8304
+ diagnostics.push(...(doctor.workflowDiagnostics ?? doctor.diagnostics).map((diagnostic) => ({
8305
+ severity: diagnostic.severity,
8306
+ code: diagnostic.code,
8307
+ message: diagnostic.message,
8308
+ scope: diagnostic.scope,
8309
+ context: {
8310
+ ...diagnostic.context,
8311
+ ...diagnostic.path ? { paths: [diagnostic.path] } : {}
8312
+ }
8313
+ })));
8314
+ return baseResult("workflowDiagnostics", [
8315
+ {
8316
+ kind: "workflow",
8317
+ target: props.request.runIdOrPlan,
8318
+ summary: `Workflow diagnostics status is ${doctor.status}.`
8319
+ }
8320
+ ], {
8321
+ action: doctor.status === "passed" ? "answer" : "validate",
8322
+ reason: doctor.status === "passed" ? "No strict workspace diagnostics were found for the workflow context." : "Review diagnostics before applying or manually editing source files."
8323
+ }, {
8324
+ status: doctor.status,
8325
+ baselineSummary,
8326
+ baselineDiagnostics: 0,
8327
+ workflowDiagnostics: doctor.workflowDiagnostics?.length ?? 0
8328
+ });
8329
+ }
8330
+ const context = await AkanContextAnalyzer.analyze(workspace, {
8331
+ app: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.app : null,
8332
+ module: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.module : null,
8333
+ includeAbstractContent: false
8334
+ });
8335
+ if (props.request.type === "workspaceOverview") {
8336
+ return baseResult("workspaceOverview", [
8337
+ {
8338
+ kind: "workspace",
8339
+ summary: `${context.repoName} has ${context.apps.length} app(s), ${context.libs.length} lib(s), and ${context.pkgs.length} package(s).`
8340
+ }
8341
+ ], {
8342
+ action: "inspect",
8343
+ reason: "Choose moduleContext or fieldInsertionContext for module-scoped evidence before planning a workflow.",
8344
+ tool: "inspect_akan_context"
8345
+ }, {
8346
+ repoName: context.repoName,
8347
+ apps: context.apps.map((app) => ({ name: app.name, path: app.path, modules: app.modules.length })),
8348
+ libs: context.libs.map((lib) => ({ name: lib.name, path: lib.path, modules: lib.modules.length })),
8349
+ pkgs: context.pkgs.map((pkg) => ({ name: pkg.name, path: pkg.path, version: pkg.version ?? null })),
8350
+ generatedFiles: context.generatedFiles,
8351
+ validationCommands: context.validationCommands
8352
+ });
8353
+ }
8354
+ const modules = AkanContextAnalyzer.findModules(context, props.request.module, {
8355
+ app: props.request.app ?? null
8356
+ });
8357
+ if (modules.length === 0) {
8358
+ diagnostics.push(inspectDiagnostic("error", "inspect-module-not-found", `No module matched ${props.request.app ? `${props.request.app}:` : ""}${props.request.module}.`));
8359
+ return baseResult(props.request.type, [], {
8360
+ action: "escape",
8361
+ reason: "The requested module was not found in the workspace index; inspect workspace files or clarify the target."
8362
+ }, { candidates: [] });
8363
+ }
8364
+ if (!props.request.app && modules.length > 1) {
8365
+ diagnostics.push(inspectDiagnostic("error", "inspect-module-ambiguous", `Multiple modules match "${props.request.module}". Re-run with app to disambiguate.`));
8366
+ return baseResult(props.request.type, modules.map(moduleEvidence), {
8367
+ action: "clarify",
8368
+ reason: "Multiple modules have the same name; choose an app before planning a workflow."
8369
+ }, { candidates: modules.map(moduleCandidate) });
8370
+ }
8371
+ const module = modules[0];
8372
+ if (props.request.type === "moduleContext") {
8373
+ return baseResult("moduleContext", [moduleEvidence(module)], {
8374
+ action: "inspect",
8375
+ reason: "Use fieldInsertionContext when preparing add-field or escape when source body details are required.",
8376
+ tool: "inspect_akan_context"
8377
+ }, { module: moduleCandidate(module) });
8378
+ }
8379
+ if (module.kind !== "domain") {
8380
+ diagnostics.push(inspectDiagnostic("error", "field-insertion-unsupported-module-kind", `fieldInsertionContext currently targets domain modules; ${module.sysName}:${module.name} is ${module.kind}.`));
8381
+ }
8382
+ const moduleIndex2 = await buildAkanModuleContextIndex(workspace, module, { field: props.request.field });
8383
+ diagnostics.push(...moduleIndex2.diagnostics);
8384
+ return baseResult("fieldInsertionContext", [
8385
+ moduleEvidence(module),
8386
+ {
8387
+ kind: "field-insertion",
8388
+ target: `${module.sysName}:${module.name}.${props.request.field}`,
8389
+ path: module.path,
8390
+ summary: "M2 returns source-body-free AST index evidence for constant fields, dictionary model labels, and light projection fields."
8391
+ }
8392
+ ], module.kind === "domain" ? {
8393
+ action: "plan_workflow",
8394
+ reason: "The module target is unambiguous; create an add-field workflow plan before source edits.",
8395
+ tool: "plan_workflow",
8396
+ args: {
8397
+ workflow: "add-field",
8398
+ inputs: {
8399
+ app: module.sysName,
8400
+ module: module.name,
8401
+ field: props.request.field,
8402
+ type: props.request.fieldType
8403
+ }
8404
+ }
8405
+ } : {
8406
+ action: "escape",
8407
+ reason: "This module kind is not a supported add-field target in the P1 context contract."
8408
+ }, {
8409
+ target: {
8410
+ app: module.sysName,
8411
+ module: module.name,
8412
+ field: props.request.field,
8413
+ fieldType: props.request.fieldType
8414
+ },
8415
+ files: moduleIndex2.files,
8416
+ moduleIndex: moduleIndex2
8417
+ });
8418
+ };
6863
8419
  // pkgs/@akanjs/devkit/applicationBuildReporter.ts
6864
8420
  import { Logger as Logger6 } from "akanjs/common";
6865
8421
 
@@ -6906,20 +8462,20 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
6906
8462
  }
6907
8463
  // pkgs/@akanjs/devkit/applicationBuildRunner.ts
6908
8464
  import { mkdir as mkdir8, rm as rm3 } from "fs/promises";
6909
- import path35 from "path";
8465
+ import path37 from "path";
6910
8466
 
6911
8467
  // pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
6912
- import path20 from "path";
8468
+ import path22 from "path";
6913
8469
 
6914
8470
  // pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
6915
8471
  import { mkdir as mkdir3 } from "fs/promises";
6916
- import path11 from "path";
8472
+ import path13 from "path";
6917
8473
  var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
6918
8474
  async function appHasStModule(appCwdPath) {
6919
- return Bun.file(path11.join(appCwdPath, "lib", "st.ts")).exists();
8475
+ return Bun.file(path13.join(appCwdPath, "lib", "st.ts")).exists();
6920
8476
  }
6921
- var IMPLICIT_LAYOUT_DIR = path11.join(".akan", "generated", "root-layouts");
6922
- var IMPLICIT_DICT_DIR = path11.join(".akan", "generated", "dict");
8477
+ var IMPLICIT_LAYOUT_DIR = path13.join(".akan", "generated", "root-layouts");
8478
+ var IMPLICIT_DICT_DIR = path13.join(".akan", "generated", "dict");
6923
8479
  function getRootBoundarySegments(key) {
6924
8480
  const match = LAYOUT_KEY_RE.exec(key);
6925
8481
  if (!match)
@@ -6934,10 +8490,10 @@ function implicitRootLayoutKey(segments) {
6934
8490
  }
6935
8491
  function implicitRootLayoutAbsPath(appCwdPath, segments) {
6936
8492
  const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
6937
- return path11.join(path11.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
8493
+ return path13.join(path13.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
6938
8494
  }
6939
8495
  function implicitDictionaryMacroAbsPath(appCwdPath) {
6940
- return path11.join(path11.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
8496
+ return path13.join(path13.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
6941
8497
  }
6942
8498
  function isRootBoundarySegments(segments, basePaths) {
6943
8499
  const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
@@ -6960,7 +8516,7 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
6960
8516
  const id = segments.join("/");
6961
8517
  boundaries.set(id, {
6962
8518
  sourceKey: key,
6963
- sourceAbsPath: path11.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
8519
+ sourceAbsPath: path13.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
6964
8520
  segments
6965
8521
  });
6966
8522
  }
@@ -6978,21 +8534,21 @@ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
6978
8534
  const segments = getRootBoundarySegments(key);
6979
8535
  return segments !== null && segments.length === 0;
6980
8536
  });
6981
- return rootLayoutKey ? path11.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
8537
+ return rootLayoutKey ? path13.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
6982
8538
  }
6983
8539
  function routePrefixForSegments(segments) {
6984
8540
  const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
6985
8541
  return visible[0] ?? null;
6986
8542
  }
6987
8543
  async function assertEnvClientConvention(appCwdPath, appName) {
6988
- const envPath = path11.join(appCwdPath, "env", "env.client.ts");
8544
+ const envPath = path13.join(appCwdPath, "env", "env.client.ts");
6989
8545
  if (!await Bun.file(envPath).exists()) {
6990
8546
  throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
6991
8547
  }
6992
8548
  }
6993
8549
  async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
6994
8550
  const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
6995
- await mkdir3(path11.dirname(absPath), { recursive: true });
8551
+ await mkdir3(path13.dirname(absPath), { recursive: true });
6996
8552
  await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
6997
8553
 
6998
8554
  export const allDictionary = getAllDictionary();
@@ -7003,13 +8559,13 @@ async function writeGeneratedRootLayoutFile(opts) {
7003
8559
  await assertEnvClientConvention(opts.appCwdPath, opts.appName);
7004
8560
  const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
7005
8561
  const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
7006
- await mkdir3(path11.dirname(absPath), { recursive: true });
7007
- const dictMacroRel = dictMacroAbsPath ? path11.relative(path11.dirname(absPath), dictMacroAbsPath).split(path11.sep).join("/") : null;
8562
+ await mkdir3(path13.dirname(absPath), { recursive: true });
8563
+ const dictMacroRel = dictMacroAbsPath ? path13.relative(path13.dirname(absPath), dictMacroAbsPath).split(path13.sep).join("/") : null;
7008
8564
  const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
7009
- const sourceRel = opts.boundary.sourceAbsPath ? path11.relative(path11.dirname(absPath), opts.boundary.sourceAbsPath).split(path11.sep).join("/") : null;
8565
+ const sourceRel = opts.boundary.sourceAbsPath ? path13.relative(path13.dirname(absPath), opts.boundary.sourceAbsPath).split(path13.sep).join("/") : null;
7010
8566
  const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
7011
8567
  const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
7012
- const inheritedSourceRel = inheritedSourceAbsPath ? path11.relative(path11.dirname(absPath), inheritedSourceAbsPath).split(path11.sep).join("/") : null;
8568
+ const inheritedSourceRel = inheritedSourceAbsPath ? path13.relative(path13.dirname(absPath), inheritedSourceAbsPath).split(path13.sep).join("/") : null;
7013
8569
  const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
7014
8570
  const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
7015
8571
  void st;
@@ -7103,7 +8659,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
7103
8659
  return absPath;
7104
8660
  }
7105
8661
  async function resolveSsrPageEntries(opts) {
7106
- const absPageDir = path11.resolve(opts.appCwdPath, "page");
8662
+ const absPageDir = path13.resolve(opts.appCwdPath, "page");
7107
8663
  const hasSt = await appHasStModule(opts.appCwdPath);
7108
8664
  const basePaths = opts.basePaths ?? [];
7109
8665
  const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
@@ -7114,7 +8670,7 @@ async function resolveSsrPageEntries(opts) {
7114
8670
  }));
7115
8671
  const base = opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map((key) => ({
7116
8672
  key,
7117
- moduleAbsPath: path11.resolve(absPageDir, key)
8673
+ moduleAbsPath: path13.resolve(absPageDir, key)
7118
8674
  }));
7119
8675
  const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
7120
8676
  key: implicitRootLayoutKey(boundary.segments),
@@ -7138,14 +8694,14 @@ async function resolveSsrPageEntriesForApp(app, pageKeys) {
7138
8694
  }
7139
8695
 
7140
8696
  // pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
7141
- import path12 from "path";
8697
+ import path14 from "path";
7142
8698
  import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey as parseRouteModuleKey2 } from "akanjs/common";
7143
8699
  function computeRouteSeedIndex(pageEntries) {
7144
8700
  const layoutsByPrefix = new Map;
7145
8701
  const pagesBySegments = [];
7146
8702
  for (const { key, moduleAbsPath, seedAbsPaths } of pageEntries) {
7147
8703
  const parsed = parseRouteModuleKey2(key);
7148
- const files = [path12.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path12.resolve(seed))];
8704
+ const files = [path14.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path14.resolve(seed))];
7149
8705
  if (parsed.kind === "layout") {
7150
8706
  const prefix = parsed.routeSegments.join("/");
7151
8707
  const prev = layoutsByPrefix.get(prefix) ?? [];
@@ -7182,7 +8738,7 @@ function computeRouteSeedIndex(pageEntries) {
7182
8738
  }
7183
8739
  var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
7184
8740
  function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
7185
- const normalizedArtifactDir = path12.resolve(artifactDir);
8741
+ const normalizedArtifactDir = path14.resolve(artifactDir);
7186
8742
  if (options.production) {
7187
8743
  return {
7188
8744
  entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
@@ -7197,22 +8753,22 @@ function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
7197
8753
  };
7198
8754
  }
7199
8755
  async function saveRouteSeedIndex(artifactDir, index, options = {}) {
7200
- const absPath = path12.join(path12.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
8756
+ const absPath = path14.join(path14.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
7201
8757
  await Bun.write(absPath, `${JSON.stringify(serializeRouteSeedIndexForArtifact(index, artifactDir, options), null, 2)}
7202
8758
  `);
7203
8759
  return absPath;
7204
8760
  }
7205
8761
  function serializeArtifactPath(artifactPath, artifactDir) {
7206
- if (!path12.isAbsolute(artifactPath))
8762
+ if (!path14.isAbsolute(artifactPath))
7207
8763
  return artifactPath;
7208
- return path12.relative(artifactDir, artifactPath).split(path12.sep).join("/");
8764
+ return path14.relative(artifactDir, artifactPath).split(path14.sep).join("/");
7209
8765
  }
7210
8766
 
7211
8767
  // pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
7212
- import path15 from "path";
8768
+ import path17 from "path";
7213
8769
 
7214
8770
  // pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
7215
- import path13 from "path";
8771
+ import path15 from "path";
7216
8772
  import { Logger as Logger7 } from "akanjs/common";
7217
8773
  var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
7218
8774
  var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
@@ -7335,7 +8891,7 @@ class BarrelAnalyzer {
7335
8891
  }
7336
8892
  #scanExports(source2, absFile) {
7337
8893
  try {
7338
- const transpiler = [".tsx", ".jsx"].includes(path13.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
8894
+ const transpiler = [".tsx", ".jsx"].includes(path15.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
7339
8895
  const { exports } = transpiler.scan(source2);
7340
8896
  return new Set(exports);
7341
8897
  } catch (err) {
@@ -7344,16 +8900,16 @@ class BarrelAnalyzer {
7344
8900
  }
7345
8901
  }
7346
8902
  #subpathFor(pkg, absFile) {
7347
- const rel = path13.relative(pkg.pkgDir, absFile);
7348
- if (!rel || rel.startsWith("..") || path13.isAbsolute(rel))
8903
+ const rel = path15.relative(pkg.pkgDir, absFile);
8904
+ if (!rel || rel.startsWith("..") || path15.isAbsolute(rel))
7349
8905
  return null;
7350
8906
  if (pkg.preserveFilePath)
7351
- return `${pkg.pkgName}/${rel.split(path13.sep).join("/")}`;
8907
+ return `${pkg.pkgName}/${rel.split(path15.sep).join("/")}`;
7352
8908
  const noExt = stripKnownExt(rel);
7353
8909
  const tail = collapseIndex(noExt);
7354
8910
  if (tail === "")
7355
8911
  return pkg.pkgName;
7356
- return `${pkg.pkgName}/${tail.split(path13.sep).join("/")}`;
8912
+ return `${pkg.pkgName}/${tail.split(path15.sep).join("/")}`;
7357
8913
  }
7358
8914
  async#resolveRel(fromFile, relSpec) {
7359
8915
  if (this.#opts.resolveRelative)
@@ -7394,9 +8950,9 @@ var readIfExists = async (absFile) => {
7394
8950
  return file.text();
7395
8951
  };
7396
8952
  var defaultResolveRelative = async (fromFile, relSpec) => {
7397
- const baseDir = path13.dirname(fromFile);
7398
- const joined = path13.resolve(baseDir, relSpec);
7399
- if (path13.extname(joined)) {
8953
+ const baseDir = path15.dirname(fromFile);
8954
+ const joined = path15.resolve(baseDir, relSpec);
8955
+ if (path15.extname(joined)) {
7400
8956
  if (await Bun.file(joined).exists())
7401
8957
  return joined;
7402
8958
  return null;
@@ -7407,7 +8963,7 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
7407
8963
  return cand;
7408
8964
  }
7409
8965
  for (const ext of CANDIDATE_EXTS) {
7410
- const cand = path13.join(joined, `index${ext}`);
8966
+ const cand = path15.join(joined, `index${ext}`);
7411
8967
  if (await Bun.file(cand).exists())
7412
8968
  return cand;
7413
8969
  }
@@ -7421,15 +8977,15 @@ var stripKnownExt = (relPath) => {
7421
8977
  return relPath;
7422
8978
  };
7423
8979
  var collapseIndex = (relPathNoExt) => {
7424
- const parts = relPathNoExt.split(path13.sep);
8980
+ const parts = relPathNoExt.split(path15.sep);
7425
8981
  if (parts[parts.length - 1] === "index")
7426
8982
  parts.pop();
7427
- return parts.join(path13.sep);
8983
+ return parts.join(path15.sep);
7428
8984
  };
7429
8985
 
7430
8986
  // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
7431
- import path14 from "path";
7432
- import ts5 from "typescript";
8987
+ import path16 from "path";
8988
+ import ts7 from "typescript";
7433
8989
  var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
7434
8990
  const akanConfig2 = await app.getConfig();
7435
8991
  const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
@@ -7487,10 +9043,10 @@ var createTsconfigPackageResolver = async (app) => {
7487
9043
  const raw = exact[0];
7488
9044
  if (!raw)
7489
9045
  return null;
7490
- const entryFile = path14.resolve(app.workspace.workspaceRoot, raw);
9046
+ const entryFile = path16.resolve(app.workspace.workspaceRoot, raw);
7491
9047
  if (!await Bun.file(entryFile).exists())
7492
9048
  return null;
7493
- const parsed = path14.parse(entryFile);
9049
+ const parsed = path16.parse(entryFile);
7494
9050
  const lastSlash = pkgName.lastIndexOf("/");
7495
9051
  if (parsed.name !== "index" && lastSlash !== -1) {
7496
9052
  const facet = pkgName.slice(lastSlash + 1);
@@ -7499,7 +9055,7 @@ var createTsconfigPackageResolver = async (app) => {
7499
9055
  return { pkgName: parentSpec, entryFile, pkgDir: parsed.dir };
7500
9056
  }
7501
9057
  }
7502
- return { pkgName, entryFile, pkgDir: path14.dirname(entryFile) };
9058
+ return { pkgName, entryFile, pkgDir: path16.dirname(entryFile) };
7503
9059
  }
7504
9060
  for (const { prefix, replacements } of wildcardEntries) {
7505
9061
  if (!pkgName.startsWith(prefix))
@@ -7509,7 +9065,7 @@ var createTsconfigPackageResolver = async (app) => {
7509
9065
  if (!repl)
7510
9066
  continue;
7511
9067
  const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
7512
- const candidate = path14.resolve(app.workspace.workspaceRoot, replPath + suffix);
9068
+ const candidate = path16.resolve(app.workspace.workspaceRoot, replPath + suffix);
7513
9069
  for (const ext of CANDIDATE_EXTS2) {
7514
9070
  const file = `${candidate}${ext}`;
7515
9071
  if (await Bun.file(file).exists()) {
@@ -7517,14 +9073,14 @@ var createTsconfigPackageResolver = async (app) => {
7517
9073
  if (lastSlash !== -1) {
7518
9074
  const parentSpec = pkgName.slice(0, lastSlash);
7519
9075
  if (parentSpec.length > 0) {
7520
- return { pkgName: parentSpec, entryFile: file, pkgDir: path14.dirname(file) };
9076
+ return { pkgName: parentSpec, entryFile: file, pkgDir: path16.dirname(file) };
7521
9077
  }
7522
9078
  }
7523
- return { pkgName, entryFile: file, pkgDir: path14.dirname(file) };
9079
+ return { pkgName, entryFile: file, pkgDir: path16.dirname(file) };
7524
9080
  }
7525
9081
  }
7526
9082
  for (const ext of CANDIDATE_EXTS2) {
7527
- const file = path14.join(candidate, `index${ext}`);
9083
+ const file = path16.join(candidate, `index${ext}`);
7528
9084
  if (await Bun.file(file).exists()) {
7529
9085
  return { pkgName, entryFile: file, pkgDir: candidate };
7530
9086
  }
@@ -7535,16 +9091,16 @@ var createTsconfigPackageResolver = async (app) => {
7535
9091
  const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
7536
9092
  if (exported)
7537
9093
  return exported;
7538
- const pkgJsonPath = path14.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
9094
+ const pkgJsonPath = path16.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
7539
9095
  if (!await Bun.file(pkgJsonPath).exists())
7540
9096
  return null;
7541
9097
  try {
7542
9098
  const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
7543
9099
  const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
7544
- const entryFile = path14.resolve(path14.dirname(pkgJsonPath), rel);
9100
+ const entryFile = path16.resolve(path16.dirname(pkgJsonPath), rel);
7545
9101
  if (!await Bun.file(entryFile).exists())
7546
9102
  return null;
7547
- return { pkgName, entryFile, pkgDir: path14.dirname(pkgJsonPath) };
9103
+ return { pkgName, entryFile, pkgDir: path16.dirname(pkgJsonPath) };
7548
9104
  } catch {
7549
9105
  return null;
7550
9106
  }
@@ -7558,22 +9114,22 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
7558
9114
  const packageName = getPackageName(specifier);
7559
9115
  if (!packageName)
7560
9116
  return null;
7561
- const pkgJsonPath = path14.join(workspaceRoot, "node_modules", packageName, "package.json");
9117
+ const pkgJsonPath = path16.join(workspaceRoot, "node_modules", packageName, "package.json");
7562
9118
  if (!await Bun.file(pkgJsonPath).exists())
7563
9119
  return null;
7564
9120
  try {
7565
- const pkgDir = path14.dirname(pkgJsonPath);
9121
+ const pkgDir = path16.dirname(pkgJsonPath);
7566
9122
  const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
7567
9123
  const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
7568
9124
  const exported = resolvePackageExport(pkgJson.exports, subpath);
7569
9125
  const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
7570
9126
  if (!rel || !rel.startsWith("."))
7571
9127
  return null;
7572
- const entryFile = await resolveFileCandidate(path14.resolve(pkgDir, rel));
9128
+ const entryFile = await resolveFileCandidate(path16.resolve(pkgDir, rel));
7573
9129
  if (!entryFile)
7574
9130
  return null;
7575
9131
  const pkgEntryName = specifier;
7576
- return { pkgName: pkgEntryName, entryFile, pkgDir: path14.dirname(entryFile), preserveFilePath: true };
9132
+ return { pkgName: pkgEntryName, entryFile, pkgDir: path16.dirname(entryFile), preserveFilePath: true };
7577
9133
  } catch {
7578
9134
  return null;
7579
9135
  }
@@ -7630,7 +9186,7 @@ var getPackageName = (specifier) => {
7630
9186
  var resolveFileCandidate = async (candidate) => {
7631
9187
  if (await Bun.file(candidate).exists())
7632
9188
  return candidate;
7633
- if (path14.extname(candidate))
9189
+ if (path16.extname(candidate))
7634
9190
  return null;
7635
9191
  for (const ext of CANDIDATE_EXTS2) {
7636
9192
  const file = `${candidate}${ext}`;
@@ -7638,7 +9194,7 @@ var resolveFileCandidate = async (candidate) => {
7638
9194
  return file;
7639
9195
  }
7640
9196
  for (const ext of CANDIDATE_EXTS2) {
7641
- const file = path14.join(candidate, `index${ext}`);
9197
+ const file = path16.join(candidate, `index${ext}`);
7642
9198
  if (await Bun.file(file).exists())
7643
9199
  return file;
7644
9200
  }
@@ -7670,11 +9226,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
7670
9226
  };
7671
9227
  var findImportStatements = (source2) => {
7672
9228
  const statements = [];
7673
- const sourceFile2 = ts5.createSourceFile("barrel-imports.tsx", source2, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
9229
+ const sourceFile2 = ts7.createSourceFile("barrel-imports.tsx", source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
7674
9230
  for (const statement of sourceFile2.statements) {
7675
- if (!ts5.isImportDeclaration(statement))
9231
+ if (!ts7.isImportDeclaration(statement))
7676
9232
  continue;
7677
- if (!ts5.isStringLiteral(statement.moduleSpecifier))
9233
+ if (!ts7.isStringLiteral(statement.moduleSpecifier))
7678
9234
  continue;
7679
9235
  const importClause = statement.importClause;
7680
9236
  if (!importClause)
@@ -7852,7 +9408,7 @@ class GraphClientEntryDiscovery {
7852
9408
  }
7853
9409
  invalidate(files) {
7854
9410
  for (const file of files) {
7855
- const absPath = path15.resolve(file);
9411
+ const absPath = path17.resolve(file);
7856
9412
  this.#readCache.delete(absPath);
7857
9413
  this.#rewriteCache.delete(absPath);
7858
9414
  this.#importCache.delete(absPath);
@@ -7862,7 +9418,7 @@ class GraphClientEntryDiscovery {
7862
9418
  this.#reachableEntriesCache.clear();
7863
9419
  }
7864
9420
  async#fileExists(p) {
7865
- const absPath = path15.resolve(p);
9421
+ const absPath = path17.resolve(p);
7866
9422
  let cached = this.#fileExistsCache.get(absPath);
7867
9423
  if (!cached) {
7868
9424
  cached = Bun.file(absPath).exists();
@@ -7871,7 +9427,7 @@ class GraphClientEntryDiscovery {
7871
9427
  return cached;
7872
9428
  }
7873
9429
  #readFile(file) {
7874
- const absPath = path15.resolve(file);
9430
+ const absPath = path17.resolve(file);
7875
9431
  let cached = this.#readCache.get(absPath);
7876
9432
  if (!cached) {
7877
9433
  cached = Bun.file(absPath).text().catch(() => null);
@@ -7880,7 +9436,7 @@ class GraphClientEntryDiscovery {
7880
9436
  return cached;
7881
9437
  }
7882
9438
  async#resolveFileCandidate(absPathNoExt) {
7883
- const cacheKey = path15.resolve(absPathNoExt);
9439
+ const cacheKey = path17.resolve(absPathNoExt);
7884
9440
  let cached = this.#resolvedFileCache.get(cacheKey);
7885
9441
  if (cached)
7886
9442
  return cached;
@@ -7893,7 +9449,7 @@ class GraphClientEntryDiscovery {
7893
9449
  return f;
7894
9450
  }
7895
9451
  for (const ext of SOURCE_EXTS2) {
7896
- const f = path15.join(cacheKey, `index${ext}`);
9452
+ const f = path17.join(cacheKey, `index${ext}`);
7897
9453
  if (await this.#fileExists(f))
7898
9454
  return f;
7899
9455
  }
@@ -7909,7 +9465,7 @@ class GraphClientEntryDiscovery {
7909
9465
  return cached;
7910
9466
  cached = (async () => {
7911
9467
  if (spec.startsWith(".") || spec.startsWith("/")) {
7912
- const abs = spec.startsWith("/") ? spec : path15.resolve(importerDir, spec);
9468
+ const abs = spec.startsWith("/") ? spec : path17.resolve(importerDir, spec);
7913
9469
  return this.#resolveFileCandidate(abs);
7914
9470
  }
7915
9471
  const pkg = await this.#resolvePackage(spec);
@@ -7921,7 +9477,7 @@ class GraphClientEntryDiscovery {
7921
9477
  return cached;
7922
9478
  }
7923
9479
  async#getRewrittenSource(file, content) {
7924
- const absPath = path15.resolve(file);
9480
+ const absPath = path17.resolve(file);
7925
9481
  let cached = this.#rewriteCache.get(absPath);
7926
9482
  if (!cached) {
7927
9483
  cached = (async () => {
@@ -7938,7 +9494,7 @@ class GraphClientEntryDiscovery {
7938
9494
  return cached;
7939
9495
  }
7940
9496
  async#getImports(file, source2) {
7941
- const absPath = path15.resolve(file);
9497
+ const absPath = path17.resolve(file);
7942
9498
  let cached = this.#importCache.get(absPath);
7943
9499
  if (!cached) {
7944
9500
  cached = Promise.resolve().then(() => {
@@ -7953,7 +9509,7 @@ class GraphClientEntryDiscovery {
7953
9509
  return cached;
7954
9510
  }
7955
9511
  async#discoverFromFile(file, visiting) {
7956
- const absPath = path15.resolve(file);
9512
+ const absPath = path17.resolve(file);
7957
9513
  const cached = this.#reachableEntriesCache.get(absPath);
7958
9514
  if (cached)
7959
9515
  return new Set(cached);
@@ -7970,7 +9526,7 @@ class GraphClientEntryDiscovery {
7970
9526
  }
7971
9527
  const source2 = await this.#getRewrittenSource(absPath, content);
7972
9528
  const imports = await this.#getImports(absPath, source2);
7973
- const importerDir = path15.dirname(absPath);
9529
+ const importerDir = path17.dirname(absPath);
7974
9530
  for (const imp of imports) {
7975
9531
  const spec = imp.path;
7976
9532
  if (!spec)
@@ -7996,14 +9552,14 @@ class GraphClientEntryDiscovery {
7996
9552
 
7997
9553
  // pkgs/@akanjs/devkit/frontendBuild/routeClientBuilder.ts
7998
9554
  import { mkdir as mkdir4 } from "fs/promises";
7999
- import path18 from "path";
9555
+ import path20 from "path";
8000
9556
 
8001
9557
  // pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
8002
- import path16 from "path";
9558
+ import path18 from "path";
8003
9559
  var USE_CLIENT_RE2 = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
8004
9560
  var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
8005
9561
  function toClientReferencePath(absPath, workspaceRoot) {
8006
- return path16.relative(path16.resolve(workspaceRoot), path16.resolve(absPath)).split(path16.sep).join("/");
9562
+ return path18.relative(path18.resolve(workspaceRoot), path18.resolve(absPath)).split(path18.sep).join("/");
8007
9563
  }
8008
9564
  function transformUseClient(source2, args) {
8009
9565
  if (!USE_CLIENT_RE2.test(source2))
@@ -8039,7 +9595,7 @@ function loaderFor2(absPath) {
8039
9595
 
8040
9596
  // pkgs/@akanjs/devkit/frontendBuild/clientEntriesBundler.ts
8041
9597
  import fs2 from "fs";
8042
- import path17 from "path";
9598
+ import path19 from "path";
8043
9599
 
8044
9600
  // pkgs/@akanjs/devkit/frontendBuild/clientBuildTypes.ts
8045
9601
  var CLIENT_BUNDLE_NAMING = {
@@ -8128,23 +9684,23 @@ class ClientEntriesBundler {
8128
9684
  };
8129
9685
  }
8130
9686
  async#createOpaqueEntryAliases() {
8131
- const aliasDir = path17.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
9687
+ const aliasDir = path19.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
8132
9688
  fs2.mkdirSync(aliasDir, { recursive: true });
8133
9689
  const originalByAlias = new Map;
8134
9690
  const aliasedEntries = await Promise.all(this.#entries.map(async (entry) => {
8135
- const absEntry = path17.resolve(entry);
9691
+ const absEntry = path19.resolve(entry);
8136
9692
  const hash = Bun.hash(`${this.#app.name}
8137
9693
  ${this.#outputSubdir}
8138
9694
  ${absEntry}`).toString(36);
8139
- const aliasPath = path17.join(aliasDir, `${hash}.tsx`);
9695
+ const aliasPath = path19.join(aliasDir, `${hash}.tsx`);
8140
9696
  await Bun.write(aliasPath, this.#createOpaqueEntryAliasSource(absEntry, await this.#scanEntryExportNames(absEntry)));
8141
- originalByAlias.set(path17.resolve(aliasPath), absEntry);
9697
+ originalByAlias.set(path19.resolve(aliasPath), absEntry);
8142
9698
  return aliasPath;
8143
9699
  }));
8144
9700
  return { entries: aliasedEntries, originalByAlias, aliasDir };
8145
9701
  }
8146
9702
  #createOpaqueEntryAliasSource(absEntry, exportNames) {
8147
- const entryLit = JSON.stringify(path17.resolve(absEntry));
9703
+ const entryLit = JSON.stringify(path19.resolve(absEntry));
8148
9704
  if (exportNames.length === 0)
8149
9705
  return `export * from ${entryLit};
8150
9706
  `;
@@ -8227,16 +9783,16 @@ ${absEntry}`).toString(36);
8227
9783
  return rewritten;
8228
9784
  }
8229
9785
  #toServeUrl(absOutPath) {
8230
- const rel = path17.relative(this.#outdir, absOutPath).split(path17.sep).join("/");
9786
+ const rel = path19.relative(this.#outdir, absOutPath).split(path19.sep).join("/");
8231
9787
  return `${this.#servePrefix}/${rel}`;
8232
9788
  }
8233
9789
  #absFromOutdir(p) {
8234
- return path17.isAbsolute(p) ? p : path17.resolve(this.#outdir, p);
9790
+ return path19.isAbsolute(p) ? p : path19.resolve(this.#outdir, p);
8235
9791
  }
8236
9792
  #absFromEntryPoint(p) {
8237
- if (path17.isAbsolute(p))
8238
- return path17.resolve(p);
8239
- const candidates = [path17.resolve(process.cwd(), p), path17.resolve(this.#app.cwdPath, p)];
9793
+ if (path19.isAbsolute(p))
9794
+ return path19.resolve(p);
9795
+ const candidates = [path19.resolve(process.cwd(), p), path19.resolve(this.#app.cwdPath, p)];
8240
9796
  return candidates.find((candidate) => fs2.existsSync(candidate)) ?? candidates[0];
8241
9797
  }
8242
9798
  #collectChunkUrls(absOutPath, visited = new Set) {
@@ -8386,13 +9942,13 @@ class RouteClientBuilder {
8386
9942
  ssrModuleMap[row.id][row.name] = { id: ssrOutput, chunks: [ssrOutput, ssrOutput], name: row.name, async: true };
8387
9943
  }
8388
9944
  for (const entry of bootstrapEntries.buildEntries) {
8389
- const buildEntry = path18.resolve(entry);
8390
- const originalEntry = path18.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
9945
+ const buildEntry = path20.resolve(entry);
9946
+ const originalEntry = path20.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
8391
9947
  if (!acceptedEntries.has(originalEntry))
8392
9948
  continue;
8393
9949
  const deps = new Set([originalEntry]);
8394
9950
  for (const dep of browserBundle.entryDepsByAbsPath.get(buildEntry) ?? [])
8395
- deps.add(path18.resolve(dep));
9951
+ deps.add(path20.resolve(dep));
8396
9952
  const sortedDeps = [...deps].sort();
8397
9953
  clientDepsByEntry[originalEntry] = sortedDeps;
8398
9954
  for (const dep of sortedDeps)
@@ -8444,25 +10000,25 @@ class RouteClientBuilder {
8444
10000
  }).bundle();
8445
10001
  }
8446
10002
  async#createBootstrapEntries(entries) {
8447
- if (!await Bun.file(path18.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
10003
+ if (!await Bun.file(path20.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
8448
10004
  return { buildEntries: entries, originalByBuildEntry: new Map };
8449
10005
  }
8450
- const outdir = path18.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
10006
+ const outdir = path20.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
8451
10007
  await mkdir4(outdir, { recursive: true });
8452
10008
  const originalByBuildEntry = new Map;
8453
10009
  const buildEntries = await Promise.all(entries.map(async (entry) => {
8454
- const absEntry = path18.resolve(entry);
10010
+ const absEntry = path20.resolve(entry);
8455
10011
  const hash = Bun.hash(`${this.#app.name}
8456
10012
  ${absEntry}`).toString(36);
8457
- const base = path18.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
8458
- const wrapperEntry = path18.join(outdir, `${base}-${hash}.tsx`);
10013
+ const base = path20.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
10014
+ const wrapperEntry = path20.join(outdir, `${base}-${hash}.tsx`);
8459
10015
  const exportNames = await this.#scanExportNames(absEntry);
8460
10016
  await Bun.write(wrapperEntry, RouteClientBuilder.createStoreBootstrapEntrySource({
8461
10017
  appName: this.#app.name,
8462
10018
  originalEntry: absEntry,
8463
10019
  exportNames
8464
10020
  }));
8465
- originalByBuildEntry.set(path18.resolve(wrapperEntry), absEntry);
10021
+ originalByBuildEntry.set(path20.resolve(wrapperEntry), absEntry);
8466
10022
  return wrapperEntry;
8467
10023
  }));
8468
10024
  return { buildEntries, originalByBuildEntry };
@@ -8514,11 +10070,11 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
8514
10070
  try {
8515
10071
  return Bun.resolveSync("akanjs/server", import.meta.dir);
8516
10072
  } catch {
8517
- return path18.resolve(import.meta.dir, "../../../server/index.ts");
10073
+ return path20.resolve(import.meta.dir, "../../../server/index.ts");
8518
10074
  }
8519
10075
  }
8520
10076
  static createStoreBootstrapEntrySource(args) {
8521
- const originalEntry = JSON.stringify(path18.resolve(args.originalEntry));
10077
+ const originalEntry = JSON.stringify(path20.resolve(args.originalEntry));
8522
10078
  const namedExports = args.exportNames.filter((name) => name !== "default");
8523
10079
  const lines = [
8524
10080
  `import ${JSON.stringify(`@apps/${args.appName}/client`)};`,
@@ -8544,7 +10100,7 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
8544
10100
  }
8545
10101
 
8546
10102
  // pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
8547
- import path19 from "path";
10103
+ import path21 from "path";
8548
10104
 
8549
10105
  class RoutesManifestArtifactSerializer {
8550
10106
  #manifest;
@@ -8552,7 +10108,7 @@ class RoutesManifestArtifactSerializer {
8552
10108
  #production;
8553
10109
  constructor(manifest, artifactDir, options = {}) {
8554
10110
  this.#manifest = manifest;
8555
- this.#artifactDir = path19.resolve(artifactDir);
10111
+ this.#artifactDir = path21.resolve(artifactDir);
8556
10112
  this.#production = options.production ?? false;
8557
10113
  }
8558
10114
  static serialize(manifest, artifactDir, options = {}) {
@@ -8585,9 +10141,9 @@ class RoutesManifestArtifactSerializer {
8585
10141
  };
8586
10142
  }
8587
10143
  #serializeArtifactPath(artifactPath) {
8588
- if (!path19.isAbsolute(artifactPath))
10144
+ if (!path21.isAbsolute(artifactPath))
8589
10145
  return artifactPath;
8590
- return path19.relative(this.#artifactDir, artifactPath).split(path19.sep).join("/");
10146
+ return path21.relative(this.#artifactDir, artifactPath).split(path21.sep).join("/");
8591
10147
  }
8592
10148
  }
8593
10149
 
@@ -8627,7 +10183,7 @@ class AllRoutesBuilder {
8627
10183
  routeIds: this.#routeIds,
8628
10184
  ...this.#merged
8629
10185
  };
8630
- const manifestPath = path20.join(path20.resolve(this.#artifactDir), "routes-manifest.json");
10186
+ const manifestPath = path22.join(path22.resolve(this.#artifactDir), "routes-manifest.json");
8631
10187
  await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
8632
10188
  production: this.#command === "build"
8633
10189
  }), null, 2)}
@@ -8664,12 +10220,12 @@ class AllRoutesBuilder {
8664
10220
  }
8665
10221
  // pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
8666
10222
  import { mkdir as mkdir5, rm, unlink } from "fs/promises";
8667
- import path22 from "path";
10223
+ import path24 from "path";
8668
10224
 
8669
10225
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
8670
10226
  import fs3 from "fs";
8671
- import path21 from "path";
8672
- import ts6 from "typescript";
10227
+ import path23 from "path";
10228
+ import ts8 from "typescript";
8673
10229
 
8674
10230
  class PagesEntrySourceGenerator {
8675
10231
  #pageEntries;
@@ -8681,7 +10237,7 @@ class PagesEntrySourceGenerator {
8681
10237
  }
8682
10238
  generate() {
8683
10239
  const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
8684
- const absPath = path21.resolve(moduleAbsPath);
10240
+ const absPath = path23.resolve(moduleAbsPath);
8685
10241
  return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(absPath)}),`;
8686
10242
  });
8687
10243
  return `export const pages = {
@@ -8695,7 +10251,7 @@ ${lines.join(`
8695
10251
  }
8696
10252
  generateStatic() {
8697
10253
  const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
8698
- const absPath = path21.resolve(moduleAbsPath);
10254
+ const absPath = path23.resolve(moduleAbsPath);
8699
10255
  return `import * as page${index} from ${JSON.stringify(absPath)};`;
8700
10256
  });
8701
10257
  const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
@@ -8712,8 +10268,8 @@ ${entries.join(`
8712
10268
  }
8713
10269
  static #hasAsyncDefaultExport(moduleAbsPath) {
8714
10270
  try {
8715
- const source2 = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
8716
- const sourceFile2 = ts6.createSourceFile(moduleAbsPath, source2, ts6.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
10271
+ const source2 = fs3.readFileSync(path23.resolve(moduleAbsPath), "utf8");
10272
+ const sourceFile2 = ts8.createSourceFile(moduleAbsPath, source2, ts8.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
8717
10273
  return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
8718
10274
  } catch {
8719
10275
  return false;
@@ -8723,31 +10279,31 @@ ${entries.join(`
8723
10279
  const asyncBindings = new Map;
8724
10280
  let defaultIdentifier = null;
8725
10281
  for (const statement of sourceFile2.statements) {
8726
- if (ts6.isFunctionDeclaration(statement)) {
8727
- if (PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.DefaultKeyword)) {
8728
- return PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword);
10282
+ if (ts8.isFunctionDeclaration(statement)) {
10283
+ if (PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.DefaultKeyword)) {
10284
+ return PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword);
8729
10285
  }
8730
10286
  if (statement.name) {
8731
- asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword));
10287
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword));
8732
10288
  }
8733
10289
  continue;
8734
10290
  }
8735
- if (ts6.isVariableStatement(statement)) {
10291
+ if (ts8.isVariableStatement(statement)) {
8736
10292
  for (const declaration of statement.declarationList.declarations) {
8737
- if (!ts6.isIdentifier(declaration.name))
10293
+ if (!ts8.isIdentifier(declaration.name))
8738
10294
  continue;
8739
10295
  asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
8740
10296
  }
8741
10297
  continue;
8742
10298
  }
8743
- if (ts6.isExportAssignment(statement)) {
10299
+ if (ts8.isExportAssignment(statement)) {
8744
10300
  if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
8745
10301
  return true;
8746
- if (ts6.isIdentifier(statement.expression))
10302
+ if (ts8.isIdentifier(statement.expression))
8747
10303
  defaultIdentifier = statement.expression.text;
8748
10304
  continue;
8749
10305
  }
8750
- if (ts6.isExportDeclaration(statement) && statement.exportClause && ts6.isNamedExports(statement.exportClause)) {
10306
+ if (ts8.isExportDeclaration(statement) && statement.exportClause && ts8.isNamedExports(statement.exportClause)) {
8751
10307
  const exportClause = statement.exportClause;
8752
10308
  for (const specifier of exportClause.elements) {
8753
10309
  if (specifier.name.text !== "default")
@@ -8759,13 +10315,13 @@ ${entries.join(`
8759
10315
  return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
8760
10316
  }
8761
10317
  static #hasModifier(node, kind) {
8762
- return ts6.canHaveModifiers(node) && (ts6.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
10318
+ return ts8.canHaveModifiers(node) && (ts8.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
8763
10319
  }
8764
10320
  static #isAsyncFunctionExpression(node) {
8765
- return Boolean(node && (ts6.isArrowFunction(node) || ts6.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts6.SyntaxKind.AsyncKeyword));
10321
+ return Boolean(node && (ts8.isArrowFunction(node) || ts8.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts8.SyntaxKind.AsyncKeyword));
8766
10322
  }
8767
10323
  static #scriptKind(moduleAbsPath) {
8768
- return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts6.ScriptKind.TSX : ts6.ScriptKind.TS;
10324
+ return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts8.ScriptKind.TSX : ts8.ScriptKind.TS;
8769
10325
  }
8770
10326
  }
8771
10327
 
@@ -8791,7 +10347,7 @@ class CsrArtifactBuilder {
8791
10347
  const csrBasePaths = [...akanConfig2.basePaths];
8792
10348
  const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
8793
10349
  await rm(this.#outputDir, { recursive: true, force: true });
8794
- await mkdir5(path22.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
10350
+ await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
8795
10351
  const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
8796
10352
  const result = await Bun.build({
8797
10353
  target: "browser",
@@ -8823,7 +10379,7 @@ ${logs}` : ""}`);
8823
10379
  return { outputDir: this.#outputDir };
8824
10380
  }
8825
10381
  get #outputDir() {
8826
- return path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
10382
+ return path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
8827
10383
  }
8828
10384
  #define() {
8829
10385
  const nodeEnv = this.#command === "build" ? "production" : "development";
@@ -8854,8 +10410,8 @@ ${logs}` : ""}`);
8854
10410
  ];
8855
10411
  }
8856
10412
  async#loadCsrArtifact() {
8857
- const artifactDir = path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
8858
- const artifactFile = Bun.file(path22.join(artifactDir, "base-artifact.json"));
10413
+ const artifactDir = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
10414
+ const artifactFile = Bun.file(path24.join(artifactDir, "base-artifact.json"));
8859
10415
  if (!await artifactFile.exists())
8860
10416
  return { cssAssets: {} };
8861
10417
  const artifact = await artifactFile.json();
@@ -8868,7 +10424,7 @@ ${logs}` : ""}`);
8868
10424
  const htmlFile = Bun.file(htmlPath);
8869
10425
  if (!await htmlFile.exists())
8870
10426
  continue;
8871
- const basePath2 = path22.basename(htmlPath, ".html") === "index" ? "" : path22.basename(htmlPath, ".html");
10427
+ const basePath2 = path24.basename(htmlPath, ".html") === "index" ? "" : path24.basename(htmlPath, ".html");
8872
10428
  const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath2]);
8873
10429
  for (const filePath of inlined.jsFiles)
8874
10430
  jsFiles.add(filePath);
@@ -8910,7 +10466,7 @@ ${remainingAssets.join(`
8910
10466
  next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
8911
10467
  }
8912
10468
  if (cssAsset) {
8913
- const cssPath = path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
10469
+ const cssPath = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
8914
10470
  const css = await Bun.file(cssPath).text();
8915
10471
  const style = CsrArtifactBuilder.createInlineStyle(css);
8916
10472
  if (!next.includes(style))
@@ -8981,16 +10537,16 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
8981
10537
  throw new Error(`[csr-build] cannot inline external script: ${src}`);
8982
10538
  }
8983
10539
  const normalized = src.startsWith("/") ? src.slice(1) : src;
8984
- return path22.resolve(path22.dirname(htmlPath), normalized);
10540
+ return path24.resolve(path24.dirname(htmlPath), normalized);
8985
10541
  }
8986
10542
  }
8987
10543
  // pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
8988
- import path24 from "path";
10544
+ import path26 from "path";
8989
10545
  import { Logger as Logger8 } from "akanjs/common";
8990
10546
  import { compile } from "tailwindcss";
8991
10547
 
8992
10548
  // pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
8993
- import path23 from "path";
10549
+ import path25 from "path";
8994
10550
  var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
8995
10551
 
8996
10552
  class CssImportResolver {
@@ -9043,7 +10599,7 @@ class CssImportResolver {
9043
10599
  const exact = this.#paths[id];
9044
10600
  if (exact) {
9045
10601
  for (const repl of exact) {
9046
- const resolved = await this.#firstExisting(path23.resolve(this.#workspaceRoot, repl));
10602
+ const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, repl));
9047
10603
  if (resolved)
9048
10604
  return resolved;
9049
10605
  }
@@ -9054,7 +10610,7 @@ class CssImportResolver {
9054
10610
  const suffix = id.slice(prefix.length);
9055
10611
  for (const repl of replacements) {
9056
10612
  const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
9057
- const resolved = await this.#firstExisting(path23.resolve(this.#workspaceRoot, replPath + suffix));
10613
+ const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, replPath + suffix));
9058
10614
  if (resolved)
9059
10615
  return resolved;
9060
10616
  }
@@ -9084,25 +10640,25 @@ class CssImportResolver {
9084
10640
  try {
9085
10641
  if (!await Bun.file(pkgPath).exists())
9086
10642
  return null;
9087
- const pkgDir = path23.dirname(pkgPath);
10643
+ const pkgDir = path25.dirname(pkgPath);
9088
10644
  const pkg = await Bun.file(pkgPath).json();
9089
10645
  const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
9090
10646
  const exportValue = pkg.exports?.[subpath];
9091
10647
  const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
9092
- return await this.#firstExisting(path23.resolve(pkgDir, styleEntry));
10648
+ return await this.#firstExisting(path25.resolve(pkgDir, styleEntry));
9093
10649
  } catch {
9094
10650
  return null;
9095
10651
  }
9096
10652
  }
9097
10653
  #resolutionBases(fromBase) {
9098
- return [fromBase, this.#workspaceRoot, path23.dirname(Bun.main), path23.resolve(path23.dirname(Bun.main), "../..")];
10654
+ return [fromBase, this.#workspaceRoot, path25.dirname(Bun.main), path25.resolve(path25.dirname(Bun.main), "../..")];
9099
10655
  }
9100
10656
  #packageJsonCandidates(pkgName) {
9101
10657
  return [
9102
- path23.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
9103
- path23.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
9104
- path23.join(path23.dirname(Bun.main), "node_modules", pkgName, "package.json"),
9105
- path23.join(path23.dirname(Bun.main), "../../", pkgName, "package.json")
10658
+ path25.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
10659
+ path25.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
10660
+ path25.join(path25.dirname(Bun.main), "node_modules", pkgName, "package.json"),
10661
+ path25.join(path25.dirname(Bun.main), "../../", pkgName, "package.json")
9106
10662
  ];
9107
10663
  }
9108
10664
  async#firstExisting(basePath2) {
@@ -9120,7 +10676,7 @@ class CssImportResolver {
9120
10676
  return parts[0] ?? null;
9121
10677
  }
9122
10678
  static isCssFile(filePath) {
9123
- return path23.extname(filePath) === ".css";
10679
+ return path25.extname(filePath) === ".css";
9124
10680
  }
9125
10681
  }
9126
10682
 
@@ -9187,7 +10743,7 @@ class CssCompiler {
9187
10743
  pageKeys
9188
10744
  } = {}) {
9189
10745
  pageKeys ??= await this.#app.getPageKeys({ refresh });
9190
- const seeds = pageKeys.map((key) => path24.resolve(this.#app.cwdPath, "page", key));
10746
+ const seeds = pageKeys.map((key) => path26.resolve(this.#app.cwdPath, "page", key));
9191
10747
  const cssFiles = new Set;
9192
10748
  const sourceFiles = new Set;
9193
10749
  const queue = [...seeds];
@@ -9219,7 +10775,7 @@ class CssCompiler {
9219
10775
  } catch {
9220
10776
  continue;
9221
10777
  }
9222
- const importerDir = path24.dirname(filePath);
10778
+ const importerDir = path26.dirname(filePath);
9223
10779
  for (const imp of imports) {
9224
10780
  const spec = imp.path;
9225
10781
  if (!spec)
@@ -9245,7 +10801,7 @@ class CssCompiler {
9245
10801
  const compileStarted = Date.now();
9246
10802
  const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
9247
10803
  const css = await Bun.file(cssPath).text();
9248
- const base = path24.dirname(cssPath);
10804
+ const base = path26.dirname(cssPath);
9249
10805
  const compiler = await compile(css, {
9250
10806
  base,
9251
10807
  loadStylesheet: (id, fromBase) => this.#loadStylesheet(id, fromBase),
@@ -9276,11 +10832,11 @@ class CssCompiler {
9276
10832
  async#loadStylesheet(id, fromBase) {
9277
10833
  const p = await this.#resolveCssImport(id, fromBase);
9278
10834
  const content = await Bun.file(p).text();
9279
- return { path: p, base: path24.dirname(p), content };
10835
+ return { path: p, base: path26.dirname(p), content };
9280
10836
  }
9281
10837
  async#resolveCssImport(id, fromBase) {
9282
10838
  if (id.startsWith(".") || id.startsWith("/"))
9283
- return path24.resolve(fromBase, id);
10839
+ return path26.resolve(fromBase, id);
9284
10840
  const resolver = await this.#getCssImportResolver();
9285
10841
  const resolved = await resolver.resolve(id, fromBase);
9286
10842
  if (resolved)
@@ -9296,11 +10852,11 @@ class CssCompiler {
9296
10852
  async#loadModule(id, fromBase) {
9297
10853
  const p = __require.resolve(id, { paths: [fromBase] });
9298
10854
  const mod = await import(p);
9299
- return { path: p, base: path24.dirname(p), module: mod.default ?? mod };
10855
+ return { path: p, base: path26.dirname(p), module: mod.default ?? mod };
9300
10856
  }
9301
10857
  async#resolveSourceImport(id, fromBase, resolvePackage) {
9302
10858
  if (id.startsWith(".") || id.startsWith("/")) {
9303
- const abs = id.startsWith("/") ? id : path24.resolve(fromBase, id);
10859
+ const abs = id.startsWith("/") ? id : path26.resolve(fromBase, id);
9304
10860
  return resolveSourceFileCandidate(abs);
9305
10861
  }
9306
10862
  const pkg = await resolvePackage(id);
@@ -9342,7 +10898,7 @@ async function resolveSourceFileCandidate(absPathNoExt) {
9342
10898
  return filePath;
9343
10899
  }
9344
10900
  for (const ext of SOURCE_EXTS3) {
9345
- const filePath = path24.join(absPathNoExt, `index${ext}`);
10901
+ const filePath = path26.join(absPathNoExt, `index${ext}`);
9346
10902
  if (await Bun.file(filePath).exists())
9347
10903
  return filePath;
9348
10904
  }
@@ -9365,19 +10921,19 @@ function resolveSourceWithRequire(id, fromBase) {
9365
10921
  }
9366
10922
  }
9367
10923
  function isSourceFile(filePath) {
9368
- return SOURCE_EXTS3.includes(path24.extname(filePath));
10924
+ return SOURCE_EXTS3.includes(path26.extname(filePath));
9369
10925
  }
9370
10926
  function isIgnoredNodeModuleSource(filePath) {
9371
10927
  return NODE_MODULES_RE3.test(filePath) && !AKANJS_NODE_MODULE_RE3.test(filePath);
9372
10928
  }
9373
10929
  function getPageKeyBasePath(pageKey, basePaths) {
9374
- const normalized = pageKey.split(path24.sep).join("/").replace(/^\.\//, "");
10930
+ const normalized = pageKey.split(path26.sep).join("/").replace(/^\.\//, "");
9375
10931
  const segments = normalized.split("/");
9376
10932
  const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
9377
10933
  return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
9378
10934
  }
9379
10935
  // pkgs/@akanjs/devkit/frontendBuild/devChangePlanner.ts
9380
- import path25 from "path";
10936
+ import path27 from "path";
9381
10937
  var SOURCE_EXTS4 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
9382
10938
  var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
9383
10939
  var BARREL_FACETS = new Set(["common", "srvkit", "ui", "webkit"]);
@@ -9389,11 +10945,11 @@ var RUNTIME_METADATA_BASENAMES2 = new Set(["dict.ts", "sig.ts", "useClient.ts",
9389
10945
  class DevChangePlanner {
9390
10946
  #workspaceRoot;
9391
10947
  constructor({ workspaceRoot }) {
9392
- this.#workspaceRoot = path25.resolve(workspaceRoot);
10948
+ this.#workspaceRoot = path27.resolve(workspaceRoot);
9393
10949
  }
9394
10950
  plan({ generation, files, kinds, generatedFiles: generatedFiles2 = [] }) {
9395
10951
  const fileList = uniqueResolved([...files, ...generatedFiles2]);
9396
- const generatedSet = new Set(generatedFiles2.map((file) => path25.resolve(file)));
10952
+ const generatedSet = new Set(generatedFiles2.map((file) => path27.resolve(file)));
9397
10953
  const kindSet = new Set(kinds);
9398
10954
  const roles = new Set;
9399
10955
  const actions = new Set;
@@ -9410,13 +10966,13 @@ class DevChangePlanner {
9410
10966
  }
9411
10967
  for (const file of fileList) {
9412
10968
  const reasons = new Set;
9413
- const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path25.resolve(file)), reasons });
10969
+ const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path27.resolve(file)), reasons });
9414
10970
  for (const role of fileRoles)
9415
10971
  roles.add(role);
9416
10972
  if (reasons.has("runtime-metadata"))
9417
10973
  actions.add("restart-builder");
9418
10974
  if (reasons.size > 0)
9419
- reasonByFile[path25.resolve(file)] = [...reasons].sort();
10975
+ reasonByFile[path27.resolve(file)] = [...reasons].sort();
9420
10976
  }
9421
10977
  if (roles.has("barrel"))
9422
10978
  actions.add("sync-generated");
@@ -9437,12 +10993,12 @@ class DevChangePlanner {
9437
10993
  }
9438
10994
  #rolesForFile(file, { isGenerated, reasons }) {
9439
10995
  const roles = new Set;
9440
- const abs = path25.resolve(file);
9441
- const base = path25.basename(abs);
9442
- const ext = path25.extname(abs).toLowerCase();
10996
+ const abs = path27.resolve(file);
10997
+ const base = path27.basename(abs);
10998
+ const ext = path27.extname(abs).toLowerCase();
9443
10999
  const isSource = SOURCE_EXTS4.has(ext);
9444
- const rel = path25.relative(this.#workspaceRoot, abs);
9445
- const parts = rel.split(path25.sep).filter(Boolean);
11000
+ const rel = path27.relative(this.#workspaceRoot, abs);
11001
+ const parts = rel.split(path27.sep).filter(Boolean);
9446
11002
  if (CONFIG_BASENAMES.has(base)) {
9447
11003
  roles.add("config");
9448
11004
  reasons.add("config-file");
@@ -9483,15 +11039,15 @@ class DevChangePlanner {
9483
11039
  return roles;
9484
11040
  }
9485
11041
  #isServerBiased(abs, parts) {
9486
- const base = path25.basename(abs);
11042
+ const base = path27.basename(abs);
9487
11043
  return parts.includes("srvkit") || SERVER_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || base === "main.ts" || base === "server.ts";
9488
11044
  }
9489
11045
  #isClientBiased(abs, parts) {
9490
- const base = path25.basename(abs);
11046
+ const base = path27.basename(abs);
9491
11047
  return parts.includes("ui") || parts.includes("webkit") || parts.includes("page") || CLIENT_SUFFIXES.some((suffix) => base.endsWith(suffix));
9492
11048
  }
9493
11049
  #isSharedBiased(abs, parts) {
9494
- const base = path25.basename(abs);
11050
+ const base = path27.basename(abs);
9495
11051
  return parts.includes("common") || SHARED_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || RUNTIME_METADATA_BASENAMES2.has(base);
9496
11052
  }
9497
11053
  #isRuntimeMetadataFile(parts, base) {
@@ -9516,16 +11072,16 @@ class DevChangePlanner {
9516
11072
  return true;
9517
11073
  }
9518
11074
  #isWorkspaceSource(rel) {
9519
- if (!rel || rel.startsWith("..") || path25.isAbsolute(rel))
11075
+ if (!rel || rel.startsWith("..") || path27.isAbsolute(rel))
9520
11076
  return false;
9521
- const [scope] = rel.split(path25.sep);
11077
+ const [scope] = rel.split(path27.sep);
9522
11078
  return scope === "apps" || scope === "libs" || scope === "pkgs";
9523
11079
  }
9524
11080
  }
9525
- var uniqueResolved = (files) => [...new Set(files.map((file) => path25.resolve(file)))].sort();
11081
+ var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
9526
11082
  // pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
9527
11083
  import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm2, stat as stat3, writeFile } from "fs/promises";
9528
- import path26 from "path";
11084
+ import path28 from "path";
9529
11085
  var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
9530
11086
  var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
9531
11087
  var FACET_EXCLUDED_FILE_RE = /(^index\.tsx?$|\.d\.ts$|\.(test|spec)\.(ts|tsx)$|\.css$|\.scss$|\.sass$)/;
@@ -9536,7 +11092,7 @@ var SCALAR_UI_TYPES = ["Template", "Unit"];
9536
11092
  class DevGeneratedIndexSync {
9537
11093
  #workspaceRoot;
9538
11094
  constructor({ workspaceRoot }) {
9539
- this.#workspaceRoot = path26.resolve(workspaceRoot);
11095
+ this.#workspaceRoot = path28.resolve(workspaceRoot);
9540
11096
  }
9541
11097
  async syncForBatch(files) {
9542
11098
  const indexPaths = new Set;
@@ -9545,12 +11101,12 @@ class DevGeneratedIndexSync {
9545
11101
  const facetIndex = this.#facetIndexFor(file);
9546
11102
  if (facetIndex)
9547
11103
  indexPaths.add(facetIndex);
9548
- const moduleIndex = await this.#moduleIndexForDirectoryEvent(file).catch((err) => {
11104
+ const moduleIndex2 = await this.#moduleIndexForDirectoryEvent(file).catch((err) => {
9549
11105
  errors.push(`[generated-index] module detection failed for ${file}: ${formatError(err)}`);
9550
11106
  return null;
9551
11107
  });
9552
- if (moduleIndex)
9553
- indexPaths.add(moduleIndex);
11108
+ if (moduleIndex2)
11109
+ indexPaths.add(moduleIndex2);
9554
11110
  }
9555
11111
  const changedFiles = [];
9556
11112
  for (const indexPath of [...indexPaths].sort()) {
@@ -9565,11 +11121,11 @@ class DevGeneratedIndexSync {
9565
11121
  return { changedFiles, errors };
9566
11122
  }
9567
11123
  #facetIndexFor(file) {
9568
- const abs = path26.resolve(file);
9569
- const rel = path26.relative(this.#workspaceRoot, abs);
9570
- if (rel.startsWith("..") || path26.isAbsolute(rel))
11124
+ const abs = path28.resolve(file);
11125
+ const rel = path28.relative(this.#workspaceRoot, abs);
11126
+ if (rel.startsWith("..") || path28.isAbsolute(rel))
9571
11127
  return null;
9572
- const parts = rel.split(path26.sep).filter(Boolean);
11128
+ const parts = rel.split(path28.sep).filter(Boolean);
9573
11129
  if (parts.length < 4)
9574
11130
  return null;
9575
11131
  const [scope, project, facet, child] = parts;
@@ -9577,32 +11133,32 @@ class DevGeneratedIndexSync {
9577
11133
  return null;
9578
11134
  if (!child || child.startsWith(".") || child === "index.ts" || child === "index.tsx")
9579
11135
  return null;
9580
- return path26.join(this.#workspaceRoot, scope, project, facet, "index.ts");
11136
+ return path28.join(this.#workspaceRoot, scope, project, facet, "index.ts");
9581
11137
  }
9582
11138
  async#moduleIndexForDirectoryEvent(file) {
9583
- const abs = path26.resolve(file);
9584
- const rel = path26.relative(this.#workspaceRoot, abs);
9585
- if (rel.startsWith("..") || path26.isAbsolute(rel))
11139
+ const abs = path28.resolve(file);
11140
+ const rel = path28.relative(this.#workspaceRoot, abs);
11141
+ if (rel.startsWith("..") || path28.isAbsolute(rel))
9586
11142
  return null;
9587
- const parts = rel.split(path26.sep).filter(Boolean);
11143
+ const parts = rel.split(path28.sep).filter(Boolean);
9588
11144
  if (parts.length !== 4 && parts.length !== 5)
9589
11145
  return null;
9590
11146
  const [scope, project, libSegment, moduleSegment, scalarSegment] = parts;
9591
11147
  if (scope !== "apps" && scope !== "libs" || !project || libSegment !== "lib")
9592
11148
  return null;
9593
11149
  const isExistingDirectory = await stat3(abs).then((s) => s.isDirectory()).catch(() => false);
9594
- const looksLikeDeletedDirectory = !path26.extname(abs);
11150
+ const looksLikeDeletedDirectory = !path28.extname(abs);
9595
11151
  if (!isExistingDirectory && !looksLikeDeletedDirectory)
9596
11152
  return null;
9597
11153
  if (moduleSegment === "__scalar" && scalarSegment) {
9598
- return path26.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
11154
+ return path28.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
9599
11155
  }
9600
11156
  if (!moduleSegment || moduleSegment === "__scalar")
9601
11157
  return null;
9602
- return path26.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
11158
+ return path28.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
9603
11159
  }
9604
11160
  async#syncIndex(indexPath) {
9605
- const dir = path26.dirname(indexPath);
11161
+ const dir = path28.dirname(indexPath);
9606
11162
  const content = await this.#contentForIndex(indexPath);
9607
11163
  if (content === null) {
9608
11164
  if (!await exists(indexPath))
@@ -9618,11 +11174,11 @@ class DevGeneratedIndexSync {
9618
11174
  return true;
9619
11175
  }
9620
11176
  async#contentForIndex(indexPath) {
9621
- const parts = path26.relative(this.#workspaceRoot, indexPath).split(path26.sep).filter(Boolean);
11177
+ const parts = path28.relative(this.#workspaceRoot, indexPath).split(path28.sep).filter(Boolean);
9622
11178
  const facet = parts.at(-2);
9623
11179
  if (facet && BARREL_FACETS2.has(facet))
9624
- return this.#facetContent(path26.dirname(indexPath));
9625
- return this.#moduleContent(path26.dirname(indexPath));
11180
+ return this.#facetContent(path28.dirname(indexPath));
11181
+ return this.#moduleContent(path28.dirname(indexPath));
9626
11182
  }
9627
11183
  async#facetContent(dir) {
9628
11184
  const entries = await readdir2(dir, { withFileTypes: true }).catch(() => []);
@@ -9645,8 +11201,8 @@ class DevGeneratedIndexSync {
9645
11201
  `;
9646
11202
  }
9647
11203
  async#moduleContent(dir) {
9648
- const rel = path26.relative(this.#workspaceRoot, dir);
9649
- const parts = rel.split(path26.sep).filter(Boolean);
11204
+ const rel = path28.relative(this.#workspaceRoot, dir);
11205
+ const parts = rel.split(path28.sep).filter(Boolean);
9650
11206
  const moduleSegment = parts.at(-1);
9651
11207
  if (!moduleSegment)
9652
11208
  return null;
@@ -9654,11 +11210,11 @@ class DevGeneratedIndexSync {
9654
11210
  const rawModel = moduleSegment.startsWith("_") ? moduleSegment.slice(1) : moduleSegment;
9655
11211
  if (!rawModel)
9656
11212
  return null;
9657
- const modelName = capitalize5(rawModel);
11213
+ const modelName = capitalize4(rawModel);
9658
11214
  const allowedTypes = isScalar ? SCALAR_UI_TYPES : moduleSegment.startsWith("_") ? SERVICE_UI_TYPES : MODULE_UI_TYPES;
9659
11215
  const fileTypes = [];
9660
11216
  for (const type of allowedTypes) {
9661
- if (await exists(path26.join(dir, `${modelName}.${type}.tsx`)))
11217
+ if (await exists(path28.join(dir, `${modelName}.${type}.tsx`)))
9662
11218
  fileTypes.push(type);
9663
11219
  }
9664
11220
  if (fileTypes.length === 0)
@@ -9671,11 +11227,11 @@ export const ${modelName} = { ${fileTypes.join(", ")} };`;
9671
11227
  }
9672
11228
  }
9673
11229
  var exists = async (file) => stat3(file).then(() => true).catch(() => false);
9674
- var capitalize5 = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
11230
+ var capitalize4 = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
9675
11231
  var formatError = (err) => err instanceof Error ? err.message : String(err);
9676
11232
  // pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
9677
11233
  import { mkdir as mkdir7 } from "fs/promises";
9678
- import path27 from "path";
11234
+ import path29 from "path";
9679
11235
  import {
9680
11236
  generateFontFace,
9681
11237
  getMetricsForFamily,
@@ -9684,7 +11240,7 @@ import {
9684
11240
  } from "fontaine";
9685
11241
  import { createFont, woff2 } from "fonteditor-core";
9686
11242
  import subsetFont from "subset-font";
9687
- import ts7 from "typescript";
11243
+ import ts9 from "typescript";
9688
11244
  var FONT_URL_PREFIX = "/_akan/fonts";
9689
11245
  var DEFAULT_FONT_SUBSETS = ["latin"];
9690
11246
 
@@ -9699,7 +11255,7 @@ class FontOptimizer {
9699
11255
  constructor(app, command = "start") {
9700
11256
  this.#app = app;
9701
11257
  this.#command = command;
9702
- this.#artifactRoot = path27.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
11258
+ this.#artifactRoot = path29.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
9703
11259
  }
9704
11260
  async optimize() {
9705
11261
  const fonts = await this.discoverFonts();
@@ -9718,7 +11274,7 @@ class FontOptimizer {
9718
11274
  const pageKeys = await this.#app.getPageKeys();
9719
11275
  const fonts = [];
9720
11276
  await Promise.all(pageKeys.map(async (key) => {
9721
- const filePath = path27.resolve(this.#app.cwdPath, "page", key);
11277
+ const filePath = path29.resolve(this.#app.cwdPath, "page", key);
9722
11278
  const file = Bun.file(filePath);
9723
11279
  if (!await file.exists())
9724
11280
  return;
@@ -9734,8 +11290,8 @@ class FontOptimizer {
9734
11290
  this.#app.logger.warn(`[font] source not found: ${face.src}`);
9735
11291
  continue;
9736
11292
  }
9737
- const outputPath = path27.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
9738
- await mkdir7(path27.dirname(outputPath), { recursive: true });
11293
+ const outputPath = path29.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
11294
+ await mkdir7(path29.dirname(outputPath), { recursive: true });
9739
11295
  const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
9740
11296
  const outputBuffer = font.subset === false ? await this.#convertToWoff2(sourceBuffer, sourcePath) : await subsetFont(sourceBuffer, await this.#getSubsetText(font), { targetFormat: "woff2" });
9741
11297
  await Bun.write(outputPath, outputBuffer);
@@ -9749,17 +11305,17 @@ class FontOptimizer {
9749
11305
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
9750
11306
  }
9751
11307
  #extractFontsExport(source2, filePath) {
9752
- const sourceFile2 = ts7.createSourceFile(filePath, source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
11308
+ const sourceFile2 = ts9.createSourceFile(filePath, source2, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TSX);
9753
11309
  const fonts = [];
9754
11310
  for (const statement of sourceFile2.statements) {
9755
- if (!ts7.isVariableStatement(statement))
11311
+ if (!ts9.isVariableStatement(statement))
9756
11312
  continue;
9757
- const modifiers = ts7.canHaveModifiers(statement) ? ts7.getModifiers(statement) : undefined;
9758
- const isExported = modifiers?.some((modifier) => modifier.kind === ts7.SyntaxKind.ExportKeyword) ?? false;
11313
+ const modifiers = ts9.canHaveModifiers(statement) ? ts9.getModifiers(statement) : undefined;
11314
+ const isExported = modifiers?.some((modifier) => modifier.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
9759
11315
  if (!isExported)
9760
11316
  continue;
9761
11317
  for (const declaration of statement.declarationList.declarations) {
9762
- if (!ts7.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
11318
+ if (!ts9.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
9763
11319
  continue;
9764
11320
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
9765
11321
  if (Array.isArray(value)) {
@@ -9770,20 +11326,20 @@ class FontOptimizer {
9770
11326
  return fonts;
9771
11327
  }
9772
11328
  #literalToValue(node) {
9773
- if (ts7.isStringLiteralLike(node))
11329
+ if (ts9.isStringLiteralLike(node))
9774
11330
  return node.text;
9775
- if (ts7.isNumericLiteral(node))
11331
+ if (ts9.isNumericLiteral(node))
9776
11332
  return Number(node.text);
9777
- if (node.kind === ts7.SyntaxKind.TrueKeyword)
11333
+ if (node.kind === ts9.SyntaxKind.TrueKeyword)
9778
11334
  return true;
9779
- if (node.kind === ts7.SyntaxKind.FalseKeyword)
11335
+ if (node.kind === ts9.SyntaxKind.FalseKeyword)
9780
11336
  return false;
9781
- if (ts7.isArrayLiteralExpression(node))
11337
+ if (ts9.isArrayLiteralExpression(node))
9782
11338
  return node.elements.map((element) => this.#literalToValue(element));
9783
- if (ts7.isObjectLiteralExpression(node)) {
11339
+ if (ts9.isObjectLiteralExpression(node)) {
9784
11340
  const obj = {};
9785
11341
  for (const prop of node.properties) {
9786
- if (!ts7.isPropertyAssignment(prop))
11342
+ if (!ts9.isPropertyAssignment(prop))
9787
11343
  continue;
9788
11344
  const name = this.#getPropertyName(prop.name);
9789
11345
  if (!name)
@@ -9792,13 +11348,13 @@ class FontOptimizer {
9792
11348
  }
9793
11349
  return obj;
9794
11350
  }
9795
- if (ts7.isAsExpression(node) || ts7.isSatisfiesExpression(node) || ts7.isParenthesizedExpression(node)) {
11351
+ if (ts9.isAsExpression(node) || ts9.isSatisfiesExpression(node) || ts9.isParenthesizedExpression(node)) {
9796
11352
  return this.#literalToValue(node.expression);
9797
11353
  }
9798
11354
  return;
9799
11355
  }
9800
11356
  #getPropertyName(name) {
9801
- if (ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
11357
+ if (ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name))
9802
11358
  return name.text;
9803
11359
  return null;
9804
11360
  }
@@ -9882,8 +11438,8 @@ class FontOptimizer {
9882
11438
  return null;
9883
11439
  const rel = src.replace(/^\//, "");
9884
11440
  const candidates = [
9885
- this.#command === "build" ? path27.join(this.#app.dist.cwdPath, "public", rel) : null,
9886
- path27.join(this.#app.cwdPath, "public", rel),
11441
+ this.#command === "build" ? path29.join(this.#app.dist.cwdPath, "public", rel) : null,
11442
+ path29.join(this.#app.cwdPath, "public", rel),
9887
11443
  this.#resolveWorkspacePublicPath(rel)
9888
11444
  ].filter(Boolean);
9889
11445
  for (const candidate of candidates) {
@@ -9911,7 +11467,7 @@ class FontOptimizer {
9911
11467
  return "woff2";
9912
11468
  if (signature === "OTTO")
9913
11469
  return "otf";
9914
- const ext = path27.extname(sourcePath).slice(1).toLowerCase();
11470
+ const ext = path29.extname(sourcePath).slice(1).toLowerCase();
9915
11471
  if (ext === "otf" || ext === "woff" || ext === "woff2")
9916
11472
  return ext;
9917
11473
  return "ttf";
@@ -9920,7 +11476,7 @@ class FontOptimizer {
9920
11476
  const [root, dep, ...rest] = rel.split("/");
9921
11477
  if (root !== "libs" || !dep || rest.length === 0)
9922
11478
  return null;
9923
- return path27.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
11479
+ return path29.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
9924
11480
  }
9925
11481
  async#getSubsetText(font) {
9926
11482
  const parts = new Set;
@@ -9930,7 +11486,7 @@ class FontOptimizer {
9930
11486
  if (font.subsetText)
9931
11487
  parts.add(font.subsetText);
9932
11488
  for (const filePath of font.subsetFiles ?? []) {
9933
- const abs = path27.isAbsolute(filePath) ? filePath : path27.join(this.#app.cwdPath, filePath);
11489
+ const abs = path29.isAbsolute(filePath) ? filePath : path29.join(this.#app.cwdPath, filePath);
9934
11490
  const file = Bun.file(abs);
9935
11491
  if (await file.exists())
9936
11492
  parts.add(await file.text());
@@ -9949,7 +11505,7 @@ class FontOptimizer {
9949
11505
  return "";
9950
11506
  }
9951
11507
  async#collectAutoSubsetText() {
9952
- const roots = ["page", "ui"].map((dir) => path27.join(this.#app.cwdPath, dir));
11508
+ const roots = ["page", "ui"].map((dir) => path29.join(this.#app.cwdPath, dir));
9953
11509
  const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
9954
11510
  const parts = [];
9955
11511
  await Promise.all(roots.map(async (root) => {
@@ -10063,7 +11619,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
10063
11619
  }
10064
11620
  }
10065
11621
  // pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
10066
- import path28 from "path";
11622
+ import path30 from "path";
10067
11623
  var SOURCE_EXTS5 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
10068
11624
  var CSS_EXTS = new Set([".css"]);
10069
11625
  var CONFIG_BASENAMES2 = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
@@ -10072,10 +11628,10 @@ class HmrChangeClassifier {
10072
11628
  classify(abs) {
10073
11629
  if (this.#isUninteresting(abs))
10074
11630
  return "ignore";
10075
- const base = path28.basename(abs);
11631
+ const base = path30.basename(abs);
10076
11632
  if (CONFIG_BASENAMES2.has(base))
10077
11633
  return "config";
10078
- const ext = path28.extname(abs).toLowerCase();
11634
+ const ext = path30.extname(abs).toLowerCase();
10079
11635
  if (CSS_EXTS.has(ext))
10080
11636
  return "css";
10081
11637
  if (SOURCE_EXTS5.has(ext))
@@ -10083,23 +11639,23 @@ class HmrChangeClassifier {
10083
11639
  return "ignore";
10084
11640
  }
10085
11641
  #isUninteresting(abs) {
10086
- const base = path28.basename(abs);
11642
+ const base = path30.basename(abs);
10087
11643
  if (!base)
10088
11644
  return true;
10089
11645
  if (base.startsWith("."))
10090
11646
  return true;
10091
11647
  if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
10092
11648
  return true;
10093
- if (abs.includes(`${path28.sep}node_modules${path28.sep}`))
11649
+ if (abs.includes(`${path30.sep}node_modules${path30.sep}`))
10094
11650
  return true;
10095
- if (abs.includes(`${path28.sep}.akan${path28.sep}`))
11651
+ if (abs.includes(`${path30.sep}.akan${path30.sep}`))
10096
11652
  return true;
10097
11653
  return false;
10098
11654
  }
10099
11655
  }
10100
11656
  // pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
10101
11657
  import fs4 from "fs";
10102
- import path29 from "path";
11658
+ import path31 from "path";
10103
11659
  class HmrWatcher {
10104
11660
  #roots;
10105
11661
  #debounceMs;
@@ -10112,7 +11668,7 @@ class HmrWatcher {
10112
11668
  #stopped = false;
10113
11669
  #flushing = false;
10114
11670
  constructor(opts) {
10115
- this.#roots = [...new Set(opts.roots.map((r) => path29.resolve(r)))];
11671
+ this.#roots = [...new Set(opts.roots.map((r) => path31.resolve(r)))];
10116
11672
  this.#debounceMs = opts.debounceMs ?? 80;
10117
11673
  this.#onBatch = opts.onBatch;
10118
11674
  this.#logger = opts.logger;
@@ -10123,7 +11679,7 @@ class HmrWatcher {
10123
11679
  const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
10124
11680
  if (!filename)
10125
11681
  return;
10126
- const abs = path29.resolve(root, filename.toString());
11682
+ const abs = path31.resolve(root, filename.toString());
10127
11683
  this.#queue(abs);
10128
11684
  });
10129
11685
  this.#watchers.push(w);
@@ -10181,10 +11737,10 @@ class HmrWatcher {
10181
11737
  }
10182
11738
  }
10183
11739
  // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
10184
- import path31 from "path";
11740
+ import path33 from "path";
10185
11741
 
10186
11742
  // pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
10187
- import path30 from "path";
11743
+ import path32 from "path";
10188
11744
  var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
10189
11745
  var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
10190
11746
  var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
@@ -10227,7 +11783,7 @@ async function createExternalizeFrameworkPlugin(options) {
10227
11783
  const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
10228
11784
  if (!replPath)
10229
11785
  continue;
10230
- const candidate = path30.resolve(workspaceRoot, replPath + suffix);
11786
+ const candidate = path32.resolve(workspaceRoot, replPath + suffix);
10231
11787
  const hit = await firstExisting(candidate);
10232
11788
  if (hit)
10233
11789
  return hit;
@@ -10239,8 +11795,8 @@ async function createExternalizeFrameworkPlugin(options) {
10239
11795
  if (spec === pkg)
10240
11796
  continue;
10241
11797
  const suffix = spec.slice(pkg.length + 1);
10242
- const pkgDir = path30.dirname(path30.resolve(workspaceRoot, entryFile));
10243
- const candidate = path30.join(pkgDir, suffix);
11798
+ const pkgDir = path32.dirname(path32.resolve(workspaceRoot, entryFile));
11799
+ const candidate = path32.join(pkgDir, suffix);
10244
11800
  const hit = await firstExisting(candidate);
10245
11801
  if (hit)
10246
11802
  return hit;
@@ -10290,7 +11846,7 @@ async function firstExisting(basePath2) {
10290
11846
  return candidate;
10291
11847
  }
10292
11848
  for (const ext of CANDIDATE_EXTS3) {
10293
- const candidate = path30.join(basePath2, `index${ext}`);
11849
+ const candidate = path32.join(basePath2, `index${ext}`);
10294
11850
  if (await Bun.file(candidate).exists())
10295
11851
  return candidate;
10296
11852
  }
@@ -10381,11 +11937,11 @@ class PagesBundleBuilder {
10381
11937
  const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
10382
11938
  if (!entryArtifact)
10383
11939
  throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
10384
- const bundlePath = path31.resolve(entryArtifact.path);
11940
+ const bundlePath = path33.resolve(entryArtifact.path);
10385
11941
  const buildId = Date.now();
10386
11942
  const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
10387
11943
  const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
10388
- this.#app.verbose(`[PagesBundleBuilder] ${path31.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
11944
+ this.#app.verbose(`[PagesBundleBuilder] ${path33.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
10389
11945
  return {
10390
11946
  bundlePath,
10391
11947
  buildId,
@@ -10467,11 +12023,11 @@ function loaderFor4(absPath) {
10467
12023
  }
10468
12024
  // pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
10469
12025
  import fs5 from "fs";
10470
- import path32 from "path";
12026
+ import path34 from "path";
10471
12027
  var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
10472
12028
  var MIN_COMPRESS_BYTES = 1024;
10473
12029
  async function precompressArtifacts(app) {
10474
- const roots = [path32.join(app.dist.cwdPath, ".akan/artifact/client")];
12030
+ const roots = [path34.join(app.dist.cwdPath, ".akan/artifact/client")];
10475
12031
  const result = { files: 0, inputBytes: 0, outputBytes: 0 };
10476
12032
  await Promise.all(roots.map((root) => precompressRoot(root, result)));
10477
12033
  if (result.files > 0) {
@@ -10497,7 +12053,7 @@ async function precompressRoot(root, result) {
10497
12053
  async function shouldPrecompress(filePath) {
10498
12054
  if (filePath.endsWith(".gz"))
10499
12055
  return false;
10500
- if (!COMPRESSIBLE_EXTS.has(path32.extname(filePath).toLowerCase()))
12056
+ if (!COMPRESSIBLE_EXTS.has(path34.extname(filePath).toLowerCase()))
10501
12057
  return false;
10502
12058
  const file = Bun.file(filePath);
10503
12059
  if (!await file.exists())
@@ -10515,7 +12071,7 @@ function formatBytes(bytes) {
10515
12071
  return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
10516
12072
  }
10517
12073
  // pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
10518
- import path33 from "path";
12074
+ import path35 from "path";
10519
12075
  import { optimize } from "@tailwindcss/node";
10520
12076
  function prepareCssAsset(command, basePath2, cssText) {
10521
12077
  return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
@@ -10531,7 +12087,7 @@ class SsrBaseArtifactBuilder {
10531
12087
  this.#app = app;
10532
12088
  this.#command = command;
10533
12089
  this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
10534
- this.#absArtifactDir = path33.resolve(this.#artifactDir);
12090
+ this.#absArtifactDir = path35.resolve(this.#artifactDir);
10535
12091
  }
10536
12092
  async build() {
10537
12093
  const akanConfig2 = await this.#app.getConfig();
@@ -10553,7 +12109,7 @@ class SsrBaseArtifactBuilder {
10553
12109
  rscRuntimeSsrManifest,
10554
12110
  vendorMap,
10555
12111
  cssAssets,
10556
- pagesBundlePath: this.#command === "build" ? path33.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
12112
+ pagesBundlePath: this.#command === "build" ? path35.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
10557
12113
  pagesBundleBuildId: pagesBundle.buildId,
10558
12114
  domains: [...akanConfig2.domains],
10559
12115
  subRoutes: Object.fromEntries(Array.from(akanConfig2.subRoutes.entries()).map(([basePath2, domains]) => [basePath2, [...domains]])),
@@ -10562,7 +12118,7 @@ class SsrBaseArtifactBuilder {
10562
12118
  i18n: akanConfig2.i18n,
10563
12119
  imageConfig: akanConfig2.images
10564
12120
  };
10565
- await Bun.write(path33.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
12121
+ await Bun.write(path35.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
10566
12122
  `);
10567
12123
  this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
10568
12124
  return { artifact, seedIndex, cssCompiler, optimizedFonts };
@@ -10610,15 +12166,15 @@ class SsrBaseArtifactBuilder {
10610
12166
  async#resolveAkanServerPath() {
10611
12167
  const candidates = [];
10612
12168
  try {
10613
- candidates.push(path33.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
12169
+ candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
10614
12170
  } catch {}
10615
- candidates.push(path33.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path33.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
12171
+ candidates.push(path35.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path35.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
10616
12172
  try {
10617
- candidates.push(path33.dirname(Bun.resolveSync("akanjs/server", path33.dirname(Bun.main))));
12173
+ candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", path35.dirname(Bun.main))));
10618
12174
  } catch {}
10619
- candidates.push(path33.join(path33.dirname(Bun.main), "node_modules/akanjs/server"), path33.join(path33.dirname(Bun.main), "../../akanjs/server"), path33.resolve(import.meta.dir, "../../server"), path33.resolve(import.meta.dir, "../server"));
12175
+ candidates.push(path35.join(path35.dirname(Bun.main), "node_modules/akanjs/server"), path35.join(path35.dirname(Bun.main), "../../akanjs/server"), path35.resolve(import.meta.dir, "../../server"), path35.resolve(import.meta.dir, "../server"));
10620
12176
  for (const candidate of candidates) {
10621
- if (await Bun.file(path33.join(candidate, "rscClient.tsx")).exists())
12177
+ if (await Bun.file(path35.join(candidate, "rscClient.tsx")).exists())
10622
12178
  return candidate;
10623
12179
  }
10624
12180
  throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
@@ -10647,14 +12203,14 @@ ${preparedCssText}`).toString(36);
10647
12203
  `styles/${cssAssetName}-${cssHash}.css`,
10648
12204
  `/_akan/styles/${cssAssetName}-${cssHash}.css`
10649
12205
  ];
10650
- await Bun.write(path33.join(this.#absArtifactDir, cssRelPath), preparedCssText);
12206
+ await Bun.write(path35.join(this.#absArtifactDir, cssRelPath), preparedCssText);
10651
12207
  this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
10652
12208
  return [basePath2, { cssUrl, cssRelPath }];
10653
12209
  }
10654
12210
  }
10655
12211
  // pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
10656
12212
  import fs6 from "fs";
10657
- import path34 from "path";
12213
+ import path36 from "path";
10658
12214
 
10659
12215
  class WatchRootResolver {
10660
12216
  #app;
@@ -10664,15 +12220,15 @@ class WatchRootResolver {
10664
12220
  async resolve() {
10665
12221
  const tsconfig = await this.#app.getTsConfig();
10666
12222
  const set = new Set;
10667
- set.add(path34.resolve(`${this.#app.cwdPath}/page`));
12223
+ set.add(path36.resolve(`${this.#app.cwdPath}/page`));
10668
12224
  for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
10669
12225
  for (const target of targets) {
10670
12226
  if (!target)
10671
12227
  continue;
10672
- if (path34.isAbsolute(target))
12228
+ if (path36.isAbsolute(target))
10673
12229
  continue;
10674
12230
  const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
10675
- const resolved = path34.resolve(this.#app.workspace.workspaceRoot, cleaned);
12231
+ const resolved = path36.resolve(this.#app.workspace.workspaceRoot, cleaned);
10676
12232
  if (fs6.existsSync(resolved))
10677
12233
  set.add(resolved);
10678
12234
  }
@@ -10739,7 +12295,7 @@ class ApplicationBuildRunner {
10739
12295
  phases: this.#phases,
10740
12296
  durationMs: Date.now() - this.#startedAt,
10741
12297
  outputDir: this.#app.dist.cwdPath,
10742
- artifactDir: path35.join(this.#app.dist.cwdPath, ".akan/artifact")
12298
+ artifactDir: path37.join(this.#app.dist.cwdPath, ".akan/artifact")
10743
12299
  };
10744
12300
  }
10745
12301
  async typecheck(options = {}) {
@@ -10747,7 +12303,7 @@ class ApplicationBuildRunner {
10747
12303
  await this.#app.getPageKeys({ refresh: true });
10748
12304
  const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
10749
12305
  if (clean)
10750
- await rm3(path35.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
12306
+ await rm3(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
10751
12307
  await this.#checkProjectInChildProcess(tsconfigPath);
10752
12308
  }
10753
12309
  async#runPhase(id, label, task, summarize, options = {}) {
@@ -10819,7 +12375,7 @@ class ApplicationBuildRunner {
10819
12375
  };
10820
12376
  }
10821
12377
  async#writeConsoleShim() {
10822
- await Bun.write(path35.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
12378
+ await Bun.write(path37.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
10823
12379
  import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
10824
12380
 
10825
12381
  const run = async () => {
@@ -10842,14 +12398,14 @@ void run().catch((error) => {
10842
12398
  try {
10843
12399
  return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
10844
12400
  } catch {
10845
- return path35.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
12401
+ return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
10846
12402
  }
10847
12403
  }
10848
12404
  #resolveConsoleRuntimeBuildEntry() {
10849
12405
  try {
10850
- return path35.join(path35.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
12406
+ return path37.join(path37.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
10851
12407
  } catch {
10852
- return path35.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
12408
+ return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
10853
12409
  }
10854
12410
  }
10855
12411
  async#buildCsr() {
@@ -10866,7 +12422,7 @@ void run().catch((error) => {
10866
12422
  return { base, allRoutes };
10867
12423
  }
10868
12424
  async#writeTypecheckTsconfig({ incremental = true } = {}) {
10869
- const typecheckDir = path35.join(this.#app.cwdPath, ".akan", "typecheck");
12425
+ const typecheckDir = path37.join(this.#app.cwdPath, ".akan", "typecheck");
10870
12426
  await mkdir8(typecheckDir, { recursive: true });
10871
12427
  const tsconfig = {
10872
12428
  extends: "../../tsconfig.json",
@@ -10885,7 +12441,7 @@ void run().catch((error) => {
10885
12441
  ],
10886
12442
  references: []
10887
12443
  };
10888
- const tsconfigPath = path35.join(typecheckDir, "tsconfig.json");
12444
+ const tsconfigPath = path37.join(typecheckDir, "tsconfig.json");
10889
12445
  await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
10890
12446
  `);
10891
12447
  return { typecheckDir, tsconfigPath };
@@ -10911,10 +12467,10 @@ void run().catch((error) => {
10911
12467
  }
10912
12468
  async#resolveTypecheckWorkerEntry() {
10913
12469
  const candidates = [
10914
- path35.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
10915
- path35.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
10916
- path35.join(import.meta.dir, "typecheck.proc.js"),
10917
- path35.join(import.meta.dir, "typecheck.proc.ts")
12470
+ path37.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
12471
+ path37.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
12472
+ path37.join(import.meta.dir, "typecheck.proc.js"),
12473
+ path37.join(import.meta.dir, "typecheck.proc.ts")
10918
12474
  ];
10919
12475
  for (const candidate of candidates)
10920
12476
  if (await Bun.file(candidate).exists())
@@ -11090,13 +12646,13 @@ class ApplicationReleasePackager {
11090
12646
  await cp(this.#app.dist.cwdPath, `${sourceRoot}/apps/${this.#app.name}`, { recursive: true });
11091
12647
  const libDeps = ["social", "shared", "platform", "util"];
11092
12648
  await Promise.all(libDeps.map((lib) => cp(`${this.#app.workspace.cwdPath}/libs/${lib}`, `${sourceRoot}/libs/${lib}`, { recursive: true })));
11093
- await Promise.all([".next", "ios", "android", "public/libs"].map(async (path36) => {
11094
- const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path36}`;
12649
+ await Promise.all([".next", "ios", "android", "public/libs"].map(async (path38) => {
12650
+ const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path38}`;
11095
12651
  if (await FileSys.dirExists(targetPath))
11096
12652
  await rm4(targetPath, { recursive: true, force: true });
11097
12653
  }));
11098
12654
  const syncPaths = [".husky", ".gitignore", "package.json"];
11099
- await Promise.all(syncPaths.map((path36) => cp(`${this.#app.workspace.cwdPath}/${path36}`, `${sourceRoot}/${path36}`, { recursive: true })));
12655
+ await Promise.all(syncPaths.map((path38) => cp(`${this.#app.workspace.cwdPath}/${path38}`, `${sourceRoot}/${path38}`, { recursive: true })));
11100
12656
  await this.#writeSourceTsconfig(sourceRoot, libDeps);
11101
12657
  await Bun.write(`${sourceRoot}/README.md`, readme);
11102
12658
  await this.#app.workspace.spawn("tar", [
@@ -11187,20 +12743,20 @@ class ApplicationReleasePackager {
11187
12743
  }
11188
12744
  }
11189
12745
  // pkgs/@akanjs/devkit/applicationTestPreload.ts
11190
- import path36 from "path";
12746
+ import path38 from "path";
11191
12747
  var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
11192
12748
  async function resolveSignalTestPreloadPath(target) {
11193
12749
  const candidates = [];
11194
12750
  const addResolvedPackageCandidate = (basePath2) => {
11195
12751
  try {
11196
- candidates.push(path36.join(path36.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
12752
+ candidates.push(path38.join(path38.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
11197
12753
  } catch {}
11198
12754
  };
11199
12755
  addResolvedPackageCandidate(target.cwdPath);
11200
12756
  addResolvedPackageCandidate(process.cwd());
11201
- addResolvedPackageCandidate(path36.dirname(Bun.main));
12757
+ addResolvedPackageCandidate(path38.dirname(Bun.main));
11202
12758
  addResolvedPackageCandidate(import.meta.dir);
11203
- candidates.push(path36.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path36.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path36.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path36.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path36.join(path36.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path36.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
12759
+ candidates.push(path38.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(path38.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
11204
12760
  for (const candidate of [...new Set(candidates)]) {
11205
12761
  if (await Bun.file(candidate).exists())
11206
12762
  return candidate;
@@ -11210,7 +12766,7 @@ async function resolveSignalTestPreloadPath(target) {
11210
12766
  // pkgs/@akanjs/devkit/builder.ts
11211
12767
  import { existsSync as existsSync2 } from "fs";
11212
12768
  import { mkdir as mkdir10 } from "fs/promises";
11213
- import path37 from "path";
12769
+ import path39 from "path";
11214
12770
  var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
11215
12771
  var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
11216
12772
  var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
@@ -11227,14 +12783,14 @@ class Builder {
11227
12783
  #globEntrypoints(cwd, pattern) {
11228
12784
  const glob = new Bun.Glob(pattern);
11229
12785
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
11230
- const segments = relativePath.split(path37.sep);
12786
+ const segments = relativePath.split(path39.sep);
11231
12787
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
11232
- }).map((rel) => path37.join(cwd, rel));
12788
+ }).map((rel) => path39.join(cwd, rel));
11233
12789
  }
11234
12790
  #globFiles(cwd, pattern = "**/*.*") {
11235
12791
  const glob = new Bun.Glob(pattern);
11236
12792
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
11237
- const segments = relativePath.split(path37.sep);
12793
+ const segments = relativePath.split(path39.sep);
11238
12794
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
11239
12795
  });
11240
12796
  }
@@ -11242,17 +12798,17 @@ class Builder {
11242
12798
  const out = [];
11243
12799
  for (const p of additionalEntryPoints) {
11244
12800
  if (p.includes("*")) {
11245
- const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path37.sep}`) ? p.slice(cwd.length + 1) : p;
12801
+ const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path39.sep}`) ? p.slice(cwd.length + 1) : p;
11246
12802
  out.push(...this.#globEntrypoints(cwd, rel));
11247
12803
  } else
11248
- out.push(path37.isAbsolute(p) ? p : path37.join(cwd, p));
12804
+ out.push(path39.isAbsolute(p) ? p : path39.join(cwd, p));
11249
12805
  }
11250
12806
  return out;
11251
12807
  }
11252
12808
  #getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
11253
12809
  const cwd = this.#executor.cwdPath;
11254
12810
  const entrypoints = [
11255
- ...bundle ? [path37.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
12811
+ ...bundle ? [path39.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
11256
12812
  ...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
11257
12813
  ];
11258
12814
  return {
@@ -11273,9 +12829,9 @@ class Builder {
11273
12829
  for (const relativePath of this.#globFiles(cwd)) {
11274
12830
  if (relativePath === "package.json")
11275
12831
  continue;
11276
- const sourcePath = path37.join(cwd, relativePath);
11277
- const targetPath = path37.join(this.#distExecutor.cwdPath, relativePath);
11278
- await mkdir10(path37.dirname(targetPath), { recursive: true });
12832
+ const sourcePath = path39.join(cwd, relativePath);
12833
+ const targetPath = path39.join(this.#distExecutor.cwdPath, relativePath);
12834
+ await mkdir10(path39.dirname(targetPath), { recursive: true });
11279
12835
  await Bun.write(targetPath, Bun.file(sourcePath));
11280
12836
  }
11281
12837
  }
@@ -11286,13 +12842,13 @@ class Builder {
11286
12842
  return withoutFormatDir;
11287
12843
  if (!hasDotSlash && withoutFormatDir === publishedPath)
11288
12844
  return publishedPath;
11289
- const parsed = path37.posix.parse(withoutFormatDir);
12845
+ const parsed = path39.posix.parse(withoutFormatDir);
11290
12846
  if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
11291
12847
  return withoutFormatDir;
11292
- const withoutExt = path37.posix.join(parsed.dir, parsed.name);
12848
+ const withoutExt = path39.posix.join(parsed.dir, parsed.name);
11293
12849
  const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
11294
12850
  const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
11295
- const matchedSource = sourceCandidates.find((candidate) => existsSync2(path37.join(this.#executor.cwdPath, candidate)));
12851
+ const matchedSource = sourceCandidates.find((candidate) => existsSync2(path39.join(this.#executor.cwdPath, candidate)));
11296
12852
  if (!matchedSource)
11297
12853
  return withoutFormatDir;
11298
12854
  return hasDotSlash ? `./${matchedSource}` : matchedSource;
@@ -11343,10 +12899,10 @@ class Builder {
11343
12899
  // pkgs/@akanjs/devkit/capacitorApp.ts
11344
12900
  import { cp as cp2, mkdir as mkdir11, rm as rm5 } from "fs/promises";
11345
12901
  import os from "os";
11346
- import path38 from "path";
12902
+ import path40 from "path";
11347
12903
  import { select as select2 } from "@inquirer/prompts";
11348
12904
  import { MobileProject } from "@trapezedev/project";
11349
- import { capitalize as capitalize6 } from "akanjs/common";
12905
+ import { capitalize as capitalize5 } from "akanjs/common";
11350
12906
 
11351
12907
  // pkgs/@akanjs/devkit/fileEditor.ts
11352
12908
  class FileEditor {
@@ -11550,13 +13106,13 @@ var rootCapacitorConfigFilenames = [
11550
13106
  "capacitor.config.js",
11551
13107
  "capacitor.config.json"
11552
13108
  ];
11553
- var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path38.join(appRoot, file));
13109
+ var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path40.join(appRoot, file));
11554
13110
  async function clearRootCapacitorConfigs(appRoot) {
11555
13111
  await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm5(file, { force: true })));
11556
13112
  }
11557
13113
  async function writeRootCapacitorConfig(appRoot, content) {
11558
13114
  await clearRootCapacitorConfigs(appRoot);
11559
- await Bun.write(path38.join(appRoot, "capacitor.config.json"), content);
13115
+ await Bun.write(path40.join(appRoot, "capacitor.config.json"), content);
11560
13116
  }
11561
13117
  var getLocalIP = () => {
11562
13118
  const interfaces = os.networkInterfaces();
@@ -11570,7 +13126,7 @@ var getLocalIP = () => {
11570
13126
  }
11571
13127
  return "127.0.0.1";
11572
13128
  };
11573
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13129
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
11574
13130
  var asString = (value) => typeof value === "string" ? value : undefined;
11575
13131
  var firstString = (...values) => values.find((value) => typeof value === "string");
11576
13132
  var scoreIosDeviceTarget = (target) => {
@@ -11594,7 +13150,7 @@ function walkRecords(value, visit) {
11594
13150
  walkRecords(item, visit);
11595
13151
  return;
11596
13152
  }
11597
- if (!isRecord(value))
13153
+ if (!isRecord2(value))
11598
13154
  return;
11599
13155
  visit(value);
11600
13156
  for (const item of Object.values(value))
@@ -11605,9 +13161,9 @@ function parseDevicectlDevices(output) {
11605
13161
  const json = JSON.parse(output);
11606
13162
  const targets = new Map;
11607
13163
  walkRecords(json, (record) => {
11608
- const deviceProperties = isRecord(record.deviceProperties) ? record.deviceProperties : {};
11609
- const hardwareProperties = isRecord(record.hardwareProperties) ? record.hardwareProperties : {};
11610
- const connectionProperties = isRecord(record.connectionProperties) ? record.connectionProperties : {};
13164
+ const deviceProperties = isRecord2(record.deviceProperties) ? record.deviceProperties : {};
13165
+ const hardwareProperties = isRecord2(record.hardwareProperties) ? record.hardwareProperties : {};
13166
+ const connectionProperties = isRecord2(record.connectionProperties) ? record.connectionProperties : {};
11611
13167
  const devicectlId = firstString(record.identifier, record.deviceIdentifier);
11612
13168
  const potentialHostnames = Array.isArray(connectionProperties.potentialHostnames) ? connectionProperties.potentialHostnames.filter((value) => typeof value === "string") : [];
11613
13169
  const hostnameUdid = potentialHostnames.map((hostname) => hostname.match(/([0-9A-Fa-f]{8}-[0-9A-Fa-f]{16})\.coredevice\.local/)?.[1]).find((value) => Boolean(value));
@@ -11640,7 +13196,7 @@ function parseSimctlDevices(output) {
11640
13196
  try {
11641
13197
  const json = JSON.parse(output);
11642
13198
  const devices = json.devices ?? {};
11643
- return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(isRecord).flatMap((device) => {
13199
+ return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(isRecord2).flatMap((device) => {
11644
13200
  const id = firstString(device.udid, device.UDID, device.identifier);
11645
13201
  const name = firstString(device.name, device.displayName);
11646
13202
  const isAvailable = device.isAvailable !== false && device.availabilityError === undefined;
@@ -11665,13 +13221,13 @@ function buildIosNativeRunCommand({
11665
13221
  scheme = "App",
11666
13222
  configuration = "Debug"
11667
13223
  }) {
11668
- const derivedDataPath = path38.join(appRoot, "ios/DerivedData", device.id);
13224
+ const derivedDataPath = path40.join(appRoot, "ios/DerivedData", device.id);
11669
13225
  const productPlatform = device.kind === "device" ? "iphoneos" : "iphonesimulator";
11670
13226
  const destination = device.kind === "device" ? `id=${device.xcodebuildId ?? device.id}` : `platform=iOS Simulator,id=${device.id}`;
11671
13227
  return {
11672
13228
  configuration,
11673
13229
  derivedDataPath,
11674
- appPath: path38.join(derivedDataPath, "Build/Products", `${configuration}-${productPlatform}`, "App.app"),
13230
+ appPath: path40.join(derivedDataPath, "Build/Products", `${configuration}-${productPlatform}`, "App.app"),
11675
13231
  xcodebuildArgs: [
11676
13232
  "-project",
11677
13233
  "App.xcodeproj",
@@ -11872,16 +13428,16 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
11872
13428
  experimental,
11873
13429
  ...capacitorConfig
11874
13430
  } = target;
11875
- const serverConfig = isRecord(server) ? server : undefined;
11876
- const cordovaConfig = isRecord(cordova) ? cordova : undefined;
11877
- const experimentalConfig = isRecord(experimental) ? experimental : undefined;
11878
- const pluginsConfig = isRecord(plugins) ? plugins : {};
11879
- const keyboardPluginConfig = isRecord(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
13431
+ const serverConfig = isRecord2(server) ? server : undefined;
13432
+ const cordovaConfig = isRecord2(cordova) ? cordova : undefined;
13433
+ const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
13434
+ const pluginsConfig = isRecord2(plugins) ? plugins : {};
13435
+ const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
11880
13436
  const config = {
11881
13437
  ...capacitorConfig,
11882
13438
  appId,
11883
13439
  appName,
11884
- webDir: path38.posix.join(".akan", "mobile", name, "www"),
13440
+ webDir: path40.posix.join(".akan", "mobile", name, "www"),
11885
13441
  plugins: {
11886
13442
  CapacitorCookies: { enabled: true },
11887
13443
  ...pluginsConfig,
@@ -11891,11 +13447,11 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
11891
13447
  }
11892
13448
  },
11893
13449
  android: {
11894
- ...isRecord(android) ? android : {},
13450
+ ...isRecord2(android) ? android : {},
11895
13451
  path: "android"
11896
13452
  },
11897
13453
  ios: {
11898
- ...isRecord(ios) ? ios : {},
13454
+ ...isRecord2(ios) ? ios : {},
11899
13455
  path: "ios"
11900
13456
  }
11901
13457
  };
@@ -11938,10 +13494,10 @@ class CapacitorApp {
11938
13494
  constructor(app, target) {
11939
13495
  this.app = app;
11940
13496
  this.target = target;
11941
- this.targetRootPath = path38.posix.join(".akan", "mobile", this.target.name);
11942
- this.targetRoot = path38.join(this.app.cwdPath, this.targetRootPath);
11943
- this.targetWebRoot = path38.join(this.targetRoot, "www");
11944
- this.targetAssetRoot = path38.join(this.targetRoot, "assets");
13497
+ this.targetRootPath = path40.posix.join(".akan", "mobile", this.target.name);
13498
+ this.targetRoot = path40.join(this.app.cwdPath, this.targetRootPath);
13499
+ this.targetWebRoot = path40.join(this.targetRoot, "www");
13500
+ this.targetAssetRoot = path40.join(this.targetRoot, "assets");
11945
13501
  this.project = new MobileProject(this.app.cwdPath, {
11946
13502
  android: { path: this.androidRootPath },
11947
13503
  ios: { path: this.iosProjectPath }
@@ -11956,9 +13512,9 @@ class CapacitorApp {
11956
13512
  await mkdir11(this.targetRoot, { recursive: true });
11957
13513
  if (regenerate) {
11958
13514
  if (!platform || platform === "ios")
11959
- await rm5(path38.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
13515
+ await rm5(path40.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
11960
13516
  if (!platform || platform === "android")
11961
- await rm5(path38.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
13517
+ await rm5(path40.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
11962
13518
  }
11963
13519
  const project = this.project;
11964
13520
  await this.project.load();
@@ -12081,7 +13637,7 @@ ${textError instanceof Error ? textError.message : ""}`);
12081
13637
  const xcodebuildArgs = noAllowProvisioningUpdates ? command.xcodebuildArgs : [...command.xcodebuildArgs.slice(0, -1), "-allowProvisioningUpdates", ...command.xcodebuildArgs.slice(-1)];
12082
13638
  try {
12083
13639
  await this.#spawn("xcodebuild", xcodebuildArgs, {
12084
- cwd: path38.join(this.app.cwdPath, this.iosProjectPath),
13640
+ cwd: path40.join(this.app.cwdPath, this.iosProjectPath),
12085
13641
  env: mobileEnv
12086
13642
  });
12087
13643
  const devicectlId = runTarget.devicectlId ?? runTarget.id;
@@ -12103,10 +13659,10 @@ ${textError instanceof Error ? textError.message : ""}`);
12103
13659
  }
12104
13660
  }
12105
13661
  #iosScheme() {
12106
- return isRecord(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
13662
+ return isRecord2(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
12107
13663
  }
12108
13664
  async#getIosDevelopmentTeam() {
12109
- const pbxprojPath = path38.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
13665
+ const pbxprojPath = path40.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
12110
13666
  if (!await Bun.file(pbxprojPath).exists())
12111
13667
  return;
12112
13668
  return (await Bun.file(pbxprojPath).text()).match(/DEVELOPMENT_TEAM = ([^;]+);/)?.[1]?.trim();
@@ -12132,7 +13688,7 @@ ${error.message}`;
12132
13688
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
12133
13689
  }
12134
13690
  async#updateAndroidBuildTypes() {
12135
- const appGradle = await FileEditor.create(path38.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
13691
+ const appGradle = await FileEditor.create(path40.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
12136
13692
  const buildTypesBlock = `
12137
13693
  debug {
12138
13694
  applicationIdSuffix ".debug"
@@ -12176,7 +13732,7 @@ ${error.message}`;
12176
13732
  const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
12177
13733
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
12178
13734
  stdio: "inherit",
12179
- cwd: path38.join(this.app.cwdPath, this.androidRootPath),
13735
+ cwd: path40.join(this.app.cwdPath, this.androidRootPath),
12180
13736
  env: await this.#commandEnv("release", env)
12181
13737
  });
12182
13738
  }
@@ -12184,10 +13740,10 @@ ${error.message}`;
12184
13740
  await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
12185
13741
  }
12186
13742
  async#ensureAndroidAssetsDir() {
12187
- await mkdir11(path38.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
13743
+ await mkdir11(path40.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
12188
13744
  }
12189
13745
  async#ensureAndroidDebugKeystore() {
12190
- const keystorePath = path38.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
13746
+ const keystorePath = path40.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
12191
13747
  if (await Bun.file(keystorePath).exists())
12192
13748
  return;
12193
13749
  await this.#spawn("keytool", [
@@ -12226,7 +13782,7 @@ ${error.message}`;
12226
13782
  await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
12227
13783
  }
12228
13784
  async#assertAndroidReleaseSigningConfig() {
12229
- const gradlePropertiesPath = path38.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
13785
+ const gradlePropertiesPath = path40.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
12230
13786
  const gradleProperties = await Bun.file(gradlePropertiesPath).exists() ? await Bun.file(gradlePropertiesPath).text() : "";
12231
13787
  const missingKeys = getMissingAndroidReleaseSigningKeys({ gradleProperties });
12232
13788
  if (missingKeys.length > 0)
@@ -12253,12 +13809,12 @@ ${error.message}`;
12253
13809
  await this.#prepareAndroid({ operation: "release", env: "main" });
12254
13810
  }
12255
13811
  async prepareWww() {
12256
- const htmlSource = path38.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
13812
+ const htmlSource = path40.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
12257
13813
  if (!await Bun.file(htmlSource).exists())
12258
13814
  throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
12259
13815
  await rm5(this.targetWebRoot, { recursive: true, force: true });
12260
13816
  await mkdir11(this.targetWebRoot, { recursive: true });
12261
- await Bun.write(path38.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
13817
+ await Bun.write(path40.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
12262
13818
  }
12263
13819
  #injectMobileTargetMeta(html) {
12264
13820
  const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
@@ -12278,7 +13834,7 @@ ${error.message}`;
12278
13834
  });
12279
13835
  const content = `${JSON.stringify(config, null, 2)}
12280
13836
  `;
12281
- await Bun.write(path38.join(this.targetRoot, "capacitor.config.json"), content);
13837
+ await Bun.write(path40.join(this.targetRoot, "capacitor.config.json"), content);
12282
13838
  return content;
12283
13839
  }
12284
13840
  async#prepareTargetAssets() {
@@ -12286,11 +13842,11 @@ ${error.message}`;
12286
13842
  return;
12287
13843
  await mkdir11(this.targetAssetRoot, { recursive: true });
12288
13844
  if (this.target.assets.icon)
12289
- await cp2(path38.join(this.app.cwdPath, this.target.assets.icon), path38.join(this.targetAssetRoot, "icon.png"), {
13845
+ await cp2(path40.join(this.app.cwdPath, this.target.assets.icon), path40.join(this.targetAssetRoot, "icon.png"), {
12290
13846
  force: true
12291
13847
  });
12292
13848
  if (this.target.assets.splash)
12293
- await cp2(path38.join(this.app.cwdPath, this.target.assets.splash), path38.join(this.targetAssetRoot, "splash.png"), {
13849
+ await cp2(path40.join(this.app.cwdPath, this.target.assets.splash), path40.join(this.targetAssetRoot, "splash.png"), {
12294
13850
  force: true
12295
13851
  });
12296
13852
  }
@@ -12298,11 +13854,11 @@ ${error.message}`;
12298
13854
  const files = this.target.files?.[platform];
12299
13855
  if (!files)
12300
13856
  return;
12301
- const platformRoot = path38.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
13857
+ const platformRoot = path40.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
12302
13858
  await Promise.all(Object.entries(files).map(async ([to, from]) => {
12303
- const targetPath = path38.join(platformRoot, to);
12304
- await mkdir11(path38.dirname(targetPath), { recursive: true });
12305
- await cp2(path38.join(this.app.cwdPath, from), targetPath, { force: true });
13859
+ const targetPath = path40.join(platformRoot, to);
13860
+ await mkdir11(path40.dirname(targetPath), { recursive: true });
13861
+ await cp2(path40.join(this.app.cwdPath, from), targetPath, { force: true });
12306
13862
  }));
12307
13863
  }
12308
13864
  async#generateAssets({ operation, env }) {
@@ -12312,7 +13868,7 @@ ${error.message}`;
12312
13868
  "@capacitor/assets",
12313
13869
  "generate",
12314
13870
  "--assetPath",
12315
- path38.posix.join(this.targetRootPath, "assets"),
13871
+ path40.posix.join(this.targetRootPath, "assets"),
12316
13872
  "--iosProject",
12317
13873
  this.iosProjectPath,
12318
13874
  "--androidProject",
@@ -12437,7 +13993,7 @@ ${error.message}`;
12437
13993
  this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
12438
13994
  }
12439
13995
  async#setPermissionInIos(permissions) {
12440
- const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize6(key)}`, value]));
13996
+ const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
12441
13997
  await Promise.all([
12442
13998
  this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", updateNs),
12443
13999
  this.project.ios.updateInfoPlist(this.iosTargetName, "Release", updateNs)
@@ -12522,15 +14078,15 @@ var Pkg = createInternalArgToken("Pkg");
12522
14078
  var Module = createInternalArgToken("Module");
12523
14079
  var Workspace = createInternalArgToken("Workspace");
12524
14080
  // pkgs/@akanjs/devkit/commandDecorators/command.ts
12525
- import path39 from "path";
14081
+ import path41 from "path";
12526
14082
  import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
12527
14083
  import { Logger as Logger10 } from "akanjs/common";
12528
14084
  import chalk6 from "chalk";
12529
14085
  import { program } from "commander";
12530
14086
 
12531
14087
  // pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
12532
- var capitalize7 = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
12533
- var createDependencyKey = (refName, kind) => `${refName}${capitalize7(kind)}`;
14088
+ var capitalize6 = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
14089
+ var createDependencyKey = (refName, kind) => `${refName}${capitalize6(kind)}`;
12534
14090
 
12535
14091
  class CommandContainer {
12536
14092
  static #instances = new Map;
@@ -13026,7 +14582,7 @@ var runCommands = async (...commands) => {
13026
14582
  process.exit(1);
13027
14583
  });
13028
14584
  const __dirname2 = getDirname(import.meta.url);
13029
- const packageJsonCandidates = [`${path39.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
14585
+ const packageJsonCandidates = [`${path41.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
13030
14586
  let cliPackageJson = null;
13031
14587
  for (const packageJsonPath of packageJsonCandidates) {
13032
14588
  if (!await FileSys.fileExists(packageJsonPath))
@@ -13269,11 +14825,11 @@ var NODE_NATIVE_MODULE_SET = new Set([
13269
14825
  // pkgs/@akanjs/devkit/getCredentials.ts
13270
14826
  import yaml from "js-yaml";
13271
14827
  // pkgs/@akanjs/devkit/getModelFileData.ts
13272
- import { capitalize as capitalize8 } from "akanjs/common";
14828
+ import { capitalize as capitalize7 } from "akanjs/common";
13273
14829
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
13274
14830
  import { readFileSync as readFileSync4, realpathSync } from "fs";
13275
14831
  import ora2 from "ora";
13276
- import * as ts8 from "typescript";
14832
+ import * as ts10 from "typescript";
13277
14833
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
13278
14834
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
13279
14835
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -13306,10 +14862,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
13306
14862
  return importSpecifiers;
13307
14863
  };
13308
14864
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
13309
- const configFile = ts8.readConfigFile(tsConfigPath, (path40) => {
13310
- return ts8.sys.readFile(path40);
14865
+ const configFile = ts10.readConfigFile(tsConfigPath, (path42) => {
14866
+ return ts10.sys.readFile(path42);
13311
14867
  });
13312
- return ts8.parseJsonConfigFileContent(configFile.config, ts8.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
14868
+ return ts10.parseJsonConfigFileContent(configFile.config, ts10.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
13313
14869
  };
13314
14870
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
13315
14871
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -13324,7 +14880,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13324
14880
  for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
13325
14881
  if (!importPath.startsWith("."))
13326
14882
  continue;
13327
- const resolved = ts8.resolveModuleName(importPath, filePath, parsedConfig.options, ts8.sys).resolvedModule?.resolvedFileName;
14883
+ const resolved = ts10.resolveModuleName(importPath, filePath, parsedConfig.options, ts10.sys).resolvedModule?.resolvedFileName;
13328
14884
  if (resolved && !allFilesToAnalyze.has(resolved)) {
13329
14885
  allFilesToAnalyze.add(resolved);
13330
14886
  collectImported(resolved);
@@ -13341,7 +14897,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
13341
14897
  var createTsProgram = (filePaths, options) => {
13342
14898
  const spinner = ora2("Creating TypeScript program for all files...");
13343
14899
  spinner.start();
13344
- const program2 = ts8.createProgram(Array.from(filePaths), options);
14900
+ const program2 = ts10.createProgram(Array.from(filePaths), options);
13345
14901
  const checker = program2.getTypeChecker();
13346
14902
  spinner.succeed("TypeScript program created.");
13347
14903
  return {
@@ -13381,17 +14937,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13381
14937
  function visit(node) {
13382
14938
  if (!source2)
13383
14939
  return;
13384
- if (ts8.isPropertyAccessExpression(node)) {
14940
+ if (ts10.isPropertyAccessExpression(node)) {
13385
14941
  const left = node.expression;
13386
14942
  const right = node.name;
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},`))) {
14943
+ const { line } = ts10.getLineAndCharacterOfPosition(source2, node.getStart());
14944
+ if (ts10.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},`))) {
13389
14945
  const symbol = getCachedSymbol(right);
13390
14946
  if (symbol?.declarations && symbol.declarations.length > 0) {
13391
14947
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
13392
14948
  const property = propertyMap.get(key);
13393
14949
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
13394
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts8.sys.getCurrentDirectory()}/`, "");
14950
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts10.sys.getCurrentDirectory()}/`, "");
13395
14951
  if (!symbolFilePath)
13396
14952
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
13397
14953
  if (property) {
@@ -13415,10 +14971,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13415
14971
  }
13416
14972
  }
13417
14973
  }
13418
- } else if (ts8.isImportDeclaration(node) && ts8.isStringLiteral(node.moduleSpecifier)) {
14974
+ } else if (ts10.isImportDeclaration(node) && ts10.isStringLiteral(node.moduleSpecifier)) {
13419
14975
  const importPath = node.moduleSpecifier.text;
13420
14976
  if (importPath.startsWith(".")) {
13421
- const resolved = ts8.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts8.sys).resolvedModule?.resolvedFileName;
14977
+ const resolved = ts10.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts10.sys).resolvedModule?.resolvedFileName;
13422
14978
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
13423
14979
  const property = propertyMap.get(moduleName);
13424
14980
  const isScalar = importPath.includes("_");
@@ -13433,7 +14989,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
13433
14989
  }
13434
14990
  }
13435
14991
  }
13436
- ts8.forEachChild(node, visit);
14992
+ ts10.forEachChild(node, visit);
13437
14993
  }
13438
14994
  visit(source2);
13439
14995
  }
@@ -13640,10 +15196,10 @@ class IncrementalBuilder {
13640
15196
  }
13641
15197
  }
13642
15198
  batchTouchesPagesTree(appDir, batch) {
13643
- const absAppDir = path40.resolve(appDir);
15199
+ const absAppDir = path42.resolve(appDir);
13644
15200
  for (const f of batch.files) {
13645
- const abs = path40.resolve(f);
13646
- if (!abs.startsWith(`${absAppDir}${path40.sep}`) && abs !== absAppDir)
15201
+ const abs = path42.resolve(f);
15202
+ if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
13647
15203
  continue;
13648
15204
  if (/\.(tsx|ts|jsx|js)$/.test(abs))
13649
15205
  return true;
@@ -13651,15 +15207,15 @@ class IncrementalBuilder {
13651
15207
  return false;
13652
15208
  }
13653
15209
  async batchMayChangePageKeys(appDir, batch) {
13654
- const absAppDir = path40.resolve(appDir);
13655
- const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path40.normalize(key)));
15210
+ const absAppDir = path42.resolve(appDir);
15211
+ const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path42.normalize(key)));
13656
15212
  for (const f of batch.files) {
13657
- const abs = path40.resolve(f);
13658
- if (!abs.startsWith(`${absAppDir}${path40.sep}`) && abs !== absAppDir)
15213
+ const abs = path42.resolve(f);
15214
+ if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
13659
15215
  continue;
13660
15216
  if (!/\.(tsx|ts|jsx|js)$/.test(abs))
13661
15217
  continue;
13662
- const rel = path40.normalize(path40.relative(absAppDir, abs));
15218
+ const rel = path42.normalize(path42.relative(absAppDir, abs));
13663
15219
  if (!await Bun.file(abs).exists() || !pageKeys.has(rel))
13664
15220
  return true;
13665
15221
  }
@@ -13687,7 +15243,7 @@ class IncrementalBuilder {
13687
15243
  ${cssText}`).toString(36);
13688
15244
  const cssRelPath = `styles/${cssAssetName}-${cssHash}.css`;
13689
15245
  const cssUrl = `/_akan/styles/${cssAssetName}-${cssHash}.css`;
13690
- await Bun.write(path40.join(artifactDir, cssRelPath), cssText);
15246
+ await Bun.write(path42.join(artifactDir, cssRelPath), cssText);
13691
15247
  cssAssetEntries.push([basePath2, { cssUrl, cssRelPath }]);
13692
15248
  cssBase64ByUrl[cssUrl] = Buffer.from(new TextEncoder().encode(cssText)).toString("base64");
13693
15249
  })()
@@ -13755,10 +15311,10 @@ ${cssText}`).toString(36);
13755
15311
  if (changedFiles.length === 0)
13756
15312
  return false;
13757
15313
  return changedFiles.some((file) => {
13758
- const normalized = path40.resolve(file);
15314
+ const normalized = path42.resolve(file);
13759
15315
  if (/\.(woff2?|ttf|otf)$/i.test(normalized))
13760
15316
  return true;
13761
- return this.#optimizedFonts.files.some((fontFile) => path40.resolve(fontFile) === normalized);
15317
+ return this.#optimizedFonts.files.some((fontFile) => path42.resolve(fontFile) === normalized);
13762
15318
  });
13763
15319
  }
13764
15320
  async installWatcher() {