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.
- package/flows/aidlc/memory-bank.yaml +2 -2
- package/flows/aidlc/skills/inception/refs/figma-story-refs.md +2 -2
- package/flows/aidlc/skills/inception/story-create.md +48 -14
- package/lib/installer.js +9 -10
- package/package.json +1 -1
- package/scripts/artifact-validator.js +5 -3
- package/scripts/bolt-complete.js +5 -3
- package/scripts/lib/frontmatter-utils.js +22 -1
- package/scripts/status-integrity.js +5 -3
|
@@ -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
|
|
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
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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.
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
|
|
302
|
-
|
|
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.
|
|
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
|
|
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 =
|
|
85
|
+
constructor(memoryBankPath = MEMORY_BANK_DIR) {
|
|
84
86
|
this.memoryBankPath = memoryBankPath;
|
|
85
87
|
this.results = [];
|
|
86
88
|
this.fixCount = 0;
|
package/scripts/bolt-complete.js
CHANGED
|
@@ -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 (
|
|
139
|
-
const
|
|
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 (
|
|
25
|
-
const
|
|
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');
|