@djordje-stojanovic/sigmaskills 0.2.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +21 -0
  3. package/README.md +342 -0
  4. package/bin/sigmaskills.js +7 -0
  5. package/manifest.json +28 -0
  6. package/package.json +42 -0
  7. package/registry/agent-hosts.json +2404 -0
  8. package/registry/schema.json +110 -0
  9. package/registry/skill-baselines.json +4 -0
  10. package/registry/source.json +6 -0
  11. package/sigmabrief/SKILL.md +56 -0
  12. package/sigmabrief/agents/openai.yaml +12 -0
  13. package/sigmabrief/references/brief-method.md +73 -0
  14. package/sigmabrief/references/prompt-contract.md +174 -0
  15. package/sigmaperformance/SKILL.md +118 -0
  16. package/sigmaperformance/agents/openai.yaml +12 -0
  17. package/sigmaperformance/references/audit-method.md +112 -0
  18. package/sigmaperformance/references/calibration.md +45 -0
  19. package/sigmaperformance/references/report-contract.md +103 -0
  20. package/sigmareview/SKILL.md +133 -0
  21. package/sigmareview/agents/openai.yaml +12 -0
  22. package/sigmareview/references/report-contract.md +217 -0
  23. package/sigmareview/references/review-method.md +233 -0
  24. package/sigmawrite/SKILL.md +45 -0
  25. package/sigmawrite/agents/openai.yaml +12 -0
  26. package/src/adoption.js +370 -0
  27. package/src/backup.js +398 -0
  28. package/src/catalog.js +211 -0
  29. package/src/cli.js +657 -0
  30. package/src/customization.js +344 -0
  31. package/src/destinations.js +491 -0
  32. package/src/interactive.js +959 -0
  33. package/src/links.js +157 -0
  34. package/src/plan.js +429 -0
  35. package/src/prepack.js +10 -0
  36. package/src/project-lock.js +169 -0
  37. package/src/purge.js +477 -0
  38. package/src/registry/automation-ci.js +411 -0
  39. package/src/registry/automation.js +554 -0
  40. package/src/registry/diff.js +149 -0
  41. package/src/registry/normalize.js +67 -0
  42. package/src/registry/parse.js +184 -0
  43. package/src/registry/sync.js +230 -0
  44. package/src/registry/validate.js +223 -0
  45. package/src/release-ci.js +12 -0
  46. package/src/release.js +837 -0
  47. package/src/restore.js +518 -0
  48. package/src/revision.js +82 -0
  49. package/src/state.js +480 -0
  50. package/src/status.js +469 -0
  51. package/src/transaction.js +636 -0
  52. package/src/uninstall.js +647 -0
  53. package/src/update.js +815 -0
@@ -0,0 +1,411 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { loadPin } from './sync.js';
6
+ import {
7
+ GENERATED_BRANCH_PREFIX,
8
+ REGISTRY_ALLOWLIST,
9
+ REGISTRY_SYNC_WORKFLOW_FILE,
10
+ classifySemanticAuthority,
11
+ executeRegistryAutomation,
12
+ } from './automation.js';
13
+ import { diffSnapshots } from './diff.js';
14
+ import { validateSnapshot } from './validate.js';
15
+ import {
16
+ RELEASE_DIST_TAG,
17
+ RELEASE_ENVIRONMENT,
18
+ RELEASE_PACKAGE_NAME,
19
+ applyRegistryPatchIdentities,
20
+ executeTrustedPatchRelease,
21
+ } from '../release.js';
22
+
23
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
24
+
25
+ function git(args, options = {}) {
26
+ const out = execFileSync('git', args, { cwd: ROOT, encoding: 'utf8', ...options });
27
+ return typeof out === 'string' ? out.trim() : '';
28
+ }
29
+
30
+ function ghJson(args, env) {
31
+ const raw = execFileSync('gh', args, { cwd: ROOT, encoding: 'utf8', env });
32
+ return JSON.parse(raw);
33
+ }
34
+
35
+ async function fetchJson(url, token) {
36
+ const headers = { 'user-agent': 'sigmaskills-registry-sync' };
37
+ if (token) headers.authorization = `Bearer ${token}`;
38
+ const res = await fetch(url, { headers });
39
+ if (!res.ok) throw new Error(`GET ${url} failed: HTTP ${res.status}`);
40
+ return res.json();
41
+ }
42
+
43
+ async function fetchText(url) {
44
+ const res = await fetch(url, { headers: { 'user-agent': 'sigmaskills-registry-sync' } });
45
+ if (!res.ok) throw new Error(`GET ${url} failed: HTTP ${res.status}`);
46
+ return res.text();
47
+ }
48
+
49
+ function writeAllowlisted(plan) {
50
+ const writes = {
51
+ 'registry/source.json': `${JSON.stringify(plan.pin, null, 2)}\n`,
52
+ 'registry/agent-hosts.json': `${JSON.stringify(plan.snapshot, null, 2)}\n`,
53
+ 'test/fixtures/vercel-skills/src/agents.ts': plan.upstreamText,
54
+ };
55
+ for (const file of REGISTRY_ALLOWLIST) {
56
+ const abs = path.join(ROOT, file);
57
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
58
+ fs.writeFileSync(abs, writes[file], 'utf8');
59
+ }
60
+ }
61
+
62
+ function stagedFiles() {
63
+ const output = git(['diff', '--cached', '--name-only', '-z']);
64
+ return output ? output.split('\0').filter(Boolean) : [];
65
+ }
66
+
67
+ function npmVersions() {
68
+ try {
69
+ const raw = execFileSync('npm', ['view', RELEASE_PACKAGE_NAME, 'versions', '--json'], {
70
+ encoding: 'utf8',
71
+ });
72
+ const parsed = JSON.parse(raw);
73
+ return Array.isArray(parsed) ? parsed : [parsed];
74
+ } catch {
75
+ return [];
76
+ }
77
+ }
78
+
79
+ function githubVersions(env) {
80
+ try {
81
+ return ghJson(['release', 'list', '--limit', '20', '--json', 'tagName'], env)
82
+ .map((item) => String(item.tagName || '').replace(/^v/, ''))
83
+ .filter((value) => /^\d+\.\d+\.\d+$/.test(value));
84
+ } catch {
85
+ return [];
86
+ }
87
+ }
88
+
89
+ function probePublication(version, env) {
90
+ let npmPackage = { exists: false, versions: {} };
91
+ try {
92
+ const name = execFileSync('npm', ['view', RELEASE_PACKAGE_NAME, 'name'], { encoding: 'utf8' }).trim();
93
+ npmPackage.exists = name === RELEASE_PACKAGE_NAME;
94
+ if (npmPackage.exists) {
95
+ try {
96
+ const integrity = execFileSync(
97
+ 'npm',
98
+ ['view', `${RELEASE_PACKAGE_NAME}@${version}`, 'dist.integrity'],
99
+ { encoding: 'utf8' },
100
+ ).trim();
101
+ if (integrity) npmPackage.versions[version] = { integrity };
102
+ } catch {
103
+ // Unpublished version; reservation still counts.
104
+ }
105
+ }
106
+ } catch {
107
+ npmPackage = { exists: false, versions: {} };
108
+ }
109
+
110
+ let githubRelease = null;
111
+ let gitTag = null;
112
+ const tag = `v${version}`;
113
+ try {
114
+ const parsed = ghJson(['release', 'view', tag, '--json', 'tagName,targetCommitish'], env);
115
+ githubRelease = { tag: parsed.tagName, targetCommit: parsed.targetCommitish };
116
+ } catch {
117
+ githubRelease = null;
118
+ }
119
+ try {
120
+ gitTag = { name: tag, commit: git(['rev-list', '-n', '1', tag]) };
121
+ } catch {
122
+ gitTag = null;
123
+ }
124
+
125
+ let environment = null;
126
+ try {
127
+ const repo = env.GITHUB_REPOSITORY || 'Djordje-Stojanovic/Sigmaskills';
128
+ const parsed = JSON.parse(execFileSync(
129
+ 'gh',
130
+ ['api', `repos/${repo}/environments/${RELEASE_ENVIRONMENT}`],
131
+ { encoding: 'utf8', env },
132
+ ));
133
+ environment = {
134
+ name: parsed.name,
135
+ protected: Array.isArray(parsed.protection_rules) && parsed.protection_rules.length > 0,
136
+ };
137
+ } catch {
138
+ environment = null;
139
+ }
140
+
141
+ return { npmPackage, githubRelease, gitTag, environment, trustedPublisher: env.GITHUB_ACTIONS === 'true' };
142
+ }
143
+
144
+ function createRealIo(env, mode) {
145
+ const token = env.GITHUB_TOKEN;
146
+ const pin = loadPin();
147
+ return {
148
+ converterSha: async () => (env.GITHUB_SHA || git(['rev-parse', 'HEAD'])).trim(),
149
+ currentDefaultSha: async () => {
150
+ try {
151
+ git(['fetch', 'origin', 'main'], { stdio: 'ignore' });
152
+ return git(['rev-parse', 'origin/main']);
153
+ } catch {
154
+ return git(['rev-parse', 'HEAD']);
155
+ }
156
+ },
157
+ resolveUpstreamRevision: async () => {
158
+ const commits = await fetchJson(
159
+ `https://api.github.com/repos/${pin.repository}/commits?path=${encodeURIComponent(pin.upstreamFile)}&per_page=1`,
160
+ token,
161
+ );
162
+ const sha = commits[0] && commits[0].sha;
163
+ if (!sha || !/^[0-9a-f]{40}$/.test(sha)) {
164
+ throw new Error('unable to resolve a pinned 40-hex upstream revision');
165
+ }
166
+ return sha;
167
+ },
168
+ fetchUpstreamText: async (revision) => fetchText(
169
+ `https://raw.githubusercontent.com/${pin.repository}/${revision}/${pin.upstreamFile}`,
170
+ ),
171
+ readPin: async () => loadPin(),
172
+ readSnapshot: async () => JSON.parse(fs.readFileSync(path.join(ROOT, 'registry/agent-hosts.json'), 'utf8')),
173
+ hasConcurrentRun: async () => {
174
+ try {
175
+ const prs = ghJson(['pr', 'list', '--state', 'open', '--json', 'headRefName'], env)
176
+ .filter((pr) => String(pr.headRefName || '').startsWith(GENERATED_BRANCH_PREFIX));
177
+ return mode === 'auto-merge' ? prs.length > 1 : prs.length > 0;
178
+ } catch {
179
+ return false;
180
+ }
181
+ },
182
+ writeAllowlisted: async (plan) => writeAllowlisted(plan),
183
+ createPullRequest: async (result) => {
184
+ const branch = `registry/sync-${result.upstreamRevision.slice(0, 12)}`;
185
+ if (env.GITHUB_ACTIONS) {
186
+ git(['config', 'user.name', 'github-actions[bot]']);
187
+ git(['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
188
+ }
189
+ git(['checkout', '-B', branch]);
190
+ git(['add', '--', ...REGISTRY_ALLOWLIST]);
191
+ const extra = stagedFiles().filter((file) => !REGISTRY_ALLOWLIST.includes(file.replace(/\\/g, '/')));
192
+ if (extra.length > 0) throw new Error(`refusing to commit files outside the registry allowlist: ${extra.join(', ')}`);
193
+ git(['commit', '-m', `chore(registry): sync Agent Host snapshot from ${result.upstreamRevision}`]);
194
+ const generatedHeadSha = git(['rev-parse', 'HEAD']);
195
+ git(['push', '-u', 'origin', branch]);
196
+ execFileSync('gh', [
197
+ 'pr', 'create',
198
+ '--title', `chore(registry): sync Agent Hosts from ${result.upstreamRevision.slice(0, 12)}`,
199
+ '--body', `${result.body}\nGenerated head SHA: \`${generatedHeadSha}\`\n`,
200
+ '--base', 'main',
201
+ ], { cwd: ROOT, encoding: 'utf8', env });
202
+ },
203
+ listBranches: async () => git(['branch', '-a']).split(/\n/).map((line) => ({
204
+ name: line.replace(/^\*?\s*/, '').replace(/^remotes\/origin\//, ''),
205
+ generated: line.includes('registry/sync-'),
206
+ })),
207
+ protectedRefs: async () => ['main'],
208
+ inspectPullRequest: async () => {
209
+ const prs = ghJson(['pr', 'list', '--state', 'open', '--json', 'number,headRefName,headRefOid,isCrossRepository,files,body'], env)
210
+ .filter((pr) => String(pr.headRefName || '').startsWith(GENERATED_BRANCH_PREFIX));
211
+ if (prs.length !== 1) return null;
212
+ const listed = prs[0];
213
+ let checkConclusion = 'failure';
214
+ try {
215
+ execFileSync('gh', ['pr', 'checks', String(listed.number), '--watch', '--fail-fast'], {
216
+ cwd: ROOT,
217
+ encoding: 'utf8',
218
+ env,
219
+ });
220
+ checkConclusion = 'success';
221
+ } catch {
222
+ checkConclusion = 'failure';
223
+ }
224
+ const pr = ghJson(['pr', 'view', String(listed.number), '--json', 'number,headRefName,headRefOid,isCrossRepository,files,body'], env);
225
+ const files = (pr.files || []).map((file) => file.path).filter(Boolean);
226
+ const recorded = String(pr.body || '').match(/Generated head SHA: `([0-9a-f]{40})`/i);
227
+ return {
228
+ origin: pr.isCrossRepository ? 'fork' : 'same-repo',
229
+ headRef: pr.headRefName,
230
+ headSha: pr.headRefOid,
231
+ expectedGeneratedSha: recorded ? recorded[1] : 'missing-generated-sha',
232
+ files,
233
+ checkConclusion,
234
+ number: pr.number,
235
+ };
236
+ },
237
+ fromTrustedWorkflow: async () => (
238
+ env.GITHUB_ACTIONS === 'true' && (
239
+ String(env.GITHUB_WORKFLOW_REF || '').includes(`${REGISTRY_SYNC_WORKFLOW_FILE}`)
240
+ || String(env.GITHUB_WORKFLOW_FILE || '') === REGISTRY_SYNC_WORKFLOW_FILE
241
+ || /registry[\s_-]?sync/i.test(String(env.GITHUB_WORKFLOW || ''))
242
+ )
243
+ ),
244
+ defaultBranchProtected: async () => {
245
+ try {
246
+ const repo = env.GITHUB_REPOSITORY || 'Djordje-Stojanovic/Sigmaskills';
247
+ const parsed = JSON.parse(execFileSync(
248
+ 'gh',
249
+ ['api', `repos/${repo}/branches/main`],
250
+ { encoding: 'utf8', env },
251
+ ));
252
+ return parsed.protected === true;
253
+ } catch {
254
+ return false;
255
+ }
256
+ },
257
+ classification: async () => {
258
+ const repo = env.GITHUB_REPOSITORY;
259
+ const prs = ghJson(['pr', 'list', '--state', 'open', '--json', 'number,headRefName,headRefOid'], env)
260
+ .filter((item) => String(item.headRefName || '').startsWith(GENERATED_BRANCH_PREFIX));
261
+ if (prs.length !== 1) return { autoEligible: false, blockedReasons: ['no generated pull request'] };
262
+ const readSnapshot = (ref) => {
263
+ const parsed = JSON.parse(execFileSync(
264
+ 'gh',
265
+ ['api', `repos/${repo}/contents/registry/agent-hosts.json?ref=${ref}`],
266
+ { encoding: 'utf8', env },
267
+ ));
268
+ return JSON.parse(Buffer.from(parsed.content, 'base64').toString('utf8'));
269
+ };
270
+ const current = readSnapshot(prs[0].headRefOid);
271
+ const validation = validateSnapshot(current);
272
+ if (!validation.valid) {
273
+ return {
274
+ autoEligible: false,
275
+ blockedReasons: [...(validation.errors || []), ...Object.values(validation.hostErrors || {})],
276
+ };
277
+ }
278
+ return classifySemanticAuthority(diffSnapshots(readSnapshot('main'), current));
279
+ },
280
+ acquireVersionLock: async () => {
281
+ const runs = ghJson(['run', 'list', '--workflow', REGISTRY_SYNC_WORKFLOW_FILE, '--status', 'in_progress', '--json', 'databaseId'], env);
282
+ if (runs.length > 1) throw new Error('concurrent registry-sync run holds the version lock');
283
+ return { release: async () => {} };
284
+ },
285
+ reconcilePublishedState: async () => ({
286
+ packageVersion: JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version,
287
+ npmVersions: npmVersions(),
288
+ githubVersions: githubVersions(env),
289
+ }),
290
+ mergePullRequest: async (pr) => {
291
+ execFileSync('gh', ['pr', 'merge', String(pr.number), '--squash'], {
292
+ cwd: ROOT,
293
+ encoding: 'utf8',
294
+ env,
295
+ });
296
+ git(['fetch', 'origin', 'main'], { stdio: 'ignore' });
297
+ return { merged: true, sha: git(['rev-parse', 'origin/main']), number: pr.number };
298
+ },
299
+ verifyMerge: async (merged) => {
300
+ const view = ghJson(['pr', 'view', String(merged.number), '--json', 'state,mergeCommit'], env);
301
+ const sha = view.mergeCommit && (view.mergeCommit.oid || view.mergeCommit);
302
+ return { ok: view.state === 'MERGED' && Boolean(sha), sha };
303
+ },
304
+ commitPatchIdentities: async ({ version }) => {
305
+ git(['fetch', 'origin', 'main']);
306
+ git(['checkout', 'main']);
307
+ git(['pull', '--ff-only', 'origin', 'main']);
308
+ if (env.GITHUB_ACTIONS) {
309
+ git(['config', 'user.name', 'github-actions[bot]']);
310
+ git(['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
311
+ }
312
+ const applied = applyRegistryPatchIdentities({
313
+ packageJson: JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')),
314
+ manifest: JSON.parse(fs.readFileSync(path.join(ROOT, 'manifest.json'), 'utf8')),
315
+ changelog: fs.readFileSync(path.join(ROOT, 'CHANGELOG.md'), 'utf8'),
316
+ version,
317
+ date: new Date().toISOString().slice(0, 10),
318
+ note: 'Agent Host registry patch from trusted registry-sync automation.',
319
+ });
320
+ fs.writeFileSync(path.join(ROOT, 'package.json'), `${JSON.stringify(applied.packageJson, null, 2)}\n`);
321
+ fs.writeFileSync(path.join(ROOT, 'manifest.json'), `${JSON.stringify(applied.manifest, null, 2)}\n`);
322
+ fs.writeFileSync(path.join(ROOT, 'CHANGELOG.md'), applied.changelog);
323
+ git(['add', '--', 'package.json', 'manifest.json', 'CHANGELOG.md']);
324
+ git(['commit', '-m', `chore(release): ${version} Agent Host registry patch`]);
325
+ git(['push', 'origin', 'HEAD:main']);
326
+ return { commit: git(['rev-parse', 'HEAD']), version };
327
+ },
328
+ trustedPatchRelease: async (payload) => {
329
+ const probes = probePublication(payload.version, env);
330
+ const rootDir = ROOT;
331
+ return executeTrustedPatchRelease({
332
+ version: payload.version,
333
+ commit: payload.commit,
334
+ rootDir,
335
+ ...probes,
336
+ publishers: {
337
+ createTag: (preview) => {
338
+ try {
339
+ execFileSync('git', ['tag', preview.tag, preview.commit], { cwd: rootDir, encoding: 'utf8' });
340
+ } catch {
341
+ // Tag may already exist at this commit.
342
+ }
343
+ execFileSync('git', ['push', 'origin', preview.tag], { cwd: rootDir, encoding: 'utf8' });
344
+ },
345
+ createGithubRelease: (preview) => {
346
+ execFileSync(
347
+ 'gh',
348
+ ['release', 'create', preview.tag, '--target', preview.commit, '--title', preview.tag, '--notes', `Agent Host registry patch ${preview.version}`],
349
+ { cwd: rootDir, encoding: 'utf8', env },
350
+ );
351
+ },
352
+ publishNpm: (preview) => {
353
+ const artifact = preview.tarball?.path;
354
+ execFileSync(
355
+ 'npm',
356
+ artifact
357
+ ? ['publish', artifact, '--access', 'public', '--tag', RELEASE_DIST_TAG, '--provenance']
358
+ : ['publish', '--access', 'public', '--tag', RELEASE_DIST_TAG, '--provenance'],
359
+ { cwd: rootDir, encoding: 'utf8', env },
360
+ );
361
+ },
362
+ },
363
+ });
364
+ },
365
+ verifyPublication: async (published) => {
366
+ const probes = probePublication(published.version, env);
367
+ const npmOk = Boolean(probes.npmPackage.versions?.[published.version]);
368
+ const githubOk = Boolean(probes.githubRelease);
369
+ return { ok: npmOk && githubOk, npmMatches: npmOk, githubMatches: githubOk };
370
+ },
371
+ deleteBranch: async (name) => {
372
+ if (!name.startsWith(GENERATED_BRANCH_PREFIX)) {
373
+ throw new Error(`refusing to delete non-generated branch ${name}`);
374
+ }
375
+ execFileSync('git', ['push', 'origin', '--delete', name], { cwd: ROOT, encoding: 'utf8', env });
376
+ },
377
+ };
378
+ }
379
+
380
+ const mode = process.argv[2] || 'generate';
381
+ const env = process.env;
382
+ const dryRun = env.DRY_RUN === '1' || process.argv.includes('--dry-run');
383
+
384
+ try {
385
+ const result = await executeRegistryAutomation({
386
+ mode,
387
+ dryRun,
388
+ expectedHead: env.EXPECTED_HEAD,
389
+ upstreamRevision: env.UPSTREAM_REVISION || undefined,
390
+ }, createRealIo(env, mode));
391
+ console.log(JSON.stringify({
392
+ ok: result.ok !== false,
393
+ dryRun: result.dryRun === true,
394
+ autoEligible: result.classification && result.classification.autoEligible,
395
+ autoAuthorized: result.autoAuthorized === true
396
+ || (result.autoAuthorization && result.autoAuthorization.autoAuthorized),
397
+ blockedReasons: result.deniedReasons
398
+ || (result.classification && result.classification.blockedReasons)
399
+ || [],
400
+ wouldDelete: result.wouldDelete || [],
401
+ files: result.files || [],
402
+ merged: result.merged === true,
403
+ published: result.published === true,
404
+ version: result.version || null,
405
+ actions: result.actions || { merge: false, publishNpm: false },
406
+ }, null, 2));
407
+ if (result.ok === false) process.exit(1);
408
+ } catch (err) {
409
+ console.error(err.message || err);
410
+ process.exit(1);
411
+ }