@dzhechkov/harness-core 0.3.5 → 0.3.7
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.
- package/dist/downloads.d.ts +22 -0
- package/dist/downloads.d.ts.map +1 -0
- package/dist/downloads.js +36 -0
- package/dist/downloads.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/publish.d.ts +35 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +87 -0
- package/dist/publish.js.map +1 -0
- package/dist/upgrade.d.ts +35 -0
- package/dist/upgrade.d.ts.map +1 -0
- package/dist/upgrade.js +77 -0
- package/dist/upgrade.js.map +1 -0
- package/package.json +2 -2
- package/src/downloads.ts +54 -0
- package/src/index.ts +6 -0
- package/src/publish.ts +121 -0
- package/src/upgrade.ts +113 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm download statistics — fetches weekly download counts for all published packages.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** Download stats for a single package. */
|
|
7
|
+
export interface PackageDownloads {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly downloads: number;
|
|
10
|
+
readonly period: string;
|
|
11
|
+
readonly error?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/** Full downloads report. */
|
|
14
|
+
export interface DownloadsReport {
|
|
15
|
+
readonly packages: readonly PackageDownloads[];
|
|
16
|
+
readonly totalDownloads: number;
|
|
17
|
+
readonly period: string;
|
|
18
|
+
readonly fetchedAt: string;
|
|
19
|
+
}
|
|
20
|
+
/** Fetch downloads for all given package names. */
|
|
21
|
+
export declare function fetchAllDownloads(packageNames: string[]): Promise<DownloadsReport>;
|
|
22
|
+
//# sourceMappingURL=downloads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloads.d.ts","sourceRoot":"","sources":["../src/downloads.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,6BAA6B;AAC7B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAuBD,mDAAmD;AACnD,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CASxF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm download statistics — fetches weekly download counts for all published packages.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** Fetch weekly downloads for a single npm package. */
|
|
7
|
+
async function fetchDownloads(name) {
|
|
8
|
+
const period = 'last-week';
|
|
9
|
+
try {
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const timer = setTimeout(() => { controller.abort(); }, 10000);
|
|
12
|
+
const url = `https://api.npmjs.org/downloads/point/${period}/${encodeURIComponent(name)}`;
|
|
13
|
+
const resp = await fetch(url, { signal: controller.signal });
|
|
14
|
+
clearTimeout(timer);
|
|
15
|
+
if (!resp.ok) {
|
|
16
|
+
return { name, downloads: 0, period, error: `HTTP ${resp.status}` };
|
|
17
|
+
}
|
|
18
|
+
const data = (await resp.json());
|
|
19
|
+
return { name, downloads: data.downloads, period };
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
return { name, downloads: 0, period, error: err instanceof Error ? err.message : String(err) };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Fetch downloads for all given package names. */
|
|
26
|
+
export async function fetchAllDownloads(packageNames) {
|
|
27
|
+
const results = await Promise.all(packageNames.map(fetchDownloads));
|
|
28
|
+
results.sort((a, b) => b.downloads - a.downloads);
|
|
29
|
+
return {
|
|
30
|
+
packages: results,
|
|
31
|
+
totalDownloads: results.reduce((sum, r) => sum + r.downloads, 0),
|
|
32
|
+
period: 'last-week',
|
|
33
|
+
fetchedAt: new Date().toISOString(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=downloads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloads.js","sourceRoot":"","sources":["../src/downloads.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,uDAAuD;AACvD,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,yCAAyC,MAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1F,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,YAAY,CAAC,KAAK,CAAC,CAAC;QAEpB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACtE,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA0B,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACjG,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAsB;IAC5D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAClD,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAChE,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,12 @@ export { checkUpstream, loadSourcesManifest } from './sync-upstream.js';
|
|
|
16
16
|
export type { SyncUpstreamReport, UpstreamCheckResult, SourcesManifest } from './sync-upstream.js';
|
|
17
17
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
18
18
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
19
|
+
export { discoverPackages, publishPackages } from './publish.js';
|
|
20
|
+
export { fetchAllDownloads } from './downloads.js';
|
|
21
|
+
export type { PackageDownloads, DownloadsReport } from './downloads.js';
|
|
22
|
+
export { discoverInstalled, checkUpgrades } from './upgrade.js';
|
|
23
|
+
export type { InstalledSkill, UpgradeCheck, UpgradeReport } from './upgrade.js';
|
|
24
|
+
export type { PublishResult, PublishReport } from './publish.js';
|
|
19
25
|
export type { RegistryEntry, Registry } from './registry.js';
|
|
20
26
|
export type { BenchmarkCheck, BenchmarkScore, BenchmarkReport, CompareResult } from './benchmark.js';
|
|
21
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,4 +14,7 @@ export { createSkill } from './create-skill.js';
|
|
|
14
14
|
export { checkUpstream, loadSourcesManifest } from './sync-upstream.js';
|
|
15
15
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
16
16
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
17
|
+
export { discoverPackages, publishPackages } from './publish.js';
|
|
18
|
+
export { fetchAllDownloads } from './downloads.js';
|
|
19
|
+
export { discoverInstalled, checkUpgrades } from './upgrade.js';
|
|
17
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automated publish — discovers changed packages, bumps patch versions,
|
|
3
|
+
* builds, and publishes to npm.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
/** Result for a single package publish attempt. */
|
|
8
|
+
export interface PublishResult {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly oldVersion: string;
|
|
11
|
+
readonly newVersion: string;
|
|
12
|
+
readonly status: 'published' | 'skipped' | 'error';
|
|
13
|
+
readonly error?: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Full publish report. */
|
|
16
|
+
export interface PublishReport {
|
|
17
|
+
readonly packages: readonly PublishResult[];
|
|
18
|
+
readonly published: number;
|
|
19
|
+
readonly skipped: number;
|
|
20
|
+
readonly errors: number;
|
|
21
|
+
readonly dryRun: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Discover all publishable @dzhechkov packages. */
|
|
24
|
+
export declare function discoverPackages(monorepoRoot: string): {
|
|
25
|
+
name: string;
|
|
26
|
+
dir: string;
|
|
27
|
+
version: string;
|
|
28
|
+
}[];
|
|
29
|
+
/** Publish packages that have changes since last publish. */
|
|
30
|
+
export declare function publishPackages(monorepoRoot: string, opts?: {
|
|
31
|
+
dryRun?: boolean | undefined;
|
|
32
|
+
filter?: string[] | undefined;
|
|
33
|
+
bumpOnly?: boolean | undefined;
|
|
34
|
+
}): PublishReport;
|
|
35
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,2BAA2B;AAC3B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AASD,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAavG;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE;IACJ,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3B,GACL,aAAa,CA4Df"}
|
package/dist/publish.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automated publish — discovers changed packages, bumps patch versions,
|
|
3
|
+
* builds, and publishes to npm.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
/** Bump patch version: 0.3.11 → 0.3.12 */
|
|
11
|
+
function bumpPatch(version) {
|
|
12
|
+
const parts = version.split('.');
|
|
13
|
+
const patch = parseInt(parts[2] ?? '0', 10);
|
|
14
|
+
return `${parts[0]}.${parts[1]}.${patch + 1}`;
|
|
15
|
+
}
|
|
16
|
+
/** Discover all publishable @dzhechkov packages. */
|
|
17
|
+
export function discoverPackages(monorepoRoot) {
|
|
18
|
+
const baseDir = join(monorepoRoot, 'packages', '@dzhechkov');
|
|
19
|
+
if (!existsSync(baseDir))
|
|
20
|
+
return [];
|
|
21
|
+
return readdirSync(baseDir, { withFileTypes: true })
|
|
22
|
+
.filter((e) => e.isDirectory())
|
|
23
|
+
.map((e) => {
|
|
24
|
+
const pkgPath = join(baseDir, e.name, 'package.json');
|
|
25
|
+
if (!existsSync(pkgPath))
|
|
26
|
+
return undefined;
|
|
27
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
28
|
+
return { name: pkg.name, dir: join(baseDir, e.name), version: pkg.version };
|
|
29
|
+
})
|
|
30
|
+
.filter((p) => p !== undefined);
|
|
31
|
+
}
|
|
32
|
+
/** Publish packages that have changes since last publish. */
|
|
33
|
+
export function publishPackages(monorepoRoot, opts = {}) {
|
|
34
|
+
const packages = discoverPackages(monorepoRoot);
|
|
35
|
+
const results = [];
|
|
36
|
+
const filtered = opts.filter && opts.filter.length > 0
|
|
37
|
+
? packages.filter((p) => opts.filter.some((f) => p.name.includes(f) || p.dir.includes(f)))
|
|
38
|
+
: packages;
|
|
39
|
+
for (const pkg of filtered) {
|
|
40
|
+
const oldVersion = pkg.version;
|
|
41
|
+
const newVersion = bumpPatch(oldVersion);
|
|
42
|
+
if (opts.dryRun) {
|
|
43
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'skipped' });
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
// Bump version in package.json
|
|
48
|
+
const pkgJsonPath = join(pkg.dir, 'package.json');
|
|
49
|
+
const pkgJson = readFileSync(pkgJsonPath, 'utf-8');
|
|
50
|
+
writeFileSync(pkgJsonPath, pkgJson.replace(`"version": "${oldVersion}"`, `"version": "${newVersion}"`));
|
|
51
|
+
if (opts.bumpOnly) {
|
|
52
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'published' });
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Build if has build script
|
|
56
|
+
const parsed = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
57
|
+
if (parsed.scripts?.['build']) {
|
|
58
|
+
execSync('pnpm build', { cwd: pkg.dir, stdio: 'pipe', encoding: 'utf-8' });
|
|
59
|
+
}
|
|
60
|
+
// Publish
|
|
61
|
+
execSync('pnpm publish --access public --no-git-checks', {
|
|
62
|
+
cwd: pkg.dir,
|
|
63
|
+
stdio: 'pipe',
|
|
64
|
+
encoding: 'utf-8',
|
|
65
|
+
env: { ...process.env },
|
|
66
|
+
});
|
|
67
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'published' });
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
results.push({
|
|
71
|
+
name: pkg.name,
|
|
72
|
+
oldVersion,
|
|
73
|
+
newVersion,
|
|
74
|
+
status: 'error',
|
|
75
|
+
error: err instanceof Error ? err.message : String(err),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
packages: results,
|
|
81
|
+
published: results.filter((r) => r.status === 'published').length,
|
|
82
|
+
skipped: results.filter((r) => r.status === 'skipped').length,
|
|
83
|
+
errors: results.filter((r) => r.status === 'error').length,
|
|
84
|
+
dryRun: opts.dryRun === true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill upgrade — detects installed skills and re-applies from canonical source.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** Info about an installed skill. */
|
|
7
|
+
export interface InstalledSkill {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly size: number;
|
|
11
|
+
readonly modifiedAt: string;
|
|
12
|
+
readonly hasFrontmatter: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Upgrade check for a single skill. */
|
|
15
|
+
export interface UpgradeCheck {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly installed: InstalledSkill;
|
|
18
|
+
readonly canonicalSize: number | undefined;
|
|
19
|
+
readonly needsUpdate: boolean;
|
|
20
|
+
readonly reason: string;
|
|
21
|
+
}
|
|
22
|
+
/** Full upgrade report. */
|
|
23
|
+
export interface UpgradeReport {
|
|
24
|
+
readonly targetDir: string;
|
|
25
|
+
readonly installed: number;
|
|
26
|
+
readonly needsUpdate: number;
|
|
27
|
+
readonly upToDate: number;
|
|
28
|
+
readonly notInCanonical: number;
|
|
29
|
+
readonly skills: readonly UpgradeCheck[];
|
|
30
|
+
}
|
|
31
|
+
/** Discover installed skills in a target platform directory. */
|
|
32
|
+
export declare function discoverInstalled(targetDir: string): InstalledSkill[];
|
|
33
|
+
/** Check which installed skills need updates by comparing with canonical sources. */
|
|
34
|
+
export declare function checkUpgrades(targetDir: string, canonicalDirs: string[]): UpgradeReport;
|
|
35
|
+
//# sourceMappingURL=upgrade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../src/upgrade.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,2BAA2B;AAC3B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;CAC1C;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAgBrE;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EAAE,GACtB,aAAa,CAoDf"}
|
package/dist/upgrade.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill upgrade — detects installed skills and re-applies from canonical source.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
/** Discover installed skills in a target platform directory. */
|
|
9
|
+
export function discoverInstalled(targetDir) {
|
|
10
|
+
if (!existsSync(targetDir))
|
|
11
|
+
return [];
|
|
12
|
+
return readdirSync(targetDir, { withFileTypes: true })
|
|
13
|
+
.filter((e) => e.isDirectory() && existsSync(join(targetDir, e.name, 'SKILL.md')))
|
|
14
|
+
.map((e) => {
|
|
15
|
+
const skillMdPath = join(targetDir, e.name, 'SKILL.md');
|
|
16
|
+
const stat = statSync(skillMdPath);
|
|
17
|
+
const content = readFileSync(skillMdPath, 'utf-8');
|
|
18
|
+
return {
|
|
19
|
+
id: e.name,
|
|
20
|
+
path: join(targetDir, e.name),
|
|
21
|
+
size: stat.size,
|
|
22
|
+
modifiedAt: stat.mtime.toISOString().slice(0, 10),
|
|
23
|
+
hasFrontmatter: content.startsWith('---'),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Check which installed skills need updates by comparing with canonical sources. */
|
|
28
|
+
export function checkUpgrades(targetDir, canonicalDirs) {
|
|
29
|
+
const installed = discoverInstalled(targetDir);
|
|
30
|
+
// Build canonical index: skill id → { dir, size }
|
|
31
|
+
const canonical = new Map();
|
|
32
|
+
for (const cDir of canonicalDirs) {
|
|
33
|
+
if (!existsSync(cDir))
|
|
34
|
+
continue;
|
|
35
|
+
const skills = readdirSync(cDir, { withFileTypes: true })
|
|
36
|
+
.filter((e) => e.isDirectory() && existsSync(join(cDir, e.name, 'SKILL.md')));
|
|
37
|
+
for (const skill of skills) {
|
|
38
|
+
const skillMdPath = join(cDir, skill.name, 'SKILL.md');
|
|
39
|
+
const stat = statSync(skillMdPath);
|
|
40
|
+
canonical.set(skill.name, { dir: join(cDir, skill.name), size: stat.size });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const checks = [];
|
|
44
|
+
for (const inst of installed) {
|
|
45
|
+
const can = canonical.get(inst.id);
|
|
46
|
+
if (!can) {
|
|
47
|
+
checks.push({
|
|
48
|
+
id: inst.id,
|
|
49
|
+
installed: inst,
|
|
50
|
+
canonicalSize: undefined,
|
|
51
|
+
needsUpdate: false,
|
|
52
|
+
reason: 'not in canonical (custom or removed)',
|
|
53
|
+
});
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const sizeDiff = Math.abs(inst.size - can.size);
|
|
57
|
+
const needsUpdate = sizeDiff > 0;
|
|
58
|
+
checks.push({
|
|
59
|
+
id: inst.id,
|
|
60
|
+
installed: inst,
|
|
61
|
+
canonicalSize: can.size,
|
|
62
|
+
needsUpdate,
|
|
63
|
+
reason: needsUpdate
|
|
64
|
+
? `size differs (installed: ${inst.size}B, canonical: ${can.size}B, delta: ${sizeDiff}B)`
|
|
65
|
+
: 'up to date',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
targetDir,
|
|
70
|
+
installed: installed.length,
|
|
71
|
+
needsUpdate: checks.filter((c) => c.needsUpdate).length,
|
|
72
|
+
upToDate: checks.filter((c) => !c.needsUpdate && c.canonicalSize !== undefined).length,
|
|
73
|
+
notInCanonical: checks.filter((c) => c.canonicalSize === undefined).length,
|
|
74
|
+
skills: checks,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../src/upgrade.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Shared harness logic - skill loading, additive apply, and the init/sync/verify/doctor operations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"yaml": "^2.0.0",
|
|
28
28
|
"@dzhechkov/adapter-claude": "0.2.0",
|
|
29
|
+
"@dzhechkov/adapter-codex": "0.2.0",
|
|
29
30
|
"@dzhechkov/adapter-hermes": "0.2.0",
|
|
30
31
|
"@dzhechkov/adapter-opencode": "0.2.0",
|
|
31
|
-
"@dzhechkov/adapter-codex": "0.2.0",
|
|
32
32
|
"@dzhechkov/adapter-openclaude": "0.1.0",
|
|
33
33
|
"@dzhechkov/core": "0.2.0"
|
|
34
34
|
},
|
package/src/downloads.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm download statistics — fetches weekly download counts for all published packages.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Download stats for a single package. */
|
|
8
|
+
export interface PackageDownloads {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly downloads: number;
|
|
11
|
+
readonly period: string;
|
|
12
|
+
readonly error?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Full downloads report. */
|
|
16
|
+
export interface DownloadsReport {
|
|
17
|
+
readonly packages: readonly PackageDownloads[];
|
|
18
|
+
readonly totalDownloads: number;
|
|
19
|
+
readonly period: string;
|
|
20
|
+
readonly fetchedAt: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Fetch weekly downloads for a single npm package. */
|
|
24
|
+
async function fetchDownloads(name: string): Promise<PackageDownloads> {
|
|
25
|
+
const period = 'last-week';
|
|
26
|
+
try {
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
const timer = setTimeout(() => { controller.abort(); }, 10000);
|
|
29
|
+
const url = `https://api.npmjs.org/downloads/point/${period}/${encodeURIComponent(name)}`;
|
|
30
|
+
const resp = await fetch(url, { signal: controller.signal });
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
|
|
33
|
+
if (!resp.ok) {
|
|
34
|
+
return { name, downloads: 0, period, error: `HTTP ${resp.status}` };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const data = (await resp.json()) as { downloads: number };
|
|
38
|
+
return { name, downloads: data.downloads, period };
|
|
39
|
+
} catch (err) {
|
|
40
|
+
return { name, downloads: 0, period, error: err instanceof Error ? err.message : String(err) };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Fetch downloads for all given package names. */
|
|
45
|
+
export async function fetchAllDownloads(packageNames: string[]): Promise<DownloadsReport> {
|
|
46
|
+
const results = await Promise.all(packageNames.map(fetchDownloads));
|
|
47
|
+
results.sort((a, b) => b.downloads - a.downloads);
|
|
48
|
+
return {
|
|
49
|
+
packages: results,
|
|
50
|
+
totalDownloads: results.reduce((sum, r) => sum + r.downloads, 0),
|
|
51
|
+
period: 'last-week',
|
|
52
|
+
fetchedAt: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -18,5 +18,11 @@ export { checkUpstream, loadSourcesManifest } from './sync-upstream.js';
|
|
|
18
18
|
export type { SyncUpstreamReport, UpstreamCheckResult, SourcesManifest } from './sync-upstream.js';
|
|
19
19
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
20
20
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
21
|
+
export { discoverPackages, publishPackages } from './publish.js';
|
|
22
|
+
export { fetchAllDownloads } from './downloads.js';
|
|
23
|
+
export type { PackageDownloads, DownloadsReport } from './downloads.js';
|
|
24
|
+
export { discoverInstalled, checkUpgrades } from './upgrade.js';
|
|
25
|
+
export type { InstalledSkill, UpgradeCheck, UpgradeReport } from './upgrade.js';
|
|
26
|
+
export type { PublishResult, PublishReport } from './publish.js';
|
|
21
27
|
export type { RegistryEntry, Registry } from './registry.js';
|
|
22
28
|
export type { BenchmarkCheck, BenchmarkScore, BenchmarkReport, CompareResult } from './benchmark.js';
|
package/src/publish.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automated publish — discovers changed packages, bumps patch versions,
|
|
3
|
+
* builds, and publishes to npm.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
|
|
12
|
+
/** Result for a single package publish attempt. */
|
|
13
|
+
export interface PublishResult {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly oldVersion: string;
|
|
16
|
+
readonly newVersion: string;
|
|
17
|
+
readonly status: 'published' | 'skipped' | 'error';
|
|
18
|
+
readonly error?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Full publish report. */
|
|
22
|
+
export interface PublishReport {
|
|
23
|
+
readonly packages: readonly PublishResult[];
|
|
24
|
+
readonly published: number;
|
|
25
|
+
readonly skipped: number;
|
|
26
|
+
readonly errors: number;
|
|
27
|
+
readonly dryRun: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Bump patch version: 0.3.11 → 0.3.12 */
|
|
31
|
+
function bumpPatch(version: string): string {
|
|
32
|
+
const parts = version.split('.');
|
|
33
|
+
const patch = parseInt(parts[2] ?? '0', 10);
|
|
34
|
+
return `${parts[0]}.${parts[1]}.${patch + 1}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Discover all publishable @dzhechkov packages. */
|
|
38
|
+
export function discoverPackages(monorepoRoot: string): { name: string; dir: string; version: string }[] {
|
|
39
|
+
const baseDir = join(monorepoRoot, 'packages', '@dzhechkov');
|
|
40
|
+
if (!existsSync(baseDir)) return [];
|
|
41
|
+
|
|
42
|
+
return readdirSync(baseDir, { withFileTypes: true })
|
|
43
|
+
.filter((e) => e.isDirectory())
|
|
44
|
+
.map((e) => {
|
|
45
|
+
const pkgPath = join(baseDir, e.name, 'package.json');
|
|
46
|
+
if (!existsSync(pkgPath)) return undefined;
|
|
47
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name: string; version: string };
|
|
48
|
+
return { name: pkg.name, dir: join(baseDir, e.name), version: pkg.version };
|
|
49
|
+
})
|
|
50
|
+
.filter((p): p is { name: string; dir: string; version: string } => p !== undefined);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Publish packages that have changes since last publish. */
|
|
54
|
+
export function publishPackages(
|
|
55
|
+
monorepoRoot: string,
|
|
56
|
+
opts: {
|
|
57
|
+
dryRun?: boolean | undefined;
|
|
58
|
+
filter?: string[] | undefined;
|
|
59
|
+
bumpOnly?: boolean | undefined;
|
|
60
|
+
} = {},
|
|
61
|
+
): PublishReport {
|
|
62
|
+
const packages = discoverPackages(monorepoRoot);
|
|
63
|
+
const results: PublishResult[] = [];
|
|
64
|
+
const filtered = opts.filter && opts.filter.length > 0
|
|
65
|
+
? packages.filter((p) => opts.filter!.some((f) => p.name.includes(f) || p.dir.includes(f)))
|
|
66
|
+
: packages;
|
|
67
|
+
|
|
68
|
+
for (const pkg of filtered) {
|
|
69
|
+
const oldVersion = pkg.version;
|
|
70
|
+
const newVersion = bumpPatch(oldVersion);
|
|
71
|
+
|
|
72
|
+
if (opts.dryRun) {
|
|
73
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'skipped' });
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Bump version in package.json
|
|
79
|
+
const pkgJsonPath = join(pkg.dir, 'package.json');
|
|
80
|
+
const pkgJson = readFileSync(pkgJsonPath, 'utf-8');
|
|
81
|
+
writeFileSync(pkgJsonPath, pkgJson.replace(`"version": "${oldVersion}"`, `"version": "${newVersion}"`));
|
|
82
|
+
|
|
83
|
+
if (opts.bumpOnly) {
|
|
84
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'published' });
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Build if has build script
|
|
89
|
+
const parsed = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')) as { scripts?: Record<string, string> };
|
|
90
|
+
if (parsed.scripts?.['build']) {
|
|
91
|
+
execSync('pnpm build', { cwd: pkg.dir, stdio: 'pipe', encoding: 'utf-8' });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Publish
|
|
95
|
+
execSync('pnpm publish --access public --no-git-checks', {
|
|
96
|
+
cwd: pkg.dir,
|
|
97
|
+
stdio: 'pipe',
|
|
98
|
+
encoding: 'utf-8',
|
|
99
|
+
env: { ...process.env },
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
results.push({ name: pkg.name, oldVersion, newVersion, status: 'published' });
|
|
103
|
+
} catch (err) {
|
|
104
|
+
results.push({
|
|
105
|
+
name: pkg.name,
|
|
106
|
+
oldVersion,
|
|
107
|
+
newVersion,
|
|
108
|
+
status: 'error',
|
|
109
|
+
error: err instanceof Error ? err.message : String(err),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
packages: results,
|
|
116
|
+
published: results.filter((r) => r.status === 'published').length,
|
|
117
|
+
skipped: results.filter((r) => r.status === 'skipped').length,
|
|
118
|
+
errors: results.filter((r) => r.status === 'error').length,
|
|
119
|
+
dryRun: opts.dryRun === true,
|
|
120
|
+
};
|
|
121
|
+
}
|
package/src/upgrade.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill upgrade — detects installed skills and re-applies from canonical source.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
|
|
10
|
+
/** Info about an installed skill. */
|
|
11
|
+
export interface InstalledSkill {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly size: number;
|
|
15
|
+
readonly modifiedAt: string;
|
|
16
|
+
readonly hasFrontmatter: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Upgrade check for a single skill. */
|
|
20
|
+
export interface UpgradeCheck {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly installed: InstalledSkill;
|
|
23
|
+
readonly canonicalSize: number | undefined;
|
|
24
|
+
readonly needsUpdate: boolean;
|
|
25
|
+
readonly reason: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Full upgrade report. */
|
|
29
|
+
export interface UpgradeReport {
|
|
30
|
+
readonly targetDir: string;
|
|
31
|
+
readonly installed: number;
|
|
32
|
+
readonly needsUpdate: number;
|
|
33
|
+
readonly upToDate: number;
|
|
34
|
+
readonly notInCanonical: number;
|
|
35
|
+
readonly skills: readonly UpgradeCheck[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Discover installed skills in a target platform directory. */
|
|
39
|
+
export function discoverInstalled(targetDir: string): InstalledSkill[] {
|
|
40
|
+
if (!existsSync(targetDir)) return [];
|
|
41
|
+
return readdirSync(targetDir, { withFileTypes: true })
|
|
42
|
+
.filter((e) => e.isDirectory() && existsSync(join(targetDir, e.name, 'SKILL.md')))
|
|
43
|
+
.map((e) => {
|
|
44
|
+
const skillMdPath = join(targetDir, e.name, 'SKILL.md');
|
|
45
|
+
const stat = statSync(skillMdPath);
|
|
46
|
+
const content = readFileSync(skillMdPath, 'utf-8');
|
|
47
|
+
return {
|
|
48
|
+
id: e.name,
|
|
49
|
+
path: join(targetDir, e.name),
|
|
50
|
+
size: stat.size,
|
|
51
|
+
modifiedAt: stat.mtime.toISOString().slice(0, 10),
|
|
52
|
+
hasFrontmatter: content.startsWith('---'),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Check which installed skills need updates by comparing with canonical sources. */
|
|
58
|
+
export function checkUpgrades(
|
|
59
|
+
targetDir: string,
|
|
60
|
+
canonicalDirs: string[],
|
|
61
|
+
): UpgradeReport {
|
|
62
|
+
const installed = discoverInstalled(targetDir);
|
|
63
|
+
|
|
64
|
+
// Build canonical index: skill id → { dir, size }
|
|
65
|
+
const canonical = new Map<string, { dir: string; size: number }>();
|
|
66
|
+
for (const cDir of canonicalDirs) {
|
|
67
|
+
if (!existsSync(cDir)) continue;
|
|
68
|
+
const skills = readdirSync(cDir, { withFileTypes: true })
|
|
69
|
+
.filter((e) => e.isDirectory() && existsSync(join(cDir, e.name, 'SKILL.md')));
|
|
70
|
+
for (const skill of skills) {
|
|
71
|
+
const skillMdPath = join(cDir, skill.name, 'SKILL.md');
|
|
72
|
+
const stat = statSync(skillMdPath);
|
|
73
|
+
canonical.set(skill.name, { dir: join(cDir, skill.name), size: stat.size });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const checks: UpgradeCheck[] = [];
|
|
78
|
+
|
|
79
|
+
for (const inst of installed) {
|
|
80
|
+
const can = canonical.get(inst.id);
|
|
81
|
+
if (!can) {
|
|
82
|
+
checks.push({
|
|
83
|
+
id: inst.id,
|
|
84
|
+
installed: inst,
|
|
85
|
+
canonicalSize: undefined,
|
|
86
|
+
needsUpdate: false,
|
|
87
|
+
reason: 'not in canonical (custom or removed)',
|
|
88
|
+
});
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const sizeDiff = Math.abs(inst.size - can.size);
|
|
93
|
+
const needsUpdate = sizeDiff > 0;
|
|
94
|
+
checks.push({
|
|
95
|
+
id: inst.id,
|
|
96
|
+
installed: inst,
|
|
97
|
+
canonicalSize: can.size,
|
|
98
|
+
needsUpdate,
|
|
99
|
+
reason: needsUpdate
|
|
100
|
+
? `size differs (installed: ${inst.size}B, canonical: ${can.size}B, delta: ${sizeDiff}B)`
|
|
101
|
+
: 'up to date',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
targetDir,
|
|
107
|
+
installed: installed.length,
|
|
108
|
+
needsUpdate: checks.filter((c) => c.needsUpdate).length,
|
|
109
|
+
upToDate: checks.filter((c) => !c.needsUpdate && c.canonicalSize !== undefined).length,
|
|
110
|
+
notInCanonical: checks.filter((c) => c.canonicalSize === undefined).length,
|
|
111
|
+
skills: checks,
|
|
112
|
+
};
|
|
113
|
+
}
|