@ancleto/spec 0.5.0 → 0.5.2
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/package.json +1 -1
- package/src/cli/index.js +9 -10
- package/src/core/discovery.js +62 -0
- package/src/core/repomix-tier.js +38 -0
package/package.json
CHANGED
package/src/cli/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import { fileURLToPath } from 'node:url'
|
|
|
8
8
|
import { homedir, tmpdir } from 'node:os'
|
|
9
9
|
import { createMemoryEngine, defaultMemoryDbPath } from '../core/memory/engine.js'
|
|
10
10
|
import { memoryDoctor } from '../core/memory/doctor.js'
|
|
11
|
+
import { writeDiscoveryMap } from '../core/discovery.js'
|
|
12
|
+
import { readProjectTier, buildRepomixArgs, tierTokenBudget } from '../core/repomix-tier.js'
|
|
11
13
|
|
|
12
14
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
13
15
|
const ROOT = join(__dirname, '..', '..')
|
|
@@ -597,16 +599,11 @@ async function checkDiscovery() {
|
|
|
597
599
|
|
|
598
600
|
async function runRepomix(flags, tmpFile) {
|
|
599
601
|
const local = await resolveBin('repomix')
|
|
602
|
+
const tier = readProjectTier(process.cwd())
|
|
603
|
+
const { exclude } = await loadDiscoveryConfig()
|
|
600
604
|
const args = []
|
|
601
605
|
if (!local) args.push('-y', 'repomix@1.18.0')
|
|
602
|
-
args.push('--output', tmpFile)
|
|
603
|
-
const inc = flagValue(flags, '--include')
|
|
604
|
-
if (inc) args.push('--include', inc)
|
|
605
|
-
const extraIgnore = flagValue(flags, '--ignore')
|
|
606
|
-
const { exclude } = await loadDiscoveryConfig()
|
|
607
|
-
const ignore = [...exclude, ...(extraIgnore ? extraIgnore.split(',') : [])].filter(Boolean)
|
|
608
|
-
if (ignore.length) args.push('--ignore', ignore.join(','))
|
|
609
|
-
if (flags.includes('--compress')) args.push('--compress')
|
|
606
|
+
args.push('--output', tmpFile, ...buildRepomixArgs(flags, tier, exclude))
|
|
610
607
|
const cmd = local || 'npx'
|
|
611
608
|
const r = spawnSync(cmd, args, { encoding: 'utf8', cwd: process.cwd(), shell: true })
|
|
612
609
|
if (r.error) {
|
|
@@ -628,8 +625,9 @@ async function packDiscovery(flags) {
|
|
|
628
625
|
let content = ''
|
|
629
626
|
try { content = await readFile(tmpFile, 'utf8') } catch {}
|
|
630
627
|
const tokens = Math.round(content.length / 4)
|
|
631
|
-
const
|
|
632
|
-
|
|
628
|
+
const explicit = flagValue(flags, '--token-budget')
|
|
629
|
+
const budget = explicit ? Number(explicit) : tierTokenBudget(readProjectTier(process.cwd()))
|
|
630
|
+
if (budget && tokens > budget) {
|
|
633
631
|
console.error(`ancleto: el pack supera el token-budget (${tokens} > ${budget})`)
|
|
634
632
|
process.exit(1)
|
|
635
633
|
}
|
|
@@ -649,6 +647,7 @@ async function packDiscovery(flags) {
|
|
|
649
647
|
}
|
|
650
648
|
|
|
651
649
|
async function discovery(flags) {
|
|
650
|
+
try { writeDiscoveryMap(process.cwd()) } catch {}
|
|
652
651
|
if (flags.includes('--check')) {
|
|
653
652
|
await checkDiscovery()
|
|
654
653
|
return
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const DISCOVERY_MAP_FILE = '.discovery-map.json'
|
|
5
|
+
export const TOPOLOGY_IGNORED_DIRS = ['node_modules', '.git', '.ancleto', 'dist', 'build', 'coverage']
|
|
6
|
+
|
|
7
|
+
function countFilesRecursive(dir, ignored) {
|
|
8
|
+
let n = 0
|
|
9
|
+
let entries
|
|
10
|
+
try {
|
|
11
|
+
entries = readdirSync(dir, { withFileTypes: true })
|
|
12
|
+
} catch {
|
|
13
|
+
return 0
|
|
14
|
+
}
|
|
15
|
+
for (const e of entries) {
|
|
16
|
+
const p = join(dir, e.name)
|
|
17
|
+
if (e.isDirectory()) {
|
|
18
|
+
if (ignored.has(e.name)) continue
|
|
19
|
+
n += countFilesRecursive(p, ignored)
|
|
20
|
+
} else if (e.isFile()) {
|
|
21
|
+
n += 1
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return n
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function buildTopologyMap(rootDir) {
|
|
28
|
+
const ignored = new Set(TOPOLOGY_IGNORED_DIRS)
|
|
29
|
+
const tree_summary = {}
|
|
30
|
+
const root_files = []
|
|
31
|
+
let total = 0
|
|
32
|
+
let entries
|
|
33
|
+
try {
|
|
34
|
+
entries = readdirSync(rootDir, { withFileTypes: true })
|
|
35
|
+
} catch {
|
|
36
|
+
entries = []
|
|
37
|
+
}
|
|
38
|
+
for (const e of entries) {
|
|
39
|
+
if (ignored.has(e.name)) continue
|
|
40
|
+
if (e.isDirectory()) {
|
|
41
|
+
const n = countFilesRecursive(join(rootDir, e.name), ignored)
|
|
42
|
+
tree_summary[e.name] = n
|
|
43
|
+
total += n
|
|
44
|
+
} else if (e.isFile()) {
|
|
45
|
+
root_files.push(e.name)
|
|
46
|
+
total += 1
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
root_files.sort()
|
|
50
|
+
return {
|
|
51
|
+
last_updated: new Date().toISOString(),
|
|
52
|
+
total_files: total,
|
|
53
|
+
tree_summary,
|
|
54
|
+
root_files
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function writeDiscoveryMap(rootDir) {
|
|
59
|
+
const map = buildTopologyMap(rootDir)
|
|
60
|
+
writeFileSync(join(rootDir, DISCOVERY_MAP_FILE), JSON.stringify(map, null, 2) + '\n')
|
|
61
|
+
return map
|
|
62
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const TIER_PACK_CONFIG = {
|
|
5
|
+
normal: { extraIgnore: [], compress: false, tokenBudget: null },
|
|
6
|
+
minimo: { extraIgnore: ['test/**', 'docs/**', '**/*.md'], compress: true, tokenBudget: null },
|
|
7
|
+
gratis: { extraIgnore: ['test/**', 'docs/**', '**/*.md'], compress: true, tokenBudget: 50000 }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function readProjectTier(cwd) {
|
|
11
|
+
for (const p of [join(cwd, '.ancleto-tier'), join(cwd, '.opencode', '.ancleto-tier')]) {
|
|
12
|
+
if (!existsSync(p)) continue
|
|
13
|
+
const v = readFileSync(p, 'utf8').trim()
|
|
14
|
+
if (v) return TIER_PACK_CONFIG[v] ? v : 'gratis'
|
|
15
|
+
}
|
|
16
|
+
return 'gratis'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function tierTokenBudget(tier) {
|
|
20
|
+
return (TIER_PACK_CONFIG[tier] || TIER_PACK_CONFIG.gratis).tokenBudget
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function buildRepomixArgs(flags, tier, exclude = []) {
|
|
24
|
+
const cfg = TIER_PACK_CONFIG[tier] || TIER_PACK_CONFIG.gratis
|
|
25
|
+
const args = []
|
|
26
|
+
const inc = flagValue(flags, '--include')
|
|
27
|
+
if (inc) args.push('--include', inc)
|
|
28
|
+
const extraIgnore = flagValue(flags, '--ignore')
|
|
29
|
+
const ignore = [...exclude, ...cfg.extraIgnore, ...(extraIgnore ? extraIgnore.split(',') : [])].filter(Boolean)
|
|
30
|
+
if (ignore.length) args.push('--ignore', ignore.join(','))
|
|
31
|
+
if (cfg.compress || flags.includes('--compress')) args.push('--compress')
|
|
32
|
+
return args
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function flagValue(args, flag) {
|
|
36
|
+
const i = args.indexOf(flag)
|
|
37
|
+
return i >= 0 && args[i + 1] ? args[i + 1] : null
|
|
38
|
+
}
|