@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.
- package/incrementalBuilder.proc.js +242 -71
- package/index.js +304 -87
- package/package.json +2 -2
|
@@ -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
|
-
|
|
4852
|
-
|
|
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,
|
|
5015
|
+
var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
|
|
5016
|
+
const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
|
|
4959
5017
|
const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
|
|
4960
|
-
const
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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}
|
|
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:
|
|
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
|
|
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: `
|
|
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:
|
|
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
|
-
...
|
|
7238
|
+
...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
7120
7239
|
"",
|
|
7121
7240
|
"## Generated Sync",
|
|
7122
|
-
...
|
|
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
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
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
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4850
|
-
|
|
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,
|
|
5013
|
+
var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
|
|
5014
|
+
const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
|
|
4957
5015
|
const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
|
|
4958
|
-
const
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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}
|
|
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:
|
|
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
|
|
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: `
|
|
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:
|
|
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
|
-
...
|
|
7236
|
+
...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
7118
7237
|
"",
|
|
7119
7238
|
"## Generated Sync",
|
|
7120
|
-
...
|
|
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
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
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
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
|
|
17437
|
-
|
|
17438
|
-
|
|
17439
|
-
|
|
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.
|
|
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.
|
|
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",
|