@meyverick/agentic 5.0.2 → 5.1.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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +15 -0
- package/README.md +2 -1
- package/package.json +5 -5
- package/scripts/{check-deps.mjs → check-deps.ts} +124 -59
- package/scripts/{git-dl.mjs → git-dl.ts} +11 -9
- package/skills/create-skill/SKILL.md +16 -16
- package/skills/create-skill/assets/templates/SKILL.md.template +1 -1
- package/skills/create-skill/evals/evals.json +4 -4
- package/skills/create-skill/evals/grading-template.json +1 -1
- package/skills/create-skill/references/component-decomposition.md +1 -1
- package/skills/create-skill/scripts/{audit-antipatterns.mjs → audit-antipatterns.ts} +75 -31
- package/skills/create-skill/scripts/{compute-benchmark.mjs → compute-benchmark.ts} +71 -30
- package/skills/create-skill/scripts/run-cold-eval.ts +202 -0
- package/skills/create-skill/scripts/{scaffold-skill.mjs → scaffold-skill.ts} +45 -25
- package/skills/create-skill/scripts/validate-routing.ts +218 -0
- package/skills/create-skill/scripts/{validate-structure.mjs → validate-structure.ts} +97 -36
- package/skills/okf-docs/SKILL.md +1 -1
- package/skills/okf-docs/evals/evals.json +2 -2
- package/skills/okf-docs/scripts/{validate-frontmatter.mjs → validate-frontmatter.ts} +73 -32
- package/skills/openspec-learn/references/evaluation-methodology.md +2 -2
- package/skills/openspec-pi-apply/SKILL.md +129 -0
- package/skills/openspec-pi-apply/references/rpc-protocol.md +43 -0
- package/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts +421 -0
- package/skills/create-skill/scripts/run-cold-eval.mjs +0 -118
- package/skills/create-skill/scripts/validate-routing.mjs +0 -137
package/AGENTS.md
CHANGED
|
@@ -181,7 +181,7 @@ stale_after: 2027-08-15
|
|
|
181
181
|
- **QMD** (Hybrid Search & Local Memory): Project-local index only — `qmd init` at repo root → `<repo>/.qmd/` (gitignored); NEVER create or populate a global/shared index, never fall back to one. Mode select: exact terms/titles/headings/symbols → `qmd search '"<phrase>"' --json -n 10 -c <collection>` (BM25, no LLM); concept/paraphrase → `qmd query $'intent: <goal + what to avoid>\nlex: <anchors>\nvec: <paraphrase>' --json -n 10` (author the fields yourself — never paste raw request text). Retrieve before claiming: `qmd get "#id:from:count"` / `qmd multi-get "<ids>" --json` (never pipe `sed`/`head`/`tail`). Maintenance [CRITICAL] mutations → `qmd update && qmd embed --chunk-strategy auto`; health `qmd status`; depth `.agents/skills/qmd-research/` (query grammar · filters · index upkeep).
|
|
182
182
|
- **Context7** (External Framework Intelligence): Trigger [CRITICAL] generating third-party setup/config or touching frameworks/packages (SvelteKit, Tailwind, SQLx, ts-rs, miniplex, Threlte, babylonjs, PixiJS, Phaser, Axum, Rayon, candle, tauri, grammY, `@telegram-apps/sdk`) → autonomous Context7 → prevent hallucinated outdated training data. Flow: `resolve-library-id(name, query)` → `/org/project` ID → `query-docs(id, full_query)` → SOTA patterns. Append explicit versions to queries. Priority Context7 > web search. Bypass for internal business logic.
|
|
183
183
|
- **check** (Workspace Gate Verification): Textbook and diagnostic manual for `./scripts/check.sh` gates. Consult `.agents/skills/check/SKILL.md` when executing check-gates, configuring the 6-slot harness (pointers, secrets, native lanes, tracked compile-time assets, clean-clone sandbox, smoke), or diagnosing and self-healing gate failures.
|
|
184
|
-
- **Skill Engineering** (`./.agents/skills/`): Utilization [CRITICAL] task initiation → scan `./.agents/skills/` → evaluate `description` frontmatters → load `SKILL.md` if relevant. Creation: extract recurring gotchas/workflows into `skills/<name>/SKILL.md` (action gerund, Validation Loops, Plan-Validate-Execute, `references/` offload for progressive disclosure). Anatomy [CRITICAL] frontmatter per the Agent Skills spec (`name` + `description` required; `license` · `compatibility` · `metadata` · `allowed-tools` optional — OKF provenance `type`/`generated` is for documents, §7), `description` <1024 chars imperative "Use this skill when...". Script bundling: self-contained (Bun `.
|
|
184
|
+
- **Skill Engineering** (`./.agents/skills/`): Utilization [CRITICAL] task initiation → scan `./.agents/skills/` → evaluate `description` frontmatters → load `SKILL.md` if relevant. Creation: extract recurring gotchas/workflows into `skills/<name>/SKILL.md` (action gerund, Validation Loops, Plan-Validate-Execute, `references/` offload for progressive disclosure). Anatomy [CRITICAL] frontmatter per the Agent Skills spec (`name` + `description` required; `license` · `compatibility` · `metadata` · `allowed-tools` optional — OKF provenance `type`/`generated` is for documents, §7), `description` <1024 chars imperative "Use this skill when...". Script bundling: self-contained (Bun `.ts`/single-file Go/PEP 723), idempotent, structured JSON/CSV, ZERO prompts. Ad-hoc spikes [CRITICAL] candid debug scripts / pre-implementation endpoint tests / quick API validation → self-contained `.ts` via `bun <file>.ts` (native top-level await+fetch, zero setup). Eval-driven evolution: generate `evals/evals.json`, measure baseline vs with-skill (pass rate/tokens/duration) → optimize `SKILL.md`.
|
|
185
185
|
|
|
186
186
|
## 9. Exploration & Discovery Stance
|
|
187
187
|
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [5.1.0] - 2026-09-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **openspec-pi-apply skill** (`add-openspec-pi-apply-skill`): 10th shipped skill — delegate OpenSpec change task implementation to a headless pi worker agent via JSON-RPC (`scripts/pi-rpc-apply.ts`), providing live streaming, automated event loop triage, and non-blocking background task orchestration
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **Consumer scripts migrated to Bun TypeScript** (`migrate-consumer-scripts-to-bun-ts`): convert all 9 consumer scripts across `scripts/` and skill packages to self-contained, typed Bun `.ts` (`check-deps.ts`, `git-dl.ts`, `validate-frontmatter.ts`, `validate-structure.ts`, `validate-routing.ts`, `audit-antipatterns.ts`, `run-cold-eval.ts`, `compute-benchmark.ts`, `scaffold-skill.ts`) with `#!/usr/bin/env bun` shebangs, eliminating language fragmentation
|
|
17
|
+
- **CI validator runners modernized**: update `project/.github/workflows/quality.yml` to execute validators natively with `bun run`
|
|
18
|
+
- **Package scripts and binaries aligned**: update `project/package.json` `scripts` and `bin` to reference `.ts` entrypoints
|
|
19
|
+
- **Agent directives standardized on Bun TypeScript**: update `AGENTS.md` (root and submodule) §8 to mandate self-contained Bun `.ts` (`bun <file>.ts`) for script bundling and ad-hoc spikes
|
|
20
|
+
- **Skill creation and evals alignment**: update `create-skill` instructions, references, template assets, and eval suites (`evals.json`) to reference `.ts` validators and scripts
|
|
21
|
+
- Total shipped skills increased from 9 to 10
|
|
22
|
+
|
|
8
23
|
## [5.0.2] - 2026-09-23
|
|
9
24
|
|
|
10
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ bunx @meyverick/agentic
|
|
|
10
10
|
|
|
11
11
|
*(or via GitHub direct: `bunx github:meyverick/agentic`)*
|
|
12
12
|
|
|
13
|
-
Installs
|
|
13
|
+
Installs 10 skills into your project's `.agents/skills/`, distributes utility scripts into `./scripts/`, writes a provenance manifest, and creates `openspec/reports/`.
|
|
14
14
|
|
|
15
15
|
## Skills
|
|
16
16
|
|
|
@@ -23,6 +23,7 @@ Installs 9 skills into your project's `.agents/skills/`, distributes utility scr
|
|
|
23
23
|
| okf-docs | Author OKF v0.2-compliant documents — ADRs, module docs, decision records — with mandatory provenance frontmatter and mechanical validation |
|
|
24
24
|
| openspec-harden | Harden an existing OpenSpec change for cold application — enrich artifacts with concrete file paths, code blocks, and verify steps |
|
|
25
25
|
| openspec-learn | Analyze reports in `./openspec/reports/` and generate OpenSpec proposals for skill/prompt improvements |
|
|
26
|
+
| openspec-pi-apply | Delegate OpenSpec change task implementation to a headless pi worker agent via JSON-RPC |
|
|
26
27
|
| openspec-report | Generate self-reflection (meditation) reports from archived OpenSpec changes |
|
|
27
28
|
| qmd-research | Research project markdown and specifications using local QMD hybrid search, and maintain index collections |
|
|
28
29
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meyverick/agentic",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "AI agent skills and prompts for pi.dev",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
"CHANGELOG.md"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"check-deps": "./scripts/check-deps.
|
|
22
|
-
"git-dl": "./scripts/git-dl.
|
|
21
|
+
"check-deps": "./scripts/check-deps.ts",
|
|
22
|
+
"git-dl": "./scripts/git-dl.ts"
|
|
23
23
|
},
|
|
24
24
|
"bin": {
|
|
25
25
|
"agentic": "install.ts",
|
|
26
|
-
"check-deps": "scripts/check-deps.
|
|
27
|
-
"git-dl": "scripts/git-dl.
|
|
26
|
+
"check-deps": "scripts/check-deps.ts",
|
|
27
|
+
"git-dl": "scripts/git-dl.ts"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
30
|
"ai",
|
|
@@ -17,6 +17,7 @@ const colors = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const USER_AGENT = 'agentic-dep-checker/1.0 (https://github.com/meyverick/agentic)';
|
|
20
|
+
const isHelp = process.argv.includes('--help') || process.argv.includes('-h');
|
|
20
21
|
const includeReferences = process.argv.includes('--all') || process.argv.includes('--references');
|
|
21
22
|
const isJson = process.argv.includes('--json');
|
|
22
23
|
|
|
@@ -36,9 +37,72 @@ const IGNORED_DIRS = new Set([
|
|
|
36
37
|
...(includeReferences ? [] : ['references'])
|
|
37
38
|
]);
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
interface ScanResults {
|
|
41
|
+
cargo: string[];
|
|
42
|
+
npm: string[];
|
|
43
|
+
lockFiles: string[];
|
|
44
|
+
toolchains: string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface ToolchainItem {
|
|
48
|
+
name: string;
|
|
49
|
+
version: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface CargoDependency {
|
|
53
|
+
name: string;
|
|
54
|
+
version: string;
|
|
55
|
+
git: string | null;
|
|
56
|
+
section: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface SemverDiff {
|
|
60
|
+
status: 'UP_TO_DATE' | 'MINOR_PATCH' | 'MAJOR_BREAKING' | 'UNKNOWN';
|
|
61
|
+
reason?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface JsonReport {
|
|
65
|
+
summary: {
|
|
66
|
+
totalChecked: number;
|
|
67
|
+
upToDate: number;
|
|
68
|
+
minorPatch: number;
|
|
69
|
+
majorBreaking: number;
|
|
70
|
+
};
|
|
71
|
+
toolchains: Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
current: string;
|
|
74
|
+
latest: string | null;
|
|
75
|
+
status: string;
|
|
76
|
+
reason: string | null;
|
|
77
|
+
}>;
|
|
78
|
+
rustModules: Array<{
|
|
79
|
+
file: string;
|
|
80
|
+
dependencies: Array<{
|
|
81
|
+
name: string;
|
|
82
|
+
declaredVersion: string;
|
|
83
|
+
resolvedVersion: string;
|
|
84
|
+
latest: string | null;
|
|
85
|
+
status: string;
|
|
86
|
+
reason: string | null;
|
|
87
|
+
section: string;
|
|
88
|
+
}>;
|
|
89
|
+
}>;
|
|
90
|
+
npmModules: Array<{
|
|
91
|
+
file: string;
|
|
92
|
+
dependencies: Array<{
|
|
93
|
+
name: string;
|
|
94
|
+
declaredVersion: string;
|
|
95
|
+
latest: string | null;
|
|
96
|
+
status: string;
|
|
97
|
+
reason: string | null;
|
|
98
|
+
type: string;
|
|
99
|
+
}>;
|
|
100
|
+
}>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function asyncPool<T, R>(limit: number, items: T[], iteratorFn: (item: T) => Promise<R>): Promise<R[]> {
|
|
104
|
+
const ret: Promise<R>[] = [];
|
|
105
|
+
const executing = new Set<Promise<R>>();
|
|
42
106
|
for (const item of items) {
|
|
43
107
|
const p = Promise.resolve().then(() => iteratorFn(item));
|
|
44
108
|
ret.push(p);
|
|
@@ -52,10 +116,10 @@ async function asyncPool(limit, items, iteratorFn) {
|
|
|
52
116
|
return Promise.all(ret);
|
|
53
117
|
}
|
|
54
118
|
|
|
55
|
-
async function scanFiles(dir) {
|
|
56
|
-
const results = { cargo: [], npm: [], lockFiles: [], toolchains: [] };
|
|
119
|
+
async function scanFiles(dir: string): Promise<ScanResults> {
|
|
120
|
+
const results: ScanResults = { cargo: [], npm: [], lockFiles: [], toolchains: [] };
|
|
57
121
|
|
|
58
|
-
async function walk(currentDir) {
|
|
122
|
+
async function walk(currentDir: string): Promise<void> {
|
|
59
123
|
const entries = await readdir(currentDir, { withFileTypes: true }).catch(() => []);
|
|
60
124
|
for (const entry of entries) {
|
|
61
125
|
const fullPath = join(currentDir, entry.name);
|
|
@@ -84,8 +148,12 @@ async function scanFiles(dir) {
|
|
|
84
148
|
return results;
|
|
85
149
|
}
|
|
86
150
|
|
|
87
|
-
async function detectToolchains(
|
|
88
|
-
|
|
151
|
+
async function detectToolchains(
|
|
152
|
+
toolchainFiles: string[],
|
|
153
|
+
cargoFiles: string[],
|
|
154
|
+
npmFiles: string[]
|
|
155
|
+
): Promise<ToolchainItem[]> {
|
|
156
|
+
let rustVersion: string | null = null;
|
|
89
157
|
|
|
90
158
|
for (const tf of toolchainFiles) {
|
|
91
159
|
try {
|
|
@@ -119,14 +187,14 @@ async function detectToolchains(toolchainFiles, cargoFiles, npmFiles) {
|
|
|
119
187
|
} catch {}
|
|
120
188
|
}
|
|
121
189
|
|
|
122
|
-
let cargoVersion = null;
|
|
190
|
+
let cargoVersion: string | null = null;
|
|
123
191
|
try {
|
|
124
192
|
const out = execSync('cargo --version', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
125
193
|
const m = out.match(/cargo\s+([0-9]+\.[0-9]+\.[0-9]+)/);
|
|
126
194
|
if (m) cargoVersion = m[1];
|
|
127
195
|
} catch {}
|
|
128
196
|
|
|
129
|
-
let bunVersion = null;
|
|
197
|
+
let bunVersion: string | null = null;
|
|
130
198
|
for (const nf of npmFiles) {
|
|
131
199
|
try {
|
|
132
200
|
const pkg = JSON.parse(await readFile(nf, 'utf8'));
|
|
@@ -150,7 +218,7 @@ async function detectToolchains(toolchainFiles, cargoFiles, npmFiles) {
|
|
|
150
218
|
} catch {}
|
|
151
219
|
}
|
|
152
220
|
|
|
153
|
-
const items = [];
|
|
221
|
+
const items: ToolchainItem[] = [];
|
|
154
222
|
if (rustVersion) {
|
|
155
223
|
items.push({ name: 'rust', version: rustVersion });
|
|
156
224
|
}
|
|
@@ -164,7 +232,7 @@ async function detectToolchains(toolchainFiles, cargoFiles, npmFiles) {
|
|
|
164
232
|
return items;
|
|
165
233
|
}
|
|
166
234
|
|
|
167
|
-
async function fetchLatestToolchain() {
|
|
235
|
+
async function fetchLatestToolchain(): Promise<string | null> {
|
|
168
236
|
try {
|
|
169
237
|
const res = await fetch('https://static.rust-lang.org/dist/channel-rust-stable.toml', {
|
|
170
238
|
headers: { 'User-Agent': USER_AGENT }
|
|
@@ -178,8 +246,8 @@ async function fetchLatestToolchain() {
|
|
|
178
246
|
}
|
|
179
247
|
}
|
|
180
248
|
|
|
181
|
-
async function parseCargoLocks(lockFiles) {
|
|
182
|
-
const lockedVersions = new Map();
|
|
249
|
+
async function parseCargoLocks(lockFiles: string[]): Promise<Map<string, string[]>> {
|
|
250
|
+
const lockedVersions = new Map<string, string[]>();
|
|
183
251
|
for (const lockPath of lockFiles) {
|
|
184
252
|
try {
|
|
185
253
|
const content = await readFile(lockPath, 'utf8');
|
|
@@ -193,7 +261,7 @@ async function parseCargoLocks(lockFiles) {
|
|
|
193
261
|
if (!lockedVersions.has(name)) {
|
|
194
262
|
lockedVersions.set(name, []);
|
|
195
263
|
}
|
|
196
|
-
lockedVersions.get(name)
|
|
264
|
+
lockedVersions.get(name)!.push(ver);
|
|
197
265
|
}
|
|
198
266
|
}
|
|
199
267
|
} catch {}
|
|
@@ -201,7 +269,7 @@ async function parseCargoLocks(lockFiles) {
|
|
|
201
269
|
return lockedVersions;
|
|
202
270
|
}
|
|
203
271
|
|
|
204
|
-
function resolveLockedVersion(name, declaredVer, lockedMap) {
|
|
272
|
+
function resolveLockedVersion(name: string, declaredVer: string, lockedMap: Map<string, string[]>): string {
|
|
205
273
|
const versions = lockedMap.get(name);
|
|
206
274
|
if (!versions || versions.length === 0) return declaredVer;
|
|
207
275
|
if (versions.length === 1) return versions[0];
|
|
@@ -220,7 +288,7 @@ function resolveLockedVersion(name, declaredVer, lockedMap) {
|
|
|
220
288
|
return matched || versions[0];
|
|
221
289
|
}
|
|
222
290
|
|
|
223
|
-
function getCrateIndexPath(crateName) {
|
|
291
|
+
function getCrateIndexPath(crateName: string): string {
|
|
224
292
|
const name = crateName.toLowerCase();
|
|
225
293
|
if (name.length === 1) return `1/${name}`;
|
|
226
294
|
if (name.length === 2) return `2/${name}`;
|
|
@@ -228,9 +296,7 @@ function getCrateIndexPath(crateName) {
|
|
|
228
296
|
return `${name.slice(0, 2)}/${name.slice(2, 4)}/${name}`;
|
|
229
297
|
}
|
|
230
298
|
|
|
231
|
-
async function fetchLatestCrate(crateName) {
|
|
232
|
-
let version = null;
|
|
233
|
-
|
|
299
|
+
async function fetchLatestCrate(crateName: string): Promise<{ version: string | null }> {
|
|
234
300
|
try {
|
|
235
301
|
const indexPath = getCrateIndexPath(crateName);
|
|
236
302
|
const indexRes = await fetch(`https://index.crates.io/${indexPath}`, {
|
|
@@ -244,27 +310,26 @@ async function fetchLatestCrate(crateName) {
|
|
|
244
310
|
try {
|
|
245
311
|
const entry = JSON.parse(lines[i]);
|
|
246
312
|
if (!entry.yanked) {
|
|
247
|
-
version
|
|
248
|
-
break;
|
|
313
|
+
return { version: entry.vers };
|
|
249
314
|
}
|
|
250
315
|
} catch {}
|
|
251
316
|
}
|
|
252
317
|
}
|
|
253
318
|
|
|
254
|
-
return { version };
|
|
319
|
+
return { version: null };
|
|
255
320
|
} catch {
|
|
256
321
|
return { version: null };
|
|
257
322
|
}
|
|
258
323
|
}
|
|
259
324
|
|
|
260
|
-
async function fetchLatestNpm(pkgName) {
|
|
325
|
+
async function fetchLatestNpm(pkgName: string): Promise<{ version: string | null }> {
|
|
261
326
|
try {
|
|
262
327
|
const encoded = pkgName.startsWith('@')
|
|
263
328
|
? `@${encodeURIComponent(pkgName.slice(1))}`
|
|
264
329
|
: encodeURIComponent(pkgName);
|
|
265
330
|
const res = await fetch(`https://registry.npmjs.org/${encoded}`);
|
|
266
331
|
if (!res.ok) return { version: null };
|
|
267
|
-
const data = await res.json();
|
|
332
|
+
const data = (await res.json()) as { 'dist-tags'?: { latest?: string }; versions?: Record<string, unknown> };
|
|
268
333
|
const version = data['dist-tags']?.latest ?? Object.keys(data.versions || {}).pop() ?? null;
|
|
269
334
|
return { version };
|
|
270
335
|
} catch {
|
|
@@ -272,10 +337,10 @@ async function fetchLatestNpm(pkgName) {
|
|
|
272
337
|
}
|
|
273
338
|
}
|
|
274
339
|
|
|
275
|
-
function parseCargoDependencies(content) {
|
|
276
|
-
const deps = [];
|
|
340
|
+
function parseCargoDependencies(content: string): CargoDependency[] {
|
|
341
|
+
const deps: CargoDependency[] = [];
|
|
277
342
|
const lines = content.split('\n');
|
|
278
|
-
let currentSection = null;
|
|
343
|
+
let currentSection: string | null = null;
|
|
279
344
|
|
|
280
345
|
for (const line of lines) {
|
|
281
346
|
const trimmed = line.trim();
|
|
@@ -298,8 +363,8 @@ function parseCargoDependencies(content) {
|
|
|
298
363
|
if (depMatch) {
|
|
299
364
|
const name = depMatch[1];
|
|
300
365
|
const val = depMatch[2];
|
|
301
|
-
let version = null;
|
|
302
|
-
let git = null;
|
|
366
|
+
let version: string | null = null;
|
|
367
|
+
let git: string | null = null;
|
|
303
368
|
|
|
304
369
|
if (val.startsWith('"')) {
|
|
305
370
|
version = val.split('"')[1];
|
|
@@ -320,7 +385,7 @@ function parseCargoDependencies(content) {
|
|
|
320
385
|
return deps;
|
|
321
386
|
}
|
|
322
387
|
|
|
323
|
-
function getSemverDiff(declared, latest) {
|
|
388
|
+
function getSemverDiff(declared: string, latest: string | null): SemverDiff {
|
|
324
389
|
if (!latest) return { status: 'UNKNOWN' };
|
|
325
390
|
|
|
326
391
|
const cleanDeclared = declared.replace(/^[\^~>=<]+/, '').trim();
|
|
@@ -345,7 +410,22 @@ function getSemverDiff(declared, latest) {
|
|
|
345
410
|
return { status: 'MINOR_PATCH', reason: `${cleanDeclared} -> ${latest}` };
|
|
346
411
|
}
|
|
347
412
|
|
|
348
|
-
|
|
413
|
+
function printUsage(): void {
|
|
414
|
+
console.log(`Usage: bun check-deps.ts [options] [target-dir]
|
|
415
|
+
|
|
416
|
+
Options:
|
|
417
|
+
--all, --references Include scanning of references directories
|
|
418
|
+
--json Output machine-readable JSON report
|
|
419
|
+
-h, --help Show this help message
|
|
420
|
+
`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function main(): Promise<void> {
|
|
424
|
+
if (isHelp) {
|
|
425
|
+
printUsage();
|
|
426
|
+
process.exit(0);
|
|
427
|
+
}
|
|
428
|
+
|
|
349
429
|
if (!isJson) {
|
|
350
430
|
console.log(`${colors.bold}${colors.cyan}================================================================${colors.reset}`);
|
|
351
431
|
console.log(`${colors.bold}${colors.cyan} Agentic - Dependency Freshness Verifier ${colors.reset}`);
|
|
@@ -362,13 +442,8 @@ async function main() {
|
|
|
362
442
|
let totalMinorPatch = 0;
|
|
363
443
|
let totalMajorBreaking = 0;
|
|
364
444
|
|
|
365
|
-
const jsonReport = {
|
|
366
|
-
summary: {
|
|
367
|
-
totalChecked: 0,
|
|
368
|
-
upToDate: 0,
|
|
369
|
-
minorPatch: 0,
|
|
370
|
-
majorBreaking: 0
|
|
371
|
-
},
|
|
445
|
+
const jsonReport: JsonReport = {
|
|
446
|
+
summary: { totalChecked: 0, upToDate: 0, minorPatch: 0, majorBreaking: 0 },
|
|
372
447
|
toolchains: [],
|
|
373
448
|
rustModules: [],
|
|
374
449
|
npmModules: []
|
|
@@ -376,9 +451,7 @@ async function main() {
|
|
|
376
451
|
|
|
377
452
|
// 1. Toolchains (Rust, Cargo, Bun)
|
|
378
453
|
if (toolchainItems.length > 0) {
|
|
379
|
-
if (!isJson) {
|
|
380
|
-
console.log(`${colors.bold}${colors.blue}⚙ Toolchains: Rust, Cargo & Bun${colors.reset}`);
|
|
381
|
-
}
|
|
454
|
+
if (!isJson) console.log(`${colors.bold}${colors.blue}⚙ Toolchains: Rust, Cargo & Bun${colors.reset}`);
|
|
382
455
|
const latestRust = await fetchLatestToolchain();
|
|
383
456
|
const { version: latestBun } = await fetchLatestNpm('bun');
|
|
384
457
|
|
|
@@ -424,17 +497,12 @@ async function main() {
|
|
|
424
497
|
const deps = parseCargoDependencies(content);
|
|
425
498
|
|
|
426
499
|
if (deps.length === 0) continue;
|
|
500
|
+
if (!isJson) console.log(`${colors.bold}${colors.blue}📦 Rust Module: ${relPath}${colors.reset}`);
|
|
427
501
|
|
|
428
|
-
|
|
429
|
-
console.log(`${colors.bold}${colors.blue}📦 Rust Module: ${relPath}${colors.reset}`);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const currentModule = { file: relPath, dependencies: [] };
|
|
502
|
+
const currentModule: JsonReport['rustModules'][number] = { file: relPath, dependencies: [] };
|
|
433
503
|
|
|
434
504
|
const results = await asyncPool(10, deps, async (dep) => {
|
|
435
|
-
if (dep.git) {
|
|
436
|
-
return { ...dep, latest: 'git' };
|
|
437
|
-
}
|
|
505
|
+
if (dep.git) return { ...dep, latest: 'git' };
|
|
438
506
|
const { version: latest } = await fetchLatestCrate(dep.name);
|
|
439
507
|
return { ...dep, latest };
|
|
440
508
|
});
|
|
@@ -482,14 +550,14 @@ async function main() {
|
|
|
482
550
|
for (const npmPath of npm) {
|
|
483
551
|
const relPath = relative(rootDir, npmPath);
|
|
484
552
|
const raw = await readFile(npmPath, 'utf8');
|
|
485
|
-
let pkgJson = {};
|
|
553
|
+
let pkgJson: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> } = {};
|
|
486
554
|
try {
|
|
487
555
|
pkgJson = JSON.parse(raw);
|
|
488
556
|
} catch {
|
|
489
557
|
continue;
|
|
490
558
|
}
|
|
491
559
|
|
|
492
|
-
const allDeps = [];
|
|
560
|
+
const allDeps: Array<{ name: string; version: string; type: string }> = [];
|
|
493
561
|
if (pkgJson.dependencies) {
|
|
494
562
|
for (const [name, version] of Object.entries(pkgJson.dependencies)) {
|
|
495
563
|
if (!version.startsWith('workspace:')) {
|
|
@@ -506,12 +574,9 @@ async function main() {
|
|
|
506
574
|
}
|
|
507
575
|
|
|
508
576
|
if (allDeps.length === 0) continue;
|
|
577
|
+
if (!isJson) console.log(`${colors.bold}${colors.magenta}🌐 NPM/Web Module: ${relPath}${colors.reset}`);
|
|
509
578
|
|
|
510
|
-
|
|
511
|
-
console.log(`${colors.bold}${colors.magenta}🌐 NPM/Web Module: ${relPath}${colors.reset}`);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const currentModule = { file: relPath, dependencies: [] };
|
|
579
|
+
const currentModule: JsonReport['npmModules'][number] = { file: relPath, dependencies: [] };
|
|
515
580
|
|
|
516
581
|
const results = await asyncPool(10, allDeps, async (dep) => {
|
|
517
582
|
const { version: latest } = await fetchLatestNpm(dep.name);
|
|
@@ -577,11 +642,11 @@ async function main() {
|
|
|
577
642
|
}
|
|
578
643
|
}
|
|
579
644
|
|
|
580
|
-
main().catch((err) => {
|
|
645
|
+
main().catch((err: Error) => {
|
|
581
646
|
if (isJson) {
|
|
582
647
|
console.error(JSON.stringify({ error: err.message }));
|
|
583
648
|
} else {
|
|
584
649
|
console.error('Error running dependency check:', err);
|
|
585
650
|
}
|
|
586
651
|
process.exit(1);
|
|
587
|
-
});
|
|
652
|
+
});
|
|
@@ -3,18 +3,19 @@ import { execFileSync, spawn } from 'node:child_process';
|
|
|
3
3
|
import { mkdir, rm } from 'node:fs/promises';
|
|
4
4
|
import { basename, join } from 'node:path';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
|
+
import type { ReadableStream as WebReadableStream } from 'node:stream/web';
|
|
6
7
|
|
|
7
8
|
const input = process.argv[2];
|
|
8
9
|
|
|
9
10
|
if (input === '-h' || input === '--help') {
|
|
10
|
-
console.log('Usage: git-dl.
|
|
11
|
+
console.log('Usage: git-dl.ts <owner/repo|url> [target-dir]');
|
|
11
12
|
console.log('Default target-dir: references/<repo>');
|
|
12
13
|
process.exit(0);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
if (!input) {
|
|
16
17
|
console.error('Error: Provide a GitHub URL or owner/repo');
|
|
17
|
-
console.error('Usage: git-dl.
|
|
18
|
+
console.error('Usage: git-dl.ts <owner/repo|url> [target-dir]');
|
|
18
19
|
console.error('Default target-dir: references/<repo>');
|
|
19
20
|
process.exit(1);
|
|
20
21
|
}
|
|
@@ -37,22 +38,23 @@ const defaultDir = join('references', basename(repo));
|
|
|
37
38
|
const dir = process.argv[3] || defaultDir;
|
|
38
39
|
|
|
39
40
|
// Resolve the latest tag via git ls-remote (version sorted, handles prefixes and monorepos)
|
|
40
|
-
let lsOutput;
|
|
41
|
+
let lsOutput: string;
|
|
41
42
|
try {
|
|
42
43
|
lsOutput = execFileSync(
|
|
43
44
|
'git',
|
|
44
45
|
['ls-remote', '--tags', '--refs', '--sort=v:refname', `https://github.com/${repo}.git`],
|
|
45
46
|
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
46
47
|
);
|
|
47
|
-
} catch (err) {
|
|
48
|
-
const
|
|
48
|
+
} catch (err: unknown) {
|
|
49
|
+
const execErr = err as { stderr?: Buffer | string; message: string };
|
|
50
|
+
const errMsg = execErr.stderr ? execErr.stderr.toString().trim() : execErr.message;
|
|
49
51
|
console.error(`Error: Failed to query tags for '${repo}': ${errMsg}`);
|
|
50
52
|
process.exit(1);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
const lines = lsOutput.trim().split('\n').filter(Boolean);
|
|
54
56
|
const lastLine = lines[lines.length - 1];
|
|
55
|
-
let rawTag = null;
|
|
57
|
+
let rawTag: string | null = null;
|
|
56
58
|
if (lastLine) {
|
|
57
59
|
const parts = lastLine.split(/\s+/);
|
|
58
60
|
if (parts.length >= 2) {
|
|
@@ -77,12 +79,12 @@ const res = await fetch(tarballUrl, {
|
|
|
77
79
|
}
|
|
78
80
|
});
|
|
79
81
|
|
|
80
|
-
if (!res.ok) {
|
|
82
|
+
if (!res.ok || !res.body) {
|
|
81
83
|
console.error(`Error: Failed to download tarball from ${tarballUrl} (${res.status} ${res.statusText})`);
|
|
82
84
|
process.exit(1);
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
await new Promise((resolve, reject) => {
|
|
87
|
+
await new Promise<void>((resolve, reject) => {
|
|
86
88
|
const tar = spawn('tar', ['-xz', '-C', dir, '--strip-components=1'], {
|
|
87
89
|
stdio: ['pipe', 'inherit', 'inherit']
|
|
88
90
|
});
|
|
@@ -93,7 +95,7 @@ await new Promise((resolve, reject) => {
|
|
|
93
95
|
else reject(new Error(`tar extraction exited with code ${code}`));
|
|
94
96
|
});
|
|
95
97
|
|
|
96
|
-
Readable.fromWeb(res.body).pipe(tar.stdin);
|
|
98
|
+
Readable.fromWeb(res.body as unknown as WebReadableStream).pipe(tar.stdin);
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
const displayDir = dir.startsWith('/') || dir.startsWith('.') ? dir : `./${dir}`;
|
|
@@ -32,7 +32,7 @@ Create new Agent Skills from problem descriptions or instruction files. Fully au
|
|
|
32
32
|
|
|
33
33
|
When the user wants to build a new skill:
|
|
34
34
|
|
|
35
|
-
1. Run `scripts/scaffold-skill.
|
|
35
|
+
1. Run `scripts/scaffold-skill.ts <skill-name>` to create skeleton in `./project/skills/`
|
|
36
36
|
2. Follow the workflow below to fill in content
|
|
37
37
|
3. Skill ships when Phase 7 completes
|
|
38
38
|
|
|
@@ -95,7 +95,7 @@ Determine:
|
|
|
95
95
|
- Tier 2 (SKILL.md body): <1500 tokens
|
|
96
96
|
- Tier 3 (references/): on-demand only
|
|
97
97
|
4. **Components**: Persona / instructions / templates / data (not omnibus) — see `references/component-decomposition.md` (Level 2).
|
|
98
|
-
5. **Scripts**: Reusable logic to bundle (.
|
|
98
|
+
5. **Scripts**: Reusable logic to bundle (.ts, cold/isolated, relative paths only)
|
|
99
99
|
6. **Eval strategy**: Test cases, assertions, near-miss negatives, baseline comparison
|
|
100
100
|
7. **Activation boundary**: Define what triggers and what does NOT trigger
|
|
101
101
|
8. **Runtime contract**: Required runtimes (bun/node/python), timeout_seconds, output_format (json)
|
|
@@ -104,7 +104,7 @@ Determine:
|
|
|
104
104
|
|
|
105
105
|
### Phase 3: Authoring
|
|
106
106
|
|
|
107
|
-
1. **Scaffold**: `scripts/scaffold-skill.
|
|
107
|
+
1. **Scaffold**: `scripts/scaffold-skill.ts <name>` → creates directory + SKILL.md skeleton
|
|
108
108
|
2. **Frontmatter**: name, description (imperative, specific, "Use when... Do NOT use when..."), positive_triggers (min 3), anti_triggers (min 2), allowed-tools, compatibility, runtime
|
|
109
109
|
3. **SKILL.md body sections** (in order):
|
|
110
110
|
- Activation Boundary: explicit trigger/exclusion lists
|
|
@@ -114,7 +114,7 @@ Determine:
|
|
|
114
114
|
- Contrast: `| Before (old) | After (new) | Why different |` table when proposal carries `Contrast:` hint (e.g., `C# null → Rust Option`); keep distinct from routing
|
|
115
115
|
- Anti-examples: `Do NOT: <before>` → `Do: <after>` with Why, when proposal carries `Anti-example:` hint from report's Concrete Gotcha; body content, NOT frontmatter `anti_triggers`
|
|
116
116
|
- Tiered depth: Level 1 basics inline, Level 2 advanced behind `references/<topic>.md` (cap one file per skill)
|
|
117
|
-
4. **Scripts**: Generate if clearly reusable (.
|
|
117
|
+
4. **Scripts**: Generate if clearly reusable (.ts, self-contained, relative paths via import.meta.url, JSON output only)
|
|
118
118
|
5. **References**: Domain-specific docs, loaded on-demand — **Tiered depth:** Level 1 basics inline in SKILL.md, Level 2 advanced behind `references/<topic>.md`; cap at one `references/` file per skill; link explicitly from SKILL.md
|
|
119
119
|
6. **Templates**: Output shapes, examples
|
|
120
120
|
7. **Single source**: Define each rule ONCE, reference everywhere else
|
|
@@ -126,7 +126,7 @@ Determine:
|
|
|
126
126
|
|
|
127
127
|
**Step 1: Structural validation**
|
|
128
128
|
```bash
|
|
129
|
-
scripts/validate-structure.
|
|
129
|
+
scripts/validate-structure.ts <skill-dir>
|
|
130
130
|
```
|
|
131
131
|
Checks: name format, description format, directory structure, file references, positive_triggers (min 3), anti_triggers (min 2), "Use when" phrasing, "Do NOT use when" phrasing, no compound intent, no hardcoded paths, runtime declared when scripts exist.
|
|
132
132
|
|
|
@@ -134,7 +134,7 @@ Checks: name format, description format, directory structure, file references, p
|
|
|
134
134
|
|
|
135
135
|
**Step 2: Semantic routing validation**
|
|
136
136
|
```bash
|
|
137
|
-
scripts/validate-routing.
|
|
137
|
+
scripts/validate-routing.ts <skill-dir>
|
|
138
138
|
```
|
|
139
139
|
Checks: positive_triggers coverage, anti_triggers coverage, description-body alignment, single-responsibility verification.
|
|
140
140
|
|
|
@@ -149,7 +149,7 @@ Agent assesses:
|
|
|
149
149
|
|
|
150
150
|
**Step 4: Antipattern self-audit**
|
|
151
151
|
```bash
|
|
152
|
-
scripts/audit-antipatterns.
|
|
152
|
+
scripts/audit-antipatterns.ts <skill-dir>
|
|
153
153
|
```
|
|
154
154
|
Checks: phantom tools, duplicated invariants, passive-voice triggers, prose bloat, single-file omnibus, vague success bars, multi-domain descriptions (A17), missing activation boundary (A18), hardcoded paths (A19), context budget violation (A20).
|
|
155
155
|
|
|
@@ -161,14 +161,14 @@ Self-correct any issues before proceeding.
|
|
|
161
161
|
|
|
162
162
|
**Step 6: Compute benchmarks**
|
|
163
163
|
```bash
|
|
164
|
-
scripts/compute-benchmark.
|
|
164
|
+
scripts/compute-benchmark.ts <eval-dir>
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
**Step 6b: Cold-agent behavioral proof (mandatory)**
|
|
168
168
|
```bash
|
|
169
|
-
scripts/run-cold-eval.
|
|
169
|
+
scripts/run-cold-eval.ts <skill-dir>
|
|
170
170
|
```
|
|
171
|
-
Runs `evals/evals.json` cold A/B (without vs with skill), computes `d = sign(with - baseline)`, `m = |with - baseline|`, emits unified envelope `{target, pass, checks, summary}` + `behavioral: {at, baseline, with_skill, d, m, ship}` (30s timeout, JSON only). Writes `evals/benchmark.json` with `stage: behavioral` block (`{at, baseline, with_skill, d, m, ship}`) replacing `pending_cold_agent_run`; record outputs in creation session. Reuses `compute-benchmark.
|
|
171
|
+
Runs `evals/evals.json` cold A/B (without vs with skill), computes `d = sign(with - baseline)`, `m = |with - baseline|`, emits unified envelope `{target, pass, checks, summary}` + `behavioral: {at, baseline, with_skill, d, m, ship}` (30s timeout, JSON only). Writes `evals/benchmark.json` with `stage: behavioral` block (`{at, baseline, with_skill, d, m, ship}`) replacing `pending_cold_agent_run`; record outputs in creation session. Reuses `compute-benchmark.ts` logic; no network, deterministic.
|
|
172
172
|
|
|
173
173
|
**Step 7: Calculate quality score**
|
|
174
174
|
```
|
|
@@ -176,7 +176,7 @@ d = direction (+1 if with_skill > baseline, -1 if lower, 0 if equal)
|
|
|
176
176
|
m = magnitude = |with_skill_pass_rate - baseline_pass_rate|
|
|
177
177
|
quality_score = d × m
|
|
178
178
|
```
|
|
179
|
-
Ship gate: d must be +1 AND m must be >= 0.2 (20% improvement over baseline) — now proven by `run-cold-eval.
|
|
179
|
+
Ship gate: d must be +1 AND m must be >= 0.2 (20% improvement over baseline) — now proven by `run-cold-eval.ts` behavioral block.
|
|
180
180
|
|
|
181
181
|
**Step 8: Iterate**
|
|
182
182
|
If quality insufficient:
|
|
@@ -208,12 +208,12 @@ If false positives occur:
|
|
|
208
208
|
3. Re-test
|
|
209
209
|
|
|
210
210
|
**Step 5: Final validation**
|
|
211
|
-
Run `scripts/validate-structure.
|
|
211
|
+
Run `scripts/validate-structure.ts` and `scripts/validate-routing.ts` again after changes.
|
|
212
212
|
|
|
213
213
|
### Phase 7: Ship
|
|
214
214
|
|
|
215
|
-
1. **Final structural validation — HARD GATE**: run `scripts/validate-structure.
|
|
216
|
-
2. **Behavioral proof — HARD GATE (fail-closed)**: run `scripts/run-cold-eval.
|
|
215
|
+
1. **Final structural validation — HARD GATE**: run `scripts/validate-structure.ts` and `scripts/validate-routing.ts`; both MUST report pass with outputs recorded. If either fails, the skill is NOT presented for approval — self-correct and re-run until both pass.
|
|
216
|
+
2. **Behavioral proof — HARD GATE (fail-closed)**: run `scripts/run-cold-eval.ts <skill-dir>`; `d == +1 AND m >= 0.2` required with outputs recorded. If fails, emit `FAIL: m < 0.2 — not worth context cost` with validator + behavioral outputs, loop to Optimization (revise description/instructions) and re-run; never present for approval without behavioral pass.
|
|
217
217
|
3. **Portability certificate**: verify no hardcoded paths, runtime deps declared, timeout bounds set, output contract defined
|
|
218
218
|
4. **Present summary**: what skill does, tier achieved, eval results, trigger rate, quality score (d × m) + behavioral `d×m`
|
|
219
219
|
5. **Wait for user approval**
|
|
@@ -257,7 +257,7 @@ runtime:
|
|
|
257
257
|
- **Anti-triggers +31.8% precision**: Frontmatter `anti_triggers` min 2, plus body `Anti-examples` distinct from routing.
|
|
258
258
|
- **Progressive disclosure**: Tier 1 <50, Tier 2 <1500, Tier 3 on-demand — see `references/component-decomposition.md`.
|
|
259
259
|
- **Single-responsibility**: One sentence without `and`, else split.
|
|
260
|
-
- **Validation + behavioral gate is fail-closed**: `validate-structure` + `validate-routing` + `run-cold-eval.
|
|
260
|
+
- **Validation + behavioral gate is fail-closed**: `validate-structure` + `validate-routing` + `run-cold-eval.ts` (`d=+1,m≥0.2`) mandatory; `m<0.2` blocks Ship.
|
|
261
261
|
- **Fragility**: Mutation strict, read-only loose, creative low — see `references/fragility-matching.md`.
|
|
262
262
|
- **No hardcoded paths**: Relative via `import.meta.url`; no `.pi`/`.agents` in scripts.
|
|
263
263
|
|
|
@@ -269,7 +269,7 @@ runtime:
|
|
|
269
269
|
/skill-create csv-analyzer
|
|
270
270
|
# 1. Discovery: Q "analyze CSV" → positive_triggers 3, anti_triggers 2
|
|
271
271
|
# 2. Design: scope atomic, fragility read-only=loose (see fragility-matching.md)
|
|
272
|
-
# 3. Scaffold: scripts/scaffold-skill.
|
|
272
|
+
# 3. Scaffold: scripts/scaffold-skill.ts csv-analyzer
|
|
273
273
|
# 4. Author SKILL.md with Contrast/Anti-examples, Tiered depth
|
|
274
274
|
# 5. Validate routing+structure + run-cold-eval (d×m≥0.2)
|
|
275
275
|
# 6. Ship when both gates pass
|
|
@@ -114,5 +114,5 @@ Why: {{anti_why}}
|
|
|
114
114
|
|
|
115
115
|
## Author Self-Check (final step before declaring this skill complete)
|
|
116
116
|
|
|
117
|
-
Run `scripts/validate-structure.
|
|
117
|
+
Run `scripts/validate-structure.ts <this-skill-dir>` and `scripts/validate-routing.ts <this-skill-dir>`.
|
|
118
118
|
Both MUST report pass with outputs recorded in the creation record. Failing either = skill not complete.
|