project-iris 0.6.8 → 0.6.10

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.
@@ -73,7 +73,7 @@ naming:
73
73
  type: "array of URLs"
74
74
  format: "https://www.figma.com/design/{file-id}/{file-name}?node-id={node-id}&t={token}"
75
75
  note: "Construction Agent uses Figma MCP to fetch design specs. Prototype connections extracted if available."
76
- collected_by: "Inception Agent during story creation (Step 4a in story-create skill)"
76
+ collected_by: "Inception Agent during story creation (Step 2 in story-create skill)"
77
77
  interaction_flows:
78
78
  description: "Manual interaction flow definition (fallback when Figma has no prototype)"
79
79
  type: "array of screen interaction definitions"
@@ -84,7 +84,7 @@ naming:
84
84
  action: navigate | overlay | close | submit
85
85
  target: {destination-screen}
86
86
  note: "Only needed if Figma file has designs but no prototype connections. Construction Agent uses this to wire navigation."
87
- collected_by: "Inception Agent during story creation (Step 4a-2 in story-create skill)"
87
+ collected_by: "Inception Agent during story creation (Step 2 in story-create skill, via figma-story-refs)"
88
88
  priority: "Figma prototype > interaction_flows > infer from labels > ask user"
89
89
 
90
90
  bolts:
@@ -4,7 +4,7 @@ This sub-skill handles collecting Figma frame URLs and interaction flows during
4
4
 
5
5
  ---
6
6
 
7
- ## 4a. Collect Figma References (UI Stories Only)
7
+ ## Collect Figma References (UI Stories Only)
8
8
 
9
9
  **For stories that involve UI screens, ask the user for Figma frame URLs.**
10
10
 
@@ -68,7 +68,7 @@ I detected {n} stories with UI components. Would you like to:
68
68
  3 - Skip Figma references for all (use ui-patterns.md)
69
69
  ```
70
70
 
71
- ## 4a-2. Collect Interaction Flows (If No Prototype in Figma)
71
+ ## Collect Interaction Flows (If No Prototype in Figma)
72
72
 
73
73
  **After collecting Figma URLs, ask about prototype connections:**
74
74
 
@@ -19,6 +19,7 @@
19
19
  - ✅ Unit-brief.md updated with story summary
20
20
  - ✅ **All assigned FRs have corresponding stories (validation passed)**
21
21
  - ✅ **FR-to-story mapping shown in output**
22
+ - ✅ **Figma URLs collected (or explicitly skipped) for all UI stories BEFORE generation**
22
23
 
23
24
  ## Failure Modes
24
25
 
@@ -28,6 +29,7 @@
28
29
  - ❌ Stories without INVEST criteria validation
29
30
  - ❌ **Assigned FRs without corresponding stories**
30
31
  - ❌ **Proceeding without FR-to-story validation**
32
+ - ❌ **Skipping Figma URL collection for UI stories (HARD GATE — see Step 2)**
31
33
 
32
34
  ---
33
35
 
@@ -99,7 +101,46 @@ Review the unit-brief.md to understand:
99
101
 
100
102
  **IMPORTANT**: Stories are created from the unit's **Assigned Requirements** section, NOT directly from intent requirements.md. The FR-to-unit mapping happened during unit decomposition.
101
103
 
102
- ### 2. Generate Stories
104
+ ### 2. Collect Figma Design URLs (⛔ HARD GATE — Before Story Generation)
105
+
106
+ **This step MUST run before generating any story files. It CANNOT be deferred or skipped for UI work.**
107
+
108
+ **Detection**: Check if this unit involves UI by looking at:
109
+
110
+ - `unit_type: frontend` in unit-brief frontmatter
111
+ - Project type is `mobile-app`, `web-app`, `desktop-app`, or similar UI-producing type
112
+ - Any FR assigned to the unit mentions screens, pages, forms, components, navigation, layouts, modals, buttons, or widgets
113
+
114
+ **If ANY UI signal is detected, this is a HARD GATE — you MUST ask the user before proceeding.**
115
+
116
+ > **Read `.iris/aidlc/skills/inception/refs/figma-story-refs.md` and follow the Batch Collection flow.**
117
+
118
+ **Batch-first approach (REQUIRED for multi-story units):**
119
+
120
+ ```text
121
+ ⛔ FIGMA DESIGN REFERENCE GATE
122
+
123
+ This unit ({unit-name}) involves UI development.
124
+ I detected {n} stories that will need UI implementation.
125
+
126
+ Before I generate story files, I need Figma design references.
127
+
128
+ Do you have Figma designs for this unit's stories?
129
+
130
+ 1 - Yes, I'll provide a Figma file/page URL (I'll map frames to stories)
131
+ 2 - Yes, I'll provide individual frame URLs per story
132
+ 3 - No Figma designs exist — use ui-patterns.md guidelines
133
+ ```
134
+
135
+ **⛔ DO NOT proceed to Step 3 (Generate Stories) until the user has responded.**
136
+
137
+ - If user selects 1: Collect the file/page URL, then ask which frames map to which stories after listing the planned stories.
138
+ - If user selects 2: Collect URLs per story as each story is generated.
139
+ - If user selects 3: Proceed without Figma URLs — all stories get `figma_frames: []`.
140
+
141
+ **Store collected URLs** so they are written into each story's frontmatter during Step 7 (Document Stories).
142
+
143
+ ### 3. Generate Stories
103
144
 
104
145
  For each feature in the unit:
105
146
 
@@ -129,7 +170,7 @@ So that {benefit}
129
170
  - {other stories this depends on}
130
171
  ```
131
172
 
132
- ### 3. Apply INVEST Criteria
173
+ ### 4. Apply INVEST Criteria
133
174
 
134
175
  Validate each story against:
135
176
 
@@ -140,7 +181,7 @@ Validate each story against:
140
181
  - [ ] **S**mall: Fits in a single bolt stage? (Required)
141
182
  - [ ] **T**estable: Acceptance criteria are binary? (Required)
142
183
 
143
- ### 4. Group by Priority
184
+ ### 5. Group by Priority
144
185
 
145
186
  Organize stories for bolt planning:
146
187
 
@@ -148,14 +189,7 @@ Organize stories for bolt planning:
148
189
  - **Should**: Important but not blocking (Error handling, validation)
149
190
  - **Could**: Nice to have (Advanced features, optimizations)
150
191
 
151
- ### 4a. Collect Figma References (UI Stories Only)
152
-
153
- **For UI stories, collect Figma frame URLs and interaction flows.**
154
-
155
- > **Read `.iris/aidlc/skills/inception/refs/figma-story-refs.md` and follow its instructions.**
156
- > Covers: UI signal detection, Figma URL collection (individual and batch), interaction flow definition, and frontmatter updates.
157
-
158
- ### 4b. Validate FR-to-Story Coverage (CRITICAL - HARD GATE)
192
+ ### 6. Validate FR-to-Story Coverage (CRITICAL - HARD GATE)
159
193
 
160
194
  **⛔ HARD GATE**: Before creating story files, validate that ALL assigned FRs have stories.
161
195
 
@@ -203,7 +237,7 @@ Organize stories for bolt planning:
203
237
  - Every FR MUST have at least one story
204
238
  - This validation catches FRs that were "lost" during decomposition
205
239
 
206
- ### 5. Document Stories
240
+ ### 7. Document Stories
207
241
 
208
242
  1. **Read Path**: Check `schema.stories` from `.iris/aidlc/memory-bank.yaml`
209
243
  *(Default: `memory-bank/intents/{intent-name}/units/{unit-name}/stories/`)*
@@ -245,7 +279,7 @@ Organize stories for bolt planning:
245
279
  4. **Link to Unit**:
246
280
  Update unit's story index if one exists
247
281
 
248
- ### 6. Update Unit Brief with Story Summary
282
+ ### 8. Update Unit Brief with Story Summary
249
283
 
250
284
  **CRITICAL**: After creating stories, update the unit-brief.md with a story summary.
251
285
 
@@ -269,7 +303,7 @@ Add/update this section in the unit's `unit-brief.md`:
269
303
 
270
304
  This ensures each unit-brief shows its story count at a glance.
271
305
 
272
- ### 7. Update Global Story Index
306
+ ### 9. Update Global Story Index
273
307
 
274
308
  **CRITICAL**: After creating EACH story, IMMEDIATELY update the index.
275
309
 
package/lib/installer.js CHANGED
@@ -298,33 +298,32 @@ async function installFlow(flowKey, toolKeys) {
298
298
  console.log(theme.dim(` Installing flow resources to ${targetFlowDir}/...`));
299
299
 
300
300
  // Clean existing flow directory to prevent duplicate files on reinstall
301
- if (await fs.pathExists(targetFlowDir)) {
302
- await fs.remove(targetFlowDir);
303
- }
304
- await fs.ensureDir(targetFlowDir);
301
+ // Use emptyDir instead of remove+ensureDir to avoid macOS filesystem race conditions
302
+ // that can create "folder 2" duplicates when Finder or iCloud observes the directory
303
+ await fs.emptyDir(targetFlowDir);
305
304
 
306
305
  // Copy agents
307
- await fs.copy(path.join(flowPath, 'agents'), path.join(targetFlowDir, 'agents'));
306
+ await fs.copy(path.join(flowPath, 'agents'), path.join(targetFlowDir, 'agents'), { overwrite: true });
308
307
 
309
308
  // Copy internal agent capabilities (legacy check)
310
309
  if (await fs.pathExists(path.join(flowPath, 'agent-capabilities'))) {
311
- await fs.copy(path.join(flowPath, 'agent-capabilities'), path.join(targetFlowDir, 'agent-capabilities'));
310
+ await fs.copy(path.join(flowPath, 'agent-capabilities'), path.join(targetFlowDir, 'agent-capabilities'), { overwrite: true });
312
311
  }
313
312
 
314
313
  // Copy bolt-types if they exist (legacy check)
315
314
  if (await fs.pathExists(path.join(flowPath, 'bolt-types'))) {
316
- await fs.copy(path.join(flowPath, 'bolt-types'), path.join(targetFlowDir, 'bolt-types'));
315
+ await fs.copy(path.join(flowPath, 'bolt-types'), path.join(targetFlowDir, 'bolt-types'), { overwrite: true });
317
316
  }
318
317
 
319
318
  // Copy skills, templates, shared (now at flow root level, not nested in .iris)
320
319
  if (await fs.pathExists(path.join(flowPath, 'skills'))) {
321
- await fs.copy(path.join(flowPath, 'skills'), path.join(targetFlowDir, 'skills'));
320
+ await fs.copy(path.join(flowPath, 'skills'), path.join(targetFlowDir, 'skills'), { overwrite: true });
322
321
  }
323
322
  if (await fs.pathExists(path.join(flowPath, 'templates'))) {
324
- await fs.copy(path.join(flowPath, 'templates'), path.join(targetFlowDir, 'templates'));
323
+ await fs.copy(path.join(flowPath, 'templates'), path.join(targetFlowDir, 'templates'), { overwrite: true });
325
324
  }
326
325
  if (await fs.pathExists(path.join(flowPath, 'shared'))) {
327
- await fs.copy(path.join(flowPath, 'shared'), path.join(targetFlowDir, 'shared'));
326
+ await fs.copy(path.join(flowPath, 'shared'), path.join(targetFlowDir, 'shared'), { overwrite: true });
328
327
  }
329
328
 
330
329
  // Copy config files
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-iris",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {
@@ -32,8 +32,10 @@ const colors = {
32
32
  bright: '\x1b[1m'
33
33
  };
34
34
 
35
- // Memory bank paths
36
- const MEMORY_BANK_DIR = 'memory-bank';
35
+ // Memory bank paths (resolved from project root)
36
+ const { findProjectRoot } = require('./lib/frontmatter-utils');
37
+ const PROJECT_ROOT = findProjectRoot();
38
+ const MEMORY_BANK_DIR = path.join(PROJECT_ROOT, 'memory-bank');
37
39
  const INTENTS_DIR = path.join(MEMORY_BANK_DIR, 'intents');
38
40
  const BOLTS_DIR = path.join(MEMORY_BANK_DIR, 'bolts');
39
41
 
@@ -80,7 +82,7 @@ const patterns = {
80
82
  };
81
83
 
82
84
  class ArtifactValidator {
83
- constructor(memoryBankPath = 'memory-bank') {
85
+ constructor(memoryBankPath = MEMORY_BANK_DIR) {
84
86
  this.memoryBankPath = memoryBankPath;
85
87
  this.results = [];
86
88
  this.fixCount = 0;
@@ -132,11 +132,13 @@ const {
132
132
  colors,
133
133
  extractFrontmatter,
134
134
  updateFrontmatter,
135
- getTimestamp
135
+ getTimestamp,
136
+ findProjectRoot
136
137
  } = require('./lib/frontmatter-utils');
137
138
 
138
- // Memory bank paths (relative to project root)
139
- const MEMORY_BANK_DIR = 'memory-bank';
139
+ // Memory bank paths (resolved from project root)
140
+ const PROJECT_ROOT = findProjectRoot();
141
+ const MEMORY_BANK_DIR = path.join(PROJECT_ROOT, 'memory-bank');
140
142
  const BOLTS_DIR = path.join(MEMORY_BANK_DIR, 'bolts');
141
143
  const INTENTS_DIR = path.join(MEMORY_BANK_DIR, 'intents');
142
144
 
@@ -6,6 +6,8 @@
6
6
  */
7
7
 
8
8
  const yaml = require('js-yaml');
9
+ const path = require('path');
10
+ const fs = require('fs');
9
11
 
10
12
  // Theme colors for CLI output
11
13
  const colors = {
@@ -67,9 +69,28 @@ function getTimestamp() {
67
69
  return date.toISOString().replace(/\.\d+Z$/, 'Z');
68
70
  }
69
71
 
72
+ /**
73
+ * Find the project root by walking up from cwd looking for memory-bank/ directory.
74
+ * Falls back to cwd if not found (preserving original behavior).
75
+ * @returns {string} Absolute path to the project root
76
+ */
77
+ function findProjectRoot() {
78
+ let dir = process.cwd();
79
+ const root = path.parse(dir).root;
80
+ while (dir !== root) {
81
+ if (fs.existsSync(path.join(dir, 'memory-bank'))) {
82
+ return dir;
83
+ }
84
+ dir = path.dirname(dir);
85
+ }
86
+ // Fallback: return cwd (original behavior)
87
+ return process.cwd();
88
+ }
89
+
70
90
  module.exports = {
71
91
  colors,
72
92
  extractFrontmatter,
73
93
  updateFrontmatter,
74
- getTimestamp
94
+ getTimestamp,
95
+ findProjectRoot
75
96
  };
@@ -18,11 +18,13 @@ const path = require('path');
18
18
  const {
19
19
  colors,
20
20
  extractFrontmatter,
21
- updateFrontmatter
21
+ updateFrontmatter,
22
+ findProjectRoot
22
23
  } = require('./lib/frontmatter-utils');
23
24
 
24
- // Memory bank paths (relative to project root)
25
- const MEMORY_BANK_DIR = 'memory-bank';
25
+ // Memory bank paths (resolved from project root)
26
+ const PROJECT_ROOT = findProjectRoot();
27
+ const MEMORY_BANK_DIR = path.join(PROJECT_ROOT, 'memory-bank');
26
28
  const BOLTS_DIR = path.join(MEMORY_BANK_DIR, 'bolts');
27
29
  const INTENTS_DIR = path.join(MEMORY_BANK_DIR, 'intents');
28
30
  const MAINTENANCE_LOG = path.join(MEMORY_BANK_DIR, 'maintenance-log.md');