trackfw 7.2.0 → 7.4.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.
@@ -2,6 +2,8 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const path = require('path')
5
+ const { resolveAgentNamespaces } = require('../validator')
6
+ const { normalizeRefSeparator } = require('../lib/pathfmt')
5
7
 
6
8
  const ROADMAP_STATES = ['wip', 'backlog', 'blocked', 'done', 'abandoned']
7
9
 
@@ -70,7 +72,15 @@ function collectNodes(dir, type, state) {
70
72
  try { content = fs.readFileSync(path.join(dir, file), 'utf8') } catch (_) {}
71
73
  const fm = parseFrontmatter(content)
72
74
  const title = extractTitle(content, file)
73
- const id = path.join(dir, file)
75
+ // node ID do grafo — IDENTIFICADOR emitido em JSON (ADR-2026-09-04, D1 categoria 2),
76
+ // e tambem o alvo de toda aresta: resolveRef() abaixo so devolve valores vindos de
77
+ // fileIndex/titleIndex, isto e, sempre um node id — nunca o valor cru do frontmatter.
78
+ // Normalizar o id aqui, portanto, normaliza `edge.to` por construcao.
79
+ //
80
+ // 🔴 O path.join da linha 71 (fs.readFileSync) e uma EXPRESSAO INDEPENDENTE sobre os
81
+ // mesmos operandos: normalizar esta nao pode afeta-la. O caminho de travessia
82
+ // permanece nativo (ADR D2). Espelha internal/serve/api_chain.go:111.
83
+ const id = normalizeRefSeparator(path.join(dir, file))
74
84
  nodes.push({ id, type, title, state, fm })
75
85
  }
76
86
  return nodes
@@ -102,14 +112,7 @@ function handleChain(cfg, req, res) {
102
112
 
103
113
  // REQs
104
114
  if (namespacing === 'by_agent') {
105
- let agents = cfg.agents || []
106
- if (!agents.length) {
107
- try {
108
- agents = fs.readdirSync(reqDir).filter(f => {
109
- try { return fs.statSync(path.join(reqDir, f)).isDirectory() } catch (_) { return false }
110
- })
111
- } catch (_) {}
112
- }
115
+ const agents = resolveAgentNamespaces(cfg, reqDir)
113
116
  for (const agent of agents) {
114
117
  for (const state of ROADMAP_STATES) {
115
118
  const dir = path.join(reqDir, agent, state)
@@ -122,14 +125,7 @@ function handleChain(cfg, req, res) {
122
125
 
123
126
  // Roadmaps
124
127
  if (namespacing === 'by_agent') {
125
- let agents = cfg.agents || []
126
- if (!agents.length) {
127
- try {
128
- agents = fs.readdirSync(roadmapDir).filter(f => {
129
- try { return fs.statSync(path.join(roadmapDir, f)).isDirectory() } catch (_) { return false }
130
- })
131
- } catch (_) {}
132
- }
128
+ const agents = resolveAgentNamespaces(cfg, roadmapDir)
133
129
  for (const agent of agents) {
134
130
  for (const state of ROADMAP_STATES) {
135
131
  const dir = path.join(roadmapDir, agent, state)
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs')
4
4
  const path = require('path')
5
5
  const { parseLog, calculate } = require('../commands/metrics')
6
+ const { resolveAgentNamespaces } = require('../validator')
6
7
 
7
8
  const STATES = ['wip', 'backlog', 'blocked', 'done', 'abandoned']
8
9
  const MS_PER_DAY = 24 * 60 * 60 * 1000
@@ -34,14 +35,7 @@ function buildStateDistribution(cfg) {
34
35
  const namespacing = cfg.roadmapNamespacing || 'flat'
35
36
 
36
37
  if (namespacing === 'by_agent') {
37
- let agents = cfg.agents || []
38
- if (!agents.length) {
39
- try {
40
- agents = fs.readdirSync(roadmapDir).filter(f => {
41
- try { return fs.statSync(path.join(roadmapDir, f)).isDirectory() } catch (_) { return false }
42
- })
43
- } catch (_) { agents = [] }
44
- }
38
+ const agents = resolveAgentNamespaces(cfg, roadmapDir)
45
39
  for (const agent of agents) {
46
40
  for (const state of STATES) {
47
41
  dist[state] = (dist[state] || 0) + countFilesInState(path.join(roadmapDir, agent, state))