@williambeto/ai-workflow 2.4.9 → 2.6.4
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 +1138 -168
- package/README.md +203 -77
- package/bin/ai-workflow.d.ts +3 -0
- package/bin/ai-workflow.js +2669 -1
- package/bin/ai-workflow.js.map +1 -0
- package/chunk-2AOV2ATY.js +749 -0
- package/chunk-5WRI5ZAA.js +31 -0
- package/chunk-6EMG6FAO.js +734 -0
- package/chunk-UHLZX2EG.js +1827 -0
- package/core/index.d.ts +440 -0
- package/core/index.js +32 -0
- package/core/index.js.map +1 -0
- package/dist-assets/AGENTS.md +23 -6
- package/dist-assets/agents/atlas.md +8 -8
- package/dist-assets/agents/nexus.md +4 -4
- package/dist-assets/agents/orion.md +1 -1
- package/dist-assets/agents/phoenix.md +1 -1
- package/dist-assets/agents/sage.md +1 -1
- package/dist-assets/commands/implement.md +1 -1
- package/dist-assets/docs/QUICKSTART.md +8 -8
- package/dist-assets/docs/cli-reference.md +7 -7
- package/dist-assets/docs/compatibility/provider-usage.md +1 -9
- package/dist-assets/docs/compatibility/runtime-matrix.md +5 -6
- package/dist-assets/docs/consumer-onboarding.md +2 -2
- package/dist-assets/docs/design-patterns-policy.md +1 -1
- package/dist-assets/docs/npm-consumer-quickstart.md +70 -109
- package/dist-assets/docs/policies/01-BRANCH_GATE.md +1 -1
- package/dist-assets/docs/policies/06-FINAL_EVIDENCE_CONTRACT.md +2 -2
- package/dist-assets/docs/policies/08-PRODUCT_TRUTHFULNESS_AND_PROJECT_DOCS.md +1 -1
- package/dist-assets/docs/policies/10-BEHAVIORAL_CONTRACT_HARDENING.md +1 -1
- package/dist-assets/docs/policies/ORCHESTRATION_PROTOCOL.md +8 -9
- package/dist-assets/docs/policies/PROCEDURE_DELIVERY_ARTIFACTS.md +4 -10
- package/dist-assets/docs/policies/SKILLS_COMMON_GOVERNANCE.md +1 -1
- package/dist-assets/docs/profiles/README.md +2 -2
- package/dist-assets/docs/specs/runtime-operational-contract.md +12 -12
- package/dist-assets/docs/troubleshooting-guide.md +2 -2
- package/dist-assets/docs/visual-validation-guide.md +3 -3
- package/dist-assets/schemas/evidence.schema.json +109 -0
- package/dist-assets/templates/ANTIGRAVITY.md.template +7 -5
- package/dist-assets/templates/CLAUDE.md.template +7 -5
- package/dist-assets/templates/CODEX.md.template +7 -5
- package/evidence-validator-76ZQQYDU.js +6661 -0
- package/package.json +7 -64
- package/{src/core/workspace/read-only-workspace.js → read-only-workspace-PZBE7KAX.js} +14 -31
- package/{src/commands/validate.js → validate-Q2NLLQ5G.js} +30 -22
- package/AGENTS.md +0 -34
- package/PUBLISH_MANIFEST.json +0 -34
- package/dist-assets/templates/.geminiignore.template +0 -8
- package/dist-assets/templates/GEMINI.md.template +0 -20
- package/docs/compatibility/provider-usage.md +0 -46
- package/docs/compatibility/runtime-matrix.md +0 -31
- package/docs/getting-started/DESKTOP_PROMPT.md +0 -52
- package/docs/getting-started/authoring-custom-skills.md +0 -80
- package/docs/getting-started/quickstart.md +0 -117
- package/docs/getting-started/troubleshooting.md +0 -123
- package/docs/getting-started/upgrading-to-v2.md +0 -62
- package/src/adapters/index.js +0 -4
- package/src/adapters/platforms/antigravity.js +0 -382
- package/src/adapters/platforms/claude.js +0 -126
- package/src/adapters/platforms/codex.js +0 -113
- package/src/adapters/platforms/gemini.js +0 -245
- package/src/cli.js +0 -155
- package/src/commands/clean.js +0 -106
- package/src/commands/collect-evidence.js +0 -25
- package/src/commands/doctor.js +0 -202
- package/src/commands/execute.js +0 -382
- package/src/commands/init.js +0 -359
- package/src/commands/run.js +0 -112
- package/src/core/backup.js +0 -65
- package/src/core/completion-contract.js +0 -35
- package/src/core/delegation-controller.js +0 -193
- package/src/core/evidence/evidence-ledger.js +0 -98
- package/src/core/execution-planner.js +0 -62
- package/src/core/filesystem.js +0 -141
- package/src/core/finalization/finalizer.js +0 -165
- package/src/core/finalization/workspace-snapshot.js +0 -110
- package/src/core/gates/branch-gate.js +0 -134
- package/src/core/gates/merge-gate.js +0 -74
- package/src/core/handoff/handoff-engine.js +0 -104
- package/src/core/healing/cli-remediation-executor.js +0 -153
- package/src/core/healing/healer-engine.js +0 -212
- package/src/core/healing/runtime-remediation-executor.js +0 -136
- package/src/core/identity.js +0 -43
- package/src/core/install-plan.js +0 -34
- package/src/core/opencode-merge.js +0 -150
- package/src/core/package-assets.js +0 -141
- package/src/core/request-classifier.js +0 -73
- package/src/core/request-router.js +0 -289
- package/src/core/runtime/opencode-adapter.js +0 -202
- package/src/core/sdd/validator.js +0 -67
- package/src/core/statuses.js +0 -29
- package/src/core/symlink-layout.js +0 -93
- package/src/core/templates.js +0 -229
- package/src/core/validation/artifact-fidelity-gate.js +0 -445
- package/src/core/validation/canonical-finalization.js +0 -43
- package/src/core/validation/delivery-decision-engine.js +0 -344
- package/src/core/validation/evidence-collector.js +0 -245
- package/src/core/validation/quality-guard.js +0 -251
- package/src/core/validation/stack-detector.js +0 -65
- package/src/core/validation/validation-planner.js +0 -134
- package/src/core/validation/visual-verifier.js +0 -175
- package/src/core/workflow-profiles.js +0 -107
- package/src/core/workflow-state-machine.js +0 -46
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { COMPLETION_STATUS_TEXT } from "../../core/statuses.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Claude Adapter - Transforms OpenCode agents and skills into CLAUDE.md and .claude/rules/.
|
|
7
|
-
*/
|
|
8
|
-
export class ClaudeAdapter {
|
|
9
|
-
constructor({ cwd }) {
|
|
10
|
-
this.cwd = cwd;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Transforms an OpenCode agent or skill into a Claude rule with completion contract.
|
|
15
|
-
*/
|
|
16
|
-
async transformToRule(filePath, type = "agent") {
|
|
17
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
18
|
-
const fileName = path.basename(filePath, ".md") === "SKILL"
|
|
19
|
-
? path.basename(path.dirname(filePath))
|
|
20
|
-
: path.basename(filePath, ".md");
|
|
21
|
-
|
|
22
|
-
const ruleName = `${type}-${fileName.toLowerCase()}`;
|
|
23
|
-
|
|
24
|
-
const hardenedContent = `---
|
|
25
|
-
name: ${ruleName}
|
|
26
|
-
description: ${type === "agent" ? "Persona" : "Skill"} rule for ${fileName}
|
|
27
|
-
---
|
|
28
|
-
# ${fileName} ${type === "agent" ? "Persona" : "Skill"}
|
|
29
|
-
|
|
30
|
-
${content}
|
|
31
|
-
|
|
32
|
-
## Completion Contract (Mandatory)
|
|
33
|
-
Every task completion MUST provide the following payload:
|
|
34
|
-
1. **Status**: ${COMPLETION_STATUS_TEXT}
|
|
35
|
-
2. **Scope reviewed**: Brief summary of what was analyzed.
|
|
36
|
-
3. **Findings**: Evidence-based discoveries.
|
|
37
|
-
4. **Files affected**: List of all concrete paths modified or created.
|
|
38
|
-
5. **Validation/evidence**: Commands run and their results.
|
|
39
|
-
6. **Risks/notes**: Any caveats or technical debt introduced.
|
|
40
|
-
7. **Required manager action**: Clear next step for the orchestrator.
|
|
41
|
-
8. **Can manager continue**: [yes/no]
|
|
42
|
-
`;
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
content: hardenedContent,
|
|
46
|
-
name: ruleName
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Deploys agents, skills, and root CLAUDE.md.
|
|
52
|
-
*/
|
|
53
|
-
async deploy(installRoot = ".ai-workflow") {
|
|
54
|
-
const rulesDir = path.join(this.cwd, ".claude/rules");
|
|
55
|
-
await fs.mkdir(rulesDir, { recursive: true });
|
|
56
|
-
|
|
57
|
-
const sourceAgentsDir = path.join(this.cwd, installRoot, "opencode/agents");
|
|
58
|
-
const sourceSkillsDir = path.join(this.cwd, installRoot, "opencode/skills");
|
|
59
|
-
const sourceCommandsDir = path.join(this.cwd, installRoot, "opencode/commands");
|
|
60
|
-
|
|
61
|
-
// 1. Deploy Agents to .claude/rules/agent-*.md
|
|
62
|
-
const agentFiles = await fs.readdir(sourceAgentsDir).catch(() => []);
|
|
63
|
-
for (const file of agentFiles) {
|
|
64
|
-
if (!file.endsWith(".md")) continue;
|
|
65
|
-
const transformed = await this.transformToRule(path.join(sourceAgentsDir, file), "agent");
|
|
66
|
-
await fs.writeFile(path.join(rulesDir, `${transformed.name}.md`), transformed.content);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 2. Deploy Skills to .claude/rules/skill-*.md
|
|
70
|
-
const skillFolders = await fs.readdir(sourceSkillsDir).catch(() => []);
|
|
71
|
-
for (const folder of skillFolders) {
|
|
72
|
-
const skillSource = path.join(sourceSkillsDir, folder, "SKILL.md");
|
|
73
|
-
if (await this.exists(skillSource)) {
|
|
74
|
-
const transformed = await this.transformToRule(skillSource, "skill");
|
|
75
|
-
await fs.writeFile(path.join(rulesDir, `${transformed.name}.md`), transformed.content);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// 3. Create root CLAUDE.md
|
|
80
|
-
await this.deployRootClaudeMd(sourceCommandsDir);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async deployRootClaudeMd(sourceCommandsDir) {
|
|
84
|
-
const targetPath = path.join(this.cwd, "CLAUDE.md");
|
|
85
|
-
|
|
86
|
-
// Collect commands to document them in CLAUDE.md
|
|
87
|
-
const commandFiles = await fs.readdir(sourceCommandsDir).catch(() => []);
|
|
88
|
-
let commandsDoc = "";
|
|
89
|
-
for (const file of commandFiles) {
|
|
90
|
-
if (!file.endsWith(".md")) continue;
|
|
91
|
-
const name = path.basename(file, ".md");
|
|
92
|
-
commandsDoc += `- \`ai-workflow run --spec-path=...\` (Target: ${name})\n`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const instructions = `# CLAUDE.md - AI Workflow Kit Governance
|
|
96
|
-
|
|
97
|
-
This project uses the **AI Workflow Kit** (OpenCode-first) workflow.
|
|
98
|
-
|
|
99
|
-
## Mandate: Atlas Authority Protocol
|
|
100
|
-
All architectural changes must align with the specifications issued by the **Specification Authority** (./specs).
|
|
101
|
-
|
|
102
|
-
## Common Commands
|
|
103
|
-
${commandsDoc}
|
|
104
|
-
- \`ai-workflow doctor\`: Verify installation.
|
|
105
|
-
- \`ai-workflow collect-evidence\`: Generate EVIDENCE.json.
|
|
106
|
-
|
|
107
|
-
## Rules & Personas
|
|
108
|
-
Adhere to the specific rules and personas defined in \`.claude/rules/\`.
|
|
109
|
-
- Always follow the **Branch Gate** policy (never work on \`main\`).
|
|
110
|
-
- Always follow the **SDD Workflow** (Spec -> Plan -> PR -> Evidence).
|
|
111
|
-
|
|
112
|
-
## Completion Contract
|
|
113
|
-
Every task completion MUST follow the payload format defined in the individual rule files.
|
|
114
|
-
`;
|
|
115
|
-
await fs.writeFile(targetPath, instructions);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async exists(p) {
|
|
119
|
-
try {
|
|
120
|
-
await fs.access(p);
|
|
121
|
-
return true;
|
|
122
|
-
} catch {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { COMPLETION_STATUS_TEXT } from "../../core/statuses.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Codex Adapter - Transforms OpenCode agents, skills, and commands into Codex-native formats.
|
|
7
|
-
*/
|
|
8
|
-
export class CodexAdapter {
|
|
9
|
-
constructor({ cwd }) {
|
|
10
|
-
this.cwd = cwd;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Transforms an OpenCode agent into a Codex prompt with completion contract.
|
|
15
|
-
*/
|
|
16
|
-
async transformAgent(filePath) {
|
|
17
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
18
|
-
const fileName = path.basename(filePath, ".md");
|
|
19
|
-
|
|
20
|
-
const hardenedContent = `${content}
|
|
21
|
-
|
|
22
|
-
## Completion Contract (Mandatory)
|
|
23
|
-
Every task completion MUST provide the following payload:
|
|
24
|
-
1. **Status**: ${COMPLETION_STATUS_TEXT}
|
|
25
|
-
2. **Scope reviewed**: Brief summary of what was analyzed.
|
|
26
|
-
3. **Findings**: Evidence-based discoveries.
|
|
27
|
-
4. **Files affected**: List of all concrete paths modified or created.
|
|
28
|
-
5. **Validation/evidence**: Commands run and their results.
|
|
29
|
-
6. **Risks/notes**: Any caveats or technical debt introduced.
|
|
30
|
-
7. **Required manager action**: Clear next step for the orchestrator.
|
|
31
|
-
8. **Can manager continue**: [yes/no]
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
content: hardenedContent,
|
|
36
|
-
name: fileName
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Deploys agents, skills, and commands to Codex-native directories.
|
|
42
|
-
* Mapping:
|
|
43
|
-
* - Agents -> .github/agents/
|
|
44
|
-
* - Skills -> .agents/skills/
|
|
45
|
-
* - Commands -> .codex/prompts/
|
|
46
|
-
*/
|
|
47
|
-
async deploy(installRoot = ".ai-workflow") {
|
|
48
|
-
const sourceAgentsDir = path.join(this.cwd, installRoot, "opencode/agents");
|
|
49
|
-
const sourceSkillsDir = path.join(this.cwd, installRoot, "opencode/skills");
|
|
50
|
-
const sourceCommandsDir = path.join(this.cwd, installRoot, "opencode/commands");
|
|
51
|
-
|
|
52
|
-
// 1. Deploy Agents to .github/agents/
|
|
53
|
-
const codexAgentsDir = path.join(this.cwd, ".github/agents");
|
|
54
|
-
await fs.mkdir(codexAgentsDir, { recursive: true });
|
|
55
|
-
|
|
56
|
-
const agentFiles = await fs.readdir(sourceAgentsDir).catch(() => []);
|
|
57
|
-
for (const file of agentFiles) {
|
|
58
|
-
if (!file.endsWith(".md")) continue;
|
|
59
|
-
const transformed = await this.transformAgent(path.join(sourceAgentsDir, file));
|
|
60
|
-
await fs.writeFile(path.join(codexAgentsDir, `${transformed.name}.md`), transformed.content);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 2. Deploy Skills to .agents/skills/
|
|
64
|
-
const codexSkillsDir = path.join(this.cwd, ".agents/skills");
|
|
65
|
-
await fs.mkdir(codexSkillsDir, { recursive: true });
|
|
66
|
-
|
|
67
|
-
const skillFolders = await fs.readdir(sourceSkillsDir).catch(() => []);
|
|
68
|
-
for (const folder of skillFolders) {
|
|
69
|
-
const skillSource = path.join(sourceSkillsDir, folder, "SKILL.md");
|
|
70
|
-
if (await this.exists(skillSource)) {
|
|
71
|
-
const targetDir = path.join(codexSkillsDir, folder);
|
|
72
|
-
await fs.mkdir(targetDir, { recursive: true });
|
|
73
|
-
const content = await fs.readFile(skillSource, "utf8");
|
|
74
|
-
await fs.writeFile(path.join(targetDir, "SKILL.md"), content);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// 3. Deploy Commands to .codex/prompts/
|
|
79
|
-
const codexPromptsDir = path.join(this.cwd, ".codex/prompts");
|
|
80
|
-
await fs.mkdir(codexPromptsDir, { recursive: true });
|
|
81
|
-
|
|
82
|
-
const commandFiles = await fs.readdir(sourceCommandsDir).catch(() => []);
|
|
83
|
-
for (const file of commandFiles) {
|
|
84
|
-
if (!file.endsWith(".md") && !file.endsWith(".toml")) continue;
|
|
85
|
-
// Codex prompts work best as .md
|
|
86
|
-
const targetFileName = file.endsWith(".toml") ? `${path.basename(file, ".toml")}.md` : file;
|
|
87
|
-
const content = await fs.readFile(path.join(sourceCommandsDir, file), "utf8");
|
|
88
|
-
await fs.writeFile(path.join(codexPromptsDir, targetFileName), content);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 4. Copy governance policy into .agents/docs/policies/ so the relative
|
|
92
|
-
// link ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md in each
|
|
93
|
-
// .agents/skills/{skill}/SKILL.md resolves correctly.
|
|
94
|
-
const codexPoliciesDir = path.join(this.cwd, ".agents", "docs", "policies");
|
|
95
|
-
await fs.mkdir(codexPoliciesDir, { recursive: true });
|
|
96
|
-
const sourcePoliciesDir = path.join(this.cwd, installRoot, "opencode", "docs", "policies");
|
|
97
|
-
const policyFiles = await fs.readdir(sourcePoliciesDir).catch(() => []);
|
|
98
|
-
for (const file of policyFiles) {
|
|
99
|
-
if (!file.endsWith(".md")) continue;
|
|
100
|
-
const policyContent = await fs.readFile(path.join(sourcePoliciesDir, file), "utf8");
|
|
101
|
-
await fs.writeFile(path.join(codexPoliciesDir, file), policyContent);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async exists(p) {
|
|
106
|
-
try {
|
|
107
|
-
await fs.access(p);
|
|
108
|
-
return true;
|
|
109
|
-
} catch {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { COMPLETION_STATUS_TEXT } from "../../core/statuses.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Maps OpenCode agent names to primary agent roles.
|
|
7
|
-
* @type {Record<string, string>}
|
|
8
|
-
*/
|
|
9
|
-
const PERSONA_MAPPING = {
|
|
10
|
-
"atlas": "Atlas",
|
|
11
|
-
"orion": "Orion",
|
|
12
|
-
"sage": "Sage",
|
|
13
|
-
"nexus": "Nexus",
|
|
14
|
-
"astra": "Astra",
|
|
15
|
-
"sage-validation": "Sage",
|
|
16
|
-
"orion-release": "Orion",
|
|
17
|
-
"orion-deploy": "Orion",
|
|
18
|
-
"nexus-discovery": "Nexus",
|
|
19
|
-
"phoenix": "Phoenix"
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Gemini Adapter - Transforms OpenCode .md to Gemini Skill format and manages .gemini/ integration.
|
|
24
|
-
*/
|
|
25
|
-
export class GeminiAdapter {
|
|
26
|
-
constructor({ cwd }) {
|
|
27
|
-
this.cwd = cwd;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Transforms an OpenCode agent or specialized skill file to a Gemini Skill.
|
|
32
|
-
* @param {string} filePath - Path to the source .md file.
|
|
33
|
-
* @returns {Promise<{content: string, name: string}>}
|
|
34
|
-
*/
|
|
35
|
-
async transform(filePath) {
|
|
36
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
37
|
-
const fileName = path.basename(filePath, ".md") === "SKILL"
|
|
38
|
-
? path.basename(path.dirname(filePath))
|
|
39
|
-
: path.basename(filePath, ".md");
|
|
40
|
-
|
|
41
|
-
const persona = PERSONA_MAPPING[fileName.toLowerCase()] || "Astra";
|
|
42
|
-
|
|
43
|
-
// Check if already has frontmatter
|
|
44
|
-
if (content.trim().startsWith("---")) {
|
|
45
|
-
return { content, name: fileName };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Extract description from the first paragraph after the title
|
|
49
|
-
const descriptionMatch = content.match(/^# .*\n\n(.*)/m);
|
|
50
|
-
const description = descriptionMatch ? descriptionMatch[1].trim() : `Specialized agent for ${fileName}.`;
|
|
51
|
-
|
|
52
|
-
const skillContent = `---
|
|
53
|
-
name: ${fileName}
|
|
54
|
-
description: ${description}
|
|
55
|
-
---
|
|
56
|
-
# ${persona} Persona
|
|
57
|
-
|
|
58
|
-
${content}
|
|
59
|
-
|
|
60
|
-
## Completion Contract (Mandatory)
|
|
61
|
-
Every task completion MUST provide the following payload:
|
|
62
|
-
1. **Status**: ${COMPLETION_STATUS_TEXT}
|
|
63
|
-
2. **Scope reviewed**: Brief summary of what was analyzed.
|
|
64
|
-
3. **Findings**: Evidence-based discoveries.
|
|
65
|
-
4. **Files affected**: List of all concrete paths modified or created.
|
|
66
|
-
5. **Validation/evidence**: Commands run and their results.
|
|
67
|
-
6. **Risks/notes**: Any caveats or technical debt introduced.
|
|
68
|
-
7. **Required manager action**: Clear next step for the orchestrator.
|
|
69
|
-
8. **Can manager continue**: [yes/no]
|
|
70
|
-
`;
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
content: skillContent,
|
|
74
|
-
name: fileName
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Deploys transformed skills and agents to their respective directories.
|
|
80
|
-
* Also orchestrates the .gemini/ native integration.
|
|
81
|
-
*/
|
|
82
|
-
async deploy(transformedItems, installRoot = ".ai-workflow") {
|
|
83
|
-
const agentsDir = path.join(this.cwd, installRoot, "opencode/agents");
|
|
84
|
-
const skillsDir = path.join(this.cwd, installRoot, "opencode/skills");
|
|
85
|
-
const geminiDir = path.join(this.cwd, ".gemini");
|
|
86
|
-
|
|
87
|
-
await fs.mkdir(agentsDir, { recursive: true });
|
|
88
|
-
await fs.mkdir(skillsDir, { recursive: true });
|
|
89
|
-
|
|
90
|
-
for (const item of transformedItems) {
|
|
91
|
-
const isAgent = PERSONA_MAPPING[item.name.toLowerCase()];
|
|
92
|
-
const targetDir = isAgent ? agentsDir : path.join(skillsDir, item.name);
|
|
93
|
-
const fileName = isAgent ? `${item.name}.md` : "SKILL.md";
|
|
94
|
-
|
|
95
|
-
const absoluteTargetDir = isAgent ? agentsDir : targetDir;
|
|
96
|
-
await fs.mkdir(absoluteTargetDir, { recursive: true });
|
|
97
|
-
await fs.writeFile(path.join(absoluteTargetDir, fileName), item.content);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Deploy native Gemini CLI extensions (.gemini/)
|
|
101
|
-
await this.deployNativeExtensions(installRoot);
|
|
102
|
-
|
|
103
|
-
// Also deploy root GEMINI.md if it doesn't exist
|
|
104
|
-
await this.deployInstructions();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Orchestrates the .gemini/ directory with copies of .ai-workflow/ assets.
|
|
109
|
-
* Using hard copies instead of symlinks ensures native discovery across all platforms.
|
|
110
|
-
*/
|
|
111
|
-
async deployNativeExtensions(installRoot = ".ai-workflow") {
|
|
112
|
-
const geminiDir = path.join(this.cwd, ".gemini");
|
|
113
|
-
const geminiAgents = path.join(geminiDir, "agents");
|
|
114
|
-
const geminiSkills = path.join(geminiDir, "skills");
|
|
115
|
-
const geminiCommands = path.join(geminiDir, "commands");
|
|
116
|
-
|
|
117
|
-
await fs.mkdir(geminiAgents, { recursive: true });
|
|
118
|
-
await fs.mkdir(geminiSkills, { recursive: true });
|
|
119
|
-
await fs.mkdir(geminiCommands, { recursive: true });
|
|
120
|
-
|
|
121
|
-
// 1. Copy Agents
|
|
122
|
-
const sourceAgentsDir = path.join(this.cwd, installRoot, "opencode/agents");
|
|
123
|
-
const agentFiles = await fs.readdir(sourceAgentsDir).catch(() => []);
|
|
124
|
-
for (const file of agentFiles) {
|
|
125
|
-
if (!file.endsWith(".md")) continue;
|
|
126
|
-
const content = await fs.readFile(path.join(sourceAgentsDir, file), "utf8");
|
|
127
|
-
await fs.writeFile(path.join(geminiAgents, file), content);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// 2. Copy Skills
|
|
131
|
-
const sourceSkillsDir = path.join(this.cwd, installRoot, "opencode/skills");
|
|
132
|
-
const skillFolders = await fs.readdir(sourceSkillsDir).catch(() => []);
|
|
133
|
-
for (const folder of skillFolders) {
|
|
134
|
-
const skillSource = path.join(sourceSkillsDir, folder, "SKILL.md");
|
|
135
|
-
if (await this.exists(skillSource)) {
|
|
136
|
-
await fs.mkdir(path.join(geminiSkills, folder), { recursive: true });
|
|
137
|
-
const content = await fs.readFile(skillSource, "utf8");
|
|
138
|
-
await fs.writeFile(path.join(geminiSkills, folder, "SKILL.md"), content);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 3. Copy Commands (from dist-assets/commands)
|
|
143
|
-
const sourceCommandsDir = path.join(this.cwd, installRoot, "opencode/commands");
|
|
144
|
-
if (await this.exists(sourceCommandsDir)) {
|
|
145
|
-
const commandFiles = await fs.readdir(sourceCommandsDir).catch(() => []);
|
|
146
|
-
for (const file of commandFiles) {
|
|
147
|
-
if (!file.endsWith(".md") && !file.endsWith(".toml")) continue;
|
|
148
|
-
const content = await fs.readFile(path.join(sourceCommandsDir, file), "utf8");
|
|
149
|
-
await fs.writeFile(path.join(geminiCommands, file), content);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 4. Copy governance policy into .gemini/docs/policies/ so the relative
|
|
154
|
-
// link ../../docs/policies/SKILLS_COMMON_GOVERNANCE.md in each
|
|
155
|
-
// .gemini/skills/{skill}/SKILL.md resolves correctly.
|
|
156
|
-
const geminiPoliciesDir = path.join(geminiDir, "docs", "policies");
|
|
157
|
-
await fs.mkdir(geminiPoliciesDir, { recursive: true });
|
|
158
|
-
const sourcePoliciesDir = path.join(this.cwd, installRoot, "opencode", "docs", "policies");
|
|
159
|
-
const policyFiles = await fs.readdir(sourcePoliciesDir).catch(() => []);
|
|
160
|
-
for (const file of policyFiles) {
|
|
161
|
-
if (!file.endsWith(".md")) continue;
|
|
162
|
-
const content = await fs.readFile(path.join(sourcePoliciesDir, file), "utf8");
|
|
163
|
-
await fs.writeFile(path.join(geminiPoliciesDir, file), content);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// 5. Inject project settings.json
|
|
167
|
-
const settingsPath = path.join(geminiDir, "settings.json");
|
|
168
|
-
if (!(await this.exists(settingsPath))) {
|
|
169
|
-
const settings = {
|
|
170
|
-
model: { name: "auto" },
|
|
171
|
-
ui: { theme: "Ayu" }
|
|
172
|
-
};
|
|
173
|
-
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async exists(p) {
|
|
178
|
-
try {
|
|
179
|
-
await fs.access(p);
|
|
180
|
-
return true;
|
|
181
|
-
} catch {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Deploys the main GEMINI.md and .geminiignore instructions to the project root.
|
|
188
|
-
*/
|
|
189
|
-
async deployInstructions() {
|
|
190
|
-
const targetPath = path.join(this.cwd, "GEMINI.md");
|
|
191
|
-
const ignorePath = path.join(this.cwd, ".geminiignore");
|
|
192
|
-
|
|
193
|
-
// Deploy GEMINI.md if it doesn't exist
|
|
194
|
-
try {
|
|
195
|
-
await fs.access(targetPath);
|
|
196
|
-
} catch {
|
|
197
|
-
const instructions = `# AI Workflow Kit - Engineering Governance
|
|
198
|
-
|
|
199
|
-
## Mandate: Atlas Authority Protocol
|
|
200
|
-
All architectural changes must align with the specifications issued by the **Specification Authority** (./specs).
|
|
201
|
-
|
|
202
|
-
## Ternary Architecture
|
|
203
|
-
- **Root:** Orchestration and config.
|
|
204
|
-
- **.ai-workflow/:** Implementation (The Muscle).
|
|
205
|
-
- **./specs:** Specifications (The Brain).
|
|
206
|
-
|
|
207
|
-
## Branch Gates
|
|
208
|
-
- **main Branch:** READ-ONLY.
|
|
209
|
-
- **Validation:** Merges require successful observed validation; full/release workflows may persist EVIDENCE.json.
|
|
210
|
-
|
|
211
|
-
## Primary Agents
|
|
212
|
-
- **Atlas (Orchestrator)**
|
|
213
|
-
- **Orion (Strategist)**
|
|
214
|
-
- **Sage (Auditor)**
|
|
215
|
-
- **Nexus (Spec Architect)**
|
|
216
|
-
- **Astra (Developer)**
|
|
217
|
-
- **Phoenix (Healer)**
|
|
218
|
-
|
|
219
|
-
## Operational Preferences
|
|
220
|
-
- Use \`token-economy\` and \`minimal-context\` skills.
|
|
221
|
-
- **Native Discovery**: This project uses workspace-specific extensions in \`.gemini/\`.
|
|
222
|
-
- **Workflow Entry**: Use \`/atlas\` to begin any task.
|
|
223
|
-
`;
|
|
224
|
-
await fs.writeFile(targetPath, instructions);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Deploy .geminiignore if it doesn't exist
|
|
228
|
-
try {
|
|
229
|
-
await fs.access(ignorePath);
|
|
230
|
-
} catch {
|
|
231
|
-
const ignoreContent = `.ai-workflow/
|
|
232
|
-
.ai-workflow-backups/
|
|
233
|
-
node_modules/
|
|
234
|
-
.git/
|
|
235
|
-
EVIDENCE.json
|
|
236
|
-
*.tgz
|
|
237
|
-
*.zip
|
|
238
|
-
*.tar
|
|
239
|
-
.gemini/tmp/
|
|
240
|
-
.gemini/history/
|
|
241
|
-
`;
|
|
242
|
-
await fs.writeFile(ignorePath, ignoreContent);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
package/src/cli.js
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { getPackageVersion } from "./core/package-assets.js";
|
|
2
|
-
import { runInit } from "./commands/init.js";
|
|
3
|
-
import { runDoctor } from "./commands/doctor.js";
|
|
4
|
-
import { runCollectEvidence } from "./commands/collect-evidence.js";
|
|
5
|
-
import { runMasterOrchestrator } from "./commands/run.js";
|
|
6
|
-
import { runExecute } from "./commands/execute.js";
|
|
7
|
-
import { runClean } from "./commands/clean.js";
|
|
8
|
-
|
|
9
|
-
function printHelp() {
|
|
10
|
-
console.log(`ai-workflow
|
|
11
|
-
|
|
12
|
-
Usage:
|
|
13
|
-
ai-workflow execute "<request>" [--task=<slug>] [--request="<request>"]
|
|
14
|
-
ai-workflow run --spec-path=<path>
|
|
15
|
-
ai-workflow init [--yes] [--force] [--dry-run] [--no-install] [--no-overwrite] [--gemini] [--claude] [--codex] [--antigravity] [--profile=<profile>]
|
|
16
|
-
ai-workflow validate [--a11y] [--visual-dist=<path>] [--port=<port>]
|
|
17
|
-
ai-workflow collect-evidence [--task=<slug>] [--mode=<quick|standard|full>] [--dry-run] [--visual-dist=<path>] [--port=<port>]
|
|
18
|
-
ai-workflow doctor
|
|
19
|
-
ai-workflow clean [--yes] [--dry-run] [--purge-agents]
|
|
20
|
-
|
|
21
|
-
Commands:
|
|
22
|
-
execute Orchestrate execution of a natural request through the state machine
|
|
23
|
-
run Proportionate orchestrator with branch safety, validation, and bounded remediation
|
|
24
|
-
init Install AI workflow defaults (OpenCode). --profile=standard (default) or --profile=full (adds examples)
|
|
25
|
-
collect-evidence Run observed project validation; persists EVIDENCE.json only for full mode
|
|
26
|
-
doctor Verify local ai-workflow installation
|
|
27
|
-
clean De-initialize and remove AI Workflow files and symlinks from the project
|
|
28
|
-
`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function parseFlags(args) {
|
|
32
|
-
const specPathArg = args.find((arg) => arg.startsWith("--spec-path="));
|
|
33
|
-
const profileEqArg = args.find((arg) => arg.startsWith("--profile="));
|
|
34
|
-
const taskArg = args.find((arg) => arg.startsWith("--task="));
|
|
35
|
-
const modeArg = args.find((arg) => arg.startsWith("--mode="));
|
|
36
|
-
const requestArg = args.find((arg) => arg.startsWith("--request="));
|
|
37
|
-
const visualDistArg = args.find((arg) => arg.startsWith("--visual-dist="));
|
|
38
|
-
const portArg = args.find((arg) => arg.startsWith("--port="));
|
|
39
|
-
const profileIdx = args.indexOf("--profile");
|
|
40
|
-
const profileVal = profileEqArg
|
|
41
|
-
? profileEqArg.replace("--profile=", "")
|
|
42
|
-
: profileIdx >= 0 && profileIdx + 1 < args.length && !args[profileIdx + 1].startsWith("--")
|
|
43
|
-
? args[profileIdx + 1]
|
|
44
|
-
: undefined;
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
yes: args.includes("--yes"),
|
|
48
|
-
force: args.includes("--force"),
|
|
49
|
-
dryRun: args.includes("--dry-run"),
|
|
50
|
-
noInstall: args.includes("--no-install"),
|
|
51
|
-
noOverwrite: args.includes("--no-overwrite"),
|
|
52
|
-
gemini: args.includes("--gemini"),
|
|
53
|
-
claude: args.includes("--claude"),
|
|
54
|
-
codex: args.includes("--codex"),
|
|
55
|
-
antigravity: args.includes("--antigravity"),
|
|
56
|
-
"dev-mode": args.includes("--dev-mode"),
|
|
57
|
-
specPath: specPathArg ? specPathArg.replace("--spec-path=", "") : undefined,
|
|
58
|
-
profile: profileVal || undefined,
|
|
59
|
-
taskSlug: taskArg ? taskArg.replace("--task=", "") : undefined,
|
|
60
|
-
mode: modeArg ? modeArg.replace("--mode=", "") : undefined,
|
|
61
|
-
request: requestArg ? requestArg.replace("--request=", "") : undefined,
|
|
62
|
-
visualDist: visualDistArg ? visualDistArg.replace("--visual-dist=", "") : undefined,
|
|
63
|
-
port: portArg ? portArg.replace("--port=", "") : undefined,
|
|
64
|
-
a11y: args.includes("--a11y"),
|
|
65
|
-
purgeAgents: args.includes("--purge-agents") || args.includes("--purge")
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
export async function runCli(args) {
|
|
71
|
-
const [command] = args;
|
|
72
|
-
|
|
73
|
-
if (command === "--version" || command === "-v") {
|
|
74
|
-
console.log(getPackageVersion() || "unknown");
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!command || command === "--help" || command === "-h") {
|
|
79
|
-
printHelp();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (command === "execute") {
|
|
84
|
-
const flags = parseFlags(args.slice(1));
|
|
85
|
-
const positionals = args.slice(1).filter((arg) => !arg.startsWith("-"));
|
|
86
|
-
const request = flags.request || positionals.join(" ");
|
|
87
|
-
const result = await runExecute({
|
|
88
|
-
cwd: process.cwd(),
|
|
89
|
-
naturalRequest: request,
|
|
90
|
-
taskSlug: flags.taskSlug
|
|
91
|
-
});
|
|
92
|
-
if (result && (result.overallStatus === "FAIL_QUALITY_GATE" || result.overallStatus === "BLOCKED" || result.overallStatus === "FAIL")) {
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (command === "run") {
|
|
99
|
-
await runMasterOrchestrator({
|
|
100
|
-
cwd: process.cwd(),
|
|
101
|
-
...parseFlags(args.slice(1))
|
|
102
|
-
});
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (command === "init") {
|
|
107
|
-
await runInit({
|
|
108
|
-
cwd: process.cwd(),
|
|
109
|
-
...parseFlags(args.slice(1))
|
|
110
|
-
});
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (command === "collect-evidence") {
|
|
115
|
-
const flags = parseFlags(args.slice(1));
|
|
116
|
-
if (flags.mode && !["quick", "standard", "full"].includes(flags.mode)) throw new Error("--mode must be quick, standard, or full");
|
|
117
|
-
await runCollectEvidence({
|
|
118
|
-
cwd: process.cwd(),
|
|
119
|
-
taskSlug: flags.taskSlug,
|
|
120
|
-
mode: flags.mode,
|
|
121
|
-
dryRun: flags.dryRun,
|
|
122
|
-
visualDist: flags.visualDist,
|
|
123
|
-
port: flags.port
|
|
124
|
-
});
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (command === "validate") {
|
|
129
|
-
const flags = parseFlags(args.slice(1));
|
|
130
|
-
const { runValidate } = await import("./commands/validate.js");
|
|
131
|
-
await runValidate({
|
|
132
|
-
cwd: process.cwd(),
|
|
133
|
-
taskSlug: flags.taskSlug,
|
|
134
|
-
a11y: flags.a11y,
|
|
135
|
-
visualDist: flags.visualDist,
|
|
136
|
-
port: flags.port
|
|
137
|
-
});
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (command === "doctor") {
|
|
142
|
-
await runDoctor({ cwd: process.cwd() });
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (command === "clean") {
|
|
147
|
-
await runClean({
|
|
148
|
-
cwd: process.cwd(),
|
|
149
|
-
...parseFlags(args.slice(1))
|
|
150
|
-
});
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
throw new Error(`unknown command: ${command}`);
|
|
155
|
-
}
|