@williambeto/ai-workflow 2.4.8 → 2.6.3

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 (122) hide show
  1. package/bin/ai-workflow.d.ts +3 -0
  2. package/bin/ai-workflow.js +2669 -1
  3. package/bin/ai-workflow.js.map +1 -0
  4. package/chunk-2AOV2ATY.js +749 -0
  5. package/chunk-5WRI5ZAA.js +31 -0
  6. package/chunk-6EMG6FAO.js +734 -0
  7. package/chunk-UHLZX2EG.js +1827 -0
  8. package/core/index.d.ts +440 -0
  9. package/core/index.js +32 -0
  10. package/core/index.js.map +1 -0
  11. package/dist-assets/AGENTS.md +23 -6
  12. package/dist-assets/agents/atlas.md +8 -8
  13. package/dist-assets/agents/nexus.md +4 -4
  14. package/dist-assets/agents/orion.md +1 -1
  15. package/dist-assets/agents/phoenix.md +1 -1
  16. package/dist-assets/agents/sage.md +1 -1
  17. package/dist-assets/commands/implement.md +1 -1
  18. package/dist-assets/docs/QUICKSTART.md +8 -8
  19. package/dist-assets/docs/cli-reference.md +7 -7
  20. package/dist-assets/docs/compatibility/provider-usage.md +1 -9
  21. package/dist-assets/docs/compatibility/runtime-matrix.md +5 -6
  22. package/dist-assets/docs/consumer-onboarding.md +2 -2
  23. package/dist-assets/docs/design-patterns-policy.md +1 -1
  24. package/dist-assets/docs/full-documentation.md +0 -2
  25. package/dist-assets/docs/npm-consumer-quickstart.md +70 -109
  26. package/dist-assets/docs/policies/01-BRANCH_GATE.md +1 -1
  27. package/dist-assets/docs/policies/06-FINAL_EVIDENCE_CONTRACT.md +2 -2
  28. package/dist-assets/docs/policies/08-PRODUCT_TRUTHFULNESS_AND_PROJECT_DOCS.md +1 -1
  29. package/dist-assets/docs/policies/10-BEHAVIORAL_CONTRACT_HARDENING.md +1 -1
  30. package/dist-assets/docs/policies/ORCHESTRATION_PROTOCOL.md +8 -9
  31. package/dist-assets/docs/policies/PROCEDURE_DELIVERY_ARTIFACTS.md +4 -10
  32. package/dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md +1 -1
  33. package/dist-assets/docs/profiles/README.md +2 -2
  34. package/dist-assets/docs/specs/runtime-operational-contract.md +12 -12
  35. package/dist-assets/docs/troubleshooting-guide.md +2 -2
  36. package/dist-assets/docs/visual-validation-guide.md +65 -3
  37. package/dist-assets/prompts/01-create-requirement.md +2 -2
  38. package/dist-assets/prompts/02-create-spec.md +2 -2
  39. package/dist-assets/prompts/03-create-tech-plan.md +4 -4
  40. package/dist-assets/prompts/04-breakdown-prs.md +4 -4
  41. package/dist-assets/prompts/05-implement-pr.md +5 -5
  42. package/dist-assets/prompts/06-review-and-fix.md +3 -3
  43. package/dist-assets/prompts/07-apply-design.md +2 -2
  44. package/dist-assets/prompts/08-validate.md +5 -5
  45. package/dist-assets/prompts/09-deploy.md +5 -5
  46. package/dist-assets/prompts/commands/implement.md +1 -1
  47. package/dist-assets/prompts/commands/tech-plan.md +2 -2
  48. package/dist-assets/prompts/commands/validate.md +2 -2
  49. package/dist-assets/runbooks/deploy-checklist.md +5 -5
  50. package/dist-assets/runbooks/how-to-use-skills.md +10 -0
  51. package/dist-assets/runbooks/validation-checklist.md +5 -5
  52. package/dist-assets/schemas/evidence.schema.json +109 -0
  53. package/dist-assets/templates/ANTIGRAVITY.md.template +7 -5
  54. package/dist-assets/templates/CLAUDE.md.template +7 -5
  55. package/dist-assets/templates/CODEX.md.template +7 -5
  56. package/evidence-validator-76ZQQYDU.js +6661 -0
  57. package/package.json +7 -65
  58. package/{src/core/workspace/read-only-workspace.js → read-only-workspace-PZBE7KAX.js} +14 -31
  59. package/{src/commands/validate.js → validate-Q2NLLQ5G.js} +30 -22
  60. package/AGENTS.md +0 -34
  61. package/CHANGELOG.md +0 -237
  62. package/LICENSE +0 -21
  63. package/PUBLISH_MANIFEST.json +0 -34
  64. package/README.md +0 -129
  65. package/dist-assets/runbooks/use-linear-for-operational-planning.md +0 -45
  66. package/dist-assets/runbooks/use-napkin-project-memory.md +0 -33
  67. package/dist-assets/templates/.geminiignore.template +0 -8
  68. package/dist-assets/templates/GEMINI.md.template +0 -20
  69. package/docs/compatibility/provider-usage.md +0 -46
  70. package/docs/compatibility/runtime-matrix.md +0 -31
  71. package/docs/getting-started/DESKTOP_PROMPT.md +0 -52
  72. package/docs/getting-started/quickstart.md +0 -117
  73. package/docs/getting-started/troubleshooting.md +0 -123
  74. package/docs/getting-started/upgrading-to-v2.md +0 -62
  75. package/read_only_safety_verification.md +0 -48
  76. package/src/adapters/index.js +0 -4
  77. package/src/adapters/platforms/antigravity.js +0 -382
  78. package/src/adapters/platforms/claude.js +0 -126
  79. package/src/adapters/platforms/codex.js +0 -113
  80. package/src/adapters/platforms/gemini.js +0 -245
  81. package/src/cli.js +0 -155
  82. package/src/commands/clean.js +0 -106
  83. package/src/commands/collect-evidence.js +0 -25
  84. package/src/commands/doctor.js +0 -202
  85. package/src/commands/execute.js +0 -382
  86. package/src/commands/init.js +0 -359
  87. package/src/commands/run.js +0 -112
  88. package/src/core/backup.js +0 -65
  89. package/src/core/completion-contract.js +0 -35
  90. package/src/core/delegation-controller.js +0 -193
  91. package/src/core/evidence/evidence-ledger.js +0 -98
  92. package/src/core/execution-planner.js +0 -62
  93. package/src/core/filesystem.js +0 -141
  94. package/src/core/finalization/finalizer.js +0 -165
  95. package/src/core/finalization/workspace-snapshot.js +0 -110
  96. package/src/core/gates/branch-gate.js +0 -134
  97. package/src/core/gates/merge-gate.js +0 -74
  98. package/src/core/handoff/handoff-engine.js +0 -104
  99. package/src/core/healing/cli-remediation-executor.js +0 -153
  100. package/src/core/healing/healer-engine.js +0 -212
  101. package/src/core/healing/runtime-remediation-executor.js +0 -136
  102. package/src/core/identity.js +0 -43
  103. package/src/core/install-plan.js +0 -34
  104. package/src/core/opencode-merge.js +0 -150
  105. package/src/core/package-assets.js +0 -141
  106. package/src/core/request-classifier.js +0 -73
  107. package/src/core/request-router.js +0 -289
  108. package/src/core/runtime/opencode-adapter.js +0 -202
  109. package/src/core/sdd/validator.js +0 -67
  110. package/src/core/statuses.js +0 -29
  111. package/src/core/symlink-layout.js +0 -93
  112. package/src/core/templates.js +0 -229
  113. package/src/core/validation/artifact-fidelity-gate.js +0 -445
  114. package/src/core/validation/canonical-finalization.js +0 -43
  115. package/src/core/validation/delivery-decision-engine.js +0 -344
  116. package/src/core/validation/evidence-collector.js +0 -245
  117. package/src/core/validation/quality-guard.js +0 -251
  118. package/src/core/validation/stack-detector.js +0 -65
  119. package/src/core/validation/validation-planner.js +0 -134
  120. package/src/core/validation/visual-verifier.js +0 -175
  121. package/src/core/workflow-profiles.js +0 -107
  122. package/src/core/workflow-state-machine.js +0 -46
@@ -1,202 +0,0 @@
1
- import { spawn, spawnSync } from "node:child_process";
2
- import readline from "node:readline";
3
-
4
- /**
5
- * OpenCodeAdapter - Real runtime integration with the OpenCode CLI.
6
- */
7
- export class OpenCodeAdapter {
8
- constructor({ cwd = process.cwd() } = {}) {
9
- this.cwd = cwd;
10
- }
11
-
12
- /**
13
- * Inspects the availability and capability of the OpenCode CLI.
14
- * @returns {Promise<{available: boolean, supports: {run: boolean, formatJson: boolean, agent: boolean, model: boolean}}>}
15
- */
16
- async inspect() {
17
- try {
18
- const cliHelp = spawnSync("opencode", ["--help"], { encoding: "utf8" });
19
- const runHelp = spawnSync("opencode", ["run", "--help"], { encoding: "utf8" });
20
-
21
- const available = cliHelp.status === 0 && runHelp.status === 0;
22
- if (!available) {
23
- return {
24
- available: false,
25
- supports: { run: false, formatJson: false, agent: false, model: false }
26
- };
27
- }
28
-
29
- return {
30
- available: true,
31
- supports: {
32
- run: /\brun\b/.test(cliHelp.stdout),
33
- formatJson: /--format/.test(runHelp.stdout),
34
- agent: /--agent/.test(runHelp.stdout),
35
- model: /--model/.test(runHelp.stdout),
36
- }
37
- };
38
- } catch {
39
- return {
40
- available: false,
41
- supports: { run: false, formatJson: false, agent: false, model: false }
42
- };
43
- }
44
- }
45
-
46
- /**
47
- * Runs opencode with a prompt and options.
48
- * @param {string} message - The message prompt.
49
- * @param {Object} options - CLI options (e.g. agent, model, readOnly).
50
- * @returns {Promise<{success: boolean, commandsRun: string[], eventCount: number, error?: string}>}
51
- */
52
- async execute(message, { agent = null, model = null, readOnly = false } = {}) {
53
- const inspection = await this.inspect();
54
- const isSpecializedAgent = agent && ["Nexus", "Orion", "Astra", "Sage", "Phoenix"].includes(agent);
55
-
56
- if (!inspection.available) {
57
- return {
58
- success: false,
59
- status: isSpecializedAgent ? "BLOCKED" : "FAILED",
60
- commandsRun: [],
61
- eventCount: 0,
62
- error: "OpenCode CLI is not installed or not available in the system PATH.",
63
- runtimeAgentRequested: agent || null,
64
- runtimeAgentApplied: null,
65
- runtimeAgentSupported: false,
66
- runtimeAgentSelectionMode: isSpecializedAgent ? "explicit" : "default"
67
- };
68
- }
69
-
70
- if (isSpecializedAgent && !inspection.supports.agent) {
71
- return {
72
- success: false,
73
- status: "BLOCKED",
74
- error: `Requested runtime actor '${agent}' cannot be applied because this OpenCode runtime does not support --agent.`,
75
- runtimeAgentRequested: agent,
76
- runtimeAgentApplied: null,
77
- runtimeAgentSupported: false,
78
- runtimeAgentSelectionMode: "unsupported",
79
- commandsRun: [],
80
- eventCount: 0
81
- };
82
- }
83
-
84
- const runInWorkspace = async (targetCwd) => {
85
- return new Promise((resolve) => {
86
- const args = ["run", message];
87
- if (inspection.supports.formatJson) {
88
- args.push("--format", "json");
89
- }
90
- if (isSpecializedAgent && inspection.supports.agent) {
91
- args.push("--agent", agent);
92
- }
93
- if (model && inspection.supports.model) {
94
- args.push("--model", model);
95
- }
96
-
97
- console.log(`[RUNTIME] Delegating to OpenCode: opencode ${args.map(a => a.includes(" ") ? `"${a}"` : a).join(" ")}`);
98
-
99
- const child = spawn("opencode", args, {
100
- cwd: targetCwd,
101
- stdio: ["ignore", "pipe", "inherit"] // Inherit stderr to show warnings directly
102
- });
103
-
104
- const rl = readline.createInterface({
105
- input: child.stdout,
106
- terminal: false
107
- });
108
-
109
- const commandsRun = [];
110
- let eventCount = 0;
111
-
112
- rl.on("line", (line) => {
113
- const trimmed = line.trim();
114
- if (!trimmed) return;
115
-
116
- try {
117
- const event = JSON.parse(trimmed);
118
- eventCount++;
119
-
120
- // 1. Stream agent output text in real-time to user
121
- if (event.type === "text" && event.part?.text) {
122
- process.stdout.write(event.part.text);
123
- }
124
-
125
- // 2. Capture tool executions/commands
126
- if (event.type === "step_start" && event.part?.toolCalls) {
127
- for (const call of event.part.toolCalls) {
128
- if (call.name === "run_command" && call.args?.CommandLine) {
129
- commandsRun.push(call.args.CommandLine);
130
- }
131
- if (readOnly) {
132
- const name = call.name || "";
133
- const isWriteTool = name.startsWith("write_") || name.includes("write") || name.includes("replace") || name.includes("edit") || name.includes("delete") || name.includes("remove");
134
- let isDestructiveGit = false;
135
- if (name === "run_command" && call.args?.CommandLine) {
136
- const cmd = call.args.CommandLine;
137
- const destPattern = /\b(git\s+(commit|add|push|merge|reset|rm|branch|checkout|switch|stash|init)|touch|rm|mkdir|cp|mv|chmod|chown|tee|sed|awk)\b|>>|>/;
138
- if (destPattern.test(cmd)) {
139
- isDestructiveGit = true;
140
- }
141
- }
142
- if (isWriteTool || isDestructiveGit) {
143
- console.error(`\n[SECURITY WARNING] Read-only execution blocked attempt to write/modify workspace: tool '${name}' or command detected.`);
144
- child.kill();
145
- resolve({
146
- success: false,
147
- commandsRun,
148
- eventCount,
149
- error: `Read-only confinement violation: tool '${name}' or command attempted write/modify operation during read-only task.`,
150
- runtimeAgentRequested: agent || null,
151
- runtimeAgentApplied: null,
152
- runtimeAgentSupported: inspection.supports.agent,
153
- runtimeAgentSelectionMode: isSpecializedAgent ? "explicit" : "default"
154
- });
155
- return;
156
- }
157
- }
158
- }
159
- }
160
- } catch {
161
- // If a line is not valid JSON (e.g. starting/finishing logs), print it directly
162
- console.log(trimmed);
163
- }
164
- });
165
-
166
- child.on("close", (code) => {
167
- console.log("\n[RUNTIME] OpenCode finished execution.");
168
- resolve({
169
- success: code === 0,
170
- commandsRun,
171
- eventCount,
172
- runtimeAgentRequested: agent || null,
173
- runtimeAgentApplied: isSpecializedAgent ? agent : null,
174
- runtimeAgentSupported: inspection.supports.agent,
175
- runtimeAgentSelectionMode: isSpecializedAgent ? "explicit" : "default"
176
- });
177
- });
178
-
179
- child.on("error", (err) => {
180
- console.error(`\n[RUNTIME] Failed to launch opencode: ${err.message}`);
181
- resolve({
182
- success: false,
183
- commandsRun,
184
- eventCount: 0,
185
- error: err.message,
186
- runtimeAgentRequested: agent || null,
187
- runtimeAgentApplied: null,
188
- runtimeAgentSupported: inspection.supports.agent,
189
- runtimeAgentSelectionMode: isSpecializedAgent ? "explicit" : "default"
190
- });
191
- });
192
- });
193
- };
194
-
195
- if (readOnly) {
196
- const { runInReadOnlyWorkspace } = await import("../workspace/read-only-workspace.js");
197
- return runInReadOnlyWorkspace(this.cwd, runInWorkspace);
198
- } else {
199
- return runInWorkspace(this.cwd);
200
- }
201
- }
202
- }
@@ -1,67 +0,0 @@
1
- import fs from "node:fs/promises";
2
-
3
- /**
4
- * SpecValidator - Enforces "No Spec, No Code" rule.
5
- * Validates existence, structure, and approval status of specifications.
6
- */
7
- export class SpecValidator {
8
- /**
9
- * Validates a specification file.
10
- * @param {string} filePath - Path to the .md specification file.
11
- * @returns {Promise<{valid: boolean, reason?: string, tier?: string}>}
12
- */
13
- async validate(filePath) {
14
- try {
15
- const content = await fs.readFile(filePath, "utf8");
16
-
17
- // Check for tiered tier identification
18
- let tier = "unknown";
19
- if (content.includes("[DEEP]")) tier = "deep";
20
- else if (content.includes("[STANDARD]")) tier = "standard";
21
- else if (content.includes("[TINY]")) tier = "tiny";
22
-
23
- if (tier === "unknown") {
24
- return { valid: false, reason: "Specification tier [DEEP|STANDARD|TINY] not identified in title." };
25
- }
26
-
27
- // Check for Metadata section
28
- if (!content.includes("## Metadata")) {
29
- return { valid: false, reason: "Missing '## Metadata' section.", tier };
30
- }
31
-
32
- // Check for Acceptance Criteria section
33
- if (!content.includes("## Acceptance Criteria")) {
34
- return { valid: false, reason: "Missing '## Acceptance Criteria' section.", tier };
35
- }
36
-
37
- // Check for Approved status
38
- const lines = content.split("\n");
39
- const statusLine = lines.find(l => l.includes("Status:"));
40
-
41
- if (!statusLine) {
42
- return { valid: false, reason: "Missing Status field in Metadata section.", tier };
43
- }
44
-
45
- const statusPart = statusLine.split(":")[1]
46
- .replace(/[\*_]/g, "") // Remove bold/italic markers
47
- .trim()
48
- .toUpperCase();
49
-
50
- // If it contains multiple options separated by |, it's not approved yet
51
- if (statusPart.includes("|")) {
52
- return { valid: false, reason: "Specification status is a template list. Must be explicitly set to 'APPROVED'.", tier };
53
- }
54
-
55
- if (statusPart !== "APPROVED") {
56
- return { valid: false, reason: `Specification status is '${statusPart}', but must be 'APPROVED' to proceed.`, tier };
57
- }
58
-
59
- return { valid: true, tier };
60
- } catch (error) {
61
- if (error.code === "ENOENT") {
62
- return { valid: false, reason: `Specification file not found: ${filePath}` };
63
- }
64
- return { valid: false, reason: `Error reading specification: ${error.message}` };
65
- }
66
- }
67
- }
@@ -1,29 +0,0 @@
1
- export const COMPLETION_STATUSES = Object.freeze([
2
- "PASS",
3
- "PASS_WITH_NOTES",
4
- "FAIL_DELEGATION_GATE",
5
- "FAIL_QUALITY_GATE",
6
- "FAIL",
7
- "BLOCKED",
8
- "NOT_RUN"
9
- ]);
10
-
11
- export const RECOVERABLE_GATE_STATUSES = Object.freeze([
12
- "FAIL_DELEGATION_GATE",
13
- "FAIL_QUALITY_GATE"
14
- ]);
15
-
16
- export const TERMINAL_FAILURE_STATUSES = Object.freeze([
17
- "FAIL",
18
- "BLOCKED"
19
- ]);
20
-
21
- export function isRecoverableGateFailure(status) {
22
- return RECOVERABLE_GATE_STATUSES.includes(status);
23
- }
24
-
25
- export function isTerminalFailure(status) {
26
- return TERMINAL_FAILURE_STATUSES.includes(status);
27
- }
28
-
29
- export const COMPLETION_STATUS_TEXT = COMPLETION_STATUSES.join(" | ");
@@ -1,93 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
-
4
- function normalize(p) {
5
- return p.split(path.sep).join("/");
6
- }
7
-
8
- /**
9
- * For v3.0.0 "Elite Governance", we want an ULTRA-CLEAN root.
10
- * Only "opencode" is symlinked to the root (required for OpenCode discovery).
11
- * All other assets stay inside .ai-workflow/.
12
- */
13
- const LINKABLE_ROOTS = new Set([
14
- "opencode",
15
- ".agents"
16
- ]);
17
-
18
- const LINKABLE_FILES = new Set([]);
19
-
20
- export function buildSymlinkEntries({ templateFiles, installRoot = ".ai-workflow" }) {
21
- const entries = new Map();
22
-
23
- for (const relativePath of Object.keys(templateFiles)) {
24
- if (relativePath === "opencode.jsonc") continue;
25
-
26
- const normalized = normalize(relativePath);
27
-
28
- if (LINKABLE_FILES.has(normalized)) {
29
- entries.set(normalized, `${installRoot}/${normalized}`);
30
- continue;
31
- }
32
-
33
- // Match composite paths in LINKABLE_ROOTS (e.g., "docs/policies")
34
- for (const rootPath of LINKABLE_ROOTS) {
35
- if (normalized === rootPath || normalized.startsWith(`${rootPath}/`)) {
36
- entries.set(rootPath, `${installRoot}/${rootPath}`);
37
- break;
38
- }
39
- }
40
- }
41
-
42
- return Array.from(entries.entries()).map(([linkPath, targetPath]) => ({ linkPath, targetPath }));
43
- }
44
-
45
- export async function isSymlinkTo(absoluteLinkPath, absoluteTargetPath) {
46
- try {
47
- const stat = await fs.lstat(absoluteLinkPath);
48
- if (!stat.isSymbolicLink()) return false;
49
- const currentTarget = await fs.readlink(absoluteLinkPath);
50
- const resolved = path.resolve(path.dirname(absoluteLinkPath), currentTarget);
51
- return resolved === absoluteTargetPath;
52
- } catch {
53
- return false;
54
- }
55
- }
56
-
57
- /**
58
- * Internal symlink to satisfy opencode.jsonc paths without polluting the root.
59
- * Creates .ai-workflow/opencode/skills -> ../.agents/skills
60
- */
61
- export async function setupInternalSymlinks(cwd, installRoot = ".ai-workflow") {
62
- const skillsLink = path.join(cwd, installRoot, "opencode/skills");
63
- const skillsTarget = path.join(cwd, installRoot, ".agents/skills");
64
-
65
- if (!(await exists(skillsTarget))) return;
66
-
67
- try {
68
- const stat = await fs.lstat(skillsLink).catch(() => null);
69
- if (stat) {
70
- if (stat.isSymbolicLink()) {
71
- const current = await fs.readlink(skillsLink);
72
- if (current === "../.agents/skills") return;
73
- await fs.unlink(skillsLink);
74
- } else {
75
- return; // File exists, skip
76
- }
77
- }
78
-
79
- const type = process.platform === "win32" ? "junction" : "dir";
80
- await fs.symlink("../.agents/skills", skillsLink, type);
81
- } catch {
82
- // Silent fail for internal symlink
83
- }
84
- }
85
-
86
- async function exists(p) {
87
- try {
88
- await fs.access(p);
89
- return true;
90
- } catch {
91
- return false;
92
- }
93
- }
@@ -1,229 +0,0 @@
1
- import { getFullAgentContent, getFullSkillFiles, discoverPackageFiles, readPackageFile, getPackageVersion } from "./package-assets.js";
2
- import { getCanonicalAgentName } from "./identity.js";
3
-
4
- const COMMON_FILES = {
5
- "opencode/README.md": `# OpenCode Setup\n\nThis directory is managed by \`ai-workflow\` init.\nAdd agent and command files required by your project workflow.\n`
6
- };
7
-
8
- const FULL_PRIMARY_AGENTS = [
9
- "atlas",
10
- "nexus",
11
- "orion",
12
- "astra",
13
- "sage",
14
- "phoenix"
15
- ];
16
-
17
- const FULL_SKILLS = [
18
- "project-memory",
19
- "optimize-tokens",
20
- "documentation",
21
- "architecture",
22
- "technical-leadership",
23
- "product-discovery",
24
- "product-planning",
25
- "spec-driven-development",
26
- "pr-workflow",
27
- "qa-workflow",
28
- "release-workflow",
29
- "deployment",
30
- "ui-ux-design",
31
- "design-principles",
32
- "frontend-development",
33
- "backend-development",
34
- "full-stack-development",
35
- "refactoring",
36
- "prompt-engineer"
37
- ];
38
-
39
- const KIT_VERSION = getPackageVersion() ?? "unknown";
40
-
41
- function buildRuntimeFiles({ includeFormalEvidence = false } = {}) {
42
- const files = {};
43
-
44
- for (const agent of FULL_PRIMARY_AGENTS) {
45
- const content = getFullAgentContent(agent);
46
- if (content === null) {
47
- throw new Error(`CRITICAL FAILURE: Missing required agent asset: dist-assets/agents/${agent}.md`);
48
- }
49
- files[`opencode/agents/${agent}.md`] = content;
50
- }
51
-
52
- for (const skill of FULL_SKILLS) {
53
- const skillFiles = getFullSkillFiles(skill);
54
- if (Object.keys(skillFiles).length === 0) {
55
- continue;
56
- }
57
- for (const [relPath, content] of Object.entries(skillFiles)) {
58
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
59
- if (!files[targetPath]) {
60
- files[targetPath] = content;
61
- }
62
- }
63
- }
64
-
65
- // Copy governance policy into opencode/docs/policies/ so the relative link
66
- // ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md resolves correctly from
67
- // opencode/skills/{skill}/SKILL.md for OpenCode and all platform adapters.
68
- const opencodeGovernancePolicy = readPackageFile("dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md");
69
- if (opencodeGovernancePolicy !== null) {
70
- files["opencode/docs/policies/SKILLS_COMMON_GOVERNANCE.md"] = opencodeGovernancePolicy;
71
- }
72
-
73
- const commandFiles = discoverPackageFiles("dist-assets/commands");
74
- for (const [relPath, content] of Object.entries(commandFiles)) {
75
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
76
- if (!files[targetPath]) {
77
- files[targetPath] = content;
78
- }
79
- }
80
-
81
- const opencodeSkillFiles = discoverPackageFiles("dist-assets/skills");
82
- for (const [relPath, content] of Object.entries(opencodeSkillFiles)) {
83
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
84
- if (!files[targetPath]) {
85
- files[targetPath] = content;
86
- }
87
- }
88
-
89
- const harnessWorkflowFiles = discoverPackageFiles("dist-assets/harness/workflows");
90
- for (const [relPath, content] of Object.entries(harnessWorkflowFiles)) {
91
- const targetPath = relPath.replace(/^dist-assets\//, "");
92
- files[targetPath] = content;
93
- }
94
-
95
- const harnessHandoffFiles = discoverPackageFiles("dist-assets/harness/handoffs");
96
- for (const [relPath, content] of Object.entries(harnessHandoffFiles)) {
97
- const targetPath = relPath.replace(/^dist-assets\//, "");
98
- files[targetPath] = content;
99
- }
100
-
101
- const agentsContent = readPackageFile("dist-assets/AGENTS.md");
102
- if (agentsContent !== null) files["AGENTS.md"] = agentsContent;
103
-
104
- const consumerQuickstart = readPackageFile("dist-assets/docs/QUICKSTART.md");
105
- if (consumerQuickstart !== null) files["QUICKSTART.md"] = consumerQuickstart;
106
-
107
- const policyContent = readPackageFile("dist-assets/docs/architecture-policy.md");
108
- if (policyContent !== null) files["opencode/docs/architecture-policy.md"] = policyContent;
109
-
110
- const dpContent = readPackageFile("dist-assets/docs/design-patterns-policy.md");
111
- if (dpContent !== null) files["opencode/docs/design-patterns-policy.md"] = dpContent;
112
-
113
- const visualValidationGuide = readPackageFile("dist-assets/docs/visual-validation-guide.md");
114
- if (visualValidationGuide !== null) files["opencode/docs/visual-validation-guide.md"] = visualValidationGuide;
115
-
116
- const governancePolicies = discoverPackageFiles("dist-assets/docs/policies");
117
- for (const [relPath, content] of Object.entries(governancePolicies)) {
118
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
119
- files[targetPath] = content;
120
- }
121
-
122
- const compatibilityDocs = discoverPackageFiles("dist-assets/docs/compatibility");
123
- for (const [relPath, content] of Object.entries(compatibilityDocs)) {
124
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
125
- files[targetPath] = content;
126
- }
127
-
128
- const qualityReferenceFiles = discoverPackageFiles("dist-assets/docs/references");
129
- for (const [relPath, content] of Object.entries(qualityReferenceFiles)) {
130
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
131
- files[targetPath] = content;
132
- }
133
-
134
- const workflowProfileFiles = discoverPackageFiles("dist-assets/docs/profiles");
135
- for (const [relPath, content] of Object.entries(workflowProfileFiles)) {
136
- const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
137
- files[targetPath] = content;
138
- }
139
-
140
- const templateFiles = discoverPackageFiles("dist-assets/templates");
141
- for (const [relPath, content] of Object.entries(templateFiles)) {
142
- if (!includeFormalEvidence && relPath.includes("/owner-evidence/")) continue;
143
- const targetPath = relPath.replace(/^dist-assets\//, "");
144
- files[targetPath] = content;
145
- }
146
-
147
- const schemaFiles = discoverPackageFiles("dist-assets/schemas");
148
- for (const [relPath, content] of Object.entries(schemaFiles)) {
149
- const targetPath = relPath.replace(/^dist-assets\//, "");
150
- files[targetPath] = content;
151
- }
152
-
153
- return files;
154
- }
155
-
156
- function buildExtraFiles() {
157
- const files = {};
158
- const exampleFiles = discoverPackageFiles("dist-assets/examples");
159
- for (const [relPath, content] of Object.entries(exampleFiles)) {
160
- const targetPath = relPath.replace(/^dist-assets\//, "");
161
- files[targetPath] = content;
162
- }
163
- return files;
164
- }
165
-
166
- const STANDARD_FILES = buildRuntimeFiles();
167
- const FULL_FILES = { ...buildRuntimeFiles({ includeFormalEvidence: true }), ...buildExtraFiles() };
168
-
169
- export const PROFILE_FILES = {
170
- standard: {
171
- ...COMMON_FILES,
172
- ...STANDARD_FILES
173
- },
174
- full: {
175
- ...COMMON_FILES,
176
- ...FULL_FILES
177
- }
178
- };
179
-
180
- export function isValidProfile(profile) {
181
- return profile === "standard" || profile === "full";
182
- }
183
-
184
- export function getTemplateFiles(profile = "standard") {
185
- return PROFILE_FILES[profile] ?? PROFILE_FILES.standard;
186
- }
187
-
188
- export function getManagedBlocks() {
189
- return [
190
- ...FULL_PRIMARY_AGENTS.map((agent) => `opencode.jsonc:agent.${getCanonicalAgentName(agent)}`),
191
- ...FULL_SKILLS.map((skill) => `opencode.jsonc:agent.${getCanonicalAgentName(skill)}`),
192
- "opencode.jsonc:command.atlas",
193
- "opencode.jsonc:command.run",
194
- "opencode.jsonc:command.discover",
195
- "opencode.jsonc:command.spec-create",
196
- "opencode.jsonc:command.spec-review",
197
- "opencode.jsonc:command.spec-implement",
198
- "opencode.jsonc:command.plan",
199
- "opencode.jsonc:command.implement",
200
- "opencode.jsonc:command.validate",
201
- "opencode.jsonc:command.audit",
202
- "opencode.jsonc:command.optimize-tokens",
203
- "opencode.jsonc:command.update-memory",
204
- "opencode.jsonc:command.release",
205
- "opencode.jsonc:command.deploy"
206
- ];
207
- }
208
-
209
- export function buildAiWorkflowConfig({ profile, managedFiles, managedLinks = [] }) {
210
- const version = getPackageVersion();
211
- const now = new Date().toISOString();
212
-
213
- return {
214
- package: "@williambeto/ai-workflow",
215
- version,
216
- runtime: "opencode",
217
- profile,
218
- installMode: "project-local",
219
- generatedAt: now,
220
- paths: {
221
- agents: ".ai-workflow/opencode/agents",
222
- commands: ".ai-workflow/opencode/commands",
223
- skills: ".ai-workflow/opencode/skills",
224
- policies: ".ai-workflow/opencode/docs/policies",
225
- harness: ".ai-workflow/harness",
226
- schemas: ".ai-workflow/schemas"
227
- }
228
- };
229
- }