rbin-task-flow 1.26.1 → 1.30.1
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/.claude/skills/task-flow-report/SKILL.md +3 -1
- package/.claude/skills/task-flow-run/SKILL.md +15 -9
- package/.claude/skills/task-flow-run/workflow.md +94 -34
- package/.claude/skills/task-flow-split/SKILL.md +23 -0
- package/.claude/skills/task-flow-status/SKILL.md +1 -1
- package/.claude/skills/task-flow-sync/workflow.md +3 -3
- package/.cursor/rules/task-flow-cursor.mdc +4 -0
- package/.cursor/rules/task-flow-sync.mdc +3 -3
- package/.cursor/rules/task_execution.mdc +1 -0
- package/.cursor/rules/task_generation.mdc +2 -2
- package/.cursor/rules/task_split.mdc +112 -0
- package/.cursor/rules/task_status.mdc +2 -2
- package/.cursor/rules/task_validate.mdc +3 -2
- package/.cursor/rules/task_work.mdc +8 -26
- package/.task-flow/README.md +32 -9
- package/.task-flow/dev-logs/.gitkeep +0 -0
- package/.task-flow/guides/AI-PLATFORMS.md +5 -4
- package/.task-flow/guides/CODEX.md +18 -3
- package/.task-flow/guides/CURSOR.md +3 -2
- package/.task-flow/guides/GRAPHIFY.md +3 -3
- package/.task-flow/guides/platforms/claude-code.md +4 -3
- package/.task-flow/guides/platforms/codex.md +1 -0
- package/.task-flow/guides/platforms/cursor.md +13 -11
- package/AGENTS.md +9 -6
- package/CLAUDE.md +1 -0
- package/README.md +38 -22
- package/bin/cli.js +8 -3
- package/lib/cursor.js +1 -1
- package/lib/install.js +91 -14
- package/lib/profiles.js +2 -2
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/install.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
|
+
const os = require('os');
|
|
2
3
|
const path = require('path');
|
|
3
4
|
const chalk = require('chalk');
|
|
4
5
|
const ora = require('ora');
|
|
@@ -23,7 +24,6 @@ const TEMPLATE_DIR = path.join(__dirname, '..');
|
|
|
23
24
|
const PACKAGE_VERSION = require('../package.json').version;
|
|
24
25
|
|
|
25
26
|
async function installInProject(targetPath, options = {}) {
|
|
26
|
-
const isUpdate = options.update || false;
|
|
27
27
|
const isReset = options.reset || false;
|
|
28
28
|
|
|
29
29
|
let profile;
|
|
@@ -42,8 +42,6 @@ async function installInProject(targetPath, options = {}) {
|
|
|
42
42
|
|
|
43
43
|
if (isReset) {
|
|
44
44
|
console.log(chalk.blue('♻️ Resetting RBIN Task Flow...'));
|
|
45
|
-
} else if (isUpdate) {
|
|
46
|
-
console.log(chalk.blue('🔄 Updating RBIN Task Flow...'));
|
|
47
45
|
} else {
|
|
48
46
|
console.log(chalk.blue('🚀 Installing RBIN Task Flow...'));
|
|
49
47
|
}
|
|
@@ -62,6 +60,12 @@ async function installInProject(targetPath, options = {}) {
|
|
|
62
60
|
? chalk.yellow('share-ai-config') + chalk.gray(' (.cursor/skills + .cursor/rules versionáveis)')
|
|
63
61
|
: chalk.gray('local .cursor/ gitignored (default)')
|
|
64
62
|
);
|
|
63
|
+
if (options.keepTasks) {
|
|
64
|
+
console.log(
|
|
65
|
+
chalk.blue('📋 Tasks:'),
|
|
66
|
+
chalk.yellow('keep-tasks') + chalk.gray(' (tasks.input.txt, tasks.status.md, .internal/, dev-logs/)')
|
|
67
|
+
);
|
|
68
|
+
}
|
|
65
69
|
console.log('');
|
|
66
70
|
|
|
67
71
|
const spinner = ora('Processing...').start();
|
|
@@ -81,8 +85,14 @@ async function installInProject(targetPath, options = {}) {
|
|
|
81
85
|
|
|
82
86
|
spinner.text = 'Creating directories...';
|
|
83
87
|
|
|
88
|
+
let taskBackup = null;
|
|
89
|
+
const taskFlowPath = path.join(targetPath, '.task-flow');
|
|
90
|
+
if (isReset && options.keepTasks && (await fs.pathExists(taskFlowPath))) {
|
|
91
|
+
taskBackup = await backupTaskFiles(taskFlowPath);
|
|
92
|
+
}
|
|
93
|
+
|
|
84
94
|
if (isReset) {
|
|
85
|
-
await fs.remove(
|
|
95
|
+
await fs.remove(taskFlowPath);
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
const dirs = [
|
|
@@ -100,7 +110,12 @@ async function installInProject(targetPath, options = {}) {
|
|
|
100
110
|
|
|
101
111
|
spinner.text = 'Copying configuration files...';
|
|
102
112
|
|
|
103
|
-
await copyConfigs(targetPath, {
|
|
113
|
+
await copyConfigs(targetPath, {
|
|
114
|
+
reset: isReset,
|
|
115
|
+
profile,
|
|
116
|
+
keepTasks: options.keepTasks === true,
|
|
117
|
+
taskBackup,
|
|
118
|
+
});
|
|
104
119
|
|
|
105
120
|
spinner.text = 'Updating .gitignore...';
|
|
106
121
|
|
|
@@ -144,13 +159,12 @@ async function installInProject(targetPath, options = {}) {
|
|
|
144
159
|
}
|
|
145
160
|
|
|
146
161
|
async function copyConfigs(targetPath, options = {}) {
|
|
147
|
-
const isUpdate = options.update || false;
|
|
148
162
|
const isReset = options.reset || false;
|
|
149
163
|
const profile = options.profile;
|
|
164
|
+
const taskBackup = options.taskBackup || null;
|
|
150
165
|
|
|
151
166
|
const rulesResult = await copyCursorRules(targetPath, TEMPLATE_DIR, {
|
|
152
167
|
profile,
|
|
153
|
-
update: isUpdate,
|
|
154
168
|
reset: isReset,
|
|
155
169
|
});
|
|
156
170
|
if (rulesResult?.mode === PROFILE_MINIMAL) {
|
|
@@ -200,7 +214,11 @@ async function copyConfigs(targetPath, options = {}) {
|
|
|
200
214
|
showSuccess('Codex instructions (AGENTS.md)');
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
await copyTaskFlow(targetPath, {
|
|
217
|
+
await copyTaskFlow(targetPath, {
|
|
218
|
+
reset: isReset,
|
|
219
|
+
keepTasks: options.keepTasks === true,
|
|
220
|
+
taskBackup,
|
|
221
|
+
});
|
|
204
222
|
}
|
|
205
223
|
|
|
206
224
|
const LEGACY_TASK_FLOW_ROOT_FILES = [
|
|
@@ -255,9 +273,55 @@ async function migrateLegacyTaskFlowLayout(taskFlowDest) {
|
|
|
255
273
|
}
|
|
256
274
|
}
|
|
257
275
|
|
|
276
|
+
async function backupTaskFiles(taskFlowDest) {
|
|
277
|
+
const backup = {};
|
|
278
|
+
const files = ['tasks.input.txt', 'tasks.status.md'];
|
|
279
|
+
for (const name of files) {
|
|
280
|
+
const filePath = path.join(taskFlowDest, name);
|
|
281
|
+
if (await fs.pathExists(filePath)) {
|
|
282
|
+
backup[name] = await fs.readFile(filePath, 'utf8');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const internalPath = path.join(taskFlowDest, '.internal');
|
|
286
|
+
if (await fs.pathExists(internalPath)) {
|
|
287
|
+
backup['.internal'] = await fs.mkdtemp(path.join(os.tmpdir(), 'rbin-task-flow-internal-'));
|
|
288
|
+
await fs.copy(internalPath, path.join(backup['.internal'], '.internal'));
|
|
289
|
+
}
|
|
290
|
+
const devLogsPath = path.join(taskFlowDest, 'dev-logs');
|
|
291
|
+
if (await fs.pathExists(devLogsPath)) {
|
|
292
|
+
backup['dev-logs'] = await fs.mkdtemp(path.join(os.tmpdir(), 'rbin-task-flow-dev-logs-'));
|
|
293
|
+
await fs.copy(devLogsPath, path.join(backup['dev-logs'], 'dev-logs'));
|
|
294
|
+
}
|
|
295
|
+
return backup;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async function restoreTaskFiles(taskFlowDest, backup) {
|
|
299
|
+
if (!backup) return;
|
|
300
|
+
for (const name of ['tasks.input.txt', 'tasks.status.md']) {
|
|
301
|
+
if (backup[name] !== undefined) {
|
|
302
|
+
await fs.writeFile(path.join(taskFlowDest, name), backup[name], 'utf8');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (backup['.internal']) {
|
|
306
|
+
const src = path.join(backup['.internal'], '.internal');
|
|
307
|
+
if (await fs.pathExists(src)) {
|
|
308
|
+
await fs.copy(src, path.join(taskFlowDest, '.internal'), { overwrite: true });
|
|
309
|
+
}
|
|
310
|
+
await fs.remove(backup['.internal']);
|
|
311
|
+
}
|
|
312
|
+
if (backup['dev-logs']) {
|
|
313
|
+
const src = path.join(backup['dev-logs'], 'dev-logs');
|
|
314
|
+
if (await fs.pathExists(src)) {
|
|
315
|
+
await fs.copy(src, path.join(taskFlowDest, 'dev-logs'), { overwrite: true });
|
|
316
|
+
}
|
|
317
|
+
await fs.remove(backup['dev-logs']);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
258
321
|
async function copyTaskFlow(targetPath, options = {}) {
|
|
259
|
-
const isUpdate = options.update || false;
|
|
260
322
|
const isReset = options.reset || false;
|
|
323
|
+
const keepTasks = options.keepTasks === true;
|
|
324
|
+
const taskBackup = options.taskBackup || null;
|
|
261
325
|
const taskFlowSrc = path.join(TEMPLATE_DIR, '.task-flow');
|
|
262
326
|
const taskFlowDest = path.join(targetPath, '.task-flow');
|
|
263
327
|
|
|
@@ -271,11 +335,15 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
271
335
|
path.join(taskFlowDest, 'tasks.status.md'),
|
|
272
336
|
path.join(taskFlowDest, 'install-meta.json'),
|
|
273
337
|
];
|
|
338
|
+
const PRESERVED_KEEP_TASKS = [
|
|
339
|
+
path.join(taskFlowDest, 'tasks.input.txt'),
|
|
340
|
+
path.join(taskFlowDest, 'tasks.status.md'),
|
|
341
|
+
];
|
|
274
342
|
|
|
275
343
|
await fs.copy(taskFlowSrc, taskFlowDest, {
|
|
276
344
|
overwrite: true,
|
|
277
345
|
filter: (src, dest) => {
|
|
278
|
-
if (isReset) {
|
|
346
|
+
if (isReset && !keepTasks) {
|
|
279
347
|
return true;
|
|
280
348
|
}
|
|
281
349
|
|
|
@@ -283,7 +351,11 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
283
351
|
return false;
|
|
284
352
|
}
|
|
285
353
|
|
|
286
|
-
if (
|
|
354
|
+
if (keepTasks && PRESERVED_KEEP_TASKS.includes(dest) && fs.existsSync(dest)) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!isReset && !keepTasks && PRESERVED_ON_INIT.includes(dest) && fs.existsSync(dest)) {
|
|
287
359
|
return false;
|
|
288
360
|
}
|
|
289
361
|
|
|
@@ -291,15 +363,20 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
291
363
|
},
|
|
292
364
|
});
|
|
293
365
|
|
|
366
|
+
if (taskBackup) {
|
|
367
|
+
await restoreTaskFiles(taskFlowDest, taskBackup);
|
|
368
|
+
}
|
|
369
|
+
|
|
294
370
|
await fs.ensureDir(path.join(taskFlowDest, 'contexts'));
|
|
371
|
+
await fs.ensureDir(path.join(taskFlowDest, 'dev-logs'));
|
|
295
372
|
await fs.ensureDir(path.join(taskFlowDest, 'guides', 'reports'));
|
|
296
373
|
await migrateLegacyTaskFlowLayout(taskFlowDest);
|
|
297
374
|
|
|
298
375
|
showSuccess('Task Flow directory');
|
|
299
|
-
if (
|
|
376
|
+
if (keepTasks) {
|
|
377
|
+
showInfo('Kept: tasks.input.txt, tasks.status.md, .internal/, dev-logs/');
|
|
378
|
+
} else if (isReset) {
|
|
300
379
|
showWarning('Reset completed: .task-flow was recreated from scratch');
|
|
301
|
-
} else if (isUpdate) {
|
|
302
|
-
showInfo('Protected: .internal/ (your task data is safe)');
|
|
303
380
|
} else {
|
|
304
381
|
showInfo('Protected on init: .internal/, tasks.input.txt, tasks.status.md');
|
|
305
382
|
}
|
package/lib/profiles.js
CHANGED
|
@@ -68,7 +68,7 @@ async function resolveProfile(targetPath, options = {}) {
|
|
|
68
68
|
return PROFILE_STANDARD;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async function copyCursorRules(targetPath, templateDir, { profile,
|
|
71
|
+
async function copyCursorRules(targetPath, templateDir, { profile, reset }) {
|
|
72
72
|
const src = path.join(templateDir, '.cursor', 'rules');
|
|
73
73
|
const dest = path.join(targetPath, '.cursor', 'rules');
|
|
74
74
|
|
|
@@ -76,7 +76,7 @@ async function copyCursorRules(targetPath, templateDir, { profile, update, reset
|
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (
|
|
79
|
+
if (reset && fs.existsSync(dest)) {
|
|
80
80
|
await fs.emptyDir(dest);
|
|
81
81
|
}
|
|
82
82
|
await fs.ensureDir(dest);
|
package/lib/version.js
CHANGED
|
@@ -97,7 +97,7 @@ async function checkModelVersion(modelName, versionInfo, settingsPath, rl) {
|
|
|
97
97
|
}
|
|
98
98
|
await fs.writeJSON(fullSettingsPath, settings, { spaces: 2 });
|
|
99
99
|
console.log(chalk.green(` ✅ ${modelName} updated to ${versionInfo.latest}`));
|
|
100
|
-
console.log(chalk.cyan(' (Repository template updated - run init/
|
|
100
|
+
console.log(chalk.cyan(' (Repository template updated - run init/reset on projects to apply)'));
|
|
101
101
|
} else {
|
|
102
102
|
console.log(chalk.cyan(' Skipped update'));
|
|
103
103
|
}
|