@williambeto/ai-workflow 2.2.7 → 2.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.3.0] - 2026-06-16
2
+
3
+ ### Added
4
+ - Isolated read-only workspace runner to prevent execution modifications from altering the original repository.
5
+ - Sage validation agent execution in full/deep task mode, logging events to the ledger and handling revalidation.
6
+ - Real OpenCode smoke test integration inside the `release:verify` suite.
7
+ - Scenario 17 in E2E tests verifying the complete multi-agent coordination loop (`Astra -> Sage -> Phoenix -> Sage`).
8
+
9
+ ### Fixed
10
+ - Sequential state transitions for read-only runs (`IMPLEMENTING -> IMPLEMENTED -> VALIDATING -> COMPLETED`).
11
+ - Snapshot comparison logic to correctly target `.snapshot.files` and compare `.sha256` properties.
12
+ - Bypassed physical writing of ledger histories and handoff markdown files during read-only executions.
13
+ - Injected mock OpenCode environment configuration inside `verify-packed-consumer.mjs` for autonomous sandbox runs.
14
+
1
15
  ## [2.0.5] - 2026-06-08
2
16
 
3
17
  ### Fixed
@@ -1,24 +1,52 @@
1
1
  # CLI reference
2
2
 
3
- ## `ai-workflow init`
3
+ ## `ai-workflow execute`
4
4
 
5
- Installs the OpenCode-first workflow assets into a consumer project.
5
+ Orchestrate execution of a natural request through the state machine.
6
6
 
7
- ## `ai-workflow doctor`
7
+ | Flag | Description |
8
+ | --- | --- |
9
+ | `--task=<slug>` | Optional custom task slug for the workflow execution. |
10
+ | `--request=<request>` | Positional or named natural language request. |
8
11
 
9
- Checks the local installation and generated configuration.
10
-
11
- ## `ai-workflow run --spec-path=<path>`
12
+ ## `ai-workflow run`
12
13
 
13
14
  Runs formal orchestration for an approved specification. It enforces branch safety, observed validation, bounded remediation, and handoff generation.
14
15
 
15
- ## `ai-workflow collect-evidence [--task=<slug>] [--mode=<quick|standard|full>] [--dry-run]`
16
+ | Flag | Description |
17
+ | --- | --- |
18
+ | `--spec-path=<path>` | Path to the approved specification file. |
19
+
20
+ ## `ai-workflow init`
21
+
22
+ Installs the OpenCode-first workflow assets into a consumer project.
23
+
24
+ | Flag | Description |
25
+ | --- | --- |
26
+ | `--yes` | Auto-approve all confirmations. |
27
+ | `--force` | Force overwrite existing files. |
28
+ | `--dry-run` | Print actions without applying changes. |
29
+ | `--no-install` | Skip installing dependencies. |
30
+ | `--no-overwrite` | Do not overwrite existing files. |
31
+ | `--gemini` | Install Gemini-specific configurations. |
32
+ | `--claude` | Install Claude-specific configurations. |
33
+ | `--codex` | Install Codex-specific configurations. |
34
+ | `--antigravity` | Install Antigravity-specific configurations. |
35
+ | `--profile=<profile>` | Specify installation profile (e.g. `standard`, `full`). |
36
+
37
+ ## `ai-workflow collect-evidence`
16
38
 
17
39
  Runs relevant project validation scripts and objective quality checks.
18
40
 
19
- - quick/standard: prints a concise delivery summary and does not require `EVIDENCE.json`;
20
- - full: persists `EVIDENCE.json` unless `--dry-run` is used;
21
- - failed or unavailable required validation returns `BLOCKED`.
41
+ | Flag | Description |
42
+ | --- | --- |
43
+ | `--task=<slug>` | Optional task slug to target. |
44
+ | `--mode=<mode>` | Validation mode (`quick`, `standard`, `full`). |
45
+ | `--dry-run` | Run checks without writing `EVIDENCE.json`. |
46
+
47
+ ## `ai-workflow doctor`
48
+
49
+ Checks the local installation and generated configuration.
22
50
 
23
51
  ## Public states
24
52
 
@@ -0,0 +1,35 @@
1
+ # AI Workflow Kit 2.3.0 Release Decision
2
+
3
+ **Status:** Finalized
4
+ **npm publish:** Pending (Awaiting user authorization)
5
+ **Published dist-tag:** `latest`
6
+
7
+ ## Identity
8
+
9
+ - **Package:** `@williambeto/ai-workflow`
10
+ - **Version:** `2.3.0`
11
+ - **Commit:** `c16d06889ed4957840b69d61df43063908c3b220`
12
+ - **Tarball SHA256:** `24b1cb412bb4503add8d8962568cdc5ea819e207e6dd0d0e3d0f9d8502c063ce`
13
+ - **Previous public line:** `2.2.7`
14
+
15
+ ## Validation evidence
16
+
17
+ - **Unit tests:** PASS — 142 tests passed
18
+ - **E2E tests:** PASS — 18 tests passed (including the new read-only safety validation and Sage/Phoenix/Astra loop verification)
19
+ - **Release-readiness validation:** PASS — 17 required files checked
20
+ - **Full validation:** PASS — 18/18 checks completed successfully (JSON, Cross-reference, Artifact safety, External link, Documentation consistency, Workflow state, Schema, Skill, Canonical policy reference, Privacy publication gate, UI evidence gate, Delegation, Behavioral contract, Token economy, Upgrade regression, Visual regression, Release readiness, Repository structure)
21
+ - **Safe pack:** PASS — `@williambeto/ai-workflow@2.3.0`, 310 files, zero root-level tarballs left behind
22
+ - **Fresh consumer install:** PASS (verified via packed consumer runner in a sandbox)
23
+ - **CLI help/init/doctor:** PASS (verified via packed consumer runner in a sandbox)
24
+ - **Real OpenCode Smoke Test:** PASS (integrated directly into the release verification)
25
+ - **Open Blocker/High findings:** None
26
+
27
+ ## Accepted limitations
28
+
29
+ - See [known-limitations.md](../internal/known-limitations.md).
30
+
31
+ ## Decision
32
+
33
+ Decision finalized for version `2.3.0`. The release includes the isolated read-only workspace runner, corrected snapshot comparisons, bypassed physical files write during read-only executions, real OpenCode smoke test integration in release verification, and Sage validation agent coordination in full mode.
34
+
35
+ **Approved by:** José Willams (Human User)
package/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@williambeto/ai-workflow",
3
- "version": "2.2.7",
3
+ "version": "2.3.0",
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",
7
7
  "type": "module",
8
8
  "private": false,
9
+ "publishConfig": {
10
+ "access": "public",
11
+ "registry": "https://registry.npmjs.org/"
12
+ },
9
13
  "engines": {
10
14
  "node": ">=20.11"
11
15
  },
@@ -34,7 +38,9 @@
34
38
  "PUBLISH_MANIFEST.json",
35
39
  "README.md",
36
40
  "LICENSE",
37
- "CHANGELOG.md"
41
+ "CHANGELOG.md",
42
+ "read_only_safety_verification.md",
43
+ "docs/releases/v2.3.0-release-decision.md"
38
44
  ],
39
45
  "scripts": {
40
46
  "build": "node internal/validate/build-publish.mjs",
@@ -56,10 +62,14 @@
56
62
  "validate:cli-docs": "node internal/validate/validate-cli-docs.mjs",
57
63
  "lint:md": "markdownlint \"**/*.md\"",
58
64
  "validate:registry": "node internal/validate/validate-registry-integrity.mjs",
65
+ "clean:verify": "node -e \"const fs = require('fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.readdirSync('.').filter(f => f.endsWith('.tgz')).forEach(f => fs.rmSync(f, { force: true }));\"",
59
66
  "test": "npm run test:unit",
60
- "test:unit": "vitest run",
67
+ "test:unit": "vitest run tests/unit/",
61
68
  "test:watch": "vitest",
62
- "test:e2e": "node tests/validate-e2e.mjs",
69
+ "test:e2e": "node tests/validate-e2e.mjs && vitest run tests/e2e/consumer-workflow.test.js",
70
+ "test:e2e:runtime": "AI_WORKFLOW_RELEASE=1 vitest run tests/e2e/consumer-workflow.test.js -t \"Real OpenCode Smoke Test\"",
71
+ "release:verify": "npm run clean:verify && npm test && npm run test:e2e && npm run validate && npm run pack:verify && npm run test:e2e:runtime",
72
+ "pack:verify": "node tests/e2e/verify-packed-consumer.mjs",
63
73
  "pack:safe": "node internal/validate/pack-safe.mjs",
64
74
  "validate:behavioral-contracts": "node internal/validate/validate-behavioral-contracts.mjs",
65
75
  "validate:token-economy": "node internal/validate/validate-token-economy.mjs",
@@ -0,0 +1,48 @@
1
+ # Read-Only Safety, Sage Validation, and OpenCode Retest Verification Report
2
+
3
+ This report documents the resolution of all blocking items identified to reach the `PASS — publish ready` status.
4
+
5
+ ## 1. Summary of Resolved Items
6
+
7
+ ### State Machine Transition Correction
8
+ - Updated [execute.js](src/commands/execute.js) to transition the state machine sequentially through:
9
+ `IMPLEMENTING -> IMPLEMENTED -> VALIDATING -> COMPLETED`
10
+ instead of attempting a direct jump from `IMPLEMENTING` to `COMPLETED` during read-only runs.
11
+
12
+ ### Snapshot Comparison Bug Fix
13
+ - Corrected [compareReadOnlyState](src/commands/execute.js) to compare `.snapshot.files` rather than `.snapshot` directly.
14
+ - Standardized comparisons on `.sha256` instead of `.hash`.
15
+
16
+ ### Physical File Write Prevention
17
+ - Prevented physical file creation of handoff markdown files and execution ledgers inside the repository when running under a read-only request.
18
+ - Moved the final ledger logs and handoffs into memory and routed them to `stdout`.
19
+ - Declared the block-scoped `plan` variable outside the `try` block so it is properly evaluated in the `finally` block of `runExecute` to suppress file saving.
20
+
21
+ ### E2E Test Suite Enhancements
22
+ - Added a new E2E test case `16. Read-only válido -> COMPLETED; sem mutações, nenhum handoff ou ledger gravado` inside [consumer-workflow.test.js](tests/e2e/consumer-workflow.test.js) asserting that a valid read-only execution maintains branch, HEAD, and files identically while leaving the `.ai-workflow/` history and handoff directories empty.
23
+ - Injected a local controlled OpenCode mock in [verify-packed-consumer.mjs](tests/e2e/verify-packed-consumer.mjs) before running doctor checks, removing dependencies on host/CI global executables.
24
+
25
+ ### Integration of Real OpenCode Smoke Test
26
+ - Updated `package.json` to link the real OpenCode smoke test (`test:e2e:runtime` with `AI_WORKFLOW_RELEASE=1`) directly into the final `release:verify` command.
27
+ - Verified that the smoke test runs and passes successfully on this host environment where the real `opencode` CLI is available.
28
+
29
+ ### Sage validation agent for full mode
30
+ - Modified [validate](src/core/delegation-controller.js) in the delegation controller to execute validation via the `Sage` agent when the task mode is `"full"`.
31
+ - Added unit tests in [delegation-ledger.test.js](tests/unit/delegation-ledger.test.js) to assert that Sage events (`validation_start`, `validation_complete`) are logged.
32
+ - Mocked Sage agent capabilities in the E2E framework ([fake-opencode.js](tests/e2e/helpers/fake-opencode.js)) to support a fail-once revalidation scenario.
33
+ - Created E2E test case `17. Alto risco / Full -> Astra e Sage executados; com finding, Phoenix e Sage revalidação` to prove the full multi-agent loop:
34
+ `Astra -> Sage -> Phoenix -> Sage`
35
+
36
+ ---
37
+
38
+ ## 2. Verification Evidence
39
+
40
+ All consolidated validation checks run and exit with code `0`.
41
+
42
+ | Test Run | Command | Result | Details |
43
+ | --- | --- | --- | --- |
44
+ | **Unit Tests** | `npm run test:unit` | **PASS (142/142)** | All unit tests completed successfully (including the new Sage validation event logging) |
45
+ | **E2E Tests** | `npm run test:e2e` | **PASS (18/18)** | All E2E test cases pass successfully, including the new read-only safety validation (16) and multi-agent coordination (17) |
46
+ | **All Gates** | `npm run validate` | **PASS (18/18)** | 18 validation checks completed successfully |
47
+ | **Packaging** | `npm run pack:verify` | **PASS** | Doctor and Init runs successfully verified against packed tarball |
48
+ | **Integrity** | `npm run release:verify` | **PASS (Exit 0)** | Consolidated clean, test, e2e, validate, pack:verify, and real OpenCode smoke tests |
package/src/cli.js CHANGED
@@ -74,12 +74,14 @@ export async function runCli(args) {
74
74
  const flags = parseFlags(args.slice(1));
75
75
  const positionals = args.slice(1).filter((arg) => !arg.startsWith("-"));
76
76
  const request = flags.request || positionals.join(" ");
77
- await runExecute({
77
+ const result = await runExecute({
78
78
  cwd: process.cwd(),
79
79
  naturalRequest: request,
80
- override: args.includes("--override") ? "authorized-override-token" : undefined,
81
80
  taskSlug: flags.taskSlug
82
81
  });
82
+ if (result && (result.overallStatus === "FAIL_QUALITY_GATE" || result.overallStatus === "BLOCKED" || result.overallStatus === "FAIL")) {
83
+ process.exit(1);
84
+ }
83
85
  return;
84
86
  }
85
87
 
@@ -1,50 +1,14 @@
1
1
  import { EvidenceCollector } from "../core/validation/evidence-collector.js";
2
2
  import { QualityGuard } from "../core/validation/quality-guard.js";
3
+ import { ValidationPlanner } from "../core/validation/validation-planner.js";
3
4
  import { buildDeliverySummary, formatDeliverySummary } from "../core/validation/canonical-finalization.js";
4
5
  import fs from "node:fs/promises";
5
6
  import path from "node:path";
6
7
 
7
- function isNoOpScript(script = "") {
8
- const value = String(script).trim().toLowerCase();
9
- return /^(echo\b|true$|exit\s+0$|node\s+-e\s+["']?console\.log)/.test(value) || value.includes("tests-pass");
10
- }
11
-
12
- function addScriptTask(tasks, scripts, name, command, { rejectNoOp = false } = {}) {
13
- const script = scripts[name];
14
- if (!script) return;
15
- if (!rejectNoOp && name === "test" && isNoOpScript(script)) return;
16
- if (rejectNoOp && isNoOpScript(script)) {
17
- tasks.push({ name, command, kind: name === "test" ? "test" : name, presetStatus: "FAIL_QUALITY_GATE", summary: `Configured ${name} script is a no-op: ${script}` });
18
- return;
19
- }
20
- tasks.push({ name, command, kind: name === "test" ? "test" : name });
21
- }
22
-
23
- function isManagedValidationPath(file = "") {
24
- return /(^|\/)(node_modules|vendor|dist|coverage|\.cache)(\/|$)/.test(String(file).replaceAll("\\", "/"));
25
- }
26
-
27
8
  export async function runCollectEvidence({ cwd, exitOnError = true, taskSlug = null, mode = null, dryRun = false, profile = "generic", branchRecovery = "NOT_RECORDED" }) {
28
- const tasks = [];
29
9
  const qualityGuard = new QualityGuard({ cwd, taskSlug, mode });
30
- try {
31
- const pkg = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf8"));
32
- const scripts = pkg.scripts || {};
33
- const executableBehavior = await qualityGuard.hasExecutableBehaviorChanges();
34
- addScriptTask(tasks, scripts, "lint", "npm run lint");
35
- addScriptTask(tasks, scripts, "test", "npm test", { rejectNoOp: executableBehavior });
36
- addScriptTask(tasks, scripts, "build", "npm run build");
37
- addScriptTask(tasks, scripts, "typecheck", "npm run typecheck");
38
- if (scripts.validate && !String(scripts.validate).includes("ai-workflow collect-evidence")) addScriptTask(tasks, scripts, "validate", "npm run validate");
39
-
40
- const changed = qualityGuard.getChangedFiles().filter((file) => !isManagedValidationPath(file));
41
- const hasTs = changed.some((file) => /\.(ts|tsx)$/.test(file)) || await fs.access(path.join(cwd, "tsconfig.json")).then(() => true).catch(() => false);
42
- if (hasTs && !scripts.typecheck) {
43
- tasks.push({ name: "typecheck", command: "npm run typecheck", kind: "typecheck", presetStatus: "FAIL_QUALITY_GATE", summary: "TypeScript detected but no typecheck script is configured." });
44
- }
45
- } catch {
46
- // Non-Node projects can still supply validation through project-specific commands.
47
- }
10
+ const planner = new ValidationPlanner({ cwd, qualityGuard });
11
+ const tasks = await planner.plan(profile);
48
12
 
49
13
  const persist = !dryRun && mode === "full";
50
14
  const collector = new EvidenceCollector({ cwd, timeout: 60000, taskSlug, mode, profile, branchRecovery });
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { exists, readJson, readJsonc } from "../core/filesystem.js";
4
+ import { OpenCodeAdapter } from "../core/runtime/opencode-adapter.js";
4
5
 
5
6
  const REQUIRED_FILES = [
6
7
  ".ai-workflow",
@@ -23,6 +24,21 @@ export async function runDoctor({ cwd }) {
23
24
 
24
25
  console.log("Doctor report:");
25
26
 
27
+ // Check OpenCode runtime
28
+ const adapter = new OpenCodeAdapter({ cwd });
29
+ const inspection = await adapter.inspect();
30
+ if (inspection.available) {
31
+ console.log("PASS opencode CLI is available");
32
+ const supportedStr = Object.entries(inspection.supports)
33
+ .filter(([_, v]) => v)
34
+ .map(([k, _]) => k)
35
+ .join(", ");
36
+ console.log(`PASS opencode capabilities detected: ${supportedStr || "none"}`);
37
+ } else {
38
+ hasFailure = true;
39
+ console.log("FAIL opencode CLI is not installed or not available in PATH");
40
+ }
41
+
26
42
  for (const relativePath of REQUIRED_FILES) {
27
43
  const ok = await exists(path.join(cwd, relativePath));
28
44