rbin-task-flow 1.19.2 → 1.19.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/.cursor/rules/task_estimate.mdc +27 -27
- package/.cursor/rules/task_generate_flow.mdc +24 -12
- package/.task-flow/README.md +2 -2
- package/lib/estimate.js +102 -5
- package/lib/install.js +23 -6
- package/package.json +1 -1
|
@@ -10,48 +10,48 @@ alwaysApply: true
|
|
|
10
10
|
- **ALL TASKS**: `task-flow: estimate all` → Estimate all tasks
|
|
11
11
|
- When user says "task-flow: estimate X", "estimate X", "estimate X,Y", "estimate all", or "how long will task X take":
|
|
12
12
|
- **READ**: `.task-flow/.internal/tasks.json` to get task details
|
|
13
|
-
- **CALCULATE**: Time estimate based on
|
|
13
|
+
- **CALCULATE**: Time estimate based on task level, complexity signals, and developer experience level
|
|
14
14
|
- **DISPLAY**: Show time estimate with intervals for 3 experience levels (junior, mid, senior)
|
|
15
15
|
- **FORMAT**: Show estimates in hours with ranges (e.g., "10-14 hours" for intermediate)
|
|
16
16
|
|
|
17
17
|
- **Estimation Rules:**
|
|
18
|
-
1. **Base
|
|
18
|
+
1. **Base Analysis**: Evaluate the task title and subtasks to infer real task level
|
|
19
19
|
2. **Experience Levels** (use internally; display "Intermediate" not "Mid-level" to user):
|
|
20
20
|
- **Junior** (0-2 years): Base time × 1.5 multiplier
|
|
21
21
|
- **Intermediate** (3-5 years): Base time × 1.0 multiplier (baseline)
|
|
22
22
|
- **Senior** (6+ years): Base time × 0.7 multiplier
|
|
23
|
-
3. **
|
|
24
|
-
-
|
|
25
|
-
- Medium
|
|
26
|
-
-
|
|
27
|
-
4. **
|
|
28
|
-
5. **
|
|
29
|
-
-
|
|
30
|
-
-
|
|
23
|
+
3. **Task Level Heuristics**:
|
|
24
|
+
- **Low**: localized change, clear requirement, low ambiguity, low regression risk
|
|
25
|
+
- **Medium**: multi-file implementation, moderate ambiguity, moderate validation needs
|
|
26
|
+
- **High**: architectural, cross-cutting, migration, security, performance, or high-risk change
|
|
27
|
+
4. **Subtask count is only one signal**: use it to inform scope, but never as the sole estimate driver
|
|
28
|
+
5. **Intermediate baseline per subtask**:
|
|
29
|
+
- Low-level task: 1.5-2.5 hours
|
|
30
|
+
- Medium-level task: 2.5-4 hours
|
|
31
|
+
- High-level task: 4-6.5 hours
|
|
32
|
+
6. **Risk and scope adjustment**:
|
|
33
|
+
- Increase estimate when the task mentions integrations, migrations, refactors, security, performance, billing, or architecture work
|
|
34
|
+
7. **Range Calculation**:
|
|
35
|
+
- Lower bound: (subtasks × baseline lower) × risk factor × experience multiplier
|
|
36
|
+
- Upper bound: (subtasks × baseline upper) × risk factor × experience multiplier
|
|
31
37
|
- Round to nearest hour
|
|
32
38
|
|
|
33
39
|
- **Estimation Formula:**
|
|
34
40
|
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Lower: subtasks × 2
|
|
43
|
-
Upper: subtasks × 3
|
|
44
|
-
|
|
45
|
-
Senior (6+ years):
|
|
46
|
-
Lower: (subtasks × 2) × 0.7
|
|
47
|
-
Upper: (subtasks × 3) × 0.7
|
|
41
|
+
1. Infer task level: low, medium, or high
|
|
42
|
+
2. Choose intermediate baseline per subtask from task level
|
|
43
|
+
3. Apply risk/scope multiplier when complexity indicators exist
|
|
44
|
+
4. Apply experience multiplier:
|
|
45
|
+
Junior: × 1.5
|
|
46
|
+
Intermediate: × 1.0
|
|
47
|
+
Senior: × 0.7
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
- **Display Format:**
|
|
51
51
|
```
|
|
52
52
|
📊 Time Estimation for Task X: [Task Title]
|
|
53
53
|
|
|
54
|
-
Based on [N] subtasks:
|
|
54
|
+
Based on [N] subtasks and task-level analysis:
|
|
55
55
|
|
|
56
56
|
👶 Junior (0-2 years): [X-Y] hours
|
|
57
57
|
👨💼 Intermediate (3-5 years): [X-Y] hours
|
|
@@ -72,11 +72,11 @@ alwaysApply: true
|
|
|
72
72
|
```
|
|
73
73
|
User: "task-flow: estimate 1"
|
|
74
74
|
|
|
75
|
-
Task 1 has 5 subtasks:
|
|
75
|
+
Task 1 has 5 subtasks and medium complexity signals:
|
|
76
76
|
|
|
77
77
|
📊 Time Estimation for Task 1: Create authentication system
|
|
78
78
|
|
|
79
|
-
Based on 5 subtasks:
|
|
79
|
+
Based on 5 subtasks and task-level analysis:
|
|
80
80
|
|
|
81
81
|
👶 Junior (0-2 years): 15-23 hours
|
|
82
82
|
👨💼 Intermediate (3-5 years): 10-15 hours
|
|
@@ -89,4 +89,4 @@ alwaysApply: true
|
|
|
89
89
|
- Estimates are informational only (not stored)
|
|
90
90
|
|
|
91
91
|
- **Principle:**
|
|
92
|
-
> **Provide realistic time estimates based on task
|
|
92
|
+
> **Provide realistic time estimates based on real task level, scope, ambiguity, and risk. Subtask count informs scope, but must not be the sole estimation criterion.**
|
|
@@ -8,19 +8,30 @@ alwaysApply: true
|
|
|
8
8
|
- **FAST FORMAT**: `task-flow: generate flow` → Populate tasks.flow.md
|
|
9
9
|
- When user says "task-flow: generate flow", "generate flow", "gerar flow", or "flow":
|
|
10
10
|
- **READ**: `.task-flow/.internal/tasks.json` and optionally `status.json`
|
|
11
|
-
- **SEARCH**: Current versions of
|
|
11
|
+
- **SEARCH**: Current versions of GPT-5.x, Composer, Claude (Haiku, Sonnet) via web search
|
|
12
12
|
- **WRITE**: Populate `.task-flow/tasks.flow.md` with the generated flow
|
|
13
13
|
- **DO NOT**: Populate tasks.flow.md when running `task-flow: sync`
|
|
14
14
|
|
|
15
15
|
- **Generation Process:**
|
|
16
|
-
1. **Search for current model versions** (web search):
|
|
16
|
+
1. **Search for current model versions** (web search): one GPT-5.x coding-capable model, Composer (Cursor), Claude Haiku, Claude Sonnet. Include version next to each model (e.g. "Claude Sonnet 4.6").
|
|
17
17
|
2. Read tasks from tasks.json
|
|
18
18
|
3. For each task, determine:
|
|
19
19
|
- **Dependencies**: Which tasks must be completed first (or "—" if none)
|
|
20
|
-
- **Estimated hours** (for billing):
|
|
21
|
-
- **3 model options** (in order of priority): one
|
|
22
|
-
- **
|
|
20
|
+
- **Estimated hours** (for billing): infer from real task scope, ambiguity, dependencies, and validation needs. Subtask count informs scope, but do not use a fixed subtasks × hours formula. Do NOT show "dev mediano" or "mid-level".
|
|
21
|
+
- **3 model options** (in order of priority): one GPT-5.x model, one Composer, one Claude — always these 3. Include version and effort for each.
|
|
22
|
+
- **Model priority must be defined by AI judgment**, based on task nature, implementation risk, ambiguity, architecture impact, validation needs, and expected autonomy. Do not use a fixed ranking.
|
|
23
|
+
- **Effort** per model: low, medium, or high, defined by task level and difficulty. Do not infer effort from subtask count alone.
|
|
23
24
|
4. **Claude**: Use only Haiku or Sonnet — **never Opus**
|
|
25
|
+
5. **Effort heuristics**:
|
|
26
|
+
- **low**: localized change, clear requirement, low ambiguity, low regression risk, limited validation
|
|
27
|
+
- **medium**: multi-file implementation, moderate ambiguity, moderate regression risk, requires broader validation
|
|
28
|
+
- **high**: architecture or cross-cutting change, high ambiguity, high regression risk, sequencing concerns, or deep investigation/refactor
|
|
29
|
+
6. **Model heuristics**:
|
|
30
|
+
- **GPT-5.x**: prioritize when the task needs strong implementation, refactoring, debugging, or broader code reasoning
|
|
31
|
+
- **Composer**: prioritize when the task benefits from editor-native iteration, repo-wide navigation, and fast execution in the coding flow
|
|
32
|
+
- **Claude Haiku**: prioritize for simpler, well-bounded tasks with low effort
|
|
33
|
+
- **Claude Sonnet**: prioritize for tasks that need more synthesis, reasoning depth, or architectural analysis
|
|
34
|
+
- The first recommendation must reflect the best fit for that specific task, not a template order reused across all tasks
|
|
24
35
|
|
|
25
36
|
- **Output Format (direct blocks per task):**
|
|
26
37
|
```markdown
|
|
@@ -37,7 +48,7 @@ alwaysApply: true
|
|
|
37
48
|
| ⚡ | Pode iniciar agora (deps satisfeitas) |
|
|
38
49
|
| 🔒 | Bloqueada por dependências |
|
|
39
50
|
|
|
40
|
-
**Esforço (Effort):**
|
|
51
|
+
**Esforço (Effort):** definido pelo nível e dificuldade real da task, não pela quantidade de subtasks
|
|
41
52
|
**Claude:** Haiku ou Sonnet — **não use Opus**
|
|
42
53
|
|
|
43
54
|
## Tasks (blocos diretos por task)
|
|
@@ -46,7 +57,7 @@ alwaysApply: true
|
|
|
46
57
|
- **Depende de:** —
|
|
47
58
|
- **Horas cobrança:** 10-15h
|
|
48
59
|
- **Modelos sugeridos** (ordem de prioridade):
|
|
49
|
-
1.
|
|
60
|
+
1. GPT-5.x [versão] — effort medium
|
|
50
61
|
2. Composer [versão] — effort medium
|
|
51
62
|
3. Claude Sonnet [versão] — effort medium
|
|
52
63
|
|
|
@@ -54,8 +65,8 @@ alwaysApply: true
|
|
|
54
65
|
- **Depende de:** Task 1 ✅
|
|
55
66
|
- **Horas cobrança:** 10-15h
|
|
56
67
|
- **Modelos sugeridos** (ordem de prioridade):
|
|
57
|
-
1.
|
|
58
|
-
2.
|
|
68
|
+
1. Composer [versão] — effort medium
|
|
69
|
+
2. GPT-5.x [versão] — effort medium
|
|
59
70
|
3. Claude Sonnet [versão] — effort medium
|
|
60
71
|
|
|
61
72
|
### 🔒 Task 3 — [Título]
|
|
@@ -63,17 +74,18 @@ alwaysApply: true
|
|
|
63
74
|
- **Horas cobrança:** 8-12h
|
|
64
75
|
- **Modelos sugeridos** (ordem de prioridade):
|
|
65
76
|
1. Claude Haiku [versão] — effort low
|
|
66
|
-
2.
|
|
77
|
+
2. GPT-5.x [versão] — effort low
|
|
67
78
|
3. Composer [versão] — effort low
|
|
68
79
|
```
|
|
69
80
|
|
|
70
81
|
- **Model Rules:**
|
|
71
|
-
- **3 models per task**: One
|
|
82
|
+
- **3 models per task**: One GPT-5.x model, one Composer, one Claude — always in order of priority
|
|
72
83
|
- **Version required**: Include current version next to each model name (from web search)
|
|
73
84
|
- **Effort required**: low, medium, or high for each model
|
|
85
|
+
- **AI-defined ranking**: order models by best fit for the task, not by a fixed global priority
|
|
74
86
|
- **No Opus**: Claude = Haiku or Sonnet only
|
|
75
87
|
|
|
76
88
|
- **Natural Language:** "generate flow", "gerar flow", "flow"
|
|
77
89
|
|
|
78
90
|
- **Principle:**
|
|
79
|
-
> **Populate tasks.flow.md with direct blocks per task. Dependencies, hours, and 3 model options (
|
|
91
|
+
> **Populate tasks.flow.md with direct blocks per task. Dependencies, hours, and 3 model options (GPT-5.x, Composer, Claude) with version and effort. Let AI define ranking and effort from task context. Never use Opus.**
|
package/.task-flow/README.md
CHANGED
|
@@ -95,7 +95,7 @@ Refactors code from specific task(s). Removes explanatory comments, improves cod
|
|
|
95
95
|
- `task-flow: refactor all` → Refactors all tasks
|
|
96
96
|
|
|
97
97
|
### `task-flow: estimate X` (simplified syntax)
|
|
98
|
-
Estimates time required to complete task(s) based on
|
|
98
|
+
Estimates time required to complete task(s) based on task level, scope, risk, and developer experience level. Subtask count informs scope, but is not the sole criterion.
|
|
99
99
|
|
|
100
100
|
**Output includes:**
|
|
101
101
|
- Time estimates for Junior (0-2 years), Intermediate (3-5 years), and Senior (6+ years) developers
|
|
@@ -108,7 +108,7 @@ Estimates time required to complete task(s) based on the number of subtasks and
|
|
|
108
108
|
- `task-flow: estimate all` → Shows time estimates for all tasks
|
|
109
109
|
|
|
110
110
|
### `task-flow: generate flow`
|
|
111
|
-
Populates `tasks.flow.md` with: (1) task dependencies (for parallelization), (2) estimated hours, and (3) AI model recommendations (
|
|
111
|
+
Populates `tasks.flow.md` with: (1) task dependencies (for parallelization), (2) estimated hours, and (3) AI model recommendations (GPT-5.x, Composer, Claude) with effort levels. Model ranking and effort must be defined by the AI from task context, not from a fixed order or only from subtask count. Run after `task-flow: sync` when you want to know which tasks can run in parallel and which model/effort to use.
|
|
112
112
|
|
|
113
113
|
### `task-flow: report X` (simplified syntax)
|
|
114
114
|
Generates a detailed implementation report for completed task(s) in Markdown format.
|
package/lib/estimate.js
CHANGED
|
@@ -40,7 +40,8 @@ async function estimateTask(taskIdsInput, targetPath = process.cwd()) {
|
|
|
40
40
|
continue;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const analysis = analyzeTaskComplexity(task);
|
|
44
|
+
const estimates = calculateEstimates(analysis);
|
|
44
45
|
|
|
45
46
|
if (taskIds.length > 1) {
|
|
46
47
|
console.log('\n' + chalk.cyan('═'.repeat(70)));
|
|
@@ -51,11 +52,13 @@ async function estimateTask(taskIdsInput, targetPath = process.cwd()) {
|
|
|
51
52
|
console.log(chalk.cyan('═'.repeat(70)) + '\n');
|
|
52
53
|
|
|
53
54
|
console.log(chalk.blue.bold('Task:'), chalk.yellow(`#${taskId} - ${task.title}\n`));
|
|
54
|
-
console.log(chalk.blue(`Complexity: ${chalk.yellow(
|
|
55
|
+
console.log(chalk.blue(`Complexity: ${chalk.yellow(analysis.level)} (${subtaskCount} subtasks)\n`));
|
|
55
56
|
|
|
56
57
|
console.log(chalk.cyan('─'.repeat(70)));
|
|
57
58
|
console.log(chalk.magenta.bold('Time Estimates by Experience Level:\n'));
|
|
58
59
|
|
|
60
|
+
console.log(chalk.gray(`Signals: ${analysis.signals.join(', ')}\n`));
|
|
61
|
+
|
|
59
62
|
const juniorDays = Math.ceil(estimates.junior.upper / 8);
|
|
60
63
|
const midDays = Math.ceil(estimates.mid.upper / 8);
|
|
61
64
|
const seniorDays = Math.ceil(estimates.senior.upper / 8);
|
|
@@ -94,9 +97,16 @@ async function estimateTask(taskIdsInput, targetPath = process.cwd()) {
|
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
97
|
-
function calculateEstimates(
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
+
function calculateEstimates(analysis) {
|
|
101
|
+
const { subtaskCount, level, riskMultiplier } = analysis;
|
|
102
|
+
const levelRanges = {
|
|
103
|
+
low: { lower: 1.5, upper: 2.5 },
|
|
104
|
+
medium: { lower: 2.5, upper: 4 },
|
|
105
|
+
high: { lower: 4, upper: 6.5 }
|
|
106
|
+
};
|
|
107
|
+
const baseRange = levelRanges[level] || levelRanges.medium;
|
|
108
|
+
const baseLower = subtaskCount * baseRange.lower * riskMultiplier;
|
|
109
|
+
const baseUpper = subtaskCount * baseRange.upper * riskMultiplier;
|
|
100
110
|
|
|
101
111
|
return {
|
|
102
112
|
junior: {
|
|
@@ -114,4 +124,91 @@ function calculateEstimates(subtaskCount) {
|
|
|
114
124
|
};
|
|
115
125
|
}
|
|
116
126
|
|
|
127
|
+
function analyzeTaskComplexity(task) {
|
|
128
|
+
const subtasks = Array.isArray(task.subtasks) ? task.subtasks : [];
|
|
129
|
+
const subtaskCount = subtasks.length;
|
|
130
|
+
const content = buildTaskContent(task, subtasks);
|
|
131
|
+
const keywordScores = scoreKeywords(content);
|
|
132
|
+
|
|
133
|
+
let score = 0;
|
|
134
|
+
|
|
135
|
+
if (subtaskCount <= 2) score += 1;
|
|
136
|
+
else if (subtaskCount <= 5) score += 2;
|
|
137
|
+
else score += 3;
|
|
138
|
+
|
|
139
|
+
score += keywordScores.complexity;
|
|
140
|
+
|
|
141
|
+
let level = 'medium';
|
|
142
|
+
if (score <= 2) level = 'low';
|
|
143
|
+
else if (score >= 6) level = 'high';
|
|
144
|
+
|
|
145
|
+
const riskMultiplier = Math.max(1, 1 + keywordScores.risk * 0.08 + keywordScores.scope * 0.06);
|
|
146
|
+
const signals = [
|
|
147
|
+
`${subtaskCount} subtasks`,
|
|
148
|
+
`${level} task level`
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
if (keywordScores.scope > 0) signals.push('multi-file or integration indicators');
|
|
152
|
+
if (keywordScores.risk > 0) signals.push('risk or validation indicators');
|
|
153
|
+
if (keywordScores.architecture > 0) signals.push('architecture/refactor indicators');
|
|
154
|
+
if (signals.length === 2) signals.push('no elevated complexity indicators');
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
subtaskCount,
|
|
158
|
+
level,
|
|
159
|
+
riskMultiplier,
|
|
160
|
+
signals
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function buildTaskContent(task, subtasks) {
|
|
165
|
+
const parts = [task.title, task.description];
|
|
166
|
+
|
|
167
|
+
for (const subtask of subtasks) {
|
|
168
|
+
if (typeof subtask === 'string') {
|
|
169
|
+
parts.push(subtask);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (subtask && typeof subtask === 'object') {
|
|
174
|
+
parts.push(subtask.title, subtask.description);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return parts
|
|
179
|
+
.filter(Boolean)
|
|
180
|
+
.join(' ')
|
|
181
|
+
.toLowerCase();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function scoreKeywords(content) {
|
|
185
|
+
const architectureKeywords = [
|
|
186
|
+
'architecture', 'arquitetura', 'refactor', 'refator', 'migrate', 'migra',
|
|
187
|
+
'core', 'infra', 'foundation', 'sdk', 'abstraction'
|
|
188
|
+
];
|
|
189
|
+
const scopeKeywords = [
|
|
190
|
+
'integration', 'integracao', 'integrar', 'api', 'database', 'banco',
|
|
191
|
+
'auth', 'oauth', 'deploy', 'pipeline', 'webhook', 'service', 'provider'
|
|
192
|
+
];
|
|
193
|
+
const riskKeywords = [
|
|
194
|
+
'critical', 'critico', 'security', 'seguranca', 'performance', 'perf',
|
|
195
|
+
'bug', 'fix', 'regression', 'migration', 'compliance', 'billing', 'payment'
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
const architecture = countMatches(content, architectureKeywords);
|
|
199
|
+
const scope = countMatches(content, scopeKeywords);
|
|
200
|
+
const risk = countMatches(content, riskKeywords);
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
architecture,
|
|
204
|
+
scope,
|
|
205
|
+
risk,
|
|
206
|
+
complexity: architecture * 2 + scope + risk
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function countMatches(content, keywords) {
|
|
211
|
+
return keywords.reduce((total, keyword) => total + (content.includes(keyword) ? 1 : 0), 0);
|
|
212
|
+
}
|
|
213
|
+
|
|
117
214
|
module.exports = { estimateTask };
|
package/lib/install.js
CHANGED
|
@@ -120,10 +120,10 @@ async function copyConfigs(targetPath, isUpdate = false) {
|
|
|
120
120
|
showSuccess('Codex instructions (AGENTS.md)');
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
await copyTaskFlow(targetPath);
|
|
123
|
+
await copyTaskFlow(targetPath, isUpdate);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
async function copyTaskFlow(targetPath) {
|
|
126
|
+
async function copyTaskFlow(targetPath, isUpdate = false) {
|
|
127
127
|
const taskFlowSrc = path.join(TEMPLATE_DIR, '.task-flow');
|
|
128
128
|
const taskFlowDest = path.join(targetPath, '.task-flow');
|
|
129
129
|
|
|
@@ -132,11 +132,24 @@ async function copyTaskFlow(targetPath) {
|
|
|
132
132
|
const PROTECTED = [
|
|
133
133
|
path.join(taskFlowDest, '.internal'),
|
|
134
134
|
];
|
|
135
|
+
const PRESERVED_ON_INIT = [
|
|
136
|
+
path.join(taskFlowDest, 'tasks.input.txt'),
|
|
137
|
+
path.join(taskFlowDest, 'tasks.status.md'),
|
|
138
|
+
path.join(taskFlowDest, 'tasks.flow.md'),
|
|
139
|
+
];
|
|
135
140
|
|
|
136
141
|
await fs.copy(taskFlowSrc, taskFlowDest, {
|
|
137
142
|
overwrite: true,
|
|
138
|
-
filter: (src) => {
|
|
139
|
-
|
|
143
|
+
filter: (src, dest) => {
|
|
144
|
+
if (PROTECTED.some((p) => src.startsWith(p) || dest.startsWith(p))) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!isUpdate && PRESERVED_ON_INIT.includes(dest) && fs.existsSync(dest)) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return true;
|
|
140
153
|
},
|
|
141
154
|
});
|
|
142
155
|
|
|
@@ -154,8 +167,12 @@ async function copyTaskFlow(targetPath) {
|
|
|
154
167
|
await fs.writeFile(flowPath, flowStub);
|
|
155
168
|
}
|
|
156
169
|
|
|
157
|
-
showSuccess('Task Flow directory
|
|
158
|
-
|
|
170
|
+
showSuccess('Task Flow directory');
|
|
171
|
+
if (isUpdate) {
|
|
172
|
+
showInfo('Protected: .internal/ (your task data is safe)');
|
|
173
|
+
} else {
|
|
174
|
+
showInfo('Protected on init: .internal/, tasks.input.txt, tasks.status.md, tasks.flow.md');
|
|
175
|
+
}
|
|
159
176
|
}
|
|
160
177
|
|
|
161
178
|
async function updateGitignore(targetPath) {
|