rrce-workflow 0.3.13 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.js +468 -514
- package/docs/AI_AGENT_GUIDE.md +65 -0
- package/package.json +1 -1
- package/dist/commands/selector.d.ts +0 -1
- package/dist/commands/selector.js +0 -29
- package/dist/commands/wizard/index.d.ts +0 -1
- package/dist/commands/wizard/index.js +0 -86
- package/dist/commands/wizard/link-flow.d.ts +0 -5
- package/dist/commands/wizard/link-flow.js +0 -97
- package/dist/commands/wizard/setup-flow.d.ts +0 -4
- package/dist/commands/wizard/setup-flow.js +0 -262
- package/dist/commands/wizard/sync-flow.d.ts +0 -4
- package/dist/commands/wizard/sync-flow.js +0 -67
- package/dist/commands/wizard/update-flow.d.ts +0 -4
- package/dist/commands/wizard/update-flow.js +0 -85
- package/dist/commands/wizard/utils.d.ts +0 -9
- package/dist/commands/wizard/utils.js +0 -33
- package/dist/commands/wizard/vscode.d.ts +0 -15
- package/dist/commands/wizard/vscode.js +0 -148
- package/dist/index.d.ts +0 -1
- package/dist/lib/autocomplete-prompt.d.ts +0 -14
- package/dist/lib/autocomplete-prompt.js +0 -167
- package/dist/lib/detection.d.ts +0 -44
- package/dist/lib/detection.js +0 -185
- package/dist/lib/git.d.ts +0 -12
- package/dist/lib/git.js +0 -37
- package/dist/lib/paths.d.ts +0 -108
- package/dist/lib/paths.js +0 -296
- package/dist/lib/prompts.d.ts +0 -18
- package/dist/lib/prompts.js +0 -62
- package/dist/types/prompt.d.ts +0 -54
- package/dist/types/prompt.js +0 -20
|
@@ -1,85 +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 { ensureDir, getAgentPromptPath, copyDirToAllStoragePaths, getEffectiveRRCEHome, getConfigPath } from '../../lib/paths';
|
|
6
|
-
import { loadPromptsFromDir, getAgentCorePromptsDir, getAgentCoreDir } from '../../lib/prompts';
|
|
7
|
-
import { copyPromptsToDir } from './utils';
|
|
8
|
-
/**
|
|
9
|
-
* Update prompts and templates from the package without resetting config
|
|
10
|
-
*/
|
|
11
|
-
export async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
12
|
-
const s = spinner();
|
|
13
|
-
s.start('Checking for updates');
|
|
14
|
-
try {
|
|
15
|
-
const agentCoreDir = getAgentCoreDir();
|
|
16
|
-
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
17
|
-
// Determine storage paths based on current mode
|
|
18
|
-
const mode = currentStorageMode || 'global';
|
|
19
|
-
// Use effective RRCE_HOME from config for path resolution
|
|
20
|
-
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
21
|
-
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
22
|
-
s.stop('Updates found');
|
|
23
|
-
// Show what will be updated
|
|
24
|
-
note(`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')}`, 'Update Preview');
|
|
25
|
-
const shouldUpdate = await confirm({
|
|
26
|
-
message: 'Proceed with update?',
|
|
27
|
-
initialValue: true,
|
|
28
|
-
});
|
|
29
|
-
if (isCancel(shouldUpdate) || !shouldUpdate) {
|
|
30
|
-
outro('Update cancelled.');
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
s.start('Updating from package');
|
|
34
|
-
// Update templates in all storage locations (no prompts in data paths)
|
|
35
|
-
for (const dataPath of dataPaths) {
|
|
36
|
-
// Update templates only
|
|
37
|
-
copyDirToAllStoragePaths(path.join(agentCoreDir, 'templates'), 'templates', [dataPath]);
|
|
38
|
-
}
|
|
39
|
-
// Also update tool-specific locations if configured
|
|
40
|
-
const configFilePath = getConfigPath(workspacePath);
|
|
41
|
-
const configContent = fs.readFileSync(configFilePath, 'utf-8');
|
|
42
|
-
if (configContent.includes('copilot: true')) {
|
|
43
|
-
const copilotPath = getAgentPromptPath(workspacePath, 'copilot');
|
|
44
|
-
ensureDir(copilotPath);
|
|
45
|
-
copyPromptsToDir(prompts, copilotPath, '.agent.md');
|
|
46
|
-
}
|
|
47
|
-
if (configContent.includes('antigravity: true')) {
|
|
48
|
-
const antigravityPath = getAgentPromptPath(workspacePath, 'antigravity');
|
|
49
|
-
ensureDir(antigravityPath);
|
|
50
|
-
copyPromptsToDir(prompts, antigravityPath, '.md');
|
|
51
|
-
}
|
|
52
|
-
s.stop('Update complete');
|
|
53
|
-
const summary = [
|
|
54
|
-
`Updated:`,
|
|
55
|
-
` ✓ ${prompts.length} agent prompts`,
|
|
56
|
-
` ✓ Output templates`,
|
|
57
|
-
``,
|
|
58
|
-
`Your configuration and knowledge files were preserved.`,
|
|
59
|
-
];
|
|
60
|
-
note(summary.join('\n'), 'Update Summary');
|
|
61
|
-
outro(pc.green('✓ Successfully updated from package!'));
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
s.stop('Error occurred');
|
|
65
|
-
cancel(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Resolve all data paths with custom global path support
|
|
71
|
-
*/
|
|
72
|
-
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
73
|
-
const globalPath = path.join(customGlobalPath, 'workspaces', workspaceName);
|
|
74
|
-
const workspacePath = path.join(workspaceRoot, '.rrce-workflow');
|
|
75
|
-
switch (mode) {
|
|
76
|
-
case 'global':
|
|
77
|
-
return [globalPath];
|
|
78
|
-
case 'workspace':
|
|
79
|
-
return [workspacePath];
|
|
80
|
-
case 'both':
|
|
81
|
-
return [workspacePath, globalPath];
|
|
82
|
-
default:
|
|
83
|
-
return [globalPath];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { ParsedPrompt } from '../../types/prompt';
|
|
2
|
-
/**
|
|
3
|
-
* Copy parsed prompts to a target directory with specified extension
|
|
4
|
-
*/
|
|
5
|
-
export declare function copyPromptsToDir(prompts: ParsedPrompt[], targetDir: string, extension: string): void;
|
|
6
|
-
/**
|
|
7
|
-
* Recursively copy a directory
|
|
8
|
-
*/
|
|
9
|
-
export declare function copyDirRecursive(src: string, dest: string): void;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { ensureDir } from '../../lib/paths';
|
|
4
|
-
/**
|
|
5
|
-
* Copy parsed prompts to a target directory with specified extension
|
|
6
|
-
*/
|
|
7
|
-
export function copyPromptsToDir(prompts, targetDir, extension) {
|
|
8
|
-
for (const prompt of prompts) {
|
|
9
|
-
const baseName = path.basename(prompt.filePath, '.md');
|
|
10
|
-
const targetName = baseName + extension;
|
|
11
|
-
const targetPath = path.join(targetDir, targetName);
|
|
12
|
-
// Read the full content including frontmatter
|
|
13
|
-
const content = fs.readFileSync(prompt.filePath, 'utf-8');
|
|
14
|
-
fs.writeFileSync(targetPath, content);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Recursively copy a directory
|
|
19
|
-
*/
|
|
20
|
-
export function copyDirRecursive(src, dest) {
|
|
21
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
22
|
-
for (const entry of entries) {
|
|
23
|
-
const srcPath = path.join(src, entry.name);
|
|
24
|
-
const destPath = path.join(dest, entry.name);
|
|
25
|
-
if (entry.isDirectory()) {
|
|
26
|
-
ensureDir(destPath);
|
|
27
|
-
copyDirRecursive(srcPath, destPath);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
fs.copyFileSync(srcPath, destPath);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type DetectedProject } from '../../lib/detection';
|
|
2
|
-
/**
|
|
3
|
-
* Generate or update VSCode workspace file with linked project folders
|
|
4
|
-
*
|
|
5
|
-
* Features:
|
|
6
|
-
* - Main workspace is clearly marked as the primary project
|
|
7
|
-
* - Linked folders are grouped under a "References" section (via naming)
|
|
8
|
-
* - Folders are organized by project with icons for type (📚 📎 📋)
|
|
9
|
-
* - Reference folders are marked as readonly in workspace settings
|
|
10
|
-
*/
|
|
11
|
-
export declare function generateVSCodeWorkspace(workspacePath: string, workspaceName: string, linkedProjects: string[] | DetectedProject[], customGlobalPath?: string): void;
|
|
12
|
-
/**
|
|
13
|
-
* Remove a project's folders from the workspace file
|
|
14
|
-
*/
|
|
15
|
-
export declare function removeProjectFromWorkspace(workspacePath: string, workspaceName: string, projectName: string): void;
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { getRRCEHome } from '../../lib/paths';
|
|
4
|
-
import { getProjectFolders } from '../../lib/detection';
|
|
5
|
-
// Reference folder group prefix - used to visually group linked folders
|
|
6
|
-
const REFERENCE_GROUP_PREFIX = '📁 References';
|
|
7
|
-
/**
|
|
8
|
-
* Generate or update VSCode workspace file with linked project folders
|
|
9
|
-
*
|
|
10
|
-
* Features:
|
|
11
|
-
* - Main workspace is clearly marked as the primary project
|
|
12
|
-
* - Linked folders are grouped under a "References" section (via naming)
|
|
13
|
-
* - Folders are organized by project with icons for type (📚 📎 📋)
|
|
14
|
-
* - Reference folders are marked as readonly in workspace settings
|
|
15
|
-
*/
|
|
16
|
-
export function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
17
|
-
const workspaceFilePath = path.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
18
|
-
let workspace;
|
|
19
|
-
// Check if workspace file already exists
|
|
20
|
-
if (fs.existsSync(workspaceFilePath)) {
|
|
21
|
-
try {
|
|
22
|
-
const content = fs.readFileSync(workspaceFilePath, 'utf-8');
|
|
23
|
-
workspace = JSON.parse(content);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
// If parse fails, create new
|
|
27
|
-
workspace = { folders: [], settings: {} };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
workspace = { folders: [], settings: {} };
|
|
32
|
-
}
|
|
33
|
-
// Initialize settings if not present
|
|
34
|
-
if (!workspace.settings) {
|
|
35
|
-
workspace.settings = {};
|
|
36
|
-
}
|
|
37
|
-
// Clear existing folders and rebuild (to ensure proper ordering)
|
|
38
|
-
const existingNonReferencesFolders = workspace.folders.filter(f => f.path === '.' || (!f.name?.includes(REFERENCE_GROUP_PREFIX) && !f.name?.startsWith('📚') && !f.name?.startsWith('📎') && !f.name?.startsWith('📋')));
|
|
39
|
-
workspace.folders = [];
|
|
40
|
-
// 1. Add main workspace folder first with clear label
|
|
41
|
-
const mainFolder = {
|
|
42
|
-
path: '.',
|
|
43
|
-
name: `🏠 ${workspaceName} (workspace)`
|
|
44
|
-
};
|
|
45
|
-
workspace.folders.push(mainFolder);
|
|
46
|
-
// 2. Add any other existing non-references folders
|
|
47
|
-
for (const folder of existingNonReferencesFolders) {
|
|
48
|
-
if (folder.path !== '.') {
|
|
49
|
-
workspace.folders.push(folder);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// 3. Add reference folders grouped by project
|
|
53
|
-
const referenceFolderPaths = [];
|
|
54
|
-
// Determine if we're working with DetectedProject[] or string[]
|
|
55
|
-
const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === 'object';
|
|
56
|
-
if (isDetectedProjects) {
|
|
57
|
-
// New behavior: use DetectedProject[] with knowledge, refs, tasks folders
|
|
58
|
-
const projects = linkedProjects;
|
|
59
|
-
for (const project of projects) {
|
|
60
|
-
const folders = getProjectFolders(project);
|
|
61
|
-
const sourceLabel = project.source === 'global' ? 'global' : 'local';
|
|
62
|
-
for (const folder of folders) {
|
|
63
|
-
referenceFolderPaths.push(folder.path);
|
|
64
|
-
// Check if already exists
|
|
65
|
-
const existingIndex = workspace.folders.findIndex(f => f.path === folder.path);
|
|
66
|
-
if (existingIndex === -1) {
|
|
67
|
-
workspace.folders.push({
|
|
68
|
-
path: folder.path,
|
|
69
|
-
name: `${folder.displayName} [${sourceLabel}]`,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Legacy behavior: string[] of project names (global storage only)
|
|
77
|
-
const projectNames = linkedProjects;
|
|
78
|
-
const rrceHome = customGlobalPath || getRRCEHome();
|
|
79
|
-
for (const projectName of projectNames) {
|
|
80
|
-
const projectDataPath = path.join(rrceHome, 'workspaces', projectName);
|
|
81
|
-
const folderTypes = [
|
|
82
|
-
{ subpath: 'knowledge', icon: '📚', type: 'knowledge' },
|
|
83
|
-
{ subpath: 'refs', icon: '📎', type: 'refs' },
|
|
84
|
-
{ subpath: 'tasks', icon: '📋', type: 'tasks' },
|
|
85
|
-
];
|
|
86
|
-
for (const { subpath, icon, type } of folderTypes) {
|
|
87
|
-
const folderPath = path.join(projectDataPath, subpath);
|
|
88
|
-
if (fs.existsSync(folderPath)) {
|
|
89
|
-
referenceFolderPaths.push(folderPath);
|
|
90
|
-
const existingIndex = workspace.folders.findIndex(f => f.path === folderPath);
|
|
91
|
-
if (existingIndex === -1) {
|
|
92
|
-
workspace.folders.push({
|
|
93
|
-
path: folderPath,
|
|
94
|
-
name: `${icon} ${projectName} (${type}) [global]`,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// 4. Add workspace settings to mark reference folders as readonly
|
|
102
|
-
// This uses files.readonlyInclude to make imported folders read-only
|
|
103
|
-
if (referenceFolderPaths.length > 0) {
|
|
104
|
-
const readonlyPatterns = {};
|
|
105
|
-
for (const folderPath of referenceFolderPaths) {
|
|
106
|
-
// Create a pattern that matches all files in this folder
|
|
107
|
-
readonlyPatterns[`${folderPath}/**`] = true;
|
|
108
|
-
}
|
|
109
|
-
// Merge with existing readonly patterns
|
|
110
|
-
const existingReadonly = workspace.settings['files.readonlyInclude'] || {};
|
|
111
|
-
workspace.settings['files.readonlyInclude'] = {
|
|
112
|
-
...existingReadonly,
|
|
113
|
-
...readonlyPatterns,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
// 5. Add helpful workspace settings for multi-root experience
|
|
117
|
-
workspace.settings['explorer.sortOrder'] = workspace.settings['explorer.sortOrder'] || 'default';
|
|
118
|
-
// Write workspace file with nice formatting
|
|
119
|
-
fs.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Remove a project's folders from the workspace file
|
|
123
|
-
*/
|
|
124
|
-
export function removeProjectFromWorkspace(workspacePath, workspaceName, projectName) {
|
|
125
|
-
const workspaceFilePath = path.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
126
|
-
if (!fs.existsSync(workspaceFilePath)) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
try {
|
|
130
|
-
const content = fs.readFileSync(workspaceFilePath, 'utf-8');
|
|
131
|
-
const workspace = JSON.parse(content);
|
|
132
|
-
// Filter out folders that match the project name
|
|
133
|
-
workspace.folders = workspace.folders.filter(f => !f.name?.includes(projectName));
|
|
134
|
-
// Also remove readonly patterns for this project
|
|
135
|
-
if (workspace.settings?.['files.readonlyInclude']) {
|
|
136
|
-
const readonly = workspace.settings['files.readonlyInclude'];
|
|
137
|
-
for (const pattern of Object.keys(readonly)) {
|
|
138
|
-
if (pattern.includes(projectName)) {
|
|
139
|
-
delete readonly[pattern];
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
fs.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
// Ignore errors
|
|
147
|
-
}
|
|
148
|
-
}
|
package/dist/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { isCancel } from '@clack/core';
|
|
2
|
-
interface DirectoryAutocompleteOptions {
|
|
3
|
-
message: string;
|
|
4
|
-
placeholder?: string;
|
|
5
|
-
initialValue?: string;
|
|
6
|
-
validate?: (value: string) => string | undefined;
|
|
7
|
-
hint?: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Custom text input with Tab-completion for directory paths
|
|
11
|
-
* Uses @clack/core TextPrompt with custom key handling
|
|
12
|
-
*/
|
|
13
|
-
export declare function directoryAutocomplete(opts: DirectoryAutocompleteOptions): Promise<string | symbol>;
|
|
14
|
-
export { isCancel };
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { TextPrompt, isCancel } from '@clack/core';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import pc from 'picocolors';
|
|
5
|
-
/**
|
|
6
|
-
* Custom text input with Tab-completion for directory paths
|
|
7
|
-
* Uses @clack/core TextPrompt with custom key handling
|
|
8
|
-
*/
|
|
9
|
-
export async function directoryAutocomplete(opts) {
|
|
10
|
-
let completions = [];
|
|
11
|
-
let completionIndex = 0;
|
|
12
|
-
let lastTabValue = '';
|
|
13
|
-
const prompt = new TextPrompt({
|
|
14
|
-
initialValue: opts.initialValue,
|
|
15
|
-
validate: opts.validate,
|
|
16
|
-
render() {
|
|
17
|
-
const title = `${pc.cyan('◆')} ${opts.message}`;
|
|
18
|
-
const hintText = opts.hint ? pc.dim(` (${opts.hint})`) : '';
|
|
19
|
-
let inputLine;
|
|
20
|
-
if (this.state === 'error') {
|
|
21
|
-
inputLine = `${pc.yellow('▲')} ${this.valueWithCursor}`;
|
|
22
|
-
}
|
|
23
|
-
else if (this.state === 'submit') {
|
|
24
|
-
inputLine = `${pc.green('✓')} ${pc.dim(String(this.value || ''))}`;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
inputLine = `${pc.cyan('│')} ${this.valueWithCursor || pc.dim(opts.placeholder || '')}`;
|
|
28
|
-
}
|
|
29
|
-
let result = `${title}${hintText}\n${inputLine}`;
|
|
30
|
-
if (this.state === 'error' && this.error) {
|
|
31
|
-
result += `\n${pc.yellow('│')} ${pc.yellow(this.error)}`;
|
|
32
|
-
}
|
|
33
|
-
// Show completion hint if multiple options
|
|
34
|
-
if (completions.length > 1 && this.state === 'active') {
|
|
35
|
-
const remaining = completions.length - 1;
|
|
36
|
-
result += `\n${pc.dim('│')} ${pc.dim(`+${remaining} more, press Tab again to cycle`)}`;
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
// Listen for key events - Tab key handling
|
|
42
|
-
prompt.on('key', (key) => {
|
|
43
|
-
if (key === '\t' || key === 'tab') {
|
|
44
|
-
handleTabCompletion(prompt);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// Reset completion state on any other key
|
|
48
|
-
completions = [];
|
|
49
|
-
completionIndex = 0;
|
|
50
|
-
lastTabValue = '';
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
function handleTabCompletion(p) {
|
|
54
|
-
const input = String(p.value || '');
|
|
55
|
-
// Expand ~ to home directory
|
|
56
|
-
const expanded = input.startsWith('~')
|
|
57
|
-
? input.replace(/^~/, process.env.HOME || '')
|
|
58
|
-
: input;
|
|
59
|
-
// If user hasn't changed input since last tab, cycle through completions
|
|
60
|
-
if (lastTabValue === input && completions.length > 1) {
|
|
61
|
-
completionIndex = (completionIndex + 1) % completions.length;
|
|
62
|
-
const completion = completions[completionIndex] || '';
|
|
63
|
-
setPromptValue(p, completion);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
// Get new completions
|
|
67
|
-
completions = getDirectoryCompletions(expanded);
|
|
68
|
-
completionIndex = 0;
|
|
69
|
-
lastTabValue = input;
|
|
70
|
-
if (completions.length === 1) {
|
|
71
|
-
// Single match - auto-complete with trailing slash if directory
|
|
72
|
-
const completion = completions[0] || '';
|
|
73
|
-
setPromptValue(p, completion.endsWith('/') ? completion : completion + '/');
|
|
74
|
-
completions = []; // Clear so next Tab gets fresh completions
|
|
75
|
-
lastTabValue = '';
|
|
76
|
-
}
|
|
77
|
-
else if (completions.length > 1) {
|
|
78
|
-
// Multiple matches - complete common prefix and show first
|
|
79
|
-
const commonPrefix = getCommonPrefix(completions);
|
|
80
|
-
if (commonPrefix.length > expanded.length) {
|
|
81
|
-
setPromptValue(p, commonPrefix);
|
|
82
|
-
lastTabValue = formatForDisplay(commonPrefix);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
// Show first completion
|
|
86
|
-
setPromptValue(p, completions[0] || '');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function setPromptValue(p, value) {
|
|
91
|
-
// Convert back to ~ format if in home directory for display
|
|
92
|
-
const displayValue = formatForDisplay(value);
|
|
93
|
-
// Update the prompt's value by emitting a value event
|
|
94
|
-
// This is a workaround since TextPrompt doesn't expose a direct setValue method
|
|
95
|
-
p.value = displayValue;
|
|
96
|
-
}
|
|
97
|
-
function formatForDisplay(value) {
|
|
98
|
-
const home = process.env.HOME || '';
|
|
99
|
-
return value.startsWith(home)
|
|
100
|
-
? value.replace(home, '~')
|
|
101
|
-
: value;
|
|
102
|
-
}
|
|
103
|
-
function getDirectoryCompletions(inputPath) {
|
|
104
|
-
try {
|
|
105
|
-
let dirToScan;
|
|
106
|
-
let prefix;
|
|
107
|
-
if (inputPath === '' || inputPath === '/') {
|
|
108
|
-
dirToScan = inputPath || '/';
|
|
109
|
-
prefix = '';
|
|
110
|
-
}
|
|
111
|
-
else if (inputPath.endsWith('/')) {
|
|
112
|
-
// User typed a complete directory path
|
|
113
|
-
dirToScan = inputPath;
|
|
114
|
-
prefix = '';
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// User is typing a partial name
|
|
118
|
-
dirToScan = path.dirname(inputPath);
|
|
119
|
-
prefix = path.basename(inputPath).toLowerCase();
|
|
120
|
-
}
|
|
121
|
-
if (!fs.existsSync(dirToScan)) {
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
const entries = fs.readdirSync(dirToScan, { withFileTypes: true })
|
|
125
|
-
.filter(entry => {
|
|
126
|
-
// Only directories
|
|
127
|
-
if (!entry.isDirectory())
|
|
128
|
-
return false;
|
|
129
|
-
// Skip hidden directories unless explicitly typing them
|
|
130
|
-
if (entry.name.startsWith('.') && !prefix.startsWith('.'))
|
|
131
|
-
return false;
|
|
132
|
-
// Match prefix
|
|
133
|
-
return prefix === '' || entry.name.toLowerCase().startsWith(prefix);
|
|
134
|
-
})
|
|
135
|
-
.map(entry => path.join(dirToScan, entry.name))
|
|
136
|
-
.sort();
|
|
137
|
-
return entries;
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return [];
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function getCommonPrefix(strings) {
|
|
144
|
-
if (strings.length === 0)
|
|
145
|
-
return '';
|
|
146
|
-
if (strings.length === 1)
|
|
147
|
-
return strings[0] || '';
|
|
148
|
-
let prefix = strings[0] || '';
|
|
149
|
-
for (let i = 1; i < strings.length; i++) {
|
|
150
|
-
const str = strings[i] || '';
|
|
151
|
-
while (prefix.length > 0 && !str.startsWith(prefix)) {
|
|
152
|
-
prefix = prefix.slice(0, -1);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return prefix;
|
|
156
|
-
}
|
|
157
|
-
const result = await prompt.prompt();
|
|
158
|
-
if (isCancel(result)) {
|
|
159
|
-
return result;
|
|
160
|
-
}
|
|
161
|
-
// Expand ~ in final result
|
|
162
|
-
const value = String(result || '');
|
|
163
|
-
return value.startsWith('~')
|
|
164
|
-
? value.replace(/^~/, process.env.HOME || '')
|
|
165
|
-
: value;
|
|
166
|
-
}
|
|
167
|
-
export { isCancel };
|
package/dist/lib/detection.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { StorageMode } from '../types/prompt';
|
|
2
|
-
/**
|
|
3
|
-
* Detected rrce-workflow project information
|
|
4
|
-
*/
|
|
5
|
-
export interface DetectedProject {
|
|
6
|
-
name: string;
|
|
7
|
-
path: string;
|
|
8
|
-
dataPath: string;
|
|
9
|
-
source: 'global' | 'sibling' | 'parent';
|
|
10
|
-
storageMode?: StorageMode;
|
|
11
|
-
knowledgePath?: string;
|
|
12
|
-
refsPath?: string;
|
|
13
|
-
tasksPath?: string;
|
|
14
|
-
}
|
|
15
|
-
interface ScanOptions {
|
|
16
|
-
excludeWorkspace?: string;
|
|
17
|
-
workspacePath?: string;
|
|
18
|
-
scanSiblings?: boolean;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Scan for rrce-workflow projects in various locations
|
|
22
|
-
*/
|
|
23
|
-
export declare function scanForProjects(options?: ScanOptions): DetectedProject[];
|
|
24
|
-
/**
|
|
25
|
-
* Parse a workspace config file
|
|
26
|
-
*/
|
|
27
|
-
export declare function parseWorkspaceConfig(configPath: string): {
|
|
28
|
-
name: string;
|
|
29
|
-
storageMode: StorageMode;
|
|
30
|
-
linkedProjects?: string[];
|
|
31
|
-
} | null;
|
|
32
|
-
/**
|
|
33
|
-
* Get display label for a detected project
|
|
34
|
-
*/
|
|
35
|
-
export declare function getProjectDisplayLabel(project: DetectedProject): string;
|
|
36
|
-
/**
|
|
37
|
-
* Get all linkable folders from a detected project
|
|
38
|
-
*/
|
|
39
|
-
export declare function getProjectFolders(project: DetectedProject): Array<{
|
|
40
|
-
path: string;
|
|
41
|
-
type: 'knowledge' | 'refs' | 'tasks';
|
|
42
|
-
displayName: string;
|
|
43
|
-
}>;
|
|
44
|
-
export {};
|