Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/skill-tree-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Skill tree CI

on:
pull_request:
paths:
- "packages/skill-tree/**"
- "pnpm-lock.yaml"
- "vitest.config.ts"
- ".github/workflows/skill-tree-ci.yml"
push:
branches: [main]
paths:
- "packages/skill-tree/**"
- "pnpm-lock.yaml"
- "vitest.config.ts"
- ".github/workflows/skill-tree-ci.yml"

permissions:
contents: read

concurrency:
group: skill-tree-ci-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm --filter @skillx/skill-tree typecheck

- name: Test (AgentKit conformance vectors and negative cases)
run: pnpm exec vitest run packages/skill-tree/test
4 changes: 4 additions & 0 deletions packages/skill-tree/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Pinned inputs are hashed byte for byte; never convert their line endings.
fixtures/** -text
scripts/unicode-15.0.0-go.json -text
scripts/stream-safe-15.0.0-go-vectors.json -text
30 changes: 30 additions & 0 deletions packages/skill-tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# @skillx/skill-tree

TypeScript port of the AgentKit `agentkit.skill-tree/v1` digest. It reads a tar,
tar.gz or zip archive (or presented entries) into a validated tree manifest
and its digest. Go parity is pinned by the vendored conformance vectors under
`fixtures/`.

## Runtime requirements

- Node.js 21.2 or later (`DecompressionStream("deflate-raw")`).
- Cloudflare Workers: enable the `nodejs_compat` compatibility flag. The
package imports `node:crypto` (`createHash`) for SHA-256.

## Ingest overhead guard (tar)

The tar reader caps the bytes it reads beyond hashed regular-file content at
`maxFiles × 64 KiB` (256 MiB at the default limits). That overhead covers
headers, PAX `x`/`g` and GNU `L`/`K` records, sparse maps, padding and the data
of non-regular entries. Regular-file content is bounded by the tree limits
(`maxFileSize`, `maxTreeSize`, `maxFiles`) as before.

- It only rejects (`tree.limit_exceeded`, detail naming the ingest overhead
guard). It never changes a digest.
- It is a SkillX resource guard outside the Go parity claim. Go
`archive/tar` has no such bound, and AgentKit has no tar reader; the
contract governs `Build`.
- Known divergence: a non-regular entry (for example type `7` or a sparse
file) whose data exceeds the guard fails with `tree.limit_exceeded`, where
Go `Reader.Next` plus `Build` would read it fully and report
`tree.unsupported_entry`.
34 changes: 34 additions & 0 deletions packages/skill-tree/fixtures/PROVENANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Fixture provenance

These files are vendored unedited. Tests pin each by sha256 (`test/provenance.test.ts`), so any
edit or line-ending conversion fails the suite. A vector change is an AgentKit contract change:
update by copying the new upstream file and its new hash, never by editing a vector here.

| File | Source | Commit | sha256 |
|---|---|---|---|
| `vectors/skill-tree-v1-vectors.json` | `bestagentkits/agentkit` `docs/conformance/skill-lifecycle/skill-tree-v1-vectors.json` | `dev` @ `479483bfe8ff022063f7bff21e75df17fabf0997` (git blob `ecb6722af896f41b176e5f5a5e1ba367c58449aa`) | `8eb46f1b8bec49cace740b75614f28f8fb4a6fc266fecfcd7e3d6892f28f3172` |
| `vectors/identity-v1-vectors.json` | `bestagentkits/agentkit` `docs/conformance/skill-lifecycle/identity-v1-vectors.json` | `dev` @ `479483bfe8ff022063f7bff21e75df17fabf0997` (git blob `d532820a500e792eef6445b0e54ba49554ab3fa6`) | `1ab9e013c229d78871abd60e3cd3bf26fcfd0e6067d98dcdd79b4f6bcc1daefb` |
| `ucd/CaseFolding-15.0.0.txt` | Unicode 15.0.0 `CaseFolding.txt`, as vendored by AgentKit at `apps/cli/internal/core/skilltree/testdata/CaseFolding-15.0.0.txt` | `840d924a7` (branch `mrgoonie/feat/skilltree-canonical-digest`) | `cdd49e55eae3bbf1f0a3f6580c974a0263cb86a6a08daa10fbf705b4808a56f7` |

The contract: AgentKit `docs/specs/skill-lifecycle-contract.md` sections 2, 4 and 10.2, and
`docs/specs/skill-lifecycle-schemas.md` section 2.1.

## Unicode tables

`src/unicode-15-tables.ts` is generated by `scripts/gen-unicode-tables.mjs` from two pinned
inputs: the case folding file above, and `scripts/unicode-15.0.0-go.json`, which
`scripts/dump-go-unicode.go` writes from the Go `unicode` tables (go1.25.3) and
`golang.org/x/text/unicode/norm` (Unicode 15.0.0), the same tables the AgentKit reference
implementation validates paths with. To regenerate:

```sh
cd <agentkit>/apps/cli && go run <skillx>/packages/skill-tree/scripts/dump-go-unicode.go > <skillx>/packages/skill-tree/scripts/unicode-15.0.0-go.json
cd <skillx>/packages/skill-tree && node scripts/gen-unicode-tables.mjs
```

`scripts/unicode-15.0.0-go.json` is pinned at sha256
`baa335155dcbaf0cfe8f40fcc0a98232c4134e821a08c3f198f829a51d911ad5` (generator and tests).
Tests check the fold table against the case folding file, and the category and combining-class
tables against the Go dump, for every code point. They also check
normalization against the runtime's `String.prototype.normalize` for every code point assigned
in Unicode 15.0.0 (normalization stability makes later Unicode versions agree on those).
Loading
Loading