gmc-openspec 1.0.0 → 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 +2 -2
- package/bin/openspec.js +3 -1
- package/dist/cli/index.d.ts +4 -1
- package/dist/cli/index.js +36 -2
- package/dist/commands/config.js +4 -4
- 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.js +10 -2
- package/dist/commands/workflow/new-change.d.ts +4 -0
- package/dist/commands/workflow/new-change.js +72 -23
- 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 +2 -0
- package/dist/commands/workflow/status.js +3 -0
- 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 +16 -8
- package/dist/commands/workspace/open.js +40 -14
- 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 +14 -8
- package/dist/commands/workspace/operations.js +228 -160
- 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 +3 -0
- package/dist/commands/workspace/selection.js +42 -40
- 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 +15 -0
- package/dist/commands/workspace.js +59 -340
- package/dist/core/artifact-graph/index.d.ts +2 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +10 -23
- package/dist/core/artifact-graph/instruction-loader.js +28 -89
- package/dist/core/artifact-graph/types.d.ts +0 -7
- package/dist/core/artifact-graph/types.js +0 -19
- 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 +475 -70
- package/dist/core/completions/shared-flags.d.ts +12 -0
- package/dist/core/completions/shared-flags.js +28 -0
- package/dist/core/config.js +2 -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/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/planning-home.js +5 -21
- package/dist/core/validation/validator.d.ts +11 -0
- package/dist/core/validation/validator.js +19 -2
- package/dist/core/workspace/foundation.d.ts +28 -48
- package/dist/core/workspace/foundation.js +130 -214
- package/dist/core/workspace/index.d.ts +2 -0
- package/dist/core/workspace/index.js +2 -0
- package/dist/core/workspace/legacy-state.d.ts +28 -0
- package/dist/core/workspace/legacy-state.js +200 -0
- package/dist/core/workspace/open-surface.d.ts +29 -8
- package/dist/core/workspace/open-surface.js +122 -44
- package/dist/core/workspace/openers.js +11 -6
- package/dist/core/workspace/registry.d.ts +24 -0
- package/dist/core/workspace/registry.js +146 -0
- package/dist/core/workspace/skills.d.ts +4 -2
- package/dist/core/workspace/skills.js +2 -2
- package/dist/core/workspace/state-io.d.ts +10 -0
- package/dist/core/workspace/state-io.js +119 -0
- package/dist/utils/change-metadata.d.ts +5 -2
- package/dist/utils/change-metadata.js +6 -12
- package/dist/utils/change-utils.d.ts +2 -2
- package/package.json +17 -19
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getWorkspaceSkillToolIds } from '../../core/workspace/index.js';
|
|
2
|
+
function collectOption(value, previous) {
|
|
3
|
+
return [...previous, value];
|
|
4
|
+
}
|
|
5
|
+
function addWorkspaceSelectionOptions(command) {
|
|
6
|
+
return command
|
|
7
|
+
.option('--workspace <name>', 'Workspace name from known local workspace views')
|
|
8
|
+
.option('--json', 'Output as JSON')
|
|
9
|
+
.option('--no-interactive', 'Disable prompts');
|
|
10
|
+
}
|
|
11
|
+
export function registerWorkspaceCommandWith(program, workspaceCommand) {
|
|
12
|
+
const workspace = program
|
|
13
|
+
.command('workspace')
|
|
14
|
+
.description('Set up and inspect coordination workspaces');
|
|
15
|
+
workspace
|
|
16
|
+
.command('setup')
|
|
17
|
+
.description('Set up a workspace and link existing repos or folders')
|
|
18
|
+
.option('--name <name>', 'Workspace name')
|
|
19
|
+
.option('--link <link>', 'Repo or folder link. Use <path> or <name>=<path>.', collectOption, [])
|
|
20
|
+
.option('--opener <id>', 'Preferred opener: codex-cli, claude, github-copilot, or editor')
|
|
21
|
+
.option('--tools <tools>', `Install OpenSpec skills for agents. Use "all", "none", or a comma-separated list of: ${getWorkspaceSkillToolIds().join(', ')}`)
|
|
22
|
+
.option('--json', 'Output as JSON')
|
|
23
|
+
.option('--no-interactive', 'Disable prompts')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
await workspaceCommand.setup(options);
|
|
26
|
+
});
|
|
27
|
+
workspace
|
|
28
|
+
.command('list')
|
|
29
|
+
.description('List known OpenSpec workspaces')
|
|
30
|
+
.option('--json', 'Output as JSON')
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
await workspaceCommand.list(options);
|
|
33
|
+
});
|
|
34
|
+
workspace
|
|
35
|
+
.command('ls')
|
|
36
|
+
.description('List known OpenSpec workspaces')
|
|
37
|
+
.option('--json', 'Output as JSON')
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
await workspaceCommand.list(options);
|
|
40
|
+
});
|
|
41
|
+
addWorkspaceSelectionOptions(workspace
|
|
42
|
+
.command('link [nameOrPath] [path]')
|
|
43
|
+
.description('Link an existing repo or folder to a workspace')).action(async (nameOrPath, linkPath, options) => {
|
|
44
|
+
await workspaceCommand.link(nameOrPath, linkPath, options);
|
|
45
|
+
});
|
|
46
|
+
addWorkspaceSelectionOptions(workspace
|
|
47
|
+
.command('relink <name> <path>')
|
|
48
|
+
.description('Update the local path for an existing workspace link')).action(async (linkName, linkPath, options) => {
|
|
49
|
+
await workspaceCommand.relink(linkName, linkPath, options);
|
|
50
|
+
});
|
|
51
|
+
addWorkspaceSelectionOptions(workspace
|
|
52
|
+
.command('doctor')
|
|
53
|
+
.description('Check what a workspace can resolve on this machine')).action(async (options) => {
|
|
54
|
+
await workspaceCommand.doctor(options);
|
|
55
|
+
});
|
|
56
|
+
workspace
|
|
57
|
+
.command('update [name]')
|
|
58
|
+
.description('Refresh workspace-local OpenSpec guidance and agent skills')
|
|
59
|
+
.option('--workspace <name>', 'Workspace name from known local workspace views')
|
|
60
|
+
.option('--tools <tools>', `Select agents for workspace skills. Use "all", "none", or a comma-separated list of: ${getWorkspaceSkillToolIds().join(', ')}. Global profile selects workflows; --tools selects agents.`)
|
|
61
|
+
.option('--json', 'Output as JSON')
|
|
62
|
+
.option('--no-interactive', 'Disable prompts')
|
|
63
|
+
.action(async (name, options) => {
|
|
64
|
+
await workspaceCommand.update(name, options);
|
|
65
|
+
});
|
|
66
|
+
workspace
|
|
67
|
+
.command('open [name]')
|
|
68
|
+
.description('Open a workspace in an agent or VS Code editor')
|
|
69
|
+
.option('--workspace <name>', 'Workspace name from known local workspace views')
|
|
70
|
+
.option('--initiative <id>', 'Open an initiative as a local workspace view')
|
|
71
|
+
.option('--store <id>', 'Context store id for --initiative')
|
|
72
|
+
.option('--store-path <path>', 'Existing local context store root for --initiative')
|
|
73
|
+
.option('--agent <tool>', 'Use an agent for this session: codex-cli, claude, or github-copilot')
|
|
74
|
+
.option('--editor', 'Open the workspace in VS Code editor mode')
|
|
75
|
+
.option('--prepare-only', 'Unsupported: preview surfaces belong to a future context/query command')
|
|
76
|
+
.option('--json', 'Output generated workspace view context as JSON after launch')
|
|
77
|
+
.option('--change <id>', 'Unsupported: change-scoped open belongs to future workspace change planning')
|
|
78
|
+
.option('--no-interactive', 'Disable prompts')
|
|
79
|
+
.action(async (name, options) => {
|
|
80
|
+
await workspaceCommand.open(name, options);
|
|
81
|
+
});
|
|
82
|
+
// Intentionally no public `workspace create` command in this slice.
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=registration.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { type WorkspaceRegistryEntry } from '../../core/workspace/index.js';
|
|
1
2
|
import { SelectedWorkspace, WorkspaceSelectionOptions } from './types.js';
|
|
3
|
+
export declare function selectedWorkspaceFromEntry(entry: WorkspaceRegistryEntry): SelectedWorkspace;
|
|
4
|
+
export declare function selectedWorkspaceFromRoot(currentWorkspaceRoot: string, entries: WorkspaceRegistryEntry[]): Promise<SelectedWorkspace>;
|
|
2
5
|
export declare function selectWorkspaceRootForCommand(workspaceRoot: string): Promise<SelectedWorkspace>;
|
|
3
6
|
export declare function selectWorkspaceForCommand(options: WorkspaceSelectionOptions, commandName: string, selectionOptions?: {
|
|
4
7
|
preferPositionalName?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { findWorkspaceRoot,
|
|
1
|
+
import { findWorkspaceRoot, listKnownWorkspaceEntries, readWorkspaceViewState, } from '../../core/workspace/index.js';
|
|
2
2
|
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
3
3
|
import { isInteractive, resolveNoInteractive } from '../../utils/interactive.js';
|
|
4
|
-
import {
|
|
4
|
+
import { validateWorkspaceNameForSetup } from './operations.js';
|
|
5
5
|
import { WorkspaceCliError, makeStatus, } from './types.js';
|
|
6
6
|
function normalizeRegistryRootForComparison(workspaceRoot) {
|
|
7
7
|
try {
|
|
@@ -11,30 +11,41 @@ function normalizeRegistryRootForComparison(workspaceRoot) {
|
|
|
11
11
|
return workspaceRoot;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
return makeStatus('warning', '
|
|
14
|
+
function workspaceNotInKnownViewsWarning() {
|
|
15
|
+
return makeStatus('warning', 'workspace_not_in_known_views', 'This workspace is not in the managed local workspace views list.', {
|
|
16
16
|
target: 'workspace.root',
|
|
17
|
-
fix: '
|
|
17
|
+
fix: 'Use openspec workspace list to inspect managed workspace views.',
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
return (
|
|
22
|
-
normalizeRegistryRootForComparison(
|
|
20
|
+
function sameWorkspaceRoot(knownRoot, currentWorkspaceRoot) {
|
|
21
|
+
return (knownRoot !== undefined &&
|
|
22
|
+
normalizeRegistryRootForComparison(knownRoot) ===
|
|
23
23
|
normalizeRegistryRootForComparison(currentWorkspaceRoot));
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
function findKnownWorkspaceByName(entries, workspaceName) {
|
|
26
|
+
return entries.find((entry) => entry.name === workspaceName);
|
|
27
|
+
}
|
|
28
|
+
export function selectedWorkspaceFromEntry(entry) {
|
|
29
29
|
return {
|
|
30
|
-
name:
|
|
30
|
+
name: entry.name,
|
|
31
|
+
root: entry.workspaceRoot,
|
|
32
|
+
status: [],
|
|
33
|
+
unregisteredCurrentWorkspace: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export async function selectedWorkspaceFromRoot(currentWorkspaceRoot, entries) {
|
|
37
|
+
const viewState = await readWorkspaceViewState(currentWorkspaceRoot);
|
|
38
|
+
const knownRoot = findKnownWorkspaceByName(entries, viewState.name)?.workspaceRoot;
|
|
39
|
+
const isKnown = sameWorkspaceRoot(knownRoot, currentWorkspaceRoot);
|
|
40
|
+
return {
|
|
41
|
+
name: viewState.name,
|
|
31
42
|
root: currentWorkspaceRoot,
|
|
32
|
-
status:
|
|
33
|
-
unregisteredCurrentWorkspace: !
|
|
43
|
+
status: isKnown ? [] : [workspaceNotInKnownViewsWarning()],
|
|
44
|
+
unregisteredCurrentWorkspace: !isKnown,
|
|
34
45
|
};
|
|
35
46
|
}
|
|
36
47
|
export async function selectWorkspaceRootForCommand(workspaceRoot) {
|
|
37
|
-
const
|
|
48
|
+
const entries = await listKnownWorkspaceEntries();
|
|
38
49
|
const currentWorkspaceRoot = await findWorkspaceRoot(workspaceRoot);
|
|
39
50
|
if (!currentWorkspaceRoot) {
|
|
40
51
|
throw new WorkspaceCliError(`No OpenSpec workspace found at '${workspaceRoot}'.`, 'workspace_not_found', {
|
|
@@ -42,31 +53,25 @@ export async function selectWorkspaceRootForCommand(workspaceRoot) {
|
|
|
42
53
|
fix: 'Pass a path inside an OpenSpec workspace.',
|
|
43
54
|
});
|
|
44
55
|
}
|
|
45
|
-
return selectedWorkspaceFromRoot(currentWorkspaceRoot,
|
|
56
|
+
return selectedWorkspaceFromRoot(currentWorkspaceRoot, entries);
|
|
46
57
|
}
|
|
47
58
|
export async function selectWorkspaceForCommand(options, commandName, selectionOptions = {}) {
|
|
48
|
-
const
|
|
59
|
+
const entries = await listKnownWorkspaceEntries();
|
|
49
60
|
if (options.workspace) {
|
|
50
61
|
const workspaceName = validateWorkspaceNameForSetup(options.workspace);
|
|
51
|
-
const
|
|
52
|
-
if (!
|
|
62
|
+
const entry = findKnownWorkspaceByName(entries, workspaceName);
|
|
63
|
+
if (!entry) {
|
|
53
64
|
throw new WorkspaceCliError(`Unknown OpenSpec workspace '${workspaceName}'.`, 'workspace_not_found', {
|
|
54
65
|
target: 'workspace.name',
|
|
55
66
|
fix: 'Run openspec workspace list to see known workspaces.',
|
|
56
67
|
});
|
|
57
68
|
}
|
|
58
|
-
return
|
|
59
|
-
name: workspaceName,
|
|
60
|
-
root: registryRoot,
|
|
61
|
-
status: [],
|
|
62
|
-
unregisteredCurrentWorkspace: false,
|
|
63
|
-
};
|
|
69
|
+
return selectedWorkspaceFromEntry(entry);
|
|
64
70
|
}
|
|
65
71
|
const currentWorkspaceRoot = await findWorkspaceRoot(process.cwd());
|
|
66
72
|
if (currentWorkspaceRoot) {
|
|
67
|
-
return selectedWorkspaceFromRoot(currentWorkspaceRoot,
|
|
73
|
+
return selectedWorkspaceFromRoot(currentWorkspaceRoot, entries);
|
|
68
74
|
}
|
|
69
|
-
const entries = listWorkspaceRegistryEntries(registry);
|
|
70
75
|
if (entries.length === 0) {
|
|
71
76
|
throw new WorkspaceCliError("No known OpenSpec workspaces. Run 'openspec workspace setup' first.\nAfter at least one workspace is known locally, you can also pass --workspace <name>.", 'no_known_workspaces', {
|
|
72
77
|
target: 'workspace.name',
|
|
@@ -75,12 +80,7 @@ export async function selectWorkspaceForCommand(options, commandName, selectionO
|
|
|
75
80
|
}
|
|
76
81
|
if (entries.length === 1) {
|
|
77
82
|
const [entry] = entries;
|
|
78
|
-
return
|
|
79
|
-
name: entry.name,
|
|
80
|
-
root: entry.workspaceRoot,
|
|
81
|
-
status: [],
|
|
82
|
-
unregisteredCurrentWorkspace: false,
|
|
83
|
-
};
|
|
83
|
+
return selectedWorkspaceFromEntry(entry);
|
|
84
84
|
}
|
|
85
85
|
if (options.json || resolveNoInteractive(options) || !isInteractive(options)) {
|
|
86
86
|
const knownNames = entries.map((entry) => entry.name).join(', ');
|
|
@@ -103,11 +103,13 @@ export async function selectWorkspaceForCommand(options, commandName, selectionO
|
|
|
103
103
|
value: entry.name,
|
|
104
104
|
})),
|
|
105
105
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
const selectedEntry = findKnownWorkspaceByName(entries, selectedName);
|
|
107
|
+
if (!selectedEntry) {
|
|
108
|
+
throw new WorkspaceCliError(`Unknown OpenSpec workspace '${selectedName}'.`, 'workspace_not_found', {
|
|
109
|
+
target: 'workspace.name',
|
|
110
|
+
fix: 'Run openspec workspace list to see known workspaces.',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return selectedWorkspaceFromEntry(selectedEntry);
|
|
112
114
|
}
|
|
113
115
|
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PromptSetupLinksOptions {
|
|
2
|
+
heading?: string;
|
|
3
|
+
intro?: string;
|
|
4
|
+
allowEmpty?: boolean;
|
|
5
|
+
emptyName?: string;
|
|
6
|
+
emptyShort?: string;
|
|
7
|
+
emptyDescription?: string;
|
|
8
|
+
finishName?: string;
|
|
9
|
+
finishShort?: string;
|
|
10
|
+
finishDescription?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function promptSetupLinks(options?: PromptSetupLinksOptions): Promise<Record<string, string>>;
|
|
13
|
+
//# sourceMappingURL=setup-prompts.d.ts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as nodeFs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { inferLinkName, resolveExistingDirectory, validateLinkNameForCommand, } from './operations.js';
|
|
5
|
+
import { workspacePromptTheme, workspaceSelectTheme } from './prompt-theme.js';
|
|
6
|
+
import { asErrorMessage } from './types.js';
|
|
7
|
+
const fs = nodeFs;
|
|
8
|
+
async function promptExistingPath(message, defaultPath) {
|
|
9
|
+
const { input } = await import('@inquirer/prompts');
|
|
10
|
+
const pathInput = await input({
|
|
11
|
+
message,
|
|
12
|
+
default: defaultPath,
|
|
13
|
+
prefill: defaultPath ? 'editable' : undefined,
|
|
14
|
+
required: true,
|
|
15
|
+
theme: workspacePromptTheme,
|
|
16
|
+
validate(value) {
|
|
17
|
+
const resolvedPath = path.isAbsolute(value)
|
|
18
|
+
? path.resolve(value)
|
|
19
|
+
: path.resolve(process.cwd(), value);
|
|
20
|
+
return fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory()
|
|
21
|
+
? true
|
|
22
|
+
: 'Enter an existing repo or folder path.';
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
return resolveExistingDirectory(pathInput);
|
|
26
|
+
}
|
|
27
|
+
async function promptLinkName(existingLinks) {
|
|
28
|
+
const { input } = await import('@inquirer/prompts');
|
|
29
|
+
return input({
|
|
30
|
+
message: 'Link name:',
|
|
31
|
+
required: true,
|
|
32
|
+
theme: workspacePromptTheme,
|
|
33
|
+
validate(value) {
|
|
34
|
+
try {
|
|
35
|
+
validateLinkNameForCommand(value);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return asErrorMessage(error);
|
|
39
|
+
}
|
|
40
|
+
if (existingLinks[value]) {
|
|
41
|
+
return `Link name '${value}' is already linked to ${existingLinks[value]}.`;
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export async function promptSetupLinks(options = {}) {
|
|
48
|
+
const { select } = await import('@inquirer/prompts');
|
|
49
|
+
const links = {};
|
|
50
|
+
const heading = options.heading ?? '[2/5] Link repos or folders';
|
|
51
|
+
const intro = options.intro ?? 'Start with the current directory, or enter another repo path.';
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log(chalk.bold(heading));
|
|
54
|
+
console.log(chalk.dim(intro));
|
|
55
|
+
console.log('');
|
|
56
|
+
while (true) {
|
|
57
|
+
const linkCount = Object.keys(links).length;
|
|
58
|
+
if (linkCount === 0 && options.allowEmpty) {
|
|
59
|
+
const firstAction = await select({
|
|
60
|
+
message: 'Continue',
|
|
61
|
+
default: 'finish',
|
|
62
|
+
choices: [
|
|
63
|
+
{
|
|
64
|
+
name: options.emptyName ?? options.finishName ?? 'Create workspace files',
|
|
65
|
+
short: options.emptyShort ?? options.finishShort ?? 'Create workspace files',
|
|
66
|
+
value: 'finish',
|
|
67
|
+
description: options.emptyDescription ?? 'Create the workspace without linked repos or folders',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'Add a repo or folder',
|
|
71
|
+
short: 'Add repo',
|
|
72
|
+
value: 'add',
|
|
73
|
+
description: 'Include local implementation context in this workspace',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
theme: workspaceSelectTheme,
|
|
77
|
+
});
|
|
78
|
+
if (firstAction === 'finish') {
|
|
79
|
+
return links;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const resolvedPath = await promptExistingPath(linkCount === 0 ? 'Repo or folder path:' : 'Another repo or folder path:', linkCount === 0 ? '.' : undefined);
|
|
83
|
+
let linkName = inferLinkName(resolvedPath);
|
|
84
|
+
try {
|
|
85
|
+
validateLinkNameForCommand(linkName);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
linkName = await promptLinkName(links);
|
|
89
|
+
}
|
|
90
|
+
if (links[linkName]) {
|
|
91
|
+
console.log(`Link name '${linkName}' is already linked to ${links[linkName]}.`);
|
|
92
|
+
linkName = await promptLinkName(links);
|
|
93
|
+
}
|
|
94
|
+
links[linkName] = resolvedPath;
|
|
95
|
+
console.log(chalk.green(`Added link '${linkName}'`));
|
|
96
|
+
console.log(chalk.dim(` ${resolvedPath}`));
|
|
97
|
+
const nextAction = await select({
|
|
98
|
+
message: 'Continue',
|
|
99
|
+
default: 'finish',
|
|
100
|
+
choices: [
|
|
101
|
+
{
|
|
102
|
+
name: options.finishName ?? 'Create workspace files',
|
|
103
|
+
short: options.finishShort ?? 'Create workspace files',
|
|
104
|
+
value: 'finish',
|
|
105
|
+
description: options.finishDescription ?? 'Run a workspace check after setup',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Add another repo or folder',
|
|
109
|
+
short: 'Add another',
|
|
110
|
+
value: 'add',
|
|
111
|
+
description: 'Include another local directory in this workspace',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
theme: workspaceSelectTheme,
|
|
115
|
+
});
|
|
116
|
+
if (nextAction === 'finish') {
|
|
117
|
+
return links;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=setup-prompts.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ContextStoreSelector } from '../../core/context-store/index.js';
|
|
1
2
|
export type StatusSeverity = 'error' | 'warning';
|
|
2
3
|
export interface WorkspaceStatus {
|
|
3
4
|
severity: StatusSeverity;
|
|
@@ -5,6 +6,7 @@ export interface WorkspaceStatus {
|
|
|
5
6
|
message: string;
|
|
6
7
|
target?: string;
|
|
7
8
|
fix?: string;
|
|
9
|
+
details?: Record<string, unknown>;
|
|
8
10
|
}
|
|
9
11
|
export interface WorkspaceLinkOutput {
|
|
10
12
|
name: string;
|
|
@@ -12,16 +14,24 @@ export interface WorkspaceLinkOutput {
|
|
|
12
14
|
repo_specs_path?: string | null;
|
|
13
15
|
status: WorkspaceStatus[];
|
|
14
16
|
}
|
|
17
|
+
export interface WorkspaceContextOutput {
|
|
18
|
+
store: string;
|
|
19
|
+
initiative: string;
|
|
20
|
+
store_selector: ContextStoreSelector;
|
|
21
|
+
}
|
|
15
22
|
export interface WorkspaceOutput {
|
|
16
23
|
name: string;
|
|
17
24
|
root: string;
|
|
18
25
|
planning_path: string;
|
|
26
|
+
state_path?: string;
|
|
27
|
+
context?: WorkspaceContextOutput | null;
|
|
19
28
|
links: WorkspaceLinkOutput[];
|
|
20
29
|
status: WorkspaceStatus[];
|
|
21
30
|
}
|
|
22
31
|
export interface WorkspaceListOutput {
|
|
23
32
|
name: string;
|
|
24
33
|
root: string;
|
|
34
|
+
context?: WorkspaceContextOutput | null;
|
|
25
35
|
links: WorkspaceLinkOutput[];
|
|
26
36
|
status: WorkspaceStatus[];
|
|
27
37
|
}
|
|
@@ -50,6 +60,9 @@ export interface WorkspaceOpenOptions extends WorkspaceSelectionOptions {
|
|
|
50
60
|
editor?: boolean;
|
|
51
61
|
prepareOnly?: boolean;
|
|
52
62
|
change?: string;
|
|
63
|
+
initiative?: string;
|
|
64
|
+
store?: string;
|
|
65
|
+
storePath?: string;
|
|
53
66
|
}
|
|
54
67
|
export interface WorkspaceListOptions {
|
|
55
68
|
json?: boolean;
|
|
@@ -74,11 +87,13 @@ export declare class WorkspaceCliError extends Error {
|
|
|
74
87
|
constructor(message: string, code: string, options?: {
|
|
75
88
|
target?: string;
|
|
76
89
|
fix?: string;
|
|
90
|
+
details?: Record<string, unknown>;
|
|
77
91
|
});
|
|
78
92
|
}
|
|
79
93
|
export declare function makeStatus(severity: StatusSeverity, code: string, message: string, options?: {
|
|
80
94
|
target?: string;
|
|
81
95
|
fix?: string;
|
|
96
|
+
details?: Record<string, unknown>;
|
|
82
97
|
}): WorkspaceStatus;
|
|
83
98
|
export declare function asErrorMessage(error: unknown): string;
|
|
84
99
|
export declare function asStatus(error: unknown): WorkspaceStatus;
|