@remnic/plugin-claude-code 1.0.1 → 9.3.517

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "remnic",
3
3
  "description": "Universal memory for AI agents — automatic recall, observation, and cross-agent knowledge sharing",
4
- "version": "1.0.0",
4
+ "version": "9.3.517",
5
5
  "author": "Joshua Warren",
6
6
  "homepage": "https://github.com/joshuaswarren/remnic",
7
7
  "repository": "https://github.com/joshuaswarren/remnic"
@@ -56,7 +56,87 @@ SESSION_ID="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write
56
56
  CWD="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(d.cwd||'')" "$INPUT" 2>/dev/null || echo "")"
57
57
  PROJECT_NAME="$(basename "$CWD" 2>/dev/null || echo "unknown")"
58
58
 
59
- log "session=$SESSION_ID project=$PROJECT_NAME"
59
+ # Resolve git context for the session's cwd (issue #569 PR 5). Produces
60
+ # either a JSON object for the `codingContext` field, or an empty string
61
+ # when the cwd is not inside a git repo. All git calls are wrapped in &&
62
+ # so any failure silently drops back to no-context.
63
+ CODING_CONTEXT_JSON=""
64
+ if [ -n "$CWD" ] && [ -d "$CWD" ] && command -v git >/dev/null 2>&1; then
65
+ # `git` calls are short-timeout and local. Any failure → empty.
66
+ REMNIC_GIT_TOP="$(git -C "$CWD" rev-parse --show-toplevel 2>/dev/null || echo "")"
67
+ if [ -n "$REMNIC_GIT_TOP" ]; then
68
+ REMNIC_GIT_BRANCH="$(git -C "$REMNIC_GIT_TOP" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")"
69
+ [ "$REMNIC_GIT_BRANCH" = "HEAD" ] && REMNIC_GIT_BRANCH=""
70
+ REMNIC_GIT_ORIGIN="$(git -C "$REMNIC_GIT_TOP" remote get-url origin 2>/dev/null || echo "")"
71
+ REMNIC_GIT_DEFAULT_BRANCH="$(git -C "$REMNIC_GIT_TOP" symbolic-ref --quiet refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||' || echo "")"
72
+ CODING_CONTEXT_JSON="$(REMNIC_GIT_TOP="$REMNIC_GIT_TOP" REMNIC_GIT_BRANCH="$REMNIC_GIT_BRANCH" REMNIC_GIT_ORIGIN="$REMNIC_GIT_ORIGIN" REMNIC_GIT_DEFAULT_BRANCH="$REMNIC_GIT_DEFAULT_BRANCH" node -e "
73
+ // Mirror the pure logic from @remnic/core's resolveGitContext so the
74
+ // hook produces the same projectId without calling into the daemon
75
+ // first. FNV-1a 32-bit stable hash.
76
+ const rootPath = process.env.REMNIC_GIT_TOP || '';
77
+ const branch = process.env.REMNIC_GIT_BRANCH || null;
78
+ const origin = process.env.REMNIC_GIT_ORIGIN || '';
79
+ const defaultBranch = process.env.REMNIC_GIT_DEFAULT_BRANCH || null;
80
+ function stableHash(input) {
81
+ let hash = 0x811c9dc5;
82
+ for (let i = 0; i < input.length; i++) {
83
+ hash ^= input.charCodeAt(i);
84
+ hash = Math.imul(hash, 0x01000193) >>> 0;
85
+ }
86
+ return hash.toString(16).padStart(8, '0');
87
+ }
88
+ // Mirrors packages/remnic-core/src/coding/git-context.ts
89
+ // normalizeOriginUrl. Keep the two in sync so the hook-computed
90
+ // projectId matches what the daemon computes on the same origin.
91
+ function normalizeOriginUrl(raw) {
92
+ let u = (raw || '').trim();
93
+ if (!u) return '';
94
+ // Case-insensitive .git strip — matches the TS canonical form.
95
+ if (/\\.git\$/i.test(u)) u = u.slice(0, -4);
96
+ // Windows drive-letter: short-circuit scp parsing.
97
+ if (/^[A-Za-z]:[\\\\/]/.test(u)) return u.toLowerCase();
98
+ // Protocol form: handles ssh://, https://, file:///, bracketed
99
+ // IPv6 hosts, optional user, optional port, and empty host
100
+ // (file:///path).
101
+ const proto = /^[a-z][a-z0-9+.-]*:\\/\\/(?:[^@/]+@)?(\\[[^\\]]+\\]|[^/:]*)(?::(\\d+))?(\\/.*)?\$/i.exec(u);
102
+ if (proto) {
103
+ let host = proto[1] || '';
104
+ const wasBracketed = host.startsWith('[') && host.endsWith(']');
105
+ if (wasBracketed) host = host.slice(1, -1);
106
+ const port = proto[2];
107
+ const p = (proto[3] || '').replace(/^\\/+/, '');
108
+ const hostPort = port
109
+ ? (wasBracketed ? '[' + host + ']:' + port : host + ':' + port)
110
+ : host;
111
+ const prefix = hostPort.length > 0 ? hostPort : 'localhost';
112
+ return (prefix + '/' + p).toLowerCase();
113
+ }
114
+ // scp form: [user@]host:path — user@ optional, bracketed IPv6 host
115
+ // supported. A matched path starting with // is a protocol-URL
116
+ // leftover and is rejected.
117
+ const scp = /^(?:([^@\\s\\/]+)@)?(\\[[^\\]]+\\]|[^:@\\s\\/]+):(.+)\$/.exec(u);
118
+ if (scp) {
119
+ let host = scp[2] || '';
120
+ if (host.startsWith('[') && host.endsWith(']')) host = host.slice(1, -1);
121
+ const p = scp[3] || '';
122
+ if (p.startsWith('//')) return u.toLowerCase();
123
+ return (host + '/' + p.replace(/^\\/+/, '')).toLowerCase();
124
+ }
125
+ return u.toLowerCase();
126
+ }
127
+ const normalized = normalizeOriginUrl(origin);
128
+ const projectId = normalized ? 'origin:' + stableHash(normalized) : 'root:' + stableHash(rootPath);
129
+ process.stdout.write(JSON.stringify({
130
+ projectId,
131
+ branch: branch || null,
132
+ rootPath,
133
+ defaultBranch: defaultBranch || null,
134
+ }));
135
+ " 2>/dev/null || echo "")"
136
+ fi
137
+ fi
138
+
139
+ log "session=$SESSION_ID project=$PROJECT_NAME coding-context=${CODING_CONTEXT_JSON:+yes}"
60
140
 
61
141
  # Health check — start daemon if not running
62
142
  if ! curl -sf --max-time 2 "$REMNIC_HEALTH_URL" >/dev/null 2>&1; then
@@ -82,12 +162,29 @@ fi
82
162
 
83
163
  QUERY="Starting a new coding session in project: ${PROJECT_NAME}. Recall relevant memories, preferences, decisions, patterns, and context about this project and the user."
84
164
 
85
- REQUEST_BODY="$(node -e "process.stdout.write(JSON.stringify({
86
- query: process.argv[1],
87
- sessionKey: process.argv[2],
88
- topK: 12,
89
- mode: 'auto'
90
- }))" "$QUERY" "$SESSION_ID" 2>/dev/null)"
165
+ REQUEST_BODY="$(REMNIC_CODING_CONTEXT_JSON="$CODING_CONTEXT_JSON" node -e "
166
+ const body = {
167
+ query: process.argv[1],
168
+ sessionKey: process.argv[2],
169
+ topK: 12,
170
+ mode: 'auto',
171
+ };
172
+ const raw = process.env.REMNIC_CODING_CONTEXT_JSON || '';
173
+ if (raw) {
174
+ try { body.codingContext = JSON.parse(raw); } catch (_) {
175
+ // Context envelope was provided but failed to parse. Explicitly
176
+ // clear any previously-attached context for this session so a
177
+ // malformed envelope does not silently keep stale state.
178
+ body.codingContext = null;
179
+ }
180
+ } else {
181
+ // No git context resolvable for this cwd. Explicitly clear any
182
+ // previously-attached context so a session that moves out of a repo
183
+ // does not keep routing to the old project namespace.
184
+ body.codingContext = null;
185
+ }
186
+ process.stdout.write(JSON.stringify(body));
187
+ " "$QUERY" "$SESSION_ID" 2>/dev/null)"
91
188
 
92
189
  [ -z "$REQUEST_BODY" ] && echo '{"continue":true}' && exit 0
93
190
 
@@ -104,12 +201,19 @@ RESPONSE="$(echo "$RAW" | sed '$d')"
104
201
 
105
202
  if [ $CURL_EXIT -ne 0 ] || ! [[ "$HTTP_STATUS" =~ ^2 ]] || [ -z "$RESPONSE" ]; then
106
203
  log "full recall failed (curl=$CURL_EXIT http=$HTTP_STATUS) — falling back to minimal"
107
- MINIMAL_BODY="$(node -e "process.stdout.write(JSON.stringify({
108
- query: process.argv[1],
109
- sessionKey: process.argv[2],
110
- topK: 8,
111
- mode: 'minimal'
112
- }))" "$QUERY" "$SESSION_ID" 2>/dev/null)"
204
+ MINIMAL_BODY="$(REMNIC_CODING_CONTEXT_JSON="$CODING_CONTEXT_JSON" node -e "
205
+ const body = {
206
+ query: process.argv[1],
207
+ sessionKey: process.argv[2],
208
+ topK: 8,
209
+ mode: 'minimal',
210
+ };
211
+ const raw = process.env.REMNIC_CODING_CONTEXT_JSON || '';
212
+ if (raw) {
213
+ try { body.codingContext = JSON.parse(raw); } catch (_) { /* ignore */ }
214
+ }
215
+ process.stdout.write(JSON.stringify(body));
216
+ " "$QUERY" "$SESSION_ID" 2>/dev/null)"
113
217
  RAW="$(curl -s -w "\n%{http_code}" --max-time 20 \
114
218
  -X POST "$REMNIC_URL" \
115
219
  -H "Authorization: Bearer ${REMNIC_TOKEN}" \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/plugin-claude-code",
3
- "version": "1.0.1",
3
+ "version": "9.3.517",
4
4
  "description": "Remnic memory plugin for Claude Code — hooks, skills, MCP integration",
5
5
  "type": "module",
6
6
  "license": "MIT",