@akanjs/cli 2.3.9-rc.8 → 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.
@@ -4799,6 +4799,11 @@ var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!d
4799
4799
 
4800
4800
  // pkgs/@akanjs/devkit/workflow/artifacts.ts
4801
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
+ };
4802
4807
  var inferNextActionCode = (action, diagnostics) => {
4803
4808
  if (action.action)
4804
4809
  return action.action;
@@ -4843,13 +4848,19 @@ var createWorkflowApplyReport = ({
4843
4848
  });
4844
4849
  }
4845
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}`);
4846
4853
  return {
4847
4854
  schemaVersion: 1,
4848
4855
  workflow,
4849
4856
  mode,
4850
4857
  status: workflowStatus(diagnostics),
4851
- changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4852
- generatedFiles: uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4858
+ summary: {
4859
+ sourceFilesChanged,
4860
+ generatedFilesSynced
4861
+ },
4862
+ changedFiles: sourceFilesChanged,
4863
+ generatedFiles: generatedFilesSynced,
4853
4864
  appliedCommands: uniqueBy(appliedCommands, (command) => command.command),
4854
4865
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
4855
4866
  commands: uniqueBy(validationCommands, (command) => command.command),
@@ -4927,6 +4938,52 @@ var statusForValidationKind = (commands, kind) => {
4927
4938
  return "unknown";
4928
4939
  return matching.some((command) => command.status === "failed") ? "failed" : "passed";
4929
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
+ };
4930
4987
  var createKnownBlockers = (commands, diagnostics) => {
4931
4988
  const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
4932
4989
  code: `workflow-validation-${command.failureScope}`,
@@ -4955,18 +5012,28 @@ var createKnownBlockers = (commands, diagnostics) => {
4955
5012
  }
4956
5013
  return [...grouped.values()];
4957
5014
  };
4958
- var createValidationStatuses = (commands, diagnostics) => {
5015
+ var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
5016
+ const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
4959
5017
  const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
4960
- 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];
4961
5024
  const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
4962
- 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";
4963
5026
  return {
4964
5027
  sourceStatus,
4965
5028
  workspaceStatus,
5029
+ validationCommandsStatus,
5030
+ baselineStatus,
4966
5031
  overallStatus,
4967
5032
  summary: {
4968
5033
  sourceChange: sourceStatus,
4969
5034
  generatedSync: statusForValidationKind(commands, "sync"),
5035
+ validationCommands: validationCommandsStatus,
5036
+ baseline: baselineStatus,
4970
5037
  workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
4971
5038
  environment: statusForScope(commands, diagnostics, scopes, "environment")
4972
5039
  }
@@ -5000,7 +5067,8 @@ var createWorkflowValidationRunReport = async ({
5000
5067
  ] : []);
5001
5068
  const reportDiagnostics = [...diagnostics, ...commandDiagnostics];
5002
5069
  const scopedDiagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
5003
- const statuses = createValidationStatuses(results, scopedDiagnostics);
5070
+ const knownBlockers = createKnownBlockers(results, scopedDiagnostics);
5071
+ const statuses = createValidationStatuses(results, reportDiagnostics, baselineDiagnostics, workflowDiagnostics);
5004
5072
  return {
5005
5073
  schemaVersion: 1,
5006
5074
  runId,
@@ -5009,9 +5077,12 @@ var createWorkflowValidationRunReport = async ({
5009
5077
  source,
5010
5078
  status: statuses.overallStatus === "passed" ? "passed" : "failed",
5011
5079
  ...statuses,
5012
- knownBlockers: createKnownBlockers(results, scopedDiagnostics),
5080
+ knownBlockers,
5013
5081
  commands: results,
5014
5082
  diagnostics: reportDiagnostics,
5083
+ baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
5084
+ knownBlockerCount: knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config").length
5085
+ }),
5015
5086
  baselineDiagnostics,
5016
5087
  workflowDiagnostics,
5017
5088
  repairActions: uniqueBy(repairActions, (action) => action.command),
@@ -6327,7 +6398,7 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
6327
6398
  return null;
6328
6399
  const content = await workspace.readFile(filePath);
6329
6400
  const source = ts6.createSourceFile(filePath, content, ts6.ScriptTarget.Latest, true, scriptKind);
6330
- const diagnostic = source.parseDiagnostics[0];
6401
+ const diagnostic = (source.parseDiagnostics ?? [])[0];
6331
6402
  if (!diagnostic)
6332
6403
  return null;
6333
6404
  const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
@@ -6525,9 +6596,9 @@ var addFieldUiSurfaceInspection = (plan) => {
6525
6596
  code: "add-field-ui-surface-review",
6526
6597
  kind: "manual-action",
6527
6598
  target,
6528
- 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.`,
6529
6600
  confidence: "medium",
6530
- 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}.`
6531
6602
  }
6532
6603
  ],
6533
6604
  nextActions: [
@@ -6782,10 +6853,48 @@ var createAddFieldDefaultRecommendations = (inputs) => {
6782
6853
  kind: "manual-action",
6783
6854
  confidence: "high",
6784
6855
  message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
6785
- 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."
6786
6857
  }
6787
6858
  ];
6788
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
+ };
6789
6898
  var createAddFieldRecommendations = (inputs) => {
6790
6899
  const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
6791
6900
  const module = typeof inputs.module === "string" ? inputs.module : "<module>";
@@ -6846,9 +6955,9 @@ var createAddFieldRecommendations = (inputs) => {
6846
6955
  code: "add-field-light-projection-choice",
6847
6956
  kind: "manual-action",
6848
6957
  target: paths.constant,
6849
- action: `Pass includeInLight=true when ${field} should appear in Light${capitalize2(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.`,
6850
6959
  confidence: "medium",
6851
- message: `Light projection exposure for ${module}.${field} is not selected yet.`
6960
+ message: `${module}.${field} is not selected for list/card projection data.`
6852
6961
  }
6853
6962
  ] : [],
6854
6963
  ...includeInLight ? [
@@ -6866,18 +6975,20 @@ var createAddFieldRecommendations = (inputs) => {
6866
6975
  kind: "manual-action",
6867
6976
  target: paths.template,
6868
6977
  confidence: "medium",
6869
- 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.`
6870
6980
  }
6871
6981
  ] : [],
6872
6982
  {
6873
6983
  code: "add-field-ui-manual-review",
6874
6984
  kind: "manual-action",
6875
6985
  target: paths.template,
6876
- 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${capitalize2(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.`,
6877
6987
  confidence: "medium",
6878
- 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.`
6879
6989
  },
6880
- ...createAddFieldDefaultRecommendations(inputs)
6990
+ ...createAddFieldDefaultRecommendations(inputs),
6991
+ ...createAddFieldInputRecommendations(inputs)
6881
6992
  ];
6882
6993
  };
6883
6994
  var createWorkflowPlanPredictedChanges = (spec, inputs) => {
@@ -7020,7 +7131,8 @@ var createWorkflowPlan = (spec, rawInputs) => {
7020
7131
  validation: spec.validation,
7021
7132
  diagnostics,
7022
7133
  recommendations: createWorkflowPlanRecommendations(spec, inputs),
7023
- requiresApproval: true
7134
+ requiresApproval: true,
7135
+ approval: workflowPlanApproval
7024
7136
  };
7025
7137
  };
7026
7138
  // pkgs/@akanjs/devkit/workflow/render.ts
@@ -7058,6 +7170,7 @@ var renderWorkflowPlan = (plan) => [
7058
7170
  "",
7059
7171
  `- Mode: ${plan.mode}`,
7060
7172
  `- Requires approval: ${plan.requiresApproval}`,
7173
+ `- Approval: ${plan.approval?.meaning ?? "Review this read-only plan before applying workflow mutations."}`,
7061
7174
  "",
7062
7175
  "## Inputs",
7063
7176
  ...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
@@ -7094,6 +7207,10 @@ var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.
7094
7207
  var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
7095
7208
  var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
7096
7209
  var renderWorkflowApplyReport = (report) => {
7210
+ const applySummary = {
7211
+ sourceFilesChanged: report.summary?.sourceFilesChanged ?? report.changedFiles,
7212
+ generatedFilesSynced: report.summary?.generatedFilesSynced ?? report.generatedFiles
7213
+ };
7097
7214
  const manualReviewItems = [
7098
7215
  ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
7099
7216
  ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
@@ -7107,6 +7224,8 @@ var renderWorkflowApplyReport = (report) => {
7107
7224
  `- Status: ${report.status}`,
7108
7225
  `- Source-change status: ${applySourceStatus(report)}`,
7109
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}`,
7110
7229
  ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
7111
7230
  "",
7112
7231
  "## Apply Checks",
@@ -7116,10 +7235,10 @@ var renderWorkflowApplyReport = (report) => {
7116
7235
  ...sourceBlockers.length ? sourceBlockers : ["- none"],
7117
7236
  "",
7118
7237
  "## Automatically Modified",
7119
- ...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"],
7120
7239
  "",
7121
7240
  "## Generated Sync",
7122
- ...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"],
7123
7242
  "",
7124
7243
  "## Applied Commands",
7125
7244
  ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
@@ -7146,52 +7265,76 @@ var renderWorkflowApplyReport = (report) => {
7146
7265
  `);
7147
7266
  };
7148
7267
  var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
7149
- var renderWorkflowValidationRunReport = (report) => [
7150
- `# Workflow Validation: ${report.workflow}`,
7151
- "",
7152
- `- Run: ${report.runId}`,
7153
- `- Status: ${report.status}`,
7154
- `- Source status: ${report.sourceStatus}`,
7155
- `- Workspace status: ${report.workspaceStatus}`,
7156
- `- Overall status: ${report.overallStatus}`,
7157
- "",
7158
- "## Status Summary",
7159
- `- Source-change: ${report.summary.sourceChange}`,
7160
- `- Generated sync: ${report.summary.generatedSync}`,
7161
- `- Workspace config: ${report.summary.workspaceConfig}`,
7162
- `- Environment: ${report.summary.environment}`,
7163
- "",
7164
- "## Source Change Diagnostics",
7165
- ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7166
- "",
7167
- "## Existing Workspace Blockers",
7168
- ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7169
- "",
7170
- "## Known Blockers",
7171
- ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
7172
- const command = blocker.command ? ` \`${blocker.command}\`` : "";
7173
- const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
7174
- const known = blocker.known ? " known" : "";
7175
- return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
7176
- }) : ["- none"],
7177
- "",
7178
- "## Commands",
7179
- ...report.commands.length ? report.commands.map((command) => {
7180
- const scope = command.failureScope ? ` (${command.failureScope})` : "";
7181
- return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
7182
- }) : ["- none"],
7183
- "",
7184
- "## Diagnostics",
7185
- ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7186
- "",
7187
- "## Repair Actions",
7188
- ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7189
- "",
7190
- "## Next Actions",
7191
- ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7192
- ""
7193
- ].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(`
7194
7336
  `);
7337
+ };
7195
7338
  var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
7196
7339
  var renderRepairReportMarkdown = (report) => [
7197
7340
  `# Akan Repair: ${report.kind}`,
@@ -7280,7 +7423,11 @@ var toolingRolloutGate = {
7280
7423
  candidates: toolingRolloutCandidates
7281
7424
  };
7282
7425
  var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
7283
- var restrictedCandidates = new Map(toolingRolloutCandidates.filter(isRestrictedCandidate).map((candidate) => [candidate.packageName, candidate]));
7426
+ var restrictedCandidates = new Map;
7427
+ for (const candidate of toolingRolloutCandidates) {
7428
+ if (isRestrictedCandidate(candidate))
7429
+ restrictedCandidates.set(candidate.packageName, candidate);
7430
+ }
7284
7431
  // pkgs/@akanjs/devkit/akanContext.ts
7285
7432
  var resourceList = [
7286
7433
  { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
@@ -7849,6 +7996,7 @@ var applyFirstPolicy = {
7849
7996
  mode: "apply-first",
7850
7997
  directSourceEdits: "fallback-only",
7851
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.",
7852
8000
  validationRequiredAfterApply: ["validationTarget", "applyReportPath"],
7853
8001
  fallbackAllowedWhen: [
7854
8002
  "list_workflows and explain_workflow show no matching workflow",
@@ -7984,7 +8132,12 @@ var readonlyMcpTools = [
7984
8132
  description: "Report workspace diagnostics, optionally split into baseline and workflow scopes.",
7985
8133
  inputSchema: {
7986
8134
  type: "object",
7987
- properties: { strict: booleanProperty, runIdOrPlan: stringProperty, changedFiles: stringArrayProperty }
8135
+ properties: {
8136
+ strict: booleanProperty,
8137
+ runIdOrPlan: stringProperty,
8138
+ changedFiles: stringArrayProperty,
8139
+ includeBaselineDetails: booleanProperty
8140
+ }
7988
8141
  }
7989
8142
  },
7990
8143
  {
@@ -8029,7 +8182,7 @@ var applyMcpTools = [
8029
8182
  description: "Validate a plan, apply report, validationTarget, or run artifact.",
8030
8183
  inputSchema: {
8031
8184
  type: "object",
8032
- properties: { runIdOrPlan: stringProperty },
8185
+ properties: { runIdOrPlan: stringProperty, includeBaselineDetails: booleanProperty },
8033
8186
  required: ["runIdOrPlan"]
8034
8187
  }
8035
8188
  },
@@ -8079,7 +8232,16 @@ var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
8079
8232
  validationStatuses: {
8080
8233
  sourceStatus: ["passed", "failed", "unknown"],
8081
8234
  workspaceStatus: ["passed", "failed", "unknown"],
8082
- overallStatus: ["passed", "failed", "blocked-by-workspace-config", "blocked-by-environment"],
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.",
8083
8245
  knownBlockers: "Repeated workspace-config/environment failures are summarized before command output."
8084
8246
  },
8085
8247
  moduleContextInputs: {
@@ -8090,6 +8252,7 @@ var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
8090
8252
  toolingRolloutGate,
8091
8253
  directEditFallbackPolicy: applyFirstPolicy,
8092
8254
  applyReportFields: [
8255
+ "summary",
8093
8256
  "appliedCommands",
8094
8257
  "recommendedValidationCommands",
8095
8258
  "commands",
@@ -8131,7 +8294,14 @@ var inspectAkanContext = async (workspace, args) => {
8131
8294
  strict: true,
8132
8295
  runIdOrPlan: workspacePath(workspace, props.request.runIdOrPlan)
8133
8296
  });
8134
- diagnostics.push(...doctor.diagnostics.map((diagnostic) => ({
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) => ({
8135
8305
  severity: diagnostic.severity,
8136
8306
  code: diagnostic.code,
8137
8307
  message: diagnostic.message,
@@ -8152,7 +8322,8 @@ var inspectAkanContext = async (workspace, args) => {
8152
8322
  reason: doctor.status === "passed" ? "No strict workspace diagnostics were found for the workflow context." : "Review diagnostics before applying or manually editing source files."
8153
8323
  }, {
8154
8324
  status: doctor.status,
8155
- baselineDiagnostics: doctor.baselineDiagnostics?.length ?? 0,
8325
+ baselineSummary,
8326
+ baselineDiagnostics: 0,
8156
8327
  workflowDiagnostics: doctor.workflowDiagnostics?.length ?? 0
8157
8328
  });
8158
8329
  }
package/index.js CHANGED
@@ -4797,6 +4797,11 @@ var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!d
4797
4797
 
4798
4798
  // pkgs/@akanjs/devkit/workflow/artifacts.ts
4799
4799
  var sourceChangeBlocked = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
4800
+ var workflowPlanApproval = {
4801
+ required: true,
4802
+ meaning: "Review this read-only plan before apply_workflow mutates files.",
4803
+ applyTool: "apply_workflow"
4804
+ };
4800
4805
  var inferNextActionCode = (action, diagnostics) => {
4801
4806
  if (action.action)
4802
4807
  return action.action;
@@ -4841,13 +4846,19 @@ var createWorkflowApplyReport = ({
4841
4846
  });
4842
4847
  }
4843
4848
  const orderedNextActions = uniqueBy(nextActionsWithIntent, (action) => action.command).sort((left, right) => nextActionPriority(left, diagnostics) - nextActionPriority(right, diagnostics));
4849
+ const sourceFilesChanged = uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
4850
+ const generatedFilesSynced = uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
4844
4851
  return {
4845
4852
  schemaVersion: 1,
4846
4853
  workflow,
4847
4854
  mode,
4848
4855
  status: workflowStatus(diagnostics),
4849
- changedFiles: uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4850
- generatedFiles: uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`),
4856
+ summary: {
4857
+ sourceFilesChanged,
4858
+ generatedFilesSynced
4859
+ },
4860
+ changedFiles: sourceFilesChanged,
4861
+ generatedFiles: generatedFilesSynced,
4851
4862
  appliedCommands: uniqueBy(appliedCommands, (command) => command.command),
4852
4863
  recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
4853
4864
  commands: uniqueBy(validationCommands, (command) => command.command),
@@ -4925,6 +4936,52 @@ var statusForValidationKind = (commands, kind) => {
4925
4936
  return "unknown";
4926
4937
  return matching.some((command) => command.status === "failed") ? "failed" : "passed";
4927
4938
  };
4939
+ var statusForCommands = (commands) => {
4940
+ if (commands.length === 0)
4941
+ return "unknown";
4942
+ return commandStatus(commands) === "failed" ? "failed" : "passed";
4943
+ };
4944
+ var statusForDiagnostics = (diagnostics) => {
4945
+ if (diagnostics.length === 0)
4946
+ return "unknown";
4947
+ return workflowStatus(diagnostics) === "failed" ? "failed" : "passed";
4948
+ };
4949
+ var workflowDiagnosticContextPaths = (diagnostics) => uniqueBy(diagnostics.flatMap((diagnostic) => diagnostic.context?.paths ?? []), (filePath) => filePath);
4950
+ var createWorkflowBaselineSummary = (diagnostics, { detailsIncluded = true, knownBlockerCount = 0 } = {}) => {
4951
+ const grouped = new Map;
4952
+ let totalErrors = 0;
4953
+ let totalWarnings = 0;
4954
+ for (const diagnostic of diagnostics) {
4955
+ if (diagnostic.severity === "error")
4956
+ totalErrors += 1;
4957
+ else
4958
+ totalWarnings += 1;
4959
+ const existing = grouped.get(diagnostic.code);
4960
+ if (existing) {
4961
+ existing.count += 1;
4962
+ if (existing.severity !== diagnostic.severity)
4963
+ existing.severity = "mixed";
4964
+ } else {
4965
+ grouped.set(diagnostic.code, {
4966
+ code: diagnostic.code,
4967
+ severity: diagnostic.severity,
4968
+ count: 1,
4969
+ sampleMessage: diagnostic.message
4970
+ });
4971
+ }
4972
+ }
4973
+ const contextPaths = workflowDiagnosticContextPaths(diagnostics);
4974
+ return {
4975
+ status: totalErrors > 0 ? "failed" : diagnostics.length > 0 ? "passed" : "unknown",
4976
+ total: diagnostics.length,
4977
+ totalErrors,
4978
+ totalWarnings,
4979
+ detailsIncluded,
4980
+ knownBlockerCount,
4981
+ byCode: [...grouped.values()],
4982
+ ...contextPaths.length ? { contextPaths } : {}
4983
+ };
4984
+ };
4928
4985
  var createKnownBlockers = (commands, diagnostics) => {
4929
4986
  const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
4930
4987
  code: `workflow-validation-${command.failureScope}`,
@@ -4953,18 +5010,28 @@ var createKnownBlockers = (commands, diagnostics) => {
4953
5010
  }
4954
5011
  return [...grouped.values()];
4955
5012
  };
4956
- var createValidationStatuses = (commands, diagnostics) => {
5013
+ var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
5014
+ const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
4957
5015
  const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
4958
- const sourceStatus = statusForScope(commands, diagnostics, scopes, "source-change");
5016
+ const sourceDiagnostics = [...reportDiagnostics, ...workflowDiagnostics].filter((diagnostic) => diagnostic.failureScope === "source-change" || diagnostic.scope === "workflow" || !diagnostic.failureScope && diagnostic.scope !== "baseline");
5017
+ const sourceScopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(sourceDiagnostics)];
5018
+ const sourceStatus = statusForScope(commands, sourceDiagnostics, sourceScopes, "source-change");
5019
+ const validationCommandsStatus = statusForCommands(commands);
5020
+ const baselineStatus = statusForDiagnostics(baselineDiagnostics);
5021
+ const nonBaselineDiagnostics = [...reportDiagnostics, ...workflowDiagnostics];
4959
5022
  const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
4960
- 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";
5023
+ 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";
4961
5024
  return {
4962
5025
  sourceStatus,
4963
5026
  workspaceStatus,
5027
+ validationCommandsStatus,
5028
+ baselineStatus,
4964
5029
  overallStatus,
4965
5030
  summary: {
4966
5031
  sourceChange: sourceStatus,
4967
5032
  generatedSync: statusForValidationKind(commands, "sync"),
5033
+ validationCommands: validationCommandsStatus,
5034
+ baseline: baselineStatus,
4968
5035
  workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
4969
5036
  environment: statusForScope(commands, diagnostics, scopes, "environment")
4970
5037
  }
@@ -4998,7 +5065,8 @@ var createWorkflowValidationRunReport = async ({
4998
5065
  ] : []);
4999
5066
  const reportDiagnostics = [...diagnostics, ...commandDiagnostics];
5000
5067
  const scopedDiagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
5001
- const statuses = createValidationStatuses(results, scopedDiagnostics);
5068
+ const knownBlockers = createKnownBlockers(results, scopedDiagnostics);
5069
+ const statuses = createValidationStatuses(results, reportDiagnostics, baselineDiagnostics, workflowDiagnostics);
5002
5070
  return {
5003
5071
  schemaVersion: 1,
5004
5072
  runId,
@@ -5007,9 +5075,12 @@ var createWorkflowValidationRunReport = async ({
5007
5075
  source,
5008
5076
  status: statuses.overallStatus === "passed" ? "passed" : "failed",
5009
5077
  ...statuses,
5010
- knownBlockers: createKnownBlockers(results, scopedDiagnostics),
5078
+ knownBlockers,
5011
5079
  commands: results,
5012
5080
  diagnostics: reportDiagnostics,
5081
+ baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
5082
+ knownBlockerCount: knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config").length
5083
+ }),
5013
5084
  baselineDiagnostics,
5014
5085
  workflowDiagnostics,
5015
5086
  repairActions: uniqueBy(repairActions, (action) => action.command),
@@ -6325,7 +6396,7 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
6325
6396
  return null;
6326
6397
  const content = await workspace.readFile(filePath);
6327
6398
  const source = ts6.createSourceFile(filePath, content, ts6.ScriptTarget.Latest, true, scriptKind);
6328
- const diagnostic = source.parseDiagnostics[0];
6399
+ const diagnostic = (source.parseDiagnostics ?? [])[0];
6329
6400
  if (!diagnostic)
6330
6401
  return null;
6331
6402
  const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
@@ -6523,9 +6594,9 @@ var addFieldUiSurfaceInspection = (plan) => {
6523
6594
  code: "add-field-ui-surface-review",
6524
6595
  kind: "manual-action",
6525
6596
  target,
6526
- 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.`,
6597
+ 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.`,
6527
6598
  confidence: "medium",
6528
- message: `Review UI surfaces for ${module}.${field}; recommended component is ${policy.component}, with manual reasons and candidate positions in action.`
6599
+ message: `Review user-visible UI for ${module}.${field}; recommended component is ${policy.component}.`
6529
6600
  }
6530
6601
  ],
6531
6602
  nextActions: [
@@ -6780,10 +6851,48 @@ var createAddFieldDefaultRecommendations = (inputs) => {
6780
6851
  kind: "manual-action",
6781
6852
  confidence: "high",
6782
6853
  message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
6783
- action: "Review the normalized default in the apply report if this value should stay unset."
6854
+ action: "Review the normalized default in the apply report. To leave the field without a default, omit the default input."
6784
6855
  }
6785
6856
  ];
6786
6857
  };
6858
+ var moneyLikeFieldPattern = /(budget|price|amount|cost|rate|fee|salary|balance)/i;
6859
+ var wholeNumberFieldPattern = /(count|quantity|total|number|index|rank|order|age)/i;
6860
+ var createAddFieldInputRecommendations = (inputs) => {
6861
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
6862
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
6863
+ const recommendations = [];
6864
+ if (!typeName)
6865
+ return recommendations;
6866
+ if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric") {
6867
+ const recommendedType = moneyLikeFieldPattern.test(field) ? "Float" : wholeNumberFieldPattern.test(field) ? "Int" : null;
6868
+ recommendations.push({
6869
+ code: "add-field-type-choice",
6870
+ kind: "input-guidance",
6871
+ confidence: recommendedType ? "high" : "medium",
6872
+ 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.`,
6873
+ action: recommendedType ? `Re-run plan_workflow with type="${recommendedType}".` : 'Re-run plan_workflow with type="Int" or type="Float".'
6874
+ });
6875
+ }
6876
+ if (typeName.toLowerCase() === "enum" && !Array.isArray(inputs.values)) {
6877
+ recommendations.push({
6878
+ code: "add-field-enum-values",
6879
+ kind: "input-guidance",
6880
+ confidence: "high",
6881
+ message: `Enum field ${field} needs values before apply can choose valid dictionary and default behavior.`,
6882
+ action: 'Pass values as an array or comma-separated string, for example values=["draft","done"].'
6883
+ });
6884
+ }
6885
+ if (inputs.default === undefined) {
6886
+ recommendations.push({
6887
+ code: "add-field-default-optional",
6888
+ kind: "input-guidance",
6889
+ confidence: "medium",
6890
+ message: `No default will be written for ${field} because default is omitted.`,
6891
+ action: "Keep default omitted when the field should have no default value."
6892
+ });
6893
+ }
6894
+ return recommendations;
6895
+ };
6787
6896
  var createAddFieldRecommendations = (inputs) => {
6788
6897
  const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
6789
6898
  const module = typeof inputs.module === "string" ? inputs.module : "<module>";
@@ -6844,9 +6953,9 @@ var createAddFieldRecommendations = (inputs) => {
6844
6953
  code: "add-field-light-projection-choice",
6845
6954
  kind: "manual-action",
6846
6955
  target: paths.constant,
6847
- action: `Pass includeInLight=true when ${field} should appear in Light${capitalize2(module)} list/card projections.`,
6956
+ 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.`,
6848
6957
  confidence: "medium",
6849
- message: `Light projection exposure for ${module}.${field} is not selected yet.`
6958
+ message: `${module}.${field} is not selected for list/card projection data.`
6850
6959
  }
6851
6960
  ] : [],
6852
6961
  ...includeInLight ? [
@@ -6864,18 +6973,20 @@ var createAddFieldRecommendations = (inputs) => {
6864
6973
  kind: "manual-action",
6865
6974
  target: paths.template,
6866
6975
  confidence: "medium",
6867
- message: `Template is not included in surfaces, so ${module}.${field} will not be auto-rendered there.`
6976
+ message: `Template form auto-edit is skipped for ${module}.${field} because surfaces does not include "template".`,
6977
+ action: `Pass surfaces=["template"] when users should enter ${field} in the Template form.`
6868
6978
  }
6869
6979
  ] : [],
6870
6980
  {
6871
6981
  code: "add-field-ui-manual-review",
6872
6982
  kind: "manual-action",
6873
6983
  target: paths.template,
6874
- 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${capitalize2(module)} projection array for list data, and Unit/View card sections for display.`,
6984
+ 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.`,
6875
6985
  confidence: "medium",
6876
- message: "UI manual review includes the reason auto-edit may be skipped and candidate insertion positions."
6986
+ message: `${app}:${module}.${field} may need UI review for user-visible Template, Unit, and View behavior.`
6877
6987
  },
6878
- ...createAddFieldDefaultRecommendations(inputs)
6988
+ ...createAddFieldDefaultRecommendations(inputs),
6989
+ ...createAddFieldInputRecommendations(inputs)
6879
6990
  ];
6880
6991
  };
6881
6992
  var createWorkflowPlanPredictedChanges = (spec, inputs) => {
@@ -7018,7 +7129,8 @@ var createWorkflowPlan = (spec, rawInputs) => {
7018
7129
  validation: spec.validation,
7019
7130
  diagnostics,
7020
7131
  recommendations: createWorkflowPlanRecommendations(spec, inputs),
7021
- requiresApproval: true
7132
+ requiresApproval: true,
7133
+ approval: workflowPlanApproval
7022
7134
  };
7023
7135
  };
7024
7136
  // pkgs/@akanjs/devkit/workflow/render.ts
@@ -7056,6 +7168,7 @@ var renderWorkflowPlan = (plan) => [
7056
7168
  "",
7057
7169
  `- Mode: ${plan.mode}`,
7058
7170
  `- Requires approval: ${plan.requiresApproval}`,
7171
+ `- Approval: ${plan.approval?.meaning ?? "Review this read-only plan before applying workflow mutations."}`,
7059
7172
  "",
7060
7173
  "## Inputs",
7061
7174
  ...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
@@ -7092,6 +7205,10 @@ var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.
7092
7205
  var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
7093
7206
  var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
7094
7207
  var renderWorkflowApplyReport = (report) => {
7208
+ const applySummary = {
7209
+ sourceFilesChanged: report.summary?.sourceFilesChanged ?? report.changedFiles,
7210
+ generatedFilesSynced: report.summary?.generatedFilesSynced ?? report.generatedFiles
7211
+ };
7095
7212
  const manualReviewItems = [
7096
7213
  ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
7097
7214
  ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
@@ -7105,6 +7222,8 @@ var renderWorkflowApplyReport = (report) => {
7105
7222
  `- Status: ${report.status}`,
7106
7223
  `- Source-change status: ${applySourceStatus(report)}`,
7107
7224
  `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
7225
+ `- Source files changed: ${applySummary.sourceFilesChanged.length}`,
7226
+ `- Generated files queued for sync: ${applySummary.generatedFilesSynced.length}`,
7108
7227
  ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
7109
7228
  "",
7110
7229
  "## Apply Checks",
@@ -7114,10 +7233,10 @@ var renderWorkflowApplyReport = (report) => {
7114
7233
  ...sourceBlockers.length ? sourceBlockers : ["- none"],
7115
7234
  "",
7116
7235
  "## Automatically Modified",
7117
- ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7236
+ ...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7118
7237
  "",
7119
7238
  "## Generated Sync",
7120
- ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7239
+ ...applySummary.generatedFilesSynced.length ? applySummary.generatedFilesSynced.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
7121
7240
  "",
7122
7241
  "## Applied Commands",
7123
7242
  ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
@@ -7144,52 +7263,76 @@ var renderWorkflowApplyReport = (report) => {
7144
7263
  `);
7145
7264
  };
7146
7265
  var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
7147
- var renderWorkflowValidationRunReport = (report) => [
7148
- `# Workflow Validation: ${report.workflow}`,
7149
- "",
7150
- `- Run: ${report.runId}`,
7151
- `- Status: ${report.status}`,
7152
- `- Source status: ${report.sourceStatus}`,
7153
- `- Workspace status: ${report.workspaceStatus}`,
7154
- `- Overall status: ${report.overallStatus}`,
7155
- "",
7156
- "## Status Summary",
7157
- `- Source-change: ${report.summary.sourceChange}`,
7158
- `- Generated sync: ${report.summary.generatedSync}`,
7159
- `- Workspace config: ${report.summary.workspaceConfig}`,
7160
- `- Environment: ${report.summary.environment}`,
7161
- "",
7162
- "## Source Change Diagnostics",
7163
- ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7164
- "",
7165
- "## Existing Workspace Blockers",
7166
- ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7167
- "",
7168
- "## Known Blockers",
7169
- ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
7170
- const command = blocker.command ? ` \`${blocker.command}\`` : "";
7171
- const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
7172
- const known = blocker.known ? " known" : "";
7173
- return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
7174
- }) : ["- none"],
7175
- "",
7176
- "## Commands",
7177
- ...report.commands.length ? report.commands.map((command) => {
7178
- const scope = command.failureScope ? ` (${command.failureScope})` : "";
7179
- return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
7180
- }) : ["- none"],
7181
- "",
7182
- "## Diagnostics",
7183
- ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7184
- "",
7185
- "## Repair Actions",
7186
- ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7187
- "",
7188
- "## Next Actions",
7189
- ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7190
- ""
7191
- ].join(`
7266
+ var renderWorkflowValidationRunReport = (report) => {
7267
+ const baselineSummary = report.baselineSummary ?? {
7268
+ status: report.baselineDiagnostics?.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "unknown",
7269
+ total: report.baselineDiagnostics?.length ?? 0,
7270
+ totalErrors: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "error").length ?? 0,
7271
+ totalWarnings: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "warning").length ?? 0,
7272
+ detailsIncluded: true,
7273
+ knownBlockerCount: report.knownBlockers.filter((blocker) => blocker.known).length,
7274
+ byCode: []
7275
+ };
7276
+ return [
7277
+ `# Workflow Validation: ${report.workflow}`,
7278
+ "",
7279
+ `- Run: ${report.runId}`,
7280
+ `- Status: ${report.status}`,
7281
+ `- Source status: ${report.sourceStatus}`,
7282
+ `- Workspace status: ${report.workspaceStatus}`,
7283
+ `- Validation commands status: ${report.validationCommandsStatus ?? "unknown"}`,
7284
+ `- Baseline status: ${report.baselineStatus ?? baselineSummary.status}`,
7285
+ `- Overall status: ${report.overallStatus}`,
7286
+ "",
7287
+ "## Status Summary",
7288
+ `- Source-change: ${report.summary.sourceChange}`,
7289
+ `- Generated sync: ${report.summary.generatedSync}`,
7290
+ `- Validation commands: ${report.summary.validationCommands ?? "unknown"}`,
7291
+ `- Baseline: ${report.summary.baseline ?? baselineSummary.status}`,
7292
+ `- Workspace config: ${report.summary.workspaceConfig}`,
7293
+ `- Environment: ${report.summary.environment}`,
7294
+ "",
7295
+ "## Source Change Diagnostics",
7296
+ ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7297
+ "",
7298
+ "## Existing Workspace Blockers",
7299
+ `- Status: ${baselineSummary.status}`,
7300
+ `- Errors: ${baselineSummary.totalErrors}`,
7301
+ `- Warnings: ${baselineSummary.totalWarnings}`,
7302
+ ...baselineSummary.byCode.length ? baselineSummary.byCode.map((item) => `- [${item.severity}] ${item.code} (${item.count}x): ${item.sampleMessage}`) : ["- none"],
7303
+ ...baselineSummary.detailsIncluded ? [] : [
7304
+ "- Baseline details are summarized by default. Re-run validation with includeBaselineDetails=true for full baselineDiagnostics."
7305
+ ],
7306
+ "",
7307
+ "## Existing Workspace Blocker Details",
7308
+ ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : baselineSummary.detailsIncluded ? ["- none"] : ["- omitted"],
7309
+ "",
7310
+ "## Known Blockers",
7311
+ ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
7312
+ const command = blocker.command ? ` \`${blocker.command}\`` : "";
7313
+ const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
7314
+ const known = blocker.known ? " known" : "";
7315
+ return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
7316
+ }) : ["- none"],
7317
+ "",
7318
+ "## Commands",
7319
+ ...report.commands.length ? report.commands.map((command) => {
7320
+ const scope = command.failureScope ? ` (${command.failureScope})` : "";
7321
+ return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
7322
+ }) : ["- none"],
7323
+ "",
7324
+ "## Diagnostics",
7325
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
7326
+ "",
7327
+ "## Repair Actions",
7328
+ ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7329
+ "",
7330
+ "## Next Actions",
7331
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
7332
+ ""
7333
+ ].join(`
7192
7334
  `);
7335
+ };
7193
7336
  var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
7194
7337
  var renderRepairReportMarkdown = (report) => [
7195
7338
  `# Akan Repair: ${report.kind}`,
@@ -7278,7 +7421,11 @@ var toolingRolloutGate = {
7278
7421
  candidates: toolingRolloutCandidates
7279
7422
  };
7280
7423
  var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
7281
- var restrictedCandidates = new Map(toolingRolloutCandidates.filter(isRestrictedCandidate).map((candidate) => [candidate.packageName, candidate]));
7424
+ var restrictedCandidates = new Map;
7425
+ for (const candidate of toolingRolloutCandidates) {
7426
+ if (isRestrictedCandidate(candidate))
7427
+ restrictedCandidates.set(candidate.packageName, candidate);
7428
+ }
7282
7429
  // pkgs/@akanjs/devkit/akanContext.ts
7283
7430
  var resourceList = [
7284
7431
  { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
@@ -7847,6 +7994,7 @@ var applyFirstPolicy = {
7847
7994
  mode: "apply-first",
7848
7995
  directSourceEdits: "fallback-only",
7849
7996
  applyRequiredWhen: ["plan_workflow returns planPath", "plan_workflow returns next.tool=apply_workflow"],
7997
+ approvalMeaning: "requiresApproval is an agent/user review signal before apply_workflow mutates files; it is not a separate MCP permission gate.",
7850
7998
  validationRequiredAfterApply: ["validationTarget", "applyReportPath"],
7851
7999
  fallbackAllowedWhen: [
7852
8000
  "list_workflows and explain_workflow show no matching workflow",
@@ -7982,7 +8130,12 @@ var readonlyMcpTools = [
7982
8130
  description: "Report workspace diagnostics, optionally split into baseline and workflow scopes.",
7983
8131
  inputSchema: {
7984
8132
  type: "object",
7985
- properties: { strict: booleanProperty, runIdOrPlan: stringProperty, changedFiles: stringArrayProperty }
8133
+ properties: {
8134
+ strict: booleanProperty,
8135
+ runIdOrPlan: stringProperty,
8136
+ changedFiles: stringArrayProperty,
8137
+ includeBaselineDetails: booleanProperty
8138
+ }
7986
8139
  }
7987
8140
  },
7988
8141
  {
@@ -8027,7 +8180,7 @@ var applyMcpTools = [
8027
8180
  description: "Validate a plan, apply report, validationTarget, or run artifact.",
8028
8181
  inputSchema: {
8029
8182
  type: "object",
8030
- properties: { runIdOrPlan: stringProperty },
8183
+ properties: { runIdOrPlan: stringProperty, includeBaselineDetails: booleanProperty },
8031
8184
  required: ["runIdOrPlan"]
8032
8185
  }
8033
8186
  },
@@ -8077,7 +8230,16 @@ var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
8077
8230
  validationStatuses: {
8078
8231
  sourceStatus: ["passed", "failed", "unknown"],
8079
8232
  workspaceStatus: ["passed", "failed", "unknown"],
8080
- overallStatus: ["passed", "failed", "blocked-by-workspace-config", "blocked-by-environment"],
8233
+ validationCommandsStatus: ["passed", "failed", "unknown"],
8234
+ baselineStatus: ["passed", "failed", "unknown"],
8235
+ overallStatus: [
8236
+ "passed",
8237
+ "failed",
8238
+ "passed-with-baseline-blockers",
8239
+ "blocked-by-workspace-config",
8240
+ "blocked-by-environment"
8241
+ ],
8242
+ baselineSummary: "Default MCP validation output summarizes baseline diagnostics; pass includeBaselineDetails=true for full baselineDiagnostics.",
8081
8243
  knownBlockers: "Repeated workspace-config/environment failures are summarized before command output."
8082
8244
  },
8083
8245
  moduleContextInputs: {
@@ -8088,6 +8250,7 @@ var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
8088
8250
  toolingRolloutGate,
8089
8251
  directEditFallbackPolicy: applyFirstPolicy,
8090
8252
  applyReportFields: [
8253
+ "summary",
8091
8254
  "appliedCommands",
8092
8255
  "recommendedValidationCommands",
8093
8256
  "commands",
@@ -8129,7 +8292,14 @@ var inspectAkanContext = async (workspace, args) => {
8129
8292
  strict: true,
8130
8293
  runIdOrPlan: workspacePath(workspace, props.request.runIdOrPlan)
8131
8294
  });
8132
- diagnostics.push(...doctor.diagnostics.map((diagnostic) => ({
8295
+ const baselineSummary = createWorkflowBaselineSummary((doctor.baselineDiagnostics ?? []).map((diagnostic) => ({
8296
+ severity: diagnostic.severity,
8297
+ code: diagnostic.code,
8298
+ message: diagnostic.message,
8299
+ scope: diagnostic.scope,
8300
+ context: diagnostic.context
8301
+ })), { detailsIncluded: false });
8302
+ diagnostics.push(...(doctor.workflowDiagnostics ?? doctor.diagnostics).map((diagnostic) => ({
8133
8303
  severity: diagnostic.severity,
8134
8304
  code: diagnostic.code,
8135
8305
  message: diagnostic.message,
@@ -8150,7 +8320,8 @@ var inspectAkanContext = async (workspace, args) => {
8150
8320
  reason: doctor.status === "passed" ? "No strict workspace diagnostics were found for the workflow context." : "Review diagnostics before applying or manually editing source files."
8151
8321
  }, {
8152
8322
  status: doctor.status,
8153
- baselineDiagnostics: doctor.baselineDiagnostics?.length ?? 0,
8323
+ baselineSummary,
8324
+ baselineDiagnostics: 0,
8154
8325
  workflowDiagnostics: doctor.workflowDiagnostics?.length ?? 0
8155
8326
  });
8156
8327
  }
@@ -17316,7 +17487,8 @@ var failedPlan = (workflow2, diagnostics) => ({
17316
17487
  validation: [],
17317
17488
  diagnostics,
17318
17489
  recommendations: [],
17319
- requiresApproval: true
17490
+ requiresApproval: true,
17491
+ approval: workflowPlanApproval
17320
17492
  });
17321
17493
  var failedApplyReport = (workflow2, diagnostics, plan2) => createWorkflowApplyReport({
17322
17494
  workflow: workflow2,
@@ -17428,17 +17600,33 @@ var applyBaselineBlockerCache = async (workspace, report) => {
17428
17600
  });
17429
17601
  }
17430
17602
  await workspace.writeFile(cachePath, jsonText({ schemaVersion: 1, workflow: report.workflow, blockers: [...blockers.values()] }), { silent: true });
17603
+ const knownBlockers = report.knownBlockers.map((blocker) => {
17604
+ if (!knownFingerprints.has(blockerFingerprint(blocker)))
17605
+ return blocker;
17606
+ return {
17607
+ ...blocker,
17608
+ known: true,
17609
+ message: `Known baseline blocker, unrelated to this source change: ${blocker.message}`
17610
+ };
17611
+ });
17431
17612
  return {
17432
17613
  ...report,
17433
- knownBlockers: report.knownBlockers.map((blocker) => {
17434
- if (!knownFingerprints.has(blockerFingerprint(blocker)))
17435
- return blocker;
17436
- return {
17437
- ...blocker,
17438
- known: true,
17439
- message: `Known baseline blocker, unrelated to this source change: ${blocker.message}`
17440
- };
17441
- })
17614
+ knownBlockers,
17615
+ baselineSummary: {
17616
+ ...report.baselineSummary,
17617
+ knownBlockerCount: knownBlockers.filter((blocker) => blocker.known).length
17618
+ }
17619
+ };
17620
+ };
17621
+ var withBaselineDetailsPolicy = (report, includeBaselineDetails) => {
17622
+ const baselineDiagnostics = report.baselineDiagnostics ?? [];
17623
+ return {
17624
+ ...report,
17625
+ baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
17626
+ detailsIncluded: includeBaselineDetails,
17627
+ knownBlockerCount: report.knownBlockers.filter((blocker) => blocker.known).length
17628
+ }),
17629
+ baselineDiagnostics: includeBaselineDetails ? baselineDiagnostics : []
17442
17630
  };
17443
17631
  };
17444
17632
 
@@ -17534,7 +17722,8 @@ class WorkflowRunner extends runner("workflow") {
17534
17722
  async validate(runIdOrPlan, {
17535
17723
  format = "markdown",
17536
17724
  workspace,
17537
- execute
17725
+ execute,
17726
+ includeBaselineDetails = false
17538
17727
  }) {
17539
17728
  const loaded = await this.loadValidationTarget(runIdOrPlan, workspace);
17540
17729
  const doctor = await AkanContextAnalyzer.doctor(workspace, {
@@ -17542,7 +17731,7 @@ class WorkflowRunner extends runner("workflow") {
17542
17731
  runIdOrPlan,
17543
17732
  changedFiles: loaded.changedFiles
17544
17733
  });
17545
- const report = await applyBaselineBlockerCache(workspace, await createWorkflowValidationRunReport({
17734
+ const report = withBaselineDetailsPolicy(await applyBaselineBlockerCache(workspace, await createWorkflowValidationRunReport({
17546
17735
  workflow: loaded.plan?.workflow ?? loaded.workflow,
17547
17736
  source: loaded.source,
17548
17737
  plan: loaded.plan,
@@ -17552,7 +17741,7 @@ class WorkflowRunner extends runner("workflow") {
17552
17741
  baselineDiagnostics: (doctor.baselineDiagnostics ?? []).map((diagnostic) => workflowDiagnosticFromDoctor(diagnostic, "baseline")),
17553
17742
  workflowDiagnostics: (doctor.workflowDiagnostics ?? []).map((diagnostic) => workflowDiagnosticFromDoctor(diagnostic, "workflow")),
17554
17743
  repairActions: loaded.repairActions
17555
- }));
17744
+ })), includeBaselineDetails);
17556
17745
  await writeWorkflowRunArtifact(workspace, report);
17557
17746
  return renderWorkflowValidation(report, format);
17558
17747
  }
@@ -18814,6 +19003,32 @@ var createCliWorkflowStepRegistry = (workspace) => createWorkflowStepRegistry({
18814
19003
  });
18815
19004
 
18816
19005
  // pkgs/@akanjs/cli/context/context.runner.ts
19006
+ var workflowDiagnosticFromContext = (diagnostic) => ({
19007
+ severity: diagnostic.severity,
19008
+ code: diagnostic.code,
19009
+ message: diagnostic.message,
19010
+ scope: diagnostic.scope,
19011
+ context: diagnostic.context
19012
+ });
19013
+ var compactDoctorWorkspaceResult = (result, includeBaselineDetails) => {
19014
+ const baselineDiagnostics = result.baselineDiagnostics ?? [];
19015
+ if (baselineDiagnostics.length === 0) {
19016
+ return {
19017
+ ...result,
19018
+ baselineSummary: createWorkflowBaselineSummary([], { detailsIncluded: includeBaselineDetails })
19019
+ };
19020
+ }
19021
+ const baselineSummary = createWorkflowBaselineSummary(baselineDiagnostics.map(workflowDiagnosticFromContext), {
19022
+ detailsIncluded: includeBaselineDetails
19023
+ });
19024
+ return {
19025
+ ...result,
19026
+ baselineSummary,
19027
+ diagnostics: includeBaselineDetails ? result.diagnostics : result.diagnostics.filter((diagnostic) => diagnostic.scope !== "baseline"),
19028
+ baselineDiagnostics: includeBaselineDetails ? baselineDiagnostics : []
19029
+ };
19030
+ };
19031
+
18817
19032
  class ContextRunner extends runner("context") {
18818
19033
  async getContext(workspace, {
18819
19034
  format = "markdown",
@@ -18903,11 +19118,11 @@ class ContextRunner extends runner("context") {
18903
19118
  if (name === "get_guideline")
18904
19119
  return await Prompter.getInstruction(stringArg(args, "name"));
18905
19120
  if (name === "doctor_workspace")
18906
- return await AkanContextAnalyzer.doctor(workspace, {
19121
+ return compactDoctorWorkspaceResult(await AkanContextAnalyzer.doctor(workspace, {
18907
19122
  strict: !!args.strict,
18908
19123
  runIdOrPlan: typeof args.runIdOrPlan === "string" ? workspacePath(workspace, args.runIdOrPlan) : null,
18909
19124
  changedFiles: Array.isArray(args.changedFiles) ? args.changedFiles.filter((file) => typeof file === "string") : []
18910
- });
19125
+ }), !!args.includeBaselineDetails);
18911
19126
  if (name === "explain_command")
18912
19127
  return this.explainCommand(stringArg(args, "command"));
18913
19128
  if (name === "get_validation_contract")
@@ -18927,6 +19142,7 @@ class ContextRunner extends runner("context") {
18927
19142
  return {
18928
19143
  ...plan2,
18929
19144
  planPath,
19145
+ approval: typeof plan2 === "object" && plan2 && "approval" in plan2 ? { ...plan2.approval, canApplyWith: { planPath } } : undefined,
18930
19146
  next: { tool: "apply_workflow", args: { planPath } },
18931
19147
  policy: applyFirstPolicy
18932
19148
  };
@@ -18949,7 +19165,8 @@ class ContextRunner extends runner("context") {
18949
19165
  if (name === "run_validation")
18950
19166
  return parseJsonOutput(await new WorkflowRunner().validate(workspacePath(workspace, stringArg(args, "runIdOrPlan")), {
18951
19167
  format: "json",
18952
- workspace
19168
+ workspace,
19169
+ includeBaselineDetails: !!args.includeBaselineDetails
18953
19170
  }));
18954
19171
  if (name === "repair_generated") {
18955
19172
  const report = parseJsonOutput(await new RepairRunner().repair("generated", { workspace, app: stringArg(args, "app"), format: "json" }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "2.3.9-rc.8",
3
+ "version": "2.3.9-rc.9",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/openai": "^1.4.6",
35
35
  "@tailwindcss/node": "^4.3.0",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "2.3.9-rc.8",
37
+ "akanjs": "2.3.9-rc.9",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "daisyui": "5.5.23",