@williambeto/ai-workflow 2.3.1 → 2.3.5

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 (29) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +14 -10
  3. package/dist-assets/agents/astra.md +1 -0
  4. package/dist-assets/skills/architecture/SKILL.md +1 -1
  5. package/dist-assets/skills/backend-development/SKILL.md +1 -1
  6. package/dist-assets/skills/deployment/SKILL.md +1 -1
  7. package/dist-assets/skills/design-principles/SKILL.md +1 -1
  8. package/dist-assets/skills/documentation/SKILL.md +1 -1
  9. package/dist-assets/skills/frontend-development/SKILL.md +2 -1
  10. package/dist-assets/skills/full-stack-development/SKILL.md +1 -1
  11. package/dist-assets/skills/optimize-tokens/SKILL.md +1 -1
  12. package/dist-assets/skills/pr-workflow/SKILL.md +1 -1
  13. package/dist-assets/skills/product-discovery/SKILL.md +1 -1
  14. package/dist-assets/skills/product-planning/SKILL.md +1 -1
  15. package/dist-assets/skills/project-memory/SKILL.md +1 -1
  16. package/dist-assets/skills/prompt-engineer/SKILL.md +1 -1
  17. package/dist-assets/skills/qa-workflow/SKILL.md +1 -1
  18. package/dist-assets/skills/refactoring/SKILL.md +1 -1
  19. package/dist-assets/skills/release-workflow/SKILL.md +1 -1
  20. package/dist-assets/skills/spec-driven-development/SKILL.md +1 -1
  21. package/dist-assets/skills/technical-leadership/SKILL.md +1 -1
  22. package/dist-assets/skills/ui-ux-design/SKILL.md +1 -1
  23. package/docs/getting-started/upgrading-to-v2.md +10 -3
  24. package/package.json +3 -2
  25. package/src/commands/execute.js +8 -0
  26. package/src/core/finalization/finalizer.js +39 -0
  27. package/src/core/templates.js +8 -8
  28. package/src/core/validation/artifact-fidelity-gate.js +63 -0
  29. package/src/core/validation/delivery-decision-engine.js +69 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [2.3.2] - 2026-06-19
2
+
3
+ ### Documentation
4
+ - Clarified first-time usage with `npx @williambeto/ai-workflow init`.
5
+ - Clarified local installed-package alias usage with `npx aw init`, `npx aw doctor`, and `npx aw run`.
6
+
7
+ ### Notes
8
+ - No CLI behavior changed.
9
+ - No runtime behavior changed.
10
+
1
11
  ## [2.3.1] - 2026-06-18
2
12
 
3
13
  ### Fixed
package/README.md CHANGED
@@ -21,26 +21,30 @@ The workflow the product guarantees is:
21
21
 
22
22
  In practice, the kit is neither a frontend framework nor a UI library. It is an operational layer for software agents: it installs instructions and guardrails so that the agent can work more effectively inside the user's repository.
23
23
 
24
- ## Installation
24
+ ## Installation and Usage
25
25
 
26
- ### Current public release
26
+ ### First-time usage
27
+
28
+ Use the full package command when running the kit before it is installed in a project:
27
29
 
28
30
  ```bash
29
- npm install -g @williambeto/ai-workflow@latest
31
+ npx @williambeto/ai-workflow init
30
32
  ```
31
33
 
32
- Use `latest` for the supported public release. Release notes record exact historical versions when needed.
34
+ ### Short alias after installation
33
35
 
34
- ## Quick start
36
+ After installing AI Workflow Kit in a project, the shorter `aw` binary is available through `node_modules/.bin`:
35
37
 
36
38
  ```bash
37
- mkdir workflow-test && cd workflow-test
38
- npm init -y
39
- ai-workflow init --yes
40
- ai-workflow doctor
41
- ai-workflow execute "Atlas, list all agents, subagents, skills, and commands in the project. Present them in a table with their name, description, and usage examples."
39
+ npm install -D @williambeto/ai-workflow
40
+
41
+ npx aw init
42
+ npx aw doctor
43
+ npx aw run "Atlas, list all agents, subagents, skills, and commands in the project. Present them in a table with their name, description, and usage examples."
42
44
  ```
43
45
 
46
+ The `aw` binary is an alias for the same CLI entrypoint as `ai-workflow`.
47
+
44
48
  The CLI receives the natural request, classifies the intent, plans the workflow, switch/creates branch safely, delegates coding tasks to the OpenCode runtime adapter, validates changes, and runs bounded remediation if necessary before outputting the handoff summary.
45
49
 
46
50
  ## Modes and profiles
@@ -38,6 +38,7 @@ Astra implements only after branch gate is satisfied. It keeps changes bounded t
38
38
  * Run relevant validation after implementation.
39
39
  * Preserve existing behavior and unrelated dirty work.
40
40
  * Load `frontend-development` and `ui-ux-design` skills only when they apply. Use selected profile as quality guidance.
41
+ * Implement all frontend, backend, or full-stack tasks using framework-native or stack-native paradigms (e.g., framework-native React/Next.js components, Vue/Nuxt files, or project stack paradigms rather than generic standalone HTML/JS prototypes) unless explicitly asked otherwise by the user.
41
42
  * Policies: `01-BRANCH_GATE.md`, `03-QUALITY_GATE.md`, `06-FINAL_EVIDENCE_CONTRACT.md`, `PROCEDURE_UI_CHECKLIST.md`.
42
43
 
43
44
  ## Allowed tools
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: architecture
3
3
  description: Skill-backed capability for architectural design and modularity
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Architecture PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: backend-development
3
3
  description: Skill-backed capability for backend APIs, routes, and data persistence
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Backend Development PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: deployment
3
3
  description: Skill-backed capability for deployment planning, environments, and validation
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Deployment PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: design-principles
3
3
  description: Skill-backed capability for clean, maintainable software design patterns
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Design Principles PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: documentation
3
3
  description: Skill-backed capability for writing and verifying technical documentation
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Documentation PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: frontend-development
3
3
  description: Skill-backed capability for frontend UI components and styles
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Frontend Development PromptContract
@@ -29,6 +29,7 @@ Do not trust:
29
29
  ## Constraints
30
30
  - Follow accessibility (WCAG/ARIA) guidelines.
31
31
  - Support responsive layouts.
32
+ - Deliver UI/frontend artifacts native to the detected or specified project stack (using framework-native or stack-native architectures like React, Vue, Nuxt, WordPress PHP, etc. rather than standalone HTML/JS files) unless explicitly specified otherwise.
32
33
  - Do not claim execution without evidence.
33
34
 
34
35
  ## Allowed tools
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: full-stack-development
3
3
  description: Skill-backed capability for coordinating frontend and backend updates
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Full-Stack Development PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: optimize-tokens
3
3
  description: Skill-backed capability for reducing context size and optimizing token economy
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Optimize Tokens PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pr-workflow
3
3
  description: Skill-backed capability for branch gates and pull request verification
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # PR Workflow PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: product-discovery
3
3
  description: Skill-backed capability for project and product discovery work
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Product Discovery PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: product-planning
3
3
  description: Skill-backed capability for translating needs into scoped requirements
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Product Planning PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: project-memory
3
3
  description: Skill-backed capability for project memory, ADRs, and decision records
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Project Memory PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: prompt-engineer
3
3
  description: Skill-backed capability for refining prompts and instructions
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Prompt Engineering PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: qa-workflow
3
3
  description: Skill-backed capability for quality gates and validation tests
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Quality Assurance PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: refactoring
3
3
  description: Skill-backed capability for code refactoring and bug-fixing
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Refactoring and Remediation PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: release-workflow
3
3
  description: Skill-backed capability for release management and validation
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Release Workflow PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: spec-driven-development
3
3
  description: Skill-backed capability for converting requirements to testable specs
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Spec-Driven Development PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: technical-leadership
3
3
  description: Skill-backed capability for high-level technical decisions and reviews
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # Technical Leadership PromptContract
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: ui-ux-design
3
3
  description: Skill-backed capability for user interface and experience design guidelines
4
- governance: dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md
4
+ governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
5
5
  ---
6
6
 
7
7
  # UI-UX Design PromptContract
@@ -19,10 +19,17 @@ Version `2.x` is a breaking public line from the previous `1.x` line. Test upgra
19
19
 
20
20
  4. Inspect initialization before applying it:
21
21
 
22
+ For first-time or pre-installation usage:
22
23
  ```bash
23
- ai-workflow init --dry-run
24
- ai-workflow init --yes
25
- ai-workflow doctor
24
+ npx @williambeto/ai-workflow init --dry-run
25
+ npx @williambeto/ai-workflow init --yes
26
+ ```
27
+
28
+ After installing AI Workflow Kit locally in your project:
29
+ ```bash
30
+ npx aw init --dry-run
31
+ npx aw init --yes
32
+ npx aw doctor
26
33
  ```
27
34
 
28
35
  ## Main changes in version 2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williambeto/ai-workflow",
3
- "version": "2.3.1",
3
+ "version": "2.3.5",
4
4
  "description": "AI Workflow Kit — OpenCode-first software delivery workflow with agents, commands, skills, validation, and evidence",
5
5
  "license": "MIT",
6
6
  "author": "José Willams",
@@ -29,7 +29,8 @@
29
29
  "url": "https://github.com/williambeto/ai-workflow/issues"
30
30
  },
31
31
  "bin": {
32
- "ai-workflow": "bin/ai-workflow.js"
32
+ "ai-workflow": "bin/ai-workflow.js",
33
+ "aw": "bin/ai-workflow.js"
33
34
  },
34
35
  "files": [
35
36
  "bin",
@@ -327,6 +327,14 @@ export async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverri
327
327
  console.log(`\n[FINALIZER BLOCKED] BLOCKED: workspace did not stabilize`);
328
328
  console.log(`Final changes detected:`, integrity.changes);
329
329
  finalStatus = "FAIL_QUALITY_GATE";
330
+ } else {
331
+ // Workspace stabilized, now run Artifact Fidelity Gate
332
+ const fidelityResult = await finalizer.verifyFidelity(result.evidence?.changedFiles);
333
+ if (!fidelityResult.passed) {
334
+ console.log(`\n[FINALIZER BLOCKED] BLOCKED: Artifact fidelity check failed!`);
335
+ console.log(`Reason: ${fidelityResult.reason}`);
336
+ finalStatus = "FAIL_QUALITY_GATE";
337
+ }
330
338
  }
331
339
 
332
340
  const finalState = finalStatus === "PASS"
@@ -1,4 +1,7 @@
1
1
  import { WorkspaceSnapshot } from "./workspace-snapshot.js";
2
+ import { DeliveryDecisionEngine } from "../validation/delivery-decision-engine.js";
3
+ import { ArtifactFidelityGate } from "../validation/artifact-fidelity-gate.js";
4
+ import { execSync } from "node:child_process";
2
5
 
3
6
  export class Finalizer {
4
7
  constructor({ cwd = process.cwd() } = {}) {
@@ -6,6 +9,42 @@ export class Finalizer {
6
9
  this.snapshotManager = new WorkspaceSnapshot({ cwd });
7
10
  }
8
11
 
12
+ getChangedFilesFromGit() {
13
+ try {
14
+ const files = new Set();
15
+ // Unstaged changes
16
+ const diff = execSync("git diff --name-only HEAD", { cwd: this.cwd, encoding: "utf8" });
17
+ diff.split("\n").map(f => f.trim()).filter(Boolean).forEach(f => files.add(f));
18
+
19
+ // Untracked/staged status
20
+ const status = execSync("git status --short --untracked-files=all", { cwd: this.cwd, encoding: "utf8" });
21
+ status.split("\n").forEach(line => {
22
+ const match = line.match(/^(?:[ MADRCU?!]{2}\s+|[MADRCU?!]\s+)(.+)$/);
23
+ if (match) {
24
+ const candidate = match[1].trim();
25
+ const renamed = candidate.includes(" -> ") ? candidate.split(" -> ").at(-1) : candidate;
26
+ if (renamed) files.add(renamed);
27
+ }
28
+ });
29
+ return [...files].sort();
30
+ } catch {
31
+ return [];
32
+ }
33
+ }
34
+
35
+ async verifyFidelity(changedFiles = null) {
36
+ const filesToCheck = changedFiles || this.getChangedFilesFromGit();
37
+ const decisionEngine = new DeliveryDecisionEngine({ cwd: this.cwd });
38
+ const deliveryClass = await decisionEngine.determineClass(filesToCheck);
39
+ const fidelityGate = new ArtifactFidelityGate({ cwd: this.cwd, deliveryClass });
40
+ const result = await fidelityGate.verify(filesToCheck);
41
+ return {
42
+ passed: result.passed,
43
+ reason: result.reason,
44
+ deliveryClass
45
+ };
46
+ }
47
+
9
48
  /**
10
49
  * Compares the current workspace state with a previously captured snapshot.
11
50
  * @param {Object} previousSnapshot - The snapshot object captured earlier.
@@ -105,35 +105,35 @@ function buildRuntimeFiles({ includeFormalEvidence = false } = {}) {
105
105
  if (consumerQuickstart !== null) files["QUICKSTART.md"] = consumerQuickstart;
106
106
 
107
107
  const policyContent = readPackageFile("dist-assets/docs/architecture-policy.md");
108
- if (policyContent !== null) files["docs/architecture-policy.md"] = policyContent;
108
+ if (policyContent !== null) files["opencode/docs/architecture-policy.md"] = policyContent;
109
109
 
110
110
  const dpContent = readPackageFile("dist-assets/docs/design-patterns-policy.md");
111
- if (dpContent !== null) files["docs/design-patterns-policy.md"] = dpContent;
111
+ if (dpContent !== null) files["opencode/docs/design-patterns-policy.md"] = dpContent;
112
112
 
113
113
  const visualValidationGuide = readPackageFile("dist-assets/docs/visual-validation-guide.md");
114
- if (visualValidationGuide !== null) files["docs/visual-validation-guide.md"] = visualValidationGuide;
114
+ if (visualValidationGuide !== null) files["opencode/docs/visual-validation-guide.md"] = visualValidationGuide;
115
115
 
116
116
  const governancePolicies = discoverPackageFiles("dist-assets/docs/policies");
117
117
  for (const [relPath, content] of Object.entries(governancePolicies)) {
118
- const targetPath = relPath.replace(/^dist-assets\//, "");
118
+ const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
119
119
  files[targetPath] = content;
120
120
  }
121
121
 
122
122
  const compatibilityDocs = discoverPackageFiles("dist-assets/docs/compatibility");
123
123
  for (const [relPath, content] of Object.entries(compatibilityDocs)) {
124
- const targetPath = relPath.replace(/^dist-assets\//, "");
124
+ const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
125
125
  files[targetPath] = content;
126
126
  }
127
127
 
128
128
  const qualityReferenceFiles = discoverPackageFiles("dist-assets/docs/references");
129
129
  for (const [relPath, content] of Object.entries(qualityReferenceFiles)) {
130
- const targetPath = relPath.replace(/^dist-assets\//, "");
130
+ const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
131
131
  files[targetPath] = content;
132
132
  }
133
133
 
134
134
  const workflowProfileFiles = discoverPackageFiles("dist-assets/docs/profiles");
135
135
  for (const [relPath, content] of Object.entries(workflowProfileFiles)) {
136
- const targetPath = relPath.replace(/^dist-assets\//, "");
136
+ const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
137
137
  files[targetPath] = content;
138
138
  }
139
139
 
@@ -221,7 +221,7 @@ export function buildAiWorkflowConfig({ profile, managedFiles, managedLinks = []
221
221
  agents: ".ai-workflow/opencode/agents",
222
222
  commands: ".ai-workflow/opencode/commands",
223
223
  skills: ".ai-workflow/opencode/skills",
224
- policies: ".ai-workflow/docs/policies",
224
+ policies: ".ai-workflow/opencode/docs/policies",
225
225
  harness: ".ai-workflow/harness",
226
226
  schemas: ".ai-workflow/schemas"
227
227
  }
@@ -0,0 +1,63 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ export class ArtifactFidelityGate {
5
+ constructor({ cwd = process.cwd(), deliveryClass } = {}) {
6
+ this.cwd = cwd;
7
+ this.deliveryClass = deliveryClass;
8
+ }
9
+
10
+ async verify(changedFiles = []) {
11
+ if (changedFiles.length === 0) {
12
+ return { passed: true };
13
+ }
14
+
15
+ if (this.deliveryClass === "framework-native-frontend") {
16
+ for (const file of changedFiles) {
17
+ const ext = path.extname(file).toLowerCase();
18
+
19
+ // 1. Forbid adding/modifying HTML files that are not SPA entry points
20
+ if (ext === ".html" || ext === ".htm") {
21
+ const basename = path.basename(file).toLowerCase();
22
+ const isSpaEntry = basename === "index.html" &&
23
+ (file === "index.html" || file === "public/index.html" || file === "src/index.html");
24
+ if (!isSpaEntry) {
25
+ return {
26
+ passed: false,
27
+ reason: `Fidelity Violation: standalone HTML file '${file}' is not permitted in a framework-native frontend project. UI must be implemented within framework components (e.g. React/Vue/Next/Nuxt files) instead of static prototypes.`
28
+ };
29
+ }
30
+
31
+ // Check if SPA entry imports framework libraries via CDN script tags
32
+ try {
33
+ const content = await fs.readFile(path.join(this.cwd, file), "utf8");
34
+ if (content.includes("unpkg.com") || content.includes("cdnjs.cloudflare.com") || content.includes("cdn.jsdelivr.net")) {
35
+ if (content.includes("vue") || content.includes("react")) {
36
+ return {
37
+ passed: false,
38
+ reason: `Fidelity Violation: SPA entry point '${file}' imports framework library via CDN scripts. Framework dependencies must be installed and resolved locally via npm/package.json.`
39
+ };
40
+ }
41
+ }
42
+ } catch {
43
+ // ignore
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ if (this.deliveryClass === "wordpress-php") {
50
+ for (const file of changedFiles) {
51
+ const ext = path.extname(file).toLowerCase();
52
+ if (ext === ".html" || ext === ".htm") {
53
+ return {
54
+ passed: false,
55
+ reason: `Fidelity Violation: standalone HTML file '${file}' is not permitted in a WordPress project. UI templates must be implemented in PHP files within theme or plugin structures.`
56
+ };
57
+ }
58
+ }
59
+ }
60
+
61
+ return { passed: true };
62
+ }
63
+ }
@@ -0,0 +1,69 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { StackDetector } from "./stack-detector.js";
4
+
5
+ export class DeliveryDecisionEngine {
6
+ constructor({ cwd = process.cwd() } = {}) {
7
+ this.cwd = cwd;
8
+ this.stackDetector = new StackDetector({ cwd });
9
+ }
10
+
11
+ async determineClass(changedFiles = []) {
12
+ if (changedFiles.length === 0) {
13
+ return "empty";
14
+ }
15
+
16
+ // 1. Docs check
17
+ const isDocs = changedFiles.every(file =>
18
+ file.endsWith(".md") || file.endsWith(".txt") || file.startsWith("docs/")
19
+ );
20
+ if (isDocs) {
21
+ return "docs-only";
22
+ }
23
+
24
+ // 2. Detect project stacks
25
+ const stacks = await this.stackDetector.detect();
26
+
27
+ // Check package.json for frontend frameworks
28
+ let usesJsFramework = false;
29
+ try {
30
+ const pkgPath = path.join(this.cwd, "package.json");
31
+ const pkgContent = await fs.readFile(pkgPath, "utf8");
32
+ const pkg = JSON.parse(pkgContent);
33
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
34
+
35
+ const frameworks = ["react", "next", "vue", "nuxt", "svelte", "solid-js", "preact", "quasar", "@angular/core"];
36
+ usesJsFramework = frameworks.some(fw => deps[fw] !== undefined);
37
+ } catch {
38
+ // package.json doesn't exist or is invalid
39
+ }
40
+
41
+ // Check for WordPress
42
+ const isWordPress = await fs.access(path.join(this.cwd, "wp-config.php")).then(() => true).catch(() => false) ||
43
+ await fs.access(path.join(this.cwd, "wp-content")).then(() => true).catch(() => false);
44
+
45
+ // Analyze changed files for UI/frontend assets
46
+ const hasFrontendFiles = changedFiles.some(file =>
47
+ /\.(html?|css|scss|sass|less|jsx|tsx|vue|svelte)$/i.test(file) ||
48
+ (/\.js$/i.test(file) && !file.includes("config") && !file.includes("test"))
49
+ );
50
+
51
+ if (isWordPress) {
52
+ return "wordpress-php";
53
+ }
54
+
55
+ if (usesJsFramework && hasFrontendFiles) {
56
+ return "framework-native-frontend";
57
+ }
58
+
59
+ if (hasFrontendFiles) {
60
+ return "standalone-web";
61
+ }
62
+
63
+ if (stacks.includes("python") || stacks.includes("php") || (stacks.includes("node") && !usesJsFramework)) {
64
+ return "backend-service";
65
+ }
66
+
67
+ return "generic-code";
68
+ }
69
+ }