rbin-task-flow 1.19.5 → 1.23.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.
Files changed (65) hide show
  1. package/.claude/skills/rbin-coding-standards/SKILL.md +29 -0
  2. package/.claude/skills/rbin-coding-standards/reference.md +42 -0
  3. package/.claude/skills/rbin-git/SKILL.md +39 -0
  4. package/.claude/skills/task-flow-audit/SKILL.md +15 -0
  5. package/.claude/skills/task-flow-check/SKILL.md +15 -0
  6. package/.claude/skills/task-flow-estimate/SKILL.md +15 -0
  7. package/.claude/skills/task-flow-generate-flow/SKILL.md +15 -0
  8. package/.claude/skills/task-flow-improve-changes/SKILL.md +15 -0
  9. package/.claude/skills/task-flow-refactor/SKILL.md +14 -0
  10. package/.claude/skills/task-flow-report/SKILL.md +15 -0
  11. package/.claude/skills/task-flow-review/SKILL.md +14 -0
  12. package/.claude/skills/task-flow-run/SKILL.md +28 -0
  13. package/.claude/skills/task-flow-run/workflow.md +59 -0
  14. package/.claude/skills/task-flow-status/SKILL.md +13 -0
  15. package/.claude/skills/task-flow-sync/SKILL.md +30 -0
  16. package/.claude/skills/task-flow-sync/workflow.md +57 -0
  17. package/.claude/skills/task-flow-think/SKILL.md +17 -0
  18. package/.codex/config.toml +10 -0
  19. package/.cursor/rules/code_comments.mdc +4 -4
  20. package/.cursor/rules/coding_standards.mdc +57 -810
  21. package/.cursor/rules/commit_practices.mdc +5 -138
  22. package/.cursor/rules/cursor_rules.mdc +4 -3
  23. package/.cursor/rules/git_control.mdc +5 -86
  24. package/.cursor/rules/graphify-task-flow.mdc +31 -0
  25. package/.cursor/rules/rbin-git-policy.mdc +47 -0
  26. package/.cursor/rules/self_improve.mdc +3 -3
  27. package/.cursor/rules/task-flow-cursor.mdc +51 -0
  28. package/.cursor/rules/task-flow-sync.mdc +46 -0
  29. package/.cursor/rules/task_analysis.mdc +31 -179
  30. package/.cursor/rules/task_audit.mdc +6 -5
  31. package/.cursor/rules/task_check.mdc +2 -3
  32. package/.cursor/rules/task_estimate.mdc +3 -4
  33. package/.cursor/rules/task_execution.mdc +26 -138
  34. package/.cursor/rules/task_generate_flow.mdc +2 -3
  35. package/.cursor/rules/task_generation.mdc +22 -140
  36. package/.cursor/rules/task_improve_changes.mdc +3 -4
  37. package/.cursor/rules/task_refactor.mdc +4 -5
  38. package/.cursor/rules/task_report.mdc +3 -4
  39. package/.cursor/rules/task_review.mdc +4 -5
  40. package/.cursor/rules/task_status.mdc +4 -4
  41. package/.cursor/rules/task_work.mdc +23 -210
  42. package/.task-flow/AI-PLATFORMS.md +104 -0
  43. package/.task-flow/CODEX.md +141 -0
  44. package/.task-flow/CURSOR.md +94 -0
  45. package/.task-flow/GRAPHIFY.md +113 -0
  46. package/.task-flow/OPTIMIZATION-IMPLEMENTATION-TASKS.md +365 -0
  47. package/.task-flow/OPTIMIZATION-PLAN.md +264 -0
  48. package/.task-flow/README.md +19 -4
  49. package/.task-flow/docs/coding-standards-full.md +851 -0
  50. package/.task-flow/platforms/claude-code.md +352 -0
  51. package/.task-flow/platforms/codex.md +379 -0
  52. package/.task-flow/platforms/cursor.md +333 -0
  53. package/AGENTS.md +69 -31
  54. package/CLAUDE.md +56 -48
  55. package/README.md +78 -10
  56. package/bin/cli.js +40 -25
  57. package/lib/codex.js +45 -0
  58. package/lib/cursor.js +41 -0
  59. package/lib/gitignore.js +101 -0
  60. package/lib/graphify.js +122 -0
  61. package/lib/install.js +83 -47
  62. package/lib/profiles.js +110 -0
  63. package/lib/skills.js +34 -0
  64. package/lib/utils.js +38 -2
  65. package/package.json +6 -2
package/lib/install.js CHANGED
@@ -3,13 +3,41 @@ const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const ora = require('ora');
5
5
  const { showHeader, showSuccess, showError, showWarning, showInfo, showNextSteps } = require('./utils');
6
+ const { setupGraphifyIntegration } = require('./graphify');
7
+ const { copySkillsToProject } = require('./skills');
8
+ const { setupCodexIntegration } = require('./codex');
9
+ const { setupCursorIntegration } = require('./cursor');
10
+ const {
11
+ PROFILE_MINIMAL,
12
+ PROFILE_STANDARD,
13
+ resolveProfile,
14
+ resolveShareAiConfig,
15
+ writeInstallMeta,
16
+ copyCursorRules,
17
+ } = require('./profiles');
18
+ const { updateGitignore } = require('./gitignore');
19
+
20
+ const PROFILES = { STANDARD: PROFILE_STANDARD, MINIMAL: PROFILE_MINIMAL };
6
21
 
7
22
  const TEMPLATE_DIR = path.join(__dirname, '..');
23
+ const PACKAGE_VERSION = require('../package.json').version;
8
24
 
9
25
  async function installInProject(targetPath, options = {}) {
10
26
  const isUpdate = options.update || false;
11
27
  const isReset = options.reset || false;
12
28
 
29
+ let profile;
30
+ let shareAiConfig;
31
+ try {
32
+ profile = await resolveProfile(targetPath, { profile: options.profile });
33
+ shareAiConfig = await resolveShareAiConfig(targetPath, {
34
+ shareAiConfig: options.shareAiConfig,
35
+ });
36
+ } catch (error) {
37
+ showError(error.message);
38
+ process.exit(1);
39
+ }
40
+
13
41
  showHeader();
14
42
 
15
43
  if (isReset) {
@@ -20,7 +48,21 @@ async function installInProject(targetPath, options = {}) {
20
48
  console.log(chalk.blue('🚀 Installing RBIN Task Flow...'));
21
49
  }
22
50
 
23
- console.log(chalk.blue('📁 Target:'), targetPath, '\n');
51
+ console.log(chalk.blue('📁 Target:'), targetPath);
52
+ console.log(
53
+ chalk.blue('📦 Profile:'),
54
+ profile === PROFILES.MINIMAL ? chalk.yellow('minimal') : chalk.green('standard'),
55
+ profile === PROFILES.MINIMAL
56
+ ? chalk.gray('(2 always-on rules + skills; workflows via @task-flow-*)')
57
+ : chalk.gray('(all Cursor rules + skills)')
58
+ );
59
+ console.log(
60
+ chalk.blue('🔗 Git:'),
61
+ shareAiConfig
62
+ ? chalk.yellow('share-ai-config') + chalk.gray(' (.cursor/skills + .cursor/rules versionáveis)')
63
+ : chalk.gray('local .cursor/ gitignored (default)')
64
+ );
65
+ console.log('');
24
66
 
25
67
  const spinner = ora('Processing...').start();
26
68
 
@@ -45,8 +87,11 @@ async function installInProject(targetPath, options = {}) {
45
87
 
46
88
  const dirs = [
47
89
  '.cursor/rules',
90
+ '.cursor/skills',
48
91
  '.claude',
49
- '.task-flow'
92
+ '.claude/skills',
93
+ '.task-flow',
94
+ '.codex'
50
95
  ];
51
96
 
52
97
  for (const dir of dirs) {
@@ -55,11 +100,33 @@ async function installInProject(targetPath, options = {}) {
55
100
 
56
101
  spinner.text = 'Copying configuration files...';
57
102
 
58
- await copyConfigs(targetPath, { update: isUpdate, reset: isReset });
103
+ await copyConfigs(targetPath, { update: isUpdate, reset: isReset, profile });
59
104
 
60
105
  spinner.text = 'Updating .gitignore...';
61
106
 
62
- await updateGitignore(targetPath);
107
+ await updateGitignore(targetPath, { shareAiConfig });
108
+ showSuccess('.gitignore updated');
109
+ if (shareAiConfig) {
110
+ showInfo('Git: .cursor/skills/ and .cursor/rules/ can be committed (see .gitignore comment)');
111
+ }
112
+
113
+ spinner.text = 'Installing agent skills...';
114
+ await copySkillsToProject(targetPath);
115
+
116
+ spinner.text = 'Configuring Cursor (rules + skills)...';
117
+ await setupCursorIntegration(targetPath, { profile });
118
+
119
+ await writeInstallMeta(targetPath, {
120
+ profile,
121
+ packageVersion: PACKAGE_VERSION,
122
+ shareAiConfig,
123
+ });
124
+
125
+ spinner.text = 'Configuring Codex (AGENTS.md + .codex/config.toml)...';
126
+ await setupCodexIntegration(targetPath);
127
+
128
+ spinner.text = 'Configuring Graphify coexistence...';
129
+ await setupGraphifyIntegration(targetPath, { extract: options.graphify === true });
63
130
 
64
131
  spinner.succeed(chalk.green('Installation completed!'));
65
132
 
@@ -79,15 +146,18 @@ async function installInProject(targetPath, options = {}) {
79
146
  async function copyConfigs(targetPath, options = {}) {
80
147
  const isUpdate = options.update || false;
81
148
  const isReset = options.reset || false;
149
+ const profile = options.profile;
82
150
 
83
- const cursorRulesPath = path.join(TEMPLATE_DIR, '.cursor/rules');
84
- const cursorRulesDest = path.join(targetPath, '.cursor/rules');
85
- if (fs.existsSync(cursorRulesPath)) {
86
- if ((isUpdate || isReset) && fs.existsSync(cursorRulesDest)) {
87
- await fs.emptyDir(cursorRulesDest);
88
- }
89
- await fs.copy(cursorRulesPath, cursorRulesDest, { overwrite: true });
90
- showSuccess('Cursor rules');
151
+ const rulesResult = await copyCursorRules(targetPath, TEMPLATE_DIR, {
152
+ profile,
153
+ update: isUpdate,
154
+ reset: isReset,
155
+ });
156
+ if (rulesResult?.mode === PROFILE_MINIMAL) {
157
+ showSuccess(`Cursor rules (minimal: ${rulesResult.count} files, always-on only)`);
158
+ showInfo('Use @task-flow-* skills for sync, run, audit — omit heavy .mdc rules to save tokens');
159
+ } else if (rulesResult) {
160
+ showSuccess(`Cursor rules (${rulesResult.count} files)`);
91
161
  }
92
162
 
93
163
  const cursorSettingsPath = path.join(TEMPLATE_DIR, '.cursor/settings.json');
@@ -148,6 +218,7 @@ async function copyTaskFlow(targetPath, options = {}) {
148
218
  path.join(taskFlowDest, 'tasks.input.txt'),
149
219
  path.join(taskFlowDest, 'tasks.status.md'),
150
220
  path.join(taskFlowDest, 'tasks.flow.md'),
221
+ path.join(taskFlowDest, 'install-meta.json'),
151
222
  ];
152
223
 
153
224
  await fs.copy(taskFlowSrc, taskFlowDest, {
@@ -193,41 +264,6 @@ async function copyTaskFlow(targetPath, options = {}) {
193
264
  }
194
265
  }
195
266
 
196
- async function updateGitignore(targetPath) {
197
- const gitignorePath = path.join(targetPath, '.gitignore');
198
-
199
- if (!fs.existsSync(gitignorePath)) {
200
- await fs.writeFile(gitignorePath, '');
201
- }
202
-
203
- let content = await fs.readFile(gitignorePath, 'utf8');
204
-
205
- const entries = [
206
- '.claude/',
207
- '.cursor/',
208
- '.task-flow/',
209
- 'CLAUDE.md',
210
- 'AGENTS.md'
211
- ];
212
-
213
- for (const entry of entries) {
214
- const regex = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'gm');
215
- content = content.replace(regex, '');
216
- }
217
-
218
- content = content.replace(/\n{3,}/g, '\n\n');
219
-
220
- if (!content.endsWith('\n')) {
221
- content += '\n';
222
- }
223
-
224
- content += '\n' + entries.join('\n') + '\n';
225
-
226
- await fs.writeFile(gitignorePath, content);
227
-
228
- showSuccess('.gitignore updated');
229
- }
230
-
231
267
  async function showModelVersions(targetPath) {
232
268
  console.log(chalk.cyan('═'.repeat(60)));
233
269
  console.log(chalk.magenta('📋 Model Versions Configured:'));
@@ -0,0 +1,110 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ const PROFILE_STANDARD = 'standard';
5
+ const PROFILE_MINIMAL = 'minimal';
6
+
7
+ const MINIMAL_RULE_FILES = ['task-flow-cursor.mdc', 'rbin-git-policy.mdc'];
8
+
9
+ function normalizeProfile(profile) {
10
+ const value = String(profile || PROFILE_STANDARD).trim().toLowerCase();
11
+ if (value !== PROFILE_STANDARD && value !== PROFILE_MINIMAL) {
12
+ throw new Error(`Invalid profile "${profile}". Use "minimal" or "standard".`);
13
+ }
14
+ return value;
15
+ }
16
+
17
+ function parseProfileOption(value) {
18
+ return normalizeProfile(value || PROFILE_STANDARD);
19
+ }
20
+
21
+ async function readInstallMeta(targetPath) {
22
+ const metaPath = path.join(targetPath, '.task-flow', 'install-meta.json');
23
+ if (!fs.existsSync(metaPath)) {
24
+ return null;
25
+ }
26
+ try {
27
+ return await fs.readJson(metaPath);
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ async function writeInstallMeta(targetPath, { profile, packageVersion, shareAiConfig }) {
34
+ const metaPath = path.join(targetPath, '.task-flow', 'install-meta.json');
35
+ await fs.ensureDir(path.dirname(metaPath));
36
+ const existing = (await readInstallMeta(targetPath)) || {};
37
+ const meta = {
38
+ ...existing,
39
+ profile: normalizeProfile(profile),
40
+ packageVersion,
41
+ updatedAt: new Date().toISOString(),
42
+ };
43
+ if (shareAiConfig !== undefined) {
44
+ meta.shareAiConfig = Boolean(shareAiConfig);
45
+ }
46
+ await fs.writeJson(metaPath, meta, { spaces: 2 });
47
+ }
48
+
49
+ async function resolveShareAiConfig(targetPath, options = {}) {
50
+ if (options.shareAiConfig !== undefined) {
51
+ return Boolean(options.shareAiConfig);
52
+ }
53
+ const meta = await readInstallMeta(targetPath);
54
+ if (meta && typeof meta.shareAiConfig === 'boolean') {
55
+ return meta.shareAiConfig;
56
+ }
57
+ return false;
58
+ }
59
+
60
+ async function resolveProfile(targetPath, options = {}) {
61
+ if (options.profile) {
62
+ return normalizeProfile(options.profile);
63
+ }
64
+ const meta = await readInstallMeta(targetPath);
65
+ if (meta?.profile) {
66
+ return normalizeProfile(meta.profile);
67
+ }
68
+ return PROFILE_STANDARD;
69
+ }
70
+
71
+ async function copyCursorRules(targetPath, templateDir, { profile, update, reset }) {
72
+ const src = path.join(templateDir, '.cursor', 'rules');
73
+ const dest = path.join(targetPath, '.cursor', 'rules');
74
+
75
+ if (!fs.existsSync(src)) {
76
+ return;
77
+ }
78
+
79
+ if ((update || reset) && fs.existsSync(dest)) {
80
+ await fs.emptyDir(dest);
81
+ }
82
+ await fs.ensureDir(dest);
83
+
84
+ if (profile === PROFILE_MINIMAL) {
85
+ for (const file of MINIMAL_RULE_FILES) {
86
+ const from = path.join(src, file);
87
+ if (fs.existsSync(from)) {
88
+ await fs.copy(from, path.join(dest, file), { overwrite: true });
89
+ }
90
+ }
91
+ return { mode: PROFILE_MINIMAL, count: MINIMAL_RULE_FILES.length };
92
+ }
93
+
94
+ await fs.copy(src, dest, { overwrite: true });
95
+ const count = (await fs.readdir(dest)).filter((name) => name.endsWith('.mdc')).length;
96
+ return { mode: PROFILE_STANDARD, count };
97
+ }
98
+
99
+ module.exports = {
100
+ PROFILE_STANDARD,
101
+ PROFILE_MINIMAL,
102
+ MINIMAL_RULE_FILES,
103
+ normalizeProfile,
104
+ parseProfileOption,
105
+ readInstallMeta,
106
+ writeInstallMeta,
107
+ resolveProfile,
108
+ resolveShareAiConfig,
109
+ copyCursorRules,
110
+ };
package/lib/skills.js ADDED
@@ -0,0 +1,34 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { showSuccess, showInfo } = require('./utils');
4
+
5
+ const TEMPLATE_DIR = path.join(__dirname, '..');
6
+ const SKILLS_SRC = path.join(TEMPLATE_DIR, '.claude', 'skills');
7
+
8
+ async function copySkillsToProject(targetPath) {
9
+ if (!fs.existsSync(SKILLS_SRC)) {
10
+ return false;
11
+ }
12
+
13
+ const destinations = [
14
+ path.join(targetPath, '.claude', 'skills'),
15
+ path.join(targetPath, '.cursor', 'skills'),
16
+ ];
17
+
18
+ for (const dest of destinations) {
19
+ await fs.ensureDir(dest);
20
+ await fs.copy(SKILLS_SRC, dest, { overwrite: true });
21
+ }
22
+
23
+ const count = (await fs.readdir(SKILLS_SRC)).filter((name) =>
24
+ fs.statSync(path.join(SKILLS_SRC, name)).isDirectory()
25
+ ).length;
26
+
27
+ showSuccess(`Agent skills (${count} skills → .claude/skills/ and .cursor/skills/)`);
28
+ showInfo('Claude Code: restart session if .claude/skills/ was created for the first time');
29
+ showInfo('Claude: /task-flow-run · Cursor: @task-flow-run in Agent (or task-flow: run next X)');
30
+
31
+ return true;
32
+ }
33
+
34
+ module.exports = { copySkillsToProject, SKILLS_SRC };
package/lib/utils.js CHANGED
@@ -36,14 +36,49 @@ function showInfo(message) {
36
36
  console.log(chalk.blue('ℹ️ ' + message));
37
37
  }
38
38
 
39
+ function measureAlwaysOnRules(targetPath) {
40
+ const rulesDir = path.join(targetPath, '.cursor', 'rules');
41
+ if (!fs.existsSync(rulesDir)) return null;
42
+
43
+ let totalBytes = 0;
44
+ const files = fs.readdirSync(rulesDir).filter((name) => name.endsWith('.mdc'));
45
+
46
+ for (const name of files) {
47
+ const filePath = path.join(rulesDir, name);
48
+ const content = fs.readFileSync(filePath, 'utf8');
49
+ if (/alwaysApply:\s*true\b/.test(content)) {
50
+ totalBytes += Buffer.byteLength(content, 'utf8');
51
+ }
52
+ }
53
+
54
+ if (totalBytes === 0) return null;
55
+ return {
56
+ bytes: totalBytes,
57
+ kb: totalBytes / 1024,
58
+ approxTokens: Math.round(totalBytes / 4),
59
+ };
60
+ }
61
+
39
62
  function showNextSteps(targetPath) {
63
+ const alwaysOn = measureAlwaysOnRules(targetPath);
64
+
40
65
  console.log('\n' + chalk.cyan('═'.repeat(60)));
41
66
  console.log(chalk.magenta.bold(' Next Steps:'));
42
67
  console.log(chalk.cyan('═'.repeat(60)));
68
+ if (alwaysOn) {
69
+ const kbLabel = alwaysOn.kb < 10 ? alwaysOn.kb.toFixed(1) : String(Math.round(alwaysOn.kb));
70
+ console.log(
71
+ chalk.gray(' Always-on rules:'),
72
+ chalk.yellow(`~${kbLabel} KB`),
73
+ chalk.gray(`(~${alwaysOn.approxTokens.toLocaleString('en-US')} tokens est.)`)
74
+ );
75
+ }
43
76
  console.log(chalk.blue(' 1.'), 'Edit', chalk.yellow('.task-flow/tasks.input.txt'));
44
- console.log(chalk.blue(' 2.'), 'Use AI command:', chalk.cyan('task-flow: sync'));
45
- console.log(chalk.blue(' 3.'), 'Work on tasks:', chalk.cyan('task-flow: run next X'));
77
+ console.log(chalk.blue(' 2.'), 'Sync:', chalk.cyan('task-flow: sync'), chalk.gray('· Cursor/Claude: @task-flow-sync or /task-flow-sync'));
78
+ console.log(chalk.blue(' 3.'), 'Run:', chalk.cyan('task-flow: run next X'), chalk.gray('· @task-flow-run'));
46
79
  console.log(chalk.blue(' 4.'), 'Check status:', chalk.cyan('task-flow: status'));
80
+ console.log(chalk.blue(' 5.'), 'Codex:', chalk.gray('AGENTS.md + .task-flow/CODEX.md on demand'));
81
+ console.log(chalk.blue(' 6.'), 'Optional Graphify:', chalk.yellow('rbin-task-flow init --graphify'), chalk.gray('— .task-flow/GRAPHIFY.md'));
47
82
  console.log(chalk.cyan('═'.repeat(60)));
48
83
  console.log(chalk.blue('\n See'), chalk.yellow('.task-flow/README.md'), chalk.blue('for all available commands\n'));
49
84
  }
@@ -69,5 +104,6 @@ module.exports = {
69
104
  showWarning,
70
105
  showInfo,
71
106
  showNextSteps,
107
+ measureAlwaysOnRules,
72
108
  parseTaskIds
73
109
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rbin-task-flow",
3
- "version": "1.19.5",
3
+ "version": "1.23.1",
4
4
  "description": "AI-powered task management for Claude and Cursor",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "scripts": {
11
11
  "test": "echo \"No tests yet\"",
12
- "prepublishOnly": "chmod +x bin/cli.js"
12
+ "measure:rules": "node scripts/measure-rule-bytes.js",
13
+ "prepublishOnly": "npm run measure:rules && chmod +x bin/cli.js scripts/measure-rule-bytes.js"
13
14
  },
14
15
  "keywords": [
15
16
  "task-flow",
@@ -32,10 +33,13 @@
32
33
  "bin/",
33
34
  ".cursor/",
34
35
  ".claude/",
36
+ ".claude/skills/",
37
+ ".cursor/skills/",
35
38
  ".task-flow/",
36
39
  ".model-versions.json",
37
40
  "CLAUDE.md",
38
41
  "AGENTS.md",
42
+ ".codex/",
39
43
  "lib/"
40
44
  ],
41
45
  "preferGlobal": true,