berg-pages 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/LICENSE +183 -0
  3. package/README.md +93 -0
  4. package/dist/adapters/local-deploy-execution-ports.d.ts +12 -0
  5. package/dist/adapters/local-deploy-execution-ports.js +81 -0
  6. package/dist/adapters/local-environment-probe.d.ts +5 -0
  7. package/dist/adapters/local-environment-probe.js +54 -0
  8. package/dist/adapters/local-init-apply-ports.d.ts +10 -0
  9. package/dist/adapters/local-init-apply-ports.js +47 -0
  10. package/dist/adapters/local-project-inspector.d.ts +4 -0
  11. package/dist/adapters/local-project-inspector.js +184 -0
  12. package/dist/application/contracts/plugins/deploy-mode-plugin.d.ts +20 -0
  13. package/dist/application/contracts/plugins/deploy-mode-plugin.js +1 -0
  14. package/dist/application/contracts/plugins/framework-plugin.d.ts +19 -0
  15. package/dist/application/contracts/plugins/framework-plugin.js +1 -0
  16. package/dist/application/contracts/ports/environment-probe-port.d.ts +4 -0
  17. package/dist/application/contracts/ports/environment-probe-port.js +1 -0
  18. package/dist/application/contracts/ports/project-inspector-port.d.ts +28 -0
  19. package/dist/application/contracts/ports/project-inspector-port.js +1 -0
  20. package/dist/application/contracts/project-context.d.ts +6 -0
  21. package/dist/application/contracts/project-context.js +1 -0
  22. package/dist/application/index.d.ts +11 -0
  23. package/dist/application/index.js +11 -0
  24. package/dist/application/usecases/apply-deploy-plan.d.ts +8 -0
  25. package/dist/application/usecases/apply-deploy-plan.js +100 -0
  26. package/dist/application/usecases/apply-init-plan.d.ts +13 -0
  27. package/dist/application/usecases/apply-init-plan.js +65 -0
  28. package/dist/application/usecases/build-deploy-plan.d.ts +9 -0
  29. package/dist/application/usecases/build-deploy-plan.js +177 -0
  30. package/dist/application/usecases/build-doctor-plan.d.ts +9 -0
  31. package/dist/application/usecases/build-doctor-plan.js +235 -0
  32. package/dist/application/usecases/build-init-plan.d.ts +9 -0
  33. package/dist/application/usecases/build-init-plan.js +140 -0
  34. package/dist/application/usecases/create-project-context.d.ts +8 -0
  35. package/dist/application/usecases/create-project-context.js +168 -0
  36. package/dist/application/usecases/workflow-diagnostics.d.ts +13 -0
  37. package/dist/application/usecases/workflow-diagnostics.js +137 -0
  38. package/dist/core/diagnostics/diagnostic.d.ts +11 -0
  39. package/dist/core/diagnostics/diagnostic.js +1 -0
  40. package/dist/core/entities/command.d.ts +1 -0
  41. package/dist/core/entities/command.js +1 -0
  42. package/dist/core/entities/deploy-mode.d.ts +6 -0
  43. package/dist/core/entities/deploy-mode.js +1 -0
  44. package/dist/core/entities/environment.d.ts +16 -0
  45. package/dist/core/entities/environment.js +1 -0
  46. package/dist/core/entities/framework.d.ts +8 -0
  47. package/dist/core/entities/framework.js +1 -0
  48. package/dist/core/entities/pages-target.d.ts +22 -0
  49. package/dist/core/entities/pages-target.js +1 -0
  50. package/dist/core/entities/project.d.ts +45 -0
  51. package/dist/core/entities/project.js +1 -0
  52. package/dist/core/index.d.ts +13 -0
  53. package/dist/core/index.js +13 -0
  54. package/dist/core/plans/assumption.d.ts +7 -0
  55. package/dist/core/plans/assumption.js +1 -0
  56. package/dist/core/plans/build-plan.d.ts +12 -0
  57. package/dist/core/plans/build-plan.js +1 -0
  58. package/dist/core/plans/command-plan.d.ts +27 -0
  59. package/dist/core/plans/command-plan.js +45 -0
  60. package/dist/core/plans/deploy-plan.d.ts +17 -0
  61. package/dist/core/plans/deploy-plan.js +1 -0
  62. package/dist/core/plans/plan-step.d.ts +59 -0
  63. package/dist/core/plans/plan-step.js +1 -0
  64. package/dist/core/plans/template-plan.d.ts +11 -0
  65. package/dist/core/plans/template-plan.js +1 -0
  66. package/dist/features/deployment-modes/git-pages-deploy-mode-plugin.d.ts +12 -0
  67. package/dist/features/deployment-modes/git-pages-deploy-mode-plugin.js +49 -0
  68. package/dist/features/frameworks/astro-framework-plugin.d.ts +36 -0
  69. package/dist/features/frameworks/astro-framework-plugin.js +97 -0
  70. package/dist/features/frameworks/static-html-framework-plugin.d.ts +36 -0
  71. package/dist/features/frameworks/static-html-framework-plugin.js +94 -0
  72. package/dist/features/frameworks/vite-framework-plugin.d.ts +36 -0
  73. package/dist/features/frameworks/vite-framework-plugin.js +97 -0
  74. package/dist/index.d.ts +2 -0
  75. package/dist/index.js +2 -0
  76. package/dist/interfaces/cli/main.d.ts +2 -0
  77. package/dist/interfaces/cli/main.js +157 -0
  78. package/dist/interfaces/cli/render-command-plan.d.ts +2 -0
  79. package/dist/interfaces/cli/render-command-plan.js +87 -0
  80. package/docs/CANARY.md +117 -0
  81. package/docs/COMPATIBILITY.md +88 -0
  82. package/docs/DEPLOY-SAFETY.md +113 -0
  83. package/package.json +83 -0
@@ -0,0 +1,168 @@
1
+ import { basename, resolve } from "node:path";
2
+ export function createProjectContext(input) {
3
+ const { inspection, environment } = input;
4
+ const remote = parseCodebergRemote(inspection.git.remoteUrl);
5
+ const repositoryName = remote?.repository ??
6
+ normalizePackageName(inspection.packageJson?.name) ??
7
+ basename(resolve(inspection.rootDir));
8
+ const framework = detectFramework(inspection);
9
+ const buildOutputDir = resolveBuildOutputDir(framework?.id, inspection);
10
+ const pages = inferPagesConfiguration(remote, inspection.git.defaultBranch, repositoryName);
11
+ return {
12
+ project: {
13
+ repository: {
14
+ name: repositoryName,
15
+ ...(remote?.owner ? { owner: remote.owner } : {}),
16
+ ...(inspection.git.remoteUrl ? { remoteUrl: inspection.git.remoteUrl } : {}),
17
+ ...(inspection.git.defaultBranch ? { defaultBranch: inspection.git.defaultBranch } : {}),
18
+ ...(inspection.git.currentBranch ? { currentBranch: inspection.git.currentBranch } : {}),
19
+ ...(inspection.git.isDirty !== undefined ? { isDirty: inspection.git.isDirty } : {})
20
+ },
21
+ paths: {
22
+ rootDir: inspection.rootDir,
23
+ ...(buildOutputDir ? { buildOutputDir } : {}),
24
+ ...(buildOutputDir
25
+ ? { buildOutputDirExists: inspection.detectedBuildOutputDirs.includes(buildOutputDir) }
26
+ : {}),
27
+ ...(inspection.detectedDomainsFile
28
+ ? {
29
+ domainsFilePath: inspection.detectedDomainsFile.path,
30
+ customDomains: inspection.detectedDomainsFile.domains
31
+ }
32
+ : {}),
33
+ ...(inspection.detectedConfigFiles.length > 0
34
+ ? { detectedConfigFiles: inspection.detectedConfigFiles }
35
+ : {}),
36
+ ...(inspection.detectedBuildOutputDirs.length > 0
37
+ ? { detectedBuildOutputDirs: inspection.detectedBuildOutputDirs }
38
+ : {}),
39
+ ...(inspection.detectedWorkflowFiles.length > 0
40
+ ? { detectedWorkflowFiles: inspection.detectedWorkflowFiles }
41
+ : {}),
42
+ ...(Object.keys(inspection.detectedWorkflowFileContents).length > 0
43
+ ? { detectedWorkflowFileContents: inspection.detectedWorkflowFileContents }
44
+ : {})
45
+ },
46
+ pages,
47
+ ...(framework ? { framework } : {}),
48
+ ...(inspection.packageJson
49
+ ? {
50
+ metadata: {
51
+ packageName: inspection.packageJson.name ?? repositoryName
52
+ }
53
+ }
54
+ : {})
55
+ },
56
+ environment
57
+ };
58
+ }
59
+ function inferPagesConfiguration(remote, defaultBranch, repositoryName) {
60
+ if (!remote) {
61
+ return {};
62
+ }
63
+ const basePath = `/${repositoryName}/`;
64
+ const url = `https://${remote.owner}.codeberg.page${basePath}`;
65
+ return {
66
+ target: {
67
+ kind: "codeberg-project",
68
+ owner: remote.owner,
69
+ repository: repositoryName,
70
+ basePath,
71
+ url
72
+ },
73
+ deployMode: {
74
+ id: "git-pages",
75
+ source: "detected"
76
+ },
77
+ publishStrategy: {
78
+ kind: "branch",
79
+ branch: defaultBranch ?? "main"
80
+ }
81
+ };
82
+ }
83
+ function detectFramework(inspection) {
84
+ const detectedConfigFiles = new Set(inspection.detectedConfigFiles.map((file) => file.toLowerCase()));
85
+ const dependencyNames = new Set([
86
+ ...inspection.packageJson?.dependencies ?? [],
87
+ ...inspection.packageJson?.devDependencies ?? []
88
+ ]);
89
+ const scriptValues = Object.values(inspection.packageJson?.scripts ?? {});
90
+ const hasAstroConfig = [...detectedConfigFiles].some((file) => file.startsWith("astro.config."));
91
+ const hasAstroDependency = dependencyNames.has("astro");
92
+ const hasAstroScript = scriptValues.some((script) => /\bastro\b/.test(script));
93
+ const hasViteConfig = [...detectedConfigFiles].some((file) => file.startsWith("vite.config."));
94
+ const hasViteDependency = dependencyNames.has("vite");
95
+ const hasViteScript = scriptValues.some((script) => /\bvite\b/.test(script));
96
+ const hasStaticOutput = resolveStaticOutputDir(inspection) !== undefined;
97
+ if (hasAstroConfig || hasAstroDependency || hasAstroScript) {
98
+ return {
99
+ id: "astro",
100
+ confidence: hasAstroConfig ? "high" : hasAstroDependency && hasAstroScript ? "high" : "medium",
101
+ source: "detected"
102
+ };
103
+ }
104
+ if (hasViteConfig || hasViteDependency || hasViteScript) {
105
+ return {
106
+ id: "vite",
107
+ confidence: hasViteConfig ? "high" : hasViteDependency && hasViteScript ? "high" : "medium",
108
+ source: "detected"
109
+ };
110
+ }
111
+ if (hasStaticOutput) {
112
+ return {
113
+ id: "static-html",
114
+ confidence: "medium",
115
+ source: "detected"
116
+ };
117
+ }
118
+ return undefined;
119
+ }
120
+ function resolveBuildOutputDir(frameworkId, inspection) {
121
+ if (frameworkId === "vite" || frameworkId === "astro") {
122
+ return "dist";
123
+ }
124
+ if (frameworkId === "static-html") {
125
+ return resolveStaticOutputDir(inspection);
126
+ }
127
+ return undefined;
128
+ }
129
+ function resolveStaticOutputDir(inspection) {
130
+ if (inspection.detectedBuildOutputDirs.includes("dist")) {
131
+ return "dist";
132
+ }
133
+ if (inspection.detectedBuildOutputDirs.includes("public")) {
134
+ return "public";
135
+ }
136
+ return undefined;
137
+ }
138
+ function normalizePackageName(packageName) {
139
+ if (!packageName) {
140
+ return undefined;
141
+ }
142
+ const normalized = packageName.includes("/") ? packageName.split("/").at(-1) : packageName;
143
+ return normalized || undefined;
144
+ }
145
+ function parseCodebergRemote(remoteUrl) {
146
+ if (!remoteUrl) {
147
+ return undefined;
148
+ }
149
+ const httpsMatch = remoteUrl.match(/^https:\/\/codeberg\.org\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
150
+ if (httpsMatch) {
151
+ const owner = httpsMatch[1];
152
+ const repository = httpsMatch[2];
153
+ if (!owner || !repository) {
154
+ return undefined;
155
+ }
156
+ return { owner, repository };
157
+ }
158
+ const sshMatch = remoteUrl.match(/^git@codeberg\.org:([^/]+)\/([^/]+?)(?:\.git)?$/i);
159
+ if (sshMatch) {
160
+ const owner = sshMatch[1];
161
+ const repository = sshMatch[2];
162
+ if (!owner || !repository) {
163
+ return undefined;
164
+ }
165
+ return { owner, repository };
166
+ }
167
+ return undefined;
168
+ }
@@ -0,0 +1,13 @@
1
+ import type { Diagnostic, DiagnosticSeverity } from "../../core/diagnostics/diagnostic.js";
2
+ import type { TemplatePlan } from "../../core/plans/template-plan.js";
3
+ import type { ProjectContext } from "../contracts/project-context.js";
4
+ type WorkflowDiagnosticCommand = "doctor" | "init" | "deploy";
5
+ interface WorkflowDiagnosticInput {
6
+ project: ProjectContext["project"];
7
+ templates: TemplatePlan[];
8
+ command: WorkflowDiagnosticCommand;
9
+ plannedConflictSeverity: DiagnosticSeverity;
10
+ unplannedWorkflowSeverity: DiagnosticSeverity;
11
+ }
12
+ export declare function getWorkflowFileDiagnostics(input: WorkflowDiagnosticInput): Diagnostic[];
13
+ export {};
@@ -0,0 +1,137 @@
1
+ export function getWorkflowFileDiagnostics(input) {
2
+ const detectedWorkflowFiles = [...input.project.paths.detectedWorkflowFiles ?? []].sort();
3
+ const detectedWorkflowFileContents = input.project.paths.detectedWorkflowFileContents ?? {};
4
+ const plannedTemplates = input.templates.filter(isFileTemplate);
5
+ const plannedWorkflowPaths = new Set(plannedTemplates.map((template) => template.path));
6
+ return [
7
+ ...plannedTemplates.flatMap((template) => getPlannedWorkflowDiagnostics({
8
+ command: input.command,
9
+ detectedWorkflowFiles,
10
+ detectedWorkflowFileContents,
11
+ plannedConflictSeverity: input.plannedConflictSeverity,
12
+ template
13
+ })),
14
+ ...detectedWorkflowFiles.flatMap((workflowPath) => {
15
+ if (plannedWorkflowPaths.has(workflowPath)) {
16
+ return [];
17
+ }
18
+ return [
19
+ getUnplannedWorkflowDiagnostic({
20
+ command: input.command,
21
+ severity: input.unplannedWorkflowSeverity,
22
+ workflowPath
23
+ })
24
+ ];
25
+ })
26
+ ];
27
+ }
28
+ function getPlannedWorkflowDiagnostics(input) {
29
+ if (!input.detectedWorkflowFiles.includes(input.template.path)) {
30
+ return [];
31
+ }
32
+ const existingContent = input.detectedWorkflowFileContents[input.template.path];
33
+ if (existingContent === input.template.content) {
34
+ return [];
35
+ }
36
+ if (input.command === "init" && existingContent === undefined) {
37
+ return [
38
+ {
39
+ code: "init.workflow-file.conflict",
40
+ severity: input.plannedConflictSeverity,
41
+ summary: `A planned workflow file already exists at ${input.template.path}.`,
42
+ detail: "Dry-run planning will not overwrite an existing workflow file without a future explicit apply strategy.",
43
+ suggestions: [
44
+ "Review the existing workflow before applying generated changes.",
45
+ "Rename or remove the conflicting workflow only after confirming it is safe."
46
+ ],
47
+ source: "application"
48
+ }
49
+ ];
50
+ }
51
+ return [
52
+ {
53
+ code: `${input.command}.workflow-file.differs`,
54
+ severity: input.plannedConflictSeverity,
55
+ summary: getPlannedConflictSummary(input.command, input.template.path),
56
+ detail: getPlannedConflictDetail(input.command),
57
+ suggestions: getPlannedConflictSuggestions(input.command),
58
+ source: "application"
59
+ }
60
+ ];
61
+ }
62
+ function getPlannedConflictSummary(command, workflowPath) {
63
+ if (command === "init") {
64
+ return `The existing workflow file at ${workflowPath} differs from the planned content.`;
65
+ }
66
+ return `Existing workflow file differs from the planned ${workflowPath} output.`;
67
+ }
68
+ function getPlannedConflictDetail(command) {
69
+ if (command === "deploy") {
70
+ return "Deploy planning is blocked until the local init workflow conflict is reviewed.";
71
+ }
72
+ if (command === "doctor") {
73
+ return "Doctor found a workflow file that should be reviewed before any future apply mode exists.";
74
+ }
75
+ return "Dry-run planning detected a workflow conflict that needs human review before any future apply mode exists.";
76
+ }
77
+ function getPlannedConflictSuggestions(command) {
78
+ if (command === "deploy") {
79
+ return [
80
+ "Compare the existing workflow with `init --dry-run` output.",
81
+ "Keep deploy in dry-run mode until the workflow conflict is resolved."
82
+ ];
83
+ }
84
+ if (command === "doctor") {
85
+ return [
86
+ "Compare the existing workflow with `init --dry-run` output.",
87
+ "Decide whether to keep, rename, or manually update the existing workflow."
88
+ ];
89
+ }
90
+ return [
91
+ "Compare the existing workflow with the dry-run preview.",
92
+ "Decide whether to keep, rename, or manually update the existing workflow."
93
+ ];
94
+ }
95
+ function getUnplannedWorkflowDiagnostic(input) {
96
+ return {
97
+ code: `${input.command}.workflow-file.unplanned-existing`,
98
+ severity: input.severity,
99
+ summary: `Existing Forgejo workflow file is outside the generated Pages workflow: ${input.workflowPath}.`,
100
+ detail: getUnplannedWorkflowDetail(input.command),
101
+ suggestions: getUnplannedWorkflowSuggestions(input.command),
102
+ source: "application",
103
+ metadata: {
104
+ workflowPath: input.workflowPath
105
+ }
106
+ };
107
+ }
108
+ function getUnplannedWorkflowDetail(command) {
109
+ if (command === "deploy") {
110
+ return "Deploy planning found another workflow that may publish, build, or mutate deployment state.";
111
+ }
112
+ if (command === "init") {
113
+ return "Init apply will not add a generated Pages workflow while another Forgejo workflow exists without review.";
114
+ }
115
+ return "Doctor found an existing Forgejo workflow that may already build, publish, or deploy this project.";
116
+ }
117
+ function getUnplannedWorkflowSuggestions(command) {
118
+ if (command === "deploy") {
119
+ return [
120
+ "Review the existing workflow before deploying directly.",
121
+ "Confirm it will not publish conflicting output to Codeberg Pages."
122
+ ];
123
+ }
124
+ if (command === "init") {
125
+ return [
126
+ "Review the existing workflow before applying generated Pages changes.",
127
+ "Rename, remove, or integrate the workflow only after confirming it is safe."
128
+ ];
129
+ }
130
+ return [
131
+ "Review the existing workflow before running init --apply.",
132
+ "Confirm whether it already deploys this site or writes to a Pages target."
133
+ ];
134
+ }
135
+ function isFileTemplate(template) {
136
+ return template.kind === "file";
137
+ }
@@ -0,0 +1,11 @@
1
+ export type DiagnosticSeverity = "error" | "warning" | "info";
2
+ export type DiagnosticSource = "core" | "application" | "framework-plugin" | "deploy-mode-plugin";
3
+ export interface Diagnostic {
4
+ code: string;
5
+ severity: DiagnosticSeverity;
6
+ summary: string;
7
+ detail?: string;
8
+ suggestions?: string[];
9
+ source: DiagnosticSource;
10
+ metadata?: Record<string, string | number | boolean>;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export type CommandId = "doctor" | "init" | "deploy" | "migrate";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { SelectionSource } from "./framework.js";
2
+ export type DeployModeId = string;
3
+ export interface DeployModeSelection {
4
+ id: DeployModeId;
5
+ source: SelectionSource;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export type OperatingSystem = "windows" | "macos" | "linux" | "unknown";
2
+ export interface ToolAvailability {
3
+ available: boolean;
4
+ version?: string;
5
+ }
6
+ export interface EnvironmentSnapshot {
7
+ cwd: string;
8
+ os: OperatingSystem;
9
+ ci: boolean;
10
+ tools: {
11
+ git?: ToolAvailability;
12
+ node?: ToolAvailability;
13
+ npm?: ToolAvailability;
14
+ [toolName: string]: ToolAvailability | undefined;
15
+ };
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export type FrameworkId = string;
2
+ export type DetectionConfidence = "low" | "medium" | "high";
3
+ export type SelectionSource = "configured" | "detected" | "assumed" | "unknown";
4
+ export interface FrameworkSelection {
5
+ id: FrameworkId;
6
+ confidence: DetectionConfidence;
7
+ source: SelectionSource;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ export interface CodebergRootTarget {
2
+ kind: "codeberg-root";
3
+ owner: string;
4
+ url: string;
5
+ }
6
+ export interface CodebergProjectTarget {
7
+ kind: "codeberg-project";
8
+ owner: string;
9
+ repository: string;
10
+ basePath: string;
11
+ url: string;
12
+ }
13
+ export interface CustomDomainTarget {
14
+ kind: "custom-domain";
15
+ domain: string;
16
+ url: string;
17
+ }
18
+ export interface UnknownPagesTarget {
19
+ kind: "unknown";
20
+ url?: string;
21
+ }
22
+ export type PagesTarget = CodebergRootTarget | CodebergProjectTarget | CustomDomainTarget | UnknownPagesTarget;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import type { DeployModeSelection } from "./deploy-mode.js";
2
+ import type { FrameworkSelection } from "./framework.js";
3
+ import type { PagesTarget } from "./pages-target.js";
4
+ export interface RepositoryIdentity {
5
+ owner?: string;
6
+ name: string;
7
+ remoteUrl?: string;
8
+ defaultBranch?: string;
9
+ currentBranch?: string;
10
+ isDirty?: boolean;
11
+ }
12
+ export interface ProjectPaths {
13
+ rootDir: string;
14
+ buildOutputDir?: string;
15
+ buildOutputDirExists?: boolean;
16
+ domainsFilePath?: string;
17
+ customDomains?: string[];
18
+ detectedConfigFiles?: string[];
19
+ detectedBuildOutputDirs?: string[];
20
+ detectedWorkflowFiles?: string[];
21
+ detectedWorkflowFileContents?: Record<string, string>;
22
+ }
23
+ export type PublishStrategy = {
24
+ kind: "branch";
25
+ branch: string;
26
+ } | {
27
+ kind: "repository";
28
+ repository: string;
29
+ branch?: string;
30
+ } | {
31
+ kind: "unknown";
32
+ };
33
+ export interface PagesConfiguration {
34
+ target?: PagesTarget;
35
+ deployMode?: DeployModeSelection;
36
+ publishStrategy?: PublishStrategy;
37
+ preserveDomainsFile?: boolean;
38
+ }
39
+ export interface Project {
40
+ repository: RepositoryIdentity;
41
+ paths: ProjectPaths;
42
+ pages: PagesConfiguration;
43
+ framework?: FrameworkSelection;
44
+ metadata?: Record<string, string | number | boolean>;
45
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ export * from "./diagnostics/diagnostic.js";
2
+ export * from "./entities/command.js";
3
+ export * from "./entities/deploy-mode.js";
4
+ export * from "./entities/environment.js";
5
+ export * from "./entities/framework.js";
6
+ export * from "./entities/pages-target.js";
7
+ export * from "./entities/project.js";
8
+ export * from "./plans/assumption.js";
9
+ export * from "./plans/build-plan.js";
10
+ export * from "./plans/command-plan.js";
11
+ export * from "./plans/deploy-plan.js";
12
+ export * from "./plans/plan-step.js";
13
+ export * from "./plans/template-plan.js";
@@ -0,0 +1,13 @@
1
+ export * from "./diagnostics/diagnostic.js";
2
+ export * from "./entities/command.js";
3
+ export * from "./entities/deploy-mode.js";
4
+ export * from "./entities/environment.js";
5
+ export * from "./entities/framework.js";
6
+ export * from "./entities/pages-target.js";
7
+ export * from "./entities/project.js";
8
+ export * from "./plans/assumption.js";
9
+ export * from "./plans/build-plan.js";
10
+ export * from "./plans/command-plan.js";
11
+ export * from "./plans/deploy-plan.js";
12
+ export * from "./plans/plan-step.js";
13
+ export * from "./plans/template-plan.js";
@@ -0,0 +1,7 @@
1
+ export type AssumptionStatus = "confirmed" | "unverified" | "missing";
2
+ export interface Assumption {
3
+ code: string;
4
+ summary: string;
5
+ status: AssumptionStatus;
6
+ detail?: string;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { FrameworkId } from "../entities/framework.js";
2
+ import type { Diagnostic } from "../diagnostics/diagnostic.js";
3
+ import type { Assumption } from "./assumption.js";
4
+ import type { BuildPlanStep } from "./plan-step.js";
5
+ export interface BuildPlan {
6
+ frameworkId: FrameworkId;
7
+ summary: string;
8
+ outputDir?: string;
9
+ assumptions: Assumption[];
10
+ diagnostics: Diagnostic[];
11
+ steps: BuildPlanStep[];
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { CommandId } from "../entities/command.js";
2
+ import type { Project } from "../entities/project.js";
3
+ import type { Diagnostic } from "../diagnostics/diagnostic.js";
4
+ import type { Assumption } from "./assumption.js";
5
+ import type { PlanStep } from "./plan-step.js";
6
+ export interface EffectSummary {
7
+ writes: number;
8
+ deletes: number;
9
+ directories: number;
10
+ commands: number;
11
+ publishes: number;
12
+ verifications: number;
13
+ notes: number;
14
+ }
15
+ export interface CommandPlan {
16
+ command: CommandId;
17
+ summary: string;
18
+ project: Project;
19
+ assumptions: Assumption[];
20
+ diagnostics: Diagnostic[];
21
+ steps: PlanStep[];
22
+ safeToApply: boolean;
23
+ effectSummary: EffectSummary;
24
+ }
25
+ export declare function hasBlockingDiagnostics(diagnostics: Diagnostic[]): boolean;
26
+ export declare function createEffectSummary(steps: PlanStep[]): EffectSummary;
27
+ export declare function createCommandPlan(input: Omit<CommandPlan, "safeToApply" | "effectSummary">): CommandPlan;
@@ -0,0 +1,45 @@
1
+ export function hasBlockingDiagnostics(diagnostics) {
2
+ return diagnostics.some((diagnostic) => diagnostic.severity === "error");
3
+ }
4
+ export function createEffectSummary(steps) {
5
+ return steps.reduce((summary, step) => {
6
+ switch (step.kind) {
7
+ case "write-file":
8
+ summary.writes += 1;
9
+ return summary;
10
+ case "delete-file":
11
+ summary.deletes += 1;
12
+ return summary;
13
+ case "ensure-directory":
14
+ summary.directories += 1;
15
+ return summary;
16
+ case "run-command":
17
+ summary.commands += 1;
18
+ return summary;
19
+ case "publish-site":
20
+ summary.publishes += 1;
21
+ return summary;
22
+ case "verify":
23
+ summary.verifications += 1;
24
+ return summary;
25
+ case "note":
26
+ summary.notes += 1;
27
+ return summary;
28
+ }
29
+ }, {
30
+ writes: 0,
31
+ deletes: 0,
32
+ directories: 0,
33
+ commands: 0,
34
+ publishes: 0,
35
+ verifications: 0,
36
+ notes: 0
37
+ });
38
+ }
39
+ export function createCommandPlan(input) {
40
+ return {
41
+ ...input,
42
+ safeToApply: !hasBlockingDiagnostics(input.diagnostics),
43
+ effectSummary: createEffectSummary(input.steps)
44
+ };
45
+ }
@@ -0,0 +1,17 @@
1
+ import type { DeployModeId } from "../entities/deploy-mode.js";
2
+ import type { PagesTarget } from "../entities/pages-target.js";
3
+ import type { Diagnostic } from "../diagnostics/diagnostic.js";
4
+ import type { Assumption } from "./assumption.js";
5
+ import type { DeployPlanStep } from "./plan-step.js";
6
+ export interface DeployPlan {
7
+ modeId: DeployModeId;
8
+ summary: string;
9
+ target?: PagesTarget;
10
+ assumptions: Assumption[];
11
+ diagnostics: Diagnostic[];
12
+ steps: DeployPlanStep[];
13
+ }
14
+ export interface DeployResult {
15
+ appliedStepIds: string[];
16
+ diagnostics: Diagnostic[];
17
+ }
@@ -0,0 +1 @@
1
+ export {};