@memorax/memorax-code 0.1.9 → 0.1.11

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 (101) hide show
  1. package/README.md +10 -0
  2. package/bin/memorax-code-codebuddy.mjs +4 -0
  3. package/bin/memorax-code-setup.mjs +182 -65
  4. package/bin/memorax-code.mjs +74 -45
  5. package/docs/configuration.md +85 -22
  6. package/docs/troubleshooting.md +72 -5
  7. package/lib/automatic-update.mjs +233 -0
  8. package/lib/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
  9. package/lib/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
  10. package/lib/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
  11. package/lib/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
  12. package/lib/memorax-code-adapter-common/src/config-utils.mjs +11 -0
  13. package/lib/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
  14. package/lib/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
  15. package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
  16. package/lib/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -1
  17. package/lib/memorax-code-backend/dist/app/backend-server.js +2 -2
  18. package/lib/memorax-code-backend/dist/app/memory-observability.js +2 -2
  19. package/lib/memorax-code-backend/dist/clients/codebuddy/jsonl-history.js +208 -0
  20. package/lib/memorax-code-backend/dist/clients/codebuddy/lifecycle.js +44 -0
  21. package/lib/memorax-code-backend/dist/clients/codebuddy/memory-hook-runtime.js +250 -0
  22. package/lib/memorax-code-backend/dist/clients/codebuddy/turn-id.js +16 -0
  23. package/lib/memorax-code-backend/dist/clients/codex/plugin-install.js +129 -7
  24. package/lib/memorax-code-backend/dist/config/memorax-code.js +14 -1
  25. package/lib/memorax-code-backend/dist/entrypoints/backend-cli.js +43 -6
  26. package/lib/memorax-code-backend/dist/lifecycle/active-clients.js +3 -0
  27. package/lib/memorax-code-backend/dist/lifecycle/automatic-update-scheduler.js +133 -0
  28. package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +14 -2
  29. package/lib/memorax-code-backend/dist/lifecycle/client-selection.js +6 -4
  30. package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +48 -9
  31. package/lib/memorax-code-backend/dist/memory/cli.js +4 -2
  32. package/lib/memorax-code-backend/dist/memory/hook-command.js +31 -1
  33. package/lib/memorax-code-backend/dist/memory/reminder-trace-recorder.js +5 -1
  34. package/lib/memorax-code-backend/dist/memory/service.js +12 -0
  35. package/lib/memorax-code-backend/dist/shared/windows-cli-invocation.js +10 -1
  36. package/lib/memorax-code-backend/dist/trace/config.js +12 -0
  37. package/lib/memorax-code-backend/dist/trace/context.js +21 -1
  38. package/lib/memorax-code-backend/dist/trace/store.js +12 -1
  39. package/lib/memorax-code-backend/package.json +1 -1
  40. package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  41. package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  42. package/lib/memorax-code-claude-adapter/package.json +1 -1
  43. package/lib/memorax-code-claude-adapter/runtime-hooks/ensure-backend.mjs +2 -0
  44. package/lib/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
  45. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  46. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  47. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
  48. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
  49. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
  50. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
  51. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.mjs +11 -0
  52. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
  53. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
  54. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
  55. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -1
  56. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
  57. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/runtime-hooks/ensure-backend.mjs +2 -0
  58. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
  59. package/lib/memorax-code-codebuddy-adapter/.codebuddy-plugin/plugin.json +7 -0
  60. package/lib/memorax-code-codebuddy-adapter/hooks/common-runtime.mjs +13 -0
  61. package/lib/memorax-code-codebuddy-adapter/hooks/hooks.json +38 -0
  62. package/lib/memorax-code-codebuddy-adapter/hooks/repo-memory-job.mjs +40 -0
  63. package/lib/memorax-code-codebuddy-adapter/hooks/runtime-hook.mjs +289 -0
  64. package/lib/memorax-code-codebuddy-adapter/package.json +9 -0
  65. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/SKILL.md +85 -0
  66. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/claude.yaml +10 -0
  67. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/openai.yaml +7 -0
  68. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/defaults.json +12 -0
  69. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-add.md +88 -0
  70. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-search.md +93 -0
  71. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-read.md +46 -0
  72. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-write.md +120 -0
  73. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-build.md +319 -0
  74. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-read.md +103 -0
  75. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-templates.md +390 -0
  76. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-update.md +127 -0
  77. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
  78. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
  79. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
  80. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
  81. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
  82. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
  83. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
  84. package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
  85. package/lib/memorax-code-codebuddy-adapter/src/cli.mjs +58 -0
  86. package/lib/memorax-code-codebuddy-adapter/src/config.mjs +340 -0
  87. package/lib/memorax-code-codebuddy-adapter/src/hook-manifest.mjs +47 -0
  88. package/lib/memorax-code-codebuddy-adapter/src/runtime-observation.mjs +65 -0
  89. package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
  90. package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
  91. package/lib/memorax-code-codex-adapter/package.json +1 -1
  92. package/lib/memorax-code-codex-adapter/runtime-hooks/ensure-backend.mjs +4 -1
  93. package/lib/memorax-code-dsh-adapter/package.json +2 -1
  94. package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +1 -0
  95. package/lib/memorax-code-opencode-adapter/package.json +1 -1
  96. package/lib/npm-invocation.mjs +51 -8
  97. package/lib/resolve-codebuddy-command.mjs +123 -0
  98. package/lib/run-entrypoint.mjs +25 -1
  99. package/lib/windows-cli-invocation.mjs +11 -1
  100. package/lib/windows-user-path.mjs +218 -0
  101. package/package.json +5 -3
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env python3
2
+ """Extract local git commit facets without GitHub/GitLab provider access."""
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import re
8
+ import shutil
9
+ import subprocess
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import Any, Iterable
13
+ from urllib.parse import urlparse
14
+
15
+
16
+ def run_git(repo_path: Path, args: list[str]) -> subprocess.CompletedProcess[str]:
17
+ if shutil.which("git") is None:
18
+ raise SystemExit("git is required for local commit facets")
19
+ return subprocess.run(["git", "-C", str(repo_path), *args], text=True, capture_output=True)
20
+
21
+
22
+ def git_stdout(repo_path: Path, args: list[str], message: str) -> str:
23
+ result = run_git(repo_path, args)
24
+ if result.returncode != 0:
25
+ raise SystemExit(f"{message}:\n{result.stderr.strip()}")
26
+ return result.stdout
27
+
28
+
29
+ def resolve_snapshot_sha(repo_path: Path, snapshot_ref: str) -> str:
30
+ return git_stdout(
31
+ repo_path,
32
+ ["rev-parse", "--verify", f"{snapshot_ref}^{{commit}}"],
33
+ f"git could not resolve snapshot ref {snapshot_ref!r} in {repo_path}",
34
+ ).strip()
35
+
36
+
37
+ def normalize_remote_path(path: str) -> str:
38
+ repo_path = path.strip().lstrip("/").rstrip("/")
39
+ if repo_path.endswith(".git"):
40
+ repo_path = repo_path[:-4]
41
+ return repo_path
42
+
43
+
44
+ def repo_name_from_remote(url: str) -> str:
45
+ if not url:
46
+ return ""
47
+ if "://" not in url:
48
+ match = re.match(r"^(?:[^@/\s]+@)?[^:/\s]+:(?P<path>.+)$", url)
49
+ return normalize_remote_path(match.group("path")) if match else ""
50
+ parsed = urlparse(url)
51
+ return normalize_remote_path(parsed.path)
52
+
53
+
54
+ def repo_name(repo_path: Path) -> str:
55
+ remote = run_git(repo_path, ["remote", "get-url", "origin"])
56
+ parsed = repo_name_from_remote(remote.stdout.strip()) if remote.returncode == 0 else ""
57
+ return parsed or repo_path.name
58
+
59
+
60
+ def unique(values: Iterable[Any]) -> list[Any]:
61
+ seen: set[Any] = set()
62
+ out: list[Any] = []
63
+ for value in values:
64
+ if value in (None, "") or value in seen:
65
+ continue
66
+ seen.add(value)
67
+ out.append(value)
68
+ return out
69
+
70
+
71
+ def path_module(path: str) -> str:
72
+ parts = [part for part in path.split("/") if part and part not in {".", ".."}]
73
+ if not parts:
74
+ return ""
75
+ if parts[0] == ".github":
76
+ return ".github/workflows"
77
+ if "." in parts[0] and len(parts) == 1:
78
+ return ""
79
+ return parts[0]
80
+
81
+
82
+ def path_modules(files: list[str]) -> list[str]:
83
+ return unique(module for module in (path_module(path) for path in files) if module)
84
+
85
+
86
+ def key_files(files: list[str], limit: int = 8) -> list[str]:
87
+ def score(path: str) -> tuple[int, int, str]:
88
+ lower = path.lower()
89
+ value = 0
90
+ if "readme" in lower or lower.endswith((".md", ".rst")):
91
+ value += 2
92
+ if any(token in lower for token in ["/src/", "/core/", "/server", "/api", "/train", "/rollout", "/loss", "/model", "/actor", "/data"]):
93
+ value += 4
94
+ if lower.endswith((".py", ".ts", ".tsx", ".rs", ".go", ".sh", ".yaml", ".yml", ".toml", ".json")):
95
+ value += 1
96
+ return (-value, len(path), path)
97
+
98
+ return sorted(files, key=score)[:limit]
99
+
100
+
101
+ def bounded_summary(parts: Iterable[str], max_chars: int) -> str:
102
+ text = "\n\n".join(part.strip() for part in parts if isinstance(part, str) and part.strip())
103
+ return text if len(text) <= max_chars else text[: max_chars - 3] + "..."
104
+
105
+
106
+ def extract_symbols(text: str) -> list[str]:
107
+ symbols: list[str] = []
108
+ for match in re.finditer(r"\b[$A-Z_a-z][$\w]*\b", text):
109
+ value = match.group(0)
110
+ looks_symbolic = (
111
+ re.search(r"[a-z][A-Z]", value) is not None
112
+ or re.match(r"^[A-Z0-9_]{2,}$", value) is not None
113
+ or "_" in value
114
+ or "$" in value
115
+ )
116
+ if looks_symbolic:
117
+ symbols.append(value)
118
+ return unique(symbols)
119
+
120
+
121
+ def parse_numstat(text: str) -> tuple[list[str], int, int]:
122
+ files: list[str] = []
123
+ additions = 0
124
+ deletions = 0
125
+ for line in text.splitlines():
126
+ parts = line.split("\t")
127
+ if len(parts) < 3:
128
+ continue
129
+ add, delete, path = parts[0], parts[1], parts[2]
130
+ if add.isdigit():
131
+ additions += int(add)
132
+ if delete.isdigit():
133
+ deletions += int(delete)
134
+ if path:
135
+ files.append(path)
136
+ return unique(files), additions, deletions
137
+
138
+
139
+ def commit_facet(repo: str, repo_path: Path, sha: str, summary_chars: int) -> dict[str, Any]:
140
+ fields = git_stdout(
141
+ repo_path,
142
+ ["show", "-s", "--date=iso-strict", "--format=%H%x1f%h%x1f%P%x1f%an%x1f%ad%x1f%s", sha],
143
+ f"git could not read commit metadata for {sha}",
144
+ ).rstrip("\n").split("\x1f")
145
+ full_sha, short_sha, parents, author, authored_at, title = (fields + [""] * 6)[:6]
146
+ body = git_stdout(repo_path, ["show", "-s", "--format=%B", sha], f"git could not read commit body for {sha}")
147
+ files, additions, deletions = parse_numstat(
148
+ git_stdout(repo_path, ["show", "--format=", "--numstat", "--no-renames", sha], f"git could not read commit diff for {sha}")
149
+ )
150
+ modules = path_modules(files)
151
+ keys = key_files(files)
152
+ summary = bounded_summary([body], summary_chars) or title
153
+ evidence = unique([
154
+ f"commit {short_sha}: {title}" if short_sha and title else "",
155
+ f"commit {short_sha} changed {', '.join(keys)}" if short_sha and keys else "",
156
+ ])
157
+ return {
158
+ "facetId": f"commit.{short_sha or full_sha[:12]}",
159
+ "sourceType": "commit",
160
+ "provider": "local_git",
161
+ "repo": repo,
162
+ "sha": full_sha,
163
+ "short_sha": short_sha,
164
+ "parents": [parent for parent in parents.split() if parent],
165
+ "is_merge": len([parent for parent in parents.split() if parent]) > 1,
166
+ "title": title,
167
+ "summary": summary,
168
+ "author": author,
169
+ "authoredAt": authored_at,
170
+ "updatedAt": authored_at,
171
+ "files": files,
172
+ "path_modules": modules,
173
+ "key_files": keys,
174
+ "changed_files": len(files),
175
+ "additions": additions,
176
+ "deletions": deletions,
177
+ "symbols": extract_symbols("\n".join([title, summary, *files])),
178
+ "evidence": evidence,
179
+ }
180
+
181
+
182
+ def fetch_facets(repo_path: Path, snapshot_ref: str, limit: int, summary_chars: int) -> list[dict[str, Any]]:
183
+ snapshot_sha = resolve_snapshot_sha(repo_path, snapshot_ref)
184
+ shas = git_stdout(
185
+ repo_path,
186
+ ["rev-list", "--max-count", str(limit), snapshot_sha],
187
+ f"git could not list commits from {snapshot_ref!r} in {repo_path}",
188
+ ).splitlines()
189
+ name = repo_name(repo_path)
190
+ return [commit_facet(name, repo_path, sha.strip(), summary_chars) for sha in shas if sha.strip()]
191
+
192
+
193
+ def parse_args(argv: list[str]) -> argparse.Namespace:
194
+ parser = argparse.ArgumentParser(description="Extract local git commit SourceFacet JSON without provider login.")
195
+ parser.add_argument("--repo-path", default=".", help="Local git repository path")
196
+ parser.add_argument("--snapshot-ref", default="HEAD", help="Local git ref whose history should be collected")
197
+ parser.add_argument("--limit", type=int, default=30, help="Maximum commits retained from the snapshot history")
198
+ parser.add_argument("--summary-chars", type=int, default=4000)
199
+ parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON")
200
+ parser.add_argument("--out", help="Write JSON to this file instead of stdout")
201
+ args = parser.parse_args(argv)
202
+ if args.limit < 1 or args.limit > 500:
203
+ parser.error("--limit must be from 1 to 500")
204
+ if args.summary_chars < 100:
205
+ parser.error("--summary-chars must be at least 100")
206
+ args.repo_path = Path(args.repo_path).expanduser().resolve()
207
+ return args
208
+
209
+
210
+ def main(argv: list[str]) -> int:
211
+ args = parse_args(argv)
212
+ facets = fetch_facets(args.repo_path, args.snapshot_ref, args.limit, args.summary_chars)
213
+ text = json.dumps(facets, ensure_ascii=False, indent=2 if args.pretty else None)
214
+ if args.out:
215
+ Path(args.out).write_text(text + "\n", encoding="utf-8")
216
+ else:
217
+ print(text)
218
+ return 0
219
+
220
+
221
+ if __name__ == "__main__":
222
+ raise SystemExit(main(sys.argv[1:]))