project-iris 0.0.6

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 (109) hide show
  1. package/README.md +384 -0
  2. package/dist/bridge/connector-factory.js +27 -0
  3. package/dist/bridge/connectors/antigravity-connector.js +18 -0
  4. package/dist/bridge/connectors/cursor-connector.js +31 -0
  5. package/dist/bridge/connectors/vscode-connector.js +31 -0
  6. package/dist/bridge/connectors/windsurf-connector.js +23 -0
  7. package/dist/bridge/filesystem-connector.js +100 -0
  8. package/dist/bridge/types.js +10 -0
  9. package/dist/cli.js +30 -0
  10. package/dist/commands/ask.js +232 -0
  11. package/dist/commands/bridge.js +259 -0
  12. package/dist/commands/develop.js +108 -0
  13. package/dist/commands/doctor.js +102 -0
  14. package/dist/commands/install.js +57 -0
  15. package/dist/commands/pack.js +27 -0
  16. package/dist/commands/phase.js +38 -0
  17. package/dist/commands/run.js +17 -0
  18. package/dist/commands/status.js +105 -0
  19. package/dist/commands/uninstall.js +12 -0
  20. package/dist/commands/validate.js +87 -0
  21. package/dist/iris/artifact-checker.js +78 -0
  22. package/dist/iris/fixer.js +143 -0
  23. package/dist/iris/guard.js +38 -0
  24. package/dist/iris/include.js +49 -0
  25. package/dist/iris/installer.js +269 -0
  26. package/dist/iris/manifest.js +54 -0
  27. package/dist/iris/packer.js +303 -0
  28. package/dist/iris/policy.js +28 -0
  29. package/dist/iris/report.js +53 -0
  30. package/dist/iris/resolver.js +63 -0
  31. package/dist/iris/router.js +114 -0
  32. package/dist/iris/routes.js +20 -0
  33. package/dist/iris/run-state.js +143 -0
  34. package/dist/iris/state.js +85 -0
  35. package/dist/iris/uninstaller.js +166 -0
  36. package/dist/iris/validator.js +329 -0
  37. package/dist/lib.js +96 -0
  38. package/dist/utils/exit-codes.js +7 -0
  39. package/dist/workflows/bolt-execution.js +238 -0
  40. package/dist/workflows/bolt-plan.js +192 -0
  41. package/dist/workflows/intent-inception.js +188 -0
  42. package/package.json +41 -0
  43. package/src/iris_bundle/.iris/aidlc/README.md +16 -0
  44. package/src/iris_bundle/.iris/aidlc/agents/iris-construction-agent.md +35 -0
  45. package/src/iris_bundle/.iris/aidlc/agents/iris-inception-agent.md +30 -0
  46. package/src/iris_bundle/.iris/aidlc/agents/iris-master-agent.md +35 -0
  47. package/src/iris_bundle/.iris/aidlc/agents/iris-operations-agent.md +29 -0
  48. package/src/iris_bundle/.iris/aidlc/commands/iris-construction-agent.md +18 -0
  49. package/src/iris_bundle/.iris/aidlc/commands/iris-inception-agent.md +18 -0
  50. package/src/iris_bundle/.iris/aidlc/commands/iris-master-agent.md +18 -0
  51. package/src/iris_bundle/.iris/aidlc/commands/iris-operations-agent.md +18 -0
  52. package/src/iris_bundle/.iris/aidlc/context/context-map.md +25 -0
  53. package/src/iris_bundle/.iris/aidlc/context/exclusion-rules.md +13 -0
  54. package/src/iris_bundle/.iris/aidlc/context/load-order.md +25 -0
  55. package/src/iris_bundle/.iris/aidlc/memory/intent-rules.md +9 -0
  56. package/src/iris_bundle/.iris/aidlc/memory/log-rules.md +5 -0
  57. package/src/iris_bundle/.iris/aidlc/memory/memory-bank.yaml +39 -0
  58. package/src/iris_bundle/.iris/aidlc/memory/unit-rules.md +9 -0
  59. package/src/iris_bundle/.iris/aidlc/quick-start.md +24 -0
  60. package/src/iris_bundle/.iris/aidlc/skills/execution/implementation.md +14 -0
  61. package/src/iris_bundle/.iris/aidlc/skills/execution/refactoring.md +13 -0
  62. package/src/iris_bundle/.iris/aidlc/skills/execution/scaffold-generation.md +15 -0
  63. package/src/iris_bundle/.iris/aidlc/skills/governance/escalation.md +13 -0
  64. package/src/iris_bundle/.iris/aidlc/skills/governance/quality-gates.md +14 -0
  65. package/src/iris_bundle/.iris/aidlc/skills/governance/stop-conditions.md +11 -0
  66. package/src/iris_bundle/.iris/aidlc/skills/reasoning/decomposition.md +23 -0
  67. package/src/iris_bundle/.iris/aidlc/skills/reasoning/risk-analysis.md +14 -0
  68. package/src/iris_bundle/.iris/aidlc/skills/reasoning/verification.md +21 -0
  69. package/src/iris_bundle/.iris/aidlc/standards/artifacts-registry.md +38 -0
  70. package/src/iris_bundle/.iris/aidlc/standards/decision-logging.md +16 -0
  71. package/src/iris_bundle/.iris/aidlc/standards/doctrine-structure.md +31 -0
  72. package/src/iris_bundle/.iris/aidlc/standards/documentation-rules.md +15 -0
  73. package/src/iris_bundle/.iris/aidlc/standards/file-structure.md +21 -0
  74. package/src/iris_bundle/.iris/aidlc/standards/naming-conventions.md +18 -0
  75. package/src/iris_bundle/.iris/aidlc/standards/phases-and-gates.md +25 -0
  76. package/src/iris_bundle/.iris/aidlc/standards/routes-and-routing.md +35 -0
  77. package/src/iris_bundle/.iris/aidlc/standards/tool-wrappers.md +32 -0
  78. package/src/iris_bundle/.iris/aidlc/templates/bolt.md +23 -0
  79. package/src/iris_bundle/.iris/aidlc/templates/doctrine-doc-template.md +33 -0
  80. package/src/iris_bundle/.iris/aidlc/templates/intent.md +23 -0
  81. package/src/iris_bundle/.iris/aidlc/templates/log.md +24 -0
  82. package/src/iris_bundle/.iris/aidlc/templates/review.md +21 -0
  83. package/src/iris_bundle/.iris/aidlc/templates/unit.md +31 -0
  84. package/src/iris_bundle/.iris/aidlc/validation/failure-modes.md +16 -0
  85. package/src/iris_bundle/.iris/aidlc/validation/phase-preconditions.md +21 -0
  86. package/src/iris_bundle/.iris/aidlc/validation/quality-checklist.md +20 -0
  87. package/src/iris_bundle/.iris/policy.yaml +27 -0
  88. package/src/iris_bundle/.iris/routes.yaml +98 -0
  89. package/src/iris_bundle/.iris/state.yaml +7 -0
  90. package/src/iris_bundle/.iris/tools/antigravity/.antigravity/knowledge/IRIS.md +6 -0
  91. package/src/iris_bundle/.iris/tools/antigravity/.antigravity/workflows/iris-construction-agent.md +25 -0
  92. package/src/iris_bundle/.iris/tools/antigravity/.antigravity/workflows/iris-inception-agent.md +25 -0
  93. package/src/iris_bundle/.iris/tools/antigravity/.antigravity/workflows/iris-master-agent.md +25 -0
  94. package/src/iris_bundle/.iris/tools/antigravity/.antigravity/workflows/iris-operations-agent.md +25 -0
  95. package/src/iris_bundle/.iris/tools/claude/.claude/claude.md +9 -0
  96. package/src/iris_bundle/.iris/tools/claude/.claude/commands/compare-specs.md +203 -0
  97. package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-construction-agent.md +25 -0
  98. package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-inception-agent.md +25 -0
  99. package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-master-agent.md +25 -0
  100. package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-operations-agent.md +25 -0
  101. package/src/iris_bundle/.iris/tools/codex/AGENTS.md +15 -0
  102. package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-construction-agent.md +25 -0
  103. package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-inception-agent.md +25 -0
  104. package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-master-agent.md +25 -0
  105. package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-operations-agent.md +25 -0
  106. package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-construction-agent.toml +29 -0
  107. package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-inception-agent.toml +29 -0
  108. package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-master-agent.toml +29 -0
  109. package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-operations-agent.toml +29 -0
@@ -0,0 +1,143 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { randomUUID } from "crypto";
4
+ import { WorkflowStage } from "../bridge/types.js";
5
+ const RUNS_DIR = path.join(process.cwd(), ".iris/runs");
6
+ /**
7
+ * Create a new workflow run
8
+ */
9
+ export function createRun(intent, ideId, gateMode = "manual") {
10
+ const runId = randomUUID();
11
+ const now = new Date().toISOString();
12
+ const runState = {
13
+ runId,
14
+ intent,
15
+ ideId,
16
+ stage: WorkflowStage.INTENT_INCEPTION,
17
+ gateMode,
18
+ artifacts: [],
19
+ bolts: [],
20
+ currentBoltIndex: 0,
21
+ pendingTasks: [],
22
+ events: [],
23
+ createdAt: now,
24
+ updatedAt: now
25
+ };
26
+ saveRun(runState);
27
+ return runState;
28
+ }
29
+ /**
30
+ * Load a run by ID
31
+ */
32
+ export function loadRun(runId) {
33
+ const runPath = path.join(RUNS_DIR, `${runId}.json`);
34
+ if (!fs.existsSync(runPath)) {
35
+ throw new Error(`Run not found: ${runId}`);
36
+ }
37
+ const content = fs.readFileSync(runPath, "utf8");
38
+ return JSON.parse(content);
39
+ }
40
+ /**
41
+ * Save run state
42
+ */
43
+ export function saveRun(state) {
44
+ if (!fs.existsSync(RUNS_DIR)) {
45
+ fs.mkdirSync(RUNS_DIR, { recursive: true });
46
+ }
47
+ state.updatedAt = new Date().toISOString();
48
+ const runPath = path.join(RUNS_DIR, `${state.runId}.json`);
49
+ fs.writeFileSync(runPath, JSON.stringify(state, null, 2), "utf8");
50
+ // Also save a small state snapshot for quick resume
51
+ const statePath = path.join(RUNS_DIR, `${state.runId}.state.json`);
52
+ const snapshot = {
53
+ runId: state.runId,
54
+ stage: state.stage,
55
+ currentBoltIndex: state.currentBoltIndex,
56
+ updatedAt: state.updatedAt
57
+ };
58
+ fs.writeFileSync(statePath, JSON.stringify(snapshot, null, 2), "utf8");
59
+ }
60
+ /**
61
+ * Append an event to the run
62
+ */
63
+ export function appendEvent(runId, event) {
64
+ const state = loadRun(runId);
65
+ const fullEvent = {
66
+ ...event,
67
+ timestamp: new Date().toISOString()
68
+ };
69
+ state.events.push(fullEvent);
70
+ saveRun(state);
71
+ }
72
+ /**
73
+ * Generate a human-readable summary of the run
74
+ */
75
+ export function generateRunSummary(runId) {
76
+ const state = loadRun(runId);
77
+ let summary = `# IRIS Workflow Run: ${runId}\n\n`;
78
+ summary += `**Intent:** ${state.intent}\n`;
79
+ summary += `**IDE:** ${state.ideId}\n`;
80
+ summary += `**Stage:** ${state.stage}\n`;
81
+ summary += `**Created:** ${state.createdAt}\n`;
82
+ summary += `**Updated:** ${state.updatedAt}\n\n`;
83
+ summary += `## Artifacts Created\n\n`;
84
+ if (state.artifacts.length > 0) {
85
+ summary += state.artifacts.map(a => `- \`${a}\``).join("\n") + "\n\n";
86
+ }
87
+ else {
88
+ summary += "*No artifacts yet*\n\n";
89
+ }
90
+ summary += `## Bolts\n\n`;
91
+ if (state.bolts.length > 0) {
92
+ state.bolts.forEach(bolt => {
93
+ summary += `### ${bolt.id} (${bolt.status})\n`;
94
+ if (bolt.designCompleted)
95
+ summary += "- ✓ Design\n";
96
+ if (bolt.implementationCompleted)
97
+ summary += "- ✓ Implementation\n";
98
+ if (bolt.testingCompleted)
99
+ summary += "- ✓ Testing\n";
100
+ summary += "\n";
101
+ });
102
+ }
103
+ else {
104
+ summary += "*No bolts yet*\n\n";
105
+ }
106
+ summary += `## Event Log\n\n`;
107
+ state.events.forEach(event => {
108
+ summary += `**${event.timestamp}** [${event.stage}] ${event.action}\n`;
109
+ if (event.message)
110
+ summary += ` ${event.message}\n`;
111
+ if (event.userGateDecision)
112
+ summary += ` Gate: ${event.userGateDecision}\n`;
113
+ summary += "\n";
114
+ });
115
+ return summary;
116
+ }
117
+ /**
118
+ * Save run summary to markdown file
119
+ */
120
+ export function saveRunSummary(runId) {
121
+ const summary = generateRunSummary(runId);
122
+ const summaryPath = path.join(RUNS_DIR, `${runId}.md`);
123
+ fs.writeFileSync(summaryPath, summary, "utf8");
124
+ }
125
+ /**
126
+ * List all runs
127
+ */
128
+ export function listRuns() {
129
+ if (!fs.existsSync(RUNS_DIR)) {
130
+ return [];
131
+ }
132
+ const files = fs.readdirSync(RUNS_DIR);
133
+ const stateFiles = files.filter(f => f.endsWith(".state.json"));
134
+ return stateFiles.map(file => {
135
+ const content = fs.readFileSync(path.join(RUNS_DIR, file), "utf8");
136
+ const snapshot = JSON.parse(content);
137
+ return {
138
+ runId: snapshot.runId,
139
+ stage: snapshot.stage,
140
+ updatedAt: snapshot.updatedAt
141
+ };
142
+ }).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
143
+ }
@@ -0,0 +1,85 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import yaml from "js-yaml";
4
+ import { EXIT_CODES } from "../utils/exit-codes.js";
5
+ const STATE_FILE_PATH = path.join(process.cwd(), ".iris/state.yaml");
6
+ export const DEFAULT_STATE = {
7
+ version: 1,
8
+ phase: {
9
+ current: "inception",
10
+ requested: null,
11
+ },
12
+ active: {
13
+ intent_id: null,
14
+ unit_id: null,
15
+ bolt_id: null,
16
+ },
17
+ last_validation: {
18
+ at: null,
19
+ result: null,
20
+ },
21
+ };
22
+ export function loadState() {
23
+ try {
24
+ if (!fs.existsSync(STATE_FILE_PATH)) {
25
+ // Auto-create directory if it doesn't exist
26
+ const dir = path.dirname(STATE_FILE_PATH);
27
+ if (!fs.existsSync(dir)) {
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ }
30
+ saveState(DEFAULT_STATE);
31
+ return DEFAULT_STATE;
32
+ }
33
+ const content = fs.readFileSync(STATE_FILE_PATH, "utf8");
34
+ const doc = yaml.load(content);
35
+ const merged = { ...DEFAULT_STATE, ...doc };
36
+ // Migration/Fixup for legacy/bundled schema
37
+ if (doc.current_phase && !doc.phase) {
38
+ merged.phase = {
39
+ current: doc.current_phase.toLowerCase(), // Normalize to lowercase
40
+ requested: null
41
+ };
42
+ }
43
+ // Ensure nested objects exist
44
+ if (!merged.phase)
45
+ merged.phase = { ...DEFAULT_STATE.phase };
46
+ if (!merged.active)
47
+ merged.active = { ...DEFAULT_STATE.active };
48
+ if (!merged.last_validation || typeof merged.last_validation !== 'object') {
49
+ merged.last_validation = { ...DEFAULT_STATE.last_validation };
50
+ }
51
+ return merged;
52
+ }
53
+ catch (error) {
54
+ console.error("Failed to load or create .iris/state.yaml:", error);
55
+ process.exit(EXIT_CODES.STATE_ERROR);
56
+ }
57
+ }
58
+ export function saveState(state) {
59
+ try {
60
+ const content = yaml.dump(state);
61
+ fs.writeFileSync(STATE_FILE_PATH, content, "utf8");
62
+ }
63
+ catch (error) {
64
+ console.error("Failed to write .iris/state.yaml:", error);
65
+ process.exit(EXIT_CODES.STATE_ERROR);
66
+ }
67
+ }
68
+ /**
69
+ * Get the selected IDE from state, or null if not set
70
+ */
71
+ export function getSelectedIde() {
72
+ const state = loadState();
73
+ return state.ide?.id || null;
74
+ }
75
+ /**
76
+ * Set the selected IDE in state
77
+ */
78
+ export function setSelectedIde(ideId) {
79
+ const state = loadState();
80
+ state.ide = {
81
+ id: ideId,
82
+ selected_at: new Date().toISOString()
83
+ };
84
+ saveState(state);
85
+ }
@@ -0,0 +1,166 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import inquirer from "inquirer";
4
+ import kleur from "kleur";
5
+ import { removeDir, repoRoot } from "../lib.js";
6
+ import { loadManifest } from "./manifest.js";
7
+ export async function uninstallIris(options) {
8
+ const root = repoRoot();
9
+ const manifest = loadManifest();
10
+ if (!manifest) {
11
+ console.log("No IRIS manifest found; nothing to uninstall.");
12
+ return;
13
+ }
14
+ // Step B: Remove installed tool wrapper files
15
+ const manifestTools = manifest.paths_installed || [];
16
+ let removedCount = 0;
17
+ let skippedCount = 0;
18
+ for (const entry of manifestTools) {
19
+ // Only remove stuff outside .iris (we delete .iris wholesale later)
20
+ if (entry.path.startsWith(".iris/"))
21
+ continue;
22
+ // Only remove if status was installed or overwritten
23
+ if (entry.status !== "installed" && entry.status !== "overwritten")
24
+ continue;
25
+ const targetPath = path.join(root, entry.path);
26
+ if (!fs.existsSync(targetPath))
27
+ continue;
28
+ // Check if modified by user?
29
+ // Method 1: Compare with mirror in .iris/tools/
30
+ // entry.path is like .claude/commands/foo.md
31
+ // We know which tool it belongs to? Not directly from installedPath.
32
+ // But we have tools_selected.
33
+ // Let's rely on finding it in one of the mirrors?
34
+ // Or cleaner: we know the 'source' from manifest? I didn't save 'source' in installedPath in installer.ts (oops).
35
+ // I saved: path, type, status.
36
+ // Recover source bundle path from mirror?
37
+ // We mirrored relevant tools to .iris/tools/<tool>.
38
+ // Check if file exists in ANY mirror that matches content?
39
+ // Or simpler: Check against ALL mirrors.
40
+ let matchFound = false;
41
+ for (const tool of manifest.tools_selected) {
42
+ const mirrorFile = path.join(root, ".iris/tools", tool, entry.path); // Mirror structure mimics repo root?
43
+ // Wrapper in installer.ts: copyDirRec(toolBundlePath, mirrorPath) -> mirrorPath = .iris/tools/<tool>
44
+ // And installToolWrapper copied from toolBundlePath to root.
45
+ // So yes, relative path inside .iris/tools/<tool> should match relative path from root?
46
+ // Wait. toolBundlePath might be .../tools/claude. Content is .claude/...
47
+ // So in mirror: .iris/tools/claude/.claude/...
48
+ // relative path of entry: .claude/...
49
+ // So yes: join(.iris/tools/<tool>, entry.path) should point to the backup.
50
+ if (fs.existsSync(mirrorFile)) {
51
+ if (areFilesEqual(targetPath, mirrorFile)) {
52
+ matchFound = true;
53
+ break;
54
+ }
55
+ }
56
+ }
57
+ if (matchFound) {
58
+ fs.unlinkSync(targetPath);
59
+ // Cleanup parent dirs if empty?
60
+ tryRemoveEmptyParents(targetPath, root);
61
+ removedCount++;
62
+ console.log(kleur.gray(`Removed ${entry.path}`));
63
+ }
64
+ else {
65
+ console.log(kleur.yellow(`Modified by user; skipping: ${entry.path}`));
66
+ skippedCount++;
67
+ }
68
+ }
69
+ // Step C: Remove .iris/tools mirrors (Implicitly done by removing .iris later, but specs say remove mirrors)
70
+ // Actually if we remove .iris entire folder, we don't need to do C.
71
+ // Step D: Remove doctrine prompt
72
+ let removeDoctrine = false;
73
+ if (options.force) {
74
+ removeDoctrine = true;
75
+ }
76
+ else {
77
+ const { confirm } = await inquirer.prompt([
78
+ {
79
+ type: "confirm",
80
+ name: "confirm",
81
+ message: "Remove IRIS doctrine (.iris/aidlc) and policy files?",
82
+ default: true
83
+ }
84
+ ]);
85
+ removeDoctrine = confirm;
86
+ }
87
+ if (removeDoctrine) {
88
+ removeDir(path.join(root, ".iris"));
89
+ console.log(kleur.green("Removed .iris/ directory."));
90
+ }
91
+ else {
92
+ console.log(kleur.gray("Kept .iris/ directory."));
93
+ }
94
+ // Step E: Memory Bank
95
+ if (!options.keepMemory) {
96
+ const { confirmMemory } = await inquirer.prompt([
97
+ {
98
+ type: "confirm",
99
+ name: "confirmMemory",
100
+ message: "Keep memory-bank/ folder? (default: Yes, keep)",
101
+ default: true
102
+ }
103
+ ]);
104
+ if (!confirmMemory) { // User said "No" to keeping -> Delete
105
+ // Check if empty or created by us
106
+ // Created dirs = manifest.created_dirs
107
+ // Safety check: contains anything we didn't create?
108
+ // Actually difficult to track every file in memory bank.
109
+ // Safe approach: Only delete if empty?
110
+ // Or prompt: "memory-bank contains files. Type DELETE to confirm."
111
+ const mbPath = path.join(root, "memory-bank");
112
+ if (fs.existsSync(mbPath)) {
113
+ const isEmpty = fs.readdirSync(mbPath).length === 0;
114
+ if (!isEmpty) {
115
+ const { typeDelete } = await inquirer.prompt([
116
+ {
117
+ type: "input",
118
+ name: "typeDelete",
119
+ message: "memory-bank contains files. Type DELETE to confirm removal:",
120
+ }
121
+ ]);
122
+ if (typeDelete === "DELETE") {
123
+ removeDir(mbPath);
124
+ console.log(kleur.green("Removed memory-bank/."));
125
+ }
126
+ else {
127
+ console.log(kleur.yellow("Skipped memory-bank removal (safety)."));
128
+ }
129
+ }
130
+ else {
131
+ removeDir(mbPath);
132
+ console.log(kleur.green("Removed empty memory-bank/."));
133
+ }
134
+ }
135
+ }
136
+ }
137
+ // Step F: Summary
138
+ console.log("");
139
+ console.log(kleur.bold("Uninstall Summary:"));
140
+ console.log(`- Removed files: ${removedCount}`);
141
+ console.log(`- Skipped files (modified): ${skippedCount}`);
142
+ console.log("");
143
+ }
144
+ function areFilesEqual(a, b) {
145
+ try {
146
+ const bufA = fs.readFileSync(a);
147
+ const bufB = fs.readFileSync(b);
148
+ return bufA.equals(bufB);
149
+ }
150
+ catch {
151
+ return false;
152
+ }
153
+ }
154
+ function tryRemoveEmptyParents(filePath, root) {
155
+ let dir = path.dirname(filePath);
156
+ while (dir && path.relative(root, dir) !== "" && !path.isAbsolute(path.relative(root, dir)) && fs.existsSync(dir)) {
157
+ const files = fs.readdirSync(dir);
158
+ if (files.length === 0) {
159
+ fs.rmdirSync(dir);
160
+ dir = path.dirname(dir);
161
+ }
162
+ else {
163
+ break;
164
+ }
165
+ }
166
+ }