vgxness 1.17.2 → 1.18.0

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.
@@ -0,0 +1,112 @@
1
+ ALTER TABLE skill_versions ADD COLUMN lifecycle_label TEXT;
2
+ ALTER TABLE skill_versions ADD COLUMN draft_parent_version_id TEXT REFERENCES skill_versions(id) ON DELETE SET NULL;
3
+ ALTER TABLE skill_versions ADD COLUMN draft_revision INTEGER;
4
+ ALTER TABLE skill_versions ADD COLUMN governance_json TEXT;
5
+ ALTER TABLE skill_versions ADD COLUMN published_at TEXT;
6
+ ALTER TABLE skill_versions ADD COLUMN published_by TEXT;
7
+ ALTER TABLE skill_versions ADD COLUMN deprecated_at TEXT;
8
+ ALTER TABLE skill_versions ADD COLUMN archived_at TEXT;
9
+
10
+ ALTER TABLE skill_usage_records ADD COLUMN workflow TEXT;
11
+ ALTER TABLE skill_usage_records ADD COLUMN phase TEXT;
12
+ ALTER TABLE skill_usage_records ADD COLUMN provider_adapter TEXT;
13
+ ALTER TABLE skill_usage_records ADD COLUMN agent_id TEXT;
14
+ ALTER TABLE skill_usage_records ADD COLUMN intent_json TEXT;
15
+ ALTER TABLE skill_usage_records ADD COLUMN evidence_json TEXT;
16
+
17
+ ALTER TABLE skill_improvement_proposals ADD COLUMN title TEXT;
18
+ ALTER TABLE skill_improvement_proposals ADD COLUMN problem TEXT;
19
+ ALTER TABLE skill_improvement_proposals ADD COLUMN suggested_change TEXT;
20
+ ALTER TABLE skill_improvement_proposals ADD COLUMN source_run_id TEXT;
21
+ ALTER TABLE skill_improvement_proposals ADD COLUMN source_agent_id TEXT;
22
+ ALTER TABLE skill_improvement_proposals ADD COLUMN evidence_json TEXT;
23
+
24
+ ALTER TABLE skill_evaluation_results ADD COLUMN request_id TEXT REFERENCES skill_evaluation_requests(id) ON DELETE SET NULL;
25
+ ALTER TABLE skill_evaluation_results ADD COLUMN score REAL;
26
+ ALTER TABLE skill_evaluation_results ADD COLUMN passed INTEGER CHECK (passed IN (0, 1));
27
+ ALTER TABLE skill_evaluation_results ADD COLUMN evidence_json TEXT;
28
+ ALTER TABLE skill_evaluation_results ADD COLUMN risk_json TEXT;
29
+ ALTER TABLE skill_evaluation_results ADD COLUMN preflight_json TEXT;
30
+
31
+ CREATE TABLE IF NOT EXISTS skill_activation_records (
32
+ id TEXT PRIMARY KEY,
33
+ project TEXT NOT NULL,
34
+ scope TEXT NOT NULL CHECK (scope IN ('project', 'personal')),
35
+ skill_id TEXT NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
36
+ version_id TEXT REFERENCES skill_versions(id) ON DELETE SET NULL,
37
+ run_id TEXT,
38
+ agent_id TEXT,
39
+ workflow TEXT,
40
+ phase TEXT,
41
+ provider_adapter TEXT,
42
+ intent_json TEXT,
43
+ reason TEXT,
44
+ payload_metadata_json TEXT,
45
+ created_at TEXT NOT NULL
46
+ );
47
+
48
+ CREATE TABLE IF NOT EXISTS skill_evaluation_requests (
49
+ id TEXT PRIMARY KEY,
50
+ project TEXT NOT NULL,
51
+ scope TEXT NOT NULL CHECK (scope IN ('project', 'personal')),
52
+ skill_id TEXT NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
53
+ version_id TEXT REFERENCES skill_versions(id) ON DELETE SET NULL,
54
+ scenario_id TEXT REFERENCES skill_evaluation_scenarios(id) ON DELETE SET NULL,
55
+ proposal_id TEXT REFERENCES skill_improvement_proposals(id) ON DELETE SET NULL,
56
+ status TEXT NOT NULL CHECK (status IN ('requested', 'planned', 'running', 'completed', 'failed', 'cancelled', 'skipped')),
57
+ requested_by TEXT NOT NULL,
58
+ run_id TEXT,
59
+ agent_id TEXT,
60
+ workflow TEXT,
61
+ phase TEXT,
62
+ provider_adapter TEXT,
63
+ risk_json TEXT,
64
+ preflight_json TEXT,
65
+ created_at TEXT NOT NULL,
66
+ updated_at TEXT NOT NULL
67
+ );
68
+
69
+ CREATE TABLE IF NOT EXISTS skill_lifecycle_events (
70
+ id TEXT PRIMARY KEY,
71
+ project TEXT NOT NULL,
72
+ scope TEXT NOT NULL CHECK (scope IN ('project', 'personal')),
73
+ skill_id TEXT NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
74
+ version_id TEXT REFERENCES skill_versions(id) ON DELETE SET NULL,
75
+ event_type TEXT NOT NULL,
76
+ actor_type TEXT,
77
+ actor_id TEXT,
78
+ run_id TEXT,
79
+ agent_id TEXT,
80
+ reason TEXT,
81
+ before_json TEXT,
82
+ after_json TEXT,
83
+ evidence_json TEXT,
84
+ created_at TEXT NOT NULL
85
+ );
86
+
87
+ CREATE INDEX IF NOT EXISTS skill_versions_status_idx
88
+ ON skill_versions(status, created_at DESC, id ASC);
89
+
90
+ CREATE INDEX IF NOT EXISTS skill_versions_lifecycle_label_idx
91
+ ON skill_versions(lifecycle_label, created_at DESC, id ASC);
92
+
93
+ CREATE INDEX IF NOT EXISTS skill_activation_records_context_idx
94
+ ON skill_activation_records(project, scope, skill_id, created_at DESC);
95
+
96
+ CREATE INDEX IF NOT EXISTS skill_activation_records_run_agent_idx
97
+ ON skill_activation_records(run_id, agent_id, created_at DESC);
98
+
99
+ CREATE INDEX IF NOT EXISTS skill_usage_records_v2_context_idx
100
+ ON skill_usage_records(skill_id, version_id, provider_adapter, created_at DESC);
101
+
102
+ CREATE INDEX IF NOT EXISTS skill_improvement_proposals_v2_context_idx
103
+ ON skill_improvement_proposals(skill_id, status, source_run_id, source_agent_id, created_at DESC);
104
+
105
+ CREATE INDEX IF NOT EXISTS skill_evaluation_requests_context_idx
106
+ ON skill_evaluation_requests(project, scope, skill_id, status, created_at DESC);
107
+
108
+ CREATE INDEX IF NOT EXISTS skill_evaluation_requests_run_agent_idx
109
+ ON skill_evaluation_requests(run_id, agent_id, created_at DESC);
110
+
111
+ CREATE INDEX IF NOT EXISTS skill_lifecycle_events_context_idx
112
+ ON skill_lifecycle_events(project, scope, skill_id, version_id, created_at DESC);
@@ -0,0 +1,190 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export class SkillEvaluationRequestRepository {
3
+ db;
4
+ constructor(db) {
5
+ this.db = db;
6
+ }
7
+ create(input) {
8
+ const validation = validateCreateInput(input);
9
+ if (!validation.ok)
10
+ return validation;
11
+ const result = this.db.transaction(() => {
12
+ assertSkillInScope(this.db, input.skillId, input.project, input.scope);
13
+ if (input.versionId !== undefined)
14
+ assertVersionBelongsToSkill(this.db, input.versionId, input.skillId);
15
+ if (input.scenarioId !== undefined)
16
+ assertScenarioBelongsToSkill(this.db, input.scenarioId, input.skillId);
17
+ if (input.proposalId !== undefined)
18
+ assertProposalBelongsToSkill(this.db, input.proposalId, input.skillId);
19
+ const now = new Date().toISOString();
20
+ const id = randomUUID();
21
+ this.db.connection
22
+ .prepare(`
23
+ INSERT INTO skill_evaluation_requests(
24
+ id, project, scope, skill_id, version_id, scenario_id, proposal_id,
25
+ status, requested_by, run_id, agent_id, workflow, phase, provider_adapter,
26
+ risk_json, preflight_json, created_at, updated_at
27
+ ) VALUES (
28
+ @id, @project, @scope, @skillId, @versionId, @scenarioId, @proposalId,
29
+ 'requested', @requestedBy, @runId, @agentId, @workflow, @phase, @providerAdapter,
30
+ @riskJson, @preflightJson, @createdAt, @updatedAt
31
+ )
32
+ `)
33
+ .run({
34
+ id,
35
+ project: input.project,
36
+ scope: input.scope,
37
+ skillId: input.skillId,
38
+ versionId: input.versionId ?? null,
39
+ scenarioId: input.scenarioId ?? null,
40
+ proposalId: input.proposalId ?? null,
41
+ requestedBy: input.requestedBy.trim(),
42
+ runId: input.runId ?? null,
43
+ agentId: input.agentId ?? null,
44
+ workflow: input.workflow ?? null,
45
+ phase: input.phase ?? null,
46
+ providerAdapter: input.providerAdapter ?? null,
47
+ riskJson: input.risk === undefined ? null : JSON.stringify(input.risk),
48
+ preflightJson: input.preflight === undefined ? null : JSON.stringify(input.preflight),
49
+ createdAt: now,
50
+ updatedAt: now,
51
+ });
52
+ const read = this.getById(id);
53
+ if (!read.ok)
54
+ throw new Error(read.error.message);
55
+ return read.value;
56
+ });
57
+ if (!result.ok && result.error.cause instanceof SkillEvaluationRequestValidationError)
58
+ return validationFailure(result.error.cause.message);
59
+ return result;
60
+ }
61
+ list(filters) {
62
+ try {
63
+ const where = ['project=@project', 'scope=@scope'];
64
+ const parameters = { project: filters.project, scope: filters.scope, limit: filters.limit ?? 25 };
65
+ addOptionalFilter(where, parameters, 'skill_id', 'skillId', filters.skillId);
66
+ addOptionalFilter(where, parameters, 'version_id', 'versionId', filters.versionId);
67
+ addOptionalFilter(where, parameters, 'scenario_id', 'scenarioId', filters.scenarioId);
68
+ addOptionalFilter(where, parameters, 'proposal_id', 'proposalId', filters.proposalId);
69
+ addOptionalFilter(where, parameters, 'status', 'status', filters.status);
70
+ addOptionalFilter(where, parameters, 'run_id', 'runId', filters.runId);
71
+ addOptionalFilter(where, parameters, 'agent_id', 'agentId', filters.agentId);
72
+ const rows = this.db.connection
73
+ .prepare(`
74
+ SELECT * FROM skill_evaluation_requests
75
+ WHERE ${where.join(' AND ')}
76
+ ORDER BY created_at DESC, rowid DESC
77
+ LIMIT @limit
78
+ `)
79
+ .all(parameters);
80
+ return ok(rows.map(mapRequest));
81
+ }
82
+ catch (cause) {
83
+ return fail('Failed to list skill evaluation requests', cause);
84
+ }
85
+ }
86
+ getById(id) {
87
+ try {
88
+ const row = this.db.connection.prepare('SELECT * FROM skill_evaluation_requests WHERE id=?').get(id);
89
+ return row ? ok(mapRequest(row)) : missing(`Skill evaluation request not found: ${id}`);
90
+ }
91
+ catch (cause) {
92
+ return fail('Failed to read skill evaluation request', cause);
93
+ }
94
+ }
95
+ }
96
+ function validateCreateInput(input) {
97
+ if (!input.project.trim())
98
+ return validationFailure('Project is required');
99
+ if (input.scope !== 'project' && input.scope !== 'personal')
100
+ return validationFailure('Scope must be project or personal');
101
+ if (!input.skillId.trim())
102
+ return validationFailure('Skill id is required');
103
+ if (!input.requestedBy.trim())
104
+ return validationFailure('Skill evaluation requester is required');
105
+ return ok(undefined);
106
+ }
107
+ function addOptionalFilter(where, parameters, column, key, value) {
108
+ if (value === undefined)
109
+ return;
110
+ where.push(`${column}=@${key}`);
111
+ parameters[key] = value;
112
+ }
113
+ function assertSkillInScope(db, skillId, project, scope) {
114
+ const row = db.connection.prepare('SELECT project, scope FROM skills WHERE id=?').get(skillId);
115
+ if (row === undefined)
116
+ throw new SkillEvaluationRequestValidationError(`Skill not found: ${skillId}`);
117
+ if (row.project !== project || row.scope !== scope)
118
+ throw new SkillEvaluationRequestValidationError('Skill does not belong to the requested project/scope');
119
+ }
120
+ function assertVersionBelongsToSkill(db, versionId, skillId) {
121
+ const row = db.connection.prepare('SELECT skill_id FROM skill_versions WHERE id=?').get(versionId);
122
+ if (row === undefined)
123
+ throw new SkillEvaluationRequestValidationError(`Skill version not found: ${versionId}`);
124
+ if (row.skill_id !== skillId)
125
+ throw new SkillEvaluationRequestValidationError('Skill version must belong to the evaluated skill');
126
+ }
127
+ function assertScenarioBelongsToSkill(db, scenarioId, skillId) {
128
+ const row = db.connection.prepare('SELECT skill_id FROM skill_evaluation_scenarios WHERE id=?').get(scenarioId);
129
+ if (row === undefined)
130
+ throw new SkillEvaluationRequestValidationError(`Skill evaluation scenario not found: ${scenarioId}`);
131
+ if (row.skill_id !== skillId)
132
+ throw new SkillEvaluationRequestValidationError('Skill evaluation scenario must belong to the evaluated skill');
133
+ }
134
+ function assertProposalBelongsToSkill(db, proposalId, skillId) {
135
+ const row = db.connection.prepare('SELECT skill_id FROM skill_improvement_proposals WHERE id=?').get(proposalId);
136
+ if (row === undefined)
137
+ throw new SkillEvaluationRequestValidationError(`Skill improvement proposal not found: ${proposalId}`);
138
+ if (row.skill_id !== skillId)
139
+ throw new SkillEvaluationRequestValidationError('Skill improvement proposal must belong to the evaluated skill');
140
+ }
141
+ function mapRequest(row) {
142
+ const request = {
143
+ id: row.id,
144
+ project: row.project,
145
+ scope: row.scope,
146
+ skillId: row.skill_id,
147
+ status: row.status,
148
+ requestedBy: row.requested_by,
149
+ createdAt: row.created_at,
150
+ updatedAt: row.updated_at,
151
+ };
152
+ if (row.version_id !== null)
153
+ request.versionId = row.version_id;
154
+ if (row.scenario_id !== null)
155
+ request.scenarioId = row.scenario_id;
156
+ if (row.proposal_id !== null)
157
+ request.proposalId = row.proposal_id;
158
+ if (row.run_id !== null)
159
+ request.runId = row.run_id;
160
+ if (row.agent_id !== null)
161
+ request.agentId = row.agent_id;
162
+ if (row.workflow !== null)
163
+ request.workflow = row.workflow;
164
+ if (row.phase !== null)
165
+ request.phase = row.phase;
166
+ if (row.provider_adapter !== null)
167
+ request.providerAdapter = row.provider_adapter;
168
+ if (row.risk_json !== null)
169
+ request.risk = JSON.parse(row.risk_json);
170
+ if (row.preflight_json !== null)
171
+ request.preflight = JSON.parse(row.preflight_json);
172
+ return request;
173
+ }
174
+ function ok(value) {
175
+ return { ok: true, value };
176
+ }
177
+ function missing(message) {
178
+ return { ok: false, error: { code: 'not_found', message } };
179
+ }
180
+ function validationFailure(message) {
181
+ return { ok: false, error: { code: 'validation_failed', message } };
182
+ }
183
+ function fail(message, cause) {
184
+ const error = { code: 'validation_failed', message };
185
+ if (cause !== undefined)
186
+ error.cause = cause;
187
+ return { ok: false, error };
188
+ }
189
+ class SkillEvaluationRequestValidationError extends Error {
190
+ }
@@ -22,11 +22,13 @@ export class SkillImprovementProposalRepository {
22
22
  id, skill_id, base_version_id, proposed_version,
23
23
  proposed_source_kind, proposed_source_path, proposed_source_url, proposed_source_inline_metadata_json,
24
24
  proposed_compatibility_json, rationale, source_signal_json, diff_summary_json,
25
+ title, problem, suggested_change, source_run_id, source_agent_id, evidence_json,
25
26
  status, created_at, updated_at
26
27
  ) VALUES (
27
28
  @id, @skillId, @baseVersionId, @proposedVersion,
28
29
  @sourceKind, @sourcePath, @sourceUrl, @sourceInlineMetadataJson,
29
30
  @compatibilityJson, @rationale, @sourceSignalJson, @diffSummaryJson,
31
+ @title, @problem, @suggestedChange, @sourceRunId, @sourceAgentId, @evidenceJson,
30
32
  'draft', @createdAt, @updatedAt
31
33
  )
32
34
  `)
@@ -43,6 +45,12 @@ export class SkillImprovementProposalRepository {
43
45
  rationale: input.rationale,
44
46
  sourceSignalJson: JSON.stringify(input.sourceSignal ?? {}),
45
47
  diffSummaryJson: JSON.stringify(diffSummary),
48
+ title: input.title ?? null,
49
+ problem: input.problem ?? null,
50
+ suggestedChange: input.suggestedChange ?? null,
51
+ sourceRunId: input.sourceRunId ?? null,
52
+ sourceAgentId: input.sourceAgentId ?? null,
53
+ evidenceJson: input.evidence === undefined ? null : JSON.stringify(input.evidence),
46
54
  createdAt: now,
47
55
  updatedAt: now,
48
56
  });
@@ -59,19 +67,44 @@ export class SkillImprovementProposalRepository {
59
67
  try {
60
68
  const where = [];
61
69
  const parameters = {};
70
+ if (filters.project !== undefined) {
71
+ where.push('s.project=@project');
72
+ parameters.project = filters.project;
73
+ }
74
+ if (filters.scope !== undefined) {
75
+ where.push('s.scope=@scope');
76
+ parameters.scope = filters.scope;
77
+ }
62
78
  if (filters.skillId !== undefined) {
63
- where.push('skill_id=@skillId');
79
+ where.push('p.skill_id=@skillId');
64
80
  parameters.skillId = filters.skillId;
65
81
  }
82
+ if (filters.baseVersionId !== undefined) {
83
+ where.push('p.base_version_id=@baseVersionId');
84
+ parameters.baseVersionId = filters.baseVersionId;
85
+ }
66
86
  if (filters.status !== undefined) {
67
- where.push('status=@status');
87
+ where.push('p.status=@status');
68
88
  parameters.status = filters.status;
69
89
  }
90
+ if (filters.runId !== undefined) {
91
+ where.push('p.source_run_id=@runId');
92
+ parameters.runId = filters.runId;
93
+ }
94
+ if (filters.agentId !== undefined) {
95
+ where.push('p.source_agent_id=@agentId');
96
+ parameters.agentId = filters.agentId;
97
+ }
98
+ const limitClause = filters.limit === undefined ? '' : 'LIMIT @limit';
99
+ if (filters.limit !== undefined)
100
+ parameters.limit = filters.limit;
70
101
  const rows = this.db.connection
71
102
  .prepare(`
72
- SELECT * FROM skill_improvement_proposals
103
+ SELECT p.* FROM skill_improvement_proposals p
104
+ JOIN skills s ON s.id = p.skill_id
73
105
  ${where.length ? `WHERE ${where.join(' AND ')}` : ''}
74
- ORDER BY created_at DESC, id ASC
106
+ ORDER BY p.created_at DESC, p.id ASC
107
+ ${limitClause}
75
108
  `)
76
109
  .all(parameters);
77
110
  return ok(rows.map(mapProposal));
@@ -211,6 +244,12 @@ function validateCreate(input) {
211
244
  return validationFailure('Proposed version is required');
212
245
  if (!input.rationale.trim())
213
246
  return validationFailure('Proposal rationale is required');
247
+ if (input.title !== undefined && !input.title.trim())
248
+ return validationFailure('Proposal title must not be empty');
249
+ if (input.problem !== undefined && !input.problem.trim())
250
+ return validationFailure('Proposal problem must not be empty');
251
+ if (input.suggestedChange !== undefined && !input.suggestedChange.trim())
252
+ return validationFailure('Proposal suggested change must not be empty');
214
253
  if (input.proposedSource.kind === 'path' && !input.proposedSource.path?.trim())
215
254
  return validationFailure('Path proposal sources require proposedSource.path');
216
255
  if (input.proposedSource.kind === 'url' && !input.proposedSource.url?.trim())
@@ -265,6 +304,18 @@ function mapProposal(row) {
265
304
  createdAt: row.created_at,
266
305
  updatedAt: row.updated_at,
267
306
  };
307
+ if (row.title !== null && row.title !== undefined)
308
+ proposal.title = row.title;
309
+ if (row.problem !== null && row.problem !== undefined)
310
+ proposal.problem = row.problem;
311
+ if (row.suggested_change !== null && row.suggested_change !== undefined)
312
+ proposal.suggestedChange = row.suggested_change;
313
+ if (row.source_run_id !== null && row.source_run_id !== undefined)
314
+ proposal.sourceRunId = row.source_run_id;
315
+ if (row.source_agent_id !== null && row.source_agent_id !== undefined)
316
+ proposal.sourceAgentId = row.source_agent_id;
317
+ if (row.evidence_json !== null && row.evidence_json !== undefined)
318
+ proposal.evidence = JSON.parse(row.evidence_json);
268
319
  if (row.submitted_at !== null)
269
320
  proposal.submittedAt = row.submitted_at;
270
321
  if (row.submitted_by !== null)