@eltonssouza/development-utility-kit 0.10.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.
Files changed (131) hide show
  1. package/.claude/agents/README.md +24 -0
  2. package/.claude/agents/analyst.md +198 -0
  3. package/.claude/agents/backend-developer.md +126 -0
  4. package/.claude/agents/brain-keeper.md +229 -0
  5. package/.claude/agents/code-reviewer.md +181 -0
  6. package/.claude/agents/database-engineer.md +94 -0
  7. package/.claude/agents/devops-engineer.md +141 -0
  8. package/.claude/agents/frontend-developer.md +97 -0
  9. package/.claude/agents/gate-keeper.md +118 -0
  10. package/.claude/agents/migrator.md +291 -0
  11. package/.claude/agents/mobile-developer.md +80 -0
  12. package/.claude/agents/n8n-specialist.md +94 -0
  13. package/.claude/agents/product-owner.md +115 -0
  14. package/.claude/agents/qa-engineer.md +232 -0
  15. package/.claude/agents/release-engineer.md +204 -0
  16. package/.claude/agents/scaffold.md +87 -0
  17. package/.claude/agents/security-engineer.md +199 -0
  18. package/.claude/agents/sprint-runner.md +46 -0
  19. package/.claude/agents/stack-resolver.md +104 -0
  20. package/.claude/agents/tech-lead.md +182 -0
  21. package/.claude/agents/update-template.md +54 -0
  22. package/.claude/agents/ux-designer.md +118 -0
  23. package/.claude/hooks/flow-guard.js +261 -0
  24. package/.claude/hooks/flow-state.js +197 -0
  25. package/.claude/local/CLAUDE.md +71 -0
  26. package/.claude/settings.json +55 -0
  27. package/.claude/skills/README.md +331 -0
  28. package/.claude/skills/active-project/SKILL.md +131 -0
  29. package/.claude/skills/api-integration-test/SKILL.md +84 -0
  30. package/.claude/skills/auto-test-guard/SKILL.md +239 -0
  31. package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
  32. package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
  33. package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
  34. package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
  35. package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
  36. package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
  37. package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
  38. package/.claude/skills/brain-keeper/SKILL.md +62 -0
  39. package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
  40. package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
  41. package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
  42. package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
  43. package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
  44. package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
  45. package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
  46. package/.claude/skills/brain-keeper/templates/README.md +51 -0
  47. package/.claude/skills/brain-keeper/templates/adr.md +40 -0
  48. package/.claude/skills/brain-keeper/templates/bug.md +35 -0
  49. package/.claude/skills/brain-keeper/templates/daily.md +38 -0
  50. package/.claude/skills/brain-keeper/templates/feature.md +62 -0
  51. package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
  52. package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
  53. package/.claude/skills/caveman/SKILL.md +189 -0
  54. package/.claude/skills/create-stack-pack/SKILL.md +281 -0
  55. package/.claude/skills/grill-me/SKILL.md +80 -0
  56. package/.claude/skills/pair-debug/SKILL.md +288 -0
  57. package/.claude/skills/prd-ready-check/SKILL.md +86 -0
  58. package/.claude/skills/project-manager/SKILL.md +334 -0
  59. package/.claude/skills/quality-standards/SKILL.md +203 -0
  60. package/.claude/skills/quick-feature/SKILL.md +266 -0
  61. package/.claude/skills/run-sprint/SKILL.md +41 -0
  62. package/.claude/skills/scaffold/SKILL.md +60 -0
  63. package/.claude/skills/stack-discovery/SKILL.md +161 -0
  64. package/.claude/skills/test-coverage-auditor/SKILL.md +87 -0
  65. package/.claude/skills/to-issues/SKILL.md +163 -0
  66. package/.claude/skills/to-prd/SKILL.md +130 -0
  67. package/.claude/skills/update-template/SKILL.md +256 -0
  68. package/.claude/stacks/CODEOWNERS +30 -0
  69. package/.claude/stacks/README.md +97 -0
  70. package/.claude/stacks/_template.md +116 -0
  71. package/.claude/stacks/dotnet/aspire-9.md +528 -0
  72. package/.claude/stacks/go/gin-1.10.md +570 -0
  73. package/.claude/stacks/java/spring-boot-3.md +376 -0
  74. package/.claude/stacks/java/spring-boot-4.md +438 -0
  75. package/.claude/stacks/node/express-5.md +538 -0
  76. package/.claude/stacks/python/django-5.md +483 -0
  77. package/.claude/stacks/python/fastapi-0.115.md +522 -0
  78. package/.claude/stacks/typescript/angular-18.md +420 -0
  79. package/.claude/stacks/typescript/angular-19.md +397 -0
  80. package/.claude/stacks/typescript/angular-21.md +494 -0
  81. package/CLAUDE.md +472 -0
  82. package/README.md +412 -0
  83. package/bin/cli.js +848 -0
  84. package/bin/lib/adr.js +146 -0
  85. package/bin/lib/backup.js +62 -0
  86. package/bin/lib/detect-stack.js +476 -0
  87. package/bin/lib/doctor.js +527 -0
  88. package/bin/lib/help.js +328 -0
  89. package/bin/lib/identity.js +108 -0
  90. package/bin/lib/lint-allowlist.json +15 -0
  91. package/bin/lib/lint.js +798 -0
  92. package/bin/lib/local-dir.js +68 -0
  93. package/bin/lib/manifest.js +236 -0
  94. package/bin/lib/sync-all.js +394 -0
  95. package/bin/lib/version-check.js +398 -0
  96. package/dashboard/db.js +321 -0
  97. package/dashboard/package.json +22 -0
  98. package/dashboard/public/app.js +853 -0
  99. package/dashboard/public/content/docs/agents-reference.en.md +911 -0
  100. package/dashboard/public/content/docs/architecture-overview.en.md +252 -0
  101. package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
  102. package/dashboard/public/content/docs/cli-reference.en.md +538 -0
  103. package/dashboard/public/content/docs/git-flow.en.md +525 -0
  104. package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
  105. package/dashboard/public/content/docs/hooks-reference.en.md +404 -0
  106. package/dashboard/public/content/docs/pipeline.en.md +414 -0
  107. package/dashboard/public/content/docs/plugins.en.md +289 -0
  108. package/dashboard/public/content/docs/quality-gate.en.md +315 -0
  109. package/dashboard/public/content/docs/skills-reference.en.md +484 -0
  110. package/dashboard/public/content/docs/stack-rules.en.md +362 -0
  111. package/dashboard/public/content/docs/troubleshooting.en.md +565 -0
  112. package/dashboard/public/content/manifest.json +114 -0
  113. package/dashboard/public/content/manual/backend.en.md +1053 -0
  114. package/dashboard/public/content/manual/existing-project.en.md +848 -0
  115. package/dashboard/public/content/manual/frontend.en.md +1008 -0
  116. package/dashboard/public/content/manual/fullstack.en.md +1459 -0
  117. package/dashboard/public/content/manual/mobile.en.md +837 -0
  118. package/dashboard/public/content/manual/quickstart.en.md +169 -0
  119. package/dashboard/public/index.html +217 -0
  120. package/dashboard/public/style.css +857 -0
  121. package/dashboard/public/vendor/marked.min.js +69 -0
  122. package/dashboard/rtk.js +143 -0
  123. package/dashboard/server-app.js +421 -0
  124. package/dashboard/server.js +104 -0
  125. package/dashboard/test/sprint1.test.js +406 -0
  126. package/dashboard/test/sprint2.test.js +571 -0
  127. package/dashboard/test/sprint3.test.js +560 -0
  128. package/package.json +33 -0
  129. package/scripts/hooks/subagent-telemetry.sh +14 -0
  130. package/scripts/hooks/telemetry-writer.js +250 -0
  131. package/scripts/latest-versions.json +56 -0
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: ux-designer
3
+ description: "Senior UX/UI designer. Produces wireframes, user flows, design system specs, microcopy, heuristic analysis, accessibility audits. Stack-aware: reads STACK CONTEXT § Code patterns to align component specs with declared UI library (ng-bootstrap, Material, Tailwind, Bootstrap 5, etc.) from the pack. Universal output: descriptive wireframes, state machines per component, mobile-first responsive design, WCAG 2.1 AA compliance. Owns visual decisions (microinteractions, states, layout, spacing); escalates to product-owner for scope/flow changes. PT triggers: 'wireframe', 'fluxo de tela', 'design system', 'acessibilidade', 'spec de UX'."
4
+ tools: Read, Write, Glob, Grep, Bash(cat:*), Bash(find:*)
5
+ model: sonnet
6
+ ---
7
+
8
+ **You decide. You don't ask.**
9
+
10
+ The "how visual" is yours — states, animations, layout, spacing, microcopy, component choice. You decide and produce the spec. You escalate to `product-owner` only when the decision affects scope or flow (what the user can do, not how it looks). You escalate to `tech-lead` only when a visual decision requires a new dependency or breaks an existing pattern. Everything else is yours. Specialists never escalate to the human.
11
+
12
+ Senior UX/UI Designer with experience in enterprise applications. Stack-agnostic in skills; stack-aware in component output (per ADR-026).
13
+
14
+ ## Step 0 — Stack Context consumption (mandatory)
15
+
16
+ Before producing any spec, consume the `STACK CONTEXT` block injected by the invoking skill (resolved by `stack-resolver`, per ADR-026). Parse:
17
+
18
+ - **UI framework + version** (e.g., `typescript/angular-21`, `typescript/react-19`, `dart/flutter-3`).
19
+ - **UI library declared in pack `§ Code patterns`** (e.g., ng-bootstrap, Angular Material, Tailwind + shadcn, Bootstrap 5, MUI, Chakra, Mantine, NativeBase).
20
+ - **Design tokens convention** (CSS variables, SCSS map, Tailwind config, theme provider).
21
+ - **A11y baseline** the pack inherits (WCAG 2.1 AA always; some packs add AAA on critical flows).
22
+
23
+ If `STACK CONTEXT` is missing, emit `[STACK: unknown | PACK: none]` as the first line and produce a stack-agnostic spec referencing semantic primitives (e.g., "primary button", "modal dialog") instead of library components. Hand off to `tech-lead` to confirm the UI library before final implementation.
24
+
25
+ First line of every output: `[STACK: <lang>/<framework>-<major> | PACK: loaded|none | UI-LIB: <lib>]`.
26
+
27
+ ## Universal skills (stack-agnostic)
28
+
29
+ - **Descriptive wireframes** — detailed textual screen specification, layout regions, content hierarchy.
30
+ - **User flows** — states + transitions + edge cases + error paths (state-machine style).
31
+ - **Information architecture** — navigation, hierarchy, grouping, progressive disclosure.
32
+ - **Component spec** — every component documents ALL states: default, hover, focus, active, disabled, error, loading, empty, success.
33
+ - **Microcopy + UX writing** — error messages that guide the user to a fix, CTAs, labels, tooltips, empty-state copy.
34
+ - **Heuristic analysis** — Nielsen's 10 heuristics applied to existing screens; output prioritized issues.
35
+ - **Mobile-first responsive design** — breakpoints, adaptive layouts, touch targets ≥ 44×44 px.
36
+ - **WCAG 2.1 AA compliance** — aria-labels, semantic landmarks, keyboard navigation, focus order, color contrast ≥ 4.5:1 (3:1 on large text), no color-only signaling.
37
+ - **Design tokens** — reference theme-aware CSS variables / pack-defined tokens; never absolute hex.
38
+
39
+ ## Stack-aware output
40
+
41
+ When the pack declares a UI library, propose components using that library's primitives:
42
+
43
+ - ng-bootstrap → `ngb-modal`, `ngb-accordion`, `ngb-typeahead`, `ngb-pagination`, `ngb-toast`.
44
+ - Angular Material → `mat-dialog`, `mat-expansion-panel`, `mat-autocomplete`, `mat-paginator`, `mat-snack-bar`.
45
+ - Tailwind + shadcn → `<Dialog>`, `<Accordion>`, `<Combobox>`, `<Pagination>`, `<Toast>`.
46
+ - Bootstrap 5 (vanilla) → `.modal`, `.accordion`, `.dropdown`, `.pagination`, `.toast`.
47
+ - MUI / Chakra / Mantine → equivalents from the library's docs.
48
+
49
+ Never invent a custom component when the declared library has a matching primitive. If the library lacks the primitive, flag it and escalate to `tech-lead` (new dependency decision).
50
+
51
+ ## Impeccable skill (ADR-010)
52
+
53
+ For visual refinement, use the Impeccable skill: `/impeccable polish|harden|audit|typeset|colorize|layout`. Reference `DESIGN.md` in the project. Impeccable is a tool, not the authority — you and `product-owner` decide design; Impeccable polishes.
54
+
55
+ ## Interaction with other agents
56
+
57
+ | Agent | When to interact | What you own vs what they own |
58
+ |---|---|---|
59
+ | `product-owner` | Scope or flow change (new screen, removed feature, changed user journey) | PO decides "what"; you decide "how visual" |
60
+ | `tech-lead` | New UI library, pattern-breaking visual decision, missing primitive | TL approves libs/patterns; you own visual spec |
61
+ | `frontend-developer` | Hand off wireframe + component spec for web implementation | You spec; developer implements per pack |
62
+ | `mobile-developer` | Hand off wireframe + component spec for mobile implementation | Joint: mobile patterns differ (gestures, safe area, native primitives) |
63
+ | `backend-developer` | API data shape affects what can be displayed | Joint: you define what UI needs; BE defines what API returns |
64
+
65
+ ## Output format
66
+
67
+ ```
68
+ [STACK: <lang>/<framework>-<major> | PACK: loaded|none | UI-LIB: <lib>]
69
+
70
+ ## Screen: [name]
71
+ **Route:** /path
72
+ **Access:** [allowed roles]
73
+
74
+ ### Layout
75
+ [Visual structure: header, sidebar, main area, footer; grid regions; responsive behavior]
76
+
77
+ ### Components
78
+ 1. **[Component name]**
79
+ - Library primitive: [from declared UI lib, or "semantic primitive" if pack absent]
80
+ - Displayed data: [fields]
81
+ - Actions: [buttons, links, gestures]
82
+ - States: default | hover | focus | active | disabled | loading | empty | error | success
83
+ - Microcopy: [labels, error messages, empty-state copy]
84
+ - Validations: [inline feedback, format hints]
85
+
86
+ ### Interaction flow
87
+ 1. User does X → system shows Y
88
+ 2. On error → display message Z in toast/alert with recovery action
89
+
90
+ ### Responsiveness (mobile-first)
91
+ - Mobile (<768px): [layout]
92
+ - Tablet (768-992px): [adaptation]
93
+ - Desktop (>992px): [adaptation]
94
+
95
+ ### Accessibility (WCAG 2.1 AA)
96
+ - Required aria-labels and semantic landmarks
97
+ - Keyboard navigation order + focus management
98
+ - Color contrast notes (token references, not hex)
99
+ - Screen-reader narration for dynamic regions (aria-live)
100
+ ```
101
+
102
+ ## Inviolable rules
103
+
104
+ 1. **Always specify ALL states** — never spec only the happy path.
105
+ 2. **Error messages guide the user to fix the issue** — no generic "An error occurred."
106
+ 3. **Empty states have a clear CTA** — never a blank screen.
107
+ 4. **Loading: skeleton screens for lists**, spinners only for short point operations (<1s).
108
+ 5. **Never absolute colors** — reference design tokens / theme variables only.
109
+ 6. **Prefer the declared UI library's primitives** — invent custom only when escalated to `tech-lead`.
110
+ 7. **WCAG 2.1 AA is non-negotiable** — aria-labels, keyboard nav, contrast notes on every spec.
111
+ 8. **Mobile-first** — design the small viewport first, expand up.
112
+
113
+ ## References
114
+
115
+ - ADR-010 (Impeccable skill — design tooling)
116
+ - ADR-026 (Generic agents + stack packs — stack-aware component output)
117
+ - `.claude/stacks/<lang>/<framework>-<major>.md` (pack with UI library + tokens convention)
118
+ - `.claude/skills/quality-standards/SKILL.md` (a11y thresholds: 0 serious / 0 critical via jest-axe + axe-playwright)
@@ -0,0 +1,261 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * flow-guard.js — UserPromptSubmit hook (T2.1 / Sprint 2).
5
+ *
6
+ * Intercepts every prompt before it reaches the model. Responsibilities:
7
+ *
8
+ * 1. Inject [FLOW STATE: <stage>] into every prompt (visibility).
9
+ * 2. Classify the prompt as `qualified` (implementation/sprint work) or `trivial`.
10
+ * 3. For `qualified` prompts missing their prerequisite artifact:
11
+ * - Hard-block with a directive injection telling the model to refuse and
12
+ * redirect to grill-me / PLAN production before proceeding.
13
+ * 4. Honor `flow: skip-guard` anywhere in the prompt — log the bypass and
14
+ * let the turn through unchanged (except the FLOW STATE injection).
15
+ * 5. Never exit with a non-zero code — the hook must never kill the turn.
16
+ *
17
+ * Input (stdin): JSON { prompt, session_id?, cwd? }
18
+ * Output (stdout): JSON { prompt } — modified prompt with injections.
19
+ *
20
+ * The hook follows the Claude Code hook protocol:
21
+ * - Exit 0 always (even on error — fail-open).
22
+ * - Output JSON with the (possibly modified) prompt.
23
+ * - Any additional instructions to the model are injected into the prompt
24
+ * text as a [SYSTEM NOTE] block that the model reads as context.
25
+ */
26
+
27
+ const fs = require('fs');
28
+ const path = require('path');
29
+
30
+ // ── Load flow-state lib ──────────────────────────────────────────────────────
31
+
32
+ let flowState;
33
+ try {
34
+ flowState = require(path.join(__dirname, 'flow-state.js'));
35
+ } catch {
36
+ // If the lib is unavailable, operate in degraded mode (inject state only).
37
+ flowState = null;
38
+ }
39
+
40
+ // ── Classification: qualified work signals ───────────────────────────────────
41
+ // A prompt is `qualified` if it signals intent to implement a feature,
42
+ // run a sprint, or perform brownfield work that requires a prior planning
43
+ // artifact (DISCOVERY_*.md or PLAN_*.md).
44
+
45
+ const QUALIFIED_KEYWORDS = [
46
+ /\bimplement\b/i,
47
+ /\bimplementa\b/i,
48
+ /\bcria\s+(endpoint|feature|funcionalidade|sistema|módulo|modulo)\b/i,
49
+ /\bcreate\s+(endpoint|feature|system|module|service)\b/i,
50
+ /\brun\s+sprint\b/i,
51
+ /\broda\s+(a\s+)?sprint\b/i,
52
+ /\bexecute\s+(the\s+)?sprint\b/i,
53
+ /\bexecuta\s+(a\s+)?sprint\b/i,
54
+ /\bdesenvolvimento\b/i,
55
+ /\bfaz\s+(o\s+)?(back|front|CRUD|endpoint|tela)\b/i,
56
+ /\bscaffold\b/i,
57
+ /\bbuild\s+(the\s+)?(feature|system|module|app)\b/i,
58
+ /\badd\s+(auth|authentication|authorization|login)\b/i,
59
+ /\badiciona\s+(auth|autenticação|login)\b/i,
60
+ /\bstart\s+coding\b/i,
61
+ /\bcomece\s+(a\s+)?codificar\b/i,
62
+ /\bnew\s+feature\b/i,
63
+ /\bnova\s+feature\b/i,
64
+ /\bnova\s+funcionalidade\b/i,
65
+ ];
66
+
67
+ // Keywords that explicitly signal sprint execution (require PLAN artifact)
68
+ const SPRINT_KEYWORDS = [
69
+ /\brun\s+sprint\b/i,
70
+ /\broda\s+(a\s+)?sprint\b/i,
71
+ /\bexecute\s+(the\s+)?sprint\b/i,
72
+ /\bexecuta\s+(a\s+)?sprint\b/i,
73
+ /\bsprint\s+\d+\b/i,
74
+ ];
75
+
76
+ // Keywords that signal trivial/conversational work (never blocked)
77
+ const TRIVIAL_KEYWORDS = [
78
+ /^(hello|hi|hey|oi|olá|ola)\b/i,
79
+ /^(what|how|why|where|quando|como|qual|quem)\b/i,
80
+ /\bexplain\b/i,
81
+ /\bexplica\b/i,
82
+ /\bshow\s+me\b/i,
83
+ /\bmostra\b/i,
84
+ /\blist\b/i,
85
+ /\blista\b/i,
86
+ /\bstatus\b/i,
87
+ /\bcheck\b/i,
88
+ /\bverifica\b/i,
89
+ /\bduk\s+lint\b/i,
90
+ /\brun\s+tests?\b/i,
91
+ /\blint\b/i,
92
+ /\bupdate\s+template\b/i,
93
+ /\bsync\b/i,
94
+ ];
95
+
96
+ // ── Helpers ──────────────────────────────────────────────────────────────────
97
+
98
+ function matchesAny(text, patterns) {
99
+ return patterns.some((p) => p.test(text));
100
+ }
101
+
102
+ function classifyPrompt(prompt) {
103
+ if (matchesAny(prompt, TRIVIAL_KEYWORDS)) return 'trivial';
104
+ if (matchesAny(prompt, SPRINT_KEYWORDS)) return 'sprint';
105
+ if (matchesAny(prompt, QUALIFIED_KEYWORDS)) return 'qualified';
106
+ return 'trivial';
107
+ }
108
+
109
+ function hasBypassDirective(prompt) {
110
+ return /flow:\s*skip-guard/i.test(prompt);
111
+ }
112
+
113
+ function resolveProjectRoot(cwd) {
114
+ return cwd || process.cwd();
115
+ }
116
+
117
+ // ── Lane classifier (for flow-guard + flow-lanes awareness) ─────────────────
118
+ // Maps classification to the 4 project-manager lanes.
119
+ // greenfield — new project / no artifacts yet
120
+ // brownfield — existing project, implementation work, needs DISCOVERY
121
+ // sprint — sprint execution, needs PLAN
122
+ // small — trivial / single-domain (route mode)
123
+
124
+ function deriveLane(classification, state) {
125
+ if (classification === 'trivial') return 'small';
126
+ if (classification === 'sprint') return 'sprint';
127
+ if (classification === 'qualified') {
128
+ // Greenfield: no feature active and no artifacts
129
+ if (!state || state.stage === 'none') return 'greenfield';
130
+ return 'brownfield';
131
+ }
132
+ return 'small';
133
+ }
134
+
135
+ // ── Main ─────────────────────────────────────────────────────────────────────
136
+
137
+ function main() {
138
+ let input = '';
139
+ process.stdin.setEncoding('utf8');
140
+ process.stdin.on('data', (chunk) => { input += chunk; });
141
+ process.stdin.on('end', () => {
142
+ run(input);
143
+ });
144
+ }
145
+
146
+ function run(rawInput) {
147
+ let payload;
148
+ try {
149
+ payload = JSON.parse(rawInput);
150
+ } catch {
151
+ // Malformed input — fail-open: echo back empty prompt wrapper.
152
+ payload = { prompt: rawInput || '' };
153
+ }
154
+
155
+ const originalPrompt = payload.prompt || '';
156
+ const sessionId = payload.session_id || 'unknown';
157
+ const projectRoot = resolveProjectRoot(payload.cwd);
158
+
159
+ // ── 1. Load flow state ───────────────────────────────────────────────────
160
+ let state = { stage: 'none', active_feature: null, discovery_artifact: null, plan_artifact: null };
161
+ if (flowState) {
162
+ try {
163
+ state = flowState.loadState(projectRoot);
164
+ } catch {
165
+ // Degraded — continue with empty state
166
+ }
167
+ }
168
+
169
+ // ── 2. Check bypass directive ────────────────────────────────────────────
170
+ if (hasBypassDirective(originalPrompt)) {
171
+ if (flowState) {
172
+ try {
173
+ flowState.logBypass({
174
+ session_id: sessionId,
175
+ prompt: originalPrompt,
176
+ reason: 'flow: skip-guard directive present in prompt',
177
+ }, projectRoot);
178
+ } catch { /* non-fatal */ }
179
+ }
180
+
181
+ const bypassedPrompt = injectFlowState(originalPrompt, state, 'BYPASS');
182
+ process.stdout.write(JSON.stringify({ prompt: bypassedPrompt }) + '\n');
183
+ process.exit(0);
184
+ return;
185
+ }
186
+
187
+ // ── 3. Classify prompt ───────────────────────────────────────────────────
188
+ const classification = classifyPrompt(originalPrompt);
189
+ const lane = deriveLane(classification, state);
190
+
191
+ // ── 4. Prerequisite enforcement ──────────────────────────────────────────
192
+ let blockDirective = null;
193
+
194
+ if (lane === 'sprint' && !state.plan_artifact) {
195
+ blockDirective = buildSprintBlock(state);
196
+ } else if ((lane === 'brownfield' || lane === 'greenfield') && !state.discovery_artifact) {
197
+ blockDirective = buildDiscoveryBlock(lane, state);
198
+ }
199
+
200
+ // ── 5. Build final prompt ────────────────────────────────────────────────
201
+ let finalPrompt;
202
+ if (blockDirective) {
203
+ finalPrompt = injectBlock(originalPrompt, state, blockDirective);
204
+ } else {
205
+ finalPrompt = injectFlowState(originalPrompt, state, 'OK');
206
+ }
207
+
208
+ process.stdout.write(JSON.stringify({ prompt: finalPrompt }) + '\n');
209
+ process.exit(0);
210
+ }
211
+
212
+ // ── Injection builders ───────────────────────────────────────────────────────
213
+
214
+ function stageLabel(state) {
215
+ const s = state.stage || 'none';
216
+ const f = state.active_feature ? ` | feature: ${state.active_feature}` : '';
217
+ return `${s}${f}`;
218
+ }
219
+
220
+ function injectFlowState(prompt, state, status) {
221
+ const label = stageLabel(state);
222
+ return `[FLOW STATE: ${label} | status: ${status}]\n\n${prompt}`;
223
+ }
224
+
225
+ function injectBlock(prompt, state, block) {
226
+ const label = stageLabel(state);
227
+ return `[FLOW STATE: ${label} | status: BLOCK]\n\n[SYSTEM NOTE — FLOW GUARD]\n${block}\n[END SYSTEM NOTE]\n\n${prompt}`;
228
+ }
229
+
230
+ function buildDiscoveryBlock(lane, state) {
231
+ const laneLabel = lane === 'greenfield' ? 'greenfield (new feature)' : 'brownfield (existing project)';
232
+ return `FLOW GUARD — BLOCK: Implementation work detected (lane: ${laneLabel}) but no DISCOVERY_*.md artifact found in docs/discovery/.
233
+
234
+ This prompt requests qualified implementation work without the mandatory prerequisite artifact.
235
+
236
+ Per ADR-036 and the project-manager front-controller rules, you MUST:
237
+ 1. Refuse to implement directly.
238
+ 2. Tell the user to run the \`grill-me\` skill first to produce a DISCOVERY_*.md artifact.
239
+ 3. After grill-me, the analyst produces a PLAN_*.md, then sprint-runner executes.
240
+
241
+ Respond with: "Antes de implementar, precisamos de um artefato de discovery. Digite 'grill me' para iniciar o processo."
242
+
243
+ To bypass this gate (audited): include 'flow: skip-guard' in your prompt.`;
244
+ }
245
+
246
+ function buildSprintBlock(state) {
247
+ return `FLOW GUARD — BLOCK: Sprint execution requested but no PLAN_*.md artifact found in docs/plans/.
248
+
249
+ Per the sprint-runner contract, sprint execution requires a formal PLAN_*.md to exist.
250
+
251
+ You MUST:
252
+ 1. Refuse to run the sprint directly.
253
+ 2. Tell the user to produce a PLAN_*.md first (via \`grill-me\` → \`analyst\` pipeline).
254
+ 3. Once the PLAN exists, retry the sprint command.
255
+
256
+ Respond with: "Não há PLAN_*.md para executar. Crie o plano primeiro via 'grill me' → analyst → PLAN_*.md."
257
+
258
+ To bypass this gate (audited): include 'flow: skip-guard' in your prompt.`;
259
+ }
260
+
261
+ main();
@@ -0,0 +1,197 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * flow-state.js — Flow state read/write helper (T2.2 / Sprint 2).
5
+ *
6
+ * Schema for .claude/.flow-state.json:
7
+ * {
8
+ * "active_feature": string | null, // current feature slug
9
+ * "stage": "none" | "discovery" | "plan" | "sprint" | "done",
10
+ * "discovery_artifact": string | null, // path to DISCOVERY_*.md
11
+ * "plan_artifact": string | null, // path to PLAN_*.md
12
+ * "bypass_log": [
13
+ * { "ts": ISO8601, "session_id": string, "prompt_snippet": string, "reason": string }
14
+ * ],
15
+ * "updated_at": ISO8601
16
+ * }
17
+ *
18
+ * When the cache file is absent or unreadable, deriveState() falls back to
19
+ * scanning DISCOVERY_ and PLAN_ artifacts in the project root so that deleting
20
+ * the cache never breaks the gate.
21
+ */
22
+
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+
26
+ const CACHE_FILENAME = '.flow-state.json';
27
+
28
+ // ── Default empty state ──────────────────────────────────────────────────────
29
+
30
+ function emptyState() {
31
+ return {
32
+ active_feature: null,
33
+ stage: 'none',
34
+ discovery_artifact: null,
35
+ plan_artifact: null,
36
+ bypass_log: [],
37
+ updated_at: new Date().toISOString(),
38
+ };
39
+ }
40
+
41
+ // ── Cache helpers ────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Returns the path to .flow-state.json for a given project root.
45
+ * Default root: the directory two levels up from this file (.claude/ parent).
46
+ */
47
+ function cachePath(projectRoot) {
48
+ const root = projectRoot || path.resolve(__dirname, '..', '..');
49
+ return path.join(root, CACHE_FILENAME);
50
+ }
51
+
52
+ /**
53
+ * Read .flow-state.json. Returns null if absent or invalid JSON.
54
+ */
55
+ function readCache(projectRoot) {
56
+ const p = cachePath(projectRoot);
57
+ try {
58
+ const raw = fs.readFileSync(p, 'utf8');
59
+ const parsed = JSON.parse(raw);
60
+ if (parsed && typeof parsed === 'object') return parsed;
61
+ return null;
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Write state object to .flow-state.json (atomic: write to tmp then rename).
69
+ */
70
+ function writeCache(state, projectRoot) {
71
+ const p = cachePath(projectRoot);
72
+ const tmp = p + '.tmp';
73
+ const updated = Object.assign({}, state, { updated_at: new Date().toISOString() });
74
+ fs.writeFileSync(tmp, JSON.stringify(updated, null, 2), 'utf8');
75
+ fs.renameSync(tmp, p);
76
+ return updated;
77
+ }
78
+
79
+ // ── Artifact scanner (derive-from-artifacts fallback) ────────────────────────
80
+
81
+ /**
82
+ * Scans the project root for DISCOVERY_*.md and PLAN_*.md to derive stage.
83
+ * Returns a state object derived from the artifact presence on disk.
84
+ *
85
+ * Priority: if both exist → stage = 'plan'; only DISCOVERY_ → stage = 'discovery';
86
+ * neither → stage = 'none'.
87
+ */
88
+ function deriveState(projectRoot) {
89
+ const root = projectRoot || path.resolve(__dirname, '..', '..');
90
+
91
+ const docsDiscovery = path.join(root, 'docs', 'discovery');
92
+ const docsPlans = path.join(root, 'docs', 'plans');
93
+
94
+ let discoveryArtifact = null;
95
+ let planArtifact = null;
96
+ let activeFeature = null;
97
+
98
+ // Scan docs/discovery/ for DISCOVERY_*.md
99
+ try {
100
+ const files = fs.readdirSync(docsDiscovery);
101
+ const discoveries = files
102
+ .filter((f) => f.startsWith('DISCOVERY_') && f.endsWith('.md'))
103
+ .sort()
104
+ .reverse(); // most recent first
105
+ if (discoveries.length > 0) {
106
+ discoveryArtifact = path.join(docsDiscovery, discoveries[0]);
107
+ // Extract feature slug from filename: DISCOVERY_<slug>.md
108
+ activeFeature = discoveries[0].replace(/^DISCOVERY_/, '').replace(/\.md$/, '');
109
+ }
110
+ } catch {
111
+ // docs/discovery/ does not exist — no discovery artifacts
112
+ }
113
+
114
+ // Scan docs/plans/ for PLAN_*.md
115
+ try {
116
+ const files = fs.readdirSync(docsPlans);
117
+ const plans = files
118
+ .filter((f) => f.startsWith('PLAN_') && f.endsWith('.md'))
119
+ .sort()
120
+ .reverse();
121
+ if (plans.length > 0) {
122
+ planArtifact = path.join(docsPlans, plans[0]);
123
+ // Override feature slug from PLAN if present
124
+ if (!activeFeature) {
125
+ activeFeature = plans[0].replace(/^PLAN_/, '').replace(/\.md$/, '');
126
+ }
127
+ }
128
+ } catch {
129
+ // docs/plans/ does not exist — no plan artifacts
130
+ }
131
+
132
+ // Determine stage
133
+ let stage = 'none';
134
+ if (planArtifact) {
135
+ stage = 'plan';
136
+ } else if (discoveryArtifact) {
137
+ stage = 'discovery';
138
+ }
139
+
140
+ return {
141
+ active_feature: activeFeature,
142
+ stage,
143
+ discovery_artifact: discoveryArtifact,
144
+ plan_artifact: planArtifact,
145
+ bypass_log: [],
146
+ updated_at: new Date().toISOString(),
147
+ derived: true, // flag: this state came from artifact scan, not cache
148
+ };
149
+ }
150
+
151
+ // ── Public API ───────────────────────────────────────────────────────────────
152
+
153
+ /**
154
+ * Load flow state. Order:
155
+ * 1. Read .flow-state.json cache.
156
+ * 2. If absent/invalid: derive from artifacts.
157
+ * 3. If no artifacts either: return empty state (stage = 'none').
158
+ */
159
+ function loadState(projectRoot) {
160
+ const cached = readCache(projectRoot);
161
+ if (cached) return cached;
162
+ return deriveState(projectRoot);
163
+ }
164
+
165
+ /**
166
+ * Append a bypass entry to the log and persist to cache.
167
+ */
168
+ function logBypass(entry, projectRoot) {
169
+ const state = loadState(projectRoot);
170
+ const log = Array.isArray(state.bypass_log) ? state.bypass_log : [];
171
+ log.push({
172
+ ts: new Date().toISOString(),
173
+ session_id: entry.session_id || 'unknown',
174
+ prompt_snippet: (entry.prompt || '').slice(0, 120),
175
+ reason: entry.reason || 'flow: skip-guard',
176
+ });
177
+ return writeCache(Object.assign({}, state, { bypass_log: log }), projectRoot);
178
+ }
179
+
180
+ /**
181
+ * Update the active feature and stage, persist to cache.
182
+ */
183
+ function updateState(patch, projectRoot) {
184
+ const state = loadState(projectRoot);
185
+ return writeCache(Object.assign({}, state, patch), projectRoot);
186
+ }
187
+
188
+ module.exports = {
189
+ loadState,
190
+ deriveState,
191
+ readCache,
192
+ writeCache,
193
+ logBypass,
194
+ updateState,
195
+ cachePath,
196
+ emptyState,
197
+ };
@@ -0,0 +1,71 @@
1
+ # Local overrides — Elton (PT-BR)
2
+
3
+ > **This file is a personal override, not part of the published harness.**
4
+ >
5
+ > Per ADR-032, `.claude/local/` is never touched by `duk install`. Anything here
6
+ > applies on top of the canonical `.claude/` directory and the public `CLAUDE.md`.
7
+ > The loader priority is: `local/` wins over harness.
8
+ >
9
+ > If you are a contributor cloning this repo to work on the harness itself,
10
+ > you can safely delete this file. It only affects the maintainer's personal
11
+ > conversational experience.
12
+
13
+ ---
14
+
15
+ ## Conversational preferences
16
+
17
+ - **Assistant reply language**: Brazilian Portuguese (`pt-BR`) in the chat layer.
18
+ The public `CLAUDE.md` (English) does not impose a chat language; this override
19
+ pins my preference. Agents and skill contents remain in English regardless.
20
+ - **Caveman style**: ON by default.
21
+ - ULTRA for code, scripts, files (`.java`, `.ts`, `.py`, `.sh`, `.yml`, `.json`)
22
+ - FULL for prose markdown (`.md`)
23
+ - LITE for contracts and PRDs that need readability
24
+ - Disable with "stop caveman" / "volta normal"
25
+ - **Tone**: direct, no fluff, no excessive apology when correcting course.
26
+
27
+ ---
28
+
29
+ ## Repository-specific habits
30
+
31
+ - I work from `C:\development\source\projects\<project-name>\` on Windows.
32
+ - I use Git Bash for shell, not PowerShell.
33
+ - I push from the local machine; CI handles publish via `publish.yml` workflow.
34
+ - I keep credentials at `C:\development\tools\credentials\vps.txt` — agents that
35
+ need VPS access should read from there silently, never prompt me.
36
+
37
+ ---
38
+
39
+ ## Things to remember about this project
40
+
41
+ - **Commits never mention Claude / Anthropic / AI / LLM / assistant.**
42
+ Same rule as the public policy in `CONTRIBUTING.md`. Strictly enforced.
43
+ - **English in code, comments, ADRs, docs.** Portuguese only in this file
44
+ and in the chat conversation between me and the assistant.
45
+ - **TDD is mandatory.** No exception. `qa-engineer` writes failing test
46
+ before any implementation.
47
+ - **Senior+ gate is non-negotiable.** Coverage >=85%, mutation >=70% on domain.
48
+ If a PR cannot meet these for legitimate reasons, the answer is "do not merge".
49
+
50
+ ---
51
+
52
+ ## Personal escalation rules
53
+
54
+ Beyond the Autonomy Matrix in the public `CLAUDE.md`, escalate to me only when:
55
+
56
+ - A decision would cost more than R$ 200/month in recurring infra
57
+ - A breaking change is needed on a contract that I have already published to npm
58
+ - An action would delete or overwrite real customer data without a recovery path
59
+ - A third-party service we depend on (RTK, Impeccable) had a breaking
60
+ change that needs a pin bump
61
+
62
+ Everything else: agents decide. Do not interrupt me for routine.
63
+
64
+ ---
65
+
66
+ ## See also
67
+
68
+ - Public `CLAUDE.md` at the repo root
69
+ - ADR-032 — drift detection + `.claude/local/` overrides policy
70
+ - `CONTRIBUTING.md` — public contribution guide
71
+ - `dashboard/public/content/docs/` — all user-facing docs