synarcx 0.1.0
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/LICENSE +23 -0
- package/README.md +90 -0
- package/bin/synarcx.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +474 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +278 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +264 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +552 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +170 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +870 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +132 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +226 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +295 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +327 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +45 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +57 -0
- package/dist/commands/workflow/shared.js +117 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +75 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workspace/open.d.ts +29 -0
- package/dist/commands/workspace/open.js +84 -0
- package/dist/commands/workspace/operations.d.ts +18 -0
- package/dist/commands/workspace/operations.js +461 -0
- package/dist/commands/workspace/selection.d.ts +5 -0
- package/dist/commands/workspace/selection.js +90 -0
- package/dist/commands/workspace/types.d.ts +83 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +3 -0
- package/dist/commands/workspace.js +635 -0
- package/dist/core/archive.d.ts +11 -0
- package/dist/core/archive.js +319 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +8 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +217 -0
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +258 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +31 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.js +43 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/bob.d.ts +14 -0
- package/dist/core/command-generation/adapters/bob.js +45 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +32 -0
- package/dist/core/command-generation/adapters/index.js +32 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +26 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +26 -0
- package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
- package/dist/core/command-generation/adapters/lingma.js +30 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +27 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +55 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +98 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +596 -0
- package/dist/core/completions/completion-provider.d.ts +71 -0
- package/dist/core/completions/completion-provider.js +129 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +35 -0
- package/dist/core/completions/generators/bash-generator.js +230 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +160 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
- package/dist/core/completions/generators/powershell-generator.js +266 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
- package/dist/core/completions/generators/zsh-generator.js +274 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
- package/dist/core/completions/installers/powershell-installer.js +387 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
- package/dist/core/completions/installers/zsh-installer.js +421 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +30 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +45 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +34 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +45 -0
- package/dist/core/completions/types.d.ts +101 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +86 -0
- package/dist/core/config-schema.js +213 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.js +38 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +49 -0
- package/dist/core/global-config.js +124 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +4 -0
- package/dist/core/init.d.ts +37 -0
- package/dist/core/init.js +585 -0
- package/dist/core/legacy-cleanup.d.ts +169 -0
- package/dist/core/legacy-cleanup.js +578 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +172 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +197 -0
- package/dist/core/parsers/markdown-parser.d.ts +26 -0
- package/dist/core/parsers/markdown-parser.js +227 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.js +88 -0
- package/dist/core/profile-sync-drift.d.ts +38 -0
- package/dist/core/profile-sync-drift.js +197 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +37 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +224 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +90 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +152 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +393 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +15 -0
- package/dist/core/templates/skill-templates.js +14 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/analyze.d.ts +4 -0
- package/dist/core/templates/workflows/analyze.js +101 -0
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +308 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +271 -0
- package/dist/core/templates/workflows/clarify.d.ts +4 -0
- package/dist/core/templates/workflows/clarify.js +108 -0
- package/dist/core/templates/workflows/debug.d.ts +4 -0
- package/dist/core/templates/workflows/debug.js +117 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +479 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +216 -0
- package/dist/core/templates/workflows/sync.d.ts +4 -0
- package/dist/core/templates/workflows/sync.js +108 -0
- package/dist/core/update.d.ts +82 -0
- package/dist/core/update.js +555 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +418 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +169 -0
- package/dist/core/workspace/foundation.d.ts +79 -0
- package/dist/core/workspace/foundation.js +367 -0
- package/dist/core/workspace/index.d.ts +5 -0
- package/dist/core/workspace/index.js +5 -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 +24 -0
- package/dist/core/workspace/open-surface.js +137 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +119 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +28 -0
- package/dist/prompts/searchable-multi-select.js +159 -0
- package/dist/ui/ascii-patterns.d.ts +25 -0
- package/dist/ui/ascii-patterns.js +140 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +144 -0
- package/dist/utils/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +62 -0
- package/dist/utils/change-utils.js +122 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +41 -0
- package/dist/utils/file-system.js +301 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +73 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +76 -0
- package/schemas/synarcx/schema.yaml +153 -0
- package/schemas/synarcx/templates/design.md +19 -0
- package/schemas/synarcx/templates/proposal.md +23 -0
- package/schemas/synarcx/templates/spec.md +8 -0
- package/schemas/synarcx/templates/tasks.md +9 -0
- package/scripts/postinstall.js +83 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as nodeFs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { getDefaultWorkspaceOpenerChoiceValue, getWorkspaceOpenerLabel, isWorkspaceAgentOpenerId, listWorkspaceOpenerChoices, parseWorkspacePreferredOpenerValue, listWorkspaceRegistryEntries, } from '../core/workspace/index.js';
|
|
5
|
+
import { isInteractive, resolveNoInteractive } from '../utils/interactive.js';
|
|
6
|
+
import { addWorkspaceLink, createManagedWorkspace, inferLinkName, loadWorkspaceForDoctor, loadWorkspaceForList, parseSetupLinks, readRegistry, resolveExistingDirectory, updateWorkspaceLink, validateLinkNameForCommand, validateWorkspaceNameForSetup, } from './workspace/operations.js';
|
|
7
|
+
import { selectWorkspaceForCommand } from './workspace/selection.js';
|
|
8
|
+
import { assertWorkspaceOpenerAvailable, buildWorkspaceOpenCommandForState, launchWorkspaceOpenCommand, readWorkspaceOpenState, } from './workspace/open.js';
|
|
9
|
+
import { WorkspaceCliError, appendStatus, asErrorMessage, asStatus, } from './workspace/types.js';
|
|
10
|
+
function printJson(payload) {
|
|
11
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
12
|
+
}
|
|
13
|
+
const workspacePromptTheme = {
|
|
14
|
+
prefix: '',
|
|
15
|
+
style: {
|
|
16
|
+
answer: (text) => chalk.cyan(text),
|
|
17
|
+
defaultAnswer: (text) => chalk.dim(text),
|
|
18
|
+
error: (text) => chalk.red(text),
|
|
19
|
+
help: (text) => chalk.dim(text),
|
|
20
|
+
highlight: (text) => chalk.cyan(text),
|
|
21
|
+
key: (text) => chalk.cyan(text),
|
|
22
|
+
message: (text) => chalk.bold(text),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const workspaceSelectTheme = {
|
|
26
|
+
...workspacePromptTheme,
|
|
27
|
+
icon: {
|
|
28
|
+
cursor: chalk.cyan('>'),
|
|
29
|
+
},
|
|
30
|
+
style: {
|
|
31
|
+
...workspacePromptTheme.style,
|
|
32
|
+
keysHelpTip: (keys) => chalk.dim(keys.map(([key, action]) => `${key}: ${action}`).join(' | ')),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
function printWorkspaceSetupIntro() {
|
|
36
|
+
console.log(chalk.bold('Workspace setup'));
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
function isPromptCancellationError(error) {
|
|
40
|
+
return (error instanceof Error &&
|
|
41
|
+
(error.name === 'ExitPromptError' || error.message.includes('force closed the prompt with SIGINT')));
|
|
42
|
+
}
|
|
43
|
+
async function promptWorkspaceName(initialName) {
|
|
44
|
+
if (initialName) {
|
|
45
|
+
return validateWorkspaceNameForSetup(initialName);
|
|
46
|
+
}
|
|
47
|
+
const { input } = await import('@inquirer/prompts');
|
|
48
|
+
console.log(chalk.bold('[1/4] Name the workspace'));
|
|
49
|
+
console.log(chalk.dim('Use a stable name for the repo group, e.g. platform.'));
|
|
50
|
+
console.log('');
|
|
51
|
+
return input({
|
|
52
|
+
message: 'Workspace name:',
|
|
53
|
+
required: true,
|
|
54
|
+
theme: workspacePromptTheme,
|
|
55
|
+
validate(value) {
|
|
56
|
+
try {
|
|
57
|
+
validateWorkspaceNameForSetup(value);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return 'Workspace names must be kebab-case with lowercase letters, numbers, and single hyphen separators.';
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function promptExistingPath(message, defaultPath) {
|
|
67
|
+
const { input } = await import('@inquirer/prompts');
|
|
68
|
+
const pathInput = await input({
|
|
69
|
+
message,
|
|
70
|
+
default: defaultPath,
|
|
71
|
+
prefill: defaultPath ? 'editable' : undefined,
|
|
72
|
+
required: true,
|
|
73
|
+
theme: workspacePromptTheme,
|
|
74
|
+
validate(value) {
|
|
75
|
+
const resolvedPath = path.isAbsolute(value)
|
|
76
|
+
? path.resolve(value)
|
|
77
|
+
: path.resolve(process.cwd(), value);
|
|
78
|
+
return nodeFs.existsSync(resolvedPath) && nodeFs.statSync(resolvedPath).isDirectory()
|
|
79
|
+
? true
|
|
80
|
+
: 'Enter an existing repo or folder path.';
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return resolveExistingDirectory(pathInput);
|
|
84
|
+
}
|
|
85
|
+
async function promptLinkName(existingLinks) {
|
|
86
|
+
const { input } = await import('@inquirer/prompts');
|
|
87
|
+
return input({
|
|
88
|
+
message: 'Link name:',
|
|
89
|
+
required: true,
|
|
90
|
+
theme: workspacePromptTheme,
|
|
91
|
+
validate(value) {
|
|
92
|
+
try {
|
|
93
|
+
validateLinkNameForCommand(value);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return asErrorMessage(error);
|
|
97
|
+
}
|
|
98
|
+
if (existingLinks[value]) {
|
|
99
|
+
return `Link name '${value}' is already linked to ${existingLinks[value]}.`;
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function promptSetupLinks() {
|
|
106
|
+
const { select } = await import('@inquirer/prompts');
|
|
107
|
+
const links = {};
|
|
108
|
+
console.log('');
|
|
109
|
+
console.log(chalk.bold('[2/4] Link repos or folders'));
|
|
110
|
+
console.log(chalk.dim('Start with the current directory, or enter another repo path.'));
|
|
111
|
+
console.log('');
|
|
112
|
+
while (true) {
|
|
113
|
+
const linkCount = Object.keys(links).length;
|
|
114
|
+
const resolvedPath = await promptExistingPath(linkCount === 0 ? 'Repo or folder path:' : 'Another repo or folder path:', linkCount === 0 ? '.' : undefined);
|
|
115
|
+
let linkName = inferLinkName(resolvedPath);
|
|
116
|
+
try {
|
|
117
|
+
validateLinkNameForCommand(linkName);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
linkName = await promptLinkName(links);
|
|
121
|
+
}
|
|
122
|
+
if (links[linkName]) {
|
|
123
|
+
console.log(`Link name '${linkName}' is already linked to ${links[linkName]}.`);
|
|
124
|
+
linkName = await promptLinkName(links);
|
|
125
|
+
}
|
|
126
|
+
links[linkName] = resolvedPath;
|
|
127
|
+
console.log(chalk.green(`Added link '${linkName}'`));
|
|
128
|
+
console.log(chalk.dim(` ${resolvedPath}`));
|
|
129
|
+
const nextAction = await select({
|
|
130
|
+
message: 'Continue',
|
|
131
|
+
default: 'finish',
|
|
132
|
+
choices: [
|
|
133
|
+
{
|
|
134
|
+
name: 'Create workspace files',
|
|
135
|
+
short: 'Create workspace files',
|
|
136
|
+
value: 'finish',
|
|
137
|
+
description: 'Run a workspace check after setup',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'Add another repo or folder',
|
|
141
|
+
short: 'Add another',
|
|
142
|
+
value: 'add',
|
|
143
|
+
description: 'Include another local directory in this workspace',
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
theme: workspaceSelectTheme,
|
|
147
|
+
});
|
|
148
|
+
if (nextAction === 'finish') {
|
|
149
|
+
return links;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function formatOpenerChoiceName(choice) {
|
|
154
|
+
return choice.unavailableNote ? `${choice.label} (${choice.unavailableNote})` : choice.label;
|
|
155
|
+
}
|
|
156
|
+
async function promptPreferredOpener(message, openerChoices = listWorkspaceOpenerChoices()) {
|
|
157
|
+
const { select } = await import('@inquirer/prompts');
|
|
158
|
+
const selectedValue = await select({
|
|
159
|
+
message,
|
|
160
|
+
default: getDefaultWorkspaceOpenerChoiceValue(openerChoices),
|
|
161
|
+
choices: openerChoices.map((choice) => ({
|
|
162
|
+
name: formatOpenerChoiceName(choice),
|
|
163
|
+
short: choice.label,
|
|
164
|
+
value: choice.value,
|
|
165
|
+
description: choice.unavailableNote ?? `Use ${choice.label}`,
|
|
166
|
+
})),
|
|
167
|
+
theme: workspaceSelectTheme,
|
|
168
|
+
});
|
|
169
|
+
return parseWorkspacePreferredOpenerValue(selectedValue);
|
|
170
|
+
}
|
|
171
|
+
function parseSetupOpenerOption(opener) {
|
|
172
|
+
if (!opener) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
return parseWorkspacePreferredOpenerValue(opener);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
throw new WorkspaceCliError(asErrorMessage(error), 'unsupported_workspace_opener', {
|
|
180
|
+
target: 'workspace.opener',
|
|
181
|
+
fix: 'Use --opener codex, --opener claude, --opener github-copilot, or --opener editor.',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function parseAgentOverride(agent) {
|
|
186
|
+
if (!isWorkspaceAgentOpenerId(agent)) {
|
|
187
|
+
throw new WorkspaceCliError(`Unsupported workspace agent '${agent}'. Supported agents: codex, claude, github-copilot.`, 'unsupported_workspace_agent', {
|
|
188
|
+
target: 'workspace.opener',
|
|
189
|
+
fix: 'Use --agent codex, --agent claude, or --agent github-copilot.',
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
kind: 'agent',
|
|
194
|
+
id: agent,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function printStatusLines(statuses) {
|
|
198
|
+
for (const status of statuses) {
|
|
199
|
+
const label = status.severity === 'warning' ? 'Warning' : 'Issue';
|
|
200
|
+
console.log(`${label}: ${status.message}`);
|
|
201
|
+
if (status.fix) {
|
|
202
|
+
console.log(`Fix: ${status.fix}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function printLinksHuman(links) {
|
|
207
|
+
if (links.length === 0) {
|
|
208
|
+
console.log(' (no linked repos or folders)');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
for (const link of links) {
|
|
212
|
+
const suffix = link.status.some((status) => status.severity === 'error') ? ' [issue]' : '';
|
|
213
|
+
console.log(` ${link.name} -> ${link.path ?? '(no local path recorded)'}${suffix}`);
|
|
214
|
+
if (link.repo_specs_path) {
|
|
215
|
+
console.log(` repo specs: ${link.repo_specs_path}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function collectWorkspaceIssues(workspace) {
|
|
220
|
+
return [
|
|
221
|
+
...workspace.status,
|
|
222
|
+
...workspace.links.flatMap((link) => link.status),
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
function printDoctorHuman(result) {
|
|
226
|
+
console.log(`Workspace: ${result.workspace.name}`);
|
|
227
|
+
console.log(`Location: ${result.workspace.root}`);
|
|
228
|
+
console.log(`Planning path: ${result.workspace.planning_path}`);
|
|
229
|
+
console.log('');
|
|
230
|
+
printStatusLines(result.status);
|
|
231
|
+
if (result.status.length > 0) {
|
|
232
|
+
console.log('');
|
|
233
|
+
}
|
|
234
|
+
console.log('Linked repos or folders:');
|
|
235
|
+
printLinksHuman(result.workspace.links);
|
|
236
|
+
const issues = collectWorkspaceIssues(result.workspace);
|
|
237
|
+
if (issues.length === 0) {
|
|
238
|
+
console.log('');
|
|
239
|
+
console.log('No workspace issues found.');
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
console.log('');
|
|
243
|
+
console.log('Issues:');
|
|
244
|
+
for (const issue of issues) {
|
|
245
|
+
console.log(` - ${issue.message}`);
|
|
246
|
+
if (issue.target) {
|
|
247
|
+
console.log(` Target: ${issue.target}`);
|
|
248
|
+
}
|
|
249
|
+
if (issue.fix) {
|
|
250
|
+
console.log(` Fix: ${issue.fix}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function printWorkspaceListHuman(workspaces) {
|
|
255
|
+
console.log(chalk.bold(`synarcx workspaces (${workspaces.length})`));
|
|
256
|
+
for (const workspace of workspaces) {
|
|
257
|
+
console.log('');
|
|
258
|
+
console.log(chalk.bold(workspace.name));
|
|
259
|
+
console.log(` Location: ${workspace.root}`);
|
|
260
|
+
if (workspace.status.length > 0) {
|
|
261
|
+
console.log(' Status:');
|
|
262
|
+
for (const status of workspace.status) {
|
|
263
|
+
const statusLabel = status.severity === 'warning' ? chalk.yellow('Warning') : chalk.red('Issue');
|
|
264
|
+
console.log(` ${statusLabel}: ${status.message}`);
|
|
265
|
+
if (status.fix) {
|
|
266
|
+
console.log(` Fix: ${status.fix}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
console.log(` Linked repos or folders (${workspace.links.length}):`);
|
|
271
|
+
if (workspace.links.length === 0) {
|
|
272
|
+
console.log(chalk.dim(' (none)'));
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
for (const link of workspace.links) {
|
|
276
|
+
const suffix = link.status.some((status) => status.severity === 'error') ? chalk.red(' [issue]') : '';
|
|
277
|
+
console.log(` ${link.name} -> ${link.path ?? '(no local path recorded)'}${suffix}`);
|
|
278
|
+
if (link.repo_specs_path) {
|
|
279
|
+
console.log(chalk.dim(` repo specs: ${link.repo_specs_path}`));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function printWorkspaceCheckSummaryHuman(result) {
|
|
285
|
+
printStatusLines(result.status);
|
|
286
|
+
const issues = collectWorkspaceIssues(result.workspace);
|
|
287
|
+
if (issues.length === 0) {
|
|
288
|
+
console.log(' No workspace issues found.');
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
console.log(' Issues:');
|
|
292
|
+
for (const issue of issues) {
|
|
293
|
+
console.log(` - ${issue.message}`);
|
|
294
|
+
if (issue.target) {
|
|
295
|
+
console.log(` Target: ${issue.target}`);
|
|
296
|
+
}
|
|
297
|
+
if (issue.fix) {
|
|
298
|
+
console.log(` Fix: ${issue.fix}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function printLinkMutationHuman(heading, payload) {
|
|
303
|
+
printStatusLines(payload.status);
|
|
304
|
+
console.log(heading);
|
|
305
|
+
console.log(` ${payload.link.name} -> ${payload.link.path}`);
|
|
306
|
+
console.log(`Workspace: ${payload.workspace.name}`);
|
|
307
|
+
}
|
|
308
|
+
async function resolveWorkspaceOpenOpener(localState, options) {
|
|
309
|
+
if (options.agent && options.editor) {
|
|
310
|
+
throw new WorkspaceCliError('workspace open accepts either --agent <tool> or --editor, not both.', 'workspace_opener_conflict', {
|
|
311
|
+
target: 'workspace.opener',
|
|
312
|
+
fix: 'Choose one opener override.',
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
if (options.agent) {
|
|
316
|
+
return parseAgentOverride(options.agent);
|
|
317
|
+
}
|
|
318
|
+
if (options.editor) {
|
|
319
|
+
return parseWorkspacePreferredOpenerValue('editor');
|
|
320
|
+
}
|
|
321
|
+
if (localState.preferred_opener) {
|
|
322
|
+
return localState.preferred_opener;
|
|
323
|
+
}
|
|
324
|
+
if (!resolveNoInteractive(options) && isInteractive(options)) {
|
|
325
|
+
const openerChoices = listWorkspaceOpenerChoices().filter((choice) => choice.available);
|
|
326
|
+
if (openerChoices.length === 0) {
|
|
327
|
+
throw new WorkspaceCliError('No supported workspace opener is available on PATH.', 'workspace_no_available_openers', {
|
|
328
|
+
target: 'workspace.opener',
|
|
329
|
+
fix: "Install VS Code ('code'), Codex ('codex'), or Claude ('claude'), then retry.",
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return promptPreferredOpener('Open with:', openerChoices);
|
|
333
|
+
}
|
|
334
|
+
throw new WorkspaceCliError('This workspace does not have a preferred opener yet.', 'workspace_opener_unset', {
|
|
335
|
+
target: 'workspace.opener',
|
|
336
|
+
fix: 'Pass --agent <tool> or --editor, or run workspace setup interactively to choose a default opener.',
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
function assertWorkspaceOpenSupportedOptions(options) {
|
|
340
|
+
if (options.prepareOnly) {
|
|
341
|
+
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', {
|
|
342
|
+
target: 'workspace.open',
|
|
343
|
+
fix: 'Run synarcx workspace open with --agent <tool> or --editor.',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
if (options.json) {
|
|
347
|
+
throw new WorkspaceCliError('workspace open supports launching through a selected opener; machine-readable context is reserved for a future context/query surface.', 'workspace_open_json_unsupported', {
|
|
348
|
+
target: 'workspace.open',
|
|
349
|
+
fix: 'Use synarcx workspace doctor --json for current workspace status.',
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
if (options.change) {
|
|
353
|
+
throw new WorkspaceCliError('workspace open currently supports root workspace open only; change-scoped open belongs to future workspace change planning.', 'workspace_open_change_unsupported', {
|
|
354
|
+
target: 'workspace.change',
|
|
355
|
+
fix: 'Open the root workspace, then start implementation from an explicit change workflow.',
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function resolveOpenWorkspaceName(positionalName, options) {
|
|
360
|
+
if (positionalName && options.workspace && positionalName !== options.workspace) {
|
|
361
|
+
throw new WorkspaceCliError(`Conflicting workspace selectors: positional '${positionalName}' and --workspace '${options.workspace}'.`, 'workspace_selection_conflict', {
|
|
362
|
+
target: 'workspace.name',
|
|
363
|
+
fix: 'Use either the positional workspace name or --workspace with the same value.',
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
return positionalName ?? options.workspace;
|
|
367
|
+
}
|
|
368
|
+
function printWorkspaceOpenHuman(selectedName, selectedRoot, opener, skipped) {
|
|
369
|
+
console.log(`Opening workspace: ${selectedName}`);
|
|
370
|
+
console.log(`Location: ${selectedRoot}`);
|
|
371
|
+
console.log(`Opener: ${getWorkspaceOpenerLabel(opener)}`);
|
|
372
|
+
if (skipped.length === 0) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
console.log('');
|
|
376
|
+
console.log('Skipped linked repos or folders:');
|
|
377
|
+
for (const link of skipped) {
|
|
378
|
+
const location = link.path ?? '(no local path recorded)';
|
|
379
|
+
console.log(` ${link.name} -> ${location}`);
|
|
380
|
+
}
|
|
381
|
+
console.log('Repair skipped links with synarcx workspace doctor.');
|
|
382
|
+
}
|
|
383
|
+
class WorkspaceCommand {
|
|
384
|
+
async setup(options = {}) {
|
|
385
|
+
try {
|
|
386
|
+
const noInteractive = resolveNoInteractive(options);
|
|
387
|
+
if (options.json && !noInteractive) {
|
|
388
|
+
throw new WorkspaceCliError('workspace setup --json requires --no-interactive.', 'setup_json_requires_no_interactive', {
|
|
389
|
+
fix: 'synarcx workspace setup --no-interactive --json --name <name> --link <path>',
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
const interactive = !noInteractive && isInteractive(options);
|
|
393
|
+
if (interactive) {
|
|
394
|
+
printWorkspaceSetupIntro();
|
|
395
|
+
}
|
|
396
|
+
if (!interactive && (!options.name || (options.link ?? []).length === 0)) {
|
|
397
|
+
throw new WorkspaceCliError('workspace setup --no-interactive requires --name <name> and at least one --link <path>.', 'missing_setup_inputs', {
|
|
398
|
+
fix: 'synarcx workspace setup --no-interactive --name platform --link /path/to/repo',
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
const workspaceName = interactive
|
|
402
|
+
? await promptWorkspaceName(options.name)
|
|
403
|
+
: validateWorkspaceNameForSetup(options.name ?? '');
|
|
404
|
+
const links = interactive ? await promptSetupLinks() : await parseSetupLinks(options.link);
|
|
405
|
+
if (interactive) {
|
|
406
|
+
console.log('');
|
|
407
|
+
console.log(chalk.bold('[3/4] Choose preferred opener'));
|
|
408
|
+
}
|
|
409
|
+
const preferredOpener = interactive
|
|
410
|
+
? await promptPreferredOpener('Preferred opener:')
|
|
411
|
+
: parseSetupOpenerOption(options.opener);
|
|
412
|
+
if (Object.keys(links).length === 0) {
|
|
413
|
+
throw new WorkspaceCliError('workspace setup --no-interactive requires --name <name> and at least one --link <path>.', 'missing_setup_inputs', {
|
|
414
|
+
fix: 'synarcx workspace setup --no-interactive --name platform --link /path/to/repo',
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (interactive) {
|
|
418
|
+
console.log('');
|
|
419
|
+
console.log(chalk.bold('[4/4] Create workspace files'));
|
|
420
|
+
}
|
|
421
|
+
const workspace = await createManagedWorkspace(workspaceName, links, preferredOpener);
|
|
422
|
+
const doctorResult = await loadWorkspaceForDoctor({
|
|
423
|
+
name: workspace.name,
|
|
424
|
+
root: workspace.root,
|
|
425
|
+
status: [],
|
|
426
|
+
unregisteredCurrentWorkspace: false,
|
|
427
|
+
});
|
|
428
|
+
if (options.json) {
|
|
429
|
+
printJson({
|
|
430
|
+
workspace: doctorResult.workspace,
|
|
431
|
+
status: doctorResult.status,
|
|
432
|
+
});
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
console.log(chalk.green('Workspace setup complete'));
|
|
436
|
+
console.log('');
|
|
437
|
+
printWorkspaceListHuman([doctorResult.workspace]);
|
|
438
|
+
console.log('');
|
|
439
|
+
console.log(`Planning path: ${doctorResult.workspace.planning_path}`);
|
|
440
|
+
console.log('');
|
|
441
|
+
console.log('Workspace check:');
|
|
442
|
+
printWorkspaceCheckSummaryHuman(doctorResult);
|
|
443
|
+
console.log('');
|
|
444
|
+
console.log('Next useful commands:');
|
|
445
|
+
console.log(` synarcx workspace doctor --workspace ${workspace.name}`);
|
|
446
|
+
console.log(' synarcx workspace list');
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
this.handleFailure(options.json, { workspace: null, status: [] }, error);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
async list(options = {}) {
|
|
453
|
+
try {
|
|
454
|
+
const registry = await readRegistry();
|
|
455
|
+
const entries = listWorkspaceRegistryEntries(registry);
|
|
456
|
+
const workspaces = await Promise.all(entries.map((entry) => loadWorkspaceForList(entry)));
|
|
457
|
+
const payload = { workspaces, status: [] };
|
|
458
|
+
if (options.json) {
|
|
459
|
+
printJson(payload);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (workspaces.length === 0) {
|
|
463
|
+
console.log("No synarcx workspaces found. Run 'synarcx workspace setup' first.");
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
printWorkspaceListHuman(workspaces);
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
this.handleFailure(options.json, { workspaces: [], status: [] }, error);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async link(nameOrPath, linkPath, options = {}) {
|
|
473
|
+
try {
|
|
474
|
+
if (!nameOrPath) {
|
|
475
|
+
throw new WorkspaceCliError('workspace link requires a repo or folder path.', 'missing_link_path', {
|
|
476
|
+
fix: 'synarcx workspace link /path/to/repo',
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
const selected = await selectWorkspaceForCommand(options, 'link');
|
|
480
|
+
const payload = await addWorkspaceLink(selected, nameOrPath, linkPath);
|
|
481
|
+
if (options.json) {
|
|
482
|
+
printJson(payload);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
printLinkMutationHuman('Linked repo or folder:', payload);
|
|
486
|
+
}
|
|
487
|
+
catch (error) {
|
|
488
|
+
this.handleFailure(options.json, { workspace: null, link: null, status: [] }, error);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
async relink(linkNameInput, linkPath, options = {}) {
|
|
492
|
+
try {
|
|
493
|
+
if (!linkNameInput || !linkPath) {
|
|
494
|
+
throw new WorkspaceCliError('workspace relink requires a link name and repo or folder path.', 'missing_relink_arguments', {
|
|
495
|
+
fix: 'synarcx workspace relink <name> /path/to/repo',
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
const selected = await selectWorkspaceForCommand(options, 'relink');
|
|
499
|
+
const payload = await updateWorkspaceLink(selected, linkNameInput, linkPath);
|
|
500
|
+
if (options.json) {
|
|
501
|
+
printJson(payload);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
printLinkMutationHuman('Relinked repo or folder:', payload);
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
this.handleFailure(options.json, { workspace: null, link: null, status: [] }, error);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
async doctor(options = {}) {
|
|
511
|
+
try {
|
|
512
|
+
const selected = await selectWorkspaceForCommand(options, 'doctor');
|
|
513
|
+
const result = await loadWorkspaceForDoctor(selected);
|
|
514
|
+
if (options.json) {
|
|
515
|
+
printJson(result);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
printDoctorHuman(result);
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
this.handleFailure(options.json, { workspace: null, status: [] }, error);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async open(positionalName, options = {}) {
|
|
525
|
+
try {
|
|
526
|
+
assertWorkspaceOpenSupportedOptions(options);
|
|
527
|
+
const workspaceName = resolveOpenWorkspaceName(positionalName, options);
|
|
528
|
+
const selected = await selectWorkspaceForCommand({
|
|
529
|
+
...options,
|
|
530
|
+
workspace: workspaceName,
|
|
531
|
+
}, 'open', { preferPositionalName: true });
|
|
532
|
+
const state = await readWorkspaceOpenState(selected);
|
|
533
|
+
const opener = await resolveWorkspaceOpenOpener(state.localState, options);
|
|
534
|
+
assertWorkspaceOpenerAvailable(opener, state.codeWorkspacePath);
|
|
535
|
+
const { command, skipped } = await buildWorkspaceOpenCommandForState(opener, selected.root, state);
|
|
536
|
+
printStatusLines(selected.status);
|
|
537
|
+
if (selected.status.length > 0) {
|
|
538
|
+
console.log('');
|
|
539
|
+
}
|
|
540
|
+
printWorkspaceOpenHuman(selected.name, selected.root, opener, skipped);
|
|
541
|
+
await launchWorkspaceOpenCommand(command);
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
this.handleFailure(options.json, { workspace: null, status: [] }, error);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
handleFailure(json, payload, error) {
|
|
548
|
+
if (!json && isPromptCancellationError(error)) {
|
|
549
|
+
console.error('Cancelled.');
|
|
550
|
+
process.exitCode = 130;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (json) {
|
|
554
|
+
printJson(appendStatus(payload, asStatus(error)));
|
|
555
|
+
process.exitCode = 1;
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const status = asStatus(error);
|
|
559
|
+
console.error(`Error: ${status.message}`);
|
|
560
|
+
if (status.fix) {
|
|
561
|
+
console.error(`Fix: ${status.fix}`);
|
|
562
|
+
}
|
|
563
|
+
process.exitCode = 1;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function collectOption(value, previous) {
|
|
567
|
+
return [...previous, value];
|
|
568
|
+
}
|
|
569
|
+
function addWorkspaceSelectionOptions(command) {
|
|
570
|
+
return command
|
|
571
|
+
.option('--workspace <name>', 'Workspace name from the local workspace registry')
|
|
572
|
+
.option('--json', 'Output as JSON')
|
|
573
|
+
.option('--no-interactive', 'Disable prompts');
|
|
574
|
+
}
|
|
575
|
+
export function registerWorkspaceCommand(program) {
|
|
576
|
+
const workspaceCommand = new WorkspaceCommand();
|
|
577
|
+
const workspace = program
|
|
578
|
+
.command('workspace')
|
|
579
|
+
.description('Set up and inspect coordination workspaces');
|
|
580
|
+
workspace
|
|
581
|
+
.command('setup')
|
|
582
|
+
.description('Set up a workspace and link existing repos or folders')
|
|
583
|
+
.option('--name <name>', 'Workspace name')
|
|
584
|
+
.option('--link <link>', 'Repo or folder link. Use <path> or <name>=<path>.', collectOption, [])
|
|
585
|
+
.option('--opener <id>', 'Preferred opener: codex, claude, github-copilot, or editor')
|
|
586
|
+
.option('--json', 'Output as JSON')
|
|
587
|
+
.option('--no-interactive', 'Disable prompts')
|
|
588
|
+
.action(async (options) => {
|
|
589
|
+
await workspaceCommand.setup(options);
|
|
590
|
+
});
|
|
591
|
+
workspace
|
|
592
|
+
.command('list')
|
|
593
|
+
.description('List known synarcx workspaces')
|
|
594
|
+
.option('--json', 'Output as JSON')
|
|
595
|
+
.action(async (options) => {
|
|
596
|
+
await workspaceCommand.list(options);
|
|
597
|
+
});
|
|
598
|
+
workspace
|
|
599
|
+
.command('ls')
|
|
600
|
+
.description('List known synarcx workspaces')
|
|
601
|
+
.option('--json', 'Output as JSON')
|
|
602
|
+
.action(async (options) => {
|
|
603
|
+
await workspaceCommand.list(options);
|
|
604
|
+
});
|
|
605
|
+
addWorkspaceSelectionOptions(workspace
|
|
606
|
+
.command('link [nameOrPath] [path]')
|
|
607
|
+
.description('Link an existing repo or folder to a workspace')).action(async (nameOrPath, linkPath, options) => {
|
|
608
|
+
await workspaceCommand.link(nameOrPath, linkPath, options);
|
|
609
|
+
});
|
|
610
|
+
addWorkspaceSelectionOptions(workspace
|
|
611
|
+
.command('relink <name> <path>')
|
|
612
|
+
.description('Update the local path for an existing workspace link')).action(async (linkName, linkPath, options) => {
|
|
613
|
+
await workspaceCommand.relink(linkName, linkPath, options);
|
|
614
|
+
});
|
|
615
|
+
addWorkspaceSelectionOptions(workspace
|
|
616
|
+
.command('doctor')
|
|
617
|
+
.description('Check what a workspace can resolve on this machine')).action(async (options) => {
|
|
618
|
+
await workspaceCommand.doctor(options);
|
|
619
|
+
});
|
|
620
|
+
workspace
|
|
621
|
+
.command('open [name]')
|
|
622
|
+
.description('Open a workspace in an agent or VS Code editor')
|
|
623
|
+
.option('--workspace <name>', 'Workspace name from the local workspace registry')
|
|
624
|
+
.option('--agent <tool>', 'Use an agent for this session: codex, claude, or github-copilot')
|
|
625
|
+
.option('--editor', 'Open the workspace in VS Code editor mode')
|
|
626
|
+
.option('--prepare-only', 'Unsupported: preview surfaces belong to a future context/query command')
|
|
627
|
+
.option('--json', 'Unsupported: machine-readable context belongs to a future context/query command')
|
|
628
|
+
.option('--change <id>', 'Unsupported: change-scoped open belongs to future workspace change planning')
|
|
629
|
+
.option('--no-interactive', 'Disable prompts')
|
|
630
|
+
.action(async (name, options) => {
|
|
631
|
+
await workspaceCommand.open(name, options);
|
|
632
|
+
});
|
|
633
|
+
// Intentionally no public `workspace create` command in this slice.
|
|
634
|
+
}
|
|
635
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class ArchiveCommand {
|
|
2
|
+
execute(changeName?: string, options?: {
|
|
3
|
+
yes?: boolean;
|
|
4
|
+
skipSpecs?: boolean;
|
|
5
|
+
noValidate?: boolean;
|
|
6
|
+
validate?: boolean;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
private selectChange;
|
|
9
|
+
private getArchiveDate;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=archive.d.ts.map
|