@fission-ai/openspec 1.4.1 → 1.6.0-beta.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 (241) hide show
  1. package/README.md +37 -4
  2. package/dist/cli/index.d.ts +5 -0
  3. package/dist/cli/index.js +95 -95
  4. package/dist/commands/change.d.ts +5 -2
  5. package/dist/commands/change.js +23 -55
  6. package/dist/commands/config.js +6 -65
  7. package/dist/commands/context.d.ts +3 -0
  8. package/dist/commands/context.js +155 -0
  9. package/dist/commands/doctor.d.ts +8 -0
  10. package/dist/commands/doctor.js +163 -0
  11. package/dist/commands/shared-gather.d.ts +14 -0
  12. package/dist/commands/shared-gather.js +31 -0
  13. package/dist/commands/shared-output.d.ts +18 -0
  14. package/dist/commands/shared-output.js +61 -0
  15. package/dist/commands/show.d.ts +11 -6
  16. package/dist/commands/show.js +70 -25
  17. package/dist/commands/spec.d.ts +5 -1
  18. package/dist/commands/spec.js +15 -4
  19. package/dist/commands/store.d.ts +3 -0
  20. package/dist/commands/store.js +547 -0
  21. package/dist/commands/validate.d.ts +10 -0
  22. package/dist/commands/validate.js +88 -40
  23. package/dist/commands/workflow/index.d.ts +0 -2
  24. package/dist/commands/workflow/index.js +0 -1
  25. package/dist/commands/workflow/instructions.d.ts +11 -1
  26. package/dist/commands/workflow/instructions.js +71 -22
  27. package/dist/commands/workflow/new-change.d.ts +6 -3
  28. package/dist/commands/workflow/new-change.js +42 -77
  29. package/dist/commands/workflow/shared.d.ts +15 -3
  30. package/dist/commands/workflow/shared.js +20 -3
  31. package/dist/commands/workflow/status.d.ts +2 -0
  32. package/dist/commands/workflow/status.js +19 -17
  33. package/dist/commands/workset-input.d.ts +19 -0
  34. package/dist/commands/workset-input.js +112 -0
  35. package/dist/commands/workset-prompts.d.ts +12 -0
  36. package/dist/commands/workset-prompts.js +143 -0
  37. package/dist/commands/workset.d.ts +25 -0
  38. package/dist/commands/workset.js +446 -0
  39. package/dist/core/archive.d.ts +17 -6
  40. package/dist/core/archive.js +220 -68
  41. package/dist/core/artifact-graph/index.d.ts +1 -1
  42. package/dist/core/artifact-graph/instruction-loader.d.ts +18 -13
  43. package/dist/core/artifact-graph/instruction-loader.js +8 -31
  44. package/dist/core/change-metadata/schema.d.ts +1 -0
  45. package/dist/core/change-metadata/schema.js +4 -2
  46. package/dist/core/change-status-policy.d.ts +5 -18
  47. package/dist/core/change-status-policy.js +2 -37
  48. package/dist/core/command-generation/adapters/bob.js +1 -14
  49. package/dist/core/command-generation/adapters/claude.d.ts +1 -1
  50. package/dist/core/command-generation/adapters/claude.js +4 -15
  51. package/dist/core/command-generation/adapters/cursor.js +1 -14
  52. package/dist/core/command-generation/adapters/index.d.ts +2 -0
  53. package/dist/core/command-generation/adapters/index.js +2 -0
  54. package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
  55. package/dist/core/command-generation/adapters/oh-my-pi.js +44 -0
  56. package/dist/core/command-generation/adapters/pi.js +1 -14
  57. package/dist/core/command-generation/adapters/trae.d.ts +13 -0
  58. package/dist/core/command-generation/adapters/trae.js +48 -0
  59. package/dist/core/command-generation/adapters/windsurf.js +1 -14
  60. package/dist/core/command-generation/registry.js +4 -0
  61. package/dist/core/command-generation/yaml.d.ts +22 -0
  62. package/dist/core/command-generation/yaml.js +38 -0
  63. package/dist/core/completions/command-registry.js +87 -289
  64. package/dist/core/completions/generators/zsh-generator.js +3 -1
  65. package/dist/core/completions/installers/bash-installer.js +3 -0
  66. package/dist/core/completions/installers/fish-installer.js +8 -0
  67. package/dist/core/completions/installers/powershell-installer.js +30 -2
  68. package/dist/core/completions/installers/zsh-installer.js +3 -0
  69. package/dist/core/completions/shared-flags.d.ts +1 -0
  70. package/dist/core/completions/shared-flags.js +5 -0
  71. package/dist/core/config-schema.d.ts +2 -1
  72. package/dist/core/config-schema.js +26 -0
  73. package/dist/core/config.js +1 -0
  74. package/dist/core/file-state.d.ts +36 -0
  75. package/dist/core/file-state.js +112 -0
  76. package/dist/core/global-config.d.ts +2 -0
  77. package/dist/core/id.d.ts +17 -0
  78. package/dist/core/id.js +30 -0
  79. package/dist/core/index.d.ts +3 -3
  80. package/dist/core/index.js +3 -3
  81. package/dist/core/init.js +27 -6
  82. package/dist/core/list.d.ts +2 -0
  83. package/dist/core/list.js +37 -14
  84. package/dist/core/openers.d.ts +77 -0
  85. package/dist/core/openers.js +251 -0
  86. package/dist/core/openspec-root.d.ts +45 -0
  87. package/dist/core/openspec-root.js +195 -0
  88. package/dist/core/parsers/change-parser.js +2 -1
  89. package/dist/core/parsers/markdown-parser.d.ts +0 -3
  90. package/dist/core/parsers/markdown-parser.js +5 -59
  91. package/dist/core/parsers/requirement-blocks.d.ts +11 -0
  92. package/dist/core/parsers/requirement-blocks.js +42 -8
  93. package/dist/core/parsers/requirement-text.d.ts +55 -0
  94. package/dist/core/parsers/requirement-text.js +136 -0
  95. package/dist/core/planning-home.d.ts +1 -6
  96. package/dist/core/planning-home.js +2 -43
  97. package/dist/core/profile-sync-drift.js +1 -0
  98. package/dist/core/profiles.d.ts +2 -2
  99. package/dist/core/profiles.js +2 -1
  100. package/dist/core/project-config.d.ts +44 -1
  101. package/dist/core/project-config.js +160 -10
  102. package/dist/core/references.d.ts +63 -0
  103. package/dist/core/references.js +310 -0
  104. package/dist/core/relationship-health.d.ts +65 -0
  105. package/dist/core/relationship-health.js +64 -0
  106. package/dist/core/root-selection.d.ts +122 -0
  107. package/dist/core/root-selection.js +337 -0
  108. package/dist/core/schemas/base.schema.js +7 -2
  109. package/dist/core/shared/allowed-tools.d.ts +12 -0
  110. package/dist/core/shared/allowed-tools.js +12 -0
  111. package/dist/core/shared/skill-generation.js +5 -1
  112. package/dist/core/shared/tool-detection.d.ts +2 -2
  113. package/dist/core/shared/tool-detection.js +2 -0
  114. package/dist/core/specs-apply.d.ts +6 -1
  115. package/dist/core/specs-apply.js +41 -5
  116. package/dist/core/store/errors.d.ts +20 -0
  117. package/dist/core/{context-store → store}/errors.js +3 -3
  118. package/dist/core/store/foundation.d.ts +56 -0
  119. package/dist/core/store/foundation.js +251 -0
  120. package/dist/core/store/git.d.ts +23 -0
  121. package/dist/core/store/git.js +137 -0
  122. package/dist/core/{context-store → store}/index.d.ts +0 -1
  123. package/dist/core/{context-store → store}/index.js +0 -1
  124. package/dist/core/store/operations.d.ts +114 -0
  125. package/dist/core/store/operations.js +803 -0
  126. package/dist/core/store/registry.d.ts +58 -0
  127. package/dist/core/store/registry.js +275 -0
  128. package/dist/core/templates/skill-templates.d.ts +1 -0
  129. package/dist/core/templates/skill-templates.js +1 -0
  130. package/dist/core/templates/workflows/apply-change.js +5 -4
  131. package/dist/core/templates/workflows/archive-change.js +5 -4
  132. package/dist/core/templates/workflows/bulk-archive-change.js +5 -4
  133. package/dist/core/templates/workflows/continue-change.js +7 -2
  134. package/dist/core/templates/workflows/explore.js +5 -0
  135. package/dist/core/templates/workflows/ff-change.js +5 -0
  136. package/dist/core/templates/workflows/new-change.js +5 -0
  137. package/dist/core/templates/workflows/onboard.js +4 -1
  138. package/dist/core/templates/workflows/propose.js +5 -0
  139. package/dist/core/templates/workflows/store-selection.d.ts +8 -0
  140. package/dist/core/templates/workflows/store-selection.js +8 -0
  141. package/dist/core/templates/workflows/sync-specs.js +5 -4
  142. package/dist/core/templates/workflows/update-change.d.ts +10 -0
  143. package/dist/core/templates/workflows/update-change.js +167 -0
  144. package/dist/core/templates/workflows/verify-change.js +5 -4
  145. package/dist/core/update.js +4 -4
  146. package/dist/core/validation/validator.d.ts +7 -0
  147. package/dist/core/validation/validator.js +101 -38
  148. package/dist/core/view.js +1 -1
  149. package/dist/core/working-set.d.ts +47 -0
  150. package/dist/core/working-set.js +43 -0
  151. package/dist/core/worksets.d.ts +75 -0
  152. package/dist/core/worksets.js +245 -0
  153. package/dist/core/zod-issues.d.ts +4 -0
  154. package/dist/core/zod-issues.js +10 -0
  155. package/dist/utils/change-metadata.d.ts +1 -0
  156. package/dist/utils/change-metadata.js +1 -1
  157. package/dist/utils/change-utils.js +15 -0
  158. package/dist/utils/file-system.js +36 -17
  159. package/dist/utils/task-progress.d.ts +10 -1
  160. package/dist/utils/task-progress.js +66 -2
  161. package/package.json +26 -23
  162. package/dist/commands/context-store.d.ts +0 -3
  163. package/dist/commands/context-store.js +0 -475
  164. package/dist/commands/initiative.d.ts +0 -13
  165. package/dist/commands/initiative.js +0 -318
  166. package/dist/commands/workflow/initiative-link.d.ts +0 -24
  167. package/dist/commands/workflow/initiative-link.js +0 -47
  168. package/dist/commands/workflow/set-change.d.ts +0 -13
  169. package/dist/commands/workflow/set-change.js +0 -87
  170. package/dist/commands/workspace/context-status.d.ts +0 -4
  171. package/dist/commands/workspace/context-status.js +0 -59
  172. package/dist/commands/workspace/open-target-selection.d.ts +0 -13
  173. package/dist/commands/workspace/open-target-selection.js +0 -146
  174. package/dist/commands/workspace/open-view.d.ts +0 -62
  175. package/dist/commands/workspace/open-view.js +0 -249
  176. package/dist/commands/workspace/open.d.ts +0 -37
  177. package/dist/commands/workspace/open.js +0 -110
  178. package/dist/commands/workspace/opener-selection.d.ts +0 -11
  179. package/dist/commands/workspace/opener-selection.js +0 -98
  180. package/dist/commands/workspace/operations.d.ts +0 -29
  181. package/dist/commands/workspace/operations.js +0 -543
  182. package/dist/commands/workspace/prompt-theme.d.ts +0 -29
  183. package/dist/commands/workspace/prompt-theme.js +0 -24
  184. package/dist/commands/workspace/registration.d.ts +0 -13
  185. package/dist/commands/workspace/registration.js +0 -84
  186. package/dist/commands/workspace/selection.d.ts +0 -8
  187. package/dist/commands/workspace/selection.js +0 -104
  188. package/dist/commands/workspace/setup-prompts.d.ts +0 -13
  189. package/dist/commands/workspace/setup-prompts.js +0 -121
  190. package/dist/commands/workspace/types.d.ts +0 -103
  191. package/dist/commands/workspace/types.js +0 -36
  192. package/dist/commands/workspace.d.ts +0 -5
  193. package/dist/commands/workspace.js +0 -574
  194. package/dist/core/collections/index.d.ts +0 -3
  195. package/dist/core/collections/index.js +0 -3
  196. package/dist/core/collections/initiatives/collection.d.ts +0 -4
  197. package/dist/core/collections/initiatives/collection.js +0 -17
  198. package/dist/core/collections/initiatives/index.d.ts +0 -6
  199. package/dist/core/collections/initiatives/index.js +0 -6
  200. package/dist/core/collections/initiatives/operations.d.ts +0 -49
  201. package/dist/core/collections/initiatives/operations.js +0 -175
  202. package/dist/core/collections/initiatives/resolution.d.ts +0 -87
  203. package/dist/core/collections/initiatives/resolution.js +0 -374
  204. package/dist/core/collections/initiatives/schema.d.ts +0 -41
  205. package/dist/core/collections/initiatives/schema.js +0 -134
  206. package/dist/core/collections/initiatives/templates.d.ts +0 -12
  207. package/dist/core/collections/initiatives/templates.js +0 -90
  208. package/dist/core/collections/runtime.d.ts +0 -46
  209. package/dist/core/collections/runtime.js +0 -194
  210. package/dist/core/context-store/binding.d.ts +0 -53
  211. package/dist/core/context-store/binding.js +0 -197
  212. package/dist/core/context-store/errors.d.ts +0 -20
  213. package/dist/core/context-store/foundation.d.ts +0 -55
  214. package/dist/core/context-store/foundation.js +0 -321
  215. package/dist/core/context-store/operations.d.ts +0 -85
  216. package/dist/core/context-store/operations.js +0 -528
  217. package/dist/core/context-store/registry.d.ts +0 -45
  218. package/dist/core/context-store/registry.js +0 -229
  219. package/dist/core/workspace/foundation.d.ts +0 -67
  220. package/dist/core/workspace/foundation.js +0 -295
  221. package/dist/core/workspace/index.d.ts +0 -8
  222. package/dist/core/workspace/index.js +0 -8
  223. package/dist/core/workspace/legacy-state.d.ts +0 -28
  224. package/dist/core/workspace/legacy-state.js +0 -200
  225. package/dist/core/workspace/link-input.d.ts +0 -9
  226. package/dist/core/workspace/link-input.js +0 -32
  227. package/dist/core/workspace/open-surface.d.ts +0 -45
  228. package/dist/core/workspace/open-surface.js +0 -215
  229. package/dist/core/workspace/openers.d.ts +0 -21
  230. package/dist/core/workspace/openers.js +0 -124
  231. package/dist/core/workspace/registry.d.ts +0 -24
  232. package/dist/core/workspace/registry.js +0 -146
  233. package/dist/core/workspace/skills.d.ts +0 -57
  234. package/dist/core/workspace/skills.js +0 -334
  235. package/dist/core/workspace/state-io.d.ts +0 -10
  236. package/dist/core/workspace/state-io.js +0 -121
  237. package/schemas/workspace-planning/schema.yaml +0 -72
  238. package/schemas/workspace-planning/templates/design.md +0 -33
  239. package/schemas/workspace-planning/templates/proposal.md +0 -28
  240. package/schemas/workspace-planning/templates/spec.md +0 -9
  241. package/schemas/workspace-planning/templates/tasks.md +0 -15
@@ -1,146 +0,0 @@
1
- import { InitiativeResolutionError, initiativeDiagnosticFromError, listInitiativeViewReferences, } from '../../core/collections/initiatives/index.js';
2
- import { createRegisteredContextStoreBinding, sameContextStoreBinding, } from '../../core/context-store/index.js';
3
- import { findWorkspaceRoot, getWorkspaceContextInitiativeId, listKnownWorkspaceEntries, readWorkspaceViewState, } from '../../core/workspace/index.js';
4
- import { isInteractive, resolveNoInteractive } from '../../utils/interactive.js';
5
- import { selectWorkspaceForCommand, selectedWorkspaceFromEntry, selectedWorkspaceFromRoot, } from './selection.js';
6
- import { WorkspaceCliError, } from './types.js';
7
- async function readKnownWorkspaceContexts(entries) {
8
- return Promise.all(entries.map(async (entry) => {
9
- try {
10
- return (await readWorkspaceViewState(entry.workspaceRoot)).context;
11
- }
12
- catch {
13
- // Broken workspaces are surfaced by list/doctor; open target selection
14
- // should not hide otherwise openable initiatives behind unreadable views.
15
- return null;
16
- }
17
- }));
18
- }
19
- function workspaceContextMatchesInitiative(context, initiative) {
20
- return (context !== null &&
21
- sameContextStoreBinding(context.store, createRegisteredContextStoreBinding(initiative.store)) &&
22
- getWorkspaceContextInitiativeId(context) === initiative.id);
23
- }
24
- function initiativeHasKnownWorkspace(contexts, initiative) {
25
- return contexts.some((context) => workspaceContextMatchesInitiative(context, initiative));
26
- }
27
- function initiativeDiagnosticToWorkspaceStatus(diagnostic) {
28
- return {
29
- severity: diagnostic.severity,
30
- code: diagnostic.code,
31
- message: diagnostic.message,
32
- target: diagnostic.target,
33
- fix: diagnostic.fix,
34
- details: diagnostic.details,
35
- };
36
- }
37
- async function listOpenableInitiatives(entries) {
38
- try {
39
- const [result, contexts] = await Promise.all([
40
- listInitiativeViewReferences(),
41
- readKnownWorkspaceContexts(entries),
42
- ]);
43
- const initiatives = [];
44
- for (const initiative of result.initiatives) {
45
- if (!initiativeHasKnownWorkspace(contexts, initiative)) {
46
- initiatives.push(initiative);
47
- }
48
- }
49
- return {
50
- kind: 'listed',
51
- initiatives,
52
- status: result.status.map(initiativeDiagnosticToWorkspaceStatus),
53
- };
54
- }
55
- catch (error) {
56
- const diagnostic = error instanceof InitiativeResolutionError
57
- ? initiativeDiagnosticFromError(error)
58
- : {
59
- severity: 'error',
60
- code: 'initiative_discovery_failed',
61
- message: error instanceof Error ? error.message : String(error),
62
- target: 'initiative',
63
- fix: 'openspec context-store doctor',
64
- };
65
- return {
66
- kind: 'unavailable',
67
- initiatives: [],
68
- status: [initiativeDiagnosticToWorkspaceStatus(diagnostic)],
69
- error: new WorkspaceCliError(diagnostic.message, diagnostic.code, {
70
- target: diagnostic.target,
71
- fix: diagnostic.fix,
72
- details: diagnostic.details,
73
- }),
74
- };
75
- }
76
- }
77
- export async function selectWorkspaceOpenTarget(workspaceName, options) {
78
- if (workspaceName ||
79
- options.json ||
80
- resolveNoInteractive(options) ||
81
- !isInteractive(options)) {
82
- return {
83
- kind: 'workspace',
84
- selected: await selectWorkspaceForCommand({
85
- ...options,
86
- workspace: workspaceName,
87
- }, 'open', { preferPositionalName: true }),
88
- status: [],
89
- };
90
- }
91
- const entries = await listKnownWorkspaceEntries();
92
- const currentWorkspaceRoot = await findWorkspaceRoot(process.cwd());
93
- if (currentWorkspaceRoot) {
94
- return {
95
- kind: 'workspace',
96
- selected: await selectedWorkspaceFromRoot(currentWorkspaceRoot, entries),
97
- status: [],
98
- };
99
- }
100
- const listed = await listOpenableInitiatives(entries);
101
- if (listed.initiatives.length === 0) {
102
- if (listed.kind === 'unavailable' && entries.length === 0) {
103
- throw listed.error;
104
- }
105
- return {
106
- kind: 'workspace',
107
- selected: await selectWorkspaceForCommand(options, 'open', {
108
- preferPositionalName: true,
109
- }),
110
- status: listed.status,
111
- };
112
- }
113
- const { select } = await import('@inquirer/prompts');
114
- const selected = await select({
115
- message: 'Select workspace or initiative:',
116
- choices: [
117
- ...entries.map((entry) => ({
118
- name: `Workspace: ${entry.name} (${entry.workspaceRoot})`,
119
- value: {
120
- kind: 'workspace',
121
- entry,
122
- },
123
- })),
124
- ...listed.initiatives.map((initiative) => ({
125
- name: `Initiative: ${initiative.store}/${initiative.id} - ${initiative.title} (create local workspace view)`,
126
- value: {
127
- kind: 'initiative',
128
- initiative,
129
- },
130
- })),
131
- ],
132
- });
133
- if (selected.kind === 'workspace') {
134
- return {
135
- kind: 'workspace',
136
- selected: selectedWorkspaceFromEntry(selected.entry),
137
- status: listed.status,
138
- };
139
- }
140
- return {
141
- kind: 'initiative',
142
- initiative: selected.initiative,
143
- status: listed.status,
144
- };
145
- }
146
- //# sourceMappingURL=open-target-selection.js.map
@@ -1,62 +0,0 @@
1
- import { InitiativeViewReference } from '../../core/collections/initiatives/index.js';
2
- import { type ContextStoreBinding } from '../../core/context-store/index.js';
3
- import { WorkspaceContextState, WorkspacePreferredOpener } from '../../core/workspace/index.js';
4
- import { type WorkspaceOpenCommandBuildResult } from './open.js';
5
- import { SelectedWorkspace, WorkspaceOpenOptions, WorkspaceStatus } from './types.js';
6
- export interface PreparedWorkspaceOpen extends WorkspaceOpenCommandBuildResult {
7
- selected: SelectedWorkspace;
8
- opener: WorkspacePreferredOpener;
9
- initiative: InitiativeViewReference | null;
10
- workspaceContext: WorkspaceContextState | null;
11
- warnings: WorkspaceStatus[];
12
- }
13
- export interface WorkspaceOpenJsonPayload {
14
- schema_version: 1;
15
- workspace: {
16
- name: string;
17
- root: string;
18
- };
19
- context: {
20
- context_store: {
21
- id: string;
22
- root: string;
23
- selector?: ContextStoreBinding['selector'];
24
- };
25
- initiative: {
26
- id: string;
27
- title: string;
28
- root: string;
29
- metadata_path: string;
30
- store_path: string;
31
- };
32
- } | null;
33
- generated_files: {
34
- agents: string;
35
- code_workspace: string;
36
- };
37
- opened_roots: PreparedWorkspaceOpen['openedRoots'];
38
- skipped_roots: Array<{
39
- kind: 'link';
40
- name: string;
41
- path: string | null;
42
- reason: PreparedWorkspaceOpen['skipped'][number]['reason'];
43
- }>;
44
- advisory_edit_boundaries: {
45
- allowed_edit_roots: string[];
46
- coordination_roots: string[];
47
- enforcement: 'advisory';
48
- };
49
- opener: PreparedWorkspaceOpen['opener'] & {
50
- label: string;
51
- };
52
- launch: {
53
- attempted: true;
54
- status: 'succeeded';
55
- };
56
- warnings: WorkspaceStatus[];
57
- status: WorkspaceStatus[];
58
- }
59
- export declare function assertWorkspaceOpenSupportedOptions(options: WorkspaceOpenOptions): void;
60
- export declare function prepareWorkspaceOpen(positionalName: string | undefined, options: WorkspaceOpenOptions): Promise<PreparedWorkspaceOpen>;
61
- export declare function buildWorkspaceOpenJsonPayload(prepared: PreparedWorkspaceOpen): WorkspaceOpenJsonPayload;
62
- //# sourceMappingURL=open-view.d.ts.map
@@ -1,249 +0,0 @@
1
- import { InitiativeResolutionError, resolveInitiativeViewReference, resolveSelectedInitiativeViewReference, } from '../../core/collections/initiatives/index.js';
2
- import { createPathContextStoreBinding, createRegisteredContextStoreBinding, formatContextStoreBinding, resolveContextStoreBinding, } from '../../core/context-store/index.js';
3
- import { createWorkspaceInitiativeContext, getWorkspaceContextInitiativeId, getWorkspaceOpenerLabel, } from '../../core/workspace/index.js';
4
- import { isInteractive, resolveNoInteractive } from '../../utils/interactive.js';
5
- import { assertWorkspaceOpenerAvailable, buildWorkspaceOpenCommandForState, readWorkspaceOpenState, } from './open.js';
6
- import { selectOrCreateWorkspaceForInitiativeOpen, } from './operations.js';
7
- import { selectWorkspaceOpenTarget } from './open-target-selection.js';
8
- import { WorkspaceCliError, asErrorMessage, } from './types.js';
9
- import { resolveWorkspaceOpenOpener, resolveWorkspaceOpenOpenerOverride, } from './opener-selection.js';
10
- import { promptSetupLinks } from './setup-prompts.js';
11
- export function assertWorkspaceOpenSupportedOptions(options) {
12
- if (!options.initiative && (options.store || options.storePath)) {
13
- throw new WorkspaceCliError('workspace open accepts --store or --store-path only with --initiative.', 'workspace_open_store_without_initiative', {
14
- target: 'workspace.initiative',
15
- fix: 'Use openspec workspace open --initiative <id> --store <store>.',
16
- });
17
- }
18
- if (options.prepareOnly) {
19
- throw new WorkspaceCliError('workspace open supports launching through a selected opener; preview output is reserved for a future context/query surface.', 'workspace_open_prepare_only_unsupported', {
20
- target: 'workspace.open',
21
- fix: 'Run openspec workspace open with --agent <tool> or --editor.',
22
- });
23
- }
24
- if (options.change) {
25
- throw new WorkspaceCliError('workspace open currently supports root workspace open only; change-scoped open belongs to future workspace change planning.', 'workspace_open_change_unsupported', {
26
- target: 'workspace.change',
27
- fix: 'Open the root workspace, then start implementation from an explicit change workflow.',
28
- });
29
- }
30
- }
31
- function resolveOpenWorkspaceName(positionalName, options) {
32
- if (positionalName && options.workspace && positionalName !== options.workspace) {
33
- throw new WorkspaceCliError(`Conflicting workspace selectors: positional '${positionalName}' and --workspace '${options.workspace}'.`, 'workspace_selection_conflict', {
34
- target: 'workspace.name',
35
- fix: 'Use either the positional workspace name or --workspace with the same value.',
36
- });
37
- }
38
- return positionalName ?? options.workspace;
39
- }
40
- function initiativeErrorAsWorkspaceError(error) {
41
- if (error instanceof InitiativeResolutionError) {
42
- return new WorkspaceCliError(error.message, error.code, {
43
- target: error.target,
44
- fix: error.fix,
45
- details: error.details,
46
- });
47
- }
48
- return new WorkspaceCliError(asErrorMessage(error), 'initiative_error');
49
- }
50
- async function resolveWorkspaceOpenInitiative(options) {
51
- if (!options.initiative) {
52
- return null;
53
- }
54
- try {
55
- return await resolveInitiativeViewReference(options.initiative, {
56
- store: options.store,
57
- storePath: options.storePath,
58
- });
59
- }
60
- catch (error) {
61
- throw initiativeErrorAsWorkspaceError(error);
62
- }
63
- }
64
- async function resolveStoredWorkspaceInitiative(context) {
65
- const initiativeId = getWorkspaceContextInitiativeId(context);
66
- try {
67
- const resolvedStore = await resolveContextStoreBinding(context.store);
68
- const selected = {
69
- id: resolvedStore.id,
70
- root: resolvedStore.root,
71
- source: resolvedStore.source,
72
- };
73
- const initiative = await resolveSelectedInitiativeViewReference(selected, initiativeId);
74
- return {
75
- initiative,
76
- warnings: resolvedStore.warnings.map(contextStoreBindingWarningToStatus),
77
- };
78
- }
79
- catch (error) {
80
- if (error instanceof InitiativeResolutionError) {
81
- throw initiativeErrorAsWorkspaceError(error);
82
- }
83
- throw new WorkspaceCliError(`Workspace context store '${formatContextStoreBinding(context.store)}' could not be read: ${asErrorMessage(error)}`, 'workspace_context_store_unavailable', {
84
- target: 'workspace.context.store',
85
- fix: context.store.selector.kind === 'registry'
86
- ? 'openspec context-store doctor'
87
- : 'Check the path in .openspec-workspace/view.yaml.',
88
- });
89
- }
90
- }
91
- function contextStoreBindingWarningToStatus(warning) {
92
- return {
93
- severity: 'warning',
94
- code: warning.code,
95
- message: warning.message,
96
- target: warning.target ? `workspace.context.store.${warning.target}` : 'workspace.context.store',
97
- ...(warning.fix ? { fix: warning.fix } : {}),
98
- };
99
- }
100
- function contextStoreBindingFromInitiative(initiative) {
101
- return initiative.storeSource === 'path'
102
- ? createPathContextStoreBinding({
103
- id: initiative.store,
104
- path: initiative.storeRoot,
105
- })
106
- : createRegisteredContextStoreBinding(initiative.store);
107
- }
108
- function toWorkspaceOpenResolvedContext(initiative) {
109
- return {
110
- contextStore: {
111
- id: initiative.store,
112
- root: initiative.storeRoot,
113
- },
114
- initiative: {
115
- id: initiative.id,
116
- title: initiative.title,
117
- root: initiative.root,
118
- metadataPath: initiative.metadataPath,
119
- storePath: initiative.storePath,
120
- },
121
- };
122
- }
123
- function buildSkippedRootWarnings(skipped) {
124
- return skipped.map((link) => {
125
- const location = link.path ?? '(no local path recorded)';
126
- return {
127
- severity: 'warning',
128
- code: 'workspace_open_link_skipped',
129
- message: `Skipped linked repo or folder '${link.name}' because ${location} is not available.`,
130
- target: `links.${link.name}.path`,
131
- fix: `openspec workspace relink ${link.name} /path/to/${link.name}`,
132
- };
133
- });
134
- }
135
- export async function prepareWorkspaceOpen(positionalName, options) {
136
- assertWorkspaceOpenSupportedOptions(options);
137
- const workspaceName = resolveOpenWorkspaceName(positionalName, options);
138
- const openerOverride = resolveWorkspaceOpenOpenerOverride(options);
139
- const requestedInitiative = await resolveWorkspaceOpenInitiative(options);
140
- const target = requestedInitiative
141
- ? { kind: 'initiative', initiative: requestedInitiative, status: [] }
142
- : await selectWorkspaceOpenTarget(workspaceName, options);
143
- const interactiveCreate = target.kind === 'initiative'
144
- && !options.json
145
- && !resolveNoInteractive(options)
146
- && isInteractive(options);
147
- const baseSelected = target.kind === 'initiative'
148
- ? (await selectOrCreateWorkspaceForInitiativeOpen({
149
- workspaceName,
150
- context: createWorkspaceInitiativeContext(contextStoreBindingFromInitiative(target.initiative), target.initiative.id),
151
- preferredOpener: openerOverride,
152
- linksForNewWorkspace: interactiveCreate
153
- ? () => promptSetupLinks({
154
- heading: 'Link repos or folders for this workspace',
155
- intro: 'Choose local repos or folders to include when opening this initiative, or create the view without links for now.',
156
- allowEmpty: true,
157
- emptyName: 'Create without linked repos',
158
- emptyShort: 'Create without links',
159
- emptyDescription: 'Create the local workspace view and add repos or folders later',
160
- finishName: 'Create and open workspace',
161
- finishShort: 'Create and open',
162
- finishDescription: 'Create the local workspace view and continue opening it',
163
- })
164
- : undefined,
165
- })).selected
166
- : target.selected;
167
- const selected = {
168
- ...baseSelected,
169
- status: [...baseSelected.status, ...target.status],
170
- };
171
- const state = await readWorkspaceOpenState(selected);
172
- const stored = target.kind === 'workspace' && state.viewState.context
173
- ? await resolveStoredWorkspaceInitiative(state.viewState.context)
174
- : null;
175
- const initiative = target.kind === 'initiative' ? target.initiative : stored?.initiative ?? null;
176
- const resolvedContext = initiative ? toWorkspaceOpenResolvedContext(initiative) : null;
177
- const opener = await resolveWorkspaceOpenOpener(state.viewState, options);
178
- assertWorkspaceOpenerAvailable(opener, state.codeWorkspacePath);
179
- const buildResult = await buildWorkspaceOpenCommandForState(opener, selected.root, state, resolvedContext);
180
- return {
181
- ...buildResult,
182
- selected,
183
- opener,
184
- initiative,
185
- workspaceContext: state.viewState.context,
186
- warnings: [
187
- ...selected.status,
188
- ...(stored?.warnings ?? []),
189
- ...buildSkippedRootWarnings(buildResult.skipped),
190
- ],
191
- };
192
- }
193
- export function buildWorkspaceOpenJsonPayload(prepared) {
194
- const linkedEditRoots = prepared.openedRoots
195
- .filter((root) => root.kind === 'link')
196
- .map((root) => root.path);
197
- return {
198
- schema_version: 1,
199
- workspace: {
200
- name: prepared.selected.name,
201
- root: prepared.selected.root,
202
- },
203
- context: prepared.initiative
204
- ? {
205
- context_store: {
206
- id: prepared.initiative.store,
207
- root: prepared.initiative.storeRoot,
208
- ...(prepared.workspaceContext
209
- ? { selector: prepared.workspaceContext.store.selector }
210
- : {}),
211
- },
212
- initiative: {
213
- id: prepared.initiative.id,
214
- title: prepared.initiative.title,
215
- root: prepared.initiative.root,
216
- metadata_path: prepared.initiative.metadataPath,
217
- store_path: prepared.initiative.storePath,
218
- },
219
- }
220
- : null,
221
- generated_files: {
222
- agents: prepared.generated.agentsPath,
223
- code_workspace: prepared.generated.codeWorkspacePath,
224
- },
225
- opened_roots: prepared.openedRoots,
226
- skipped_roots: prepared.skipped.map((link) => ({
227
- kind: 'link',
228
- name: link.name,
229
- path: link.path,
230
- reason: link.reason,
231
- })),
232
- advisory_edit_boundaries: {
233
- allowed_edit_roots: linkedEditRoots,
234
- coordination_roots: prepared.initiative ? [prepared.initiative.root] : [],
235
- enforcement: 'advisory',
236
- },
237
- opener: {
238
- ...prepared.opener,
239
- label: getWorkspaceOpenerLabel(prepared.opener),
240
- },
241
- launch: {
242
- attempted: true,
243
- status: 'succeeded',
244
- },
245
- warnings: prepared.warnings,
246
- status: [],
247
- };
248
- }
249
- //# sourceMappingURL=open-view.js.map
@@ -1,37 +0,0 @@
1
- import { spawn as nodeSpawn } from 'node:child_process';
2
- import { WorkspacePreferredOpener, WorkspaceViewState, WorkspaceOpenResolvedContext, WorkspaceOpenSurfaceGeneration, WorkspaceSkippedOpenLink } from '../../core/workspace/index.js';
3
- import { SelectedWorkspace } from './types.js';
4
- export declare const WORKSPACE_OPEN_MINIMAL_PROMPT = "Open this OpenSpec workspace.";
5
- export interface WorkspaceOpenState {
6
- viewState: WorkspaceViewState;
7
- codeWorkspacePath: string;
8
- }
9
- export interface WorkspaceOpenLaunchCommand {
10
- executable: string;
11
- args: string[];
12
- cwd: string;
13
- openerLabel: string;
14
- }
15
- export type WorkspaceOpenedRoot = {
16
- kind: 'workspace' | 'initiative' | 'link';
17
- name?: string;
18
- path: string;
19
- };
20
- export interface WorkspaceOpenCommandBuildResult {
21
- command: WorkspaceOpenLaunchCommand;
22
- skipped: WorkspaceSkippedOpenLink[];
23
- generated: WorkspaceOpenSurfaceGeneration;
24
- openedRoots: WorkspaceOpenedRoot[];
25
- }
26
- export type WorkspaceOpenSpawn = typeof nodeSpawn;
27
- export interface WorkspaceOpenLaunchOptions {
28
- spawn?: WorkspaceOpenSpawn;
29
- isExecutableAvailable?: (executable: string) => boolean;
30
- stdio?: 'inherit' | 'ignore';
31
- }
32
- export declare function readWorkspaceOpenState(selected: SelectedWorkspace): Promise<WorkspaceOpenState>;
33
- export declare function buildWorkspaceOpenLaunchCommand(opener: WorkspacePreferredOpener, workspaceRoot: string, codeWorkspacePath: string, attachedPaths: string[]): WorkspaceOpenLaunchCommand;
34
- export declare function assertWorkspaceOpenerAvailable(opener: WorkspacePreferredOpener, codeWorkspacePath: string, isExecutableAvailable?: (executable: string) => boolean): void;
35
- export declare function buildWorkspaceOpenCommandForState(opener: WorkspacePreferredOpener, workspaceRoot: string, state: WorkspaceOpenState, resolvedContext?: WorkspaceOpenResolvedContext | null): Promise<WorkspaceOpenCommandBuildResult>;
36
- export declare function launchWorkspaceOpenCommand(command: WorkspaceOpenLaunchCommand, options?: WorkspaceOpenLaunchOptions): Promise<void>;
37
- //# sourceMappingURL=open.d.ts.map
@@ -1,110 +0,0 @@
1
- import { createRequire } from 'node:module';
2
- import { getWorkspaceCodeWorkspacePath, getWorkspaceOpenerExecutable, getWorkspaceOpenerLabel, isWorkspaceExecutableAvailable, readWorkspaceViewState, syncWorkspaceOpenSurface, } from '../../core/workspace/index.js';
3
- import { WorkspaceCliError, asErrorMessage } from './types.js';
4
- export const WORKSPACE_OPEN_MINIMAL_PROMPT = 'Open this OpenSpec workspace.';
5
- const CODEX_CLI_WRITABLE_ROOT_SANDBOX_ARGS = ['--sandbox', 'workspace-write'];
6
- const require = createRequire(import.meta.url);
7
- const spawn = require('cross-spawn');
8
- function isCodexCliOpener(opener) {
9
- const openerId = opener.id;
10
- return opener.kind === 'agent' && (openerId === 'codex-cli' || openerId === 'codex');
11
- }
12
- export async function readWorkspaceOpenState(selected) {
13
- const viewState = await readWorkspaceViewState(selected.root);
14
- return {
15
- viewState,
16
- codeWorkspacePath: getWorkspaceCodeWorkspacePath(selected.root, viewState.name),
17
- };
18
- }
19
- export function buildWorkspaceOpenLaunchCommand(opener, workspaceRoot, codeWorkspacePath, attachedPaths) {
20
- const executable = getWorkspaceOpenerExecutable(opener);
21
- const openerLabel = getWorkspaceOpenerLabel(opener);
22
- if (opener.kind === 'editor' || opener.id === 'github-copilot') {
23
- return {
24
- executable,
25
- args: [codeWorkspacePath],
26
- cwd: workspaceRoot,
27
- openerLabel,
28
- };
29
- }
30
- return {
31
- executable,
32
- args: [
33
- ...(isCodexCliOpener(opener) && attachedPaths.length > 0
34
- ? CODEX_CLI_WRITABLE_ROOT_SANDBOX_ARGS
35
- : []),
36
- ...attachedPaths.flatMap((linkedPath) => ['--add-dir', linkedPath]),
37
- WORKSPACE_OPEN_MINIMAL_PROMPT,
38
- ],
39
- cwd: workspaceRoot,
40
- openerLabel,
41
- };
42
- }
43
- export function assertWorkspaceOpenerAvailable(opener, codeWorkspacePath, isExecutableAvailable = isWorkspaceExecutableAvailable) {
44
- const executable = getWorkspaceOpenerExecutable(opener);
45
- if (isExecutableAvailable(executable)) {
46
- return;
47
- }
48
- const openerLabel = getWorkspaceOpenerLabel(opener);
49
- const manualPath = executable === 'code'
50
- ? ` You can open the workspace file manually: ${codeWorkspacePath}`
51
- : '';
52
- throw new WorkspaceCliError(`${openerLabel} requires '${executable}', but '${executable}' was not found on PATH.${manualPath}`, 'workspace_opener_unavailable', {
53
- target: 'workspace.opener',
54
- fix: `Install '${executable}' or choose another opener.`,
55
- });
56
- }
57
- export async function buildWorkspaceOpenCommandForState(opener, workspaceRoot, state, resolvedContext) {
58
- const openSurface = await syncWorkspaceOpenSurface(workspaceRoot, state.viewState, resolvedContext);
59
- const openedRoots = [
60
- { kind: 'workspace', path: workspaceRoot },
61
- ...(resolvedContext
62
- ? [
63
- {
64
- kind: 'initiative',
65
- name: resolvedContext.initiative.id,
66
- path: resolvedContext.initiative.root,
67
- },
68
- ]
69
- : []),
70
- ...openSurface.links.map((link) => ({
71
- kind: 'link',
72
- name: link.name,
73
- path: link.path,
74
- })),
75
- ];
76
- return {
77
- command: buildWorkspaceOpenLaunchCommand(opener, workspaceRoot, state.codeWorkspacePath, openedRoots
78
- .filter((root) => root.kind !== 'workspace')
79
- .map((root) => root.path)),
80
- skipped: openSurface.skipped,
81
- generated: openSurface.generated,
82
- openedRoots,
83
- };
84
- }
85
- export async function launchWorkspaceOpenCommand(command, options = {}) {
86
- const spawnCommand = options.spawn ?? spawn;
87
- await new Promise((resolve, reject) => {
88
- const child = spawnCommand(command.executable, command.args, {
89
- cwd: command.cwd,
90
- stdio: options.stdio ?? 'inherit',
91
- shell: false,
92
- });
93
- child.on('error', (error) => {
94
- reject(new WorkspaceCliError(`Could not launch ${command.openerLabel}: ${asErrorMessage(error)}`, 'workspace_opener_launch_failed', {
95
- target: 'workspace.opener',
96
- }));
97
- });
98
- child.on('close', (code, signal) => {
99
- if (code === 0) {
100
- resolve();
101
- return;
102
- }
103
- const reason = signal ? `signal ${signal}` : `exit code ${code}`;
104
- reject(new WorkspaceCliError(`${command.openerLabel} exited with ${reason}.`, 'workspace_opener_launch_failed', {
105
- target: 'workspace.opener',
106
- }));
107
- });
108
- });
109
- }
110
- //# sourceMappingURL=open.js.map
@@ -1,11 +0,0 @@
1
- import { WorkspacePreferredOpener } from '../../core/workspace/index.js';
2
- import { WorkspaceOpenOptions } from './types.js';
3
- export declare function promptPreferredOpener(message: string, openerChoices?: import("../../core/workspace/openers.js").WorkspaceOpenerChoice[]): Promise<WorkspacePreferredOpener>;
4
- export declare function parseSetupOpenerOption(opener: string | undefined): WorkspacePreferredOpener | undefined;
5
- export declare function parseWorkspaceAgentOverride(agent: string): WorkspacePreferredOpener;
6
- export declare function getPreferredWorkspaceSkillAgentId(preferredOpener: WorkspacePreferredOpener | undefined): string | null;
7
- export declare function resolveWorkspaceOpenOpenerOverride(options: WorkspaceOpenOptions): WorkspacePreferredOpener | undefined;
8
- export declare function resolveWorkspaceOpenOpener(localState: {
9
- preferred_opener?: WorkspacePreferredOpener;
10
- }, options: WorkspaceOpenOptions): Promise<WorkspacePreferredOpener>;
11
- //# sourceMappingURL=opener-selection.d.ts.map