rrce-workflow 0.1.1 → 0.1.2
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/package.json +10 -16
- package/src/commands/selector.ts +42 -0
- package/src/commands/wizard.ts +130 -0
- package/src/index.ts +11 -0
- package/src/App.tsx +0 -110
- package/src/components/AgentSelector.tsx +0 -43
- package/src/components/Logo.tsx +0 -17
- package/src/components/Wizard.tsx +0 -170
- package/src/index.tsx +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rrce-workflow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
|
|
5
5
|
"author": "RRCE Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"ink"
|
|
25
25
|
],
|
|
26
26
|
"type": "module",
|
|
27
|
-
"module": "src/index.
|
|
27
|
+
"module": "src/index.ts",
|
|
28
28
|
"bin": {
|
|
29
29
|
"rrce-workflow": "bin/rrce-workflow.js"
|
|
30
30
|
},
|
|
@@ -35,28 +35,22 @@
|
|
|
35
35
|
"bin"
|
|
36
36
|
],
|
|
37
37
|
"scripts": {
|
|
38
|
-
"dev": "bun run src/index.
|
|
39
|
-
"wizard": "bun run src/index.
|
|
40
|
-
"select": "bun run src/index.
|
|
41
|
-
"start": "bun run src/index.
|
|
38
|
+
"dev": "bun run src/index.ts",
|
|
39
|
+
"wizard": "bun run src/index.ts wizard",
|
|
40
|
+
"select": "bun run src/index.ts select",
|
|
41
|
+
"start": "bun run src/index.ts"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=18",
|
|
45
45
|
"bun": ">=1.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"@clack/prompts": "^0.11.0",
|
|
48
49
|
"gray-matter": "^4.0.3",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"ink-gradient": "^3.0.0",
|
|
52
|
-
"ink-select-input": "^5.0.0",
|
|
53
|
-
"ink-spinner": "^5.0.0",
|
|
54
|
-
"pastel": "^4.0.0",
|
|
55
|
-
"react": "^18",
|
|
56
|
-
"zod": "^4"
|
|
50
|
+
"picocolors": "^1.1.1",
|
|
51
|
+
"zod": "^4.2.1"
|
|
57
52
|
},
|
|
58
53
|
"devDependencies": {
|
|
59
|
-
"@types/bun": "latest"
|
|
60
|
-
"@types/react": "^18"
|
|
54
|
+
"@types/bun": "latest"
|
|
61
55
|
}
|
|
62
56
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { intro, select, note, cancel, isCancel, outro } from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { loadPromptsFromDir, getAgentCorePromptsDir } from '../lib/prompts';
|
|
5
|
+
import type { ParsedPrompt } from '../types/prompt';
|
|
6
|
+
|
|
7
|
+
export async function runSelector() {
|
|
8
|
+
const workspaceName = path.basename(process.cwd());
|
|
9
|
+
|
|
10
|
+
intro(pc.cyan(pc.inverse(` RRCE-Workflow | ${workspaceName} `)));
|
|
11
|
+
|
|
12
|
+
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
13
|
+
|
|
14
|
+
if (prompts.length === 0) {
|
|
15
|
+
cancel('No agents found. Run `rrce-workflow` to set up.');
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const selection = await select({
|
|
20
|
+
message: 'Select an agent:',
|
|
21
|
+
options: prompts.map(p => ({
|
|
22
|
+
value: p,
|
|
23
|
+
label: p.frontmatter.name,
|
|
24
|
+
hint: p.frontmatter.description
|
|
25
|
+
})),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (isCancel(selection)) {
|
|
29
|
+
cancel('Selection cancelled.');
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const prompt = selection as ParsedPrompt;
|
|
34
|
+
|
|
35
|
+
note(
|
|
36
|
+
`Use this agent in your IDE by invoking:
|
|
37
|
+
${pc.bold(pc.cyan(`@${prompt.frontmatter.name}`))}`,
|
|
38
|
+
'Agent Selected'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
outro('Done');
|
|
42
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { intro, 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 { getGitUser } from '../lib/git';
|
|
6
|
+
import { detectWorkspaceRoot, getWorkspaceName, resolveDataPath, ensureDir, getAgentPromptPath } from '../lib/paths';
|
|
7
|
+
import type { StorageMode } from '../types/prompt';
|
|
8
|
+
import { loadPromptsFromDir, getAgentCorePromptsDir } from '../lib/prompts';
|
|
9
|
+
|
|
10
|
+
import type { ParsedPrompt } from '../types/prompt';
|
|
11
|
+
|
|
12
|
+
export async function runWizard() {
|
|
13
|
+
intro(pc.cyan(pc.inverse(' RRCE-Workflow Setup ')));
|
|
14
|
+
|
|
15
|
+
const s = spinner();
|
|
16
|
+
s.start('Detecting environment');
|
|
17
|
+
|
|
18
|
+
const workspacePath = detectWorkspaceRoot();
|
|
19
|
+
const workspaceName = getWorkspaceName(workspacePath);
|
|
20
|
+
const gitUser = getGitUser();
|
|
21
|
+
|
|
22
|
+
await new Promise(r => setTimeout(r, 800)); // Dramatic pause
|
|
23
|
+
s.stop('Environment detected');
|
|
24
|
+
|
|
25
|
+
note(
|
|
26
|
+
`Git User: ${pc.bold(gitUser || '(not found)')}
|
|
27
|
+
Workspace: ${pc.bold(workspaceName)}`,
|
|
28
|
+
'Context'
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const config = await group(
|
|
32
|
+
{
|
|
33
|
+
storageMode: () =>
|
|
34
|
+
select({
|
|
35
|
+
message: 'Where should workflow data be stored?',
|
|
36
|
+
options: [
|
|
37
|
+
{ value: 'global', label: 'Global (~/.rrce-workflow/)' },
|
|
38
|
+
{ value: 'workspace', label: 'Workspace (.rrce-workflow/)' },
|
|
39
|
+
{ value: 'both', label: 'Both' },
|
|
40
|
+
],
|
|
41
|
+
initialValue: 'global',
|
|
42
|
+
}),
|
|
43
|
+
tools: () =>
|
|
44
|
+
multiselect({
|
|
45
|
+
message: 'Which AI tools do you use?',
|
|
46
|
+
options: [
|
|
47
|
+
{ value: 'copilot', label: 'GitHub Copilot', hint: 'VSCode' },
|
|
48
|
+
{ value: 'antigravity', label: 'Antigravity IDE' },
|
|
49
|
+
],
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
52
|
+
confirm: () =>
|
|
53
|
+
confirm({
|
|
54
|
+
message: 'Create configuration?',
|
|
55
|
+
initialValue: true,
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
onCancel: () => {
|
|
60
|
+
cancel('Setup process cancelled.');
|
|
61
|
+
process.exit(0);
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (!config.confirm) {
|
|
67
|
+
outro('Setup cancelled by user.');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
s.start('Generating configuration');
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Create config file
|
|
75
|
+
const dataPath = resolveDataPath(config.storageMode as StorageMode, workspaceName, workspacePath);
|
|
76
|
+
ensureDir(dataPath);
|
|
77
|
+
|
|
78
|
+
// Load prompts
|
|
79
|
+
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
80
|
+
|
|
81
|
+
// Copy prompts
|
|
82
|
+
const selectedTools = config.tools as string[];
|
|
83
|
+
|
|
84
|
+
if (selectedTools.includes('copilot')) {
|
|
85
|
+
const copilotPath = getAgentPromptPath(workspacePath, 'copilot');
|
|
86
|
+
ensureDir(copilotPath);
|
|
87
|
+
copyPromptsToDir(prompts, copilotPath, '.agent.md');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (selectedTools.includes('antigravity')) {
|
|
91
|
+
const antigravityPath = getAgentPromptPath(workspacePath, 'antigravity');
|
|
92
|
+
ensureDir(antigravityPath);
|
|
93
|
+
copyPromptsToDir(prompts, antigravityPath, '.md');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Create workspace config
|
|
97
|
+
const workspaceConfigPath = path.join(workspacePath, '.rrce-workflow.yaml');
|
|
98
|
+
const configContent = `# RRCE-Workflow Configuration
|
|
99
|
+
version: 1
|
|
100
|
+
|
|
101
|
+
storage:
|
|
102
|
+
mode: ${config.storageMode}
|
|
103
|
+
|
|
104
|
+
project:
|
|
105
|
+
name: "${workspaceName}"
|
|
106
|
+
`;
|
|
107
|
+
fs.writeFileSync(workspaceConfigPath, configContent);
|
|
108
|
+
|
|
109
|
+
s.stop('Configuration generated');
|
|
110
|
+
|
|
111
|
+
outro(pc.green(`✓ Setup complete! You can now run "rrce-workflow select" to start using agents.`));
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
s.stop('Error occurred');
|
|
115
|
+
cancel(`Failed to setup: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function copyPromptsToDir(prompts: ParsedPrompt[], targetDir: string, extension: string) {
|
|
121
|
+
for (const prompt of prompts) {
|
|
122
|
+
const baseName = path.basename(prompt.filePath, '.md');
|
|
123
|
+
const targetName = baseName + extension;
|
|
124
|
+
const targetPath = path.join(targetDir, targetName);
|
|
125
|
+
|
|
126
|
+
// Read the full content including frontmatter
|
|
127
|
+
const content = fs.readFileSync(prompt.filePath, 'utf-8');
|
|
128
|
+
fs.writeFileSync(targetPath, content);
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/index.ts
ADDED
package/src/App.tsx
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { Wizard, type WizardConfig } from './components/Wizard';
|
|
4
|
-
import { AgentSelector } from './components/AgentSelector';
|
|
5
|
-
import { loadPromptsFromDir, getAgentCorePromptsDir } from './lib/prompts';
|
|
6
|
-
import { ensureDir, getAgentPromptPath, resolveDataPath, getRRCEHome } from './lib/paths';
|
|
7
|
-
import type { ParsedPrompt } from './types/prompt';
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
|
|
11
|
-
type AppMode = 'wizard' | 'select' | 'done';
|
|
12
|
-
|
|
13
|
-
interface AppProps {
|
|
14
|
-
command?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function App({ command }: AppProps) {
|
|
18
|
-
const [mode, setMode] = React.useState<AppMode>(command === 'select' ? 'select' : 'wizard');
|
|
19
|
-
const [selectedPrompt, setSelectedPrompt] = React.useState<ParsedPrompt | null>(null);
|
|
20
|
-
const [message, setMessage] = React.useState<string | null>(null);
|
|
21
|
-
|
|
22
|
-
// Load prompts from agent-core
|
|
23
|
-
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
24
|
-
|
|
25
|
-
const handleWizardComplete = (config: WizardConfig) => {
|
|
26
|
-
// Create config file
|
|
27
|
-
const dataPath = resolveDataPath(config.storageMode, config.workspaceName, config.workspacePath);
|
|
28
|
-
ensureDir(dataPath);
|
|
29
|
-
|
|
30
|
-
// Copy prompts to appropriate locations
|
|
31
|
-
if (config.tools.copilot) {
|
|
32
|
-
const copilotPath = getAgentPromptPath(config.workspacePath, 'copilot');
|
|
33
|
-
ensureDir(copilotPath);
|
|
34
|
-
copyPromptsToDir(prompts, copilotPath, '.agent.md');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (config.tools.antigravity) {
|
|
38
|
-
const antigravityPath = getAgentPromptPath(config.workspacePath, 'antigravity');
|
|
39
|
-
ensureDir(antigravityPath);
|
|
40
|
-
copyPromptsToDir(prompts, antigravityPath, '.md');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create workspace config
|
|
44
|
-
const workspaceConfigPath = path.join(config.workspacePath, '.rrce-workflow.yaml');
|
|
45
|
-
const configContent = `# RRCE-Workflow Configuration
|
|
46
|
-
version: 1
|
|
47
|
-
|
|
48
|
-
storage:
|
|
49
|
-
mode: ${config.storageMode}
|
|
50
|
-
|
|
51
|
-
project:
|
|
52
|
-
name: "${config.workspaceName}"
|
|
53
|
-
`;
|
|
54
|
-
fs.writeFileSync(workspaceConfigPath, configContent);
|
|
55
|
-
|
|
56
|
-
setMessage(`✓ Setup complete! Created config and copied agents.`);
|
|
57
|
-
setMode('done');
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const handleAgentSelect = (prompt: ParsedPrompt) => {
|
|
61
|
-
setSelectedPrompt(prompt);
|
|
62
|
-
setMessage(`Selected: ${prompt.frontmatter.name}\n\nUse this agent in your IDE by invoking @${prompt.frontmatter.name}`);
|
|
63
|
-
setMode('done');
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
if (mode === 'wizard') {
|
|
67
|
-
return <Wizard onComplete={handleWizardComplete} />;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (mode === 'done') {
|
|
71
|
-
return (
|
|
72
|
-
<Box flexDirection="column" padding={1}>
|
|
73
|
-
<Box borderStyle="round" borderColor="green" paddingX={2}>
|
|
74
|
-
<Text bold color="green">RRCE-Workflow</Text>
|
|
75
|
-
</Box>
|
|
76
|
-
<Box marginTop={1}>
|
|
77
|
-
<Text>{message}</Text>
|
|
78
|
-
</Box>
|
|
79
|
-
</Box>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (prompts.length === 0) {
|
|
84
|
-
return (
|
|
85
|
-
<Box flexDirection="column" padding={1}>
|
|
86
|
-
<Text color="yellow">No prompts found. Run `rrce-workflow wizard` to set up.</Text>
|
|
87
|
-
</Box>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<AgentSelector
|
|
93
|
-
prompts={prompts}
|
|
94
|
-
workspaceName={path.basename(process.cwd())}
|
|
95
|
-
onSelect={handleAgentSelect}
|
|
96
|
-
/>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function copyPromptsToDir(prompts: ParsedPrompt[], targetDir: string, extension: string) {
|
|
101
|
-
for (const prompt of prompts) {
|
|
102
|
-
const baseName = path.basename(prompt.filePath, '.md');
|
|
103
|
-
const targetName = baseName + extension;
|
|
104
|
-
const targetPath = path.join(targetDir, targetName);
|
|
105
|
-
|
|
106
|
-
// Read the full content including frontmatter
|
|
107
|
-
const content = fs.readFileSync(prompt.filePath, 'utf-8');
|
|
108
|
-
fs.writeFileSync(targetPath, content);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import SelectInput from 'ink-select-input';
|
|
4
|
-
import type { ParsedPrompt } from '../types/prompt';
|
|
5
|
-
|
|
6
|
-
interface AgentSelectorProps {
|
|
7
|
-
prompts: ParsedPrompt[];
|
|
8
|
-
workspaceName: string;
|
|
9
|
-
onSelect: (prompt: ParsedPrompt) => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function AgentSelector({ prompts, workspaceName, onSelect }: AgentSelectorProps) {
|
|
13
|
-
const items = prompts.map((p, i) => ({
|
|
14
|
-
key: p.filePath,
|
|
15
|
-
label: `${p.frontmatter.name} - ${p.frontmatter.description}`,
|
|
16
|
-
value: p,
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
const handleSelect = (item: { value: ParsedPrompt }) => {
|
|
20
|
-
onSelect(item.value);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<Box flexDirection="column" padding={1}>
|
|
25
|
-
<Box borderStyle="round" borderColor="cyan" paddingX={2}>
|
|
26
|
-
<Text bold color="cyan">RRCE-Workflow</Text>
|
|
27
|
-
<Text> </Text>
|
|
28
|
-
<Text dimColor>| {workspaceName}</Text>
|
|
29
|
-
</Box>
|
|
30
|
-
|
|
31
|
-
<Box marginTop={1} flexDirection="column">
|
|
32
|
-
<Text>Select an agent:</Text>
|
|
33
|
-
<Box marginTop={1}>
|
|
34
|
-
<SelectInput items={items} onSelect={handleSelect} />
|
|
35
|
-
</Box>
|
|
36
|
-
</Box>
|
|
37
|
-
|
|
38
|
-
<Box marginTop={1}>
|
|
39
|
-
<Text dimColor>↑↓ to navigate, Enter to select</Text>
|
|
40
|
-
</Box>
|
|
41
|
-
</Box>
|
|
42
|
-
);
|
|
43
|
-
}
|
package/src/components/Logo.tsx
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import Gradient from 'ink-gradient';
|
|
3
|
-
import BigText from 'ink-big-text';
|
|
4
|
-
import { Box } from 'ink';
|
|
5
|
-
|
|
6
|
-
export function Logo() {
|
|
7
|
-
return (
|
|
8
|
-
<Box flexDirection="column" alignItems="center" marginBottom={1}>
|
|
9
|
-
<Gradient name="morning">
|
|
10
|
-
<BigText text="RRCE" align='center' font='block'/>
|
|
11
|
-
</Gradient>
|
|
12
|
-
<Gradient name="cristal">
|
|
13
|
-
<BigText text="Workflow" align='center' font='chrome'/>
|
|
14
|
-
</Gradient>
|
|
15
|
-
</Box>
|
|
16
|
-
);
|
|
17
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Box, Text, useInput } from 'ink';
|
|
3
|
-
import SelectInput from 'ink-select-input';
|
|
4
|
-
import Spinner from 'ink-spinner';
|
|
5
|
-
import Gradient from 'ink-gradient';
|
|
6
|
-
import { Logo } from './Logo';
|
|
7
|
-
import type { StorageMode } from '../types/prompt';
|
|
8
|
-
import { getGitUser } from '../lib/git';
|
|
9
|
-
import { detectWorkspaceRoot, getWorkspaceName } from '../lib/paths';
|
|
10
|
-
|
|
11
|
-
interface WizardProps {
|
|
12
|
-
onComplete: (config: WizardConfig) => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface WizardConfig {
|
|
16
|
-
workspaceName: string;
|
|
17
|
-
workspacePath: string;
|
|
18
|
-
storageMode: StorageMode;
|
|
19
|
-
tools: {
|
|
20
|
-
copilot: boolean;
|
|
21
|
-
antigravity: boolean;
|
|
22
|
-
};
|
|
23
|
-
gitUser: string | null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type WizardStep = 'welcome' | 'storage' | 'tools' | 'confirm';
|
|
27
|
-
|
|
28
|
-
const storageModeItems = [
|
|
29
|
-
{ label: 'Global (~/.rrce-workflow/)', value: 'global' as StorageMode },
|
|
30
|
-
{ label: 'Workspace (.rrce-workflow/)', value: 'workspace' as StorageMode },
|
|
31
|
-
{ label: 'Both', value: 'both' as StorageMode },
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
export function Wizard({ onComplete }: WizardProps) {
|
|
35
|
-
const [loading, setLoading] = React.useState(true);
|
|
36
|
-
const [step, setStep] = React.useState<WizardStep>('welcome');
|
|
37
|
-
const [storageMode, setStorageMode] = React.useState<StorageMode>('global');
|
|
38
|
-
const [tools, setTools] = React.useState({ copilot: true, antigravity: true });
|
|
39
|
-
|
|
40
|
-
// Data state
|
|
41
|
-
const [workspacePath, setWorkspacePath] = React.useState('');
|
|
42
|
-
const [workspaceName, setWorkspaceName] = React.useState('');
|
|
43
|
-
const [gitUser, setGitUser] = React.useState<string | null>(null);
|
|
44
|
-
|
|
45
|
-
React.useEffect(() => {
|
|
46
|
-
// Simulate a small delay for dramatic effect/loading feeling
|
|
47
|
-
const timer = setTimeout(() => {
|
|
48
|
-
setWorkspacePath(detectWorkspaceRoot());
|
|
49
|
-
setWorkspaceName(getWorkspaceName(detectWorkspaceRoot()));
|
|
50
|
-
setGitUser(getGitUser());
|
|
51
|
-
setLoading(false);
|
|
52
|
-
}, 800);
|
|
53
|
-
return () => clearTimeout(timer);
|
|
54
|
-
}, []);
|
|
55
|
-
|
|
56
|
-
useInput((input, key) => {
|
|
57
|
-
if (loading) return;
|
|
58
|
-
|
|
59
|
-
if (step === 'welcome' && key.return) {
|
|
60
|
-
setStep('storage');
|
|
61
|
-
} else if (step === 'confirm' && key.return) {
|
|
62
|
-
onComplete({
|
|
63
|
-
workspaceName,
|
|
64
|
-
workspacePath,
|
|
65
|
-
storageMode,
|
|
66
|
-
tools,
|
|
67
|
-
gitUser,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const handleStorageSelect = (item: { value: StorageMode }) => {
|
|
73
|
-
setStorageMode(item.value);
|
|
74
|
-
setStep('tools');
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const handleToolsSelect = (item: { value: string }) => {
|
|
78
|
-
if (item.value === 'done') {
|
|
79
|
-
setStep('confirm');
|
|
80
|
-
} else if (item.value === 'copilot') {
|
|
81
|
-
setTools((t: typeof tools) => ({ ...t, copilot: !t.copilot }));
|
|
82
|
-
} else if (item.value === 'antigravity') {
|
|
83
|
-
setTools((t: typeof tools) => ({ ...t, antigravity: !t.antigravity }));
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<Box flexDirection="column" padding={1} alignItems="center">
|
|
89
|
-
<Logo />
|
|
90
|
-
|
|
91
|
-
<Box borderStyle="round" borderColor="cyan" paddingX={2} paddingY={1} width={60} flexDirection="column">
|
|
92
|
-
{step === 'welcome' && (
|
|
93
|
-
<Box flexDirection="column" alignItems="center">
|
|
94
|
-
{loading ? (
|
|
95
|
-
<Box>
|
|
96
|
-
<Text color="cyan"><Spinner type="dots" /> </Text>
|
|
97
|
-
<Text> Detecting environment...</Text>
|
|
98
|
-
</Box>
|
|
99
|
-
) : (
|
|
100
|
-
<Box flexDirection="column" alignItems="center">
|
|
101
|
-
<Box marginBottom={1}>
|
|
102
|
-
<Text bold color="cyan">Welcome to RRCE-Workflow Setup</Text>
|
|
103
|
-
</Box>
|
|
104
|
-
|
|
105
|
-
<Box flexDirection="column" width="100%" marginBottom={1}>
|
|
106
|
-
<Box>
|
|
107
|
-
<Text color="green">✓</Text>
|
|
108
|
-
<Text> Git User: </Text>
|
|
109
|
-
<Text bold color="white">{gitUser || '(not found)'}</Text>
|
|
110
|
-
</Box>
|
|
111
|
-
<Box>
|
|
112
|
-
<Text color="green">✓</Text>
|
|
113
|
-
<Text> Workspace: </Text>
|
|
114
|
-
<Text bold color="white">{workspaceName}</Text>
|
|
115
|
-
</Box>
|
|
116
|
-
</Box>
|
|
117
|
-
|
|
118
|
-
<Text dimColor>Press Enter to continue ❯</Text>
|
|
119
|
-
</Box>
|
|
120
|
-
)}
|
|
121
|
-
</Box>
|
|
122
|
-
)}
|
|
123
|
-
|
|
124
|
-
{step === 'storage' && (
|
|
125
|
-
<Box flexDirection="column">
|
|
126
|
-
<Box marginBottom={1}><Text bold underline>Storage Configuration</Text></Box>
|
|
127
|
-
<Box marginBottom={1}><Text>Where should workflow data be stored?</Text></Box>
|
|
128
|
-
<SelectInput items={storageModeItems} onSelect={handleStorageSelect} />
|
|
129
|
-
</Box>
|
|
130
|
-
)}
|
|
131
|
-
|
|
132
|
-
{step === 'tools' && (
|
|
133
|
-
<Box flexDirection="column">
|
|
134
|
-
<Box marginBottom={1}><Text bold underline>AI Tools Integration</Text></Box>
|
|
135
|
-
<Box marginBottom={1}><Text>Select the tools you want to generate prompts for:</Text></Box>
|
|
136
|
-
<SelectInput
|
|
137
|
-
items={[
|
|
138
|
-
{ label: `[${tools.copilot ? 'x' : ' '}] GitHub Copilot`, value: 'copilot' },
|
|
139
|
-
{ label: `[${tools.antigravity ? 'x' : ' '}] Antigravity IDE`, value: 'antigravity' },
|
|
140
|
-
{ label: '───────────────', value: 'sep' },
|
|
141
|
-
{ label: 'Done (Continue)', value: 'done' },
|
|
142
|
-
]}
|
|
143
|
-
onSelect={handleToolsSelect}
|
|
144
|
-
/>
|
|
145
|
-
</Box>
|
|
146
|
-
)}
|
|
147
|
-
|
|
148
|
-
{step === 'confirm' && (
|
|
149
|
-
<Box flexDirection="column">
|
|
150
|
-
<Box marginBottom={1}><Text bold underline>Summary</Text></Box>
|
|
151
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
152
|
-
<Box><Text bold>Storage:</Text><Text> {storageMode}</Text></Box>
|
|
153
|
-
<Box><Text bold>Copilot:</Text><Text color={tools.copilot ? 'green' : 'red'}> {tools.copilot ? 'Enabled' : 'Disabled'}</Text></Box>
|
|
154
|
-
<Box><Text bold>Antigravity:</Text><Text color={tools.antigravity ? 'green' : 'red'}> {tools.antigravity ? 'Enabled' : 'Disabled'}</Text></Box>
|
|
155
|
-
</Box>
|
|
156
|
-
<Box marginTop={1} alignItems="center">
|
|
157
|
-
<Text dimColor>Press Enter to generate config ❯</Text>
|
|
158
|
-
</Box>
|
|
159
|
-
</Box>
|
|
160
|
-
)}
|
|
161
|
-
</Box>
|
|
162
|
-
|
|
163
|
-
{!loading && (
|
|
164
|
-
<Box marginTop={1}>
|
|
165
|
-
<Text dimColor>v{process.env.npm_package_version || '0.1.0'}</Text>
|
|
166
|
-
</Box>
|
|
167
|
-
)}
|
|
168
|
-
</Box>
|
|
169
|
-
);
|
|
170
|
-
}
|