rbin-task-flow 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/install.js ADDED
@@ -0,0 +1,280 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const ora = require('ora');
5
+ const { showHeader, showSuccess, showError, showWarning, showInfo, showNextSteps } = require('./utils');
6
+
7
+ // DiretΓ³rio onde o pacote npm estΓ‘ instalado globalmente
8
+ const TEMPLATE_DIR = path.join(__dirname, '..');
9
+
10
+ async function installInProject(targetPath, options = {}) {
11
+ const isUpdate = options.update || false;
12
+
13
+ showHeader();
14
+
15
+ if (isUpdate) {
16
+ console.log(chalk.blue('πŸ”„ Updating RBIN Task Flow...'));
17
+ } else {
18
+ console.log(chalk.blue('πŸš€ Installing RBIN Task Flow...'));
19
+ }
20
+
21
+ console.log(chalk.blue('πŸ“ Target:'), targetPath, '\n');
22
+
23
+ const spinner = ora('Processing...').start();
24
+
25
+ try {
26
+ // Verificar se diretΓ³rio existe
27
+ if (!fs.existsSync(targetPath)) {
28
+ spinner.fail(chalk.red(`Directory not found: ${targetPath}`));
29
+ process.exit(1);
30
+ }
31
+
32
+ // Verificar permissΓ΅es de escrita
33
+ try {
34
+ fs.accessSync(targetPath, fs.constants.W_OK);
35
+ } catch (error) {
36
+ spinner.fail(chalk.red('No write permission in target directory'));
37
+ process.exit(1);
38
+ }
39
+
40
+ spinner.text = 'Creating directories...';
41
+
42
+ // Criar diretΓ³rios necessΓ‘rios
43
+ const dirs = [
44
+ '.cursor/rules',
45
+ '.claude',
46
+ '.gemini',
47
+ '.task-flow'
48
+ ];
49
+
50
+ for (const dir of dirs) {
51
+ await fs.ensureDir(path.join(targetPath, dir));
52
+ }
53
+
54
+ spinner.text = 'Copying configuration files...';
55
+
56
+ // Copiar arquivos de configuraΓ§Γ£o
57
+ await copyConfigs(targetPath);
58
+
59
+ spinner.text = 'Updating .gitignore...';
60
+
61
+ // Atualizar .gitignore
62
+ await updateGitignore(targetPath);
63
+
64
+ spinner.succeed(chalk.green('Installation completed!'));
65
+
66
+ console.log('');
67
+
68
+ // Mostrar versΓ΅es configuradas
69
+ await showModelVersions(targetPath);
70
+
71
+ showNextSteps(targetPath);
72
+
73
+ } catch (error) {
74
+ spinner.fail(chalk.red('Installation failed'));
75
+ console.error(chalk.red('\nError:'), error.message);
76
+ process.exit(1);
77
+ }
78
+ }
79
+
80
+ async function copyConfigs(targetPath) {
81
+ // Copiar regras do Cursor
82
+ const cursorRulesPath = path.join(TEMPLATE_DIR, '.cursor/rules');
83
+ if (fs.existsSync(cursorRulesPath)) {
84
+ await fs.copy(
85
+ cursorRulesPath,
86
+ path.join(targetPath, '.cursor/rules'),
87
+ { overwrite: true }
88
+ );
89
+ showSuccess('Cursor rules');
90
+ }
91
+
92
+ // Copiar settings do Cursor
93
+ const cursorSettingsPath = path.join(TEMPLATE_DIR, '.cursor/settings.json');
94
+ if (fs.existsSync(cursorSettingsPath)) {
95
+ await fs.copy(
96
+ cursorSettingsPath,
97
+ path.join(targetPath, '.cursor/settings.json'),
98
+ { overwrite: true }
99
+ );
100
+ showSuccess('Cursor settings');
101
+ }
102
+
103
+ // Copiar settings do Claude
104
+ const claudeSettingsPath = path.join(TEMPLATE_DIR, '.claude/settings.json');
105
+ if (fs.existsSync(claudeSettingsPath)) {
106
+ await fs.copy(
107
+ claudeSettingsPath,
108
+ path.join(targetPath, '.claude/settings.json'),
109
+ { overwrite: true }
110
+ );
111
+ showSuccess('Claude settings');
112
+ }
113
+
114
+ // Copiar instruΓ§Γ΅es do Claude
115
+ const claudeInstructionsPath = path.join(TEMPLATE_DIR, 'CLAUDE.md');
116
+ if (fs.existsSync(claudeInstructionsPath)) {
117
+ await fs.copy(
118
+ claudeInstructionsPath,
119
+ path.join(targetPath, 'CLAUDE.md'),
120
+ { overwrite: true }
121
+ );
122
+ showSuccess('Claude instructions');
123
+ }
124
+
125
+ // Copiar settings do Gemini
126
+ const geminiSettingsPath = path.join(TEMPLATE_DIR, '.gemini/settings.json');
127
+ if (fs.existsSync(geminiSettingsPath)) {
128
+ await fs.copy(
129
+ geminiSettingsPath,
130
+ path.join(targetPath, '.gemini/settings.json'),
131
+ { overwrite: true }
132
+ );
133
+ showSuccess('Gemini settings');
134
+ }
135
+
136
+ // Copiar instruΓ§Γ΅es do Gemini
137
+ const geminiInstructionsPath = path.join(TEMPLATE_DIR, 'GEMINI.md');
138
+ if (fs.existsSync(geminiInstructionsPath)) {
139
+ await fs.copy(
140
+ geminiInstructionsPath,
141
+ path.join(targetPath, 'GEMINI.md'),
142
+ { overwrite: true }
143
+ );
144
+ showSuccess('Gemini instructions');
145
+ }
146
+
147
+ // Copiar Task Flow (preservando dados internos)
148
+ await copyTaskFlow(targetPath);
149
+ }
150
+
151
+ async function copyTaskFlow(targetPath) {
152
+ const taskFlowSrc = path.join(TEMPLATE_DIR, '.task-flow');
153
+ const taskFlowDest = path.join(targetPath, '.task-flow');
154
+
155
+ await fs.ensureDir(taskFlowDest);
156
+
157
+ showSuccess('Task Flow directory');
158
+ showInfo('Note: .internal/tasks.json and .internal/status.json are NOT overwritten (your data is safe)');
159
+
160
+ // Copiar apenas templates, nΓ£o sobrescrever dados do usuΓ‘rio
161
+ const files = [
162
+ { name: 'README.md', overwrite: true },
163
+ { name: 'tasks.input.txt', overwrite: false },
164
+ { name: 'tasks.status.md', overwrite: false }
165
+ ];
166
+
167
+ for (const file of files) {
168
+ const src = path.join(taskFlowSrc, file.name);
169
+ const dest = path.join(taskFlowDest, file.name);
170
+
171
+ if (fs.existsSync(src)) {
172
+ // Sempre sobrescrever README, outros arquivos sΓ³ se nΓ£o existirem
173
+ if (file.overwrite || !fs.existsSync(dest)) {
174
+ await fs.copy(src, dest, { overwrite: file.overwrite });
175
+ }
176
+ }
177
+ }
178
+
179
+ // NΓ£o copiar .internal - deixar que seja criado pela IA
180
+ }
181
+
182
+ async function updateGitignore(targetPath) {
183
+ const gitignorePath = path.join(targetPath, '.gitignore');
184
+
185
+ // Criar se nΓ£o existe
186
+ if (!fs.existsSync(gitignorePath)) {
187
+ await fs.writeFile(gitignorePath, '');
188
+ }
189
+
190
+ let content = await fs.readFile(gitignorePath, 'utf8');
191
+
192
+ // Entradas a adicionar
193
+ const entries = [
194
+ '.claude/',
195
+ '.gemini/',
196
+ '.cursor/',
197
+ '.task-flow/',
198
+ 'CLAUDE.md',
199
+ 'GEMINI.md'
200
+ ];
201
+
202
+ // Remover entradas antigas (caso existam)
203
+ for (const entry of entries) {
204
+ const regex = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'gm');
205
+ content = content.replace(regex, '');
206
+ }
207
+
208
+ // Remover linhas vazias consecutivas
209
+ content = content.replace(/\n{3,}/g, '\n\n');
210
+
211
+ // Adicionar novas entradas
212
+ if (!content.endsWith('\n')) {
213
+ content += '\n';
214
+ }
215
+
216
+ content += '\n' + entries.join('\n') + '\n';
217
+
218
+ await fs.writeFile(gitignorePath, content);
219
+
220
+ showSuccess('.gitignore updated');
221
+ }
222
+
223
+ async function showModelVersions(targetPath) {
224
+ console.log(chalk.cyan('═'.repeat(60)));
225
+ console.log(chalk.magenta('πŸ“‹ Model Versions Configured:'));
226
+ console.log(chalk.cyan('═'.repeat(60)));
227
+ console.log('');
228
+
229
+ let hasModels = false;
230
+
231
+ // Claude
232
+ const claudeSettingsPath = path.join(targetPath, '.claude/settings.json');
233
+ if (fs.existsSync(claudeSettingsPath)) {
234
+ try {
235
+ const settings = await fs.readJSON(claudeSettingsPath);
236
+ if (settings.model) {
237
+ console.log(chalk.blue('Claude:'), chalk.yellow(settings.model));
238
+ hasModels = true;
239
+ }
240
+ } catch (error) {
241
+ // Ignorar erros de parsing
242
+ }
243
+ }
244
+
245
+ // Cursor
246
+ const cursorSettingsPath = path.join(targetPath, '.cursor/settings.json');
247
+ if (fs.existsSync(cursorSettingsPath)) {
248
+ try {
249
+ const settings = await fs.readJSON(cursorSettingsPath);
250
+ if (settings.model) {
251
+ console.log(chalk.blue('Cursor:'), chalk.yellow(settings.model));
252
+ hasModels = true;
253
+ }
254
+ } catch (error) {
255
+ // Ignorar erros de parsing
256
+ }
257
+ }
258
+
259
+ // Gemini
260
+ const geminiSettingsPath = path.join(targetPath, '.gemini/settings.json');
261
+ if (fs.existsSync(geminiSettingsPath)) {
262
+ try {
263
+ const settings = await fs.readJSON(geminiSettingsPath);
264
+ if (settings.model) {
265
+ console.log(chalk.blue('Gemini:'), chalk.yellow(settings.model));
266
+ hasModels = true;
267
+ }
268
+ } catch (error) {
269
+ // Ignorar erros de parsing
270
+ }
271
+ }
272
+
273
+ if (!hasModels) {
274
+ console.log(chalk.yellow('No model versions configured yet'));
275
+ }
276
+
277
+ console.log('');
278
+ }
279
+
280
+ module.exports = { installInProject };
package/lib/utils.js ADDED
@@ -0,0 +1,45 @@
1
+ const chalk = require('chalk');
2
+
3
+ function showHeader() {
4
+ console.clear();
5
+ console.log(chalk.cyan('╔════════════════════════════════════════════════════════════════╗'));
6
+ console.log(chalk.cyan('β•‘') + ' ' + chalk.magenta('✨ RBIN Task Flow - Installation ✨') + ' ' + chalk.cyan('β•‘'));
7
+ console.log(chalk.cyan('β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•') + '\n');
8
+ }
9
+
10
+ function showSuccess(message) {
11
+ console.log(chalk.green('βœ… ' + message));
12
+ }
13
+
14
+ function showError(message) {
15
+ console.log(chalk.red('❌ ' + message));
16
+ }
17
+
18
+ function showWarning(message) {
19
+ console.log(chalk.yellow('⚠️ ' + message));
20
+ }
21
+
22
+ function showInfo(message) {
23
+ console.log(chalk.blue('ℹ️ ' + message));
24
+ }
25
+
26
+ function showNextSteps(targetPath) {
27
+ console.log('\n' + chalk.cyan('═'.repeat(60)));
28
+ console.log(chalk.magenta.bold(' Next Steps:'));
29
+ console.log(chalk.cyan('═'.repeat(60)));
30
+ console.log(chalk.blue(' 1.'), 'Edit', chalk.yellow('.task-flow/tasks.input.txt'));
31
+ console.log(chalk.blue(' 2.'), 'Use AI command:', chalk.cyan('task-flow: sync'));
32
+ console.log(chalk.blue(' 3.'), 'Work on tasks:', chalk.cyan('task-flow: run next X'));
33
+ console.log(chalk.blue(' 4.'), 'Check status:', chalk.cyan('task-flow: status'));
34
+ console.log(chalk.cyan('═'.repeat(60)));
35
+ console.log(chalk.blue('\n See'), chalk.yellow('.task-flow/README.md'), chalk.blue('for all available commands\n'));
36
+ }
37
+
38
+ module.exports = {
39
+ showHeader,
40
+ showSuccess,
41
+ showError,
42
+ showWarning,
43
+ showInfo,
44
+ showNextSteps
45
+ };
package/lib/version.js ADDED
@@ -0,0 +1,114 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const readline = require('readline');
5
+
6
+ const TEMPLATE_DIR = path.join(__dirname, '..');
7
+
8
+ function createInterface() {
9
+ return readline.createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout
12
+ });
13
+ }
14
+
15
+ function question(rl, query) {
16
+ return new Promise((resolve) => {
17
+ rl.question(query, resolve);
18
+ });
19
+ }
20
+
21
+ async function checkVersionUpdates() {
22
+ const versionsFilePath = path.join(TEMPLATE_DIR, '.model-versions.json');
23
+
24
+ if (!fs.existsSync(versionsFilePath)) {
25
+ console.log(chalk.yellow('⚠️ No version file found'));
26
+ return;
27
+ }
28
+
29
+ try {
30
+ const versions = await fs.readJSON(versionsFilePath);
31
+
32
+ console.log('\n' + chalk.cyan('╔════════════════════════════════════════════════════════════════╗'));
33
+ console.log(chalk.cyan('β•‘') + ' ' + chalk.magenta('πŸ“‹ Model Version Check') + ' ' + chalk.cyan('β•‘'));
34
+ console.log(chalk.cyan('β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•') + '\n');
35
+
36
+ const rl = createInterface();
37
+
38
+ // Check Claude
39
+ if (versions.claude) {
40
+ await checkModelVersion('Claude', versions.claude, '.claude/settings.json', rl);
41
+ }
42
+
43
+ // Check Cursor
44
+ if (versions.cursor) {
45
+ await checkModelVersion('Cursor', versions.cursor, '.cursor/settings.json', rl);
46
+ }
47
+
48
+ // Check Gemini
49
+ if (versions.gemini) {
50
+ await checkModelVersion('Gemini', versions.gemini, '.gemini/settings.json', rl);
51
+ }
52
+
53
+ rl.close();
54
+
55
+ console.log(chalk.green('\nβœ… Version check completed!\n'));
56
+
57
+ } catch (error) {
58
+ console.error(chalk.red('Error reading version file:'), error.message);
59
+ }
60
+ }
61
+
62
+ async function checkModelVersion(modelName, versionInfo, settingsPath, rl) {
63
+ const fullSettingsPath = path.join(TEMPLATE_DIR, settingsPath);
64
+
65
+ if (!fs.existsSync(fullSettingsPath)) {
66
+ console.log(chalk.gray(`${modelName}: Settings file not found`));
67
+ return;
68
+ }
69
+
70
+ try {
71
+ const settings = await fs.readJSON(fullSettingsPath);
72
+ const currentVersion = settings.model;
73
+
74
+ if (!currentVersion) {
75
+ console.log(chalk.gray(`${modelName}: No model configured`));
76
+ return;
77
+ }
78
+
79
+ console.log('');
80
+ console.log(chalk.blue('━'.repeat(60)));
81
+ console.log(chalk.blue.bold(`${modelName}:`));
82
+ console.log(chalk.cyan(' Current:'), chalk.yellow(currentVersion));
83
+ console.log(chalk.cyan(' Latest:'), chalk.yellow(versionInfo.latest));
84
+
85
+ if (versionInfo.checkUrl) {
86
+ console.log(chalk.cyan(' Info:'), chalk.gray(versionInfo.checkUrl));
87
+ }
88
+
89
+ if (currentVersion !== versionInfo.latest) {
90
+ console.log(chalk.yellow('\n ⚠️ New version available!'));
91
+
92
+ const answer = await question(
93
+ rl,
94
+ chalk.blue(` Update ${modelName} to ${versionInfo.latest}? [y/N]: `)
95
+ );
96
+
97
+ if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
98
+ settings.model = versionInfo.latest;
99
+ await fs.writeJSON(fullSettingsPath, settings, { spaces: 2 });
100
+ console.log(chalk.green(` βœ… ${modelName} updated to ${versionInfo.latest}`));
101
+ console.log(chalk.cyan(' (Repository template updated - run init/update on projects to apply)'));
102
+ } else {
103
+ console.log(chalk.cyan(' Skipped update'));
104
+ }
105
+ } else {
106
+ console.log(chalk.green(' βœ… Up to date'));
107
+ }
108
+
109
+ } catch (error) {
110
+ console.log(chalk.red(`${modelName}: Error reading settings -`), error.message);
111
+ }
112
+ }
113
+
114
+ module.exports = { checkVersionUpdates };
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "rbin-task-flow",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered task management for Claude, Cursor, and Gemini",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "rbin-task-flow": "./bin/cli.js",
8
+ "task-flow": "./bin/cli.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"No tests yet\"",
12
+ "prepublishOnly": "chmod +x bin/cli.js"
13
+ },
14
+ "keywords": [
15
+ "task-flow",
16
+ "ai",
17
+ "claude",
18
+ "cursor",
19
+ "gemini",
20
+ "cli",
21
+ "task-management",
22
+ "ai-powered"
23
+ ],
24
+ "author": "Rubens de Oliveira",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/rubensdeoliveira/rbin-task-flow.git"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ ".cursor/",
33
+ ".claude/",
34
+ ".gemini/",
35
+ ".task-flow/",
36
+ ".model-versions.json",
37
+ "CLAUDE.md",
38
+ "GEMINI.md",
39
+ "lib/"
40
+ ],
41
+ "preferGlobal": true,
42
+ "engines": {
43
+ "node": ">=14.0.0"
44
+ },
45
+ "dependencies": {
46
+ "chalk": "^4.1.2",
47
+ "commander": "^11.0.0",
48
+ "fs-extra": "^11.0.0",
49
+ "ora": "^5.4.1"
50
+ }
51
+ }