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.
@@ -92,9 +92,9 @@ function toPayloadItem(skill, index, workspaceRoot, maxSourceBytes, mode) {
92
92
  function loadContent(skill, workspaceRoot, maxSourceBytes, mode) {
93
93
  if (skill.source.kind === 'inline') {
94
94
  if (skill.content !== undefined)
95
- return contentPayload(skill.content, skill.summary, inlineRef(skill), mode);
95
+ return inlineContentPayload(skill.content, skill.summary, inlineRef(skill), maxSourceBytes, mode);
96
96
  if (skill.summary !== undefined)
97
- return contentPayload(skill.summary, skill.summary, inlineRef(skill), mode);
97
+ return inlineContentPayload(skill.summary, skill.summary, inlineRef(skill), maxSourceBytes, mode);
98
98
  return { status: 'unavailable', unavailableReason: 'inline_content_missing' };
99
99
  }
100
100
  if (skill.source.kind === 'url')
@@ -125,6 +125,13 @@ function loadContent(skill, workspaceRoot, maxSourceBytes, mode) {
125
125
  return { status: 'unavailable', unavailableReason: 'path_read_failed' };
126
126
  }
127
127
  }
128
+ function inlineContentPayload(value, summary, ref, maxSourceBytes, mode) {
129
+ const byteSize = Buffer.byteLength(value, 'utf8');
130
+ if (mode === 'verbose' && byteSize > maxSourceBytes) {
131
+ return { status: 'unavailable', unavailableReason: 'inline_too_large', byteSize, ...(ref === undefined ? {} : { ref }) };
132
+ }
133
+ return contentPayload(value, summary, ref, mode, byteSize);
134
+ }
128
135
  function compactPathContent(skill, byteSize) {
129
136
  const metadataHash = stringMetadata(skill.sourceMetadata.sha256) ?? stringMetadata(skill.sourceMetadata.hash) ?? stringMetadata(skill.sourceMetadata.contentHash);
130
137
  const metadataSummary = skill.summary ?? stringMetadata(skill.sourceMetadata.summary);
@@ -1,4 +1,5 @@
1
1
  import { AgentRepository } from '../agents/repositories/agents.js';
2
+ import { SkillEvaluationRequestRepository, } from './repositories/skill-evaluation-requests.js';
2
3
  import { SkillEvaluationScenarioRepository, } from './repositories/skill-evaluation-scenarios.js';
3
4
  import { SkillImprovementProposalRepository, } from './repositories/skill-improvement-proposals.js';
4
5
  import { SkillRepository, } from './repositories/skills.js';
@@ -9,11 +10,13 @@ export class SkillRegistryService {
9
10
  skills;
10
11
  proposals;
11
12
  evaluationScenarios;
13
+ evaluationRequests;
12
14
  constructor(database) {
13
15
  this.database = database;
14
16
  this.skills = new SkillRepository(database);
15
17
  this.proposals = new SkillImprovementProposalRepository(database);
16
18
  this.evaluationScenarios = new SkillEvaluationScenarioRepository(database);
19
+ this.evaluationRequests = new SkillEvaluationRequestRepository(database);
17
20
  }
18
21
  registerSkill(input) {
19
22
  return this.skills.register(input);
@@ -30,8 +33,218 @@ export class SkillRegistryService {
30
33
  recordSkillUsage(input) {
31
34
  return this.skills.recordUsage(input);
32
35
  }
33
- getSkill(id) {
34
- return this.skills.getById(id);
36
+ createSkillDraft(input) {
37
+ const created = this.skills.createDraft(input);
38
+ if (!created.ok)
39
+ return created;
40
+ return ok({
41
+ kind: 'skill-draft-created',
42
+ version: 1,
43
+ project: input.project,
44
+ scope: input.scope ?? 'project',
45
+ skill: created.value.skill,
46
+ draft: created.value.version,
47
+ event: created.value.event,
48
+ safety: lifecycleSafety(false),
49
+ warnings: ['Draft creation does not publish, activate, approve, or human-accept a skill version.'],
50
+ });
51
+ }
52
+ updateSkillDraft(input) {
53
+ const updated = this.skills.updateDraft(input);
54
+ if (!updated.ok)
55
+ return updated;
56
+ return ok({
57
+ kind: 'skill-draft-updated',
58
+ version: 1,
59
+ project: input.project,
60
+ scope: input.scope ?? 'project',
61
+ skill: updated.value.skill,
62
+ draft: updated.value.version,
63
+ event: updated.value.event,
64
+ safety: lifecycleSafety(false),
65
+ warnings: ['Draft updates are limited to draft versions and do not mutate active, deprecated, or archived versions.'],
66
+ });
67
+ }
68
+ publishSkillVersion(input) {
69
+ if (!input.reason.trim())
70
+ return validationFailure('Publish reason is required');
71
+ const published = this.skills.publishVersion(input);
72
+ if (!published.ok)
73
+ return published;
74
+ return ok({
75
+ kind: 'skill-version-published',
76
+ version: 1,
77
+ project: input.project,
78
+ scope: input.scope ?? 'project',
79
+ skill: published.value.skill,
80
+ published: published.value.version,
81
+ previousCurrentVersionId: published.value.previousCurrentVersionId,
82
+ event: published.value.event,
83
+ safety: lifecycleSafety(true),
84
+ warnings: ['Publication updates the current active version; it is not skill activation, SDD artifact acceptance, or correctness proof.'],
85
+ });
86
+ }
87
+ activateSkill(input) {
88
+ const scope = input.scope ?? 'project';
89
+ if ((input.skillId === undefined || input.skillId.trim().length === 0) && (input.name === undefined || input.name.trim().length === 0)) {
90
+ return validationFailure('Either skill id or name is required');
91
+ }
92
+ const skill = input.skillId !== undefined ? this.skills.getById(input.skillId) : this.skills.getByName(input.project, scope, input.name ?? '');
93
+ if (!skill.ok)
94
+ return skill;
95
+ if (skill.value.project !== input.project || skill.value.scope !== scope)
96
+ return validationFailure('Skill does not belong to the requested project/scope');
97
+ const version = this.activationVersion(skill.value.id, input);
98
+ if (!version.ok)
99
+ return version;
100
+ if (version.value.status !== 'active')
101
+ return validationFailure(`Skill ${skill.value.name} version ${version.value.version} is ${version.value.status}, not active`);
102
+ const summary = stringMetadata(version.value.source.inlineMetadata?.summary);
103
+ const content = stringMetadata(version.value.source.inlineMetadata?.content);
104
+ const resolvedSkill = {
105
+ skillId: skill.value.id,
106
+ name: skill.value.name,
107
+ description: skill.value.description,
108
+ versionId: version.value.id,
109
+ version: version.value.version,
110
+ source: version.value.source,
111
+ sourceMetadata: version.value.source.inlineMetadata ?? {},
112
+ attachmentSources: [{ kind: 'attachment', targetType: 'intent-signal', targetKey: 'manual-skill-activation', reason: input.reason ?? 'skill activation requested' }],
113
+ };
114
+ if (summary !== undefined)
115
+ resolvedSkill.summary = summary;
116
+ if (content !== undefined)
117
+ resolvedSkill.content = content;
118
+ const resolution = {
119
+ context: {
120
+ project: input.project,
121
+ scope,
122
+ ...(input.agentId === undefined ? {} : { agentId: input.agentId }),
123
+ ...(input.workflow === undefined ? {} : { workflow: input.workflow }),
124
+ ...(input.phase === undefined ? {} : { phase: input.phase }),
125
+ ...(input.providerAdapter === undefined ? {} : { providerAdapter: input.providerAdapter }),
126
+ ...(input.runId === undefined ? {} : { runId: input.runId }),
127
+ ...(input.intent?.signals !== undefined && Array.isArray(input.intent.signals) ? { intentSignals: input.intent.signals.filter((value) => typeof value === 'string') } : {}),
128
+ },
129
+ skills: [resolvedSkill],
130
+ skipped: [],
131
+ skillDiagnostics: {
132
+ provider: input.providerAdapter ?? 'unknown',
133
+ providerState: input.providerAdapter === 'opencode' ? 'preview-only' : 'unknown',
134
+ summary: { declared: 1, resolved: 1, skipped: 0, warnings: input.providerAdapter === 'opencode' ? 2 : 0, errors: 0 },
135
+ skills: [
136
+ {
137
+ name: skill.value.name,
138
+ registryState: 'active',
139
+ activeVersion: version.value.version,
140
+ payloadState: 'preview-only',
141
+ providerState: input.providerAdapter === 'opencode' ? 'preview-only' : 'unknown',
142
+ included: true,
143
+ reason: null,
144
+ attachments: { declared: 1, resolved: 1, missing: 0 },
145
+ },
146
+ ],
147
+ diagnostics: input.providerAdapter === 'opencode'
148
+ ? [
149
+ {
150
+ code: 'SKILL_PROVIDER_PREVIEW_ONLY',
151
+ severity: 'info',
152
+ message: 'Skill activation payload is preview/context-only for OpenCode and does not install or native-load skills.',
153
+ details: { provider: 'opencode', providerState: 'preview-only' },
154
+ },
155
+ {
156
+ code: 'SKILL_PROVIDER_NATIVE_UNSUPPORTED',
157
+ severity: 'info',
158
+ message: 'OpenCode native skill loading is not implemented by VGXNESS for this activation payload.',
159
+ details: { provider: 'opencode', providerState: 'preview-only', installsNativeSkills: false, mutatesProviderConfig: false },
160
+ },
161
+ ]
162
+ : [],
163
+ },
164
+ warnings: ['Skill activation is an audit and payload preparation event only; it is not approval, publication, or proof of correctness.'],
165
+ usageRecorded: 0,
166
+ };
167
+ const payload = buildSkillInjectionPayload(resolution, {
168
+ ...(input.workspaceRoot === undefined ? {} : { workspaceRoot: input.workspaceRoot }),
169
+ ...(input.maxSourceBytes === undefined ? {} : { maxSourceBytes: input.maxSourceBytes }),
170
+ ...(input.mode === undefined ? {} : { mode: input.mode }),
171
+ });
172
+ if (!payload.ok)
173
+ return payload;
174
+ const recordInput = {
175
+ project: input.project,
176
+ scope,
177
+ skillId: skill.value.id,
178
+ versionId: version.value.id,
179
+ ...(input.runId === undefined ? {} : { runId: input.runId }),
180
+ ...(input.agentId === undefined ? {} : { agentId: input.agentId }),
181
+ ...(input.workflow === undefined ? {} : { workflow: input.workflow }),
182
+ ...(input.phase === undefined ? {} : { phase: input.phase }),
183
+ ...(input.providerAdapter === undefined ? {} : { providerAdapter: input.providerAdapter }),
184
+ ...(input.intent === undefined ? {} : { intent: input.intent }),
185
+ ...(input.reason === undefined ? {} : { reason: input.reason }),
186
+ payloadMetadata: { itemCount: payload.value.items.length, mode: input.mode ?? 'compact', providerAgnostic: true },
187
+ };
188
+ const activation = this.skills.recordActivation(recordInput);
189
+ if (!activation.ok)
190
+ return activation;
191
+ return ok({
192
+ kind: 'skill-activation',
193
+ version: 1,
194
+ project: input.project,
195
+ scope,
196
+ activation: activation.value,
197
+ skill: { id: skill.value.id, name: skill.value.name, description: skill.value.description, versionId: version.value.id, version: version.value.version },
198
+ payload: payload.value,
199
+ safety: {
200
+ providerConfigWrites: false,
201
+ opencodeWrites: false,
202
+ nativeSkillFileWrites: false,
203
+ providerExecution: false,
204
+ approval: false,
205
+ publication: false,
206
+ correctnessProof: false,
207
+ },
208
+ warnings: ['Skill activation is not approval, publication, or proof of correctness.', ...payload.value.warnings],
209
+ });
210
+ }
211
+ getSkill(input) {
212
+ if (typeof input === 'string')
213
+ return this.skills.getById(input);
214
+ const scope = input.scope ?? 'project';
215
+ if ((input.id === undefined || input.id.trim().length === 0) && (input.name === undefined || input.name.trim().length === 0)) {
216
+ return validationFailure('Either skill id or name is required');
217
+ }
218
+ const base = input.id !== undefined ? this.skills.getById(input.id) : this.skills.getByName(input.project, scope, input.name ?? '');
219
+ if (!base.ok)
220
+ return base;
221
+ if (base.value.project !== input.project || base.value.scope !== scope)
222
+ return validationFailure('Skill does not belong to the requested project/scope');
223
+ const details = this.skills.getDetails(base.value.id);
224
+ if (!details.ok)
225
+ return details;
226
+ return ok({
227
+ kind: 'skill-get',
228
+ version: 1,
229
+ project: input.project,
230
+ scope,
231
+ skill: {
232
+ id: details.value.id,
233
+ project: details.value.project,
234
+ scope: details.value.scope,
235
+ name: details.value.name,
236
+ description: details.value.description,
237
+ currentVersionId: details.value.currentVersionId ?? null,
238
+ createdAt: details.value.createdAt,
239
+ updatedAt: details.value.updatedAt,
240
+ currentVersion: details.value.currentVersion ?? null,
241
+ versions: details.value.versions,
242
+ attachments: details.value.attachments,
243
+ usage: input.includeUsage === true ? details.value.usage.slice(0, 25) : [],
244
+ },
245
+ diagnostics: [],
246
+ safety: readOnlySafety(),
247
+ });
35
248
  }
36
249
  getSkillByName(project, scope, name) {
37
250
  return this.skills.getByName(project, scope, name);
@@ -42,6 +255,39 @@ export class SkillRegistryService {
42
255
  listSkills(filters = {}) {
43
256
  return this.skills.list(filters);
44
257
  }
258
+ searchSkills(input) {
259
+ const scope = input.scope ?? 'project';
260
+ const limit = normalizeLimit(input.limit);
261
+ const searchInput = { project: input.project, scope, limit };
262
+ if (input.query !== undefined)
263
+ searchInput.query = input.query;
264
+ if (input.status !== undefined)
265
+ searchInput.status = input.status;
266
+ if (input.sourceKind !== undefined)
267
+ searchInput.sourceKind = input.sourceKind;
268
+ const skills = this.skills.search(searchInput);
269
+ if (!skills.ok)
270
+ return skills;
271
+ const matched = this.skills.countSearchMatches(searchInput);
272
+ if (!matched.ok)
273
+ return matched;
274
+ return ok({
275
+ kind: 'skills-search',
276
+ version: 1,
277
+ project: input.project,
278
+ scope,
279
+ filters: {
280
+ query: input.query?.trim() || null,
281
+ status: input.status ?? null,
282
+ sourceKind: input.sourceKind ?? null,
283
+ limit,
284
+ },
285
+ totals: { matched: matched.value, returned: skills.value.length },
286
+ skills: skills.value,
287
+ diagnostics: [],
288
+ safety: readOnlySafety(),
289
+ });
290
+ }
45
291
  listSkillVersions(skillId) {
46
292
  return this.skills.listVersions(skillId);
47
293
  }
@@ -51,8 +297,106 @@ export class SkillRegistryService {
51
297
  createSkillImprovementProposal(input) {
52
298
  return this.proposals.create(input);
53
299
  }
54
- listSkillImprovementProposals(filters = {}) {
55
- return this.proposals.list(filters);
300
+ proposeSkillImprovement(input) {
301
+ const scope = input.scope ?? 'project';
302
+ if ((input.skillId === undefined || input.skillId.trim().length === 0) && (input.name === undefined || input.name.trim().length === 0)) {
303
+ return validationFailure('Either skillId or name is required');
304
+ }
305
+ if (input.baseVersionId !== undefined && input.baseVersion !== undefined)
306
+ return validationFailure('Use either baseVersionId or baseVersion, not both');
307
+ if (!input.title.trim())
308
+ return validationFailure('Proposal title is required');
309
+ if (!input.problem.trim())
310
+ return validationFailure('Proposal problem statement is required');
311
+ if (!input.suggestedChange.trim())
312
+ return validationFailure('Proposal suggested change is required');
313
+ const skill = input.skillId !== undefined ? this.skills.getById(input.skillId) : this.skills.getByName(input.project, scope, input.name ?? '');
314
+ if (!skill.ok)
315
+ return skill;
316
+ if (skill.value.project !== input.project || skill.value.scope !== scope)
317
+ return validationFailure('Skill does not belong to the requested project/scope');
318
+ const baseVersion = resolveProposalBaseVersion(this.skills, skill.value.id, input.baseVersionId, input.baseVersion);
319
+ if (!baseVersion.ok)
320
+ return baseVersion;
321
+ const sourceSignal = {
322
+ ...(input.sourceContext ?? {}),
323
+ ...(input.workflow === undefined ? {} : { workflow: input.workflow }),
324
+ ...(input.phase === undefined ? {} : { phase: input.phase }),
325
+ ...(input.providerAdapter === undefined ? {} : { providerAdapter: input.providerAdapter }),
326
+ ...(input.actor === undefined ? {} : { actor: input.actor }),
327
+ };
328
+ const evidence = input.evidenceRefs === undefined ? (input.evidence ?? {}) : { ...(input.evidence ?? {}), refs: input.evidenceRefs };
329
+ const proposal = this.proposals.create({
330
+ skillId: skill.value.id,
331
+ baseVersionId: baseVersion.value.id,
332
+ proposedVersion: input.proposedVersion,
333
+ proposedSource: input.proposedSource,
334
+ ...(input.proposedCompatibility === undefined ? {} : { proposedCompatibility: input.proposedCompatibility }),
335
+ rationale: `${input.problem.trim()}\n\nSuggested change: ${input.suggestedChange.trim()}`,
336
+ sourceSignal,
337
+ title: input.title.trim(),
338
+ problem: input.problem.trim(),
339
+ suggestedChange: input.suggestedChange.trim(),
340
+ ...(input.runId === undefined ? {} : { sourceRunId: input.runId }),
341
+ ...(input.agentId === undefined ? {} : { sourceAgentId: input.agentId }),
342
+ evidence,
343
+ });
344
+ if (!proposal.ok)
345
+ return proposal;
346
+ return ok({
347
+ kind: 'skill-improvement-proposal',
348
+ version: 1,
349
+ project: input.project,
350
+ scope,
351
+ skill: { id: skill.value.id, name: skill.value.name, versionId: baseVersion.value.id, version: baseVersion.value.version },
352
+ proposal: proposal.value,
353
+ safety: proposalSafety(),
354
+ warnings: ['Improvement proposal creation is non-destructive and does not mutate active or published skill content.'],
355
+ });
356
+ }
357
+ listSkillImprovementProposals(input = {}) {
358
+ if (isSkillListImprovementProposalsInput(input)) {
359
+ const scope = input.scope ?? 'project';
360
+ const limit = normalizeLimit(input.limit);
361
+ let skillId = input.skillId;
362
+ if (skillId === undefined && input.name !== undefined) {
363
+ const skill = this.skills.getByName(input.project, scope, input.name);
364
+ if (!skill.ok)
365
+ return skill;
366
+ skillId = skill.value.id;
367
+ }
368
+ const proposals = this.proposals.list({
369
+ project: input.project,
370
+ scope,
371
+ ...(skillId === undefined ? {} : { skillId }),
372
+ ...(input.baseVersionId === undefined ? {} : { baseVersionId: input.baseVersionId }),
373
+ ...(input.status === undefined ? {} : { status: input.status }),
374
+ ...(input.runId === undefined ? {} : { runId: input.runId }),
375
+ ...(input.agentId === undefined ? {} : { agentId: input.agentId }),
376
+ limit,
377
+ });
378
+ if (!proposals.ok)
379
+ return proposals;
380
+ return ok({
381
+ kind: 'skill-improvement-proposals-list',
382
+ version: 1,
383
+ project: input.project,
384
+ scope,
385
+ filters: {
386
+ skillId: skillId ?? null,
387
+ name: input.name ?? null,
388
+ baseVersionId: input.baseVersionId ?? null,
389
+ status: input.status ?? null,
390
+ runId: input.runId ?? null,
391
+ agentId: input.agentId ?? null,
392
+ limit,
393
+ },
394
+ totals: { returned: proposals.value.length, bounded: true },
395
+ proposals: proposals.value,
396
+ safety: { ...proposalSafety(), readOnly: true },
397
+ });
398
+ }
399
+ return this.proposals.list(input);
56
400
  }
57
401
  getSkillImprovementProposal(id) {
58
402
  return this.proposals.getById(id);
@@ -84,11 +428,217 @@ export class SkillRegistryService {
84
428
  listSkillEvaluationResults(filters = {}) {
85
429
  return this.evaluationScenarios.listResults(filters);
86
430
  }
431
+ createSkillEvaluationRequest(input) {
432
+ return this.evaluationRequests.create(input);
433
+ }
434
+ requestSkillEvaluation(input) {
435
+ const scope = input.scope ?? 'project';
436
+ if ((input.skillId === undefined || input.skillId.trim().length === 0) && (input.name === undefined || input.name.trim().length === 0)) {
437
+ return validationFailure('Either skillId or name is required');
438
+ }
439
+ if (input.versionId !== undefined && input.version !== undefined)
440
+ return validationFailure('Use either versionId or version, not both');
441
+ const skill = input.skillId !== undefined ? this.skills.getById(input.skillId) : this.skills.getByName(input.project, scope, input.name ?? '');
442
+ if (!skill.ok)
443
+ return skill;
444
+ if (skill.value.project !== input.project || skill.value.scope !== scope)
445
+ return validationFailure('Skill does not belong to the requested project/scope');
446
+ let versionId = input.versionId;
447
+ if (versionId === undefined && input.version !== undefined) {
448
+ const version = this.skills.getVersionBySkillVersion(skill.value.id, input.version);
449
+ if (!version.ok)
450
+ return version;
451
+ versionId = version.value.id;
452
+ }
453
+ const request = this.evaluationRequests.create({
454
+ project: input.project,
455
+ scope,
456
+ skillId: skill.value.id,
457
+ requestedBy: input.requestedBy,
458
+ ...(versionId === undefined ? {} : { versionId }),
459
+ ...(input.scenarioId === undefined ? {} : { scenarioId: input.scenarioId }),
460
+ ...(input.proposalId === undefined ? {} : { proposalId: input.proposalId }),
461
+ ...(input.runId === undefined ? {} : { runId: input.runId }),
462
+ ...(input.agentId === undefined ? {} : { agentId: input.agentId }),
463
+ ...(input.workflow === undefined ? {} : { workflow: input.workflow }),
464
+ ...(input.phase === undefined ? {} : { phase: input.phase }),
465
+ ...(input.providerAdapter === undefined ? {} : { providerAdapter: input.providerAdapter }),
466
+ ...(input.risk === undefined ? {} : { risk: input.risk }),
467
+ ...(input.preflight === undefined ? {} : { preflight: input.preflight }),
468
+ });
469
+ if (!request.ok)
470
+ return request;
471
+ return ok({
472
+ kind: 'skill-evaluation-request',
473
+ version: 1,
474
+ project: input.project,
475
+ scope,
476
+ request: request.value,
477
+ safety: evaluationRequestSafety(),
478
+ warnings: ['Skill evaluation request creation only queues a request; it does not execute an evaluator or provider.'],
479
+ });
480
+ }
481
+ listSkillEvaluationRequests(filters) {
482
+ return this.evaluationRequests.list(filters);
483
+ }
484
+ listSkillEvaluations(input) {
485
+ const scope = input.scope ?? 'project';
486
+ const limit = normalizeLimit(input.limit);
487
+ let skillId = input.skillId;
488
+ if (skillId === undefined && input.name !== undefined) {
489
+ const skill = this.skills.getByName(input.project, scope, input.name);
490
+ if (!skill.ok)
491
+ return skill;
492
+ skillId = skill.value.id;
493
+ }
494
+ const requests = this.evaluationRequests.list({
495
+ project: input.project,
496
+ scope,
497
+ ...(skillId === undefined ? {} : { skillId }),
498
+ ...(input.versionId === undefined ? {} : { versionId: input.versionId }),
499
+ ...(input.scenarioId === undefined ? {} : { scenarioId: input.scenarioId }),
500
+ ...(input.proposalId === undefined ? {} : { proposalId: input.proposalId }),
501
+ ...(input.status === undefined ? {} : { status: input.status }),
502
+ ...(input.runId === undefined ? {} : { runId: input.runId }),
503
+ ...(input.agentId === undefined ? {} : { agentId: input.agentId }),
504
+ limit,
505
+ });
506
+ if (!requests.ok)
507
+ return requests;
508
+ return ok({
509
+ kind: 'skill-evaluations-list',
510
+ version: 1,
511
+ project: input.project,
512
+ scope,
513
+ filters: {
514
+ skillId: skillId ?? null,
515
+ name: input.name ?? null,
516
+ versionId: input.versionId ?? null,
517
+ scenarioId: input.scenarioId ?? null,
518
+ proposalId: input.proposalId ?? null,
519
+ status: input.status ?? null,
520
+ runId: input.runId ?? null,
521
+ agentId: input.agentId ?? null,
522
+ limit,
523
+ },
524
+ totals: { returned: requests.value.length, bounded: true },
525
+ requests: requests.value,
526
+ safety: { ...evaluationRequestSafety(), readOnly: true },
527
+ });
528
+ }
529
+ getSkillEvaluationRequest(input) {
530
+ if (typeof input === 'string')
531
+ return this.evaluationRequests.getById(input);
532
+ const scope = input.scope ?? 'project';
533
+ const request = this.evaluationRequests.getById(input.id);
534
+ if (!request.ok)
535
+ return request;
536
+ if (request.value.project !== input.project || request.value.scope !== scope)
537
+ return validationFailure('Skill evaluation request does not belong to the requested project/scope');
538
+ return request;
539
+ }
87
540
  buildSkillPayload(input, options = {}) {
88
541
  const resolution = this.resolveSkills(input);
89
542
  return resolution.ok ? buildSkillInjectionPayload(resolution.value, options) : resolution;
90
543
  }
544
+ activationVersion(skillId, input) {
545
+ if (input.versionId !== undefined) {
546
+ const version = this.skills.getVersion(input.versionId);
547
+ if (!version.ok)
548
+ return version;
549
+ if (version.value.skillId !== skillId)
550
+ return validationFailure('Skill version must belong to the activated skill');
551
+ return version;
552
+ }
553
+ if (input.version !== undefined)
554
+ return this.skills.getVersionBySkillVersion(skillId, input.version);
555
+ const details = this.skills.getDetails(skillId);
556
+ if (!details.ok)
557
+ return details;
558
+ if (details.value.currentVersion === undefined)
559
+ return validationFailure(`Skill ${details.value.name} has no current version`);
560
+ return ok(details.value.currentVersion);
561
+ }
91
562
  close() {
92
563
  this.database.close();
93
564
  }
94
565
  }
566
+ function isSkillListImprovementProposalsInput(input) {
567
+ return typeof input.project === 'string';
568
+ }
569
+ function readOnlySafety() {
570
+ return {
571
+ readOnly: true,
572
+ providerConfigWrites: false,
573
+ opencodeWrites: false,
574
+ nativeSkillFileWrites: false,
575
+ urlFetches: false,
576
+ usageRecords: false,
577
+ providerExecution: false,
578
+ };
579
+ }
580
+ function proposalSafety() {
581
+ return {
582
+ providerConfigWrites: false,
583
+ opencodeWrites: false,
584
+ nativeSkillFileWrites: false,
585
+ activeSkillContentMutation: false,
586
+ providerExecution: false,
587
+ };
588
+ }
589
+ function evaluationRequestSafety() {
590
+ return {
591
+ providerConfigWrites: false,
592
+ opencodeWrites: false,
593
+ nativeSkillFileWrites: false,
594
+ providerExecution: false,
595
+ evaluatorExecution: false,
596
+ runStarted: false,
597
+ };
598
+ }
599
+ function lifecycleSafety(activeVersionUpdated) {
600
+ return {
601
+ providerConfigWrites: false,
602
+ opencodeWrites: false,
603
+ nativeSkillFileWrites: false,
604
+ providerExecution: false,
605
+ activation: false,
606
+ approval: false,
607
+ humanAcceptance: false,
608
+ activeVersionUpdated,
609
+ };
610
+ }
611
+ function resolveProposalBaseVersion(skills, skillId, baseVersionId, baseVersion) {
612
+ if (baseVersionId !== undefined) {
613
+ const version = skills.getVersion(baseVersionId);
614
+ if (!version.ok)
615
+ return version;
616
+ if (version.value.skillId !== skillId)
617
+ return validationFailure('Base version must belong to the proposed skill');
618
+ return version;
619
+ }
620
+ if (baseVersion !== undefined)
621
+ return skills.getVersionBySkillVersion(skillId, baseVersion);
622
+ const details = skills.getDetails(skillId);
623
+ if (!details.ok)
624
+ return details;
625
+ if (details.value.currentVersion === undefined)
626
+ return validationFailure(`Skill ${details.value.name} has no current version`);
627
+ return ok(details.value.currentVersion);
628
+ }
629
+ function normalizeLimit(limit) {
630
+ if (limit === undefined)
631
+ return 25;
632
+ if (!Number.isSafeInteger(limit) || limit < 1)
633
+ return 25;
634
+ return Math.min(limit, 100);
635
+ }
636
+ function stringMetadata(value) {
637
+ return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
638
+ }
639
+ function ok(value) {
640
+ return { ok: true, value };
641
+ }
642
+ function validationFailure(message) {
643
+ return { ok: false, error: { code: 'validation_failed', message } };
644
+ }
@@ -39,6 +39,9 @@ export class SkillStatusService {
39
39
  const declared = agentItems.reduce((sum, item) => sum + item.declaredSkills.length, 0);
40
40
  const resolved = agentItems.reduce((sum, item) => sum + item.resolvedSkills.length, 0);
41
41
  const missing = agentItems.reduce((sum, item) => sum + item.missingSkills.length, 0);
42
+ const v2Counts = this.skills.skills.getV2Counts(input.project, scope);
43
+ if (!v2Counts.ok)
44
+ return v2Counts;
42
45
  return ok({
43
46
  kind: 'skills-status',
44
47
  version: 1,
@@ -65,7 +68,7 @@ export class SkillStatusService {
65
68
  current: skill.currentVersionId !== null && skill.currentVersion !== null,
66
69
  providerAvailable: false,
67
70
  })),
68
- registry: { skills: registry.value },
71
+ registry: { skills: registry.value, v2: v2Counts.value },
69
72
  agents: { modes, declared, resolved, missing, items: agentItems },
70
73
  diagnostics,
71
74
  safety: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgxness",
3
- "version": "1.17.2",
3
+ "version": "1.18.0",
4
4
  "description": "CLI and MCP control plane for guided AI-agent workflows, SDD, memory, and OpenCode setup.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {