rrce-workflow 0.1.5 → 0.2.6
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/agent-core/prompts/documentation.md +2 -2
- package/agent-core/prompts/executor.md +6 -9
- package/agent-core/prompts/init.md +9 -8
- package/agent-core/prompts/planning_orchestrator.md +2 -2
- package/agent-core/prompts/research_discussion.md +2 -2
- package/agent-core/prompts/sync.md +2 -2
- package/agent-core/templates/documentation_output.md +2 -2
- package/agent-core/templates/executor_output.md +2 -2
- package/agent-core/templates/init_output.md +2 -2
- package/agent-core/templates/planning_output.md +2 -2
- package/agent-core/templates/research_output.md +2 -2
- package/package.json +1 -1
- package/src/commands/wizard/index.ts +114 -0
- package/src/commands/wizard/link-flow.ts +101 -0
- package/src/commands/wizard/setup-flow.ts +356 -0
- package/src/commands/wizard/sync-flow.ts +93 -0
- package/src/commands/wizard/update-flow.ts +129 -0
- package/src/commands/wizard/utils.ts +38 -0
- package/src/commands/wizard/vscode.ts +66 -0
- package/src/index.ts +1 -1
- package/src/lib/paths.ts +117 -6
- package/src/types/prompt.ts +3 -2
- package/src/commands/wizard.ts +0 -612
|
@@ -48,7 +48,7 @@ Non-Negotiables
|
|
|
48
48
|
6. Close the loop in `meta.json` when working within a task by setting `agents.documentation.status`, refreshing `checklist`, and updating overall `status`.
|
|
49
49
|
|
|
50
50
|
Path Resolution
|
|
51
|
-
- Storage mode: Determined by
|
|
51
|
+
- Storage mode: Determined by `config.yaml → `storage.mode`` → global config → default (`global`)
|
|
52
52
|
- `global`: Data in `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
53
53
|
- `workspace`: Data in `<workspace>/.rrce-workflow/`
|
|
54
54
|
- `both`: **Dual storage** - data stored in BOTH locations simultaneously
|
|
@@ -56,7 +56,7 @@ Path Resolution
|
|
|
56
56
|
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
57
57
|
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
58
58
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
59
|
-
- Global home: `{{RRCE_HOME}}`
|
|
59
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:** read `.rrce-workflow/config.yaml` → `storage.globalPath`, or default `~/.rrce-workflow`
|
|
60
60
|
- Workspace root: `{{WORKSPACE_ROOT}}` (auto-detected or via `$RRCE_WORKSPACE`)
|
|
61
61
|
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
62
62
|
|
|
@@ -52,17 +52,14 @@ Non-Negotiables
|
|
|
52
52
|
6. Update `meta.json` as you proceed so statuses stay accurate.
|
|
53
53
|
|
|
54
54
|
Path Resolution
|
|
55
|
-
-
|
|
56
|
-
|
|
55
|
+
- **Config file**: `.rrce-workflow/config.yaml` (read this first to resolve paths)
|
|
56
|
+
- Storage mode: Determined by `config.yaml` → `storage.mode` (default: `global`)
|
|
57
|
+
- `global`: Data in `{{RRCE_HOME}}/workspaces/<workspace-name>/`
|
|
57
58
|
- `workspace`: Data in `<workspace>/.rrce-workflow/`
|
|
58
|
-
- `both`:
|
|
59
|
-
- Primary (for reads): `<workspace>/.rrce-workflow/`
|
|
60
|
-
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
61
|
-
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
59
|
+
- `both`: Dual storage - data in BOTH locations
|
|
62
60
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
63
|
-
- Global home: `{{RRCE_HOME}}`
|
|
64
|
-
- Workspace
|
|
65
|
-
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
61
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:** read `config.yaml` → `storage.globalPath`, or default `~/.rrce-workflow`
|
|
62
|
+
- Workspace name: `{{WORKSPACE_NAME}}` (from `config.yaml` → `project.name`)
|
|
66
63
|
|
|
67
64
|
Cross-Project References
|
|
68
65
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
|
@@ -34,17 +34,18 @@ Non-Negotiables
|
|
|
34
34
|
6. Keep output actionable and scannable; use structured sections.
|
|
35
35
|
|
|
36
36
|
Path Resolution
|
|
37
|
-
-
|
|
38
|
-
|
|
37
|
+
- **Config file**: `.rrce-workflow/config.yaml` (read this first to resolve paths)
|
|
38
|
+
- Storage mode: Determined by `config.yaml` → `storage.mode` (default: `global`)
|
|
39
|
+
- `global`: Data stored in `{{RRCE_HOME}}/workspaces/<workspace-name>/`
|
|
39
40
|
- `workspace`: Data stored in `<workspace>/.rrce-workflow/`
|
|
40
|
-
- `both`: **Dual storage** - data
|
|
41
|
-
- Primary (for reads): `<workspace>/.rrce-workflow/`
|
|
42
|
-
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
43
|
-
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
41
|
+
- `both`: **Dual storage** - data in BOTH locations
|
|
44
42
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
45
|
-
- Global home: `{{RRCE_HOME}}`
|
|
43
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:**
|
|
44
|
+
1. Read `.rrce-workflow/config.yaml`
|
|
45
|
+
2. If `storage.globalPath` exists, use that value
|
|
46
|
+
3. Otherwise, default to `~/.rrce-workflow`
|
|
46
47
|
- Workspace root: `{{WORKSPACE_ROOT}}` (auto-detected or via `$RRCE_WORKSPACE`)
|
|
47
|
-
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
48
|
+
- Workspace name: `{{WORKSPACE_NAME}}` (from `config.yaml` → `project.name` or directory name)
|
|
48
49
|
|
|
49
50
|
Cross-Project References
|
|
50
51
|
- To reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project-name>/knowledge/`
|
|
@@ -44,7 +44,7 @@ Non-Negotiables
|
|
|
44
44
|
6. Keep the written plan under 500 lines and reference supporting materials explicitly.
|
|
45
45
|
|
|
46
46
|
Path Resolution
|
|
47
|
-
- Storage mode: Determined by
|
|
47
|
+
- Storage mode: Determined by `config.yaml → `storage.mode`` → global config → default (`global`)
|
|
48
48
|
- `global`: Data in `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
49
49
|
- `workspace`: Data in `<workspace>/.rrce-workflow/`
|
|
50
50
|
- `both`: **Dual storage** - data stored in BOTH locations simultaneously
|
|
@@ -52,7 +52,7 @@ Path Resolution
|
|
|
52
52
|
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
53
53
|
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
54
54
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
55
|
-
- Global home: `{{RRCE_HOME}}`
|
|
55
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:** read `.rrce-workflow/config.yaml` → `storage.globalPath`, or default `~/.rrce-workflow`
|
|
56
56
|
- Workspace root: `{{WORKSPACE_ROOT}}` (auto-detected or via `$RRCE_WORKSPACE`)
|
|
57
57
|
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
58
58
|
|
|
@@ -38,7 +38,7 @@ Non-Negotiables
|
|
|
38
38
|
6. Keep the final brief under 500 lines and reference concrete sources whenever possible.
|
|
39
39
|
|
|
40
40
|
Path Resolution
|
|
41
|
-
- Storage mode: Determined by
|
|
41
|
+
- Storage mode: Determined by `config.yaml → `storage.mode`` → global config → default (`global`)
|
|
42
42
|
- `global`: Data in `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
43
43
|
- `workspace`: Data in `<workspace>/.rrce-workflow/`
|
|
44
44
|
- `both`: **Dual storage** - data stored in BOTH locations simultaneously
|
|
@@ -46,7 +46,7 @@ Path Resolution
|
|
|
46
46
|
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
47
47
|
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
48
48
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
49
|
-
- Global home: `{{RRCE_HOME}}`
|
|
49
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:** read `.rrce-workflow/config.yaml` → `storage.globalPath`, or default `~/.rrce-workflow`
|
|
50
50
|
- Workspace root: `{{WORKSPACE_ROOT}}` (auto-detected or via `$RRCE_WORKSPACE`)
|
|
51
51
|
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
52
52
|
|
|
@@ -38,7 +38,7 @@ Non-Negotiables
|
|
|
38
38
|
5. Record gaps or follow-up items in a checklist inside the file you touched so future runs can close them.
|
|
39
39
|
|
|
40
40
|
Path Resolution
|
|
41
|
-
- Storage mode: Determined by
|
|
41
|
+
- Storage mode: Determined by `config.yaml → `storage.mode`` → global config → default (`global`)
|
|
42
42
|
- `global`: Data in `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
43
43
|
- `workspace`: Data in `<workspace>/.rrce-workflow/`
|
|
44
44
|
- `both`: **Dual storage** - data stored in BOTH locations simultaneously
|
|
@@ -46,7 +46,7 @@ Path Resolution
|
|
|
46
46
|
- Secondary (auto-synced): `~/.rrce-workflow/workspaces/<workspace-name>/`
|
|
47
47
|
- When writing, always write to `{{RRCE_DATA}}` - the system ensures both locations stay in sync
|
|
48
48
|
- Data path: `{{RRCE_DATA}}` (resolves to primary storage based on mode)
|
|
49
|
-
- Global home: `{{RRCE_HOME}}`
|
|
49
|
+
- Global home: `{{RRCE_HOME}}` - **To resolve:** read `.rrce-workflow/config.yaml` → `storage.globalPath`, or default `~/.rrce-workflow`
|
|
50
50
|
- Workspace root: `{{WORKSPACE_ROOT}}` (auto-detected or via `$RRCE_WORKSPACE`)
|
|
51
51
|
- Workspace name: `{{WORKSPACE_NAME}}` (from config or directory name)
|
|
52
52
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
RRCE Template Variables:
|
|
3
3
|
- {{RRCE_DATA}}: Primary storage path (resolves based on storage mode in .rrce-workflow.yaml)
|
|
4
|
-
- global:
|
|
4
|
+
- global: {{RRCE_HOME}}/workspaces/<workspace-name>/
|
|
5
5
|
- workspace: <workspace>/.rrce-workflow/
|
|
6
6
|
- both: <workspace>/.rrce-workflow/ (primary, auto-synced to global)
|
|
7
|
-
- {{RRCE_HOME}}:
|
|
7
|
+
- {{RRCE_HOME}}: Global home (default: ~/.rrce-workflow, customizable via storage.globalPath in config)
|
|
8
8
|
- {{WORKSPACE_ROOT}}: Workspace root directory
|
|
9
9
|
- {{WORKSPACE_NAME}}: Workspace name from config or directory name
|
|
10
10
|
-->
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
RRCE Template Variables:
|
|
3
3
|
- {{RRCE_DATA}}: Primary storage path (resolves based on storage mode in .rrce-workflow.yaml)
|
|
4
|
-
- global:
|
|
4
|
+
- global: {{RRCE_HOME}}/workspaces/<workspace-name>/
|
|
5
5
|
- workspace: <workspace>/.rrce-workflow/
|
|
6
6
|
- both: <workspace>/.rrce-workflow/ (primary, auto-synced to global)
|
|
7
|
-
- {{RRCE_HOME}}:
|
|
7
|
+
- {{RRCE_HOME}}: Global home (default: ~/.rrce-workflow, customizable via storage.globalPath in config)
|
|
8
8
|
- {{WORKSPACE_ROOT}}: Workspace root directory
|
|
9
9
|
- {{WORKSPACE_NAME}}: Workspace name from config or directory name
|
|
10
10
|
-->
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
RRCE Template Variables:
|
|
3
3
|
- {{RRCE_DATA}}: Primary storage path (resolves based on storage mode in .rrce-workflow.yaml)
|
|
4
|
-
- global:
|
|
4
|
+
- global: {{RRCE_HOME}}/workspaces/<workspace-name>/
|
|
5
5
|
- workspace: <workspace>/.rrce-workflow/
|
|
6
6
|
- both: <workspace>/.rrce-workflow/ (primary, auto-synced to global)
|
|
7
|
-
- {{RRCE_HOME}}:
|
|
7
|
+
- {{RRCE_HOME}}: Global home (default: ~/.rrce-workflow, customizable via storage.globalPath in config)
|
|
8
8
|
- {{WORKSPACE_ROOT}}: Workspace root directory
|
|
9
9
|
- {{WORKSPACE_NAME}}: Workspace name from config or directory name
|
|
10
10
|
-->
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
RRCE Template Variables:
|
|
3
3
|
- {{RRCE_DATA}}: Primary storage path (resolves based on storage mode in .rrce-workflow.yaml)
|
|
4
|
-
- global:
|
|
4
|
+
- global: {{RRCE_HOME}}/workspaces/<workspace-name>/
|
|
5
5
|
- workspace: <workspace>/.rrce-workflow/
|
|
6
6
|
- both: <workspace>/.rrce-workflow/ (primary, auto-synced to global)
|
|
7
|
-
- {{RRCE_HOME}}:
|
|
7
|
+
- {{RRCE_HOME}}: Global home (default: ~/.rrce-workflow, customizable via storage.globalPath in config)
|
|
8
8
|
- {{WORKSPACE_ROOT}}: Workspace root directory
|
|
9
9
|
- {{WORKSPACE_NAME}}: Workspace name from config or directory name
|
|
10
10
|
-->
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
RRCE Template Variables:
|
|
3
3
|
- {{RRCE_DATA}}: Primary storage path (resolves based on storage mode in .rrce-workflow.yaml)
|
|
4
|
-
- global:
|
|
4
|
+
- global: {{RRCE_HOME}}/workspaces/<workspace-name>/
|
|
5
5
|
- workspace: <workspace>/.rrce-workflow/
|
|
6
6
|
- both: <workspace>/.rrce-workflow/ (primary, auto-synced to global)
|
|
7
|
-
- {{RRCE_HOME}}:
|
|
7
|
+
- {{RRCE_HOME}}: Global home (default: ~/.rrce-workflow, customizable via storage.globalPath in config)
|
|
8
8
|
- {{WORKSPACE_ROOT}}: Workspace root directory
|
|
9
9
|
- {{WORKSPACE_NAME}}: Workspace name from config or directory name
|
|
10
10
|
-->
|
package/package.json
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { intro, select, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { getGitUser } from '../../lib/git';
|
|
5
|
+
import {
|
|
6
|
+
detectWorkspaceRoot,
|
|
7
|
+
getWorkspaceName,
|
|
8
|
+
listGlobalProjects,
|
|
9
|
+
getLocalWorkspacePath,
|
|
10
|
+
getConfigPath
|
|
11
|
+
} from '../../lib/paths';
|
|
12
|
+
|
|
13
|
+
// Import flows
|
|
14
|
+
import { runSetupFlow } from './setup-flow';
|
|
15
|
+
import { runLinkProjectsFlow } from './link-flow';
|
|
16
|
+
import { runSyncToGlobalFlow } from './sync-flow';
|
|
17
|
+
import { runUpdateFlow } from './update-flow';
|
|
18
|
+
|
|
19
|
+
export async function runWizard() {
|
|
20
|
+
intro(pc.cyan(pc.inverse(' RRCE-Workflow Setup ')));
|
|
21
|
+
|
|
22
|
+
const s = spinner();
|
|
23
|
+
s.start('Detecting environment');
|
|
24
|
+
|
|
25
|
+
const workspacePath = detectWorkspaceRoot();
|
|
26
|
+
const workspaceName = getWorkspaceName(workspacePath);
|
|
27
|
+
const gitUser = getGitUser();
|
|
28
|
+
|
|
29
|
+
await new Promise(r => setTimeout(r, 800)); // Dramatic pause
|
|
30
|
+
s.stop('Environment detected');
|
|
31
|
+
|
|
32
|
+
note(
|
|
33
|
+
`Git User: ${pc.bold(gitUser || '(not found)')}
|
|
34
|
+
Workspace: ${pc.bold(workspaceName)}`,
|
|
35
|
+
'Context'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Check for existing projects in global storage
|
|
39
|
+
const existingProjects = listGlobalProjects(workspaceName);
|
|
40
|
+
|
|
41
|
+
// Check if already configured (using getConfigPath for new/legacy support)
|
|
42
|
+
const configFilePath = getConfigPath(workspacePath);
|
|
43
|
+
const isAlreadyConfigured = fs.existsSync(configFilePath);
|
|
44
|
+
|
|
45
|
+
// Check current storage mode from config
|
|
46
|
+
let currentStorageMode: string | null = null;
|
|
47
|
+
if (isAlreadyConfigured) {
|
|
48
|
+
try {
|
|
49
|
+
const configContent = fs.readFileSync(configFilePath, 'utf-8');
|
|
50
|
+
const modeMatch = configContent.match(/mode:\s*(global|workspace|both)/);
|
|
51
|
+
currentStorageMode = modeMatch?.[1] ?? null;
|
|
52
|
+
} catch {
|
|
53
|
+
// Ignore parse errors
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check if workspace has local data that could be synced
|
|
58
|
+
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
59
|
+
const hasLocalData = fs.existsSync(localDataPath);
|
|
60
|
+
|
|
61
|
+
// If already configured, show menu
|
|
62
|
+
if (isAlreadyConfigured) {
|
|
63
|
+
const menuOptions: { value: string; label: string; hint?: string }[] = [];
|
|
64
|
+
|
|
65
|
+
// Add link option if other projects exist
|
|
66
|
+
if (existingProjects.length > 0) {
|
|
67
|
+
menuOptions.push({
|
|
68
|
+
value: 'link',
|
|
69
|
+
label: 'Link other project knowledge',
|
|
70
|
+
hint: `${existingProjects.length} projects available`
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add sync to global option if using workspace-only mode
|
|
75
|
+
if (currentStorageMode === 'workspace' && hasLocalData) {
|
|
76
|
+
menuOptions.push({
|
|
77
|
+
value: 'sync-global',
|
|
78
|
+
label: 'Sync to global storage',
|
|
79
|
+
hint: 'Share knowledge with other projects'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
menuOptions.push({ value: 'update', label: 'Update from package', hint: 'Get latest prompts & templates' });
|
|
84
|
+
menuOptions.push({ value: 'exit', label: 'Exit' });
|
|
85
|
+
|
|
86
|
+
const action = await select({
|
|
87
|
+
message: 'This workspace is already configured. What would you like to do?',
|
|
88
|
+
options: menuOptions,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (isCancel(action) || action === 'exit') {
|
|
92
|
+
outro('Exited.');
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (action === 'link') {
|
|
97
|
+
await runLinkProjectsFlow(workspacePath, workspaceName, existingProjects);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (action === 'sync-global') {
|
|
102
|
+
await runSyncToGlobalFlow(workspacePath, workspaceName);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (action === 'update') {
|
|
107
|
+
await runUpdateFlow(workspacePath, workspaceName, currentStorageMode);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Run full setup flow for new workspaces
|
|
113
|
+
await runSetupFlow(workspacePath, workspaceName, existingProjects);
|
|
114
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { multiselect, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { listGlobalProjects, getEffectiveRRCEHome, getConfigPath } from '../../lib/paths';
|
|
5
|
+
import { generateVSCodeWorkspace } from './vscode';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run the link-only flow for adding other project knowledge to an existing workspace
|
|
9
|
+
*/
|
|
10
|
+
export async function runLinkProjectsFlow(
|
|
11
|
+
workspacePath: string,
|
|
12
|
+
workspaceName: string,
|
|
13
|
+
existingProjects?: string[]
|
|
14
|
+
) {
|
|
15
|
+
// Get projects if not provided
|
|
16
|
+
const projects = existingProjects ?? listGlobalProjects(workspaceName);
|
|
17
|
+
|
|
18
|
+
if (projects.length === 0) {
|
|
19
|
+
outro(pc.yellow('No other projects found in global storage.'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
24
|
+
|
|
25
|
+
const linkedProjects = await multiselect({
|
|
26
|
+
message: 'Select projects to link:',
|
|
27
|
+
options: projects.map(name => ({
|
|
28
|
+
value: name,
|
|
29
|
+
label: name,
|
|
30
|
+
hint: `${customGlobalPath}/workspaces/${name}/knowledge`
|
|
31
|
+
})),
|
|
32
|
+
required: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (isCancel(linkedProjects)) {
|
|
36
|
+
cancel('Cancelled.');
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const selectedProjects = linkedProjects as string[];
|
|
41
|
+
|
|
42
|
+
if (selectedProjects.length === 0) {
|
|
43
|
+
outro('No projects selected.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const s = spinner();
|
|
48
|
+
s.start('Linking projects');
|
|
49
|
+
|
|
50
|
+
// Update config.yaml with linked projects
|
|
51
|
+
const configFilePath = getConfigPath(workspacePath);
|
|
52
|
+
let configContent = fs.readFileSync(configFilePath, 'utf-8');
|
|
53
|
+
|
|
54
|
+
// Check if linked_projects section exists
|
|
55
|
+
if (configContent.includes('linked_projects:')) {
|
|
56
|
+
// Append to existing section - find and update
|
|
57
|
+
const lines = configContent.split('\n');
|
|
58
|
+
const linkedIndex = lines.findIndex(l => l.trim() === 'linked_projects:');
|
|
59
|
+
if (linkedIndex !== -1) {
|
|
60
|
+
// Find where to insert new projects (after existing ones)
|
|
61
|
+
let insertIndex = linkedIndex + 1;
|
|
62
|
+
while (insertIndex < lines.length && lines[insertIndex]?.startsWith(' - ')) {
|
|
63
|
+
insertIndex++;
|
|
64
|
+
}
|
|
65
|
+
// Add new projects that aren't already there
|
|
66
|
+
for (const name of selectedProjects) {
|
|
67
|
+
if (!configContent.includes(` - ${name}`)) {
|
|
68
|
+
lines.splice(insertIndex, 0, ` - ${name}`);
|
|
69
|
+
insertIndex++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
configContent = lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
// Add new linked_projects section
|
|
76
|
+
configContent += `\nlinked_projects:\n`;
|
|
77
|
+
selectedProjects.forEach(name => {
|
|
78
|
+
configContent += ` - ${name}\n`;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fs.writeFileSync(configFilePath, configContent);
|
|
83
|
+
|
|
84
|
+
// Update VSCode workspace file
|
|
85
|
+
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
86
|
+
|
|
87
|
+
s.stop('Projects linked');
|
|
88
|
+
|
|
89
|
+
// Show summary
|
|
90
|
+
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
91
|
+
const summary = [
|
|
92
|
+
`Linked projects:`,
|
|
93
|
+
...selectedProjects.map(p => ` ✓ ${p}`),
|
|
94
|
+
``,
|
|
95
|
+
`Workspace file: ${pc.cyan(workspaceFile)}`,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
note(summary.join('\n'), 'Link Summary');
|
|
99
|
+
|
|
100
|
+
outro(pc.green(`✓ Projects linked! Open ${pc.bold(workspaceFile)} in VSCode to access linked knowledge.`));
|
|
101
|
+
}
|