@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.
- package/README.md +9 -2
- package/bin/openspec.js +3 -1
- package/dist/cli/index.d.ts +4 -1
- package/dist/cli/index.js +65 -3
- package/dist/commands/completion.js +7 -0
- package/dist/commands/config.js +64 -5
- package/dist/commands/context-store.d.ts +3 -0
- package/dist/commands/context-store.js +475 -0
- package/dist/commands/initiative.d.ts +13 -0
- package/dist/commands/initiative.js +318 -0
- package/dist/commands/workflow/index.d.ts +2 -0
- package/dist/commands/workflow/index.js +1 -0
- package/dist/commands/workflow/initiative-link.d.ts +24 -0
- package/dist/commands/workflow/initiative-link.js +47 -0
- package/dist/commands/workflow/instructions.d.ts +1 -1
- package/dist/commands/workflow/instructions.js +28 -11
- package/dist/commands/workflow/new-change.d.ts +6 -0
- package/dist/commands/workflow/new-change.js +114 -17
- package/dist/commands/workflow/set-change.d.ts +13 -0
- package/dist/commands/workflow/set-change.js +87 -0
- package/dist/commands/workflow/shared.d.ts +4 -2
- package/dist/commands/workflow/shared.js +6 -6
- package/dist/commands/workflow/status.js +19 -4
- package/dist/commands/workspace/context-status.d.ts +4 -0
- package/dist/commands/workspace/context-status.js +59 -0
- package/dist/commands/workspace/open-target-selection.d.ts +13 -0
- package/dist/commands/workspace/open-target-selection.js +146 -0
- package/dist/commands/workspace/open-view.d.ts +62 -0
- package/dist/commands/workspace/open-view.js +249 -0
- package/dist/commands/workspace/open.d.ts +37 -0
- package/dist/commands/workspace/open.js +110 -0
- package/dist/commands/workspace/opener-selection.d.ts +11 -0
- package/dist/commands/workspace/opener-selection.js +98 -0
- package/dist/commands/workspace/operations.d.ts +29 -0
- package/dist/commands/workspace/operations.js +543 -0
- package/dist/commands/workspace/prompt-theme.d.ts +29 -0
- package/dist/commands/workspace/prompt-theme.js +24 -0
- package/dist/commands/workspace/registration.d.ts +13 -0
- package/dist/commands/workspace/registration.js +84 -0
- package/dist/commands/workspace/selection.d.ts +8 -0
- package/dist/commands/workspace/selection.js +104 -0
- package/dist/commands/workspace/setup-prompts.d.ts +13 -0
- package/dist/commands/workspace/setup-prompts.js +121 -0
- package/dist/commands/workspace/types.d.ts +103 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +5 -0
- package/dist/commands/workspace.js +574 -0
- package/dist/core/artifact-graph/index.d.ts +2 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +41 -1
- package/dist/core/artifact-graph/instruction-loader.js +46 -6
- package/dist/core/artifact-graph/types.d.ts +0 -5
- package/dist/core/artifact-graph/types.js +0 -14
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/schema.d.ts +18 -0
- package/dist/core/change-metadata/schema.js +28 -0
- package/dist/core/change-status-policy.d.ts +50 -0
- package/dist/core/change-status-policy.js +70 -0
- package/dist/core/collections/index.d.ts +3 -0
- package/dist/core/collections/index.js +3 -0
- package/dist/core/collections/initiatives/collection.d.ts +4 -0
- package/dist/core/collections/initiatives/collection.js +17 -0
- package/dist/core/collections/initiatives/index.d.ts +6 -0
- package/dist/core/collections/initiatives/index.js +6 -0
- package/dist/core/collections/initiatives/operations.d.ts +49 -0
- package/dist/core/collections/initiatives/operations.js +175 -0
- package/dist/core/collections/initiatives/resolution.d.ts +87 -0
- package/dist/core/collections/initiatives/resolution.js +374 -0
- package/dist/core/collections/initiatives/schema.d.ts +41 -0
- package/dist/core/collections/initiatives/schema.js +134 -0
- package/dist/core/collections/initiatives/templates.d.ts +12 -0
- package/dist/core/collections/initiatives/templates.js +90 -0
- package/dist/core/collections/runtime.d.ts +46 -0
- package/dist/core/collections/runtime.js +194 -0
- package/dist/core/completions/command-registry.d.ts +1 -5
- package/dist/core/completions/command-registry.js +532 -32
- package/dist/core/completions/completion-provider.d.ts +11 -0
- package/dist/core/completions/completion-provider.js +27 -0
- package/dist/core/completions/generators/bash-generator.d.ts +3 -0
- package/dist/core/completions/generators/bash-generator.js +60 -4
- package/dist/core/completions/generators/fish-generator.js +3 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +3 -0
- package/dist/core/completions/generators/powershell-generator.js +63 -4
- package/dist/core/completions/generators/zsh-generator.d.ts +3 -0
- package/dist/core/completions/generators/zsh-generator.js +46 -22
- package/dist/core/completions/installers/zsh-installer.d.ts +0 -8
- package/dist/core/completions/installers/zsh-installer.js +3 -31
- package/dist/core/completions/shared-flags.d.ts +12 -0
- package/dist/core/completions/shared-flags.js +28 -0
- package/dist/core/completions/templates/bash-templates.d.ts +1 -1
- package/dist/core/completions/templates/bash-templates.js +6 -0
- package/dist/core/completions/templates/fish-templates.d.ts +1 -1
- package/dist/core/completions/templates/fish-templates.js +6 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +1 -1
- package/dist/core/completions/templates/powershell-templates.js +9 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +1 -1
- package/dist/core/completions/templates/zsh-templates.js +9 -0
- package/dist/core/completions/types.d.ts +23 -1
- package/dist/core/config.js +3 -1
- package/dist/core/context-store/binding.d.ts +53 -0
- package/dist/core/context-store/binding.js +197 -0
- package/dist/core/context-store/errors.d.ts +20 -0
- package/dist/core/context-store/errors.js +22 -0
- package/dist/core/context-store/foundation.d.ts +55 -0
- package/dist/core/context-store/foundation.js +321 -0
- package/dist/core/context-store/index.d.ts +6 -0
- package/dist/core/context-store/index.js +6 -0
- package/dist/core/context-store/operations.d.ts +85 -0
- package/dist/core/context-store/operations.js +528 -0
- package/dist/core/context-store/registry.d.ts +45 -0
- package/dist/core/context-store/registry.js +229 -0
- package/dist/core/global-config.d.ts +6 -1
- package/dist/core/global-config.js +15 -16
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.js +4 -0
- package/dist/core/parsers/requirement-blocks.js +5 -5
- package/dist/core/parsers/spec-structure.js +1 -1
- package/dist/core/planning-home.d.ts +21 -0
- package/dist/core/planning-home.js +108 -0
- package/dist/core/profiles.d.ts +1 -1
- package/dist/core/profiles.js +1 -1
- package/dist/core/specs-apply.js +1 -1
- package/dist/core/templates/workflows/apply-change.js +6 -0
- package/dist/core/templates/workflows/archive-change.js +21 -15
- package/dist/core/templates/workflows/bulk-archive-change.js +14 -10
- package/dist/core/templates/workflows/continue-change.js +6 -4
- package/dist/core/templates/workflows/explore.js +8 -10
- package/dist/core/templates/workflows/ff-change.js +8 -6
- package/dist/core/templates/workflows/new-change.js +6 -6
- package/dist/core/templates/workflows/onboard.js +13 -15
- package/dist/core/templates/workflows/propose.js +8 -6
- package/dist/core/templates/workflows/sync-specs.js +28 -10
- package/dist/core/templates/workflows/verify-change.js +10 -4
- package/dist/core/update.d.ts +5 -0
- package/dist/core/update.js +20 -0
- package/dist/core/validation/validator.d.ts +11 -0
- package/dist/core/validation/validator.js +19 -2
- package/dist/core/workspace/foundation.d.ts +67 -0
- package/dist/core/workspace/foundation.js +295 -0
- package/dist/core/workspace/index.d.ts +8 -0
- package/dist/core/workspace/index.js +8 -0
- package/dist/core/workspace/legacy-state.d.ts +28 -0
- package/dist/core/workspace/legacy-state.js +200 -0
- package/dist/core/workspace/link-input.d.ts +9 -0
- package/dist/core/workspace/link-input.js +32 -0
- package/dist/core/workspace/open-surface.d.ts +45 -0
- package/dist/core/workspace/open-surface.js +215 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +124 -0
- package/dist/core/workspace/registry.d.ts +24 -0
- package/dist/core/workspace/registry.js +146 -0
- package/dist/core/workspace/skills.d.ts +57 -0
- package/dist/core/workspace/skills.js +334 -0
- package/dist/core/workspace/state-io.d.ts +10 -0
- package/dist/core/workspace/state-io.js +121 -0
- package/dist/utils/change-metadata.d.ts +5 -2
- package/dist/utils/change-metadata.js +7 -13
- package/dist/utils/change-utils.d.ts +9 -0
- package/dist/utils/change-utils.js +7 -5
- package/package.json +2 -1
- package/schemas/workspace-planning/schema.yaml +72 -0
- package/schemas/workspace-planning/templates/design.md +33 -0
- package/schemas/workspace-planning/templates/proposal.md +28 -0
- package/schemas/workspace-planning/templates/spec.md +9 -0
- package/schemas/workspace-planning/templates/tasks.md +15 -0
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ openspec init
|
|
|
96
96
|
|
|
97
97
|
Now tell your AI: `/opsx:propose <what-you-want-to-build>`
|
|
98
98
|
|
|
99
|
-
If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:
|
|
99
|
+
If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`.
|
|
100
100
|
|
|
101
101
|
> [!NOTE]
|
|
102
102
|
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 25+ tools and growing.
|
|
@@ -115,6 +115,13 @@ If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/
|
|
|
115
115
|
→ **[Customization](docs/customization.md)**: make it yours
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
## Community schemas
|
|
119
|
+
|
|
120
|
+
Third-party schema bundles distributed via standalone repositories — these provide opinionated workflows that integrate OpenSpec with other tools, similar to how [github/spec-kit's community extension catalog](https://github.com/github/spec-kit/tree/main/extensions) handles tool integrations.
|
|
121
|
+
|
|
122
|
+
→ **[Browse the catalog](docs/customization.md#community-schemas)** in the customization docs.
|
|
123
|
+
|
|
124
|
+
|
|
118
125
|
## Why OpenSpec?
|
|
119
126
|
|
|
120
127
|
AI coding assistants are powerful but unpredictable when requirements live only in chat history. OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written.
|
|
@@ -150,7 +157,7 @@ openspec update
|
|
|
150
157
|
|
|
151
158
|
## Usage Notes
|
|
152
159
|
|
|
153
|
-
**Model selection**: OpenSpec works best with high-reasoning models. We recommend
|
|
160
|
+
**Model selection**: OpenSpec works best with high-reasoning models. We recommend Codex 5.5 and Opus 4.7 for both planning and implementation.
|
|
154
161
|
|
|
155
162
|
**Context hygiene**: OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session.
|
|
156
163
|
|
package/bin/openspec.js
CHANGED
package/dist/cli/index.d.ts
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -2,8 +2,9 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
5
6
|
import { promises as fs } from 'fs';
|
|
6
|
-
import { AI_TOOLS } from '../core/config.js';
|
|
7
|
+
import { AI_TOOLS, OPENSPEC_DIR_NAME } from '../core/config.js';
|
|
7
8
|
import { UpdateCommand } from '../core/update.js';
|
|
8
9
|
import { ListCommand } from '../core/list.js';
|
|
9
10
|
import { ArchiveCommand } from '../core/archive.js';
|
|
@@ -16,7 +17,11 @@ import { CompletionCommand } from '../commands/completion.js';
|
|
|
16
17
|
import { FeedbackCommand } from '../commands/feedback.js';
|
|
17
18
|
import { registerConfigCommand } from '../commands/config.js';
|
|
18
19
|
import { registerSchemaCommand } from '../commands/schema.js';
|
|
19
|
-
import {
|
|
20
|
+
import { registerWorkspaceCommand } from '../commands/workspace.js';
|
|
21
|
+
import { registerContextStoreCommand } from '../commands/context-store.js';
|
|
22
|
+
import { registerInitiativeCommand } from '../commands/initiative.js';
|
|
23
|
+
import { findWorkspaceRoot } from '../core/workspace/index.js';
|
|
24
|
+
import { statusCommand, instructionsCommand, applyInstructionsCommand, templatesCommand, schemasCommand, newChangeCommand, setChangeCommand, DEFAULT_SCHEMA, } from '../commands/workflow/index.js';
|
|
20
25
|
import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
|
|
21
26
|
const program = new Command();
|
|
22
27
|
const require = createRequire(import.meta.url);
|
|
@@ -65,6 +70,21 @@ program.hook('postAction', async () => {
|
|
|
65
70
|
});
|
|
66
71
|
const availableToolIds = AI_TOOLS.filter((tool) => tool.skillsDir).map((tool) => tool.value);
|
|
67
72
|
const toolsOptionDescription = `Configure AI tools non-interactively. Use "all", "none", or a comma-separated list of: ${availableToolIds.join(', ')}`;
|
|
73
|
+
async function hasRepoLocalOpenSpecProject(projectPath) {
|
|
74
|
+
try {
|
|
75
|
+
const stats = await fs.stat(path.join(projectPath, OPENSPEC_DIR_NAME));
|
|
76
|
+
return stats.isDirectory();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const code = typeof error === 'object' && error !== null && 'code' in error
|
|
80
|
+
? error.code
|
|
81
|
+
: undefined;
|
|
82
|
+
if (code !== 'ENOENT' && code !== 'ENOTDIR') {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
68
88
|
program
|
|
69
89
|
.command('init [path]')
|
|
70
90
|
.description('Initialize OpenSpec in your project')
|
|
@@ -137,6 +157,14 @@ program
|
|
|
137
157
|
try {
|
|
138
158
|
const resolvedPath = path.resolve(targetPath);
|
|
139
159
|
const updateCommand = new UpdateCommand({ force: options?.force });
|
|
160
|
+
if (await hasRepoLocalOpenSpecProject(resolvedPath)) {
|
|
161
|
+
await updateCommand.execute(resolvedPath);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const workspaceRoot = await findWorkspaceRoot(resolvedPath);
|
|
165
|
+
if (workspaceRoot) {
|
|
166
|
+
throw new Error('OpenSpec workspace detected. Run `openspec workspace update` to refresh workspace-local guidance and skills.');
|
|
167
|
+
}
|
|
140
168
|
await updateCommand.execute(resolvedPath);
|
|
141
169
|
}
|
|
142
170
|
catch (error) {
|
|
@@ -259,6 +287,9 @@ program
|
|
|
259
287
|
registerSpecCommand(program);
|
|
260
288
|
registerConfigCommand(program);
|
|
261
289
|
registerSchemaCommand(program);
|
|
290
|
+
registerWorkspaceCommand(program);
|
|
291
|
+
registerContextStoreCommand(program);
|
|
292
|
+
registerInitiativeCommand(program);
|
|
262
293
|
// Top-level validate command
|
|
263
294
|
program
|
|
264
295
|
.command('validate [item-name]')
|
|
@@ -467,7 +498,13 @@ newCmd
|
|
|
467
498
|
.command('change <name>')
|
|
468
499
|
.description('Create a new change directory')
|
|
469
500
|
.option('--description <text>', 'Description to add to README.md')
|
|
501
|
+
.option('--goal <text>', 'Workspace product goal to store with the change')
|
|
502
|
+
.option('--areas <names>', 'Comma-separated affected workspace link names')
|
|
503
|
+
.option('--initiative <id>', 'Link the repo-local change to an initiative')
|
|
504
|
+
.option('--store <id>', 'Context store id for --initiative')
|
|
505
|
+
.option('--store-path <path>', 'Existing local context store root for --initiative')
|
|
470
506
|
.option('--schema <name>', `Workflow schema to use (default: ${DEFAULT_SCHEMA})`)
|
|
507
|
+
.option('--json', 'Output as JSON')
|
|
471
508
|
.action(async (name, options) => {
|
|
472
509
|
try {
|
|
473
510
|
await newChangeCommand(name, options);
|
|
@@ -478,5 +515,30 @@ newCmd
|
|
|
478
515
|
process.exit(1);
|
|
479
516
|
}
|
|
480
517
|
});
|
|
481
|
-
|
|
518
|
+
// Set command group
|
|
519
|
+
const setCmd = program.command('set').description('Set checked-in OpenSpec metadata');
|
|
520
|
+
setCmd
|
|
521
|
+
.command('change <name>')
|
|
522
|
+
.description('Set repo-local change metadata')
|
|
523
|
+
.option('--initiative <id>', 'Link the repo-local change to an initiative')
|
|
524
|
+
.option('--store <id>', 'Context store id for --initiative')
|
|
525
|
+
.option('--store-path <path>', 'Existing local context store root for --initiative')
|
|
526
|
+
.option('--json', 'Output as JSON')
|
|
527
|
+
.action(async (name, options) => {
|
|
528
|
+
try {
|
|
529
|
+
await setChangeCommand(name, options);
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
console.log();
|
|
533
|
+
ora().fail(`Error: ${error.message}`);
|
|
534
|
+
process.exit(1);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
export { program };
|
|
538
|
+
export function runCli(argv = process.argv) {
|
|
539
|
+
program.parse(argv);
|
|
540
|
+
}
|
|
541
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
542
|
+
runCli();
|
|
543
|
+
}
|
|
482
544
|
//# sourceMappingURL=index.js.map
|
|
@@ -229,6 +229,13 @@ export class CompletionCommand {
|
|
|
229
229
|
}
|
|
230
230
|
break;
|
|
231
231
|
}
|
|
232
|
+
case 'schemas': {
|
|
233
|
+
const schemaNames = await this.completionProvider.getSchemaNames();
|
|
234
|
+
for (const name of schemaNames) {
|
|
235
|
+
console.log(`${name}\tschema`);
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
232
239
|
case 'archived-changes': {
|
|
233
240
|
const archivedIds = await getArchivedChangeIds();
|
|
234
241
|
for (const id of archivedIds) {
|
package/dist/commands/config.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getNestedValue, setNestedValue, deleteNestedValue, coerceValue, formatV
|
|
|
6
6
|
import { CORE_WORKFLOWS, ALL_WORKFLOWS, getProfileWorkflows } from '../core/profiles.js';
|
|
7
7
|
import { OPENSPEC_DIR_NAME } from '../core/config.js';
|
|
8
8
|
import { hasProjectConfigDrift } from '../core/profile-sync-drift.js';
|
|
9
|
+
import { findWorkspaceRoot, hasWorkspaceSkillProfileDrift, readOptionalWorkspaceViewState, } from '../core/workspace/index.js';
|
|
9
10
|
const WORKFLOW_PROMPT_META = {
|
|
10
11
|
propose: {
|
|
11
12
|
name: 'Propose change',
|
|
@@ -132,7 +133,17 @@ export function diffProfileState(before, after) {
|
|
|
132
133
|
lines,
|
|
133
134
|
};
|
|
134
135
|
}
|
|
135
|
-
function
|
|
136
|
+
async function resolveWorkspaceConfigProfileContext(cwd = process.cwd()) {
|
|
137
|
+
const workspaceRoot = await findWorkspaceRoot(cwd);
|
|
138
|
+
if (!workspaceRoot) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
root: workspaceRoot,
|
|
143
|
+
commandCwd: cwd,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function maybeWarnProjectConfigDrift(projectDir, state, colorize) {
|
|
136
147
|
const openspecDir = path.join(projectDir, OPENSPEC_DIR_NAME);
|
|
137
148
|
if (!fs.existsSync(openspecDir)) {
|
|
138
149
|
return;
|
|
@@ -142,6 +153,30 @@ function maybeWarnConfigDrift(projectDir, state, colorize) {
|
|
|
142
153
|
}
|
|
143
154
|
console.log(colorize('Warning: Global config is not applied to this project. Run `openspec update` to sync.'));
|
|
144
155
|
}
|
|
156
|
+
async function maybeWarnConfigDrift(state, colorize) {
|
|
157
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
158
|
+
if (workspaceContext) {
|
|
159
|
+
let viewState = null;
|
|
160
|
+
try {
|
|
161
|
+
viewState = await readOptionalWorkspaceViewState(workspaceContext.root);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (hasWorkspaceSkillProfileDrift(viewState)) {
|
|
167
|
+
console.log(colorize('Warning: Workspace-local agent skills are out of sync with the active global profile. Run `openspec workspace update` to sync.'));
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
maybeWarnProjectConfigDrift(process.cwd(), state, colorize);
|
|
172
|
+
}
|
|
173
|
+
function printConfigProfileApplyGuidance(workspaceContext) {
|
|
174
|
+
if (workspaceContext) {
|
|
175
|
+
console.log('Config updated. Run `openspec workspace update` to apply it to workspace-local skills.');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
console.log('Config updated. Run `openspec update` in your projects to apply.');
|
|
179
|
+
}
|
|
145
180
|
/**
|
|
146
181
|
* Register the config command and all its subcommands.
|
|
147
182
|
*
|
|
@@ -383,7 +418,8 @@ export function registerConfigCommand(program) {
|
|
|
383
418
|
config.workflows = [...CORE_WORKFLOWS];
|
|
384
419
|
// Preserve delivery setting
|
|
385
420
|
saveGlobalConfig(config);
|
|
386
|
-
|
|
421
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
422
|
+
printConfigProfileApplyGuidance(workspaceContext);
|
|
387
423
|
return;
|
|
388
424
|
}
|
|
389
425
|
if (preset) {
|
|
@@ -436,7 +472,7 @@ export function registerConfigCommand(program) {
|
|
|
436
472
|
});
|
|
437
473
|
if (action === 'keep') {
|
|
438
474
|
console.log('No config changes.');
|
|
439
|
-
maybeWarnConfigDrift(
|
|
475
|
+
await maybeWarnConfigDrift(currentState, chalk.yellow);
|
|
440
476
|
return;
|
|
441
477
|
}
|
|
442
478
|
const nextState = {
|
|
@@ -505,7 +541,7 @@ export function registerConfigCommand(program) {
|
|
|
505
541
|
const diff = diffProfileState(currentState, nextState);
|
|
506
542
|
if (!diff.hasChanges) {
|
|
507
543
|
console.log('No config changes.');
|
|
508
|
-
maybeWarnConfigDrift(
|
|
544
|
+
await maybeWarnConfigDrift(nextState, chalk.yellow);
|
|
509
545
|
return;
|
|
510
546
|
}
|
|
511
547
|
console.log(chalk.bold('\nConfig changes:'));
|
|
@@ -517,6 +553,29 @@ export function registerConfigCommand(program) {
|
|
|
517
553
|
config.delivery = nextState.delivery;
|
|
518
554
|
config.workflows = nextState.workflows;
|
|
519
555
|
saveGlobalConfig(config);
|
|
556
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
557
|
+
if (workspaceContext) {
|
|
558
|
+
const applyNow = await confirm({
|
|
559
|
+
message: 'Apply changes to this workspace now?',
|
|
560
|
+
default: true,
|
|
561
|
+
});
|
|
562
|
+
if (applyNow) {
|
|
563
|
+
try {
|
|
564
|
+
execSync('npx openspec workspace update', {
|
|
565
|
+
stdio: 'inherit',
|
|
566
|
+
cwd: workspaceContext.commandCwd,
|
|
567
|
+
});
|
|
568
|
+
console.log('Run `openspec workspace update` in your other workspaces to apply.');
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
console.error('`openspec workspace update` failed. Please run it manually to apply the profile changes.');
|
|
572
|
+
process.exitCode = 1;
|
|
573
|
+
}
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
printConfigProfileApplyGuidance(workspaceContext);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
520
579
|
// Check if inside an OpenSpec project
|
|
521
580
|
const projectDir = process.cwd();
|
|
522
581
|
const openspecDir = path.join(projectDir, OPENSPEC_DIR_NAME);
|
|
@@ -537,7 +596,7 @@ export function registerConfigCommand(program) {
|
|
|
537
596
|
return;
|
|
538
597
|
}
|
|
539
598
|
}
|
|
540
|
-
|
|
599
|
+
printConfigProfileApplyGuidance(null);
|
|
541
600
|
}
|
|
542
601
|
catch (error) {
|
|
543
602
|
if (isPromptCancellationError(error)) {
|