rbin-task-flow 1.27.1 → 1.30.3
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-status/SKILL.md +1 -1
- package/.claude/skills/task-flow-sync/workflow.md +3 -3
- package/.cursor/rules/task-flow-cursor.mdc +3 -0
- package/.cursor/rules/task-flow-sync.mdc +3 -3
- package/.cursor/rules/task_generation.mdc +2 -2
- 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 +22 -9
- package/.task-flow/dev-logs/.gitkeep +0 -0
- package/.task-flow/guides/AI-PLATFORMS.md +2 -2
- package/.task-flow/guides/CODEX.md +5 -3
- package/.task-flow/guides/CURSOR.md +3 -3
- package/.task-flow/guides/GRAPHIFY.md +3 -3
- package/.task-flow/guides/platforms/claude-code.md +1 -1
- package/.task-flow/guides/platforms/cursor.md +10 -20
- package/AGENTS.md +8 -6
- package/README.md +44 -52
- package/bin/cli.js +9 -4
- package/lib/cursor.js +1 -1
- package/lib/gitignore.js +40 -71
- package/lib/install.js +95 -20
- 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
|
}
|
|
@@ -59,9 +57,15 @@ async function installInProject(targetPath, options = {}) {
|
|
|
59
57
|
console.log(
|
|
60
58
|
chalk.blue('🔗 Git:'),
|
|
61
59
|
shareAiConfig
|
|
62
|
-
? chalk.yellow('share-ai-config') + chalk.gray(' (
|
|
63
|
-
: chalk.gray('
|
|
60
|
+
? chalk.yellow('share-ai-config') + chalk.gray(' (flag saved in install-meta.json)')
|
|
61
|
+
: chalk.gray('appends .task-flow to .gitignore')
|
|
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,15 +110,18 @@ 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
|
|
|
107
|
-
await updateGitignore(targetPath
|
|
122
|
+
await updateGitignore(targetPath);
|
|
108
123
|
showSuccess('.gitignore updated');
|
|
109
|
-
|
|
110
|
-
showInfo('Git: .cursor/skills/ and .cursor/rules/ can be committed (see .gitignore comment)');
|
|
111
|
-
}
|
|
124
|
+
showInfo('Git: appended .task-flow to .gitignore');
|
|
112
125
|
|
|
113
126
|
spinner.text = 'Installing agent skills...';
|
|
114
127
|
await copySkillsToProject(targetPath);
|
|
@@ -144,13 +157,12 @@ async function installInProject(targetPath, options = {}) {
|
|
|
144
157
|
}
|
|
145
158
|
|
|
146
159
|
async function copyConfigs(targetPath, options = {}) {
|
|
147
|
-
const isUpdate = options.update || false;
|
|
148
160
|
const isReset = options.reset || false;
|
|
149
161
|
const profile = options.profile;
|
|
162
|
+
const taskBackup = options.taskBackup || null;
|
|
150
163
|
|
|
151
164
|
const rulesResult = await copyCursorRules(targetPath, TEMPLATE_DIR, {
|
|
152
165
|
profile,
|
|
153
|
-
update: isUpdate,
|
|
154
166
|
reset: isReset,
|
|
155
167
|
});
|
|
156
168
|
if (rulesResult?.mode === PROFILE_MINIMAL) {
|
|
@@ -200,7 +212,11 @@ async function copyConfigs(targetPath, options = {}) {
|
|
|
200
212
|
showSuccess('Codex instructions (AGENTS.md)');
|
|
201
213
|
}
|
|
202
214
|
|
|
203
|
-
await copyTaskFlow(targetPath, {
|
|
215
|
+
await copyTaskFlow(targetPath, {
|
|
216
|
+
reset: isReset,
|
|
217
|
+
keepTasks: options.keepTasks === true,
|
|
218
|
+
taskBackup,
|
|
219
|
+
});
|
|
204
220
|
}
|
|
205
221
|
|
|
206
222
|
const LEGACY_TASK_FLOW_ROOT_FILES = [
|
|
@@ -255,9 +271,55 @@ async function migrateLegacyTaskFlowLayout(taskFlowDest) {
|
|
|
255
271
|
}
|
|
256
272
|
}
|
|
257
273
|
|
|
274
|
+
async function backupTaskFiles(taskFlowDest) {
|
|
275
|
+
const backup = {};
|
|
276
|
+
const files = ['tasks.input.txt', 'tasks.status.md'];
|
|
277
|
+
for (const name of files) {
|
|
278
|
+
const filePath = path.join(taskFlowDest, name);
|
|
279
|
+
if (await fs.pathExists(filePath)) {
|
|
280
|
+
backup[name] = await fs.readFile(filePath, 'utf8');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const internalPath = path.join(taskFlowDest, '.internal');
|
|
284
|
+
if (await fs.pathExists(internalPath)) {
|
|
285
|
+
backup['.internal'] = await fs.mkdtemp(path.join(os.tmpdir(), 'rbin-task-flow-internal-'));
|
|
286
|
+
await fs.copy(internalPath, path.join(backup['.internal'], '.internal'));
|
|
287
|
+
}
|
|
288
|
+
const devLogsPath = path.join(taskFlowDest, 'dev-logs');
|
|
289
|
+
if (await fs.pathExists(devLogsPath)) {
|
|
290
|
+
backup['dev-logs'] = await fs.mkdtemp(path.join(os.tmpdir(), 'rbin-task-flow-dev-logs-'));
|
|
291
|
+
await fs.copy(devLogsPath, path.join(backup['dev-logs'], 'dev-logs'));
|
|
292
|
+
}
|
|
293
|
+
return backup;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function restoreTaskFiles(taskFlowDest, backup) {
|
|
297
|
+
if (!backup) return;
|
|
298
|
+
for (const name of ['tasks.input.txt', 'tasks.status.md']) {
|
|
299
|
+
if (backup[name] !== undefined) {
|
|
300
|
+
await fs.writeFile(path.join(taskFlowDest, name), backup[name], 'utf8');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (backup['.internal']) {
|
|
304
|
+
const src = path.join(backup['.internal'], '.internal');
|
|
305
|
+
if (await fs.pathExists(src)) {
|
|
306
|
+
await fs.copy(src, path.join(taskFlowDest, '.internal'), { overwrite: true });
|
|
307
|
+
}
|
|
308
|
+
await fs.remove(backup['.internal']);
|
|
309
|
+
}
|
|
310
|
+
if (backup['dev-logs']) {
|
|
311
|
+
const src = path.join(backup['dev-logs'], 'dev-logs');
|
|
312
|
+
if (await fs.pathExists(src)) {
|
|
313
|
+
await fs.copy(src, path.join(taskFlowDest, 'dev-logs'), { overwrite: true });
|
|
314
|
+
}
|
|
315
|
+
await fs.remove(backup['dev-logs']);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
258
319
|
async function copyTaskFlow(targetPath, options = {}) {
|
|
259
|
-
const isUpdate = options.update || false;
|
|
260
320
|
const isReset = options.reset || false;
|
|
321
|
+
const keepTasks = options.keepTasks === true;
|
|
322
|
+
const taskBackup = options.taskBackup || null;
|
|
261
323
|
const taskFlowSrc = path.join(TEMPLATE_DIR, '.task-flow');
|
|
262
324
|
const taskFlowDest = path.join(targetPath, '.task-flow');
|
|
263
325
|
|
|
@@ -271,11 +333,15 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
271
333
|
path.join(taskFlowDest, 'tasks.status.md'),
|
|
272
334
|
path.join(taskFlowDest, 'install-meta.json'),
|
|
273
335
|
];
|
|
336
|
+
const PRESERVED_KEEP_TASKS = [
|
|
337
|
+
path.join(taskFlowDest, 'tasks.input.txt'),
|
|
338
|
+
path.join(taskFlowDest, 'tasks.status.md'),
|
|
339
|
+
];
|
|
274
340
|
|
|
275
341
|
await fs.copy(taskFlowSrc, taskFlowDest, {
|
|
276
342
|
overwrite: true,
|
|
277
343
|
filter: (src, dest) => {
|
|
278
|
-
if (isReset) {
|
|
344
|
+
if (isReset && !keepTasks) {
|
|
279
345
|
return true;
|
|
280
346
|
}
|
|
281
347
|
|
|
@@ -283,7 +349,11 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
283
349
|
return false;
|
|
284
350
|
}
|
|
285
351
|
|
|
286
|
-
if (
|
|
352
|
+
if (keepTasks && PRESERVED_KEEP_TASKS.includes(dest) && fs.existsSync(dest)) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (!isReset && !keepTasks && PRESERVED_ON_INIT.includes(dest) && fs.existsSync(dest)) {
|
|
287
357
|
return false;
|
|
288
358
|
}
|
|
289
359
|
|
|
@@ -291,15 +361,20 @@ async function copyTaskFlow(targetPath, options = {}) {
|
|
|
291
361
|
},
|
|
292
362
|
});
|
|
293
363
|
|
|
364
|
+
if (taskBackup) {
|
|
365
|
+
await restoreTaskFiles(taskFlowDest, taskBackup);
|
|
366
|
+
}
|
|
367
|
+
|
|
294
368
|
await fs.ensureDir(path.join(taskFlowDest, 'contexts'));
|
|
369
|
+
await fs.ensureDir(path.join(taskFlowDest, 'dev-logs'));
|
|
295
370
|
await fs.ensureDir(path.join(taskFlowDest, 'guides', 'reports'));
|
|
296
371
|
await migrateLegacyTaskFlowLayout(taskFlowDest);
|
|
297
372
|
|
|
298
373
|
showSuccess('Task Flow directory');
|
|
299
|
-
if (
|
|
374
|
+
if (keepTasks) {
|
|
375
|
+
showInfo('Kept: tasks.input.txt, tasks.status.md, .internal/, dev-logs/');
|
|
376
|
+
} else if (isReset) {
|
|
300
377
|
showWarning('Reset completed: .task-flow was recreated from scratch');
|
|
301
|
-
} else if (isUpdate) {
|
|
302
|
-
showInfo('Protected: .internal/ (your task data is safe)');
|
|
303
378
|
} else {
|
|
304
379
|
showInfo('Protected on init: .internal/, tasks.input.txt, tasks.status.md');
|
|
305
380
|
}
|
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
|
}
|