@smartmemory/compose 0.1.2-beta → 0.1.4-beta

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/bin/compose.js CHANGED
@@ -576,13 +576,13 @@ if (cmd === 'new') {
576
576
  if (result.options.reviewAgent === 'Codex (automated review)') {
577
577
  const { pipelineSet } = await import('../lib/pipeline-cli.js')
578
578
  try {
579
- pipelineSet(cwd, 'review_gate', ['--mode', 'review'])
580
- } catch { /* gate may not exist in new.stratum.yaml */ }
579
+ pipelineSet(cwd, 'review_gate', ['--mode', 'review'], 'new.stratum.yaml')
580
+ } catch { /* kickoff spec missing or review_gate already absent */ }
581
581
  } else if (result.options.reviewAgent === 'Skip review') {
582
582
  const { pipelineDisable } = await import('../lib/pipeline-cli.js')
583
583
  try {
584
- pipelineDisable(cwd, ['review_gate'])
585
- } catch { /* ignore */ }
584
+ pipelineDisable(cwd, ['review_gate'], 'new.stratum.yaml')
585
+ } catch { /* kickoff spec missing or review_gate already absent */ }
586
586
  }
587
587
  } else if (hasAnswers && !autoMode) {
588
588
  // Load saved answers to enrich intent without prompting
@@ -20,12 +20,13 @@ import { parse, stringify } from 'yaml'
20
20
  // Helpers
21
21
  // ---------------------------------------------------------------------------
22
22
 
23
- function loadSpec(cwd) {
24
- const specPath = join(cwd, 'pipelines', 'build.stratum.yaml')
23
+ function loadSpec(cwd, specName = 'build.stratum.yaml') {
24
+ const specPath = join(cwd, 'pipelines', specName)
25
25
  if (!existsSync(specPath)) {
26
26
  throw new Error(`No pipeline found at ${specPath}. Run 'compose init' first.`)
27
27
  }
28
- return { specPath, spec: parse(readFileSync(specPath, 'utf-8')) }
28
+ const flowName = specName.replace(/\.stratum\.yaml$/, '')
29
+ return { specPath, spec: parse(readFileSync(specPath, 'utf-8')), flowName }
29
30
  }
30
31
 
31
32
  function saveSpec(specPath, spec) {
@@ -54,12 +55,12 @@ const LEVEL_COLORS = {
54
55
  }
55
56
  const RESET = '\x1b[0m'
56
57
 
57
- export function pipelineShow(cwd) {
58
- const { spec } = loadSpec(cwd)
59
- const mainFlow = spec.flows?.build
60
- if (!mainFlow) throw new Error('No "build" flow found in pipeline spec.')
58
+ export function pipelineShow(cwd, specName = 'build.stratum.yaml') {
59
+ const { spec, flowName } = loadSpec(cwd, specName)
60
+ const mainFlow = spec.flows?.[flowName]
61
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found in pipeline spec.`)
61
62
 
62
- console.log(`\n Pipeline: build (${mainFlow.steps.length} steps)\n`)
63
+ console.log(`\n Pipeline: ${flowName} (${mainFlow.steps.length} steps)\n`)
63
64
 
64
65
  for (const step of mainFlow.steps) {
65
66
  const isGate = !!step.function
@@ -133,10 +134,10 @@ function gateTimeout(spec, funcName) {
133
134
  // set
134
135
  // ---------------------------------------------------------------------------
135
136
 
136
- export function pipelineSet(cwd, stepId, flags) {
137
- const { specPath, spec } = loadSpec(cwd)
138
- const mainFlow = spec.flows?.build
139
- if (!mainFlow) throw new Error('No "build" flow found.')
137
+ export function pipelineSet(cwd, stepId, flags, specName = 'build.stratum.yaml') {
138
+ const { specPath, spec, flowName } = loadSpec(cwd, specName)
139
+ const mainFlow = spec.flows?.[flowName]
140
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found.`)
140
141
 
141
142
  const { step, idx } = findStep(mainFlow.steps, stepId)
142
143
 
@@ -305,10 +306,10 @@ function convertToAgent(spec, mainFlow, step, stepId) {
305
306
  // add
306
307
  // ---------------------------------------------------------------------------
307
308
 
308
- export function pipelineAdd(cwd, flags) {
309
- const { specPath, spec } = loadSpec(cwd)
310
- const mainFlow = spec.flows?.build
311
- if (!mainFlow) throw new Error('No "build" flow found.')
309
+ export function pipelineAdd(cwd, flags, specName = 'build.stratum.yaml') {
310
+ const { specPath, spec, flowName } = loadSpec(cwd, specName)
311
+ const mainFlow = spec.flows?.[flowName]
312
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found.`)
312
313
 
313
314
  const id = flagVal(flags, '--id')
314
315
  const after = flagVal(flags, '--after')
@@ -353,10 +354,10 @@ export function pipelineAdd(cwd, flags) {
353
354
  // remove
354
355
  // ---------------------------------------------------------------------------
355
356
 
356
- export function pipelineRemove(cwd, stepId) {
357
- const { specPath, spec } = loadSpec(cwd)
358
- const mainFlow = spec.flows?.build
359
- if (!mainFlow) throw new Error('No "build" flow found.')
357
+ export function pipelineRemove(cwd, stepId, specName = 'build.stratum.yaml') {
358
+ const { specPath, spec, flowName } = loadSpec(cwd, specName)
359
+ const mainFlow = spec.flows?.[flowName]
360
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found.`)
360
361
 
361
362
  const { step, idx } = findStep(mainFlow.steps, stepId)
362
363
 
@@ -388,10 +389,10 @@ export function pipelineRemove(cwd, stepId) {
388
389
  // enable / disable
389
390
  // ---------------------------------------------------------------------------
390
391
 
391
- export function pipelineEnable(cwd, stepIds) {
392
- const { specPath, spec } = loadSpec(cwd)
393
- const mainFlow = spec.flows?.build
394
- if (!mainFlow) throw new Error('No "build" flow found.')
392
+ export function pipelineEnable(cwd, stepIds, specName = 'build.stratum.yaml') {
393
+ const { specPath, spec, flowName } = loadSpec(cwd, specName)
394
+ const mainFlow = spec.flows?.[flowName]
395
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found.`)
395
396
 
396
397
  for (const stepId of stepIds) {
397
398
  const { step } = findStep(mainFlow.steps, stepId)
@@ -403,10 +404,10 @@ export function pipelineEnable(cwd, stepIds) {
403
404
  saveSpec(specPath, spec)
404
405
  }
405
406
 
406
- export function pipelineDisable(cwd, stepIds) {
407
- const { specPath, spec } = loadSpec(cwd)
408
- const mainFlow = spec.flows?.build
409
- if (!mainFlow) throw new Error('No "build" flow found.')
407
+ export function pipelineDisable(cwd, stepIds, specName = 'build.stratum.yaml') {
408
+ const { specPath, spec, flowName } = loadSpec(cwd, specName)
409
+ const mainFlow = spec.flows?.[flowName]
410
+ if (!mainFlow) throw new Error(`No "${flowName}" flow found.`)
410
411
 
411
412
  for (const stepId of stepIds) {
412
413
  const { step } = findStep(mainFlow.steps, stepId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartmemory/compose",
3
- "version": "0.1.2-beta",
3
+ "version": "0.1.4-beta",
4
4
  "description": "Structured AI dev pipeline — goal-to-product orchestration with gates, iteration loops, and feature lifecycle management.",
5
5
  "author": "SmartMemory",
6
6
  "license": "MIT",
@@ -0,0 +1,182 @@
1
+ version: "0.2"
2
+
3
+ workflow:
4
+ name: new
5
+ description: "Product kickoff — research, brainstorm, and scaffold a new project from intent"
6
+ input:
7
+ projectName:
8
+ type: string
9
+ required: true
10
+ intent:
11
+ type: string
12
+ required: true
13
+
14
+ contracts:
15
+ ResearchResult:
16
+ priorArt: {type: array}
17
+ patterns: {type: array}
18
+ risks: {type: array}
19
+ summary: {type: string}
20
+
21
+ BrainstormResult:
22
+ features: {type: array}
23
+ userStories: {type: array}
24
+ archOptions: {type: array}
25
+ summary: {type: string}
26
+
27
+ RoadmapResult:
28
+ phases: {type: array}
29
+ features: {type: array}
30
+ summary: {type: string}
31
+ artifact: {type: string}
32
+
33
+ ScaffoldResult:
34
+ created: {type: array}
35
+ summary: {type: string}
36
+
37
+ functions:
38
+ review_gate:
39
+ mode: gate
40
+ timeout: 7200
41
+
42
+ roadmap_gate:
43
+ mode: gate
44
+ timeout: 3600
45
+
46
+ flows:
47
+ new:
48
+ input:
49
+ projectName: {type: string}
50
+ intent: {type: string}
51
+ output: ScaffoldResult
52
+ steps:
53
+ # Phase: Research prior art
54
+ - id: research
55
+ agent: claude
56
+ intent: >
57
+ Research prior art for this product idea. Search the web for:
58
+ 1. Existing tools that solve the same or similar problems
59
+ 2. Common architectural patterns used in this domain
60
+ 3. Known pitfalls and risks
61
+
62
+ Write your findings to docs/discovery/research.md.
63
+ If docs/discovery/research.md already exists, read it and build on it
64
+ rather than starting from scratch.
65
+ inputs:
66
+ intent: "$.input.intent"
67
+ output_contract: ResearchResult
68
+ ensure:
69
+ - "file_exists('docs/discovery/research.md')"
70
+ validate:
71
+ artifact: docs/discovery/research.md
72
+ criteria:
73
+ - "Contains at least 2 existing tools or prior art entries"
74
+ - "Mentions architectural patterns or common approaches"
75
+ - "Lists risks or pitfalls"
76
+ retries: 3
77
+
78
+ # Phase: Brainstorm features
79
+ - id: brainstorm
80
+ agent: claude
81
+ intent: >
82
+ Given the product intent (and any available research findings),
83
+ brainstorm the product. Generate:
84
+ 1. A feature list — discrete capabilities the product should have,
85
+ each with a short code (e.g. LOG-1, LOG-2) and description.
86
+ Order features by dependency: foundational first, advanced later.
87
+ 2. User stories — "As a <user>, I want <goal>, so that <benefit>"
88
+ 3. Architecture options — 2-3 high-level approaches with trade-offs
89
+
90
+ If docs/discovery/research.md exists, read it first for prior-art
91
+ context. Otherwise proceed from the product intent alone — research
92
+ is an optional input, not a hard requirement (the questionnaire can
93
+ skip it).
94
+
95
+ Write the full brainstorm to docs/discovery/brainstorm.md.
96
+ If docs/discovery/brainstorm.md already exists, read it and refine it
97
+ rather than starting from scratch.
98
+ inputs:
99
+ intent: "$.input.intent"
100
+ research: "$.steps.research.output.summary" # may be null when research is skipped
101
+ output_contract: BrainstormResult
102
+ ensure:
103
+ - "file_exists('docs/discovery/brainstorm.md')"
104
+ validate:
105
+ artifact: docs/discovery/brainstorm.md
106
+ criteria:
107
+ - "Contains at least 3 features with short codes (e.g. LOG-1, LOG-2)"
108
+ - "Contains user stories in 'As a... I want... so that...' format"
109
+ - "Contains at least 2 architecture options with trade-offs"
110
+ retries: 3
111
+ depends_on: [research]
112
+
113
+ # Gate: Human reviews brainstorm
114
+ - id: review_gate
115
+ function: review_gate
116
+ on_approve: roadmap
117
+ on_revise: brainstorm
118
+ on_kill: null
119
+ depends_on: [brainstorm]
120
+
121
+ # Phase: Structure the roadmap
122
+ - id: roadmap
123
+ agent: claude
124
+ intent: >
125
+ Take the approved brainstorm and structure it into a phased ROADMAP.
126
+
127
+ First read docs/discovery/brainstorm.md for the full brainstorm.
128
+ If ROADMAP.md already exists, read it and update it rather than overwriting.
129
+
130
+ Write ROADMAP.md in the project root with:
131
+ 1. Project name and description
132
+ 2. Roadmap conventions (status values, numbering rules)
133
+ 3. Phases grouping features by dependency order
134
+ 4. Each feature as a numbered row with its code, description, and PLANNED status
135
+
136
+ Follow this table format for each phase:
137
+ | # | Feature | Item | Status |
138
+ |---|---------|------|--------|
139
+ | 1 | CODE-1 | Description | PLANNED |
140
+ inputs:
141
+ intent: "$.input.intent"
142
+ brainstorm: "$.steps.brainstorm.output.summary"
143
+ output_contract: RoadmapResult
144
+ ensure:
145
+ - "file_exists('ROADMAP.md')"
146
+ validate:
147
+ artifact: ROADMAP.md
148
+ criteria:
149
+ - "Contains a markdown table with feature codes and status columns"
150
+ - "Features are organized into phases"
151
+ - "All features have PLANNED status"
152
+ retries: 3
153
+ depends_on: [review_gate]
154
+
155
+ # Gate: Human approves the roadmap
156
+ - id: roadmap_gate
157
+ function: roadmap_gate
158
+ on_approve: scaffold
159
+ on_revise: roadmap
160
+ on_kill: null
161
+ depends_on: [roadmap]
162
+
163
+ # Phase: Scaffold feature folders
164
+ - id: scaffold
165
+ agent: claude
166
+ intent: >
167
+ Read the approved ROADMAP.md and create a feature folder for each
168
+ feature listed. For each feature:
169
+ 1. Create docs/features/<CODE>/design.md with a seed design doc containing:
170
+ - Title: "<CODE>: <description>"
171
+ - Status: PLANNED
172
+ - Created date
173
+ - Intent section with the feature description
174
+ - Notes section explaining this is a seed for compose build
175
+ inputs:
176
+ intent: "$.input.intent"
177
+ roadmap: "$.steps.roadmap.output.summary"
178
+ output_contract: ScaffoldResult
179
+ ensure:
180
+ - "len(result.created) > 0"
181
+ retries: 2
182
+ depends_on: [roadmap_gate]