@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.
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williambeto/ai-workflow",
3
- "version": "2.3.2",
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",
@@ -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
+ }