context-engineer 1.1.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 +88 -0
- package/bin/cli.mjs +91 -0
- package/lib/copy.mjs +102 -0
- package/lib/init.mjs +166 -0
- package/lib/prompts.mjs +144 -0
- package/lib/update.mjs +198 -0
- package/package.json +35 -0
- package/templates/checksums.json +68 -0
- package/templates/claude/.claude/rules/context-maintenance.md +38 -0
- package/templates/claude/.claude/rules/experience-capture.md +46 -0
- package/templates/claude/.claude/settings.project.json +22 -0
- package/templates/claude/.claude/skills/bootstrap/SKILL.md +223 -0
- package/templates/claude/.claude/skills/dev/SKILL.md +119 -0
- package/templates/claude/.claude/skills/dev-capture/SKILL.md +111 -0
- package/templates/claude/.claude/skills/dev-commit/SKILL.md +90 -0
- package/templates/claude/.claude/skills/dev-decompose/SKILL.md +113 -0
- package/templates/claude/.claude/skills/dev-deps/SKILL.md +108 -0
- package/templates/claude/.claude/skills/dev-execute/SKILL.md +196 -0
- package/templates/claude/.claude/skills/dev-prd/SKILL.md +100 -0
- package/templates/claude/.claude/skills/dev-quality/SKILL.md +109 -0
- package/templates/claude/.claude/skills/dev-requirements/SKILL.md +75 -0
- package/templates/claude/.claude/skills/review-context/SKILL.md +120 -0
- package/templates/claude/.claude/skills/sync/SKILL.md +107 -0
- package/templates/claude/.claude/skills/update-context/SKILL.md +105 -0
- package/templates/claude/.claude/workflow/agents/implementer.md +65 -0
- package/templates/claude/.claude/workflow/agents/reviewer.md +96 -0
- package/templates/claude/.claude/workflow/agents/team-config.md +97 -0
- package/templates/claude/.claude/workflow/agents/tester.md +98 -0
- package/templates/claude/.claude/workflow/interfaces/phase-contract.md +157 -0
- package/templates/claude/CLAUDE.md +50 -0
- package/templates/core/.context/_meta/concepts.md +9 -0
- package/templates/core/.context/_meta/drift-report.md +16 -0
- package/templates/core/.context/_meta/last-sync.json +6 -0
- package/templates/core/.context/_meta/schema.md +242 -0
- package/templates/core/.context/architecture/api-surface.md +52 -0
- package/templates/core/.context/architecture/class-index.md +49 -0
- package/templates/core/.context/architecture/data-flow.md +103 -0
- package/templates/core/.context/architecture/data-model.md +35 -0
- package/templates/core/.context/architecture/decisions/001-template.md +35 -0
- package/templates/core/.context/architecture/dependencies.md +35 -0
- package/templates/core/.context/architecture/infrastructure.md +42 -0
- package/templates/core/.context/architecture/module-graph.md +68 -0
- package/templates/core/.context/architecture/overview.md +87 -0
- package/templates/core/.context/business/domain-model.md +43 -0
- package/templates/core/.context/business/glossary.md +23 -0
- package/templates/core/.context/business/overview.md +29 -0
- package/templates/core/.context/business/workflows.md +61 -0
- package/templates/core/.context/constitution.md +84 -0
- package/templates/core/.context/conventions/code-style.md +47 -0
- package/templates/core/.context/conventions/error-handling.md +50 -0
- package/templates/core/.context/conventions/git.md +46 -0
- package/templates/core/.context/conventions/patterns.md +41 -0
- package/templates/core/.context/conventions/testing.md +49 -0
- package/templates/core/.context/experience/debugging.md +21 -0
- package/templates/core/.context/experience/incidents.md +26 -0
- package/templates/core/.context/experience/lessons.md +23 -0
- package/templates/core/.context/experience/performance.md +29 -0
- package/templates/core/.context/index.md +93 -0
- package/templates/core/.context/progress/backlog.md +23 -0
- package/templates/core/.context/progress/status.md +30 -0
- package/templates/core/.context/workflow/artifacts/.gitkeep +0 -0
- package/templates/core/.context/workflow/config.md +35 -0
- package/templates/core/AGENTS.md +53 -0
- package/templates/core/scripts/compact-experience.sh +83 -0
- package/templates/core/scripts/detect-drift.sh +388 -0
- package/templates/core/scripts/extract-structure.sh +757 -0
- package/templates/core/scripts/sync-context.sh +510 -0
- package/templates/cursor/.cursor/rules/always.mdc +18 -0
- package/templates/cursor/.cursor/rules/backend.mdc +16 -0
- package/templates/cursor/.cursor/rules/database.mdc +16 -0
- package/templates/cursor/.cursor/rules/frontend.mdc +13 -0
- package/templates/cursor/.cursorrules +23 -0
- package/templates/github/.github/copilot-instructions.md +15 -0
- package/templates/github/.github/workflows/context-drift.yml +73 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# detect-drift.sh — Detect drift between source code and .context/ documentation
|
|
4
|
+
#
|
|
5
|
+
# Usage: bash scripts/detect-drift.sh [--report] [--ci] [--semantic]
|
|
6
|
+
# --report Save results to .context/_meta/drift-report.md
|
|
7
|
+
# --ci Exit with code 1 if drift is detected (for CI/CD)
|
|
8
|
+
# --semantic Enable entity-list comparison (compares documented names vs code)
|
|
9
|
+
#
|
|
10
|
+
# This script checks for drift between source code and context documentation.
|
|
11
|
+
# It does NOT block commits — it only reports warnings.
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
CONTEXT_DIR=".context"
|
|
16
|
+
META_DIR="$CONTEXT_DIR/_meta"
|
|
17
|
+
REPORT_FILE="$META_DIR/drift-report.md"
|
|
18
|
+
SAVE_REPORT=false
|
|
19
|
+
CI_MODE=false
|
|
20
|
+
SEMANTIC_MODE=false
|
|
21
|
+
DRIFT_COUNT=0
|
|
22
|
+
REPORT_LINES=()
|
|
23
|
+
|
|
24
|
+
# Parse arguments
|
|
25
|
+
for arg in "$@"; do
|
|
26
|
+
case $arg in
|
|
27
|
+
--report) SAVE_REPORT=true ;;
|
|
28
|
+
--ci) CI_MODE=true ;;
|
|
29
|
+
--semantic) SEMANTIC_MODE=true ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# Colors (disabled in CI)
|
|
34
|
+
if [ -t 1 ] && [ "$CI_MODE" = false ]; then
|
|
35
|
+
RED='\033[0;31m'
|
|
36
|
+
YELLOW='\033[1;33m'
|
|
37
|
+
GREEN='\033[0;32m'
|
|
38
|
+
NC='\033[0m'
|
|
39
|
+
else
|
|
40
|
+
RED='' YELLOW='' GREEN='' NC=''
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
log_ok() {
|
|
44
|
+
echo -e "${GREEN}[OK]${NC} $1"
|
|
45
|
+
REPORT_LINES+=("| $1 | OK | — |")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
log_warn() {
|
|
49
|
+
echo -e "${YELLOW}[DRIFT]${NC} $1"
|
|
50
|
+
REPORT_LINES+=("| $1 | DRIFT | $2 |")
|
|
51
|
+
DRIFT_COUNT=$((DRIFT_COUNT + 1))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
log_missing() {
|
|
55
|
+
echo -e "${RED}[MISSING]${NC} $1"
|
|
56
|
+
REPORT_LINES+=("| $1 | MISSING | File does not exist or is empty |")
|
|
57
|
+
DRIFT_COUNT=$((DRIFT_COUNT + 1))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
echo "========================================="
|
|
61
|
+
echo " Context Drift Detection"
|
|
62
|
+
echo "========================================="
|
|
63
|
+
echo ""
|
|
64
|
+
|
|
65
|
+
# Check that .context/ exists
|
|
66
|
+
if [ ! -d "$CONTEXT_DIR" ]; then
|
|
67
|
+
echo -e "${RED}ERROR: .context/ directory not found. Run bootstrap first.${NC}"
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# --- Check 1: Schema/Migration drift ---
|
|
72
|
+
echo "--- Checking Data Model Drift ---"
|
|
73
|
+
DATA_MODEL="$CONTEXT_DIR/architecture/data-model.md"
|
|
74
|
+
if [ -f "$DATA_MODEL" ]; then
|
|
75
|
+
# Check if data model file contains only placeholders
|
|
76
|
+
if grep -q "PLACEHOLDER" "$DATA_MODEL" 2>/dev/null; then
|
|
77
|
+
log_warn "architecture/data-model.md" "Contains placeholder text — not yet populated"
|
|
78
|
+
else
|
|
79
|
+
# Find any migration/model files newer than the data model doc
|
|
80
|
+
NEWER_FILES=""
|
|
81
|
+
|
|
82
|
+
# Check common migration/model patterns
|
|
83
|
+
for pattern in "**/migrations/*" "**/Migration*" "prisma/schema.prisma" "**/models.py" "**/entities/*.cs" "**/entities/*.ts" "**/models/*.ts" "**/models/*.cs"; do
|
|
84
|
+
while IFS= read -r file; do
|
|
85
|
+
if [ -n "$file" ] && [ "$file" -nt "$DATA_MODEL" ]; then
|
|
86
|
+
NEWER_FILES="$NEWER_FILES $file"
|
|
87
|
+
fi
|
|
88
|
+
done < <(find . -path "./.git" -prune -o -path "$pattern" -print 2>/dev/null || true)
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
if [ -n "$NEWER_FILES" ]; then
|
|
92
|
+
log_warn "architecture/data-model.md" "Source files modified after last update:${NEWER_FILES}"
|
|
93
|
+
else
|
|
94
|
+
log_ok "architecture/data-model.md"
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
log_missing "architecture/data-model.md"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# --- Check 2: API Surface drift ---
|
|
102
|
+
echo "--- Checking API Surface Drift ---"
|
|
103
|
+
API_SURFACE="$CONTEXT_DIR/architecture/api-surface.md"
|
|
104
|
+
if [ -f "$API_SURFACE" ]; then
|
|
105
|
+
if grep -q "PLACEHOLDER" "$API_SURFACE" 2>/dev/null; then
|
|
106
|
+
log_warn "architecture/api-surface.md" "Contains placeholder text — not yet populated"
|
|
107
|
+
else
|
|
108
|
+
NEWER_FILES=""
|
|
109
|
+
for pattern in "**/controllers/*" "**/routes/*" "**/api/*" "**/*Controller*" "**/*Router*"; do
|
|
110
|
+
while IFS= read -r file; do
|
|
111
|
+
if [ -n "$file" ] && [ "$file" -nt "$API_SURFACE" ]; then
|
|
112
|
+
NEWER_FILES="$NEWER_FILES $file"
|
|
113
|
+
fi
|
|
114
|
+
done < <(find . -path "./.git" -prune -o -path "$pattern" -print 2>/dev/null || true)
|
|
115
|
+
done
|
|
116
|
+
|
|
117
|
+
if [ -n "$NEWER_FILES" ]; then
|
|
118
|
+
log_warn "architecture/api-surface.md" "Source files modified after last update:${NEWER_FILES}"
|
|
119
|
+
else
|
|
120
|
+
log_ok "architecture/api-surface.md"
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
else
|
|
124
|
+
log_missing "architecture/api-surface.md"
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
# --- Check 3: Dependencies drift ---
|
|
128
|
+
echo "--- Checking Dependencies Drift ---"
|
|
129
|
+
DEPS_FILE="$CONTEXT_DIR/architecture/dependencies.md"
|
|
130
|
+
if [ -f "$DEPS_FILE" ]; then
|
|
131
|
+
if grep -q "PLACEHOLDER" "$DEPS_FILE" 2>/dev/null; then
|
|
132
|
+
log_warn "architecture/dependencies.md" "Contains placeholder text — not yet populated"
|
|
133
|
+
else
|
|
134
|
+
NEWER_FILES=""
|
|
135
|
+
for manifest in "package.json" "package-lock.json" "yarn.lock" "pnpm-lock.yaml" \
|
|
136
|
+
"requirements.txt" "pyproject.toml" "Pipfile.lock" \
|
|
137
|
+
"go.mod" "go.sum" "Cargo.toml" "Cargo.lock" \
|
|
138
|
+
"*.csproj" "*.sln" "pom.xml" "build.gradle"; do
|
|
139
|
+
while IFS= read -r file; do
|
|
140
|
+
if [ -n "$file" ] && [ "$file" -nt "$DEPS_FILE" ]; then
|
|
141
|
+
NEWER_FILES="$NEWER_FILES $file"
|
|
142
|
+
fi
|
|
143
|
+
done < <(find . -maxdepth 3 -name "$manifest" -not -path "./.git/*" 2>/dev/null || true)
|
|
144
|
+
done
|
|
145
|
+
|
|
146
|
+
if [ -n "$NEWER_FILES" ]; then
|
|
147
|
+
log_warn "architecture/dependencies.md" "Package manifests modified after last update:${NEWER_FILES}"
|
|
148
|
+
else
|
|
149
|
+
log_ok "architecture/dependencies.md"
|
|
150
|
+
fi
|
|
151
|
+
fi
|
|
152
|
+
else
|
|
153
|
+
log_missing "architecture/dependencies.md"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# --- Check 4: Module Graph drift ---
|
|
157
|
+
echo "--- Checking Module Graph Drift ---"
|
|
158
|
+
MODULE_GRAPH="$CONTEXT_DIR/architecture/module-graph.md"
|
|
159
|
+
if [ -f "$MODULE_GRAPH" ]; then
|
|
160
|
+
if grep -q "PLACEHOLDER\|TO BE FILLED" "$MODULE_GRAPH" 2>/dev/null; then
|
|
161
|
+
log_warn "architecture/module-graph.md" "Contains placeholder text — not yet populated"
|
|
162
|
+
else
|
|
163
|
+
NEWER_FILES=""
|
|
164
|
+
# Check if any source files are newer than module-graph.md
|
|
165
|
+
for pattern in "*.h" "*.hpp" "*.cs" "*.ts" "*.py" "*.go" "*.rs" "*.java"; do
|
|
166
|
+
while IFS= read -r file; do
|
|
167
|
+
if [ -n "$file" ] && [ "$file" -nt "$MODULE_GRAPH" ]; then
|
|
168
|
+
NEWER_FILES="$NEWER_FILES $(basename "$file")"
|
|
169
|
+
break # One per pattern is enough to trigger
|
|
170
|
+
fi
|
|
171
|
+
done < <(find . -path "./.git" -prune -o -path "./node_modules" -prune -o -name "$pattern" -print 2>/dev/null | head -5 || true)
|
|
172
|
+
done
|
|
173
|
+
|
|
174
|
+
if [ -n "$NEWER_FILES" ]; then
|
|
175
|
+
log_warn "architecture/module-graph.md" "Source files modified after last update (samples:${NEWER_FILES})"
|
|
176
|
+
else
|
|
177
|
+
log_ok "architecture/module-graph.md"
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
else
|
|
181
|
+
log_missing "architecture/module-graph.md"
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
# --- Check 5: Class Index drift ---
|
|
185
|
+
echo "--- Checking Class Index Drift ---"
|
|
186
|
+
CLASS_INDEX="$CONTEXT_DIR/architecture/class-index.md"
|
|
187
|
+
if [ -f "$CLASS_INDEX" ]; then
|
|
188
|
+
if grep -q "PLACEHOLDER" "$CLASS_INDEX" 2>/dev/null; then
|
|
189
|
+
log_warn "architecture/class-index.md" "Contains placeholder text — not yet populated"
|
|
190
|
+
else
|
|
191
|
+
NEWER_FILES=""
|
|
192
|
+
for pattern in "*.h" "*.hpp" "*.cs" "*.ts" "*.py" "*.go" "*.rs" "*.java"; do
|
|
193
|
+
while IFS= read -r file; do
|
|
194
|
+
if [ -n "$file" ] && [ "$file" -nt "$CLASS_INDEX" ]; then
|
|
195
|
+
NEWER_FILES="$NEWER_FILES $(basename "$file")"
|
|
196
|
+
break
|
|
197
|
+
fi
|
|
198
|
+
done < <(find . -path "./.git" -prune -o -path "./node_modules" -prune -o -name "$pattern" -print 2>/dev/null | head -5 || true)
|
|
199
|
+
done
|
|
200
|
+
|
|
201
|
+
if [ -n "$NEWER_FILES" ]; then
|
|
202
|
+
log_warn "architecture/class-index.md" "Source files modified after last update (samples:${NEWER_FILES})"
|
|
203
|
+
else
|
|
204
|
+
log_ok "architecture/class-index.md"
|
|
205
|
+
fi
|
|
206
|
+
fi
|
|
207
|
+
else
|
|
208
|
+
log_missing "architecture/class-index.md"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# --- Check 6: Data Flow drift ---
|
|
212
|
+
echo "--- Checking Data Flow Drift ---"
|
|
213
|
+
DATA_FLOW="$CONTEXT_DIR/architecture/data-flow.md"
|
|
214
|
+
if [ -f "$DATA_FLOW" ]; then
|
|
215
|
+
if grep -q "PLACEHOLDER" "$DATA_FLOW" 2>/dev/null; then
|
|
216
|
+
log_warn "architecture/data-flow.md" "Contains placeholder text — not yet populated"
|
|
217
|
+
else
|
|
218
|
+
log_ok "architecture/data-flow.md"
|
|
219
|
+
fi
|
|
220
|
+
else
|
|
221
|
+
log_missing "architecture/data-flow.md"
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
# --- Check 7: Semantic entity-list comparison (optional) ---
|
|
225
|
+
if [ "$SEMANTIC_MODE" = true ]; then
|
|
226
|
+
echo "--- Semantic Entity Comparison ---"
|
|
227
|
+
|
|
228
|
+
# Helper: compare two sorted name lists, report additions and removals
|
|
229
|
+
semantic_compare() {
|
|
230
|
+
local label="$1"
|
|
231
|
+
local doc_names="$2"
|
|
232
|
+
local code_names="$3"
|
|
233
|
+
|
|
234
|
+
if [ -z "$doc_names" ] || [ -z "$code_names" ]; then
|
|
235
|
+
return # skip if either list is empty (file not populated)
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
local added removed
|
|
239
|
+
added=$(comm -13 <(echo "$doc_names") <(echo "$code_names") | tr '\n' ', ' | sed 's/,$//')
|
|
240
|
+
removed=$(comm -23 <(echo "$doc_names") <(echo "$code_names") | tr '\n' ', ' | sed 's/,$//')
|
|
241
|
+
|
|
242
|
+
if [ -n "$added" ] || [ -n "$removed" ]; then
|
|
243
|
+
local detail=""
|
|
244
|
+
[ -n "$added" ] && detail="New in code: [${added}]"
|
|
245
|
+
[ -n "$removed" ] && detail="${detail:+$detail | }In doc but not in code: [${removed}]"
|
|
246
|
+
log_warn "$label (semantic)" "$detail"
|
|
247
|
+
else
|
|
248
|
+
log_ok "$label (semantic match)"
|
|
249
|
+
fi
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
# --- Semantic: class-index.md ---
|
|
253
|
+
if [ -f "$CLASS_INDEX" ] && ! grep -q "PLACEHOLDER" "$CLASS_INDEX" 2>/dev/null; then
|
|
254
|
+
# Extract class/interface/struct names from the document (markdown table rows)
|
|
255
|
+
doc_classes=$(grep -oP '^\| \K[A-Z][a-zA-Z0-9_<>]+' "$CLASS_INDEX" 2>/dev/null | sed 's/<.*>//' | sort -u)
|
|
256
|
+
# Extract from source code
|
|
257
|
+
code_classes=$(find . -path "./.git" -prune -o -path "./node_modules" -prune -o \
|
|
258
|
+
\( -name "*.cs" -o -name "*.ts" -o -name "*.py" -o -name "*.java" -o -name "*.go" -o -name "*.h" -o -name "*.hpp" -o -name "*.rs" \) \
|
|
259
|
+
-print 2>/dev/null | xargs grep -ohP '^\s*(export\s+)?(public\s+)?(abstract\s+)?(sealed\s+)?(partial\s+)?(class|interface|struct|trait|enum|record)\s+\K[A-Z][a-zA-Z0-9_]+' 2>/dev/null | sort -u)
|
|
260
|
+
semantic_compare "architecture/class-index.md" "$doc_classes" "$code_classes"
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
# --- Semantic: dependencies.md ---
|
|
264
|
+
if [ -f "$DEPS_FILE" ] && ! grep -q "PLACEHOLDER" "$DEPS_FILE" 2>/dev/null; then
|
|
265
|
+
# Extract package names from the document
|
|
266
|
+
doc_deps=$(grep -oP '^\| `?\K[a-z@][a-z0-9_./@-]+' "$DEPS_FILE" 2>/dev/null | sort -u)
|
|
267
|
+
# Extract from package.json (if exists)
|
|
268
|
+
code_deps=""
|
|
269
|
+
if [ -f "package.json" ]; then
|
|
270
|
+
code_deps=$(grep -oP '"[a-z@][a-z0-9_./@-]+":\s*"' package.json 2>/dev/null | grep -oP '"[a-z@][a-z0-9_./@-]+"' | tr -d '"' | sort -u)
|
|
271
|
+
elif [ -f "requirements.txt" ]; then
|
|
272
|
+
code_deps=$(grep -oP '^[a-zA-Z][a-zA-Z0-9_-]+' requirements.txt 2>/dev/null | tr '[:upper:]' '[:lower:]' | sort -u)
|
|
273
|
+
elif [ -f "go.mod" ]; then
|
|
274
|
+
code_deps=$(grep -oP '^\s+\K\S+' go.mod 2>/dev/null | grep '/' | sort -u)
|
|
275
|
+
fi
|
|
276
|
+
[ -n "$code_deps" ] && semantic_compare "architecture/dependencies.md" "$doc_deps" "$code_deps"
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# --- Semantic: api-surface.md ---
|
|
280
|
+
if [ -f "$API_SURFACE" ] && ! grep -q "PLACEHOLDER" "$API_SURFACE" 2>/dev/null; then
|
|
281
|
+
# Extract endpoint paths from the document (e.g., /api/users, GET /users)
|
|
282
|
+
doc_endpoints=$(grep -oP '(GET|POST|PUT|DELETE|PATCH)\s+\K/[a-zA-Z0-9_/{}-]+' "$API_SURFACE" 2>/dev/null | sort -u)
|
|
283
|
+
if [ -z "$doc_endpoints" ]; then
|
|
284
|
+
# Try extracting from table format: | /api/users | or | `GET /api/users` |
|
|
285
|
+
doc_endpoints=$(grep -oP '^\| `?(/[a-zA-Z0-9_/{}-]+)' "$API_SURFACE" 2>/dev/null | sed 's/^| `\?//' | sort -u)
|
|
286
|
+
fi
|
|
287
|
+
# Only report if we found documented endpoints but skip code extraction (too varied per framework)
|
|
288
|
+
# The timestamp-based check already covers this — semantic check for APIs needs framework-specific logic
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# --- Semantic: data-model.md ---
|
|
292
|
+
if [ -f "$DATA_MODEL" ] && ! grep -q "PLACEHOLDER" "$DATA_MODEL" 2>/dev/null; then
|
|
293
|
+
# Extract entity/table names from the document
|
|
294
|
+
doc_entities=$(grep -oP '^\| `?\K[A-Z][a-zA-Z0-9_]+' "$DATA_MODEL" 2>/dev/null | sort -u)
|
|
295
|
+
# Extract from common ORM patterns
|
|
296
|
+
code_entities=""
|
|
297
|
+
# EF Core / C# entities
|
|
298
|
+
if find . -name "*.cs" -path "*/entities/*" -o -name "*.cs" -path "*/models/*" 2>/dev/null | head -1 | grep -q .; then
|
|
299
|
+
code_entities=$(find . \( -path "*/entities/*.cs" -o -path "*/models/*.cs" \) 2>/dev/null | xargs grep -ohP '(class|record)\s+\K[A-Z][a-zA-Z0-9_]+' 2>/dev/null | sort -u)
|
|
300
|
+
# Python models
|
|
301
|
+
elif find . -name "models.py" 2>/dev/null | head -1 | grep -q .; then
|
|
302
|
+
code_entities=$(find . -name "models.py" 2>/dev/null | xargs grep -ohP 'class\s+\K[A-Z][a-zA-Z0-9_]+' 2>/dev/null | sort -u)
|
|
303
|
+
# Prisma
|
|
304
|
+
elif [ -f "prisma/schema.prisma" ]; then
|
|
305
|
+
code_entities=$(grep -oP 'model\s+\K[A-Z][a-zA-Z0-9_]+' prisma/schema.prisma 2>/dev/null | sort -u)
|
|
306
|
+
fi
|
|
307
|
+
[ -n "$code_entities" ] && semantic_compare "architecture/data-model.md" "$doc_entities" "$code_entities"
|
|
308
|
+
fi
|
|
309
|
+
fi
|
|
310
|
+
|
|
311
|
+
# --- Check 8: File size budgets ---
|
|
312
|
+
# (was Check 7 before semantic check was added)
|
|
313
|
+
echo "--- Checking File Size Budgets ---"
|
|
314
|
+
check_size() {
|
|
315
|
+
local file=$1
|
|
316
|
+
local budget=$2
|
|
317
|
+
local label=$3
|
|
318
|
+
if [ -f "$file" ]; then
|
|
319
|
+
local lines
|
|
320
|
+
lines=$(wc -l < "$file")
|
|
321
|
+
if [ "$lines" -gt "$budget" ]; then
|
|
322
|
+
log_warn "$label" "Exceeds budget: ${lines}/${budget} lines"
|
|
323
|
+
else
|
|
324
|
+
log_ok "$label (${lines}/${budget} lines)"
|
|
325
|
+
fi
|
|
326
|
+
fi
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
check_size "$CONTEXT_DIR/constitution.md" 200 "constitution.md"
|
|
330
|
+
check_size "AGENTS.md" 150 "AGENTS.md"
|
|
331
|
+
check_size "$CONTEXT_DIR/architecture/overview.md" 800 "architecture/overview.md"
|
|
332
|
+
check_size "$CONTEXT_DIR/architecture/module-graph.md" 500 "architecture/module-graph.md"
|
|
333
|
+
check_size "$CONTEXT_DIR/architecture/data-flow.md" 500 "architecture/data-flow.md"
|
|
334
|
+
check_size "$CONTEXT_DIR/architecture/class-index.md" 500 "architecture/class-index.md"
|
|
335
|
+
check_size "$CONTEXT_DIR/experience/lessons.md" 500 "experience/lessons.md"
|
|
336
|
+
check_size "$CONTEXT_DIR/experience/debugging.md" 500 "experience/debugging.md"
|
|
337
|
+
|
|
338
|
+
# --- Check 9: Required files existence ---
|
|
339
|
+
echo "--- Checking Required Files ---"
|
|
340
|
+
for required in "index.md" "constitution.md" "business/overview.md" "architecture/overview.md" \
|
|
341
|
+
"architecture/module-graph.md" "architecture/data-flow.md" "architecture/class-index.md" \
|
|
342
|
+
"conventions/code-style.md" "conventions/patterns.md"; do
|
|
343
|
+
if [ -f "$CONTEXT_DIR/$required" ]; then
|
|
344
|
+
log_ok "$required exists"
|
|
345
|
+
else
|
|
346
|
+
log_missing "$required"
|
|
347
|
+
fi
|
|
348
|
+
done
|
|
349
|
+
|
|
350
|
+
# --- Summary ---
|
|
351
|
+
echo ""
|
|
352
|
+
echo "========================================="
|
|
353
|
+
if [ "$DRIFT_COUNT" -eq 0 ]; then
|
|
354
|
+
echo -e "${GREEN}All checks passed. No drift detected.${NC}"
|
|
355
|
+
else
|
|
356
|
+
echo -e "${YELLOW}${DRIFT_COUNT} issue(s) detected.${NC}"
|
|
357
|
+
fi
|
|
358
|
+
echo "========================================="
|
|
359
|
+
|
|
360
|
+
# --- Save report ---
|
|
361
|
+
if [ "$SAVE_REPORT" = true ]; then
|
|
362
|
+
{
|
|
363
|
+
echo "# Drift Detection Report"
|
|
364
|
+
echo ""
|
|
365
|
+
echo "<!-- AUTO-GENERATED by scripts/detect-drift.sh -->"
|
|
366
|
+
echo "<!-- generated-at: $(date -u +%Y-%m-%dT%H:%M:%SZ) -->"
|
|
367
|
+
echo ""
|
|
368
|
+
if [ "$DRIFT_COUNT" -eq 0 ]; then
|
|
369
|
+
echo "## Status: All Clear"
|
|
370
|
+
else
|
|
371
|
+
echo "## Status: ${DRIFT_COUNT} issue(s) detected"
|
|
372
|
+
fi
|
|
373
|
+
echo ""
|
|
374
|
+
echo "| File | Status | Details |"
|
|
375
|
+
echo "|------|--------|---------|"
|
|
376
|
+
for line in "${REPORT_LINES[@]}"; do
|
|
377
|
+
echo "$line"
|
|
378
|
+
done
|
|
379
|
+
} > "$REPORT_FILE"
|
|
380
|
+
echo "Report saved to $REPORT_FILE"
|
|
381
|
+
fi
|
|
382
|
+
|
|
383
|
+
# --- CI mode exit code ---
|
|
384
|
+
if [ "$CI_MODE" = true ] && [ "$DRIFT_COUNT" -gt 0 ]; then
|
|
385
|
+
exit 1
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
exit 0
|