MCPcopy
hub / github.com/Fission-AI/OpenSpec / createChange

Function createChange

src/utils/change-utils.ts:121–190  ·  view source on GitHub ↗
(
  projectRoot: string,
  name: string,
  options: CreateChangeOptions = {}
)

Source from the content-addressed store, hash-verified

119 * console.log(result.schema) // 'my-workflow'
120 */
121export async function createChange(
122 projectRoot: string,
123 name: string,
124 options: CreateChangeOptions = {}
125): Promise<CreateChangeResult> {
126 // Validate the name first
127 const validation = validateChangeName(name);
128 if (!validation.valid) {
129 throw new Error(validation.error);
130 }
131
132 const defaultSchema = options.defaultSchema ?? DEFAULT_SCHEMA;
133
134 // Determine schema: explicit option → project config → supplied default
135 let schemaName: string;
136 if (options.schema) {
137 schemaName = options.schema;
138 } else {
139 // Try to read from project config
140 try {
141 const config = readProjectConfig(projectRoot);
142 schemaName = config?.schema ?? defaultSchema;
143 } catch {
144 // If config read fails, use default
145 schemaName = defaultSchema;
146 }
147 }
148
149 // Validate the resolved schema
150 validateSchemaName(schemaName, projectRoot);
151
152 // Build the change directory path
153 const changeDir = path.join(options.changesDir ?? path.join(projectRoot, 'openspec', 'changes'), name);
154
155 // Check if change already exists
156 if (await FileSystemUtils.directoryExists(changeDir)) {
157 throw new Error(`Change '${name}' already exists at ${changeDir}`);
158 }
159
160 // Creating a change may scaffold or complete the root itself (an
161 // implicit root, or a config-only/incomplete clone). Never leave a
162 // half-root behind that doctor immediately calls unhealthy: ensure
163 // specs/ and changes/archive/ exist, and write a config only when
164 // none exists. The config records the PROJECT default schema, never
165 // a one-change --schema override.
166 const openspecDir = path.join(projectRoot, 'openspec');
167
168 // Create the directory (including parent directories if needed)
169 await FileSystemUtils.createDirectory(changeDir);
170 await FileSystemUtils.createDirectory(path.join(openspecDir, 'specs'));
171 await FileSystemUtils.createDirectory(path.join(openspecDir, 'changes', 'archive'));
172 const configPath = path.join(openspecDir, 'config.yaml');
173 const configYmlPath = path.join(openspecDir, 'config.yml');
174 if (
175 !(await FileSystemUtils.fileExists(configPath)) &&
176 !(await FileSystemUtils.fileExists(configYmlPath))
177 ) {
178 await FileSystemUtils.writeFile(configPath, `schema: ${defaultSchema}\n`);

Callers 1

newChangeCommandFunction · 0.50

Calls 8

validateChangeNameFunction · 0.85
readProjectConfigFunction · 0.85
validateSchemaNameFunction · 0.85
writeChangeMetadataFunction · 0.85
directoryExistsMethod · 0.80
createDirectoryMethod · 0.80
fileExistsMethod · 0.80
writeFileMethod · 0.80

Tested by

no test coverage detected