openmoneta-dev-kit 1.12.0 → 1.13.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.
- package/VERSION +1 -1
- package/hooks/inject-process-context.sh +18 -0
- package/opencode/plugins/openmoneta-guard.ts +31 -1
- package/package.json +1 -1
- package/skills/docs-maintenance/SKILL.md +5 -5
- package/src/commands/update.js +115 -2
- package/update.ps1 +53 -0
- package/update.sh +65 -8
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.13.0
|
|
@@ -10,12 +10,30 @@ set -euo pipefail
|
|
|
10
10
|
|
|
11
11
|
INPUT_JSON=$(cat 2>/dev/null || echo '{}')
|
|
12
12
|
|
|
13
|
+
# Auto-register project vào Cursor registry (seed cho `update --all-projects`).
|
|
14
|
+
# Im lặng. Chỉ append khi: workspace có docs/INDEX.md, Cursor install home đã cài,
|
|
15
|
+
# và path chưa có trong registry (dedup, chuẩn hoá pwd -P).
|
|
16
|
+
register_project_cursor() {
|
|
17
|
+
local ws="$1"
|
|
18
|
+
[[ -n "$ws" && -f "$ws/docs/INDEX.md" ]] || return 0
|
|
19
|
+
[[ -f "$HOME/.cursor/.openmoneta-version" ]] || return 0
|
|
20
|
+
local reg="$HOME/.cursor/.openmoneta-projects"
|
|
21
|
+
local abs
|
|
22
|
+
abs="$(cd "$ws" 2>/dev/null && pwd -P)" || return 0
|
|
23
|
+
[[ -n "$abs" ]] || return 0
|
|
24
|
+
if [[ -f "$reg" ]] && grep -qFx "$abs" "$reg" 2>/dev/null; then
|
|
25
|
+
return 0
|
|
26
|
+
fi
|
|
27
|
+
echo "$abs" >> "$reg" 2>/dev/null || true
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
# Reset docs-index marker mỗi session (force re-read INDEX.md)
|
|
14
31
|
if command -v jq >/dev/null 2>&1; then
|
|
15
32
|
WORKSPACE_FROM_INPUT=$(echo "$INPUT_JSON" | jq -r '.workspace_roots[0] // ""' 2>/dev/null || echo "")
|
|
16
33
|
if [[ -n "$WORKSPACE_FROM_INPUT" && -d "$WORKSPACE_FROM_INPUT/.cursor" ]]; then
|
|
17
34
|
rm -f "$WORKSPACE_FROM_INPUT/.cursor/.docs-index-read" 2>/dev/null || true
|
|
18
35
|
fi
|
|
36
|
+
register_project_cursor "$WORKSPACE_FROM_INPUT" 2>/dev/null || true
|
|
19
37
|
fi
|
|
20
38
|
|
|
21
39
|
# === Summary 6 bước (~45 dòng, ~650 tokens) ===
|
|
@@ -400,6 +400,33 @@ function clearVerifyLoop(root: string) {
|
|
|
400
400
|
fs.rmSync(path.join(root, ".cursor", ".openmoneta-verify-loop.json"), { force: true })
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
// Auto-register project vào OpenCode registry (seed cho `update --all-projects`).
|
|
404
|
+
// Im lặng + try/catch — seed không được phép làm fail guard. Chỉ append khi:
|
|
405
|
+
// project có docs/INDEX.md, OpenCode install home đã cài, path chưa có trong registry.
|
|
406
|
+
function registerProjectOpenCode(root: string) {
|
|
407
|
+
try {
|
|
408
|
+
if (!fs.existsSync(path.join(root, "docs", "INDEX.md"))) return
|
|
409
|
+
const home = process.env.HOME || process.env.USERPROFILE || ""
|
|
410
|
+
const xdg = process.env.XDG_CONFIG_HOME || path.join(home, ".config")
|
|
411
|
+
const ocHome = path.join(xdg, "opencode")
|
|
412
|
+
if (!fs.existsSync(path.join(ocHome, ".openmoneta-version"))) return
|
|
413
|
+
const reg = path.join(ocHome, ".openmoneta-projects")
|
|
414
|
+
const abs = fs.realpathSync(root)
|
|
415
|
+
let lines: string[] = []
|
|
416
|
+
if (fs.existsSync(reg)) {
|
|
417
|
+
lines = fs
|
|
418
|
+
.readFileSync(reg, "utf8")
|
|
419
|
+
.split("\n")
|
|
420
|
+
.map((l) => l.trim())
|
|
421
|
+
.filter(Boolean)
|
|
422
|
+
}
|
|
423
|
+
if (lines.includes(abs)) return
|
|
424
|
+
fs.appendFileSync(reg, `${abs}\n`)
|
|
425
|
+
} catch {
|
|
426
|
+
// im lặng
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
403
430
|
type SessionPromptClient = {
|
|
404
431
|
session?: {
|
|
405
432
|
prompt?: (input: {
|
|
@@ -434,7 +461,7 @@ export const OpenMonetaGuard = async (ctx: GuardContext) => {
|
|
|
434
461
|
{
|
|
435
462
|
loaded_at: new Date().toISOString(),
|
|
436
463
|
root,
|
|
437
|
-
version: "1.
|
|
464
|
+
version: "1.13.0",
|
|
438
465
|
load_count: globalState[globalKey],
|
|
439
466
|
},
|
|
440
467
|
null,
|
|
@@ -442,6 +469,9 @@ export const OpenMonetaGuard = async (ctx: GuardContext) => {
|
|
|
442
469
|
)}\n`,
|
|
443
470
|
)
|
|
444
471
|
|
|
472
|
+
// Seed project vào OpenCode registry để `update --all-projects` thấy project này.
|
|
473
|
+
registerProjectOpenCode(root)
|
|
474
|
+
|
|
445
475
|
// OpenCode does not have Cursor's sessionStart hook, so reset the docs-first
|
|
446
476
|
// marker when the plugin is loaded for a new OpenCode process/session.
|
|
447
477
|
if (fs.existsSync(marker)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openmoneta-dev-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "OpenMoneta Dev Kit — Biến Cursor IDE / OpenCode thành team developer hoàn chỉnh với quy trình 6 bước, adaptive planning, hooks enforcement, và token-aware doc routing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursor",
|
|
@@ -42,14 +42,14 @@ Stale docs còn tệ hơn không có docs — session sau AI đọc sai, làm sa
|
|
|
42
42
|
|
|
43
43
|
## Workflow
|
|
44
44
|
|
|
45
|
-
### 1. Lấy danh sách (deterministic)
|
|
45
|
+
### 1. Lấy danh sách + soi ghost (deterministic)
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
bash ~/.cursor/scripts/docs-audit.sh --worklist
|
|
49
|
-
#
|
|
48
|
+
bash ~/.cursor/scripts/docs-audit.sh --worklist # MISSING/STALE/ok (TSV: slug\tdocs\tsource\tstatus)
|
|
49
|
+
bash ~/.cursor/scripts/docs-audit.sh --validate # liệt kê GHOST (doc/INDEX trỏ source/module đã mất)
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
(OpenCode: `~/.config/opencode/scripts/docs-audit.sh`.) Mode `audit`
|
|
52
|
+
(OpenCode: `~/.config/opencode/scripts/docs-audit.sh`.) **BẮT BUỘC chạy cả `--validate`** ở mọi mode để không bỏ sót ghost. Mode `audit` in cả 2 kết quả rồi dừng, không qua các bước tạo/sửa dưới.
|
|
53
53
|
|
|
54
54
|
### 2. (Repo lớn) đọc song song
|
|
55
55
|
|
|
@@ -75,7 +75,7 @@ Cho mỗi module status `stale`:
|
|
|
75
75
|
### 5. Sync `docs/INDEX.md`
|
|
76
76
|
|
|
77
77
|
- Module mới → thêm dòng vào bảng "Modules hiện có" + **3-5 keyword (VN+EN)** vào bảng "Token Routing" (bắt buộc, để hook docs-first + token-aware reading hoạt động).
|
|
78
|
-
- GHOST →
|
|
78
|
+
- **GHOST** (từ `--validate` ở Bước 1) → LIỆT KÊ rõ từng ghost cho user. **KHÔNG tự xóa** — map slug→source là heuristic, có thể là module vừa đổi tên/di chuyển. Hỏi user bằng `AskQuestion` (xóa doc/dòng INDEX, hay map lại sang source mới); chỉ thao tác sau khi user xác nhận từng cái.
|
|
79
79
|
|
|
80
80
|
### 6. Report cuối
|
|
81
81
|
|
package/src/commands/update.js
CHANGED
|
@@ -57,6 +57,104 @@ function pruneRegistry() {
|
|
|
57
57
|
return pruned
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
const SCAN_PRUNE_DIRS = new Set([
|
|
61
|
+
"node_modules",
|
|
62
|
+
".git",
|
|
63
|
+
"Library",
|
|
64
|
+
".Trash",
|
|
65
|
+
".cache",
|
|
66
|
+
".npm",
|
|
67
|
+
".cargo",
|
|
68
|
+
".gradle",
|
|
69
|
+
".venv",
|
|
70
|
+
"dist",
|
|
71
|
+
"build",
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
function findProjects(root, maxDepth) {
|
|
75
|
+
const out = []
|
|
76
|
+
function walk(dir, depth) {
|
|
77
|
+
if (depth > maxDepth) return
|
|
78
|
+
if (isOpenmonetaProject(dir)) {
|
|
79
|
+
try {
|
|
80
|
+
fs.accessSync(path.join(dir, "AGENTS.md"))
|
|
81
|
+
out.push(dir)
|
|
82
|
+
} catch {
|
|
83
|
+
// thiếu AGENTS.md → không tính là OM project khi scan
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let entries
|
|
87
|
+
try {
|
|
88
|
+
entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
89
|
+
} catch {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
for (const e of entries) {
|
|
93
|
+
if (!e.isDirectory()) continue
|
|
94
|
+
if (SCAN_PRUNE_DIRS.has(e.name) || e.name.startsWith(".")) continue
|
|
95
|
+
walk(path.join(dir, e.name), depth + 1)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
walk(root, 0)
|
|
99
|
+
return out
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function scanSeed(root, pkgRoot) {
|
|
103
|
+
let absRoot
|
|
104
|
+
try {
|
|
105
|
+
absRoot = fs.realpathSync(root)
|
|
106
|
+
} catch {
|
|
107
|
+
console.log(` [!] Scan root không tồn tại: ${root}`)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
const targets = ["cursor", "opencode"].filter((t) => isInstalled(t))
|
|
111
|
+
if (targets.length === 0) {
|
|
112
|
+
console.log(` [!] Chưa có install home nào để seed registry.`)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
let kitRoot
|
|
116
|
+
try {
|
|
117
|
+
kitRoot = fs.realpathSync(pkgRoot)
|
|
118
|
+
} catch {
|
|
119
|
+
kitRoot = pkgRoot
|
|
120
|
+
}
|
|
121
|
+
const uniq = [
|
|
122
|
+
...new Set(
|
|
123
|
+
findProjects(absRoot, 5)
|
|
124
|
+
.map((p) => {
|
|
125
|
+
try {
|
|
126
|
+
return fs.realpathSync(p)
|
|
127
|
+
} catch {
|
|
128
|
+
return p
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
.filter((p) => p !== kitRoot)
|
|
132
|
+
),
|
|
133
|
+
]
|
|
134
|
+
let seeded = 0
|
|
135
|
+
for (const t of targets) {
|
|
136
|
+
const reg = getProjectRegistry(t)
|
|
137
|
+
let existing = new Set()
|
|
138
|
+
try {
|
|
139
|
+
existing = new Set(
|
|
140
|
+
fs
|
|
141
|
+
.readFileSync(reg, "utf8")
|
|
142
|
+
.split("\n")
|
|
143
|
+
.map((l) => l.trim())
|
|
144
|
+
.filter(Boolean)
|
|
145
|
+
)
|
|
146
|
+
} catch {
|
|
147
|
+
// registry chưa tồn tại → tạo mới khi append
|
|
148
|
+
}
|
|
149
|
+
const toAdd = uniq.filter((p) => !existing.has(p))
|
|
150
|
+
if (toAdd.length) {
|
|
151
|
+
fs.appendFileSync(reg, toAdd.map((p) => `${p}\n`).join(""))
|
|
152
|
+
seeded += toAdd.length
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
console.log(` Scan: thấy ${uniq.length} OM project, seed ${seeded} entry mới.`)
|
|
156
|
+
}
|
|
157
|
+
|
|
60
158
|
function syncProject(initScript, dir) {
|
|
61
159
|
if (isWindows()) {
|
|
62
160
|
execSync(`bash "${initScript}" "${dir}"`, { stdio: "inherit", shell: true })
|
|
@@ -69,7 +167,14 @@ async function run(args) {
|
|
|
69
167
|
const checkOnly = args.includes("--check")
|
|
70
168
|
const autoYes = args.includes("--yes") || args.includes("-y")
|
|
71
169
|
const skipProjects = args.includes("--skip-projects")
|
|
72
|
-
const
|
|
170
|
+
const scanIdx = args.indexOf("--scan")
|
|
171
|
+
const scan = scanIdx !== -1
|
|
172
|
+
let scanRoot = process.env.HOME || process.env.USERPROFILE || "."
|
|
173
|
+
if (scan) {
|
|
174
|
+
const next = args[scanIdx + 1]
|
|
175
|
+
if (next && !next.startsWith("-")) scanRoot = next
|
|
176
|
+
}
|
|
177
|
+
const allProjects = args.includes("--all-projects") || scan
|
|
73
178
|
const force = args.includes("--force")
|
|
74
179
|
|
|
75
180
|
const local = getLocalVersion()
|
|
@@ -140,6 +245,11 @@ async function run(args) {
|
|
|
140
245
|
const initScript = path.join(pkgRoot, "scripts", "init-project.sh")
|
|
141
246
|
const cwd = process.cwd()
|
|
142
247
|
|
|
248
|
+
if (scan) {
|
|
249
|
+
console.log(`\n ▶ --scan: dò OM project để seed registry...`)
|
|
250
|
+
scanSeed(scanRoot, pkgRoot)
|
|
251
|
+
}
|
|
252
|
+
|
|
143
253
|
if (allProjects) {
|
|
144
254
|
const pruned = pruneRegistry()
|
|
145
255
|
if (pruned > 0) console.log(`\n ℹ Registry: prune ${pruned} entry chết.`)
|
|
@@ -196,4 +306,7 @@ async function run(args) {
|
|
|
196
306
|
console.log(`\n 🎉 Hoàn tất. Restart Cursor/OpenCode để áp dụng.`)
|
|
197
307
|
}
|
|
198
308
|
|
|
199
|
-
module.exports = {
|
|
309
|
+
module.exports = {
|
|
310
|
+
run,
|
|
311
|
+
_internal: { isOpenmonetaProject, readRegistry, pruneRegistry, findProjects, scanSeed },
|
|
312
|
+
}
|
package/update.ps1
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
# .\update.ps1 -Check # chỉ check, không cài
|
|
8
8
|
# .\update.ps1 -Project C:\path # global + sync thêm project chỉ định
|
|
9
9
|
# .\update.ps1 -AllProjects # global + sync MỌI project trong registry
|
|
10
|
+
# .\update.ps1 -Scan [-ScanRoot path] # dò OM project (mặc định $HOME) → seed registry → sync all
|
|
10
11
|
# .\update.ps1 -SkipProjects # global only (old behavior)
|
|
11
12
|
|
|
12
13
|
param(
|
|
@@ -15,6 +16,8 @@ param(
|
|
|
15
16
|
[switch]$Check,
|
|
16
17
|
[switch]$SkipProjects,
|
|
17
18
|
[switch]$AllProjects,
|
|
19
|
+
[switch]$Scan,
|
|
20
|
+
[string]$ScanRoot,
|
|
18
21
|
[string[]]$Project
|
|
19
22
|
)
|
|
20
23
|
|
|
@@ -124,6 +127,49 @@ function Invoke-PruneRegistry {
|
|
|
124
127
|
return $pruned
|
|
125
128
|
}
|
|
126
129
|
|
|
130
|
+
# Helper: scan tìm OM project (docs\INDEX.md + AGENTS.md) → seed registry mỗi home tồn tại
|
|
131
|
+
function Invoke-ScanSeed {
|
|
132
|
+
$root = if ($ScanRoot) { $ScanRoot } else { $env:USERPROFILE }
|
|
133
|
+
$absRoot = (Resolve-Path $root -ErrorAction SilentlyContinue).Path
|
|
134
|
+
if (-not $absRoot) { Write-Host " [!] Scan root không tồn tại: $root"; return }
|
|
135
|
+
|
|
136
|
+
$homes = @()
|
|
137
|
+
if (Test-Path (Join-Path $env:USERPROFILE ".cursor\.openmoneta-version")) {
|
|
138
|
+
$homes += (Join-Path $env:USERPROFILE ".cursor\.openmoneta-projects")
|
|
139
|
+
}
|
|
140
|
+
$ocBase = if ($env:XDG_CONFIG_HOME) { "$env:XDG_CONFIG_HOME\opencode" } else { "$env:USERPROFILE\.config\opencode" }
|
|
141
|
+
if (Test-Path (Join-Path $ocBase ".openmoneta-version")) {
|
|
142
|
+
$homes += (Join-Path $ocBase ".openmoneta-projects")
|
|
143
|
+
}
|
|
144
|
+
if ($homes.Count -eq 0) { Write-Host " [!] Chưa có install home nào để seed registry."; return }
|
|
145
|
+
|
|
146
|
+
$prune = @('node_modules', '.git', 'Library', '.Trash', '.cache', '.npm', '.cargo', '.gradle', '.venv', 'dist', 'build')
|
|
147
|
+
Write-Host " Scanning '$absRoot' (depth ~6)..."
|
|
148
|
+
$indexes = Get-ChildItem -Path $absRoot -Recurse -Depth 6 -Filter "INDEX.md" -File -ErrorAction SilentlyContinue |
|
|
149
|
+
Where-Object { (Split-Path $_.DirectoryName -Leaf) -eq "docs" }
|
|
150
|
+
|
|
151
|
+
$found = 0; $seeded = 0
|
|
152
|
+
$absKit = (Resolve-Path $RepoDir -ErrorAction SilentlyContinue).Path
|
|
153
|
+
foreach ($idx in $indexes) {
|
|
154
|
+
$proj = Split-Path (Split-Path $idx.FullName -Parent) -Parent
|
|
155
|
+
$skip = $false
|
|
156
|
+
foreach ($d in $prune) { if ($proj -like "*\$d\*" -or $proj -like "*\$d") { $skip = $true; break } }
|
|
157
|
+
if ($skip) { continue }
|
|
158
|
+
if (-not (Test-Path (Join-Path $proj "AGENTS.md"))) { continue }
|
|
159
|
+
$abs = (Resolve-Path $proj -ErrorAction SilentlyContinue).Path
|
|
160
|
+
if (-not $abs -or $abs -eq $absKit) { continue }
|
|
161
|
+
$found++
|
|
162
|
+
foreach ($reg in $homes) {
|
|
163
|
+
$existing = @()
|
|
164
|
+
if (Test-Path $reg) { $existing = Get-Content $reg | ForEach-Object { $_.Trim() } | Where-Object { $_ } }
|
|
165
|
+
if ($existing -contains $abs) { continue }
|
|
166
|
+
Add-Content -Path $reg -Value $abs
|
|
167
|
+
$seeded++
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
Write-Host " Scan: thấy $found OM project, seed $seeded entry mới vào registry."
|
|
171
|
+
}
|
|
172
|
+
|
|
127
173
|
# Helper: collect projects to sync
|
|
128
174
|
function Get-OpenMonetaProjects {
|
|
129
175
|
$found = @()
|
|
@@ -262,6 +308,13 @@ if ($SkipProjects) {
|
|
|
262
308
|
exit 0
|
|
263
309
|
}
|
|
264
310
|
|
|
311
|
+
if ($Scan) {
|
|
312
|
+
$AllProjects = $true
|
|
313
|
+
Write-Host ""
|
|
314
|
+
Write-Host "==> -Scan: dò OM project để seed registry..."
|
|
315
|
+
Invoke-ScanSeed
|
|
316
|
+
}
|
|
317
|
+
|
|
265
318
|
if ($AllProjects) {
|
|
266
319
|
Write-Host ""
|
|
267
320
|
Write-Host "==> -AllProjects: dọn registry + gom mọi project đã đăng ký..."
|
package/update.sh
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
# bash update.sh --check # chỉ check, không cài
|
|
10
10
|
# bash update.sh --project /path # global + sync thêm project chỉ định
|
|
11
11
|
# bash update.sh --all-projects # global + sync MỌI project trong registry
|
|
12
|
+
# bash update.sh --scan [root] # dò OM project (mặc định $HOME) → seed registry → sync all
|
|
12
13
|
# bash update.sh --skip-projects # global only (old behavior)
|
|
13
14
|
|
|
14
15
|
set -euo pipefail
|
|
@@ -22,31 +23,42 @@ SKIP_PROJECTS=0
|
|
|
22
23
|
FORCE=0
|
|
23
24
|
CHECK_ONLY=0
|
|
24
25
|
ALL_PROJECTS=0
|
|
26
|
+
SCAN=0
|
|
27
|
+
SCAN_ROOT=""
|
|
25
28
|
PROJECT_PATHS=()
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
case "$
|
|
30
|
+
while [[ $# -gt 0 ]]; do
|
|
31
|
+
case "$1" in
|
|
29
32
|
--yes|-y) AUTO_YES=1 ;;
|
|
30
33
|
--force) FORCE=1 ;;
|
|
31
34
|
--check) CHECK_ONLY=1 ;;
|
|
32
35
|
--all-projects) ALL_PROJECTS=1 ;;
|
|
33
36
|
--skip-projects) SKIP_PROJECTS=1 ;;
|
|
37
|
+
--scan)
|
|
38
|
+
SCAN=1
|
|
39
|
+
ALL_PROJECTS=1
|
|
40
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
41
|
+
SCAN_ROOT="$2"
|
|
42
|
+
shift
|
|
43
|
+
fi
|
|
44
|
+
;;
|
|
34
45
|
--help|-h)
|
|
35
|
-
grep '^#' "$0" | sed 's/^# \?//' | head -
|
|
46
|
+
grep '^#' "$0" | sed 's/^# \?//' | head -18
|
|
36
47
|
exit 0
|
|
37
48
|
;;
|
|
38
49
|
--project)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
51
|
+
PROJECT_PATHS+=("$2")
|
|
52
|
+
shift
|
|
42
53
|
fi
|
|
43
54
|
;;
|
|
44
55
|
*)
|
|
45
|
-
if [[ "$
|
|
46
|
-
PROJECT_PATHS+=("$
|
|
56
|
+
if [[ "$1" != -* ]]; then
|
|
57
|
+
PROJECT_PATHS+=("$1")
|
|
47
58
|
fi
|
|
48
59
|
;;
|
|
49
60
|
esac
|
|
61
|
+
shift
|
|
50
62
|
done
|
|
51
63
|
|
|
52
64
|
cd "$REPO_DIR"
|
|
@@ -146,6 +158,45 @@ prune_registry() {
|
|
|
146
158
|
return 0
|
|
147
159
|
}
|
|
148
160
|
|
|
161
|
+
# === Helper: scan tìm OM project (docs/INDEX.md + AGENTS.md) → seed registry mỗi home tồn tại ===
|
|
162
|
+
scan_seed() {
|
|
163
|
+
local root="${SCAN_ROOT:-$HOME}"
|
|
164
|
+
local abs_root
|
|
165
|
+
abs_root="$(cd "$root" 2>/dev/null && pwd -P)" || { echo " [!] Scan root không tồn tại: $root"; return 0; }
|
|
166
|
+
|
|
167
|
+
local homes=()
|
|
168
|
+
[[ -f "$HOME/.cursor/.openmoneta-version" ]] && homes+=("$HOME/.cursor/.openmoneta-projects")
|
|
169
|
+
[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-version" ]] && \
|
|
170
|
+
homes+=("${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-projects")
|
|
171
|
+
if [[ ${#homes[@]} -eq 0 ]]; then
|
|
172
|
+
echo " [!] Chưa có install home nào để seed registry."
|
|
173
|
+
return 0
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
echo " Scanning '$abs_root' (maxdepth project ~5)..."
|
|
177
|
+
local found=0 seeded=0 idx proj abs reg
|
|
178
|
+
while IFS= read -r idx; do
|
|
179
|
+
proj="$(dirname "$(dirname "$idx")")"
|
|
180
|
+
[[ -f "$proj/AGENTS.md" ]] || continue
|
|
181
|
+
abs="$(cd "$proj" 2>/dev/null && pwd -P)" || continue
|
|
182
|
+
[[ -z "$abs" || "$abs" == "$REPO_DIR" ]] && continue
|
|
183
|
+
found=$((found + 1))
|
|
184
|
+
for reg in "${homes[@]}"; do
|
|
185
|
+
if [[ -f "$reg" ]] && grep -qFx "$abs" "$reg" 2>/dev/null; then
|
|
186
|
+
continue
|
|
187
|
+
fi
|
|
188
|
+
echo "$abs" >> "$reg"
|
|
189
|
+
seeded=$((seeded + 1))
|
|
190
|
+
done
|
|
191
|
+
done < <(find "$abs_root" -maxdepth 7 \
|
|
192
|
+
\( -name node_modules -o -name .git -o -name Library -o -name .Trash \
|
|
193
|
+
-o -name .cache -o -name .npm -o -name .cargo -o -name .gradle \
|
|
194
|
+
-o -name .venv -o -name dist -o -name build \) -prune -o \
|
|
195
|
+
-type f -path '*/docs/INDEX.md' -print 2>/dev/null)
|
|
196
|
+
|
|
197
|
+
echo " Scan: thấy $found OM project, seed $seeded entry mới vào registry."
|
|
198
|
+
}
|
|
199
|
+
|
|
149
200
|
# === Helper: collect projects to sync ===
|
|
150
201
|
collect_projects() {
|
|
151
202
|
local found=()
|
|
@@ -293,6 +344,12 @@ print_registry_hint() {
|
|
|
293
344
|
return 0
|
|
294
345
|
}
|
|
295
346
|
|
|
347
|
+
if [[ $SCAN -eq 1 ]]; then
|
|
348
|
+
echo ""
|
|
349
|
+
echo "==> --scan: dò OM project để seed registry..."
|
|
350
|
+
scan_seed
|
|
351
|
+
fi
|
|
352
|
+
|
|
296
353
|
if [[ $ALL_PROJECTS -eq 1 ]]; then
|
|
297
354
|
echo ""
|
|
298
355
|
echo "==> --all-projects: dọn registry + gom mọi project đã đăng ký..."
|