rrce-workflow 0.2.14 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/bin/rrce-workflow.js +3 -33
  2. package/dist/commands/selector.d.ts +1 -0
  3. package/dist/commands/selector.js +29 -0
  4. package/dist/commands/wizard/index.d.ts +1 -0
  5. package/dist/commands/wizard/index.js +86 -0
  6. package/dist/commands/wizard/link-flow.d.ts +5 -0
  7. package/dist/commands/wizard/link-flow.js +97 -0
  8. package/dist/commands/wizard/setup-flow.d.ts +4 -0
  9. package/dist/commands/wizard/setup-flow.js +262 -0
  10. package/dist/commands/wizard/sync-flow.d.ts +4 -0
  11. package/dist/commands/wizard/sync-flow.js +67 -0
  12. package/dist/commands/wizard/update-flow.d.ts +4 -0
  13. package/dist/commands/wizard/update-flow.js +85 -0
  14. package/dist/commands/wizard/utils.d.ts +9 -0
  15. package/dist/commands/wizard/utils.js +33 -0
  16. package/dist/commands/wizard/vscode.d.ts +15 -0
  17. package/dist/commands/wizard/vscode.js +148 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1191 -0
  20. package/dist/lib/autocomplete-prompt.d.ts +14 -0
  21. package/dist/lib/autocomplete-prompt.js +167 -0
  22. package/dist/lib/detection.d.ts +44 -0
  23. package/dist/lib/detection.js +185 -0
  24. package/dist/lib/git.d.ts +12 -0
  25. package/dist/lib/git.js +37 -0
  26. package/dist/lib/paths.d.ts +108 -0
  27. package/dist/lib/paths.js +296 -0
  28. package/dist/lib/prompts.d.ts +18 -0
  29. package/dist/lib/prompts.js +62 -0
  30. package/dist/types/prompt.d.ts +54 -0
  31. package/dist/types/prompt.js +20 -0
  32. package/package.json +10 -7
  33. package/src/commands/selector.ts +0 -42
  34. package/src/commands/wizard/index.ts +0 -114
  35. package/src/commands/wizard/link-flow.ts +0 -118
  36. package/src/commands/wizard/setup-flow.ts +0 -347
  37. package/src/commands/wizard/sync-flow.ts +0 -93
  38. package/src/commands/wizard/update-flow.ts +0 -124
  39. package/src/commands/wizard/utils.ts +0 -38
  40. package/src/commands/wizard/vscode.ts +0 -197
  41. package/src/index.ts +0 -11
  42. package/src/lib/autocomplete-prompt.ts +0 -190
  43. package/src/lib/detection.ts +0 -235
  44. package/src/lib/git.ts +0 -37
  45. package/src/lib/paths.ts +0 -332
  46. package/src/lib/prompts.ts +0 -73
  47. package/src/types/prompt.ts +0 -54
@@ -1,118 +0,0 @@
1
- import { multiselect, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
2
- import pc from 'picocolors';
3
- import * as fs from 'fs';
4
- import { getEffectiveRRCEHome, getConfigPath } from '../../lib/paths';
5
- import { generateVSCodeWorkspace } from './vscode';
6
- import { scanForProjects, getProjectDisplayLabel, type DetectedProject } from '../../lib/detection';
7
-
8
- /**
9
- * Run the link-only flow for adding other project knowledge to an existing workspace
10
- * Now supports detecting workspace-scoped sibling projects, not just global storage
11
- */
12
- export async function runLinkProjectsFlow(
13
- workspacePath: string,
14
- workspaceName: string,
15
- existingProjects?: string[]
16
- ) {
17
- // Scan for projects using the new detection system
18
- const detectedProjects = scanForProjects({
19
- excludeWorkspace: workspaceName,
20
- workspacePath: workspacePath,
21
- scanSiblings: true,
22
- });
23
-
24
- // If legacy string array is passed, use that instead (for backwards compat)
25
- const projects = existingProjects
26
- ? existingProjects.map(name => ({ name, source: 'global' as const } as DetectedProject))
27
- : detectedProjects;
28
-
29
- if (projects.length === 0) {
30
- outro(pc.yellow('No other projects found. Try setting up another project first.'));
31
- return;
32
- }
33
-
34
- const customGlobalPath = getEffectiveRRCEHome(workspacePath);
35
-
36
- // Build options with source labels
37
- const linkedProjects = await multiselect({
38
- message: 'Select projects to link:',
39
- options: projects.map(project => ({
40
- value: project.name,
41
- label: project.name,
42
- hint: pc.dim(getProjectDisplayLabel(project)),
43
- })),
44
- required: true,
45
- });
46
-
47
- if (isCancel(linkedProjects)) {
48
- cancel('Cancelled.');
49
- process.exit(0);
50
- }
51
-
52
- const selectedProjectNames = linkedProjects as string[];
53
-
54
- if (selectedProjectNames.length === 0) {
55
- outro('No projects selected.');
56
- return;
57
- }
58
-
59
- // Get the full DetectedProject objects for selected projects
60
- const selectedProjects = projects.filter(p => selectedProjectNames.includes(p.name));
61
-
62
- const s = spinner();
63
- s.start('Linking projects');
64
-
65
- // Update config.yaml with linked projects
66
- const configFilePath = getConfigPath(workspacePath);
67
- let configContent = fs.readFileSync(configFilePath, 'utf-8');
68
-
69
- // Check if linked_projects section exists
70
- if (configContent.includes('linked_projects:')) {
71
- // Append to existing section - find and update
72
- const lines = configContent.split('\n');
73
- const linkedIndex = lines.findIndex(l => l.trim() === 'linked_projects:');
74
- if (linkedIndex !== -1) {
75
- // Find where to insert new projects (after existing ones)
76
- let insertIndex = linkedIndex + 1;
77
- while (insertIndex < lines.length && lines[insertIndex]?.startsWith(' - ')) {
78
- insertIndex++;
79
- }
80
- // Add new projects that aren't already there
81
- for (const name of selectedProjectNames) {
82
- if (!configContent.includes(` - ${name}`)) {
83
- lines.splice(insertIndex, 0, ` - ${name}`);
84
- insertIndex++;
85
- }
86
- }
87
- configContent = lines.join('\n');
88
- }
89
- } else {
90
- // Add new linked_projects section
91
- configContent += `\nlinked_projects:\n`;
92
- selectedProjectNames.forEach(name => {
93
- configContent += ` - ${name}\n`;
94
- });
95
- }
96
-
97
- fs.writeFileSync(configFilePath, configContent);
98
-
99
- // Update VSCode workspace file with full project info (includes refs, tasks)
100
- generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
101
-
102
- s.stop('Projects linked');
103
-
104
- // Show summary with project sources
105
- const workspaceFile = `${workspaceName}.code-workspace`;
106
- const summary = [
107
- `Linked projects:`,
108
- ...selectedProjects.map(p => ` ✓ ${p.name} ${pc.dim(`(${p.source})`)}`),
109
- ``,
110
- `Workspace file: ${pc.cyan(workspaceFile)}`,
111
- ``,
112
- pc.dim('Includes: knowledge, refs, tasks folders'),
113
- ];
114
-
115
- note(summary.join('\n'), 'Link Summary');
116
-
117
- outro(pc.green(`✓ Projects linked! Open ${pc.bold(workspaceFile)} in VSCode to access linked knowledge.`));
118
- }
@@ -1,347 +0,0 @@
1
- import { group, text, select, multiselect, confirm, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
2
- import pc from 'picocolors';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import type { StorageMode } from '../../types/prompt';
6
- import {
7
- ensureDir,
8
- getAgentPromptPath,
9
- syncMetadataToAll,
10
- copyDirToAllStoragePaths,
11
- checkWriteAccess,
12
- getDefaultRRCEHome
13
- } from '../../lib/paths';
14
- import { loadPromptsFromDir, getAgentCorePromptsDir, getAgentCoreDir } from '../../lib/prompts';
15
- import { copyPromptsToDir } from './utils';
16
- import { generateVSCodeWorkspace } from './vscode';
17
- import { directoryAutocomplete, isCancel as isAutocompleteCancel } from '../../lib/autocomplete-prompt';
18
-
19
- interface SetupConfig {
20
- storageMode: StorageMode;
21
- globalPath?: string;
22
- tools: string[];
23
- linkedProjects: string[];
24
- }
25
-
26
- /**
27
- * Run the full setup flow for new workspaces
28
- */
29
- export async function runSetupFlow(
30
- workspacePath: string,
31
- workspaceName: string,
32
- existingProjects: string[]
33
- ): Promise<void> {
34
- const s = spinner();
35
-
36
- // Full setup flow
37
- const config = await group(
38
- {
39
- storageMode: () =>
40
- select({
41
- message: 'Where should workflow data be stored?',
42
- options: [
43
- { value: 'global', label: 'Global (~/.rrce-workflow/)' },
44
- { value: 'workspace', label: 'Workspace (.rrce-workflow/)' },
45
- { value: 'both', label: 'Both' },
46
- ],
47
- initialValue: 'global',
48
- }),
49
- tools: () =>
50
- multiselect({
51
- message: 'Which AI tools do you use?',
52
- options: [
53
- { value: 'copilot', label: 'GitHub Copilot', hint: 'VSCode' },
54
- { value: 'antigravity', label: 'Antigravity IDE' },
55
- ],
56
- required: false,
57
- }),
58
- linkedProjects: () => {
59
- // Only show if there are other projects to link
60
- if (existingProjects.length === 0) {
61
- return Promise.resolve([]);
62
- }
63
- return multiselect({
64
- message: 'Link knowledge from other projects?',
65
- options: existingProjects.map(name => ({
66
- value: name,
67
- label: name,
68
- hint: `~/.rrce-workflow/workspaces/${name}/knowledge`
69
- })),
70
- required: false,
71
- });
72
- },
73
- confirm: () =>
74
- confirm({
75
- message: 'Create configuration?',
76
- initialValue: true,
77
- }),
78
- },
79
- {
80
- onCancel: () => {
81
- cancel('Setup process cancelled.');
82
- process.exit(0);
83
- },
84
- }
85
- );
86
-
87
- if (!config.confirm) {
88
- outro('Setup cancelled by user.');
89
- process.exit(0);
90
- }
91
-
92
- // Determine global path for 'global' or 'both' modes
93
- let customGlobalPath: string | undefined;
94
-
95
- if (config.storageMode === 'global' || config.storageMode === 'both') {
96
- customGlobalPath = await resolveGlobalPath();
97
- if (!customGlobalPath) {
98
- cancel('Setup cancelled - no writable global path available.');
99
- process.exit(1);
100
- }
101
- }
102
-
103
- s.start('Generating configuration');
104
-
105
- try {
106
- await generateConfiguration({
107
- storageMode: config.storageMode as StorageMode,
108
- globalPath: customGlobalPath,
109
- tools: config.tools as string[],
110
- linkedProjects: config.linkedProjects as string[],
111
- }, workspacePath, workspaceName);
112
-
113
- s.stop('Configuration generated');
114
-
115
- // Show summary
116
- const dataPaths = getDataPaths(
117
- config.storageMode as StorageMode,
118
- workspaceName,
119
- workspacePath,
120
- customGlobalPath
121
- );
122
-
123
- const summary = [
124
- `Storage: ${config.storageMode === 'both' ? 'global + workspace' : config.storageMode}`,
125
- ];
126
-
127
- if (customGlobalPath && customGlobalPath !== getDefaultRRCEHome()) {
128
- summary.push(`Global path: ${pc.cyan(customGlobalPath)}`);
129
- }
130
-
131
- if (dataPaths.length > 0) {
132
- summary.push(`Data paths:`);
133
- dataPaths.forEach(p => summary.push(` - ${p}`));
134
- }
135
-
136
- const selectedTools = config.tools as string[];
137
- if (selectedTools.length > 0) {
138
- summary.push(`Tools: ${selectedTools.join(', ')}`);
139
- }
140
-
141
- const linkedProjects = config.linkedProjects as string[];
142
- if (linkedProjects.length > 0) {
143
- summary.push(`Linked projects: ${linkedProjects.join(', ')}`);
144
- summary.push(`Workspace file: ${pc.cyan(`${workspaceName}.code-workspace`)}`);
145
- }
146
-
147
- note(summary.join('\n'), 'Setup Summary');
148
-
149
- // Show appropriate outro message
150
- if (linkedProjects.length > 0) {
151
- outro(pc.green(`✓ Setup complete! Open ${pc.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
152
- } else {
153
- outro(pc.green(`✓ Setup complete! Your agents are ready to use.`));
154
- }
155
-
156
- } catch (error) {
157
- s.stop('Error occurred');
158
- cancel(`Failed to setup: ${error instanceof Error ? error.message : String(error)}`);
159
- process.exit(1);
160
- }
161
- }
162
-
163
- /**
164
- * Resolve global path - always prompt user to choose default or custom
165
- */
166
- async function resolveGlobalPath(): Promise<string | undefined> {
167
- const defaultPath = getDefaultRRCEHome();
168
- const isDefaultWritable = checkWriteAccess(defaultPath);
169
-
170
- // Build options
171
- const options: { value: string; label: string; hint?: string }[] = [];
172
-
173
- // Default option
174
- options.push({
175
- value: 'default',
176
- label: `Default (${defaultPath})`,
177
- hint: isDefaultWritable ? pc.green('✓ writable') : pc.red('✗ not writable'),
178
- });
179
-
180
- // Custom option
181
- options.push({
182
- value: 'custom',
183
- label: 'Custom path',
184
- hint: 'Specify your own directory',
185
- });
186
-
187
- const choice = await select({
188
- message: 'Global storage location:',
189
- options,
190
- initialValue: isDefaultWritable ? 'default' : 'custom',
191
- });
192
-
193
- if (isCancel(choice)) {
194
- return undefined;
195
- }
196
-
197
- if (choice === 'default') {
198
- // Verify it's writable
199
- if (!isDefaultWritable) {
200
- note(
201
- `${pc.yellow('⚠')} Cannot write to default path:\n ${pc.dim(defaultPath)}\n\nThis can happen when running via npx/bunx in restricted environments.\nPlease choose a custom path instead.`,
202
- 'Write Access Issue'
203
- );
204
- // Recursively ask again
205
- return resolveGlobalPath();
206
- }
207
- return defaultPath;
208
- }
209
-
210
- // Custom path input with Tab autocomplete
211
- const suggestedPath = path.join(process.env.HOME || '~', '.local', 'share', 'rrce-workflow');
212
- const customPath = await directoryAutocomplete({
213
- message: 'Enter custom global path:',
214
- initialValue: suggestedPath,
215
- hint: 'Tab to autocomplete',
216
- validate: (value) => {
217
- if (!value.trim()) {
218
- return 'Path cannot be empty';
219
- }
220
- // Expand ~ to home directory
221
- const expandedPath = value.startsWith('~')
222
- ? value.replace('~', process.env.HOME || '')
223
- : value;
224
-
225
- if (!checkWriteAccess(expandedPath)) {
226
- return `Cannot write to ${expandedPath}. Please choose a writable path.`;
227
- }
228
- return undefined;
229
- },
230
- });
231
-
232
- if (isAutocompleteCancel(customPath)) {
233
- return undefined;
234
- }
235
-
236
- // Path is already expanded by directoryAutocomplete
237
- return customPath as string;
238
- }
239
-
240
- /**
241
- * Generate configuration files and directories
242
- */
243
- async function generateConfiguration(
244
- config: SetupConfig,
245
- workspacePath: string,
246
- workspaceName: string
247
- ): Promise<void> {
248
- const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
249
-
250
- for (const dataPath of dataPaths) {
251
- ensureDir(dataPath);
252
- // Create agent metadata subdirectories (data only, no prompts)
253
- ensureDir(path.join(dataPath, 'knowledge'));
254
- ensureDir(path.join(dataPath, 'refs'));
255
- ensureDir(path.join(dataPath, 'tasks'));
256
- ensureDir(path.join(dataPath, 'templates'));
257
- }
258
-
259
- // Get the agent-core directory path
260
- const agentCoreDir = getAgentCoreDir();
261
-
262
- // Sync metadata (knowledge, refs, tasks) from agent-core to all storage locations
263
- syncMetadataToAll(agentCoreDir, dataPaths);
264
-
265
- // Also copy templates to all storage locations
266
- copyDirToAllStoragePaths(path.join(agentCoreDir, 'templates'), 'templates', dataPaths);
267
-
268
- // Load prompts for IDE-specific locations
269
- const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
270
-
271
- // Copy prompts to tool-specific locations (for IDE integration)
272
- if (config.tools.includes('copilot')) {
273
- const copilotPath = getAgentPromptPath(workspacePath, 'copilot');
274
- ensureDir(copilotPath);
275
- copyPromptsToDir(prompts, copilotPath, '.agent.md');
276
- }
277
-
278
- if (config.tools.includes('antigravity')) {
279
- const antigravityPath = getAgentPromptPath(workspacePath, 'antigravity');
280
- ensureDir(antigravityPath);
281
- copyPromptsToDir(prompts, antigravityPath, '.md');
282
- }
283
-
284
- // Create workspace config (inside .rrce-workflow folder)
285
- const workspaceConfigPath = path.join(workspacePath, '.rrce-workflow', 'config.yaml');
286
- ensureDir(path.dirname(workspaceConfigPath));
287
-
288
- let configContent = `# RRCE-Workflow Configuration
289
- version: 1
290
-
291
- storage:
292
- mode: ${config.storageMode}`;
293
-
294
- // Add custom global path if different from default
295
- if (config.globalPath && config.globalPath !== getDefaultRRCEHome()) {
296
- configContent += `\n globalPath: "${config.globalPath}"`;
297
- }
298
-
299
- configContent += `
300
-
301
- project:
302
- name: "${workspaceName}"
303
-
304
- tools:
305
- copilot: ${config.tools.includes('copilot')}
306
- antigravity: ${config.tools.includes('antigravity')}
307
- `;
308
-
309
- // Add linked projects if any
310
- if (config.linkedProjects.length > 0) {
311
- configContent += `\nlinked_projects:\n`;
312
- config.linkedProjects.forEach(name => {
313
- configContent += ` - ${name}\n`;
314
- });
315
- }
316
-
317
- fs.writeFileSync(workspaceConfigPath, configContent);
318
-
319
- // Generate VSCode workspace file if using copilot or has linked projects
320
- if (config.tools.includes('copilot') || config.linkedProjects.length > 0) {
321
- generateVSCodeWorkspace(workspacePath, workspaceName, config.linkedProjects, config.globalPath);
322
- }
323
- }
324
-
325
- /**
326
- * Get data paths based on storage mode and custom global path
327
- */
328
- function getDataPaths(
329
- mode: StorageMode,
330
- workspaceName: string,
331
- workspaceRoot: string,
332
- customGlobalPath?: string
333
- ): string[] {
334
- const globalPath = path.join(customGlobalPath || getDefaultRRCEHome(), 'workspaces', workspaceName);
335
- const workspacePath = path.join(workspaceRoot, '.rrce-workflow');
336
-
337
- switch (mode) {
338
- case 'global':
339
- return [globalPath];
340
- case 'workspace':
341
- return [workspacePath];
342
- case 'both':
343
- return [workspacePath, globalPath];
344
- default:
345
- return [globalPath];
346
- }
347
- }
@@ -1,93 +0,0 @@
1
- import { confirm, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
2
- import pc from 'picocolors';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import {
6
- ensureDir,
7
- getLocalWorkspacePath,
8
- getGlobalWorkspacePath,
9
- getEffectiveRRCEHome,
10
- getConfigPath
11
- } from '../../lib/paths';
12
- import { copyDirRecursive } from './utils';
13
-
14
- /**
15
- * Sync workspace knowledge to global storage so other projects can reference it
16
- */
17
- export async function runSyncToGlobalFlow(workspacePath: string, workspaceName: string) {
18
- const localPath = getLocalWorkspacePath(workspacePath);
19
- const customGlobalPath = getEffectiveRRCEHome(workspacePath);
20
- const globalPath = path.join(customGlobalPath, 'workspaces', workspaceName);
21
-
22
- // Check what exists locally
23
- const subdirs = ['knowledge', 'prompts', 'templates', 'tasks', 'refs'];
24
- const existingDirs = subdirs.filter(dir =>
25
- fs.existsSync(path.join(localPath, dir))
26
- );
27
-
28
- if (existingDirs.length === 0) {
29
- outro(pc.yellow('No data found in workspace storage to sync.'));
30
- return;
31
- }
32
-
33
- // Show what will be synced
34
- note(
35
- `The following will be copied to global storage:\n${existingDirs.map(d => ` • ${d}/`).join('\n')}\n\nDestination: ${pc.cyan(globalPath)}`,
36
- 'Sync Preview'
37
- );
38
-
39
- const shouldSync = await confirm({
40
- message: 'Proceed with sync to global storage?',
41
- initialValue: true,
42
- });
43
-
44
- if (isCancel(shouldSync) || !shouldSync) {
45
- outro('Sync cancelled.');
46
- return;
47
- }
48
-
49
- const s = spinner();
50
- s.start('Syncing to global storage');
51
-
52
- try {
53
- // Ensure global directory exists
54
- ensureDir(globalPath);
55
-
56
- // Copy each directory
57
- for (const dir of existingDirs) {
58
- const srcDir = path.join(localPath, dir);
59
- const destDir = path.join(globalPath, dir);
60
- ensureDir(destDir);
61
-
62
- // Copy files recursively
63
- copyDirRecursive(srcDir, destDir);
64
- }
65
-
66
- // Update the config to reflect 'both' mode
67
- const configFilePath = getConfigPath(workspacePath);
68
- let configContent = fs.readFileSync(configFilePath, 'utf-8');
69
- configContent = configContent.replace(/mode:\s*workspace/, 'mode: both');
70
- fs.writeFileSync(configFilePath, configContent);
71
-
72
- s.stop('Sync complete');
73
-
74
- const summary = [
75
- `Synced directories:`,
76
- ...existingDirs.map(d => ` ✓ ${d}/`),
77
- ``,
78
- `Global path: ${pc.cyan(globalPath)}`,
79
- `Storage mode updated to: ${pc.bold('both')}`,
80
- ``,
81
- `Other projects can now link this knowledge!`,
82
- ];
83
-
84
- note(summary.join('\n'), 'Sync Summary');
85
-
86
- outro(pc.green('✓ Workspace knowledge synced to global storage!'));
87
-
88
- } catch (error) {
89
- s.stop('Error occurred');
90
- cancel(`Failed to sync: ${error instanceof Error ? error.message : String(error)}`);
91
- process.exit(1);
92
- }
93
- }
@@ -1,124 +0,0 @@
1
- import { confirm, spinner, note, outro, cancel, isCancel } from '@clack/prompts';
2
- import pc from 'picocolors';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import type { StorageMode } from '../../types/prompt';
6
- import {
7
- ensureDir,
8
- resolveAllDataPaths,
9
- getAgentPromptPath,
10
- copyDirToAllStoragePaths,
11
- getEffectiveRRCEHome,
12
- getConfigPath
13
- } from '../../lib/paths';
14
- import { loadPromptsFromDir, getAgentCorePromptsDir, getAgentCoreDir } from '../../lib/prompts';
15
- import { copyPromptsToDir } from './utils';
16
-
17
- /**
18
- * Update prompts and templates from the package without resetting config
19
- */
20
- export async function runUpdateFlow(
21
- workspacePath: string,
22
- workspaceName: string,
23
- currentStorageMode: string | null
24
- ) {
25
- const s = spinner();
26
- s.start('Checking for updates');
27
-
28
- try {
29
- const agentCoreDir = getAgentCoreDir();
30
- const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
31
-
32
- // Determine storage paths based on current mode
33
- const mode = (currentStorageMode as StorageMode) || 'global';
34
-
35
- // Use effective RRCE_HOME from config for path resolution
36
- const customGlobalPath = getEffectiveRRCEHome(workspacePath);
37
- const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
38
-
39
- s.stop('Updates found');
40
-
41
- // Show what will be updated
42
- note(
43
- `The following will be updated from the package:\n • prompts/ (${prompts.length} agent prompts)\n • templates/ (output templates)\n\nTarget locations:\n${dataPaths.map(p => ` • ${p}`).join('\n')}`,
44
- 'Update Preview'
45
- );
46
-
47
- const shouldUpdate = await confirm({
48
- message: 'Proceed with update?',
49
- initialValue: true,
50
- });
51
-
52
- if (isCancel(shouldUpdate) || !shouldUpdate) {
53
- outro('Update cancelled.');
54
- return;
55
- }
56
-
57
- s.start('Updating from package');
58
-
59
- // Update templates in all storage locations (no prompts in data paths)
60
- for (const dataPath of dataPaths) {
61
- // Update templates only
62
- copyDirToAllStoragePaths(path.join(agentCoreDir, 'templates'), 'templates', [dataPath]);
63
- }
64
-
65
- // Also update tool-specific locations if configured
66
- const configFilePath = getConfigPath(workspacePath);
67
- const configContent = fs.readFileSync(configFilePath, 'utf-8');
68
-
69
- if (configContent.includes('copilot: true')) {
70
- const copilotPath = getAgentPromptPath(workspacePath, 'copilot');
71
- ensureDir(copilotPath);
72
- copyPromptsToDir(prompts, copilotPath, '.agent.md');
73
- }
74
-
75
- if (configContent.includes('antigravity: true')) {
76
- const antigravityPath = getAgentPromptPath(workspacePath, 'antigravity');
77
- ensureDir(antigravityPath);
78
- copyPromptsToDir(prompts, antigravityPath, '.md');
79
- }
80
-
81
- s.stop('Update complete');
82
-
83
- const summary = [
84
- `Updated:`,
85
- ` ✓ ${prompts.length} agent prompts`,
86
- ` ✓ Output templates`,
87
- ``,
88
- `Your configuration and knowledge files were preserved.`,
89
- ];
90
-
91
- note(summary.join('\n'), 'Update Summary');
92
-
93
- outro(pc.green('✓ Successfully updated from package!'));
94
-
95
- } catch (error) {
96
- s.stop('Error occurred');
97
- cancel(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
98
- process.exit(1);
99
- }
100
- }
101
-
102
- /**
103
- * Resolve all data paths with custom global path support
104
- */
105
- function resolveAllDataPathsWithCustomGlobal(
106
- mode: StorageMode,
107
- workspaceName: string,
108
- workspaceRoot: string,
109
- customGlobalPath: string
110
- ): string[] {
111
- const globalPath = path.join(customGlobalPath, 'workspaces', workspaceName);
112
- const workspacePath = path.join(workspaceRoot, '.rrce-workflow');
113
-
114
- switch (mode) {
115
- case 'global':
116
- return [globalPath];
117
- case 'workspace':
118
- return [workspacePath];
119
- case 'both':
120
- return [workspacePath, globalPath];
121
- default:
122
- return [globalPath];
123
- }
124
- }