rbin-task-flow 1.5.0 → 1.7.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.
@@ -21,12 +21,42 @@ src/
21
21
  └── shared/ # Global reusable code
22
22
  ```
23
23
 
24
+ ### Allowed folders in shared/ and features/ (Front web & Mobile only)
25
+
26
+ In **front web** (Next.js, React, or other React-based web) or **mobile** (Expo, React Native) projects, only the following folder names may exist directly under `shared/` or under each feature in `features/`:
27
+
28
+ | Folder | Use |
29
+ |---------------|------------------------|
30
+ | `pages/` | Web only — page components |
31
+ | `screens/` | Mobile only — screen components |
32
+ | `components/` | UI components |
33
+ | `constants/` | Constants |
34
+ | `utils/` | Utilities |
35
+ | `validations/` | Validation helpers (e.g. `.validation.ts` for Zod) |
36
+ | `hooks/` | Custom hooks |
37
+ | `providers/` | Context providers |
38
+ | `styles/` | Styles |
39
+ | `types/` | TypeScript types |
40
+ | `libs/` | Library wrappers |
41
+ | `services/` | React Query / API wrappers |
42
+ | `use-cases/` | Pure API / business logic |
43
+ | `schemas/` | Zod (or similar) schemas |
44
+
45
+ **No other folder names** are allowed under `shared/` or under `features/[feature-name]/`. Use only `pages/` for web and `screens/` for mobile; do not mix both in the same project type.
46
+
47
+ ### No subfolders in shared/ (Front web & Mobile only)
48
+
49
+ In **front web** (Next.js, React) or **mobile** (Expo, React Native) projects, each folder under `shared/` must be **flat**: no subfolders. Files assume the responsibility through clear naming.
50
+
51
+ - **shared/components/**: One file per component, directly in `shared/components/`. No nested folders (e.g. no `form/`, `inputs/`). Name files so the purpose is clear (e.g. `button.tsx`, `input-text.tsx`, `input-container.tsx`, `input-error.tsx`, `input-label.tsx`).
52
+ - **shared/hooks/**, **shared/utils/**, **shared/validations/**, **shared/constants/**, etc.: Same rule — only files, no subfolders. Use the file name to carry the responsibility. Validation helpers (e.g. `required-email.validation.ts`) live in `shared/validations/`.
53
+
24
54
  ---
25
55
 
26
56
  ## Tech Stack
27
57
 
28
- ### Front-end (Next.js)
29
- - **Framework**: Next.js 15+ with App Router
58
+ ### Front-end (Next.js / React)
59
+ - **Framework**: Next.js 15+ with App Router, or React (Vite, CRA, or similar). These rules apply to any React-based web project.
30
60
  - **Language**: TypeScript (strict mode)
31
61
  - **Styling**: Tailwind CSS v4 + `clsx` + `tailwind-merge` via `cn()` helper
32
62
  - **UI Components**: shadcn/ui + `lucide-react` icons
@@ -37,7 +67,7 @@ src/
37
67
  - **E2E Testing**: Playwright and/or Cypress
38
68
 
39
69
  ### Mobile (Expo / React Native)
40
- - **Framework**: Expo with Expo Router
70
+ - **Framework**: Expo with Expo Router, or React Native (bare or managed). These rules apply to both Expo and React Native.
41
71
  - **Language**: TypeScript (strict mode)
42
72
  - **Styling**: NativeWind + `clsx` + `tailwind-merge` via `cn()` helper
43
73
  - **Data Fetching**: `@tanstack/react-query`
@@ -61,7 +91,7 @@ src/
61
91
 
62
92
  The `app/` directory contains ONLY route definitions. Each file is a thin wrapper that imports and renders the feature page/screen.
63
93
 
64
- **Front-end (Next.js App Router):**
94
+ **Front-end (Next.js App Router or React):**
65
95
  ```typescript
66
96
  // src/app/(private)/dashboard/page.tsx
67
97
  import { DashboardPage } from '@/features/dashboard/pages/dashboard.page'
@@ -71,7 +101,7 @@ export default function Dashboard() {
71
101
  }
72
102
  ```
73
103
 
74
- **Mobile (Expo Router):**
104
+ **Mobile (Expo Router or React Native):**
75
105
  ```typescript
76
106
  // src/app/(private)/dashboard.tsx
77
107
  import { DashboardScreen } from '@/features/dashboard/screens/dashboard.screen'
@@ -283,6 +313,8 @@ export function DashboardActiveCard({ data, isLoading, isError }: DashboardActiv
283
313
 
284
314
  ## shared/ — Global Reusable Code
285
315
 
316
+ In front web (Next.js, React) and mobile (Expo, React Native), `shared/` is flat per folder (no subfolders). One file per concern; naming carries the responsibility.
317
+
286
318
  ```
287
319
  shared/
288
320
  ├── components/
@@ -291,14 +323,11 @@ shared/
291
323
  │ ├── data-handler.tsx
292
324
  │ ├── skeleton.tsx
293
325
  │ ├── dialog.tsx
294
- └── form/
295
- └── inputs/
296
- ├── input-text.tsx
297
- ├── input-select.tsx
298
- └── shared/
299
- │ ├── input-container.tsx
300
- │ ├── input-error.tsx
301
- │ └── input-label.tsx
326
+ ├── input-text.tsx
327
+ ├── input-select.tsx
328
+ ├── input-container.tsx
329
+ ├── input-error.tsx
330
+ └── input-label.tsx
302
331
  ├── hooks/
303
332
  │ ├── dialog.hook.tsx
304
333
  │ └── drawer.hook.tsx
@@ -312,11 +341,11 @@ shared/
312
341
  │ └── shared.ui.type.ts
313
342
  ├── constants/
314
343
  │ └── server-routes.constants.ts
344
+ ├── validations/
345
+ │ ├── required-email.validation.ts
346
+ │ ├── required-string.validation.ts
347
+ │ └── required-phone.validation.ts
315
348
  └── utils/
316
- ├── validation/
317
- │ ├── required-email.validation.ts
318
- │ ├── required-string.validation.ts
319
- │ └── required-phone.validation.ts
320
349
  └── error.util.ts
321
350
  ```
322
351
 
@@ -516,8 +545,8 @@ export type ServiceInput<TData = unknown> = {
516
545
  ```typescript
517
546
  // src/features/auth/schemas/login.schema.ts
518
547
  import { z } from 'zod'
519
- import { requiredEmail } from '@/shared/utils/validation/required-email.validation'
520
- import { requiredString } from '@/shared/utils/validation/required-string.validation'
548
+ import { requiredEmail } from '@/shared/validations/required-email.validation'
549
+ import { requiredString } from '@/shared/validations/required-string.validation'
521
550
 
522
551
  export const loginSchema = z.object({
523
552
  email: requiredEmail(),
@@ -529,7 +558,7 @@ export type LoginSchema = z.infer<typeof loginSchema>
529
558
 
530
559
  **Reusable validators in shared/:**
531
560
  ```typescript
532
- // src/shared/utils/validation/required-string.validation.ts
561
+ // src/shared/validations/required-string.validation.ts
533
562
  import { z } from 'zod'
534
563
 
535
564
  export const requiredString = ({ field, min = 1 }: { field: string; min?: number }) =>
@@ -547,7 +576,7 @@ import { zodResolver } from '@hookform/resolvers/zod'
547
576
  import { useForm } from 'react-hook-form'
548
577
  import { LoginSchema, loginSchema } from '@/features/auth/schemas/login.schema'
549
578
  import { SessionCreateService } from '@/features/auth/services/session-create.service'
550
- import { InputText } from '@/shared/components/form/inputs/input-text'
579
+ import { InputText } from '@/shared/components/input-text'
551
580
  import { Button } from '@/shared/components/button'
552
581
 
553
582
  export function LoginForm() {
@@ -572,7 +601,7 @@ export function LoginForm() {
572
601
 
573
602
  **Input uses `Controller` from RHF and is generic:**
574
603
  ```typescript
575
- // src/shared/components/form/inputs/input-text.tsx
604
+ // src/shared/components/input-text.tsx
576
605
  import { Control, Controller, FieldValues, Path, PathValue } from 'react-hook-form'
577
606
  import { cn } from '@/shared/libs/tw-merge'
578
607
 
@@ -616,13 +645,24 @@ export function InputText<T extends FieldValues>({
616
645
 
617
646
  ## File Naming Conventions
618
647
 
619
- Use kebab-case for all filenames. Suffix reflects the file's role:
648
+ ### Rule for front (web & mobile): outside `app/` only
649
+
650
+ Every file outside the `app/` folder must follow:
651
+
652
+ - **Format**: lowercase, words separated by `-`, then `.tipo.ext` (suffix by role).
653
+ - **Examples**: `pagina-exemplo.page.tsx`, `login.schema.ts`, `session-create.use-case.ts`, `dashboard-active.type.ts`.
654
+
655
+ **Components are the exception**: do **not** use a `.component` suffix. Use only kebab-case + extension, e.g. `pagina-exemplo.tsx`, `dashboard-revenue-card.tsx`, `input-text.tsx`.
656
+
657
+ **Another exception**: files inside any `styles/` folder do not need to follow this pattern (e.g. CSS/SCSS modules may use their own convention).
658
+
659
+ ### Suffix by role
620
660
 
621
661
  | Role | Suffix | Example |
622
662
  |------|--------|---------|
623
- | Page component | `.page.tsx` | `dashboard.page.tsx` |
663
+ | Page component | `.page.tsx` | `pagina-exemplo.page.tsx` |
624
664
  | Screen component (mobile) | `.screen.tsx` | `login.screen.tsx` |
625
- | UI component | `.tsx` | `dashboard-revenue-card.tsx` |
665
+ | UI component | (no suffix) `.tsx` | `dashboard-revenue-card.tsx`, `input-text.tsx` |
626
666
  | React Query service | `.service.tsx` | `session-create.service.tsx` |
627
667
  | API call (pure) | `.use-case.ts` | `session-create.use-case.ts` |
628
668
  | Zod schema | `.schema.ts` | `login.schema.ts` |
@@ -630,7 +670,7 @@ Use kebab-case for all filenames. Suffix reflects the file's role:
630
670
  | API response type | `.api.type.ts` | `session.api.type.ts` |
631
671
  | Domain type | `.type.ts` | `dashboard-active.type.ts` |
632
672
  | Utility | `.util.ts` | `error.util.ts` |
633
- | Validation helper | `.validation.ts` | `required-email.validation.ts` |
673
+ | Validation helper | `.validation.ts` | `required-email.validation.ts` (in `validations/`) |
634
674
  | Constants | `.constants.ts` | `server-routes.constants.ts` |
635
675
 
636
676
  ---
@@ -684,7 +724,7 @@ export const useAuth = () => useContext(AuthContext)
684
724
 
685
725
  ## Testing
686
726
 
687
- ### Front-end (Next.js)
727
+ ### Front-end (Next.js / React)
688
728
  - **E2E**: Playwright and/or Cypress
689
729
  - Tests live in `e2e/` or `cypress/` at project root
690
730
  - Test files: `[feature].spec.ts` (Playwright) or `[feature].cy.ts` (Cypress)
@@ -710,3 +750,4 @@ export const useAuth = () => useContext(AuthContext)
710
750
  8. **Type everything**: No `any`. All props, params, and return values must be typed.
711
751
  9. **Shared is truly shared**: Only put in `shared/` what is used by 2+ features.
712
752
  10. **Naming reflects role**: File name + suffix must make the file's purpose immediately obvious.
753
+ 11. **No barrel files for re-exports**: Do not use `index.ts` (or `index.tsx`) only to re-export other modules. Import directly from the source file (e.g. `from '@/shared/components/button'` not `from '@/shared/components'`). An `index.ts` is only allowed when it contains real logic or composition, not mere re-exports.
package/AGENTS.md ADDED
@@ -0,0 +1,42 @@
1
+ # Project norms (Codex)
2
+
3
+ This repo follows the same development norms as in `.cursor/rules/` and `CLAUDE.md`. When working here, follow these rules.
4
+
5
+ ## Git
6
+
7
+ - **Never run** `git add`, `git commit`, `git push`, `git pull`, `git merge`, `git checkout`, `git reset`, `git rebase`, etc.
8
+ - **Only suggest** git commands; the user runs them.
9
+ - You **may** run read-only git: `git status`, `git diff`, `git log`, `git show`, `git branch` (list only).
10
+
11
+ ## Commits
12
+
13
+ - After completing tasks, **suggest** a commit message (Conventional Commits: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`).
14
+ - Include task/subtask ID when relevant, e.g. `Task ID: 3.2`.
15
+
16
+ ## Code and comments
17
+
18
+ - **No explanatory comments** in code; keep code self-explanatory via names.
19
+ - **Document non-obvious or complex topics** in `dev-logs/` (markdown).
20
+ - **Allowed comments**: only section separators in this form:
21
+ ```text
22
+ // ────────────────────────────────
23
+ // Section Name
24
+ // ────────────────────────────────
25
+ ```
26
+
27
+ ## RBIN Task Flow
28
+
29
+ - **Task flow** always means **RBIN Task Flow**.
30
+ - Tasks: `.task-flow/tasks.input.txt` (format: `- Task description`).
31
+ - Status: `.task-flow/tasks.status.md` and `.task-flow/.internal/status.json`.
32
+ - **Commands** to support: `task-flow: sync`, `task-flow: think`, `task-flow: audit`, `task-flow: status`, `task-flow: run next X`, `task-flow: run X` (or `X,Y` / `all`), `task-flow: review X`, `task-flow: refactor X`, `task-flow: estimate X`, `task-flow: report X`.
33
+ - When running `task-flow: audit`: scan the codebase, score it against `.cursor/rules/coding_standards.mdc`, present a report, and ask the user which improvements to adopt — never impose changes.
34
+ - When running subtasks: read `.task-flow/.internal/tasks.json` and `status.json`, implement, then update `status.json` and `tasks.status.md` (mark done, refresh summary).
35
+ - Use context from `.task-flow/contexts/` when subtask instructions reference it.
36
+
37
+ ## Full rules
38
+
39
+ For complete wording and examples, see:
40
+
41
+ - `CLAUDE.md` – overview and task-flow commands
42
+ - `.cursor/rules/` – all rules (git, commits, comments, task-flow, etc.)
package/lib/install.js CHANGED
@@ -48,7 +48,7 @@ async function installInProject(targetPath, options = {}) {
48
48
 
49
49
  spinner.text = 'Copying configuration files...';
50
50
 
51
- await copyConfigs(targetPath);
51
+ await copyConfigs(targetPath, isUpdate);
52
52
 
53
53
  spinner.text = 'Updating .gitignore...';
54
54
 
@@ -69,14 +69,14 @@ async function installInProject(targetPath, options = {}) {
69
69
  }
70
70
  }
71
71
 
72
- async function copyConfigs(targetPath) {
72
+ async function copyConfigs(targetPath, isUpdate = false) {
73
73
  const cursorRulesPath = path.join(TEMPLATE_DIR, '.cursor/rules');
74
+ const cursorRulesDest = path.join(targetPath, '.cursor/rules');
74
75
  if (fs.existsSync(cursorRulesPath)) {
75
- await fs.copy(
76
- cursorRulesPath,
77
- path.join(targetPath, '.cursor/rules'),
78
- { overwrite: true }
79
- );
76
+ if (isUpdate && fs.existsSync(cursorRulesDest)) {
77
+ await fs.emptyDir(cursorRulesDest);
78
+ }
79
+ await fs.copy(cursorRulesPath, cursorRulesDest, { overwrite: true });
80
80
  showSuccess('Cursor rules');
81
81
  }
82
82
 
@@ -110,6 +110,16 @@ async function copyConfigs(targetPath) {
110
110
  showSuccess('Claude instructions');
111
111
  }
112
112
 
113
+ const agentsPath = path.join(TEMPLATE_DIR, 'AGENTS.md');
114
+ if (fs.existsSync(agentsPath)) {
115
+ await fs.copy(
116
+ agentsPath,
117
+ path.join(targetPath, 'AGENTS.md'),
118
+ { overwrite: true }
119
+ );
120
+ showSuccess('Codex instructions (AGENTS.md)');
121
+ }
122
+
113
123
  await copyTaskFlow(targetPath);
114
124
  }
115
125
 
@@ -119,39 +129,22 @@ async function copyTaskFlow(targetPath) {
119
129
 
120
130
  await fs.ensureDir(taskFlowDest);
121
131
 
122
- showSuccess('Task Flow directory');
123
- showInfo('Note: .internal/tasks.json and .internal/status.json are NOT overwritten (your data is safe)');
124
-
125
- const contextsDest = path.join(taskFlowDest, 'contexts');
126
- await fs.ensureDir(contextsDest);
127
- showSuccess('Contexts directory (.task-flow/contexts/)');
128
-
129
- const docsDest = path.join(taskFlowDest, 'docs');
130
- await fs.ensureDir(docsDest);
131
- showSuccess('Documentation directory (.task-flow/docs/)');
132
-
133
- const exampleSrc = path.join(taskFlowSrc, 'contexts/example.png.txt');
134
- const exampleDest = path.join(contextsDest, 'example.png.txt');
135
- if (fs.existsSync(exampleSrc) && !fs.existsSync(exampleDest)) {
136
- await fs.copy(exampleSrc, exampleDest);
137
- }
138
-
139
- const files = [
140
- { name: 'README.md', overwrite: true },
141
- { name: 'tasks.input.txt', overwrite: false },
142
- { name: 'tasks.status.md', overwrite: false }
132
+ const PROTECTED = [
133
+ path.join(taskFlowDest, '.internal'),
143
134
  ];
144
135
 
145
- for (const file of files) {
146
- const src = path.join(taskFlowSrc, file.name);
147
- const dest = path.join(taskFlowDest, file.name);
136
+ await fs.copy(taskFlowSrc, taskFlowDest, {
137
+ overwrite: true,
138
+ filter: (src) => {
139
+ return !PROTECTED.some((p) => src.startsWith(p));
140
+ },
141
+ });
148
142
 
149
- if (fs.existsSync(src)) {
150
- if (file.overwrite || !fs.existsSync(dest)) {
151
- await fs.copy(src, dest, { overwrite: file.overwrite });
152
- }
153
- }
154
- }
143
+ await fs.ensureDir(path.join(taskFlowDest, 'contexts'));
144
+ await fs.ensureDir(path.join(taskFlowDest, 'docs'));
145
+
146
+ showSuccess('Task Flow directory (overwritten)');
147
+ showInfo('Protected: .internal/ (your task data is safe)');
155
148
  }
156
149
 
157
150
  async function updateGitignore(targetPath) {
@@ -167,7 +160,8 @@ async function updateGitignore(targetPath) {
167
160
  '.claude/',
168
161
  '.cursor/',
169
162
  '.task-flow/',
170
- 'CLAUDE.md'
163
+ 'CLAUDE.md',
164
+ 'AGENTS.md'
171
165
  ];
172
166
 
173
167
  for (const entry of entries) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rbin-task-flow",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "AI-powered task management for Claude and Cursor",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -33,6 +33,7 @@
33
33
  ".task-flow/",
34
34
  ".model-versions.json",
35
35
  "CLAUDE.md",
36
+ "AGENTS.md",
36
37
  "lib/"
37
38
  ],
38
39
  "preferGlobal": true,