@williambeto/ai-workflow 2.3.2 → 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.
- package/dist-assets/agents/astra.md +1 -0
- package/dist-assets/skills/architecture/SKILL.md +1 -1
- package/dist-assets/skills/backend-development/SKILL.md +1 -1
- package/dist-assets/skills/deployment/SKILL.md +1 -1
- package/dist-assets/skills/design-principles/SKILL.md +1 -1
- package/dist-assets/skills/documentation/SKILL.md +1 -1
- package/dist-assets/skills/frontend-development/SKILL.md +2 -1
- package/dist-assets/skills/full-stack-development/SKILL.md +1 -1
- package/dist-assets/skills/optimize-tokens/SKILL.md +1 -1
- package/dist-assets/skills/pr-workflow/SKILL.md +1 -1
- package/dist-assets/skills/product-discovery/SKILL.md +1 -1
- package/dist-assets/skills/product-planning/SKILL.md +1 -1
- package/dist-assets/skills/project-memory/SKILL.md +1 -1
- package/dist-assets/skills/prompt-engineer/SKILL.md +1 -1
- package/dist-assets/skills/qa-workflow/SKILL.md +1 -1
- package/dist-assets/skills/refactoring/SKILL.md +1 -1
- package/dist-assets/skills/release-workflow/SKILL.md +1 -1
- package/dist-assets/skills/spec-driven-development/SKILL.md +1 -1
- package/dist-assets/skills/technical-leadership/SKILL.md +1 -1
- package/dist-assets/skills/ui-ux-design/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/commands/execute.js +8 -0
- package/src/core/finalization/finalizer.js +39 -0
- package/src/core/templates.js +8 -8
- package/src/core/validation/artifact-fidelity-gate.js +63 -0
- package/src/core/validation/delivery-decision-engine.js +69 -0
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
4
|
+
governance: ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# UI-UX Design PromptContract
|
package/package.json
CHANGED
package/src/commands/execute.js
CHANGED
|
@@ -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.
|
package/src/core/templates.js
CHANGED
|
@@ -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
|
+
}
|