@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,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
- }
@@ -1,106 +0,0 @@
1
- import { existsSync, rmSync, lstatSync, unlinkSync } from "node:fs";
2
- import { join } from "node:path";
3
- import readline from "node:readline";
4
-
5
- function askConfirmation(question) {
6
- const rl = readline.createInterface({
7
- input: process.stdin,
8
- output: process.stdout
9
- });
10
- return new Promise((resolve) => {
11
- rl.question(question, (answer) => {
12
- rl.close();
13
- resolve(answer.trim().toLowerCase());
14
- });
15
- });
16
- }
17
-
18
- function isSymlink(filePath) {
19
- try {
20
- return lstatSync(filePath).isSymbolicLink();
21
- } catch (_) {
22
- return false;
23
- }
24
- }
25
-
26
- export async function runClean({ cwd, yes = false, dryRun = false, purgeAgents = false }) {
27
- const targets = [
28
- ".ai-workflow",
29
- "opencode.jsonc",
30
- ".workflow-state.json",
31
- "opencode"
32
- ];
33
-
34
- const hasAgents = existsSync(join(cwd, ".agents"));
35
-
36
- // Check what actually exists
37
- const existingTargets = targets
38
- .map(name => join(cwd, name))
39
- .filter(path => existsSync(path) || isSymlink(path));
40
-
41
- if (existingTargets.length === 0 && (!hasAgents || !purgeAgents)) {
42
- console.log("No AI Workflow configuration or files found in the current project.");
43
- return;
44
- }
45
-
46
- console.log("\n[AI WORKFLOW] De-initialization");
47
- console.log("===============================");
48
-
49
- if (dryRun) {
50
- console.log("[DRY RUN] The following items would be deleted:");
51
- existingTargets.forEach(path => console.log(` - ${path}`));
52
- if (hasAgents && purgeAgents) {
53
- console.log(` - ${join(cwd, ".agents")} (customizations folder)`);
54
- } else if (hasAgents) {
55
- console.log(` - NOTE: ${join(cwd, ".agents")} exists but will NOT be deleted (run with --purge-agents to delete)`);
56
- }
57
- return;
58
- }
59
-
60
- // Interactive prompts if --yes / -y is not passed
61
- if (!yes) {
62
- if (!process.stdin.isTTY) {
63
- console.log("Error: Non-interactive terminal detected. Run with --yes to bypass confirmation.");
64
- if (process.env.NODE_ENV === "test") {
65
- // Allow tests to bypass TTY block if they mock/stub process.stdin
66
- } else {
67
- process.exit(1);
68
- }
69
- }
70
-
71
- const confirmDeinit = await askConfirmation("Are you sure you want to de-initialize AI Workflow from the project? [y/N] ");
72
- if (confirmDeinit !== "y" && confirmDeinit !== "yes") {
73
- console.log("Aborted.");
74
- return;
75
- }
76
-
77
- if (hasAgents && !purgeAgents) {
78
- const confirmPurge = await askConfirmation("A custom '.agents' folder was detected. Do you want to purge it (this deletes custom prompts/rules/skills)? [y/N] ");
79
- if (confirmPurge === "y" || confirmPurge === "yes") {
80
- purgeAgents = true;
81
- }
82
- }
83
- }
84
-
85
- // Add .agents if requested and exists
86
- if (purgeAgents && hasAgents) {
87
- existingTargets.push(join(cwd, ".agents"));
88
- }
89
-
90
- console.log("\nRemoving files...");
91
- for (const target of existingTargets) {
92
- try {
93
- if (isSymlink(target)) {
94
- unlinkSync(target);
95
- console.log(`Deleted symlink: ${target}`);
96
- } else {
97
- rmSync(target, { recursive: true, force: true });
98
- console.log(`Deleted directory/file: ${target}`);
99
- }
100
- } catch (error) {
101
- console.error(`Failed to delete ${target}: ${error.message}`);
102
- }
103
- }
104
-
105
- console.log("\nAI Workflow has been successfully removed from this project.");
106
- }
@@ -1,25 +0,0 @@
1
- import { EvidenceCollector } from "../core/validation/evidence-collector.js";
2
- import { QualityGuard } from "../core/validation/quality-guard.js";
3
- import { ValidationPlanner } from "../core/validation/validation-planner.js";
4
- import { buildDeliverySummary, formatDeliverySummary } from "../core/validation/canonical-finalization.js";
5
- import fs from "node:fs/promises";
6
- import path from "node:path";
7
-
8
- export async function runCollectEvidence({ cwd, exitOnError = true, taskSlug = null, mode = null, dryRun = false, profile = "generic", branchRecovery = "NOT_RECORDED", userRequest = null, explicitApprovals = [], visualDist = null, port = null }) {
9
- const qualityGuard = new QualityGuard({ cwd, taskSlug, mode });
10
- const planner = new ValidationPlanner({ cwd, qualityGuard });
11
- const tasks = await planner.plan(profile);
12
-
13
- const persist = !dryRun && mode === "full";
14
- const collector = new EvidenceCollector({ cwd, timeout: 60000, taskSlug, mode, profile, branchRecovery, userRequest, explicitApprovals, visualDist, port });
15
- const evidence = await collector.collect(tasks, { writeArtifact: persist });
16
- const summary = buildDeliverySummary({ evidence });
17
-
18
- console.log("\n--- Delivery Summary ---");
19
- console.log(formatDeliverySummary(summary));
20
- console.log(persist ? "\nArtifact: EVIDENCE.json" : "\nArtifact: NOT_REQUIRED for quick/standard mode");
21
- console.log(`Commands processed: ${evidence.commands.length}\n`);
22
-
23
- if (evidence.status === "BLOCKED" && exitOnError) process.exit(1);
24
- return evidence;
25
- }