mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-10-31 07:29:03 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38019327f5 | ||
|
|
c3b5bce5f5 | ||
|
|
0845aeb58a | ||
|
|
92d92ecadb | ||
|
|
ab0c9a01ef | ||
|
|
f19c247278 |
@@ -7,7 +7,7 @@ replace github.com/sugarme/tokenizer => github.com/clems4ever/tokenizer v0.0.0-2
|
||||
require (
|
||||
github.com/asg017/sqlite-vec-go-bindings v0.1.6
|
||||
github.com/fsnotify/fsnotify v1.10.1
|
||||
github.com/go-chi/chi/v5 v5.3.2
|
||||
github.com/go-chi/chi/v5 v5.4.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.7
|
||||
github.com/goccy/go-json v0.11.2
|
||||
github.com/lukaszraczylo/oss-telemetry v0.2.5
|
||||
|
||||
@@ -8,8 +8,8 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
|
||||
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/chi/v5 v5.4.0 h1:+ufzvFTGKyin26Or5DLrlIDq4ygIDBVcj7oVNeeaYFE=
|
||||
github.com/go-chi/chi/v5 v5.4.0/go.mod h1:d1IG7GtKPSjPyBP365PH8sAGVHk3qfB/IhjFNRH1wWM=
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.7 h1:PdT4jVPbRb4R+0Ey2R0yJOdctVf4Whiq1Qi4necaZdg=
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.7/go.mod h1:3ouXglTuPrKF5+7cQyVGfvAXTU4vLMaYh9+EPl03uog=
|
||||
github.com/goccy/go-json v0.11.2 h1:jdZv93Tt4ioR8yW1CoNsvSxrcZlCXAUU1aZXN7gpXUA=
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
//go:build fts5
|
||||
|
||||
package gorm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/lukaszraczylo/claude-mnemonic/pkg/models"
|
||||
)
|
||||
|
||||
// An archived note is kept, but it must stay out of search, context, lists, counts and the vector rebuild, and an
|
||||
// export (which asks for it) still has it.
|
||||
func TestArchivedObservationsAreKeptButHiddenEverywhereExceptAnExport(t *testing.T) {
|
||||
s, store, cleanup := testObservationStore(t)
|
||||
defer cleanup()
|
||||
ctx := context.Background()
|
||||
|
||||
var ids []int64
|
||||
for _, title := range []string{"Zebra ledger reconciliation", "Quokka deployment checklist", "Ocelot retry budget"} {
|
||||
id, _, err := s.StoreObservation(ctx, "claude-1", "proj",
|
||||
&models.ParsedObservation{Type: models.ObsTypeDiscovery, Title: title, Narrative: title + " notes"}, 1, 10)
|
||||
require.NoError(t, err)
|
||||
ids = append(ids, id)
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}
|
||||
archivedID := ids[0] // the zebra note
|
||||
require.NoError(t, s.ArchiveObservation(ctx, archivedID, "test"))
|
||||
|
||||
has := func(obs []*models.Observation) bool {
|
||||
for _, o := range obs {
|
||||
if o.ID == archivedID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
recent, err := s.GetRecentObservations(ctx, "proj", 10)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(recent), "context injection does not see it")
|
||||
|
||||
strict, err := s.GetObservationsByProjectStrict(ctx, "proj", 10)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(strict))
|
||||
|
||||
all, err := s.GetAllRecentObservations(ctx, 10)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(all))
|
||||
|
||||
byID, err := s.GetObservationsByIDs(ctx, ids, "default", 0)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(byID), "a vector hit for it is dropped when it is loaded")
|
||||
assert.Len(t, byID, 2)
|
||||
|
||||
ordered, err := s.GetObservationsByIDsPreserveOrder(ctx, ids)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(ordered))
|
||||
|
||||
fts, err := s.SearchObservationsFTS(ctx, "zebra ledger", "proj", 10)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(fts), "full-text search does not find it")
|
||||
other, err := s.SearchObservationsFTS(ctx, "quokka deployment", "proj", 10)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, other, 1, "and still finds the others")
|
||||
|
||||
n, err := s.GetObservationCount(ctx, "proj")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, n, "the count is of notes that can be used")
|
||||
|
||||
rebuild, err := s.GetAllObservations(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(rebuild), "a vector rebuild does not put it back into the index")
|
||||
|
||||
listed, total, err := s.GetAllRecentObservationsPaginated(ctx, 10, 0, false)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(listed))
|
||||
assert.EqualValues(t, 2, total)
|
||||
projListed, projTotal, err := s.GetObservationsByProjectStrictPaginated(ctx, "proj", 10, 0, false)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, has(projListed))
|
||||
assert.EqualValues(t, 2, projTotal)
|
||||
|
||||
exported, total, err := s.GetAllRecentObservationsPaginated(ctx, 10, 0, true)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, has(exported), "an export asks for them")
|
||||
assert.EqualValues(t, 3, total)
|
||||
projExported, _, err := s.GetObservationsByProjectStrictPaginated(ctx, "proj", 10, 0, true)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, has(projExported))
|
||||
|
||||
// Kept: the row is still there, and restoring it makes it visible again.
|
||||
one, err := s.GetObservationByID(ctx, archivedID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, one)
|
||||
require.NoError(t, s.UnarchiveObservation(ctx, archivedID))
|
||||
back, err := s.SearchObservationsFTS(ctx, "zebra ledger", "proj", 10)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, has(back))
|
||||
var rows int64
|
||||
require.NoError(t, store.DB.Model(&Observation{}).Where("project = ?", "proj").Count(&rows).Error)
|
||||
assert.EqualValues(t, 3, rows)
|
||||
}
|
||||
@@ -290,7 +290,7 @@ func (s *ObservationStore) GetObservationsByIDs(ctx context.Context, ids []int64
|
||||
}
|
||||
|
||||
var dbObservations []Observation
|
||||
query := s.db.WithContext(ctx).Where("id IN ?", ids)
|
||||
query := s.db.WithContext(ctx).Scopes(notArchivedFilter()).Where("id IN ?", ids)
|
||||
|
||||
// Apply ordering
|
||||
switch orderBy {
|
||||
@@ -329,7 +329,7 @@ func (s *ObservationStore) GetObservationsByIDsPreserveOrder(ctx context.Context
|
||||
|
||||
// Fetch all observations in a single query
|
||||
var dbObservations []Observation
|
||||
err := s.db.WithContext(ctx).Where("id IN ?", ids).Find(&dbObservations).Error
|
||||
err := s.db.WithContext(ctx).Scopes(notArchivedFilter()).Where("id IN ?", ids).Find(&dbObservations).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -380,7 +380,7 @@ func (s *ObservationStore) BatchGetObservationsWithScores(ctx context.Context, i
|
||||
func (s *ObservationStore) GetRecentObservations(ctx context.Context, project string, limit int) ([]*models.Observation, error) {
|
||||
var dbObservations []Observation
|
||||
err := s.db.WithContext(ctx).
|
||||
Scopes(projectScopeFilter(project), importanceOrdering()).
|
||||
Scopes(projectScopeFilter(project), notArchivedFilter(), importanceOrdering()).
|
||||
Limit(limit).
|
||||
Find(&dbObservations).Error
|
||||
|
||||
@@ -430,7 +430,7 @@ func (s *ObservationStore) GetObservationsByProjectStrict(ctx context.Context, p
|
||||
var dbObservations []Observation
|
||||
err := s.db.WithContext(ctx).
|
||||
Where("project = ?", project).
|
||||
Scopes(importanceOrdering()).
|
||||
Scopes(notArchivedFilter(), importanceOrdering()).
|
||||
Limit(limit).
|
||||
Find(&dbObservations).Error
|
||||
|
||||
@@ -447,6 +447,7 @@ func (s *ObservationStore) GetObservationCount(ctx context.Context, project stri
|
||||
err := s.db.WithContext(ctx).
|
||||
Model(&Observation{}).
|
||||
Where("project = ?", project).
|
||||
Scopes(notArchivedFilter()).
|
||||
Count(&count).Error
|
||||
|
||||
return int(count), err
|
||||
@@ -456,7 +457,7 @@ func (s *ObservationStore) GetObservationCount(ctx context.Context, project stri
|
||||
func (s *ObservationStore) GetAllRecentObservations(ctx context.Context, limit int) ([]*models.Observation, error) {
|
||||
var dbObservations []Observation
|
||||
err := s.db.WithContext(ctx).
|
||||
Scopes(importanceOrdering()).
|
||||
Scopes(notArchivedFilter(), importanceOrdering()).
|
||||
Limit(limit).
|
||||
Find(&dbObservations).Error
|
||||
|
||||
@@ -467,19 +468,21 @@ func (s *ObservationStore) GetAllRecentObservations(ctx context.Context, limit i
|
||||
return toModelObservations(dbObservations), nil
|
||||
}
|
||||
|
||||
// GetAllRecentObservationsPaginated retrieves recent observations with pagination.
|
||||
func (s *ObservationStore) GetAllRecentObservationsPaginated(ctx context.Context, limit, offset int) ([]*models.Observation, int64, error) {
|
||||
// GetAllRecentObservationsPaginated retrieves recent observations with pagination. Archived notes are left out unless
|
||||
// includeArchived is set (an export asks for them).
|
||||
func (s *ObservationStore) GetAllRecentObservationsPaginated(ctx context.Context, limit, offset int, includeArchived bool) ([]*models.Observation, int64, error) {
|
||||
var dbObservations []Observation
|
||||
var total int64
|
||||
visible := visibleScope(includeArchived)
|
||||
|
||||
// Get total count
|
||||
if err := s.db.WithContext(ctx).Model(&Observation{}).Count(&total).Error; err != nil {
|
||||
if err := s.db.WithContext(ctx).Model(&Observation{}).Scopes(visible).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
err := s.db.WithContext(ctx).
|
||||
Scopes(importanceOrdering()).
|
||||
Scopes(visible, importanceOrdering()).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&dbObservations).Error
|
||||
@@ -491,20 +494,22 @@ func (s *ObservationStore) GetAllRecentObservationsPaginated(ctx context.Context
|
||||
return toModelObservations(dbObservations), total, nil
|
||||
}
|
||||
|
||||
// GetObservationsByProjectStrictPaginated retrieves observations strictly from a project with pagination.
|
||||
func (s *ObservationStore) GetObservationsByProjectStrictPaginated(ctx context.Context, project string, limit, offset int) ([]*models.Observation, int64, error) {
|
||||
// GetObservationsByProjectStrictPaginated retrieves observations strictly from a project with pagination. Archived notes
|
||||
// are left out unless includeArchived is set (an export asks for them).
|
||||
func (s *ObservationStore) GetObservationsByProjectStrictPaginated(ctx context.Context, project string, limit, offset int, includeArchived bool) ([]*models.Observation, int64, error) {
|
||||
var dbObservations []Observation
|
||||
var total int64
|
||||
visible := visibleScope(includeArchived)
|
||||
|
||||
// Get total count for project
|
||||
if err := s.db.WithContext(ctx).Model(&Observation{}).Where("project = ?", project).Count(&total).Error; err != nil {
|
||||
if err := s.db.WithContext(ctx).Model(&Observation{}).Where("project = ?", project).Scopes(visible).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
err := s.db.WithContext(ctx).
|
||||
Where("project = ?", project).
|
||||
Scopes(importanceOrdering()).
|
||||
Scopes(visible, importanceOrdering()).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&dbObservations).Error
|
||||
@@ -516,11 +521,13 @@ func (s *ObservationStore) GetObservationsByProjectStrictPaginated(ctx context.C
|
||||
return toModelObservations(dbObservations), total, nil
|
||||
}
|
||||
|
||||
// GetAllObservations retrieves all observations (for vector rebuild).
|
||||
// GetAllObservations retrieves all observations that are not archived (for vector rebuild: an archived note stays out of
|
||||
// the vector index).
|
||||
// Note: For large datasets, prefer GetAllObservationsIterator to avoid memory issues.
|
||||
func (s *ObservationStore) GetAllObservations(ctx context.Context) ([]*models.Observation, error) {
|
||||
var dbObservations []Observation
|
||||
err := s.db.WithContext(ctx).
|
||||
Scopes(notArchivedFilter()).
|
||||
Order("id").
|
||||
Find(&dbObservations).Error
|
||||
|
||||
@@ -606,6 +613,7 @@ func (s *ObservationStore) SearchObservationsFTS(ctx context.Context, query, pro
|
||||
JOIN observations_fts fts ON o.id = fts.rowid
|
||||
WHERE observations_fts MATCH ?
|
||||
AND (o.project = ? OR o.scope = 'global')
|
||||
AND COALESCE(o.is_archived, 0) = 0
|
||||
ORDER BY rank, COALESCE(o.importance_score, 1.0) DESC
|
||||
LIMIT ?
|
||||
`
|
||||
@@ -660,7 +668,7 @@ func (s *ObservationStore) searchObservationsLike(ctx context.Context, keywords
|
||||
|
||||
// Build WHERE clause
|
||||
whereClause := strings.Join(conditions, " OR ")
|
||||
fullWhere := "(" + whereClause + ") AND (project = ? OR scope = 'global')"
|
||||
fullWhere := "(" + whereClause + ") AND (project = ? OR scope = 'global') AND COALESCE(is_archived, 0) = 0"
|
||||
args = append(args, project)
|
||||
|
||||
var dbObservations []Observation
|
||||
@@ -958,6 +966,21 @@ func projectScopeFilter(project string) func(*gorm.DB) *gorm.DB {
|
||||
}
|
||||
}
|
||||
|
||||
// notArchivedFilter hides archived notes: an archived note is kept, but it must stay out of search, context and lists.
|
||||
func notArchivedFilter() func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("COALESCE(is_archived, 0) = 0")
|
||||
}
|
||||
}
|
||||
|
||||
// visibleScope hides archived notes unless they are asked for (an export keeps them; lists and counts do not).
|
||||
func visibleScope(includeArchived bool) func(*gorm.DB) *gorm.DB {
|
||||
if includeArchived {
|
||||
return func(db *gorm.DB) *gorm.DB { return db }
|
||||
}
|
||||
return notArchivedFilter()
|
||||
}
|
||||
|
||||
// activeObservationFilter filters for active (non-archived, non-superseded) observations.
|
||||
// This is more efficient than chaining notSupersededFilter + notArchivedFilter
|
||||
// as it produces a single WHERE clause for the query optimizer.
|
||||
|
||||
@@ -28,6 +28,8 @@ func (s *Service) handleGetObservations(w http.ResponseWriter, r *http.Request)
|
||||
pagination := gorm.ParsePaginationParams(r, DefaultObservationsLimit)
|
||||
project := r.URL.Query().Get("project")
|
||||
query := r.URL.Query().Get("query")
|
||||
// Archived notes are not listed unless asked for.
|
||||
includeArchived := r.URL.Query().Get("include_archived") == "true"
|
||||
|
||||
// Validate project name to prevent path traversal
|
||||
if err := ValidateProjectName(project); err != nil {
|
||||
@@ -60,10 +62,10 @@ func (s *Service) handleGetObservations(w http.ResponseWriter, r *http.Request)
|
||||
if !usedVector {
|
||||
if project != "" {
|
||||
// Strict project filtering for dashboard - only observations from this project
|
||||
observations, total, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, pagination.Limit, pagination.Offset)
|
||||
observations, total, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, pagination.Limit, pagination.Offset, includeArchived)
|
||||
} else {
|
||||
// All projects
|
||||
observations, total, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, pagination.Limit, pagination.Offset)
|
||||
observations, total, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, pagination.Limit, pagination.Offset, includeArchived)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,8 @@ func (s *Service) handleArchiveObservations(w http.ResponseWriter, r *http.Reque
|
||||
Int("failed", len(failedIDs)).
|
||||
Msg("Observations archived")
|
||||
|
||||
s.dropArchivedFromVectors(archivedIDs)
|
||||
|
||||
// Invalidate cache if any observations were archived
|
||||
if len(archivedIDs) > 0 {
|
||||
if req.Project != "" {
|
||||
@@ -322,6 +324,22 @@ func (s *Service) handleArchiveObservations(w http.ResponseWriter, r *http.Reque
|
||||
writeJSON(w, response)
|
||||
}
|
||||
|
||||
// dropArchivedFromVectors takes archived notes out of the vector index, so search cannot return them (unarchiving puts
|
||||
// them back). Every path that archives notes calls it.
|
||||
func (s *Service) dropArchivedFromVectors(ids []int64) {
|
||||
if len(ids) == 0 || s.vectorSync == nil {
|
||||
return
|
||||
}
|
||||
ids = append([]int64(nil), ids...)
|
||||
s.asyncVectorSync(func() {
|
||||
ctx, cancel := context.WithTimeout(s.ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
if err := s.vectorSync.DeleteObservations(ctx, ids); err != nil && s.ctx.Err() == nil {
|
||||
log.Warn().Err(err).Int("count", len(ids)).Msg("Failed to drop archived observations from sqlite-vec")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// handleUnarchiveObservation restores an archived observation.
|
||||
func (s *Service) handleUnarchiveObservation(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := chi.URLParam(r, "id")
|
||||
@@ -336,6 +354,21 @@ func (s *Service) handleUnarchiveObservation(w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
// Archiving dropped the note's vectors; put them back so search finds it again.
|
||||
if s.vectorSync != nil {
|
||||
s.asyncVectorSync(func() {
|
||||
ctx, cancel := context.WithTimeout(s.ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
obs, err := s.observationStore.GetObservationByID(ctx, id)
|
||||
if err != nil || obs == nil {
|
||||
return
|
||||
}
|
||||
if err := s.vectorSync.SyncObservation(ctx, obs); err != nil && s.ctx.Err() == nil {
|
||||
log.Warn().Err(err).Int64("id", id).Msg("Failed to restore an unarchived observation to sqlite-vec")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Invalidate all caches since we don't know the project
|
||||
s.invalidateAllObsCountCache()
|
||||
|
||||
@@ -400,9 +433,9 @@ func (s *Service) handleExportObservations(w http.ResponseWriter, r *http.Reques
|
||||
var err error
|
||||
|
||||
if project != "" {
|
||||
observations, _, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, limit, 0)
|
||||
observations, _, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, limit, 0, true)
|
||||
} else {
|
||||
observations, _, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, limit, 0)
|
||||
observations, _, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, limit, 0, true)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -531,14 +564,17 @@ func (s *Service) handleBulkStatusUpdate(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
case "archive":
|
||||
var archivedIDs []int64
|
||||
for _, id := range req.IDs {
|
||||
if err := s.observationStore.ArchiveObservation(ctx, id, req.Reason); err != nil {
|
||||
failed++
|
||||
errors = append(errors, fmt.Sprintf("id %d: %v", id, err))
|
||||
} else {
|
||||
updated++
|
||||
archivedIDs = append(archivedIDs, id)
|
||||
}
|
||||
}
|
||||
s.dropArchivedFromVectors(archivedIDs)
|
||||
|
||||
case "set_feedback":
|
||||
if req.Feedback < -1 || req.Feedback > 1 {
|
||||
@@ -598,9 +634,9 @@ func (s *Service) handleFindDuplicates(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
|
||||
if project != "" {
|
||||
observations, _, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, limit, 0)
|
||||
observations, _, err = s.observationStore.GetObservationsByProjectStrictPaginated(ctx, project, limit, 0, true)
|
||||
} else {
|
||||
observations, _, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, limit, 0)
|
||||
observations, _, err = s.observationStore.GetAllRecentObservationsPaginated(ctx, limit, 0, true)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
+10
-10
@@ -13,7 +13,7 @@
|
||||
{
|
||||
"name": "claude-mnemonic",
|
||||
"description": "Persistent memory system for Claude Code - Go implementation with SQLite and ChromaDB vector search",
|
||||
"version": "0.21.123",
|
||||
"version": "0.21.135",
|
||||
"author": {
|
||||
"name": "lukaszraczylo",
|
||||
"url": "https://github.com/lukaszraczylo"
|
||||
@@ -23,25 +23,25 @@
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/lukaszraczylo/claude-mnemonic",
|
||||
"releases": {
|
||||
"latest": "0.21.123",
|
||||
"latest": "0.21.135",
|
||||
"versions": {
|
||||
"0.21.123": {
|
||||
"releaseDate": "2026-10-11",
|
||||
"0.21.135": {
|
||||
"releaseDate": "2026-10-13",
|
||||
"downloads": {
|
||||
"darwin-arm64": {
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.123/claude-mnemonic_0.21.123_darwin_arm64.tar.gz",
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.135/claude-mnemonic_0.21.135_darwin_arm64.tar.gz",
|
||||
"format": "tar.gz",
|
||||
"sha256": "ea212ba91313cc1385848aafa000f975179d0e925d289cd7fcc8bf829e883fa8"
|
||||
"sha256": "53e8c356e9ae8de276c149dce75792fe74eeb8d9a896ef4e7bbfb458126631f4"
|
||||
},
|
||||
"linux-amd64": {
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.123/claude-mnemonic_0.21.123_linux_amd64.tar.gz",
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.135/claude-mnemonic_0.21.135_linux_amd64.tar.gz",
|
||||
"format": "tar.gz",
|
||||
"sha256": "2ffe3f550422e899887bf8526210cb1aa8a3fe5f062387aac047b8faeb38e464"
|
||||
"sha256": "c7de792c2e943f0c7f504b145b11330ed29b41a77d58e3b3b2c4df2364ff1ef6"
|
||||
},
|
||||
"windows-amd64": {
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.123/claude-mnemonic_0.21.123_windows_amd64.zip",
|
||||
"url": "https://github.com/lukaszraczylo/claude-mnemonic/releases/download/v0.21.135/claude-mnemonic_0.21.135_windows_amd64.zip",
|
||||
"format": "zip",
|
||||
"sha256": "dc517e197cc0395ef6f846e911078ac11dc24f0697c863ba05d5bf2cc156b760"
|
||||
"sha256": "02850c046476b0bd6dc9bff84450c1f4ec6599098b0627431f7ef41b190c6968"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+18
-18
@@ -812,9 +812,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "6.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz",
|
||||
"integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==",
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.10.tgz",
|
||||
"integrity": "sha512-b80aUQh3n+qEzzZm5oQp3rT2QImeCx58K6eFl/RkJ3d65KW0kTuv5lNsLRVAjbW9YRUpo/wzmvzMgV34bTAItA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -825,7 +825,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||
"vue": "^3.2.25"
|
||||
"vue": "^3.2.25 || ^3.6.0-rc.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
@@ -908,9 +908,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.12.tgz",
|
||||
"integrity": "sha512-k7uIKR0n4CBidk233y7cac9osnDQ5WRidTl6nsrNvpZ3nf8cx9iJxRVsRzVsoPRHbowT/iKgGMTS9RGov3jeIA==",
|
||||
"version": "3.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.13.tgz",
|
||||
"integrity": "sha512-axA0Xemn5LuUKuKWob0/kVq7xQ2mJJM6VqA9Exvt35nM9yRC31goWVve/G/Zb2ZCLsXC8FHYjjfXlnshknSCew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1386,9 +1386,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.19",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz",
|
||||
"integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==",
|
||||
"version": "3.3.20",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
|
||||
"integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -1430,9 +1430,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.29",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz",
|
||||
"integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==",
|
||||
"version": "8.5.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz",
|
||||
"integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -1449,7 +1449,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.19",
|
||||
"nanoid": "^3.3.20",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.2"
|
||||
},
|
||||
@@ -2003,14 +2003,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.12.tgz",
|
||||
"integrity": "sha512-kbpaz18O9jPVkXVHD1BEjpUXM6WhXSu+62L1sGGr6Wbzd8GbvkBQWjoj3KZ/C0aq2MZllce7UdtWzwCIYsBMGA==",
|
||||
"version": "3.3.13",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.13.tgz",
|
||||
"integrity": "sha512-jE4/bXdOMSHVxEGgQCqNllJy+9N3Gx6tfSAsg0yhFK/MAN6eXqISihupnDEKSCt12VVnjN2gI3AqLYcqoh5x/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@volar/typescript": "2.4.28",
|
||||
"@vue/language-core": "3.3.12"
|
||||
"@vue/language-core": "3.3.13"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
|
||||
Reference in New Issue
Block a user