Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: en-US

early_access: true

issue_enrichment:
auto_enrich:
enabled: true

reviews:
profile: assertive
request_changes_workflow: false
high_level_summary_in_walkthrough: true
fail_commit_status: true
suggested_labels: false
auto_assign_reviewers: true
profile: chill
request_changes_workflow: true
high_level_summary: true
review_status: true
changed_files_summary: true
Expand All @@ -13,9 +23,41 @@ reviews:
enabled: true
drafts: false
auto_incremental_review: true
auto_pause_after_reviewed_commits: 0
base_branches:
- ".*"
path_instructions:
- path: package.json
instructions: |
do not allow any carats in package.json, we never want any auto updates for any patch versions of any
packages in package.json
- path: "**"
instructions: |
always check the stack if there is one for the current PR. do not give localized reviews for the PR,
always see all changes in the light of the whole stack of PRs (if there is a stack, if there is no stack you can
continue to make localized suggestions/reviews)
- path: "**/*.go"
instructions: |
Rule: No raw context keys in Go.

When reviewing code, ALWAYS check for incorrect usage of context values.

Reject or flag the change if you find ANY of the following:
- context.WithValue(ctx, "someKey", value) // string literal key
- context.WithValue(ctx, someStringVar, value) // key is type string
- context.WithValue(ctx, fmt.Sprintf(...), value) // computed/dynamic string key
- ctx.Value("someKey") or ctx.Value(someStringVar) // same problem on retrieval

Required pattern:
- Context keys MUST be a dedicated named type (NOT plain string), e.g.
- type contextKey string
const userIDKey contextKey = "userId"
OR
- type userIDKeyType struct{}
var userIDKey userIDKeyType

- The key passed to WithValue/Value MUST be that typed identifier, e.g.
- ctx = context.WithValue(ctx, userIDKey, userID)
- path: "core/**"
instructions: |
Review Go core changes for concurrency safety, provider isolation, pooled object reset discipline, and plugin hook ordering.
Expand Down
70 changes: 70 additions & 0 deletions framework/configstore/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ func triggerMigrations(ctx context.Context, db *gorm.DB) error {
if err := migrationAddPromptRepoTables(ctx, db); err != nil {
return err
}
if err := migrationAddSkillsRepoTables(ctx, db); err != nil {
return err
}
if err := migrationAddPluginOrderColumns(ctx, db); err != nil {
return err
}
Expand Down Expand Up @@ -6575,6 +6578,73 @@ func migrationAddMCPClientAllowedExtraHeadersJSONColumn(ctx context.Context, db
return nil
}

// migrationAddSkillsRepoTables adds the skills repository tables.
// Files belong to skill_versions (not directly to skills); blobs are reused
// across versions via shared blob_id/storage_key references.
//
// Idempotent: guards each table create so retrying after a partially applied
// migration does not fail when some tables were already created.
Comment thread
danpiths marked this conversation as resolved.
func migrationAddSkillsRepoTables(ctx context.Context, db *gorm.DB) error {
m := migrator.New(db, migrator.DefaultOptions, []*migrator.Migration{{
ID: "add_skills_repo_tables",
Migrate: func(tx *gorm.DB) error {
tx = tx.WithContext(ctx)
mg := tx.Migrator()

// --- skills table ---
if !mg.HasTable(&tables.TableSkill{}) {
if err := mg.CreateTable(&tables.TableSkill{}); err != nil {
return fmt.Errorf("create skills table: %w", err)
}
}

// --- skill_versions table ---
if !mg.HasTable(&tables.TableSkillVersion{}) {
if err := mg.CreateTable(&tables.TableSkillVersion{}); err != nil {
return fmt.Errorf("create skill_versions table: %w", err)
}
}

// --- skill_file_blobs table ---
if !mg.HasTable(&tables.TableSkillFileBlob{}) {
if err := mg.CreateTable(&tables.TableSkillFileBlob{}); err != nil {
return fmt.Errorf("create skill_file_blobs table: %w", err)
}
}

// --- skill_files table ---
if !mg.HasTable(&tables.TableSkillFile{}) {
if err := mg.CreateTable(&tables.TableSkillFile{}); err != nil {
return fmt.Errorf("create skill_files table: %w", err)
}
}

return nil
},
Rollback: func(tx *gorm.DB) error {
tx = tx.WithContext(ctx)
mg := tx.Migrator()
if err := mg.DropTable(&tables.TableSkillFile{}); err != nil {
return err
}
if err := mg.DropTable(&tables.TableSkillVersion{}); err != nil {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return err
}
if err := mg.DropTable(&tables.TableSkill{}); err != nil {
return err
}
if err := mg.DropTable(&tables.TableSkillFileBlob{}); err != nil {
return err
}
return nil
Comment thread
danpiths marked this conversation as resolved.
},
}})
if err := m.Migrate(); err != nil {
return fmt.Errorf("error while running skills repo tables migration: %s", err.Error())
}
return nil
}

// migrationAddPluginOrderColumns adds placement and exec_order columns to config_plugins table
func migrationAddPluginOrderColumns(ctx context.Context, db *gorm.DB) error {
m := migrator.New(db, migrator.DefaultOptions, []*migrator.Migration{{
Expand Down
77 changes: 77 additions & 0 deletions framework/configstore/rdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,83 @@ func TestUpsertMCPLibraryEntry(t *testing.T) {
require.Equal(t, "updated", entries[0].Description)
}

func TestValidateSkillVersionIncrementRequiresGreaterVersion(t *testing.T) {
tests := []struct {
name string
latest string
next string
wantErr bool
}{
{name: "rejects lower prerelease core", latest: "1.0.3", next: "1.0.2-1", wantErr: true},
{name: "accepts same core with suffix after release", latest: "1.0.3", next: "1.0.3-1", wantErr: false},
{name: "accepts release after same core suffix", latest: "1.0.3-beta1", next: "1.0.3", wantErr: false},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{name: "accepts higher patch", latest: "1.0.3", next: "1.0.4", wantErr: false},
{name: "accepts higher minor", latest: "1.0.3", next: "1.1.0", wantErr: false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateSkillVersionIncrement(tt.latest, tt.next)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

func TestLatestCreatedSkillVersionUsesCreationOrder(t *testing.T) {
store := setupRDBTestStore(t)
err := store.DB().AutoMigrate(
&tables.TableSkill{},
&tables.TableSkillVersion{},
&tables.TableSkillFile{},
&tables.TableSkillFileBlob{},
)
require.NoError(t, err)
ctx := context.Background()
baseTime := time.Now()

skillID := "skill-latest-created"
err = store.DB().Create(&tables.TableSkill{
ID: skillID,
Name: "latest-created",
Description: "Latest created version test",
SkillMDBody: "body",
LatestVersion: "1.0.3",
CreatedAt: baseTime,
UpdatedAt: baseTime,
}).Error
require.NoError(t, err)
err = store.DB().Create(&tables.TableSkillVersion{
ID: "skill-version-old",
SkillID: skillID,
Version: "1.0.3",
SkillMDBody: "body",
FrontmatterSnapshot: tables.SkillJSONMap{"name": "latest-created", "description": "Latest created version test"},
CreatedAt: baseTime,
}).Error
require.NoError(t, err)
err = store.DB().Create(&tables.TableSkillVersion{
ID: "skill-version-new",
SkillID: skillID,
Version: "1.0.2-1",
SkillMDBody: "body",
FrontmatterSnapshot: tables.SkillJSONMap{"name": "latest-created", "description": "Latest created version test"},
CreatedAt: baseTime.Add(time.Minute),
}).Error
require.NoError(t, err)

latest, err := latestCreatedSkillVersion(store.DB(), skillID)
require.NoError(t, err)
assert.Equal(t, "1.0.2-1", latest)

skill, err := store.GetSkillLean(ctx, skillID)
require.NoError(t, err)
assert.Equal(t, "1.0.2-1", skill.HighestVersion)
}
Comment thread
danpiths marked this conversation as resolved.
Comment thread
danpiths marked this conversation as resolved.

// =============================================================================
// Provider and Key Tests
// =============================================================================
Expand Down
Loading
Loading