@akanjs/devkit 3.0.0-beta.9 → 3.0.0
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/DEV_RUNTIME_KNOBS.md +44 -26
- package/README.ko.md +21 -7
- package/README.md +17 -8
- package/abstractDoc.test.ts +6 -15
- package/abstractDoc.ts +6 -8
- package/agentsIndex.test.ts +4 -7
- package/agentsIndex.ts +6 -22
- package/akanApp/BackendImportGraph.test.ts +8 -22
- package/akanApp/BackendImportGraph.ts +1 -20
- package/akanApp/akanApp.host.test.ts +56 -3
- package/akanApp/akanApp.host.ts +218 -278
- package/akanApp/devBootLatch.test.ts +39 -0
- package/akanApp/devBootLatch.ts +39 -0
- package/akanApp/devHostPolicy.test.ts +81 -35
- package/akanApp/devHostPolicy.ts +41 -102
- package/akanConfig/akanBin.test.ts +62 -0
- package/akanConfig/akanBin.ts +78 -0
- package/akanConfig/akanConfig.test.ts +439 -141
- package/akanConfig/akanConfig.ts +359 -275
- package/akanConfig/index.ts +1 -0
- package/akanConfig/types.ts +22 -8
- package/akanContext.ts +110 -160
- package/akanMcpContract.ts +28 -73
- package/appSelectionMemory.ts +1 -4
- package/applicationBuildReporter.ts +37 -5
- package/applicationBuildRunner.test.ts +41 -5
- package/applicationBuildRunner.ts +71 -63
- package/applicationTestPreload.ts +3 -12
- package/artifact/implicitRootLayout.test.ts +32 -30
- package/artifact/implicitRootLayout.ts +58 -106
- package/artifact/routeSeedIndex.test.ts +7 -6
- package/artifact/routeSeedIndex.ts +11 -44
- package/biome.base.json +35 -2
- package/biomeBase.ts +2 -5
- package/cloud/cloudApi.test.ts +202 -0
- package/cloud/cloudApi.ts +77 -39
- package/cloud/configLock.test.ts +64 -0
- package/cloud/configLock.ts +96 -0
- package/cloud/constants.ts +26 -5
- package/cloud/globalConfig.ts +71 -32
- package/codeAgent/agent/AkanCodeServices.ts +97 -0
- package/codeAgent/agent/AkanContextFiles.ts +94 -0
- package/codeAgent/agent/CodeAgent.ts +551 -0
- package/codeAgent/agent/CodeAgentAsks.ts +66 -0
- package/codeAgent/agent/CodeAgentEventMapper.ts +225 -0
- package/codeAgent/agent/CodeAgentGate.ts +93 -0
- package/codeAgent/agent/CodeAgentProxy.ts +82 -0
- package/codeAgent/agent/CodeAgentRpcHost.ts +103 -0
- package/codeAgent/agent/CodeAgentRpcListener.ts +109 -0
- package/codeAgent/agent/CodeAgentStreamPrinter.ts +86 -0
- package/codeAgent/agent/CodeAgentSuspended.ts +85 -0
- package/codeAgent/agent/CodeAgentUi.ts +47 -0
- package/codeAgent/agent/CodeMailbox.ts +148 -0
- package/codeAgent/agent/CodeSessionFork.ts +56 -0
- package/codeAgent/agent/CodeSessionIndex.ts +78 -0
- package/codeAgent/agent/SubagentPool.ts +214 -0
- package/codeAgent/agent/akanCodeModel.ts +47 -0
- package/codeAgent/agent/akanCodePaths.ts +31 -0
- package/codeAgent/agent/akanContextFiles.test.ts +114 -0
- package/codeAgent/agent/akanSystemPrompt.ts +46 -0
- package/codeAgent/agent/codeAgent.test.ts +178 -0
- package/codeAgent/agent/codeAgentContract.test.ts +523 -0
- package/codeAgent/agent/codeAgentProxy.test.ts +74 -0
- package/codeAgent/agent/codeAgentRpcListener.test.ts +113 -0
- package/codeAgent/agent/codeAgentSuspended.test.ts +47 -0
- package/codeAgent/agent/codeMailbox.test.ts +76 -0
- package/codeAgent/agent/codeSessionFork.test.ts +58 -0
- package/codeAgent/agent/codeSessionIndex.test.ts +77 -0
- package/codeAgent/agent/consoleToStderr.ts +8 -0
- package/codeAgent/agent/jsonLines.ts +29 -0
- package/codeAgent/agent/stringArg.ts +5 -0
- package/codeAgent/feedback/DevLogFeedback.ts +82 -0
- package/codeAgent/feedback/PreviewChrome.ts +82 -0
- package/codeAgent/feedback/PreviewFeedback.ts +46 -0
- package/codeAgent/feedback/PreviewView.ts +95 -0
- package/codeAgent/feedback/TurnFeedback.ts +98 -0
- package/codeAgent/feedback/VerifyFeedback.ts +40 -0
- package/codeAgent/feedback/previewChrome.test.ts +73 -0
- package/codeAgent/index.ts +34 -0
- package/codeAgent/skills/akan-code/SKILL.md +130 -0
- package/codeAgent/skills/akan-debug/SKILL.md +42 -0
- package/codeAgent/skills/akan-deps/SKILL.md +50 -0
- package/codeAgent/skills/akan-err/SKILL.md +39 -0
- package/codeAgent/skills/akan-module/SKILL.md +45 -0
- package/codeAgent/skills/akan-scaffold/SKILL.md +76 -0
- package/codeAgent/skills/akan-scalar/SKILL.md +52 -0
- package/codeAgent/skills/akan-service/SKILL.md +34 -0
- package/codeAgent/skills/akan-store/SKILL.md +67 -0
- package/codeAgent/skills/akan-ui/SKILL.md +63 -0
- package/codeAgent/skills/akan-validate/SKILL.md +44 -0
- package/codeAgent/tools/AkanCli.ts +50 -0
- package/codeAgent/tools/AkanCodePlugins.ts +136 -0
- package/codeAgent/tools/AkanEditScope.ts +48 -0
- package/codeAgent/tools/AkanEnvKeys.ts +50 -0
- package/codeAgent/tools/AkanToolPack.ts +92 -0
- package/codeAgent/tools/AkanVerifier.ts +48 -0
- package/codeAgent/tools/AskToolPack.ts +99 -0
- package/codeAgent/tools/MailToolPack.ts +76 -0
- package/codeAgent/tools/McpClient.ts +187 -0
- package/codeAgent/tools/McpOAuth.ts +233 -0
- package/codeAgent/tools/McpOAuthLoopback.ts +64 -0
- package/codeAgent/tools/McpServerConfig.ts +129 -0
- package/codeAgent/tools/McpSignIn.ts +158 -0
- package/codeAgent/tools/McpTokenStore.ts +81 -0
- package/codeAgent/tools/McpToolPack.ts +199 -0
- package/codeAgent/tools/SessionToolPack.ts +91 -0
- package/codeAgent/tools/WebToolPack.ts +147 -0
- package/codeAgent/tools/akanCodePlugins.test.ts +677 -0
- package/codeAgent/tools/askToolPack.test.ts +116 -0
- package/codeAgent/tools/mcpOAuth.test.ts +612 -0
- package/codeAgent/tools/mcpServerConfig.test.ts +212 -0
- package/codegenLock.test.ts +4 -13
- package/codegenLock.ts +3 -17
- package/commandDecorators/argMeta.ts +1 -5
- package/commandDecorators/camelToKebabCase.ts +1 -0
- package/commandDecorators/command.ts +46 -102
- package/commandDecorators/commandBuilder.ts +30 -61
- package/commandDecorators/commandDecorators.test.ts +2 -10
- package/commandDecorators/dependencyBuilder.ts +10 -1
- package/commandDecorators/helpFormatter.ts +68 -145
- package/commandDecorators/index.ts +0 -2
- package/commandDecorators/targetMeta.ts +9 -7
- package/createTunnel.ts +7 -14
- package/csrE2e/csrE2eHarness.fixture.ts +505 -0
- package/csrE2e/csrFastRefresh.e2e.test.ts +233 -0
- package/csrE2e/csrPageStack.e2e.test.ts +252 -0
- package/csrE2e/csrPatchFirst.e2e.test.ts +87 -0
- package/csrE2e/csrRootLayout.e2e.test.ts +134 -0
- package/csrE2e/devHmrLatency.e2e.test.ts +391 -0
- package/csrE2e/registryVendor.e2e.test.ts +221 -0
- package/csrE2e/ssrRegistry.e2e.test.ts +644 -0
- package/dependencyScanner.test.ts +4 -16
- package/dependencyScanner.ts +31 -80
- package/devkitUtils.test.ts +48 -20
- package/executors.linkFallback.test.ts +103 -0
- package/executors.test.ts +176 -106
- package/executors.ts +212 -498
- package/fileEditor.ts +9 -37
- package/{getDirname.test.ts → fileSys.test.ts} +5 -3
- package/fileSys.ts +22 -9
- package/formSetterScanner.ts +3 -16
- package/frontendBuild/allRoutesBuilder.ts +7 -21
- package/frontendBuild/autoImportSync.test.ts +27 -38
- package/frontendBuild/autoImportSync.ts +31 -65
- package/frontendBuild/buildRouteClient.test.ts +123 -37
- package/frontendBuild/bundleDefine.test.ts +12 -0
- package/frontendBuild/bundleDefine.ts +16 -0
- package/frontendBuild/clientBuildTypes.ts +5 -36
- package/frontendBuild/clientEntriesBundler.ts +9 -40
- package/frontendBuild/clientEntryDiscovery.test.ts +112 -0
- package/frontendBuild/clientEntryDiscovery.ts +122 -110
- package/frontendBuild/csrArtifactBuilder.ts +9 -31
- package/frontendBuild/csrDevArtifactWriter.test.ts +151 -0
- package/frontendBuild/csrDevArtifactWriter.ts +307 -0
- package/frontendBuild/csrDevBundler.test.ts +66 -0
- package/frontendBuild/csrDevBundler.ts +95 -0
- package/frontendBuild/csrDevFactoryCheck.test.ts +33 -0
- package/frontendBuild/csrDevFactoryCheck.ts +39 -0
- package/frontendBuild/csrDevModuleCompiler.test.ts +293 -0
- package/frontendBuild/csrDevModuleCompiler.ts +422 -0
- package/frontendBuild/csrDevPatcher.test.ts +572 -0
- package/frontendBuild/csrDevPatcher.ts +548 -0
- package/frontendBuild/csrDevPaths.ts +145 -0
- package/frontendBuild/csrDevResolver.test.ts +239 -0
- package/frontendBuild/csrDevResolver.ts +363 -0
- package/frontendBuild/csrDevTypes.ts +61 -0
- package/frontendBuild/csrEntryFiles.ts +24 -0
- package/frontendBuild/cssCandidateCache.test.ts +0 -6
- package/frontendBuild/cssCandidateCache.ts +6 -41
- package/frontendBuild/cssCompiler.ts +31 -82
- package/frontendBuild/cssImportResolver.ts +6 -19
- package/frontendBuild/devChangePlanner.ts +7 -10
- package/frontendBuild/devGeneratedIndexSync.test.ts +12 -27
- package/frontendBuild/devGeneratedIndexSync.ts +1 -4
- package/frontendBuild/devRegistryBundler.ts +192 -0
- package/frontendBuild/fontOptimizer.test.ts +6 -14
- package/frontendBuild/fontOptimizer.ts +15 -72
- package/frontendBuild/fontPruner.test.ts +5 -10
- package/frontendBuild/fontPruner.ts +5 -20
- package/frontendBuild/frontendBuild.test.ts +57 -70
- package/frontendBuild/hmrChangeClassifier.ts +2 -2
- package/frontendBuild/hmrWatcher.test.ts +59 -32
- package/frontendBuild/hmrWatcher.ts +31 -74
- package/frontendBuild/index.ts +4 -0
- package/frontendBuild/pagesBundleBuilder.ts +28 -30
- package/frontendBuild/pagesEntrySourceGenerator.ts +56 -6
- package/frontendBuild/precompressArtifacts.ts +5 -18
- package/frontendBuild/registryMetadataFingerprint.test.ts +63 -0
- package/frontendBuild/registryMetadataFingerprint.ts +28 -0
- package/frontendBuild/routeClientBuilder.ts +100 -62
- package/frontendBuild/routesManifestArtifactSerializer.ts +5 -36
- package/frontendBuild/serverGraphFile.test.ts +77 -0
- package/frontendBuild/serverGraphFile.ts +93 -0
- package/frontendBuild/sourceMtimeIndex.test.ts +41 -97
- package/frontendBuild/sourceMtimeIndex.ts +19 -130
- package/frontendBuild/ssrBaseArtifactBuilder.ts +19 -13
- package/frontendBuild/ssrDevBundler.ts +85 -0
- package/frontendBuild/styleContract.ts +1 -8
- package/frontendBuild/themeValidator.ts +4 -26
- package/frontendBuild/watchRootResolver.test.ts +23 -42
- package/frontendBuild/watchRootResolver.ts +5 -27
- package/getRelatedCnsts.ts +12 -92
- package/incrementalBuilder/buildBatch.proc.ts +147 -63
- package/incrementalBuilder/buildBatchProtocol.ts +13 -38
- package/incrementalBuilder/buildBatchRunner.test.ts +65 -0
- package/incrementalBuilder/buildBatchRunner.ts +26 -38
- package/incrementalBuilder/builderChannel.test.ts +24 -49
- package/incrementalBuilder/builderChannel.ts +6 -37
- package/incrementalBuilder/builderRequestRouter.test.ts +0 -8
- package/incrementalBuilder/builderRequestRouter.ts +5 -24
- package/incrementalBuilder/builderWorkQueue.test.ts +94 -0
- package/incrementalBuilder/builderWorkQueue.ts +126 -0
- package/incrementalBuilder/devWatchBatch.test.ts +21 -24
- package/incrementalBuilder/incrementalBuilder.host.test.ts +53 -56
- package/incrementalBuilder/incrementalBuilder.host.ts +68 -81
- package/incrementalBuilder/incrementalBuilder.proc.test.ts +270 -0
- package/incrementalBuilder/incrementalBuilder.proc.ts +596 -208
- package/index.ts +5 -19
- package/integration/devResourceProbe.ts +50 -56
- package/integration/devStability.integration.test.ts +105 -199
- package/integration/devStabilityHarness.test.ts +13 -28
- package/integration/devStabilityHarness.ts +65 -330
- package/integration/ssrMemoryProbe.ts +41 -167
- package/libSource.test.ts +4 -15
- package/libSource.ts +19 -31
- package/lint/__fixtures__/no-document-cookie/bad.tsx +4 -0
- package/lint/__fixtures__/no-document-cookie/good.tsx +7 -0
- package/lint/__fixtures__/no-web-only-api-outside-webkit/bad.tsx +7 -0
- package/lint/__fixtures__/no-web-only-api-outside-webkit/good.tsx +11 -0
- package/lint/__fixtures__/no-web-storage/bad.tsx +6 -0
- package/lint/__fixtures__/no-web-storage/good.tsx +7 -0
- package/lint/gritRules.test.ts +8 -24
- package/lint/no-deep-internal-import.grit +2 -2
- package/lint/no-document-cookie.grit +29 -0
- package/lint/no-redeclare-predefined-endpoint.grit +2 -1
- package/lint/no-web-only-api-outside-webkit.grit +44 -0
- package/lint/no-web-storage.grit +30 -0
- package/linter.test.ts +1 -2
- package/linter.ts +26 -116
- package/mobile/desktopBin.test.ts +182 -0
- package/mobile/desktopBin.ts +144 -0
- package/mobile/desktopServerStage.test.ts +252 -0
- package/mobile/desktopServerStage.ts +178 -0
- package/mobile/index.ts +9 -0
- package/mobile/mobileTarget.test.ts +57 -8
- package/mobile/mobileTarget.ts +45 -26
- package/mobile/nativeApi.test.ts +30 -0
- package/mobile/nativeApi.ts +40 -0
- package/mobile/nativeApp.test.ts +184 -0
- package/mobile/nativeApp.ts +454 -0
- package/mobile/nativeAppLine.test.ts +69 -0
- package/mobile/nativeAppLine.ts +71 -0
- package/mobile/nativeConfig.test.ts +438 -0
- package/mobile/nativeConfig.ts +294 -0
- package/mobile/nativePluginFolders.test.ts +81 -0
- package/mobile/nativePluginFolders.ts +60 -0
- package/mobile/nativeWebDir.test.ts +80 -0
- package/mobile/nativeWebDir.ts +66 -0
- package/mobile/placeholderAppId.test.ts +13 -0
- package/mobile/placeholderAppId.ts +16 -0
- package/mobile/usageDescriptions.test.ts +27 -0
- package/mobile/usageDescriptions.ts +24 -0
- package/package.json +11 -11
- package/packageExports.test.ts +3 -18
- package/packageExportsMap.ts +3 -19
- package/piDependencyPins.test.ts +46 -0
- package/platformTest/BunTestReport.test.ts +60 -0
- package/platformTest/BunTestReport.ts +65 -0
- package/platformTest/IdleWatchedProcess.test.ts +56 -0
- package/platformTest/IdleWatchedProcess.ts +73 -0
- package/platformTest/LinuxDockerTarget.ts +105 -0
- package/platformTest/PlatformTestRun.test.ts +64 -0
- package/platformTest/PlatformTestRun.ts +141 -0
- package/platformTest/PlatformTestTarget.ts +142 -0
- package/platformTest/TestSnapshot.test.ts +72 -0
- package/platformTest/TestSnapshot.ts +103 -0
- package/platformTest/WindowsSshTarget.ts +151 -0
- package/prompter.ts +3 -13
- package/qualityScanner.test.ts +9 -26
- package/qualityScanner.ts +200 -286
- package/recipeScanner.test.ts +7 -12
- package/recipeScanner.ts +9 -38
- package/repoIdentity.ts +2 -9
- package/routeSourceValidator.test.ts +0 -1
- package/routeSourceValidator.ts +7 -42
- package/scanInfo.ts +91 -225
- package/selectModel.ts +1 -2
- package/semver.ts +3 -5
- package/slicePlanner.test.ts +6 -24
- package/slicePlanner.ts +11 -32
- package/spinner.test.ts +3 -8
- package/spinner.ts +4 -16
- package/sshTunnel.ts +1 -6
- package/ssrScanner.test.ts +1 -6
- package/ssrScanner.ts +103 -113
- package/stripAnsi.ts +3 -0
- package/subspace.test.ts +9 -25
- package/subspace.ts +48 -115
- package/subspaceConfig.ts +3 -11
- package/testHelpers.ts +194 -0
- package/transforms/asyncDefaultExportDetector.ts +3 -11
- package/transforms/barrelAnalyzer.ts +43 -135
- package/transforms/barrelImportsPlugin.ts +38 -175
- package/transforms/externalizeFrameworkPlugin.test.ts +39 -118
- package/transforms/externalizeFrameworkPlugin.ts +13 -87
- package/transforms/moduleSyntax.ts +32 -0
- package/transforms/rscUseClientTransform.ts +42 -20
- package/transforms/serverEnvPlugin.test.ts +103 -0
- package/transforms/serverEnvPlugin.ts +41 -0
- package/transforms/transforms.test.ts +166 -44
- package/transforms/tsconfigPackageResolver.test.ts +6 -24
- package/transforms/useClientBundlePlugin.ts +6 -23
- package/typeChecker.ts +7 -63
- package/types.ts +2 -0
- package/uploadRelease.ts +10 -25
- package/workflow/artifacts.ts +18 -0
- package/workflow/executor.test.ts +1 -12
- package/workflow/executor.ts +101 -110
- package/workflow/index.ts +0 -1
- package/workflow/moduleIndex.test.ts +4 -15
- package/workflow/moduleIndex.ts +9 -49
- package/workflow/plan.ts +18 -25
- package/workflow/render.ts +80 -96
- package/workflow/rolloutGate.test.ts +1 -1
- package/workflow/source.ts +52 -69
- package/workflow/sourceAst.ts +50 -0
- package/workspaceLayout.test.ts +18 -3
- package/workspaceLayout.ts +22 -23
- package/abstractCompactor.ts +0 -112
- package/aiEditor.test.ts +0 -60
- package/aiEditor.ts +0 -387
- package/applicationReleasePackager.ts +0 -209
- package/capacitorApp.test.ts +0 -372
- package/capacitorApp.ts +0 -1648
- package/commandDecorators/commandMeta.ts +0 -7
- package/commandDecorators/types.ts +0 -10
- package/getDirname.ts +0 -4
- package/guideline.ts +0 -19
- package/local/optimize-resource/ipcprobe/child.ts +0 -1
- package/local/optimize-resource/ipcprobe/parent.ts +0 -11
- package/workflow/primitive.ts +0 -59
package/workflow/executor.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { capitalize } from "akanjs/common";
|
|
1
2
|
import ts from "typescript";
|
|
2
3
|
import type { AkanModuleContext } from "../akanContext";
|
|
3
4
|
import type { Sys, Workspace } from "../commandDecorators";
|
|
@@ -47,16 +48,13 @@ const workflowStringListInput = (value: WorkflowInputValue | undefined) =>
|
|
|
47
48
|
const workflowStringArrayInput = (value: WorkflowInputValue | undefined) => (Array.isArray(value) ? value : null);
|
|
48
49
|
const workflowBooleanInput = (value: WorkflowInputValue | undefined) => (typeof value === "boolean" ? value : null);
|
|
49
50
|
|
|
50
|
-
const postApplyDiagnostic = (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const postApplyWarning = (code: string, message: string, target: string): WorkflowDiagnostic => ({
|
|
59
|
-
severity: "warning",
|
|
51
|
+
const postApplyDiagnostic = (
|
|
52
|
+
code: string,
|
|
53
|
+
message: string,
|
|
54
|
+
target: string,
|
|
55
|
+
severity: WorkflowDiagnostic["severity"] = "error",
|
|
56
|
+
): WorkflowDiagnostic => ({
|
|
57
|
+
severity,
|
|
60
58
|
code,
|
|
61
59
|
message,
|
|
62
60
|
failureScope: "source-change",
|
|
@@ -113,27 +111,23 @@ const checkTypeScriptSyntax = async (workspace: Workspace, filePath: string) =>
|
|
|
113
111
|
|
|
114
112
|
const checkChangedFile = async (workspace: Workspace, file: PrimitiveChangedFile): Promise<WorkflowStepResult> => {
|
|
115
113
|
if (file.action === "remove") return { postApplyChecks: [] };
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return { diagnostics, postApplyChecks: checks };
|
|
114
|
+
const issue = (await checkPathCasing(workspace, file.path)) ?? (await checkTypeScriptSyntax(workspace, file.path));
|
|
115
|
+
if (issue) {
|
|
116
|
+
return {
|
|
117
|
+
diagnostics: [postApplyDiagnostic(issue.code, issue.message, file.path)],
|
|
118
|
+
postApplyChecks: [{ ...issue, target: file.path, status: "failed" }],
|
|
119
|
+
};
|
|
123
120
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
message: "Changed file exists with exact casing and parses as source when applicable.",
|
|
135
|
-
});
|
|
136
|
-
return { postApplyChecks: checks };
|
|
121
|
+
return {
|
|
122
|
+
postApplyChecks: [
|
|
123
|
+
{
|
|
124
|
+
code: "workflow-post-apply-file-valid",
|
|
125
|
+
target: file.path,
|
|
126
|
+
status: "passed",
|
|
127
|
+
message: "Changed file exists with exact casing and parses as source when applicable.",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
137
131
|
};
|
|
138
132
|
|
|
139
133
|
const checkRecommendationPath = async (
|
|
@@ -198,18 +192,6 @@ const workflowModuleContext = async (workspace: Workspace, plan: WorkflowPlan):
|
|
|
198
192
|
};
|
|
199
193
|
};
|
|
200
194
|
|
|
201
|
-
const structureCheck = (
|
|
202
|
-
code: string,
|
|
203
|
-
target: string,
|
|
204
|
-
status: WorkflowPostApplyCheck["status"],
|
|
205
|
-
message: string,
|
|
206
|
-
): WorkflowPostApplyCheck => ({
|
|
207
|
-
code,
|
|
208
|
-
target,
|
|
209
|
-
status,
|
|
210
|
-
message,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
195
|
const checkAddFieldStructure = async (workspace: Workspace, plan: WorkflowPlan): Promise<WorkflowStepResult> => {
|
|
214
196
|
if (plan.workflow !== "add-field" && plan.workflow !== "add-enum-field") return {};
|
|
215
197
|
const app = workflowStringInput(plan.inputs.app);
|
|
@@ -259,16 +241,14 @@ const checkAddFieldStructure = async (workspace: Workspace, plan: WorkflowPlan):
|
|
|
259
241
|
.map((diagnostic) => diagnostic.message),
|
|
260
242
|
].filter((failure): failure is string => failure !== null);
|
|
261
243
|
const constantValid = constantFailures.length === 0;
|
|
262
|
-
postApplyChecks.push(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
),
|
|
271
|
-
);
|
|
244
|
+
postApplyChecks.push({
|
|
245
|
+
code: constantValid ? "workflow-post-apply-constant-shape-valid" : "workflow-post-apply-structure-invalid",
|
|
246
|
+
target: constantPath,
|
|
247
|
+
status: constantValid ? "passed" : "failed",
|
|
248
|
+
message: constantValid
|
|
249
|
+
? `${inputClassName} keeps via structure, builder usage, imports, and requested field presence.`
|
|
250
|
+
: constantFailures.join(" "),
|
|
251
|
+
});
|
|
272
252
|
if (!constantValid) {
|
|
273
253
|
diagnostics.push(
|
|
274
254
|
postApplyDiagnostic("workflow-post-apply-structure-invalid", constantFailures.join(" "), constantPath),
|
|
@@ -293,16 +273,14 @@ const checkAddFieldStructure = async (workspace: Workspace, plan: WorkflowPlan):
|
|
|
293
273
|
.map((diagnostic) => diagnostic.message),
|
|
294
274
|
].filter((failure): failure is string => failure !== null);
|
|
295
275
|
const dictionaryValid = dictionaryFailures.length === 0;
|
|
296
|
-
postApplyChecks.push(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
),
|
|
305
|
-
);
|
|
276
|
+
postApplyChecks.push({
|
|
277
|
+
code: dictionaryValid ? "workflow-post-apply-dictionary-shape-valid" : "workflow-post-apply-structure-invalid",
|
|
278
|
+
target: dictionaryPath,
|
|
279
|
+
status: dictionaryValid ? "passed" : "failed",
|
|
280
|
+
message: dictionaryValid
|
|
281
|
+
? `.model<${moduleClassName}> keeps the requested field inside the model object and preserves dictionary chain order.`
|
|
282
|
+
: dictionaryFailures.join(" "),
|
|
283
|
+
});
|
|
306
284
|
if (!dictionaryValid) {
|
|
307
285
|
diagnostics.push(
|
|
308
286
|
postApplyDiagnostic("workflow-post-apply-structure-invalid", dictionaryFailures.join(" "), dictionaryPath),
|
|
@@ -312,22 +290,21 @@ const checkAddFieldStructure = async (workspace: Workspace, plan: WorkflowPlan):
|
|
|
312
290
|
const constantOrderValid = fieldOrderValid(constantNames, fieldName);
|
|
313
291
|
const dictionaryOrderValid = fieldOrderValid(dictionaryStructure.fields, fieldName);
|
|
314
292
|
const orderValid = constantOrderValid && dictionaryOrderValid;
|
|
315
|
-
postApplyChecks.push(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
),
|
|
324
|
-
);
|
|
293
|
+
postApplyChecks.push({
|
|
294
|
+
code: "workflow-post-apply-field-order-valid",
|
|
295
|
+
target: `${constantPath}, ${dictionaryPath}`,
|
|
296
|
+
status: orderValid ? "passed" : "failed",
|
|
297
|
+
message: orderValid
|
|
298
|
+
? `Field "${fieldName}" follows the shared priority ordering policy.`
|
|
299
|
+
: `Field "${fieldName}" is present but does not match the shared priority ordering policy.`,
|
|
300
|
+
});
|
|
325
301
|
if (!orderValid) {
|
|
326
302
|
diagnostics.push(
|
|
327
|
-
|
|
303
|
+
postApplyDiagnostic(
|
|
328
304
|
"workflow-post-apply-field-order-mismatch",
|
|
329
305
|
`Field "${fieldName}" is present but does not match the shared priority ordering policy.`,
|
|
330
306
|
`${constantPath}, ${dictionaryPath}`,
|
|
307
|
+
"warning",
|
|
331
308
|
),
|
|
332
309
|
);
|
|
333
310
|
}
|
|
@@ -364,6 +341,14 @@ const unsupportedInput = (input: string, message: string): WorkflowDiagnostic =>
|
|
|
364
341
|
message,
|
|
365
342
|
});
|
|
366
343
|
|
|
344
|
+
const surfaceReview = (
|
|
345
|
+
plan: WorkflowPlan,
|
|
346
|
+
{ code, target, action, message, reason }: Record<"code" | "target" | "action" | "message" | "reason", string>,
|
|
347
|
+
): WorkflowStepResult => ({
|
|
348
|
+
recommendations: [{ code, kind: "manual-action", target, action, confidence: "medium", message }],
|
|
349
|
+
nextActions: [{ command: `akan workflow explain ${plan.workflow}`, reason }],
|
|
350
|
+
});
|
|
351
|
+
|
|
367
352
|
const addFieldUiSurfaceInspection = (plan: WorkflowPlan): WorkflowStepResult => {
|
|
368
353
|
const app = workflowStringInput(plan.inputs.app);
|
|
369
354
|
const module = workflowStringInput(plan.inputs.module) ?? "<module>";
|
|
@@ -373,27 +358,41 @@ const addFieldUiSurfaceInspection = (plan: WorkflowPlan): WorkflowStepResult =>
|
|
|
373
358
|
const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
|
|
374
359
|
const templateRequested = surfaces?.includes("template") ?? false;
|
|
375
360
|
const moduleClassName = moduleComponentName(module);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
361
|
+
return surfaceReview(plan, {
|
|
362
|
+
code: "add-field-ui-surface-review",
|
|
363
|
+
target: `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`,
|
|
364
|
+
action: templateRequested
|
|
365
|
+
? `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.`
|
|
366
|
+
: `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.`,
|
|
367
|
+
message: `Review user-visible UI for ${module}.${field}; recommended component is ${policy.component}.`,
|
|
368
|
+
reason: "Review UI surface guidance before manually editing ambiguous UI files.",
|
|
369
|
+
});
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const addMutationActionSurfaceInspection = (plan: WorkflowPlan): WorkflowStepResult => {
|
|
373
|
+
const module = workflowStringInput(plan.inputs.module) ?? "<module>";
|
|
374
|
+
const mutation = workflowStringInput(plan.inputs.mutation) ?? "<mutation>";
|
|
375
|
+
const moduleClassName = moduleComponentName(module);
|
|
376
|
+
return surfaceReview(plan, {
|
|
377
|
+
code: "add-mutation-action-surface-review",
|
|
378
|
+
target: `*/${moduleSourcePaths(module).store}`,
|
|
379
|
+
action: `Name the endpoint's guards and add its dictionary .endpoint() entry with a .desc(). After sync, fetch.${mutation} exists; write a store action only for a toast, an optimistic update, or a multi-field write, and put the control that calls it in ${moduleClassName}.Util.tsx.`,
|
|
380
|
+
message: `Workflow apply does not write store or UI code for ${module}.${mutation}; review whether a screen should call it.`,
|
|
381
|
+
reason: "Review action surface guidance before manually editing store or UI files.",
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const addSliceViewSurfaceInspection = (plan: WorkflowPlan): WorkflowStepResult => {
|
|
386
|
+
const module = workflowStringInput(plan.inputs.module) ?? "<module>";
|
|
387
|
+
const slice = workflowStringInput(plan.inputs.slice) ?? "<slice>";
|
|
388
|
+
const moduleClassName = moduleComponentName(module);
|
|
389
|
+
return surfaceReview(plan, {
|
|
390
|
+
code: "add-slice-view-surface-review",
|
|
391
|
+
target: `*/${moduleSourcePaths(module).zone}`,
|
|
392
|
+
action: `Fill in the service query stub and add the dictionary .slice() entry. After sync, load fetch.init${moduleClassName}${capitalize(slice)}() in the page and pass the result to a ${moduleClassName}.Zone as an init prop.`,
|
|
393
|
+
message: `Workflow apply does not write page or Zone code for ${module}.${slice}; review where the list should render.`,
|
|
394
|
+
reason: "Review view surface guidance before manually editing Zone or page files.",
|
|
395
|
+
});
|
|
397
396
|
};
|
|
398
397
|
|
|
399
398
|
export const createWorkflowStepRegistry = ({
|
|
@@ -494,6 +493,8 @@ export const createWorkflowStepRegistry = ({
|
|
|
494
493
|
}),
|
|
495
494
|
),
|
|
496
495
|
[workflowStepKey("add-mutation", "update-signal")]: inspect,
|
|
496
|
+
[workflowStepKey("add-mutation", "update-action-surfaces")]: async (_step, plan) =>
|
|
497
|
+
addMutationActionSurfaceInspection(plan),
|
|
497
498
|
[workflowStepKey("add-slice", "update-service-query")]: async (_step, plan) =>
|
|
498
499
|
primitiveReportToWorkflowStepResult(
|
|
499
500
|
await addSlice({
|
|
@@ -503,6 +504,7 @@ export const createWorkflowStepRegistry = ({
|
|
|
503
504
|
}),
|
|
504
505
|
),
|
|
505
506
|
[workflowStepKey("add-slice", "update-signal-slice")]: inspect,
|
|
507
|
+
[workflowStepKey("add-slice", "connect-view-surfaces")]: async (_step, plan) => addSliceViewSurfaceInspection(plan),
|
|
506
508
|
};
|
|
507
509
|
};
|
|
508
510
|
|
|
@@ -529,9 +531,8 @@ export class WorkflowExecutor {
|
|
|
529
531
|
const postApplyChecks: WorkflowPostApplyCheck[] = [];
|
|
530
532
|
const recommendations = [...plan.recommendations];
|
|
531
533
|
const nextActions: PrimitiveNextAction[] = [];
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
return createWorkflowApplyReport({
|
|
534
|
+
const report = () =>
|
|
535
|
+
createWorkflowApplyReport({
|
|
535
536
|
workflow: plan.workflow,
|
|
536
537
|
mode: "apply",
|
|
537
538
|
changedFiles,
|
|
@@ -543,7 +544,8 @@ export class WorkflowExecutor {
|
|
|
543
544
|
nextActions,
|
|
544
545
|
plan,
|
|
545
546
|
});
|
|
546
|
-
|
|
547
|
+
|
|
548
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) return report();
|
|
547
549
|
|
|
548
550
|
recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
|
|
549
551
|
nextActions.push(...workflowCommandsForPlan(plan));
|
|
@@ -594,17 +596,6 @@ export class WorkflowExecutor {
|
|
|
594
596
|
);
|
|
595
597
|
}
|
|
596
598
|
|
|
597
|
-
return
|
|
598
|
-
workflow: plan.workflow,
|
|
599
|
-
mode: "apply",
|
|
600
|
-
changedFiles,
|
|
601
|
-
generatedFiles,
|
|
602
|
-
recommendedValidationCommands,
|
|
603
|
-
diagnostics,
|
|
604
|
-
postApplyChecks,
|
|
605
|
-
recommendations,
|
|
606
|
-
nextActions,
|
|
607
|
-
plan,
|
|
608
|
-
});
|
|
599
|
+
return report();
|
|
609
600
|
}
|
|
610
601
|
}
|
package/workflow/index.ts
CHANGED
|
@@ -1,31 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
4
2
|
import path from "node:path";
|
|
5
3
|
import type { AkanModuleContext } from "../akanContext";
|
|
6
4
|
import type { Workspace } from "../commandDecorators";
|
|
5
|
+
import { tempDirs, writeText } from "../testHelpers";
|
|
7
6
|
import { buildAkanModuleContextIndex } from "./moduleIndex";
|
|
8
7
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
13
|
-
});
|
|
8
|
+
const tempRoot = tempDirs("akan-module-index-");
|
|
14
9
|
|
|
15
10
|
const makeWorkspace = async () => {
|
|
16
|
-
const root = await
|
|
17
|
-
tempRoots.push(root);
|
|
11
|
+
const root = await tempRoot();
|
|
18
12
|
return {
|
|
19
13
|
root,
|
|
20
14
|
workspace: { workspaceRoot: root } as Workspace,
|
|
21
15
|
};
|
|
22
16
|
};
|
|
23
17
|
|
|
24
|
-
const writeText = async (filePath: string, content: string) => {
|
|
25
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
26
|
-
await writeFile(filePath, content);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
18
|
const moduleContext = (files: string[], name = "post"): AkanModuleContext => ({
|
|
30
19
|
kind: "domain",
|
|
31
20
|
name,
|
package/workflow/moduleIndex.ts
CHANGED
|
@@ -4,6 +4,15 @@ import ts from "typescript";
|
|
|
4
4
|
import type { AkanModuleContext } from "../akanContext";
|
|
5
5
|
import type { Workspace } from "../commandDecorators";
|
|
6
6
|
import { moduleComponentName, moduleSourcePaths } from "./source";
|
|
7
|
+
import {
|
|
8
|
+
callExpressionName,
|
|
9
|
+
expressionName,
|
|
10
|
+
firstObjectReturnedByArrow,
|
|
11
|
+
heritageCall,
|
|
12
|
+
nodeName,
|
|
13
|
+
propertyName,
|
|
14
|
+
sourceFileFor,
|
|
15
|
+
} from "./sourceAst";
|
|
7
16
|
import type {
|
|
8
17
|
AkanConstantIndex,
|
|
9
18
|
AkanDictionaryIndex,
|
|
@@ -52,9 +61,6 @@ const fileExists = async (filePath: string) => {
|
|
|
52
61
|
}
|
|
53
62
|
};
|
|
54
63
|
|
|
55
|
-
const sourceFileFor = (filePath: string, content: string) =>
|
|
56
|
-
ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
57
|
-
|
|
58
64
|
const parseDiagnosticsFor = (source: ts.SourceFile, filePath: string): WorkflowDiagnostic[] => {
|
|
59
65
|
const parseDiagnostics =
|
|
60
66
|
(source as ts.SourceFile & { parseDiagnostics?: readonly ts.DiagnosticWithLocation[] }).parseDiagnostics ?? [];
|
|
@@ -83,25 +89,6 @@ const spanFor = (source: ts.SourceFile, file: string, node: ts.Node): AkanSource
|
|
|
83
89
|
};
|
|
84
90
|
};
|
|
85
91
|
|
|
86
|
-
const nodeName = (node: ts.PropertyName | ts.BindingName | undefined) => {
|
|
87
|
-
if (!node) return null;
|
|
88
|
-
if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) return node.text;
|
|
89
|
-
return null;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const propertyName = (node: ts.ObjectLiteralElementLike) =>
|
|
93
|
-
ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node) || ts.isMethodDeclaration(node)
|
|
94
|
-
? nodeName(node.name)
|
|
95
|
-
: null;
|
|
96
|
-
|
|
97
|
-
const expressionName = (expression: ts.Expression): string | null => {
|
|
98
|
-
if (ts.isIdentifier(expression)) return expression.text;
|
|
99
|
-
if (ts.isPropertyAccessExpression(expression)) return expression.name.text;
|
|
100
|
-
if (ts.isCallExpression(expression)) return expressionName(expression.expression);
|
|
101
|
-
if (ts.isAsExpression(expression)) return expressionName(expression.expression);
|
|
102
|
-
return null;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
92
|
const expressionSummary = (expression: ts.Expression): string => {
|
|
106
93
|
if (ts.isAsExpression(expression)) return expressionSummary(expression.expression);
|
|
107
94
|
if (ts.isIdentifier(expression) || ts.isPropertyAccessExpression(expression))
|
|
@@ -151,30 +138,6 @@ const fieldsFromObject = (
|
|
|
151
138
|
})
|
|
152
139
|
.filter((field): field is AkanFieldOutline => field !== null);
|
|
153
140
|
|
|
154
|
-
const firstObjectReturnedByArrow = (node: ts.Node): ts.ObjectLiteralExpression | null => {
|
|
155
|
-
if (!ts.isArrowFunction(node) && !ts.isFunctionExpression(node)) return null;
|
|
156
|
-
if (ts.isObjectLiteralExpression(node.body)) return node.body;
|
|
157
|
-
if (ts.isParenthesizedExpression(node.body) && ts.isObjectLiteralExpression(node.body.expression)) {
|
|
158
|
-
return node.body.expression;
|
|
159
|
-
}
|
|
160
|
-
if (!ts.isBlock(node.body)) return null;
|
|
161
|
-
for (const statement of node.body.statements) {
|
|
162
|
-
if (ts.isReturnStatement(statement) && statement.expression && ts.isObjectLiteralExpression(statement.expression)) {
|
|
163
|
-
return statement.expression;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return null;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const isViaCall = (expression: ts.Expression) =>
|
|
170
|
-
ts.isCallExpression(expression) && expressionName(expression.expression) === "via";
|
|
171
|
-
|
|
172
|
-
const heritageCall = (node: ts.ClassDeclaration) => {
|
|
173
|
-
const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
|
|
174
|
-
const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
|
|
175
|
-
return expression && ts.isCallExpression(expression) ? expression : null;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
141
|
interface ParsedConstantIndex {
|
|
179
142
|
index: AkanConstantIndex;
|
|
180
143
|
diagnostics: WorkflowDiagnostic[];
|
|
@@ -297,9 +260,6 @@ const parseConstantIndex = (filePath: string, content: string, moduleClassName:
|
|
|
297
260
|
};
|
|
298
261
|
};
|
|
299
262
|
|
|
300
|
-
const callExpressionName = (node: ts.CallExpression) =>
|
|
301
|
-
ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
|
|
302
|
-
|
|
303
263
|
const parseDictionaryIndex = (filePath: string, content: string, moduleClassName: string): ParsedDictionaryIndex => {
|
|
304
264
|
const source = sourceFileFor(filePath, content);
|
|
305
265
|
const diagnostics = parseDiagnosticsFor(source, filePath);
|
package/workflow/plan.ts
CHANGED
|
@@ -206,31 +206,24 @@ const createAddFieldRecommendations = (inputs: Record<string, WorkflowInputValue
|
|
|
206
206
|
},
|
|
207
207
|
]
|
|
208
208
|
: []),
|
|
209
|
-
|
|
210
|
-
?
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
{
|
|
226
|
-
|
|
227
|
-
kind: "placement" as const,
|
|
228
|
-
target: paths.constant,
|
|
229
|
-
confidence: "high" as const,
|
|
230
|
-
message: `Add ${field} to Light${capitalize(module)} projection fields.`,
|
|
231
|
-
},
|
|
232
|
-
]
|
|
233
|
-
: []),
|
|
209
|
+
includeInLight
|
|
210
|
+
? {
|
|
211
|
+
code: "add-field-light-projection",
|
|
212
|
+
kind: "placement",
|
|
213
|
+
target: paths.constant,
|
|
214
|
+
confidence: "high",
|
|
215
|
+
message: `Add ${field} to Light${capitalize(module)} projection fields.`,
|
|
216
|
+
}
|
|
217
|
+
: {
|
|
218
|
+
code: "add-field-light-projection-choice",
|
|
219
|
+
kind: "manual-action",
|
|
220
|
+
target: paths.constant,
|
|
221
|
+
action: `Pass includeInLight=true when users should see ${field} in list/card data. Without it, the field can exist on ${capitalize(
|
|
222
|
+
module,
|
|
223
|
+
)}Input but stay absent from Light${capitalize(module)} projections.`,
|
|
224
|
+
confidence: "medium",
|
|
225
|
+
message: `${module}.${field} is not selected for list/card projection data.`,
|
|
226
|
+
},
|
|
234
227
|
...(surfaces && !templateRequested
|
|
235
228
|
? [
|
|
236
229
|
{
|