@fission-ai/openspec 1.3.1 → 1.4.1

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 (165) hide show
  1. package/README.md +9 -2
  2. package/bin/openspec.js +3 -1
  3. package/dist/cli/index.d.ts +4 -1
  4. package/dist/cli/index.js +65 -3
  5. package/dist/commands/completion.js +7 -0
  6. package/dist/commands/config.js +64 -5
  7. package/dist/commands/context-store.d.ts +3 -0
  8. package/dist/commands/context-store.js +475 -0
  9. package/dist/commands/initiative.d.ts +13 -0
  10. package/dist/commands/initiative.js +318 -0
  11. package/dist/commands/workflow/index.d.ts +2 -0
  12. package/dist/commands/workflow/index.js +1 -0
  13. package/dist/commands/workflow/initiative-link.d.ts +24 -0
  14. package/dist/commands/workflow/initiative-link.js +47 -0
  15. package/dist/commands/workflow/instructions.d.ts +1 -1
  16. package/dist/commands/workflow/instructions.js +28 -11
  17. package/dist/commands/workflow/new-change.d.ts +6 -0
  18. package/dist/commands/workflow/new-change.js +114 -17
  19. package/dist/commands/workflow/set-change.d.ts +13 -0
  20. package/dist/commands/workflow/set-change.js +87 -0
  21. package/dist/commands/workflow/shared.d.ts +4 -2
  22. package/dist/commands/workflow/shared.js +6 -6
  23. package/dist/commands/workflow/status.js +19 -4
  24. package/dist/commands/workspace/context-status.d.ts +4 -0
  25. package/dist/commands/workspace/context-status.js +59 -0
  26. package/dist/commands/workspace/open-target-selection.d.ts +13 -0
  27. package/dist/commands/workspace/open-target-selection.js +146 -0
  28. package/dist/commands/workspace/open-view.d.ts +62 -0
  29. package/dist/commands/workspace/open-view.js +249 -0
  30. package/dist/commands/workspace/open.d.ts +37 -0
  31. package/dist/commands/workspace/open.js +110 -0
  32. package/dist/commands/workspace/opener-selection.d.ts +11 -0
  33. package/dist/commands/workspace/opener-selection.js +98 -0
  34. package/dist/commands/workspace/operations.d.ts +29 -0
  35. package/dist/commands/workspace/operations.js +543 -0
  36. package/dist/commands/workspace/prompt-theme.d.ts +29 -0
  37. package/dist/commands/workspace/prompt-theme.js +24 -0
  38. package/dist/commands/workspace/registration.d.ts +13 -0
  39. package/dist/commands/workspace/registration.js +84 -0
  40. package/dist/commands/workspace/selection.d.ts +8 -0
  41. package/dist/commands/workspace/selection.js +104 -0
  42. package/dist/commands/workspace/setup-prompts.d.ts +13 -0
  43. package/dist/commands/workspace/setup-prompts.js +121 -0
  44. package/dist/commands/workspace/types.d.ts +103 -0
  45. package/dist/commands/workspace/types.js +36 -0
  46. package/dist/commands/workspace.d.ts +5 -0
  47. package/dist/commands/workspace.js +574 -0
  48. package/dist/core/artifact-graph/index.d.ts +2 -1
  49. package/dist/core/artifact-graph/instruction-loader.d.ts +41 -1
  50. package/dist/core/artifact-graph/instruction-loader.js +46 -6
  51. package/dist/core/artifact-graph/types.d.ts +0 -5
  52. package/dist/core/artifact-graph/types.js +0 -14
  53. package/dist/core/change-metadata/index.d.ts +2 -0
  54. package/dist/core/change-metadata/index.js +2 -0
  55. package/dist/core/change-metadata/schema.d.ts +18 -0
  56. package/dist/core/change-metadata/schema.js +28 -0
  57. package/dist/core/change-status-policy.d.ts +50 -0
  58. package/dist/core/change-status-policy.js +70 -0
  59. package/dist/core/collections/index.d.ts +3 -0
  60. package/dist/core/collections/index.js +3 -0
  61. package/dist/core/collections/initiatives/collection.d.ts +4 -0
  62. package/dist/core/collections/initiatives/collection.js +17 -0
  63. package/dist/core/collections/initiatives/index.d.ts +6 -0
  64. package/dist/core/collections/initiatives/index.js +6 -0
  65. package/dist/core/collections/initiatives/operations.d.ts +49 -0
  66. package/dist/core/collections/initiatives/operations.js +175 -0
  67. package/dist/core/collections/initiatives/resolution.d.ts +87 -0
  68. package/dist/core/collections/initiatives/resolution.js +374 -0
  69. package/dist/core/collections/initiatives/schema.d.ts +41 -0
  70. package/dist/core/collections/initiatives/schema.js +134 -0
  71. package/dist/core/collections/initiatives/templates.d.ts +12 -0
  72. package/dist/core/collections/initiatives/templates.js +90 -0
  73. package/dist/core/collections/runtime.d.ts +46 -0
  74. package/dist/core/collections/runtime.js +194 -0
  75. package/dist/core/completions/command-registry.d.ts +1 -5
  76. package/dist/core/completions/command-registry.js +532 -32
  77. package/dist/core/completions/completion-provider.d.ts +11 -0
  78. package/dist/core/completions/completion-provider.js +27 -0
  79. package/dist/core/completions/generators/bash-generator.d.ts +3 -0
  80. package/dist/core/completions/generators/bash-generator.js +60 -4
  81. package/dist/core/completions/generators/fish-generator.js +3 -0
  82. package/dist/core/completions/generators/powershell-generator.d.ts +3 -0
  83. package/dist/core/completions/generators/powershell-generator.js +63 -4
  84. package/dist/core/completions/generators/zsh-generator.d.ts +3 -0
  85. package/dist/core/completions/generators/zsh-generator.js +46 -22
  86. package/dist/core/completions/installers/zsh-installer.d.ts +0 -8
  87. package/dist/core/completions/installers/zsh-installer.js +3 -31
  88. package/dist/core/completions/shared-flags.d.ts +12 -0
  89. package/dist/core/completions/shared-flags.js +28 -0
  90. package/dist/core/completions/templates/bash-templates.d.ts +1 -1
  91. package/dist/core/completions/templates/bash-templates.js +6 -0
  92. package/dist/core/completions/templates/fish-templates.d.ts +1 -1
  93. package/dist/core/completions/templates/fish-templates.js +6 -0
  94. package/dist/core/completions/templates/powershell-templates.d.ts +1 -1
  95. package/dist/core/completions/templates/powershell-templates.js +9 -0
  96. package/dist/core/completions/templates/zsh-templates.d.ts +1 -1
  97. package/dist/core/completions/templates/zsh-templates.js +9 -0
  98. package/dist/core/completions/types.d.ts +23 -1
  99. package/dist/core/config.js +3 -1
  100. package/dist/core/context-store/binding.d.ts +53 -0
  101. package/dist/core/context-store/binding.js +197 -0
  102. package/dist/core/context-store/errors.d.ts +20 -0
  103. package/dist/core/context-store/errors.js +22 -0
  104. package/dist/core/context-store/foundation.d.ts +55 -0
  105. package/dist/core/context-store/foundation.js +321 -0
  106. package/dist/core/context-store/index.d.ts +6 -0
  107. package/dist/core/context-store/index.js +6 -0
  108. package/dist/core/context-store/operations.d.ts +85 -0
  109. package/dist/core/context-store/operations.js +528 -0
  110. package/dist/core/context-store/registry.d.ts +45 -0
  111. package/dist/core/context-store/registry.js +229 -0
  112. package/dist/core/global-config.d.ts +6 -1
  113. package/dist/core/global-config.js +15 -16
  114. package/dist/core/index.d.ts +5 -1
  115. package/dist/core/index.js +4 -0
  116. package/dist/core/parsers/requirement-blocks.js +5 -5
  117. package/dist/core/parsers/spec-structure.js +1 -1
  118. package/dist/core/planning-home.d.ts +21 -0
  119. package/dist/core/planning-home.js +108 -0
  120. package/dist/core/profiles.d.ts +1 -1
  121. package/dist/core/profiles.js +1 -1
  122. package/dist/core/specs-apply.js +1 -1
  123. package/dist/core/templates/workflows/apply-change.js +6 -0
  124. package/dist/core/templates/workflows/archive-change.js +21 -15
  125. package/dist/core/templates/workflows/bulk-archive-change.js +14 -10
  126. package/dist/core/templates/workflows/continue-change.js +6 -4
  127. package/dist/core/templates/workflows/explore.js +8 -10
  128. package/dist/core/templates/workflows/ff-change.js +8 -6
  129. package/dist/core/templates/workflows/new-change.js +6 -6
  130. package/dist/core/templates/workflows/onboard.js +13 -15
  131. package/dist/core/templates/workflows/propose.js +8 -6
  132. package/dist/core/templates/workflows/sync-specs.js +28 -10
  133. package/dist/core/templates/workflows/verify-change.js +10 -4
  134. package/dist/core/update.d.ts +5 -0
  135. package/dist/core/update.js +20 -0
  136. package/dist/core/validation/validator.d.ts +11 -0
  137. package/dist/core/validation/validator.js +19 -2
  138. package/dist/core/workspace/foundation.d.ts +67 -0
  139. package/dist/core/workspace/foundation.js +295 -0
  140. package/dist/core/workspace/index.d.ts +8 -0
  141. package/dist/core/workspace/index.js +8 -0
  142. package/dist/core/workspace/legacy-state.d.ts +28 -0
  143. package/dist/core/workspace/legacy-state.js +200 -0
  144. package/dist/core/workspace/link-input.d.ts +9 -0
  145. package/dist/core/workspace/link-input.js +32 -0
  146. package/dist/core/workspace/open-surface.d.ts +45 -0
  147. package/dist/core/workspace/open-surface.js +215 -0
  148. package/dist/core/workspace/openers.d.ts +21 -0
  149. package/dist/core/workspace/openers.js +124 -0
  150. package/dist/core/workspace/registry.d.ts +24 -0
  151. package/dist/core/workspace/registry.js +146 -0
  152. package/dist/core/workspace/skills.d.ts +57 -0
  153. package/dist/core/workspace/skills.js +334 -0
  154. package/dist/core/workspace/state-io.d.ts +10 -0
  155. package/dist/core/workspace/state-io.js +121 -0
  156. package/dist/utils/change-metadata.d.ts +5 -2
  157. package/dist/utils/change-metadata.js +7 -13
  158. package/dist/utils/change-utils.d.ts +9 -0
  159. package/dist/utils/change-utils.js +7 -5
  160. package/package.json +2 -1
  161. package/schemas/workspace-planning/schema.yaml +72 -0
  162. package/schemas/workspace-planning/templates/design.md +33 -0
  163. package/schemas/workspace-planning/templates/proposal.md +28 -0
  164. package/schemas/workspace-planning/templates/spec.md +9 -0
  165. package/schemas/workspace-planning/templates/tasks.md +15 -0
@@ -0,0 +1,318 @@
1
+ import chalk from 'chalk';
2
+ import { createInitiative, INITIATIVE_FILE_NAMES, listInitiativeViewReferences, mountInitiativesCollection, initiativeDiagnosticFromError as coreInitiativeDiagnosticFromError, resolveInitiativeViewReference as resolveCoreInitiativeViewReference, selectContextStoreForInitiative, formatContextStoreSelector, } from '../core/collections/initiatives/index.js';
3
+ export class InitiativeCliError extends Error {
4
+ diagnostic;
5
+ constructor(message, code, options = {}) {
6
+ super(message);
7
+ this.diagnostic = {
8
+ severity: 'error',
9
+ code,
10
+ message,
11
+ ...options,
12
+ };
13
+ }
14
+ }
15
+ function printJson(payload) {
16
+ console.log(JSON.stringify(payload, null, 2));
17
+ }
18
+ export function initiativeDiagnosticFromError(error) {
19
+ if (error instanceof InitiativeCliError) {
20
+ return error.diagnostic;
21
+ }
22
+ return coreInitiativeDiagnosticFromError(error);
23
+ }
24
+ function appendDiagnostic(payload, diagnostic) {
25
+ return {
26
+ ...payload,
27
+ status: [...payload.status, diagnostic],
28
+ };
29
+ }
30
+ function requireNonBlankOption(value, flagName, target, code) {
31
+ if (value === undefined || value.trim().length === 0) {
32
+ throw new InitiativeCliError(`Pass --${flagName} <value>.`, code, {
33
+ target,
34
+ fix: `openspec initiative create <id> --${flagName} <value>`,
35
+ });
36
+ }
37
+ return value.trim();
38
+ }
39
+ function requireInitiativeId(id, commandName) {
40
+ if (id === undefined || id.trim().length === 0) {
41
+ throw new InitiativeCliError('Pass an initiative id.', 'initiative_id_required', {
42
+ target: 'initiative.id',
43
+ fix: `openspec initiative ${commandName} <id>`,
44
+ });
45
+ }
46
+ return id.trim();
47
+ }
48
+ function toContextStoreOutput(selected) {
49
+ return {
50
+ id: selected.id,
51
+ root: selected.root,
52
+ source: selected.source,
53
+ };
54
+ }
55
+ function toInitiativeOutput(selected, state) {
56
+ const collection = mountInitiativesCollection(selected.root);
57
+ return {
58
+ ...state,
59
+ store: selected.id,
60
+ root: collection.resolvePath(state.id),
61
+ store_path: collection.toStorePath(state.id),
62
+ };
63
+ }
64
+ function listedInitiativeToOutput(initiative) {
65
+ return {
66
+ version: 1,
67
+ id: initiative.id,
68
+ title: initiative.title,
69
+ summary: initiative.summary,
70
+ status: initiative.status,
71
+ created: initiative.created,
72
+ owners: initiative.owners,
73
+ metadata: initiative.metadata,
74
+ store: initiative.store,
75
+ root: initiative.root,
76
+ store_path: initiative.storePath,
77
+ };
78
+ }
79
+ function initiativeReferenceToShowOutput(reference) {
80
+ return {
81
+ version: 1,
82
+ id: reference.id,
83
+ title: reference.title,
84
+ summary: reference.summary,
85
+ created: reference.created,
86
+ root: reference.root,
87
+ store_path: reference.storePath,
88
+ metadata_path: reference.metadataPath,
89
+ };
90
+ }
91
+ function printCreateHuman(payload) {
92
+ if (!payload.context_store || !payload.initiative) {
93
+ return;
94
+ }
95
+ console.log(chalk.green('Created initiative'));
96
+ console.log(`ID: ${payload.initiative.id}`);
97
+ console.log(`Title: ${payload.initiative.title}`);
98
+ console.log(`Status: ${payload.initiative.status}`);
99
+ console.log(`Context store: ${payload.context_store.id}`);
100
+ console.log(`Location: ${payload.initiative.root}`);
101
+ console.log('');
102
+ console.log(`Created files (${payload.created_files.length}):`);
103
+ for (const fileName of payload.created_files) {
104
+ console.log(` - ${fileName}`);
105
+ }
106
+ console.log('');
107
+ console.log('Next useful commands:');
108
+ console.log(` openspec initiative list ${formatContextStoreSelector(payload.context_store)}`);
109
+ }
110
+ function printTableHeader(includeStore) {
111
+ const idHeader = 'ID'.padEnd(22);
112
+ const storeHeader = includeStore ? `${'Store'.padEnd(12)}` : '';
113
+ console.log(`${idHeader}${storeHeader}Title`);
114
+ }
115
+ function printInitiativeRow(initiative, includeStore) {
116
+ const id = initiative.id.padEnd(22);
117
+ const store = includeStore ? `${initiative.store.padEnd(12)}` : '';
118
+ console.log(`${id}${store}${initiative.title}`);
119
+ }
120
+ function printListStatuses(statuses) {
121
+ if (statuses.length === 0) {
122
+ return;
123
+ }
124
+ console.log('');
125
+ for (const status of statuses) {
126
+ console.log(status.message);
127
+ if (status.fix) {
128
+ console.log(`Run: ${status.fix}`);
129
+ }
130
+ }
131
+ }
132
+ function printListHuman(payload) {
133
+ if (payload.context_store) {
134
+ console.log(`OpenSpec initiatives in ${payload.context_store.id} (${payload.initiatives.length})`);
135
+ if (payload.initiatives.length === 0) {
136
+ console.log('');
137
+ console.log(`No initiatives found in ${payload.context_store.id}.`);
138
+ console.log('');
139
+ console.log(`Location: ${payload.context_store.root}`);
140
+ return;
141
+ }
142
+ console.log('');
143
+ printTableHeader(false);
144
+ for (const initiative of payload.initiatives) {
145
+ printInitiativeRow(initiative, false);
146
+ }
147
+ console.log('');
148
+ console.log(`Location: ${payload.context_store.root}`);
149
+ return;
150
+ }
151
+ if (payload.context_stores.length === 0) {
152
+ console.log('No initiatives found because no context stores are registered.');
153
+ return;
154
+ }
155
+ if (payload.initiatives.length === 0) {
156
+ console.log('No initiatives found across registered context stores.');
157
+ printListStatuses(payload.status);
158
+ return;
159
+ }
160
+ console.log(`OpenSpec initiatives (${payload.initiatives.length} across ${payload.context_stores.length} stores)`);
161
+ console.log('');
162
+ printTableHeader(true);
163
+ for (const initiative of payload.initiatives) {
164
+ printInitiativeRow(initiative, true);
165
+ }
166
+ printListStatuses(payload.status);
167
+ }
168
+ function printShowHuman(payload) {
169
+ if (!payload.context_store || !payload.initiative) {
170
+ return;
171
+ }
172
+ console.log(`OpenSpec initiative: ${payload.initiative.title}`);
173
+ console.log('');
174
+ console.log(`ID: ${payload.initiative.id}`);
175
+ console.log(`Summary: ${payload.initiative.summary}`);
176
+ console.log(`Context store: ${payload.context_store.id}`);
177
+ console.log(`Location: ${payload.initiative.root}`);
178
+ console.log(`Metadata: ${payload.initiative.metadata_path}`);
179
+ }
180
+ function printDiagnosticMatches(diagnostic) {
181
+ const matches = diagnostic.details?.matches ?? [];
182
+ if (matches.length === 0) {
183
+ return;
184
+ }
185
+ console.error('');
186
+ console.error(diagnostic.code === 'initiative_lookup_incomplete' ? 'Partial matches:' : 'Matches:');
187
+ for (const match of matches) {
188
+ console.error(` ${match.context_store.id.padEnd(12)}${match.initiative.root}`);
189
+ }
190
+ }
191
+ class InitiativeCommand {
192
+ async create(id, options = {}) {
193
+ try {
194
+ const initiativeId = requireInitiativeId(id, 'create');
195
+ const title = requireNonBlankOption(options.title, 'title', 'initiative.title', 'initiative_title_required');
196
+ const summary = requireNonBlankOption(options.summary, 'summary', 'initiative.summary', 'initiative_summary_required');
197
+ const selected = await selectContextStoreForInitiative(options, 'create');
198
+ const collection = mountInitiativesCollection(selected.root);
199
+ const state = await createInitiative({
200
+ collection,
201
+ id: initiativeId,
202
+ title,
203
+ summary,
204
+ });
205
+ const payload = {
206
+ context_store: toContextStoreOutput(selected),
207
+ initiative: toInitiativeOutput(selected, state),
208
+ created_files: [...INITIATIVE_FILE_NAMES],
209
+ status: [],
210
+ };
211
+ if (options.json) {
212
+ printJson(payload);
213
+ return;
214
+ }
215
+ printCreateHuman(payload);
216
+ }
217
+ catch (error) {
218
+ this.handleFailure(options.json, { context_store: null, initiative: null, created_files: [], status: [] }, error);
219
+ }
220
+ }
221
+ async list(options = {}) {
222
+ try {
223
+ const payload = await this.buildListPayload(options);
224
+ if (options.json) {
225
+ printJson(payload);
226
+ return;
227
+ }
228
+ printListHuman(payload);
229
+ }
230
+ catch (error) {
231
+ this.handleFailure(options.json, { context_store: null, context_stores: [], initiatives: [], status: [] }, error);
232
+ }
233
+ }
234
+ async show(id, options = {}) {
235
+ try {
236
+ const initiativeId = requireInitiativeId(id, 'show');
237
+ const payload = await this.buildShowPayload(initiativeId, options);
238
+ if (options.json) {
239
+ printJson(payload);
240
+ return;
241
+ }
242
+ printShowHuman(payload);
243
+ }
244
+ catch (error) {
245
+ this.handleFailure(options.json, { context_store: null, initiative: null, status: [] }, error);
246
+ }
247
+ }
248
+ async buildListPayload(options) {
249
+ const listed = await listInitiativeViewReferences(options);
250
+ const contextStores = listed.contextStores.map((store) => ({
251
+ context_store: toContextStoreOutput(store.contextStore),
252
+ initiatives: store.initiatives.map(listedInitiativeToOutput),
253
+ status: store.status,
254
+ }));
255
+ return {
256
+ context_store: listed.contextStore ? toContextStoreOutput(listed.contextStore) : null,
257
+ context_stores: contextStores,
258
+ initiatives: listed.initiatives.map(listedInitiativeToOutput),
259
+ status: listed.status,
260
+ };
261
+ }
262
+ async buildShowPayload(initiativeId, options) {
263
+ const reference = await resolveCoreInitiativeViewReference(initiativeId, options);
264
+ return {
265
+ context_store: {
266
+ id: reference.store,
267
+ root: reference.storeRoot,
268
+ },
269
+ initiative: initiativeReferenceToShowOutput(reference),
270
+ status: [],
271
+ };
272
+ }
273
+ handleFailure(json, payload, error) {
274
+ const diagnostic = initiativeDiagnosticFromError(error);
275
+ if (json) {
276
+ printJson(appendDiagnostic(payload, diagnostic));
277
+ process.exitCode = 1;
278
+ return;
279
+ }
280
+ console.error(`Error: ${diagnostic.message}`);
281
+ printDiagnosticMatches(diagnostic);
282
+ if (diagnostic.fix) {
283
+ console.error(`Fix: ${diagnostic.fix}`);
284
+ }
285
+ process.exitCode = 1;
286
+ }
287
+ }
288
+ function addContextStoreSelectorOptions(command) {
289
+ return command
290
+ .option('--store <id>', 'Context store id from the local context-store registry')
291
+ .option('--store-path <path>', 'Existing local context store root')
292
+ .option('--json', 'Output as JSON');
293
+ }
294
+ export function registerInitiativeCommand(program) {
295
+ const initiativeCommand = new InitiativeCommand();
296
+ const initiative = program
297
+ .command('initiative')
298
+ .description('Create and list coordinated initiatives');
299
+ addContextStoreSelectorOptions(initiative
300
+ .command('create [id]')
301
+ .description('Create an initiative in a context store')
302
+ .option('--title <title>', 'Initiative title')
303
+ .option('--summary <summary>', 'Initiative summary')).action(async (id, options) => {
304
+ await initiativeCommand.create(id, options);
305
+ });
306
+ addContextStoreSelectorOptions(initiative
307
+ .command('show <id>')
308
+ .description('Show where an initiative lives and how to read it')).action(async (id, options) => {
309
+ await initiativeCommand.show(id, options);
310
+ });
311
+ addContextStoreSelectorOptions(initiative
312
+ .command('list')
313
+ .alias('ls')
314
+ .description('List initiatives across registered context stores')).action(async (options) => {
315
+ await initiativeCommand.list(options);
316
+ });
317
+ }
318
+ //# sourceMappingURL=initiative.js.map
@@ -13,5 +13,7 @@ export { schemasCommand } from './schemas.js';
13
13
  export type { SchemasOptions } from './schemas.js';
14
14
  export { newChangeCommand } from './new-change.js';
15
15
  export type { NewChangeOptions } from './new-change.js';
16
+ export { setChangeCommand } from './set-change.js';
17
+ export type { SetChangeOptions } from './set-change.js';
16
18
  export { DEFAULT_SCHEMA } from './shared.js';
17
19
  //# sourceMappingURL=index.d.ts.map
@@ -8,5 +8,6 @@ export { instructionsCommand, applyInstructionsCommand } from './instructions.js
8
8
  export { templatesCommand } from './templates.js';
9
9
  export { schemasCommand } from './schemas.js';
10
10
  export { newChangeCommand } from './new-change.js';
11
+ export { setChangeCommand } from './set-change.js';
11
12
  export { DEFAULT_SCHEMA } from './shared.js';
12
13
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,24 @@
1
+ import type { PlanningHome } from '../../core/planning-home.js';
2
+ import { type InitiativeLinkReference } from '../../core/collections/initiatives/index.js';
3
+ export interface ChangeCommandStatus {
4
+ severity: 'error' | 'warning';
5
+ code: string;
6
+ message: string;
7
+ target?: string;
8
+ fix?: string;
9
+ details?: unknown;
10
+ }
11
+ export interface InitiativeSelectorOptions {
12
+ initiative?: string;
13
+ store?: string;
14
+ storePath?: string;
15
+ }
16
+ export declare const REPO_LOCAL_INITIATIVE_LINK_ERROR = "Initiative links are supported only for repo-local changes. Run this command from the repo that owns the implementation plan.";
17
+ export declare function printJson(payload: unknown): void;
18
+ export declare function statusFromError(error: unknown): ChangeCommandStatus;
19
+ export declare function assertInitiativeSelectorsHaveReference(options: InitiativeSelectorOptions): void;
20
+ export declare function assertInitiativeReference(value: string | undefined): asserts value is string;
21
+ export declare function assertRepoLocalInitiativeLinkPlanningHome(planningHome: PlanningHome): void;
22
+ export declare function formatInitiativeLink(initiative: InitiativeLinkReference): string;
23
+ export declare function sameInitiativeLink(left: InitiativeLinkReference | undefined, right: InitiativeLinkReference): boolean;
24
+ //# sourceMappingURL=initiative-link.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { InitiativeResolutionError, } from '../../core/collections/initiatives/index.js';
2
+ export const REPO_LOCAL_INITIATIVE_LINK_ERROR = 'Initiative links are supported only for repo-local changes. Run this command from the repo that owns the implementation plan.';
3
+ export function printJson(payload) {
4
+ console.log(JSON.stringify(payload, null, 2));
5
+ }
6
+ export function statusFromError(error) {
7
+ if (error instanceof InitiativeResolutionError) {
8
+ return {
9
+ severity: 'error',
10
+ code: error.code,
11
+ message: error.message,
12
+ ...(error.target ? { target: error.target } : {}),
13
+ ...(error.fix ? { fix: error.fix } : {}),
14
+ ...(error.details ? { details: error.details } : {}),
15
+ };
16
+ }
17
+ return {
18
+ severity: 'error',
19
+ code: 'change_error',
20
+ message: error instanceof Error ? error.message : String(error),
21
+ };
22
+ }
23
+ export function assertInitiativeSelectorsHaveReference(options) {
24
+ if (!options.initiative && (options.store !== undefined || options.storePath !== undefined)) {
25
+ throw new Error('Pass --initiative when using --store or --store-path.');
26
+ }
27
+ if (options.initiative !== undefined && options.initiative.trim().length === 0) {
28
+ throw new Error('Pass --initiative <id> to link a change to an initiative.');
29
+ }
30
+ }
31
+ export function assertInitiativeReference(value) {
32
+ if (value === undefined || value.trim().length === 0) {
33
+ throw new Error('Pass --initiative <id> to set a change initiative link.');
34
+ }
35
+ }
36
+ export function assertRepoLocalInitiativeLinkPlanningHome(planningHome) {
37
+ if (planningHome.kind === 'workspace') {
38
+ throw new Error(REPO_LOCAL_INITIATIVE_LINK_ERROR);
39
+ }
40
+ }
41
+ export function formatInitiativeLink(initiative) {
42
+ return `${initiative.store}/${initiative.id}`;
43
+ }
44
+ export function sameInitiativeLink(left, right) {
45
+ return left?.store === right.store && left.id === right.id;
46
+ }
47
+ //# sourceMappingURL=initiative-link.js.map
@@ -23,7 +23,7 @@ export declare function printInstructionsText(instructions: ArtifactInstructions
23
23
  * Schema-aware: reads apply phase configuration from schema to determine
24
24
  * required artifacts, tracking file, and instruction.
25
25
  */
26
- export declare function generateApplyInstructions(projectRoot: string, changeName: string, schemaName?: string): Promise<ApplyInstructions>;
26
+ export declare function generateApplyInstructions(projectRoot: string, changeName: string, schemaName?: string, planningHome?: import("../../core/planning-home.js").PlanningHome): Promise<ApplyInstructions>;
27
27
  export declare function applyInstructionsCommand(options: ApplyInstructionsOptions): Promise<void>;
28
28
  export declare function printApplyInstructionsText(instructions: ApplyInstructions): void;
29
29
  //# sourceMappingURL=instructions.d.ts.map
@@ -8,6 +8,7 @@ import ora from 'ora';
8
8
  import path from 'path';
9
9
  import * as fs from 'fs';
10
10
  import { loadChangeContext, generateInstructions, resolveSchema, resolveArtifactOutputs, } from '../../core/artifact-graph/index.js';
11
+ import { getChangeDir, resolveCurrentPlanningHomeSync } from '../../core/planning-home.js';
11
12
  import { validateChangeExists, validateSchemaExists, } from './shared.js';
12
13
  // -----------------------------------------------------------------------------
13
14
  // Artifact Instructions Command
@@ -15,14 +16,18 @@ import { validateChangeExists, validateSchemaExists, } from './shared.js';
15
16
  export async function instructionsCommand(artifactId, options) {
16
17
  const spinner = options.json ? undefined : ora('Generating instructions...').start();
17
18
  try {
18
- const projectRoot = process.cwd();
19
- const changeName = await validateChangeExists(options.change, projectRoot);
19
+ const planningHome = resolveCurrentPlanningHomeSync();
20
+ const projectRoot = planningHome.root;
21
+ const changeName = await validateChangeExists(options.change, projectRoot, planningHome.changesDir);
20
22
  // Validate schema if explicitly provided
21
23
  if (options.schema) {
22
24
  validateSchemaExists(options.schema, projectRoot);
23
25
  }
24
26
  // loadChangeContext will auto-detect schema from metadata if not provided
25
- const context = loadChangeContext(projectRoot, changeName, options.schema);
27
+ const context = loadChangeContext(projectRoot, changeName, options.schema, {
28
+ changeDir: getChangeDir(planningHome, changeName),
29
+ planningHome,
30
+ });
26
31
  if (!artifactId) {
27
32
  spinner?.stop();
28
33
  const validIds = context.graph.getAllArtifacts().map((a) => a.id);
@@ -49,10 +54,14 @@ export async function instructionsCommand(artifactId, options) {
49
54
  }
50
55
  }
51
56
  export function printInstructionsText(instructions, isBlocked) {
52
- const { artifactId, changeName, schemaName, changeDir, outputPath, description, instruction, context, rules, template, dependencies, unlocks, } = instructions;
57
+ const { artifactId, changeName, schemaName, changeDir, initiative, resolvedOutputPath, description, instruction, context, rules, template, dependencies, unlocks, } = instructions;
53
58
  // Opening tag
54
59
  console.log(`<artifact id="${artifactId}" change="${changeName}" schema="${schemaName}">`);
55
60
  console.log();
61
+ if (initiative) {
62
+ console.log(`<initiative store="${initiative.store}" id="${initiative.id}" />`);
63
+ console.log();
64
+ }
56
65
  // Warning for blocked artifacts
57
66
  if (isBlocked) {
58
67
  const missing = dependencies.filter((d) => !d.done).map((d) => d.id);
@@ -104,7 +113,7 @@ export function printInstructionsText(instructions, isBlocked) {
104
113
  }
105
114
  // Output location
106
115
  console.log('<output>');
107
- console.log(`Write to: ${path.join(changeDir, outputPath)}`);
116
+ console.log(`Write to: ${resolvedOutputPath}`);
108
117
  console.log('</output>');
109
118
  console.log();
110
119
  // Instruction (guidance)
@@ -166,9 +175,12 @@ function parseTasksFile(content) {
166
175
  * Schema-aware: reads apply phase configuration from schema to determine
167
176
  * required artifacts, tracking file, and instruction.
168
177
  */
169
- export async function generateApplyInstructions(projectRoot, changeName, schemaName) {
178
+ export async function generateApplyInstructions(projectRoot, changeName, schemaName, planningHome = resolveCurrentPlanningHomeSync({ startPath: projectRoot })) {
170
179
  // loadChangeContext will auto-detect schema from metadata if not provided
171
- const context = loadChangeContext(projectRoot, changeName, schemaName);
180
+ const context = loadChangeContext(projectRoot, changeName, schemaName, {
181
+ changeDir: getChangeDir(planningHome, changeName),
182
+ planningHome,
183
+ });
172
184
  const changeDir = context.changeDir;
173
185
  // Get the full schema to access the apply phase configuration
174
186
  const schema = resolveSchema(context.schemaName, projectRoot);
@@ -245,6 +257,7 @@ export async function generateApplyInstructions(projectRoot, changeName, schemaN
245
257
  changeName,
246
258
  changeDir,
247
259
  schemaName: context.schemaName,
260
+ ...(context.initiative ? { initiative: context.initiative } : {}),
248
261
  contextFiles,
249
262
  progress: { total, complete, remaining },
250
263
  tasks,
@@ -256,14 +269,15 @@ export async function generateApplyInstructions(projectRoot, changeName, schemaN
256
269
  export async function applyInstructionsCommand(options) {
257
270
  const spinner = options.json ? undefined : ora('Generating apply instructions...').start();
258
271
  try {
259
- const projectRoot = process.cwd();
260
- const changeName = await validateChangeExists(options.change, projectRoot);
272
+ const planningHome = resolveCurrentPlanningHomeSync();
273
+ const projectRoot = planningHome.root;
274
+ const changeName = await validateChangeExists(options.change, projectRoot, planningHome.changesDir);
261
275
  // Validate schema if explicitly provided
262
276
  if (options.schema) {
263
277
  validateSchemaExists(options.schema, projectRoot);
264
278
  }
265
279
  // generateApplyInstructions uses loadChangeContext which auto-detects schema
266
- const instructions = await generateApplyInstructions(projectRoot, changeName, options.schema);
280
+ const instructions = await generateApplyInstructions(projectRoot, changeName, options.schema, planningHome);
267
281
  spinner?.stop();
268
282
  if (options.json) {
269
283
  console.log(JSON.stringify(instructions, null, 2));
@@ -277,9 +291,12 @@ export async function applyInstructionsCommand(options) {
277
291
  }
278
292
  }
279
293
  export function printApplyInstructionsText(instructions) {
280
- const { changeName, schemaName, contextFiles, progress, tasks, state, missingArtifacts, instruction } = instructions;
294
+ const { changeName, schemaName, initiative, contextFiles, progress, tasks, state, missingArtifacts, instruction } = instructions;
281
295
  console.log(`## Apply: ${changeName}`);
282
296
  console.log(`Schema: ${schemaName}`);
297
+ if (initiative) {
298
+ console.log(`Initiative: ${initiative.store}/${initiative.id}`);
299
+ }
283
300
  console.log();
284
301
  // Warning for blocked state
285
302
  if (state === 'blocked' && missingArtifacts) {
@@ -5,7 +5,13 @@
5
5
  */
6
6
  export interface NewChangeOptions {
7
7
  description?: string;
8
+ goal?: string;
9
+ areas?: string;
8
10
  schema?: string;
11
+ initiative?: string;
12
+ store?: string;
13
+ storePath?: string;
14
+ json?: boolean;
9
15
  }
10
16
  export declare function newChangeCommand(name: string | undefined, options: NewChangeOptions): Promise<void>;
11
17
  //# sourceMappingURL=new-change.d.ts.map