carrymem 0.1.2__tar.gz

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.
Files changed (129) hide show
  1. carrymem-0.1.2/.description +1 -0
  2. carrymem-0.1.2/.github/workflows/ci.yml +480 -0
  3. carrymem-0.1.2/.gitignore +98 -0
  4. carrymem-0.1.2/.pre-commit-config.yaml +45 -0
  5. carrymem-0.1.2/CHANGELOG.md +137 -0
  6. carrymem-0.1.2/CONTRIBUTING.md +268 -0
  7. carrymem-0.1.2/LICENSE +21 -0
  8. carrymem-0.1.2/MANIFEST.in +4 -0
  9. carrymem-0.1.2/PKG-INFO +433 -0
  10. carrymem-0.1.2/README.md +375 -0
  11. carrymem-0.1.2/benchmarks/baseline_benchmark.py +392 -0
  12. carrymem-0.1.2/benchmarks/baseline_results.json +124 -0
  13. carrymem-0.1.2/benchmarks/classification_accuracy.py +1063 -0
  14. carrymem-0.1.2/benchmarks/dataset/en.json +117 -0
  15. carrymem-0.1.2/benchmarks/dataset/ja.json +69 -0
  16. carrymem-0.1.2/benchmarks/dataset/zh.json +69 -0
  17. carrymem-0.1.2/benchmarks/final_results.json +124 -0
  18. carrymem-0.1.2/benchmarks/leaderboard.py +76 -0
  19. carrymem-0.1.2/benchmarks/performance_benchmark.py +329 -0
  20. carrymem-0.1.2/benchmarks/run_benchmark.py +198 -0
  21. carrymem-0.1.2/ci_local_check.py +224 -0
  22. carrymem-0.1.2/docs/API_REFERENCE.md +302 -0
  23. carrymem-0.1.2/docs/ARCHITECTURE.md +448 -0
  24. carrymem-0.1.2/docs/QUICK_START_GUIDE.md +273 -0
  25. carrymem-0.1.2/docs/README.md +184 -0
  26. carrymem-0.1.2/docs/ROADMAP.md +110 -0
  27. carrymem-0.1.2/docs/USER_STORIES.md +374 -0
  28. carrymem-0.1.2/docs/guides/USER_PERSPECTIVE_REVIEW-CN.md +116 -0
  29. carrymem-0.1.2/docs/i18n/README-CN.md +372 -0
  30. carrymem-0.1.2/docs/i18n/README-JP.md +372 -0
  31. carrymem-0.1.2/docs/i18n/docs-hub-CN.md +372 -0
  32. carrymem-0.1.2/docs/internal/AI Agent/351/225/277/346/234/237/350/256/260/345/277/206/347/263/273/347/273/237/345/270/202/345/234/272/346/240/274/345/261/200_ima/350/204/221/345/233/276.jpeg +0 -0
  33. carrymem-0.1.2/docs/internal/COMPETITIVE_ANALYSIS-CN.md +210 -0
  34. carrymem-0.1.2/docs/internal/PRODUCT_VISION_ANALYSIS-CN.md +657 -0
  35. carrymem-0.1.2/docs/planning/OPTIMIZATION_ROADMAP-CN.md +257 -0
  36. carrymem-0.1.2/docs/planning/SEVEN_MEMBER_VOTE_CONSENSUS-CN.md +439 -0
  37. carrymem-0.1.2/docs/planning/V050_PHASE1_PLAN-CN.md +355 -0
  38. carrymem-0.1.2/docs/planning/V060_PHASE2_PLAN-CN.md +267 -0
  39. carrymem-0.1.2/docs/planning/V070_PHASE3_PLAN-CN.md +188 -0
  40. carrymem-0.1.2/docs/planning/V080_PHASE_PLAN.md +149 -0
  41. carrymem-0.1.2/examples/basic_usage.py +52 -0
  42. carrymem-0.1.2/examples/simple_assistant/README.md +86 -0
  43. carrymem-0.1.2/examples/simple_assistant/assistant.py +80 -0
  44. carrymem-0.1.2/examples/thread_safe_usage.py +57 -0
  45. carrymem-0.1.2/install.sh +130 -0
  46. carrymem-0.1.2/integrations/claude_code/mcp.json +9 -0
  47. carrymem-0.1.2/integrations/cursor/mcp.json +8 -0
  48. carrymem-0.1.2/mypy.ini +20 -0
  49. carrymem-0.1.2/pyproject.toml +105 -0
  50. carrymem-0.1.2/requirements.txt +8 -0
  51. carrymem-0.1.2/setup.cfg +4 -0
  52. carrymem-0.1.2/setup.py +82 -0
  53. carrymem-0.1.2/src/carrymem.egg-info/PKG-INFO +433 -0
  54. carrymem-0.1.2/src/carrymem.egg-info/SOURCES.txt +127 -0
  55. carrymem-0.1.2/src/carrymem.egg-info/dependency_links.txt +1 -0
  56. carrymem-0.1.2/src/carrymem.egg-info/entry_points.txt +7 -0
  57. carrymem-0.1.2/src/carrymem.egg-info/requires.txt +26 -0
  58. carrymem-0.1.2/src/carrymem.egg-info/top_level.txt +1 -0
  59. carrymem-0.1.2/src/memory_classification_engine/__init__.py +78 -0
  60. carrymem-0.1.2/src/memory_classification_engine/__main__.py +115 -0
  61. carrymem-0.1.2/src/memory_classification_engine/__version__.py +1 -0
  62. carrymem-0.1.2/src/memory_classification_engine/adapters/__init__.py +13 -0
  63. carrymem-0.1.2/src/memory_classification_engine/adapters/base.py +527 -0
  64. carrymem-0.1.2/src/memory_classification_engine/adapters/json_adapter.py +258 -0
  65. carrymem-0.1.2/src/memory_classification_engine/adapters/loader.py +61 -0
  66. carrymem-0.1.2/src/memory_classification_engine/adapters/obsidian_adapter.py +433 -0
  67. carrymem-0.1.2/src/memory_classification_engine/adapters/sqlite_adapter.py +1280 -0
  68. carrymem-0.1.2/src/memory_classification_engine/async_carrymem.py +164 -0
  69. carrymem-0.1.2/src/memory_classification_engine/backup.py +161 -0
  70. carrymem-0.1.2/src/memory_classification_engine/cache.py +121 -0
  71. carrymem-0.1.2/src/memory_classification_engine/carrymem.py +991 -0
  72. carrymem-0.1.2/src/memory_classification_engine/cli.py +1296 -0
  73. carrymem-0.1.2/src/memory_classification_engine/conflict_detector.py +417 -0
  74. carrymem-0.1.2/src/memory_classification_engine/context.py +245 -0
  75. carrymem-0.1.2/src/memory_classification_engine/coordinators/__init__.py +7 -0
  76. carrymem-0.1.2/src/memory_classification_engine/coordinators/classification_pipeline.py +257 -0
  77. carrymem-0.1.2/src/memory_classification_engine/engine.py +195 -0
  78. carrymem-0.1.2/src/memory_classification_engine/exceptions.py +51 -0
  79. carrymem-0.1.2/src/memory_classification_engine/integration/__init__.py +8 -0
  80. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/__init__.py +21 -0
  81. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/__main__.py +18 -0
  82. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/handlers.py +396 -0
  83. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/http_server.py +249 -0
  84. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/server.py +296 -0
  85. carrymem-0.1.2/src/memory_classification_engine/integration/layer2_mcp/tools.py +501 -0
  86. carrymem-0.1.2/src/memory_classification_engine/layers/__init__.py +1 -0
  87. carrymem-0.1.2/src/memory_classification_engine/layers/feedback_loop.py +377 -0
  88. carrymem-0.1.2/src/memory_classification_engine/layers/pattern_analyzer.py +1434 -0
  89. carrymem-0.1.2/src/memory_classification_engine/layers/rule_matcher.py +100 -0
  90. carrymem-0.1.2/src/memory_classification_engine/layers/semantic_classifier.py +100 -0
  91. carrymem-0.1.2/src/memory_classification_engine/merge.py +124 -0
  92. carrymem-0.1.2/src/memory_classification_engine/py.typed +0 -0
  93. carrymem-0.1.2/src/memory_classification_engine/quality_scorer.py +414 -0
  94. carrymem-0.1.2/src/memory_classification_engine/scoring.py +84 -0
  95. carrymem-0.1.2/src/memory_classification_engine/security/__init__.py +33 -0
  96. carrymem-0.1.2/src/memory_classification_engine/security/audit.py +161 -0
  97. carrymem-0.1.2/src/memory_classification_engine/security/encryption.py +218 -0
  98. carrymem-0.1.2/src/memory_classification_engine/security/input_validator.py +494 -0
  99. carrymem-0.1.2/src/memory_classification_engine/semantic/__init__.py +16 -0
  100. carrymem-0.1.2/src/memory_classification_engine/semantic/data/__init__.py +15 -0
  101. carrymem-0.1.2/src/memory_classification_engine/semantic/data/synonyms_daily_en.yaml +383 -0
  102. carrymem-0.1.2/src/memory_classification_engine/semantic/data/synonyms_jp.yaml +501 -0
  103. carrymem-0.1.2/src/memory_classification_engine/semantic/data/synonyms_technical_cn.yaml +454 -0
  104. carrymem-0.1.2/src/memory_classification_engine/semantic/expander.py +320 -0
  105. carrymem-0.1.2/src/memory_classification_engine/semantic/merger.py +245 -0
  106. carrymem-0.1.2/src/memory_classification_engine/tui.py +320 -0
  107. carrymem-0.1.2/src/memory_classification_engine/utils/__init__.py +1 -0
  108. carrymem-0.1.2/src/memory_classification_engine/utils/config.py +93 -0
  109. carrymem-0.1.2/src/memory_classification_engine/utils/confirmation.py +39 -0
  110. carrymem-0.1.2/src/memory_classification_engine/utils/constants.py +68 -0
  111. carrymem-0.1.2/src/memory_classification_engine/utils/helpers.py +146 -0
  112. carrymem-0.1.2/src/memory_classification_engine/utils/language.py +293 -0
  113. carrymem-0.1.2/src/memory_classification_engine/utils/logger.py +55 -0
  114. carrymem-0.1.2/src/memory_classification_engine/utils/performance.py +303 -0
  115. carrymem-0.1.2/src/memory_classification_engine/utils/validators.py +261 -0
  116. carrymem-0.1.2/tests/test_async_carrymem.py +161 -0
  117. carrymem-0.1.2/tests/test_cache.py +202 -0
  118. carrymem-0.1.2/tests/test_carrymem.py +1537 -0
  119. carrymem-0.1.2/tests/test_environment.py +191 -0
  120. carrymem-0.1.2/tests/test_execution_context.py +142 -0
  121. carrymem-0.1.2/tests/test_helpers.py +278 -0
  122. carrymem-0.1.2/tests/test_mce_recall.py +43 -0
  123. carrymem-0.1.2/tests/test_scoring.py +148 -0
  124. carrymem-0.1.2/tests/test_security.py +106 -0
  125. carrymem-0.1.2/tests/test_v050.py +403 -0
  126. carrymem-0.1.2/tests/test_v060.py +317 -0
  127. carrymem-0.1.2/tests/test_v070.py +283 -0
  128. carrymem-0.1.2/tests/test_v080_cli.py +541 -0
  129. carrymem-0.1.2/tests/test_v080_quality.py +116 -0
@@ -0,0 +1 @@
1
+ CarryMem - Portable AI Memory Layer | 便携式 AI 记忆层 | ポータブル AI メモリレイヤー
@@ -0,0 +1,480 @@
1
+ name: CI Quality Gates
2
+
3
+ on:
4
+ push:
5
+ branches: [new-main]
6
+ tags: ['v*']
7
+ pull_request:
8
+ branches: [new-main]
9
+ workflow_dispatch:
10
+ inputs:
11
+ reason:
12
+ description: 'Reason for manual run'
13
+ required: false
14
+
15
+ concurrency:
16
+ group: ${{ github.workflow }}-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ # ──────────────────────────────────────────────
21
+ # GATE 1: Code Quality (lint, format, type-check)
22
+ # ──────────────────────────────────────────────
23
+ quality:
24
+ name: Code Quality
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: '3.11'
33
+
34
+ - name: Install dependencies
35
+ run: |
36
+ python -m pip install --upgrade pip
37
+ pip install -e ".[dev]" flake8 black isort mypy
38
+
39
+ - name: Lint — fatal errors only
40
+ run: |
41
+ flake8 src/ tests/ \
42
+ --count --select=E9,F63,F7,F82 \
43
+ --show-source --statistics
44
+
45
+ - name: Lint — warnings (non-blocking)
46
+ run: |
47
+ flake8 src/ tests/ \
48
+ --count --exit-zero \
49
+ --max-complexity=12 \
50
+ --max-line-length=127 \
51
+ --statistics
52
+
53
+ - name: Format check — Black
54
+ run: |
55
+ black --check --diff --color src/ tests/
56
+
57
+ - name: Format check — isort
58
+ run: |
59
+ isort --check-only --diff --color src/ tests/
60
+
61
+ - name: Type check — MyPy
62
+ run: |
63
+ mypy src/ --ignore-missing-imports --no-error-summary || true
64
+
65
+ # ──────────────────────────────────────────────
66
+ # GATE 2: Internationalization (i18n) Compliance
67
+ # ──────────────────────────────────────────────
68
+ i18n:
69
+ name: i18n Compliance
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+
74
+ - name: Set up Python
75
+ uses: actions/setup-python@v5
76
+ with:
77
+ python-version: '3.11'
78
+
79
+ - name: Check for Chinese comments in source code
80
+ run: |
81
+ python3 << 'EOF'
82
+ import os, re, sys
83
+
84
+ errors = []
85
+ # Files that are allowed to contain Chinese (i18n data)
86
+ i18n_whitelist = [
87
+ 'language.py', # Multi-language keyword lists
88
+ 'context.py', # Prompt templates for zh/ja locales
89
+ 'pattern_analyzer.py',# CJK regex patterns & feedback phrases
90
+ 'tools.py', # Schema label_zh / zh_name fields
91
+ '__main__.py', # Demo/test data with Chinese examples
92
+ '__init__.py', # Docstring examples showing multilingual recall
93
+ 'feedback_loop.py', # Chinese indicator keywords for classification
94
+ 'confirmation.py', # Chinese confirmation regex patterns
95
+ 'expander.py', # Docstring examples for cross-language expansion
96
+ 'merger.py', # Docstring examples for cross-language merging
97
+ ]
98
+
99
+ for root, dirs, files in os.walk('src'):
100
+ dirs[:] = [d for d in dirs if d not in ('__pycache__', '.pytest_cache')]
101
+ for f in files:
102
+ if not f.endswith('.py'):
103
+ continue
104
+ filepath = os.path.join(root, f)
105
+ relpath = os.path.relpath(filepath)
106
+
107
+ # Skip whitelisted files
108
+ if any(w in relpath for w in i18n_whitelist):
109
+ continue
110
+
111
+ try:
112
+ with open(filepath, 'r', encoding='utf-8') as fh:
113
+ for lineno, line in enumerate(fh, 1):
114
+ # Skip strings inside i18n data structures
115
+ stripped = line.strip()
116
+ if (stripped.startswith("'zh-cn:") or
117
+ stripped.startswith('"zh-cn:') or
118
+ stripped.startswith('# i18n') or
119
+ 'label_zh=' in stripped or
120
+ 'zh_name=' in stripped):
121
+ continue
122
+
123
+ # Check for Chinese characters in comments and code
124
+ if re.search(r'[\u4e00-\u9fff]', line):
125
+ # Allow Chinese in docstrings that are clearly i18n data
126
+ if '"""' in line or "'''" in line:
127
+ continue
128
+ errors.append(f"{relpath}:{lineno}: {line.rstrip()[:80]}")
129
+ except Exception as e:
130
+ print(f"Warning: Could not read {filepath}: {e}")
131
+
132
+ if errors:
133
+ print(f"\n❌ Found {len(errors)} lines with Chinese characters outside i18n data:")
134
+ for err in errors[:30]:
135
+ print(f" {err}")
136
+ if len(errors) > 30:
137
+ print(f" ... and {len(errors)-30} more")
138
+ sys.exit(1)
139
+ else:
140
+ print("✅ No Chinese characters found in non-i18n source code.")
141
+ EOF
142
+
143
+ - name: Check for mangled comments (# Comment in Chinese removed...)
144
+ run: |
145
+ if grep -r "# Comment in Chinese removed" src/ --include="*.py"; then
146
+ echo "::error::Found mangled '# Comment in Chinese removed' remnants"
147
+ exit 1
148
+ fi
149
+ echo "✅ No mangled comments found."
150
+
151
+ - name: Verify English display labels in helpers.py
152
+ run: |
153
+ python3 << 'EOF'
154
+ import ast, sys
155
+
156
+ with open('src/memory_classification_engine/utils/helpers.py') as f:
157
+ tree = ast.parse(f.read())
158
+
159
+ chinese_found = []
160
+ for node in ast.walk(tree):
161
+ if isinstance(node, ast.Assign):
162
+ for target in node.targets:
163
+ if isinstance(target, ast.Name) and target.id == 'MEMORY_TYPES':
164
+ for kv in node.value.keys:
165
+ if isinstance(kv.value, ast.Constant) and re.search(r'[\u4e00-\u9fff]', str(kv.value.s)):
166
+ chinese_found.append(f" MEMORY_TYPES[{kv.value.s}]")
167
+ if isinstance(target, ast.Name) and target.id == 'MEMORY_TIERS':
168
+ for kv in node.value.keys:
169
+ if isinstance(kv.value, ast.Constant) and re.search(r'[\u4e00-\u9fff]', str(kv.value.s)):
170
+ chinese_found.append(f" MEMORY_TIERS[{kv.value.s}]")
171
+
172
+ if chinese_found:
173
+ print(f"❌ Chinese labels found in helpers.py:")
174
+ for c in chinese_found:
175
+ print(c)
176
+ sys.exit(1)
177
+ else:
178
+ print("✅ All display labels in helpers.py are English.")
179
+ EOF
180
+
181
+ # ──────────────────────────────────────────────
182
+ # GATE 3: Unit Tests (matrix: Python × OS)
183
+ # ──────────────────────────────────────────────
184
+ test:
185
+ name: Tests (Python ${{ matrix.python-version }} on ${{ matrix.os }})
186
+ needs: [quality, i18n]
187
+ runs-on: ${{ matrix.os }}
188
+ strategy:
189
+ fail-fast: false
190
+ matrix:
191
+ python-version: ['3.9', '3.10', '3.11', '3.12']
192
+ os: [ubuntu-latest]
193
+
194
+ steps:
195
+ - uses: actions/checkout@v4
196
+
197
+ - name: Set up Python ${{ matrix.python-version }}
198
+ uses: actions/setup-python@v5
199
+ with:
200
+ python-version: ${{ matrix.python-version }}
201
+
202
+ - name: Cache pip
203
+ uses: actions/cache@v4
204
+ with:
205
+ path: ~/.cache/pip
206
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py', 'requirements.txt') }}
207
+
208
+ - name: Install dependencies
209
+ run: |
210
+ python -m pip install --upgrade pip
211
+ pip install -e ".[dev]"
212
+
213
+ - name: Run tests
214
+ run: |
215
+ python -m pytest tests/ \
216
+ --cov=memory_classification_engine \
217
+ --cov-report=xml \
218
+ --cov-report=term-missing \
219
+ -v \
220
+ --tb=short \
221
+ 2>&1 | tee pytest_output.txt
222
+
223
+ - name: Enforce minimum coverage
224
+ run: |
225
+ python3 << 'EOF'
226
+ import re, sys
227
+
228
+ with open('pytest_output.txt') as f:
229
+ content = f.read()
230
+
231
+ match = re.search(r'TOTAL\s+\d+\s+\d+\s+(\d+)%', content)
232
+ if match:
233
+ coverage = int(match.group(1))
234
+ print(f"\n📊 Coverage: {coverage}%")
235
+ if coverage < 55:
236
+ print(f"❌ Coverage {coverage}% is below minimum threshold of 55%")
237
+ sys.exit(1)
238
+ print(f"✅ Coverage {coverage}% meets minimum threshold of 55%")
239
+ else:
240
+ print("⚠️ Could not parse coverage from output")
241
+ EOF
242
+
243
+ - name: Upload coverage to Codecov
244
+ if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest'
245
+ uses: codecov/codecov-action@v4
246
+ with:
247
+ file: ./coverage.xml
248
+ fail_ci_if_error: false
249
+
250
+ - name: Upload test results
251
+ uses: actions/upload-artifact@v4
252
+ if: always()
253
+ with:
254
+ name: test-results-${{ matrix.os }}-py${{ matrix.python-version }}
255
+ path: |
256
+ ./coverage.xml
257
+ pytest_output.txt
258
+
259
+ # ──────────────────────────────────────────────
260
+ # GATE 4: Package Build + Fresh Install Verification
261
+ # ──────────────────────────────────────────────
262
+ build-and-install:
263
+ name: Build & Install Test
264
+ needs: [test]
265
+ runs-on: ubuntu-latest
266
+ steps:
267
+ - uses: actions/checkout@v4
268
+
269
+ - name: Set up Python
270
+ uses: actions/setup-python@v5
271
+ with:
272
+ python-version: '3.11'
273
+
274
+ - name: Install build tools
275
+ run: |
276
+ python -m pip install --upgrade pip
277
+ pip install build twine
278
+
279
+ - name: Build sdist and wheel
280
+ run: |
281
+ rm -rf dist/ build/ *.egg-info/
282
+ python -m build
283
+
284
+ - name: List build artifacts
285
+ run: |
286
+ echo "=== Build Artifacts ==="
287
+ ls -lh dist/
288
+ echo ""
289
+ echo "=== Wheel Contents ==="
290
+ unzip -l dist/carrymem-*.whl | head -40
291
+
292
+ - name: twine check
293
+ run: |
294
+ twine check dist/*
295
+
296
+ - name: "Fresh venv install from wheel"
297
+ run: |
298
+ python -m venv /tmp/carrymem_test_venv
299
+ source /tmp/carrymem_test_venv/bin/activate
300
+
301
+ echo "=== Installing from wheel ==="
302
+ WHEEL=$(ls dist/carrymem-*.whl 2>/dev/null | head -1)
303
+ pip install "$WHEEL"
304
+
305
+ echo ""
306
+ echo "=== Verifying package metadata ==="
307
+ python -c "import memory_classification_engine; print('✅ Package importable')"
308
+ python -c "from memory_classification_engine.utils.helpers import MEMORY_TYPES; print('✅ utils importable')"
309
+ python -c "from memory_classification_engine.layers.pattern_analyzer import PatternAnalyzer; print('✅ layers importable')"
310
+ python -c "from memory_classification_engine.security.input_validator import InputValidator; print('✅ security importable')"
311
+ python -c "from memory_classification_engine.adapters.sqlite_adapter import SQLiteAdapter; print('✅ adapters importable')"
312
+ python -c "from memory_classification_engine.cli import main; print('✅ cli importable')"
313
+
314
+ echo ""
315
+ echo "=== Version check ==="
316
+ carrymem version
317
+
318
+ echo ""
319
+ echo "=== Init check ==="
320
+ carrymem init
321
+
322
+ echo ""
323
+ echo "=== Add + Search smoke test ==="
324
+ carrymem add "CI test: I prefer dark mode"
325
+ carrymem search "dark"
326
+
327
+ echo ""
328
+ echo "=== Whoami smoke test ==="
329
+ carrymem whoami
330
+
331
+ echo ""
332
+ echo "=== Doctor smoke test ==="
333
+ carrymem doctor
334
+
335
+ echo ""
336
+ echo "✅ ALL FRESH INSTALL CHECKS PASSED"
337
+
338
+ - name: Check all __init__.py exist in wheel
339
+ run: |
340
+ echo "=== Verifying __init__.py in wheel ==="
341
+ missing=$(unzip -l dist/carrymem-*.whl | grep "/__init__.py$" || true)
342
+ if [ -z "$missing" ]; then
343
+ echo "❌ No __init__.py files found in wheel!"
344
+ unzip -l dist/carrymem-*.whl | grep "/" | head -20
345
+ exit 1
346
+ fi
347
+ expected_dirs=("utils/" "layers/" "adapters/" "security/" "semantic/")
348
+ for dir in "${expected_dirs[@]}"; do
349
+ if ! unzip -l dist/carrymem-*.whl | grep -q "$dir/__init__.py$"; then
350
+ echo "❌ Missing __init__.py in $dir"
351
+ exit 1
352
+ fi
353
+ echo "✅ $dir has __init__.py"
354
+ done
355
+
356
+ - name: Upload build artifacts
357
+ uses: actions/upload-artifact@v4
358
+ with:
359
+ name: build-artifacts
360
+ path: dist/
361
+
362
+ # ──────────────────────────────────────────────
363
+ # GATE 5: Security Scan
364
+ # ──────────────────────────────────────────────
365
+ security:
366
+ name: Security Scan
367
+ runs-on: ubuntu-latest
368
+ steps:
369
+ - uses: actions/checkout@v4
370
+
371
+ - name: Set up Python
372
+ uses: actions/setup-python@v5
373
+ with:
374
+ python-version: '3.11'
375
+
376
+ - name: Check for secrets / hardcoded keys
377
+ run: |
378
+ echo "=== Checking for potential secrets ==="
379
+ # Common secret patterns (not exhaustive, but catches obvious cases)
380
+ if grep -rnE "(api_key|secret_key|password|token)\s*=\s*['\"][^']{8,}" src/ --include="*.py" | \
381
+ grep -v "test_" | \
382
+ grep -v "# " | \
383
+ grep -v "os.environ" | \
384
+ grep -v "getenv"; then
385
+ echo "::warning::Potential hardcoded secret detected above"
386
+ else
387
+ echo "✅ No obvious hardcoded secrets found"
388
+ fi
389
+
390
+ - name: "Check for bare except clauses"
391
+ run: |
392
+ if grep -rn "except:" src/ --include="*.py" | grep -v "except Exception" | grep -v "except ("; then
393
+ echo "::error::Found bare except: clause (should use except Exception)"
394
+ grep -rn "except:" src/ --include="*.py" | grep -v "except Exception" | grep -v "except ("
395
+ exit 1
396
+ fi
397
+ echo "✅ No bare except: clauses found"
398
+
399
+ - name: Check for SQL injection risk patterns
400
+ run: |
401
+ if grep -rnE '(f".*SELECT|f".*INSERT|f".*UPDATE|f".*DELETE).*(query|sql)' src/ --include="*.py" | \
402
+ grep -v "validate_query" | \
403
+ grep -v "_sanitize" | \
404
+ grep -v "# safe"; then
405
+ echo "::warning::Potential raw SQL query construction (review manually)"
406
+ else
407
+ echo "✅ No obvious SQL injection patterns"
408
+ fi
409
+
410
+ # ──────────────────────────────────────────────
411
+ # GATE 6: Documentation Build Check
412
+ # ──────────────────────────────────────────────
413
+ docs:
414
+ name: Documentation Check
415
+ runs-on: ubuntu-latest
416
+ steps:
417
+ - uses: actions/checkout@v4
418
+
419
+ - name: Check README links
420
+ run: |
421
+ pip install mdformat-gfm 2>/dev/null || true
422
+ echo "=== Checking required docs exist ==="
423
+ for doc in README.md CONTRIBUTING.md LICENSE CHANGELOG.md docs/README.md; do
424
+ if [ ! -f "$doc" ]; then
425
+ echo "::error::Missing required document: $doc"
426
+ exit 1
427
+ fi
428
+ echo "✅ $doc exists"
429
+ done
430
+
431
+ echo ""
432
+ echo "=== Checking i18n docs exist ==="
433
+ for doc in docs/i18n/README-CN.md docs/i18n/README-JP.md; do
434
+ if [ ! -f "$doc" ]; then
435
+ echo "::error::Missing i18n document: $doc"
436
+ exit 1
437
+ fi
438
+ echo "✅ $doc exists"
439
+ done
440
+
441
+ - name: Verify version consistency
442
+ run: |
443
+ python3 << 'EOF'
444
+ import re, sys
445
+
446
+ # Read version from source
447
+ with open('src/memory_classification_engine/__version__.py') as f:
448
+ src_ver = re.search(r'__version__\s*=\s*["\']([^"\']+)["\']', f.read()).group(1)
449
+
450
+ # Read version from setup.py
451
+ with open('setup.py') as f:
452
+ content = f.read()
453
+ setup_ver = None
454
+ if '__version__' in content:
455
+ pass # Uses dynamic version from source
456
+ else:
457
+ m = re.search(r'version=["\']([^"\']+)["\']', content)
458
+ if m:
459
+ setup_ver = m.group(1)
460
+
461
+ # Read version from README
462
+ with open('README.md') as f:
463
+ readme_ver = None
464
+ for line in f:
465
+ if 'v0.' in line and ('version' in line.lower() or '**v' in line):
466
+ m = re.search(r'v(\d+\.\d+\.\d+)', line)
467
+ if m:
468
+ readme_ver = m.group(1)
469
+ break
470
+
471
+ print(f"Source version: {src_ver}")
472
+ print(f"Setup.py version: {setup_ver or '(dynamic)'}")
473
+ print(f"README version: {readme_ver or '(not found)'}")
474
+
475
+ versions = [v for v in [src_ver, setup_ver, readme_ver] if v]
476
+ if len(set(versions)) > 1:
477
+ print(f"\n❌ Version inconsistency detected!")
478
+ sys.exit(1)
479
+ print(f"\n✅ Versions consistent: {src_ver}")
480
+ EOF
@@ -0,0 +1,98 @@
1
+ # Cache directories
2
+ .cache/
3
+ .test_cache/
4
+ .test_smart_cache/
5
+ .benchmarks/
6
+
7
+ # Model downloads (large, ~1GB+)
8
+ models/
9
+
10
+ # Profiling
11
+ profile.out
12
+
13
+ # Backups (contain user data)
14
+ *.bak
15
+ backup/
16
+
17
+ # Virtual environments
18
+ .venv/
19
+ env/
20
+
21
+ # IDE config
22
+ .vscode/
23
+ .idea/
24
+
25
+ # Logs
26
+ *.log
27
+ logs/
28
+ src/logs/
29
+
30
+ # Test artifacts
31
+ .pytest_cache/
32
+ htmlcov/
33
+ .coverage
34
+ coverage.xml
35
+ test_results*.log
36
+
37
+ # OS files
38
+ .DS_Store
39
+ Thumbs.db
40
+
41
+ # Data directories (user data)
42
+ data/
43
+ src/data/
44
+ mce-mcp/data/
45
+
46
+ # Python compiled files
47
+ __pycache__/
48
+ *.pyc
49
+
50
+ # Egg info / build artifacts
51
+ *.egg-info/
52
+ dist/
53
+ build/
54
+ *.egg
55
+
56
+ # Sensitive: encryption keys
57
+ config/encryption_keys.json
58
+
59
+ # IDE-specific
60
+ .trae/
61
+
62
+ # Type checking cache
63
+ .mypy_cache/
64
+
65
+ # Development debug files (temporary)
66
+ debug_*.py
67
+ /test_*.py
68
+ verify_*.py
69
+ monkey_patch.py
70
+ simplest_test.py
71
+ ultimate_test.py
72
+ find_crash.py
73
+ inspect_benchmark.py
74
+ final_pipeline_test.py
75
+ run_bench_reload.py
76
+ force_reload.py
77
+ final_verify.py
78
+
79
+ # Temporary review/walkthrough reports
80
+ CARRYMEM_PROJECT_REVIEW_*.md
81
+ CODE_WALKTHROUGH_ISSUES_*.md
82
+
83
+ # Benchmark results
84
+ benchmarks/*.json
85
+ mce_bench_*.json
86
+
87
+ # Demo recordings
88
+ demo/*.cast
89
+ demo/demo.gif
90
+
91
+ # Deprecated MCP server
92
+ mce-mcp/mce_mcp_server/__pycache__/
93
+
94
+ # Image assets (kept locally, not in repo)
95
+ *.jpeg
96
+ *.jpg
97
+ !docs/**/*.jpeg
98
+ !docs/**/*.jpg
@@ -0,0 +1,45 @@
1
+ # Pre-commit hooks for CarryMem
2
+ # Install: pre-commit install
3
+ # Run manually: pre-commit run --all-files
4
+
5
+ repos:
6
+ - repo: https://github.com/pre-commit/pre-commit-hooks
7
+ rev: v4.5.0
8
+ hooks:
9
+ - id: trailing-whitespace
10
+ - id: end-of-file-fixer
11
+ - id: check-yaml
12
+ - id: check-added-large-files
13
+ args: ['--maxkb=1000']
14
+ - id: check-json
15
+ - id: check-toml
16
+ - id: check-merge-conflict
17
+ - id: debug-statements
18
+ - id: mixed-line-ending
19
+
20
+ - repo: https://github.com/psf/black
21
+ rev: 23.12.1
22
+ hooks:
23
+ - id: black
24
+ language_version: python3.9
25
+ args: ['--line-length=100']
26
+
27
+ - repo: https://github.com/pycqa/isort
28
+ rev: 5.13.2
29
+ hooks:
30
+ - id: isort
31
+ args: ['--profile=black', '--line-length=100']
32
+
33
+ - repo: https://github.com/pycqa/flake8
34
+ rev: 7.0.0
35
+ hooks:
36
+ - id: flake8
37
+ args: ['--max-line-length=100', '--extend-ignore=E203,W503']
38
+ additional_dependencies: [flake8-docstrings]
39
+
40
+ - repo: https://github.com/pre-commit/mirrors-mypy
41
+ rev: v1.8.0
42
+ hooks:
43
+ - id: mypy
44
+ additional_dependencies: [types-PyYAML]
45
+ args: ['--ignore-missing-imports', '--no-strict-optional']