openmoneta-dev-kit 1.9.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/README.md +103 -0
- package/agents/qa-autonomous.md +131 -0
- package/agents/requirement-analyst.md +98 -0
- package/agents/security-auditor.md +120 -0
- package/agents/ui-tester.md +186 -0
- package/bin/openmoneta.js +11 -0
- package/hooks/check-plan-exists.sh +154 -0
- package/hooks/enforce-docs-first.sh +169 -0
- package/hooks/inject-process-context.sh +117 -0
- package/hooks/track-changes.sh +46 -0
- package/hooks/verify-completion.sh +165 -0
- package/hooks.json +30 -0
- package/opencode/AGENTS.md.tpl +38 -0
- package/opencode/agents/qa-autonomous.md +42 -0
- package/opencode/agents/requirement-analyst.md +51 -0
- package/opencode/agents/security-auditor.md +46 -0
- package/opencode/agents/ui-tester.md +43 -0
- package/opencode/plugins/openmoneta-guard.ts +389 -0
- package/package.json +41 -0
- package/scripts/debug-hooks.sh +54 -0
- package/scripts/init-project.sh +438 -0
- package/scripts/list-affected-modules.sh +74 -0
- package/skills/auth-bypass-testing/SKILL.md +236 -0
- package/skills/automated-testing/SKILL.md +162 -0
- package/skills/automated-testing/scripts/install-playwright.sh +134 -0
- package/skills/module-architect/SKILL.md +256 -0
- package/skills/plan-writer/SKILL.md +229 -0
- package/skills/requirement-analysis/SKILL.md +163 -0
- package/skills/safe-push/SKILL.md +182 -0
- package/skills/security-checklist/SKILL.md +116 -0
- package/skills/test-strategy/SKILL.md +135 -0
- package/skills/ui-test-loop/SKILL.md +161 -0
- package/src/cli.js +63 -0
- package/src/commands/check.js +30 -0
- package/src/commands/init.js +43 -0
- package/src/commands/install.js +50 -0
- package/src/commands/uninstall.js +74 -0
- package/src/commands/update.js +81 -0
- package/src/lib/paths.js +46 -0
- package/src/lib/version.js +45 -0
- package/templates/AGENTS.md.tpl +106 -0
- package/templates/docs-INDEX.md.tpl +62 -0
- package/templates/env.test.tpl +16 -0
- package/templates/karpathy-reference.md +49 -0
- package/templates/plans-INDEX.md.tpl +38 -0
- package/templates/playwright.config.ts.tpl +44 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# debug-hooks.sh — kiểm tra nhanh trạng thái hooks OpenMoneta trong 1 project.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bash ~/.cursor/scripts/debug-hooks.sh /path/to/project
|
|
6
|
+
# bash ~/.cursor/scripts/debug-hooks.sh . # default
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
PROJECT="${1:-$(pwd)}"
|
|
11
|
+
if [[ -d "$PROJECT" ]]; then
|
|
12
|
+
PROJECT="$(cd "$PROJECT" && pwd -P)"
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
MARKER="$PROJECT/.cursor/.docs-index-read"
|
|
16
|
+
CHANGES="$PROJECT/.cursor/.session-changes.json"
|
|
17
|
+
INDEX="$PROJECT/docs/INDEX.md"
|
|
18
|
+
|
|
19
|
+
echo "OpenMoneta Hook Debug"
|
|
20
|
+
echo "====================="
|
|
21
|
+
echo "Project: $PROJECT"
|
|
22
|
+
echo "Version: $(cat "$HOME/.cursor/.openmoneta-version" 2>/dev/null || echo "unknown")"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
echo "Project files:"
|
|
26
|
+
[[ -f "$INDEX" ]] && echo " OK docs/INDEX.md: $INDEX" || echo " MISSING docs/INDEX.md: $INDEX"
|
|
27
|
+
[[ -d "$PROJECT/plans" ]] && echo " OK plans/: $PROJECT/plans" || echo " MISSING plans/: $PROJECT/plans"
|
|
28
|
+
echo ""
|
|
29
|
+
|
|
30
|
+
echo "Session markers:"
|
|
31
|
+
[[ -f "$MARKER" ]] && echo " OK docs marker exists: $MARKER" || echo " MISSING docs marker: $MARKER"
|
|
32
|
+
[[ -f "$CHANGES" ]] && echo " OK session changes: $CHANGES" || echo " MISSING session changes: $CHANGES"
|
|
33
|
+
echo ""
|
|
34
|
+
|
|
35
|
+
echo "Installed hooks:"
|
|
36
|
+
for hook in inject-process-context.sh check-plan-exists.sh enforce-docs-first.sh track-changes.sh verify-completion.sh; do
|
|
37
|
+
path="$HOME/.cursor/hooks/$hook"
|
|
38
|
+
if [[ -x "$path" ]]; then
|
|
39
|
+
echo " OK executable: $path"
|
|
40
|
+
elif [[ -f "$path" ]]; then
|
|
41
|
+
echo " WARN not executable: $path"
|
|
42
|
+
else
|
|
43
|
+
echo " MISSING: $path"
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
echo ""
|
|
47
|
+
|
|
48
|
+
echo "Quick enforce-docs-first check:"
|
|
49
|
+
if [[ -f "$HOME/.cursor/hooks/enforce-docs-first.sh" ]]; then
|
|
50
|
+
printf '{"workspace_roots":["%s"],"tool_name":"Read","tool_input":{"file_path":"%s/src/example.ts"}}\n' "$PROJECT" "$PROJECT" \
|
|
51
|
+
| bash "$HOME/.cursor/hooks/enforce-docs-first.sh"
|
|
52
|
+
else
|
|
53
|
+
echo " Cannot run: enforce-docs-first.sh missing"
|
|
54
|
+
fi
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# init-project.sh — Khởi tạo cấu trúc OpenMoneta Dev Kit cho 1 project (v1.7.x Lean Mode).
|
|
3
|
+
#
|
|
4
|
+
# IDEMPOTENT: chạy nhiều lần sẽ re-sync file managed và giữ các block riêng của project.
|
|
5
|
+
#
|
|
6
|
+
# v1.7.x chỉ tạo 4 file thiết yếu cho AI navigation:
|
|
7
|
+
# - AGENTS.md — quy trình 6 bước
|
|
8
|
+
# - docs/INDEX.md — entry point + Token Routing
|
|
9
|
+
# - plans/INDEX.md — bảng theo dõi plans
|
|
10
|
+
# - .gitignore — patterns chuẩn
|
|
11
|
+
#
|
|
12
|
+
# Các file/folder khác (tests/, .env.test, docs/architecture, CHANGELOG, ...) chỉ tạo khi user yêu cầu cụ thể (on-demand skills).
|
|
13
|
+
#
|
|
14
|
+
# Usage: bash ~/.cursor/scripts/init-project.sh [project-path]
|
|
15
|
+
# (default: pwd)
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
PROJECT_DIR="${1:-$(pwd)}"
|
|
20
|
+
PROJECT_DIR="$(cd "$PROJECT_DIR" 2>/dev/null && pwd || echo "$PROJECT_DIR")"
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd || pwd)"
|
|
22
|
+
SCRIPT_HOME="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd || echo "")"
|
|
23
|
+
|
|
24
|
+
if [[ ! -d "$PROJECT_DIR" ]]; then
|
|
25
|
+
echo "[!] Project dir không tồn tại: $PROJECT_DIR" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
OPENMONETA_HOME="${OPENMONETA_HOME:-}"
|
|
30
|
+
if [[ -z "$OPENMONETA_HOME" ]]; then
|
|
31
|
+
if [[ -n "$SCRIPT_HOME" && -d "$SCRIPT_HOME/templates" ]]; then
|
|
32
|
+
OPENMONETA_HOME="$SCRIPT_HOME"
|
|
33
|
+
elif [[ -d "$HOME/.cursor/templates" ]]; then
|
|
34
|
+
OPENMONETA_HOME="$HOME/.cursor"
|
|
35
|
+
elif [[ -d "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/templates" ]]; then
|
|
36
|
+
OPENMONETA_HOME="${XDG_CONFIG_HOME:-$HOME/.config}/opencode"
|
|
37
|
+
else
|
|
38
|
+
OPENMONETA_HOME="$HOME/.cursor"
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
TEMPLATES="$OPENMONETA_HOME/templates"
|
|
43
|
+
if [[ ! -d "$TEMPLATES" ]]; then
|
|
44
|
+
echo "[!] Templates dir không tồn tại: $TEMPLATES" >&2
|
|
45
|
+
echo " Cài Cursor: bash install.sh" >&2
|
|
46
|
+
echo " Cài OpenCode: bash install-opencode.sh" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
KIT_VERSION=$(cat "$OPENMONETA_HOME/.openmoneta-version" 2>/dev/null || echo "1.7.x")
|
|
50
|
+
|
|
51
|
+
echo "==> Init OpenMoneta Dev Kit (Lean Mode v$KIT_VERSION) cho: $PROJECT_DIR"
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
cd "$PROJECT_DIR"
|
|
55
|
+
|
|
56
|
+
CREATED=()
|
|
57
|
+
UPDATED=()
|
|
58
|
+
SKIPPED=()
|
|
59
|
+
BACKUPS=()
|
|
60
|
+
SYNC_BACKUP_DIR=""
|
|
61
|
+
|
|
62
|
+
ensure_dir() {
|
|
63
|
+
local dir="$1"
|
|
64
|
+
if [[ ! -d "$dir" ]]; then
|
|
65
|
+
mkdir -p "$dir"
|
|
66
|
+
CREATED+=("dir: $dir/")
|
|
67
|
+
fi
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
copy_if_missing() {
|
|
71
|
+
local src="$1"
|
|
72
|
+
local dst="$2"
|
|
73
|
+
if [[ -f "$dst" ]]; then
|
|
74
|
+
SKIPPED+=("file: $dst (đã tồn tại)")
|
|
75
|
+
return
|
|
76
|
+
fi
|
|
77
|
+
cp "$src" "$dst"
|
|
78
|
+
CREATED+=("file: $dst")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ensure_sync_backup_dir() {
|
|
82
|
+
if [[ -z "$SYNC_BACKUP_DIR" ]]; then
|
|
83
|
+
SYNC_BACKUP_DIR=".cursor/backups/init-sync-$(date +%Y%m%d-%H%M%S)"
|
|
84
|
+
mkdir -p "$SYNC_BACKUP_DIR"
|
|
85
|
+
fi
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
backup_before_sync() {
|
|
89
|
+
local dst="$1"
|
|
90
|
+
ensure_sync_backup_dir
|
|
91
|
+
local safe_name
|
|
92
|
+
safe_name="${dst//\//__}"
|
|
93
|
+
cp -p "$dst" "$SYNC_BACKUP_DIR/$safe_name"
|
|
94
|
+
BACKUPS+=("$dst -> $SYNC_BACKUP_DIR/$safe_name")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
extract_block() {
|
|
98
|
+
local src="$1"
|
|
99
|
+
local block="$2"
|
|
100
|
+
local out="$3"
|
|
101
|
+
local begin="<!-- BEGIN $block -->"
|
|
102
|
+
local end="<!-- END $block -->"
|
|
103
|
+
|
|
104
|
+
awk -v begin="$begin" -v end="$end" '
|
|
105
|
+
$0 == begin { in_block = 1; found_begin = 1; next }
|
|
106
|
+
$0 == end {
|
|
107
|
+
if (in_block) { found_end = 1 }
|
|
108
|
+
in_block = 0
|
|
109
|
+
next
|
|
110
|
+
}
|
|
111
|
+
in_block { print }
|
|
112
|
+
END { exit(found_begin && found_end ? 0 : 1) }
|
|
113
|
+
' "$src" > "$out"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
extract_section_body() {
|
|
117
|
+
local src="$1"
|
|
118
|
+
local heading="$2"
|
|
119
|
+
local out="$3"
|
|
120
|
+
|
|
121
|
+
awk -v heading="$heading" '
|
|
122
|
+
$0 == heading { in_section = 1; found = 1; next }
|
|
123
|
+
in_section && /^##[[:space:]]/ { exit }
|
|
124
|
+
in_section { print }
|
|
125
|
+
END { exit(found ? 0 : 1) }
|
|
126
|
+
' "$src" > "$out"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
extract_between_sections() {
|
|
130
|
+
local src="$1"
|
|
131
|
+
local start_heading="$2"
|
|
132
|
+
local stop_heading="$3"
|
|
133
|
+
local out="$4"
|
|
134
|
+
|
|
135
|
+
awk -v start_heading="$start_heading" -v stop_heading="$stop_heading" '
|
|
136
|
+
$0 == start_heading { in_range = 1; found = 1; print; next }
|
|
137
|
+
in_range && $0 == stop_heading { exit }
|
|
138
|
+
in_range { print }
|
|
139
|
+
END { exit(found ? 0 : 1) }
|
|
140
|
+
' "$src" > "$out"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
extract_section_table() {
|
|
144
|
+
local src="$1"
|
|
145
|
+
local heading="$2"
|
|
146
|
+
local out="$3"
|
|
147
|
+
|
|
148
|
+
awk -v heading="$heading" '
|
|
149
|
+
$0 == heading { in_section = 1; next }
|
|
150
|
+
in_section && /^##[[:space:]]/ { exit }
|
|
151
|
+
in_section && /^\|/ {
|
|
152
|
+
if (pending_blank) {
|
|
153
|
+
print ""
|
|
154
|
+
pending_blank = 0
|
|
155
|
+
}
|
|
156
|
+
found = 1
|
|
157
|
+
print
|
|
158
|
+
next
|
|
159
|
+
}
|
|
160
|
+
in_section && found && /^[[:space:]]*$/ {
|
|
161
|
+
pending_blank = 1
|
|
162
|
+
next
|
|
163
|
+
}
|
|
164
|
+
END { exit(found ? 0 : 1) }
|
|
165
|
+
' "$src" > "$out"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
replace_block() {
|
|
169
|
+
local target="$1"
|
|
170
|
+
local block="$2"
|
|
171
|
+
local content_file="$3"
|
|
172
|
+
local tmp
|
|
173
|
+
tmp=$(mktemp)
|
|
174
|
+
|
|
175
|
+
local begin="<!-- BEGIN $block -->"
|
|
176
|
+
local end="<!-- END $block -->"
|
|
177
|
+
|
|
178
|
+
awk -v begin="$begin" -v end="$end" -v content_file="$content_file" '
|
|
179
|
+
$0 == begin {
|
|
180
|
+
print
|
|
181
|
+
while ((getline line < content_file) > 0) {
|
|
182
|
+
print line
|
|
183
|
+
}
|
|
184
|
+
close(content_file)
|
|
185
|
+
in_block = 1
|
|
186
|
+
next
|
|
187
|
+
}
|
|
188
|
+
$0 == end {
|
|
189
|
+
in_block = 0
|
|
190
|
+
print
|
|
191
|
+
next
|
|
192
|
+
}
|
|
193
|
+
!in_block { print }
|
|
194
|
+
' "$target" > "$tmp"
|
|
195
|
+
|
|
196
|
+
mv "$tmp" "$target"
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
sync_agents_md() {
|
|
200
|
+
local src="$TEMPLATES/AGENTS.md.tpl"
|
|
201
|
+
local dst="AGENTS.md"
|
|
202
|
+
|
|
203
|
+
if [[ ! -f "$dst" ]]; then
|
|
204
|
+
cp "$src" "$dst"
|
|
205
|
+
CREATED+=("file: $dst")
|
|
206
|
+
return
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
local rendered override
|
|
210
|
+
rendered=$(mktemp)
|
|
211
|
+
override=$(mktemp)
|
|
212
|
+
cp "$src" "$rendered"
|
|
213
|
+
|
|
214
|
+
if ! extract_block "$dst" "PROJECT OVERRIDE" "$override"; then
|
|
215
|
+
{
|
|
216
|
+
echo "<!-- Nội dung AGENTS.md cũ được giữ lại khi migrate sang managed sync. Hãy review và rút gọn nếu cần. -->"
|
|
217
|
+
echo ""
|
|
218
|
+
cat "$dst"
|
|
219
|
+
} > "$override"
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
replace_block "$rendered" "PROJECT OVERRIDE" "$override"
|
|
223
|
+
|
|
224
|
+
if cmp -s "$rendered" "$dst"; then
|
|
225
|
+
SKIPPED+=("file: $dst (đã sync, không đổi)")
|
|
226
|
+
rm -f "$rendered" "$override"
|
|
227
|
+
return
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
backup_before_sync "$dst"
|
|
231
|
+
mv "$rendered" "$dst"
|
|
232
|
+
rm -f "$override"
|
|
233
|
+
UPDATED+=("sync: $dst (giữ PROJECT OVERRIDE)")
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
sync_docs_index() {
|
|
237
|
+
local src="$TEMPLATES/docs-INDEX.md.tpl"
|
|
238
|
+
local dst="docs/INDEX.md"
|
|
239
|
+
|
|
240
|
+
if [[ ! -f "$dst" ]]; then
|
|
241
|
+
cp "$src" "$dst"
|
|
242
|
+
CREATED+=("file: $dst")
|
|
243
|
+
return
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
local rendered content
|
|
247
|
+
rendered=$(mktemp)
|
|
248
|
+
cp "$src" "$rendered"
|
|
249
|
+
|
|
250
|
+
content=$(mktemp)
|
|
251
|
+
if extract_block "$dst" "PROJECT DOC STRUCTURE" "$content" || extract_section_body "$dst" "## Cấu trúc tài liệu" "$content"; then
|
|
252
|
+
replace_block "$rendered" "PROJECT DOC STRUCTURE" "$content"
|
|
253
|
+
fi
|
|
254
|
+
rm -f "$content"
|
|
255
|
+
|
|
256
|
+
content=$(mktemp)
|
|
257
|
+
if extract_block "$dst" "PROJECT MODULES" "$content" || extract_section_body "$dst" "## Modules hiện có" "$content"; then
|
|
258
|
+
replace_block "$rendered" "PROJECT MODULES" "$content"
|
|
259
|
+
fi
|
|
260
|
+
rm -f "$content"
|
|
261
|
+
|
|
262
|
+
content=$(mktemp)
|
|
263
|
+
if extract_block "$dst" "PROJECT TOKEN ROUTING" "$content" || extract_section_body "$dst" "## Feature / Keyword → Module (Token Routing)" "$content"; then
|
|
264
|
+
replace_block "$rendered" "PROJECT TOKEN ROUTING" "$content"
|
|
265
|
+
fi
|
|
266
|
+
rm -f "$content"
|
|
267
|
+
|
|
268
|
+
content=$(mktemp)
|
|
269
|
+
if extract_block "$dst" "PROJECT DOCS NOTES" "$content" || extract_section_body "$dst" "## Ghi chú riêng của dự án" "$content"; then
|
|
270
|
+
replace_block "$rendered" "PROJECT DOCS NOTES" "$content"
|
|
271
|
+
fi
|
|
272
|
+
rm -f "$content"
|
|
273
|
+
|
|
274
|
+
if cmp -s "$rendered" "$dst"; then
|
|
275
|
+
SKIPPED+=("file: $dst (đã sync, không đổi)")
|
|
276
|
+
rm -f "$rendered"
|
|
277
|
+
return
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
backup_before_sync "$dst"
|
|
281
|
+
mv "$rendered" "$dst"
|
|
282
|
+
UPDATED+=("sync: $dst (giữ DOC STRUCTURE / MODULES / TOKEN ROUTING / DOCS NOTES)")
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
sync_plans_index() {
|
|
286
|
+
local src="$TEMPLATES/plans-INDEX.md.tpl"
|
|
287
|
+
local dst="plans/INDEX.md"
|
|
288
|
+
|
|
289
|
+
if [[ ! -f "$dst" ]]; then
|
|
290
|
+
cp "$src" "$dst"
|
|
291
|
+
CREATED+=("file: $dst")
|
|
292
|
+
return
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
local rendered content
|
|
296
|
+
rendered=$(mktemp)
|
|
297
|
+
cp "$src" "$rendered"
|
|
298
|
+
|
|
299
|
+
content=$(mktemp)
|
|
300
|
+
if extract_block "$dst" "ACTIVE PLANS" "$content" || extract_section_body "$dst" "## Active (đang triển khai)" "$content"; then
|
|
301
|
+
replace_block "$rendered" "ACTIVE PLANS" "$content"
|
|
302
|
+
fi
|
|
303
|
+
rm -f "$content"
|
|
304
|
+
|
|
305
|
+
content=$(mktemp)
|
|
306
|
+
if extract_block "$dst" "PROJECT PLANS EXTRA" "$content" || extract_between_sections "$dst" "## Done (đã hoàn thành, chưa archive)" "## Archived" "$content"; then
|
|
307
|
+
replace_block "$rendered" "PROJECT PLANS EXTRA" "$content"
|
|
308
|
+
fi
|
|
309
|
+
rm -f "$content"
|
|
310
|
+
|
|
311
|
+
content=$(mktemp)
|
|
312
|
+
if extract_block "$dst" "ARCHIVED PLANS" "$content" || extract_section_body "$dst" "## Archived (đã Done, đã move sang plans/archive/)" "$content" || extract_section_body "$dst" "## Archived" "$content"; then
|
|
313
|
+
replace_block "$rendered" "ARCHIVED PLANS" "$content"
|
|
314
|
+
fi
|
|
315
|
+
rm -f "$content"
|
|
316
|
+
|
|
317
|
+
content=$(mktemp)
|
|
318
|
+
if extract_block "$dst" "PROJECT PLANS NOTES" "$content" || extract_section_body "$dst" "## Ghi chú riêng của dự án" "$content"; then
|
|
319
|
+
replace_block "$rendered" "PROJECT PLANS NOTES" "$content"
|
|
320
|
+
fi
|
|
321
|
+
rm -f "$content"
|
|
322
|
+
|
|
323
|
+
if cmp -s "$rendered" "$dst"; then
|
|
324
|
+
SKIPPED+=("file: $dst (đã sync, không đổi)")
|
|
325
|
+
rm -f "$rendered"
|
|
326
|
+
return
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
backup_before_sync "$dst"
|
|
330
|
+
mv "$rendered" "$dst"
|
|
331
|
+
UPDATED+=("sync: $dst (giữ ACTIVE PLANS / PLANS EXTRA / ARCHIVED PLANS / PLANS NOTES)")
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
sync_opencode_project_guard() {
|
|
335
|
+
# Guard is now global-only (~/.config/opencode/plugins/).
|
|
336
|
+
# Just clean up any old project-level plugins from pre-v1.9 migration.
|
|
337
|
+
rm -rf ".opencode/plugins" ".opencode/plugin" 2>/dev/null || true
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
# === Bước 1: Tạo cấu trúc thư mục tối thiểu ===
|
|
341
|
+
echo "==> Tạo thư mục tối thiểu..."
|
|
342
|
+
ensure_dir "docs"
|
|
343
|
+
ensure_dir "docs/modules"
|
|
344
|
+
ensure_dir "plans"
|
|
345
|
+
ensure_dir "plans/archive"
|
|
346
|
+
ensure_dir ".cursor"
|
|
347
|
+
|
|
348
|
+
# === Bước 2: Sync managed templates, giữ block riêng của project ===
|
|
349
|
+
echo "==> Sync managed templates..."
|
|
350
|
+
|
|
351
|
+
sync_agents_md
|
|
352
|
+
sync_docs_index
|
|
353
|
+
sync_plans_index
|
|
354
|
+
sync_opencode_project_guard
|
|
355
|
+
|
|
356
|
+
# === Bước 3: .gitignore với patterns chuẩn ===
|
|
357
|
+
echo "==> Update .gitignore..."
|
|
358
|
+
GITIGNORE=".gitignore"
|
|
359
|
+
PATTERNS=(
|
|
360
|
+
".cursor/.session-changes.json"
|
|
361
|
+
".cursor/.docs-index-read"
|
|
362
|
+
".cursor/.openmoneta-guard-loaded.json"
|
|
363
|
+
".cursor/.changelog-baseline"
|
|
364
|
+
".cursor/.last-test-result"
|
|
365
|
+
".cursor/.ui-session.json"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if [[ ! -f "$GITIGNORE" ]]; then
|
|
369
|
+
{
|
|
370
|
+
echo "# OpenMoneta Dev Kit"
|
|
371
|
+
printf '%s\n' "${PATTERNS[@]}"
|
|
372
|
+
} > "$GITIGNORE"
|
|
373
|
+
CREATED+=("file: .gitignore")
|
|
374
|
+
else
|
|
375
|
+
ADDED=0
|
|
376
|
+
TO_ADD=()
|
|
377
|
+
for p in "${PATTERNS[@]}"; do
|
|
378
|
+
if ! grep -qFx "$p" "$GITIGNORE"; then
|
|
379
|
+
TO_ADD+=("$p")
|
|
380
|
+
ADDED=1
|
|
381
|
+
fi
|
|
382
|
+
done
|
|
383
|
+
if [[ $ADDED -eq 1 ]]; then
|
|
384
|
+
{
|
|
385
|
+
echo ""
|
|
386
|
+
echo "# OpenMoneta Dev Kit"
|
|
387
|
+
printf '%s\n' "${TO_ADD[@]}"
|
|
388
|
+
} >> "$GITIGNORE"
|
|
389
|
+
CREATED+=("update: .gitignore (thêm ${#TO_ADD[@]} patterns)")
|
|
390
|
+
else
|
|
391
|
+
SKIPPED+=("file: .gitignore (đã có patterns)")
|
|
392
|
+
fi
|
|
393
|
+
fi
|
|
394
|
+
|
|
395
|
+
# === Báo cáo ===
|
|
396
|
+
echo ""
|
|
397
|
+
echo "================================================"
|
|
398
|
+
echo "✅ Init OpenMoneta Dev Kit (Lean Mode) hoàn tất."
|
|
399
|
+
echo "================================================"
|
|
400
|
+
echo ""
|
|
401
|
+
echo "Đã tạo (${#CREATED[@]}):"
|
|
402
|
+
if [[ ${#CREATED[@]} -gt 0 ]]; then
|
|
403
|
+
for item in "${CREATED[@]}"; do
|
|
404
|
+
echo " + $item"
|
|
405
|
+
done
|
|
406
|
+
fi
|
|
407
|
+
if [[ ${#UPDATED[@]} -gt 0 ]]; then
|
|
408
|
+
echo ""
|
|
409
|
+
echo "Đã update (${#UPDATED[@]}):"
|
|
410
|
+
for item in "${UPDATED[@]}"; do
|
|
411
|
+
echo " ~ $item"
|
|
412
|
+
done
|
|
413
|
+
fi
|
|
414
|
+
if [[ ${#BACKUPS[@]} -gt 0 ]]; then
|
|
415
|
+
echo ""
|
|
416
|
+
echo "Backup trước khi sync (${#BACKUPS[@]}):"
|
|
417
|
+
for item in "${BACKUPS[@]}"; do
|
|
418
|
+
echo " - $item"
|
|
419
|
+
done
|
|
420
|
+
fi
|
|
421
|
+
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
|
|
422
|
+
echo ""
|
|
423
|
+
echo "Đã skip (${#SKIPPED[@]}):"
|
|
424
|
+
for item in "${SKIPPED[@]}"; do
|
|
425
|
+
echo " - $item"
|
|
426
|
+
done
|
|
427
|
+
fi
|
|
428
|
+
echo ""
|
|
429
|
+
echo "Bước tiếp theo:"
|
|
430
|
+
echo " 1. Đọc AGENTS.md (quy trình 6 bước, Adaptive Planning + B6 conditional)."
|
|
431
|
+
echo " 2. Edit docs/INDEX.md → mô tả modules + cập nhật bảng Token Routing."
|
|
432
|
+
echo ""
|
|
433
|
+
echo "On-demand (chỉ khi user yêu cầu):"
|
|
434
|
+
echo " - Test (Playwright/Vitest): chạy skill 'automated-testing' khi cần."
|
|
435
|
+
echo " - Test bypass auth: chạy skill 'auth-bypass-testing' khi cần."
|
|
436
|
+
echo " - Security audit: chạy skill 'security-checklist' khi cần."
|
|
437
|
+
echo " - Architecture docs: tự tạo docs/architecture/ khi dự án lớn."
|
|
438
|
+
echo " - Project CHANGELOG: tự tạo CHANGELOG.md khi cần publish release."
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# list-affected-modules.sh — infer module slug từ .session-changes.json hoặc danh sách path.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bash list-affected-modules.sh .cursor/.session-changes.json
|
|
6
|
+
# bash list-affected-modules.sh # default .cursor/.session-changes.json
|
|
7
|
+
# echo "apps/landing/src/x.ts" | bash list-affected-modules.sh - # đọc paths từ stdin
|
|
8
|
+
#
|
|
9
|
+
# Output: 1 module slug per line (sorted, unique). Format: <slug>\t<docs_path>\t<source_path>
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
INPUT="${1:-.cursor/.session-changes.json}"
|
|
14
|
+
|
|
15
|
+
read_paths() {
|
|
16
|
+
if [[ "$INPUT" == "-" ]]; then
|
|
17
|
+
cat
|
|
18
|
+
elif [[ -f "$INPUT" ]]; then
|
|
19
|
+
if command -v jq >/dev/null 2>&1; then
|
|
20
|
+
jq -r '.changes[]?.path // empty' "$INPUT"
|
|
21
|
+
else
|
|
22
|
+
grep -oE '"path"[[:space:]]*:[[:space:]]*"[^"]+"' "$INPUT" | sed 's/.*"\([^"]*\)"$/\1/'
|
|
23
|
+
fi
|
|
24
|
+
else
|
|
25
|
+
echo "[!] Input không tồn tại: $INPUT" >&2
|
|
26
|
+
return 1
|
|
27
|
+
fi
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
infer() {
|
|
31
|
+
awk -F/ '
|
|
32
|
+
# Skip empty
|
|
33
|
+
NF == 0 { next }
|
|
34
|
+
# Whitelist không phải code module
|
|
35
|
+
/^docs\// { next }
|
|
36
|
+
/^plans\// { next }
|
|
37
|
+
/^tests\// { next }
|
|
38
|
+
/^scripts\// { next }
|
|
39
|
+
/^infra\// { next }
|
|
40
|
+
/^logs\// { next }
|
|
41
|
+
/^\.cursor\// { next }
|
|
42
|
+
/^node_modules\// { next }
|
|
43
|
+
$0 == "AGENTS.md" { next }
|
|
44
|
+
$0 == "CHANGELOG.md" { next }
|
|
45
|
+
$0 == "README.md" { next }
|
|
46
|
+
$0 == ".gitignore" { next }
|
|
47
|
+
$0 == ".env.example" { next }
|
|
48
|
+
|
|
49
|
+
# apps/<x>/...
|
|
50
|
+
/^apps\// && NF >= 2 {
|
|
51
|
+
slug = "apps-" $2
|
|
52
|
+
print slug "\tdocs/modules/" slug "\tapps/" $2
|
|
53
|
+
next
|
|
54
|
+
}
|
|
55
|
+
# packages/<x>/...
|
|
56
|
+
/^packages\// && NF >= 2 {
|
|
57
|
+
slug = "packages-" $2
|
|
58
|
+
print slug "\tdocs/modules/" slug "\tpackages/" $2
|
|
59
|
+
next
|
|
60
|
+
}
|
|
61
|
+
# src/modules/<x>/...
|
|
62
|
+
/^src\/modules\// && NF >= 3 {
|
|
63
|
+
print $3 "\tdocs/modules/" $3 "\tsrc/modules/" $3
|
|
64
|
+
next
|
|
65
|
+
}
|
|
66
|
+
# src/<x>/... (single-repo, không có modules/)
|
|
67
|
+
/^src\// && NF >= 2 && $2 != "modules" {
|
|
68
|
+
print $2 "\tdocs/modules/" $2 "\tsrc/" $2
|
|
69
|
+
next
|
|
70
|
+
}
|
|
71
|
+
' | sort -u
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
read_paths | infer
|