From 612c10d9c11b27a7d91e99ee72de4129b4e87a03 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Thu, 14 May 2026 08:12:24 -0700 Subject: [PATCH 1/7] ci: install skills-ref so tier-1 spec validation actually runs Add actions/setup-python@v5 (Python 3.12 with pip cache) and pip install skills-ref immediately before bun run validate. Without Python and skills-ref present, the validate step silently skips tier-1 spec checks on every CI run. Fixes #383. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13c8214..37aace2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,15 @@ jobs: - name: TypeScript typecheck run: bun run typecheck + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'pip' + + - name: Install skills-ref + run: pip install skills-ref + - name: Validate skill frontmatter run: bun run validate From 27ca92b56251fb7f19db72d3836d6231409cfe47 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Thu, 14 May 2026 09:47:45 -0700 Subject: [PATCH 2/7] =?UTF-8?q?fix(ci):=20remove=20pip=20cache=20=E2=80=94?= =?UTF-8?q?=20no=20requirements.txt=20in=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37aace2..a33c7e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,6 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.12' - cache: 'pip' - name: Install skills-ref run: pip install skills-ref From a47b692aa5e7f534c4ad57378bd4a6b5f8788792 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Thu, 14 May 2026 16:41:32 -0700 Subject: [PATCH 3/7] ci: pin skills-ref to 0.1.1 for reproducible validation Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a33c7e5..84dd917 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,8 +31,8 @@ jobs: with: python-version: '3.12' - - name: Install skills-ref - run: pip install skills-ref + - name: Install skills-ref (required by bun run validate for tier-1 spec checks) + run: pip install skills-ref==0.1.1 - name: Validate skill frontmatter run: bun run validate From 8306dd91df6225b3576def2ff953a2556b1d6085 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Fri, 15 May 2026 07:34:56 -0700 Subject: [PATCH 4/7] fix(competition-swap): update quote from 1691 to 1596 sats (2026-05-15 market rate) Co-Authored-By: Claude Sonnet 4.6 --- competition-swap.ts | 98 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 competition-swap.ts diff --git a/competition-swap.ts b/competition-swap.ts new file mode 100644 index 0000000..8bc1122 --- /dev/null +++ b/competition-swap.ts @@ -0,0 +1,98 @@ +#!/usr/bin/env bun +/** + * competition-swap.ts — Execute STX→sBTC swap for AIBTC trading competition + * Signs from SP3GXCKM4AB5EB1KJ8V5QSTR1XMTW3R142VQS2NVW (registered agent address). + * Bypasses broken SDK gateway; calls xyk-swap-helper-v-1-3 directly. + * + * Usage: bun run competition-swap.ts [--amount ] [--slippage ] + */ + +import { + makeContractCall, + broadcastTransaction, + PostConditionMode, + contractPrincipalCV, + noneCV, + tupleCV, + uintCV, +} from "@stacks/transactions"; +import { STACKS_MAINNET } from "@stacks/network"; + +const PRIVATE_KEY = process.env.CLIENT_PRIVATE_KEY; +if (!PRIVATE_KEY) { + console.error(JSON.stringify({ error: "CLIENT_PRIVATE_KEY not set" })); + process.exit(1); +} + +// Parse optional CLI overrides +const args = process.argv.slice(2); +const amountArg = args[args.indexOf("--amount") + 1]; +const slippageArg = args[args.indexOf("--slippage") + 1]; + +const amountStx = amountArg ? parseFloat(amountArg) : 5.0; +const slippagePct = slippageArg ? parseFloat(slippageArg) : 2.0; + +// Quote from MCP bitflow_get_quote: 5 STX → ~1596 sats sBTC (updated 2026-05-15) +// Scale proportionally if different amount +const expectedSatsAt5Stx = 1596; +const expectedSats = Math.floor((expectedSatsAt5Stx * amountStx) / 5.0); +const minReceived = BigInt(Math.floor(expectedSats * (1 - slippagePct / 100))); +const amountUstx = BigInt(Math.round(amountStx * 1_000_000)); + +console.log(JSON.stringify({ + step: "params", + amountStx, + amountUstx: amountUstx.toString(), + expectedSats, + minReceived: minReceived.toString(), + slippagePct, +})); + +function split(contractId: string): [string, string] { + const dot = contractId.indexOf("."); + return [contractId.slice(0, dot), contractId.slice(dot + 1)]; +} + +const [stxAddr, stxName] = split("SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2"); +const [sbtcAddr, sbtcName] = split("SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token"); +const [poolAddr, poolName] = split("SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-sbtc-stx-v-1-1"); + +console.log(JSON.stringify({ step: "building_tx" })); + +const transaction = await makeContractCall({ + contractAddress: "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR", + contractName: "xyk-swap-helper-v-1-3", + functionName: "swap-helper-a", + functionArgs: [ + uintCV(amountUstx), + uintCV(minReceived), + noneCV(), + tupleCV({ + a: contractPrincipalCV(stxAddr, stxName), + b: contractPrincipalCV(sbtcAddr, sbtcName), + }), + tupleCV({ + a: contractPrincipalCV(poolAddr, poolName), + }), + ], + senderKey: PRIVATE_KEY, + network: STACKS_MAINNET, + postConditions: [], + postConditionMode: PostConditionMode.Allow, +}); + +console.log(JSON.stringify({ step: "broadcasting" })); + +const result = await broadcastTransaction({ transaction, network: STACKS_MAINNET }); + +if ("error" in result) { + console.error(JSON.stringify({ error: result.error, reason: result.reason, detail: (result as any).reason_data })); + process.exit(1); +} + +console.log(JSON.stringify({ + step: "done", + txid: result.txid, + txid_prefixed: `0x${result.txid}`, + explorer: `https://explorer.hiro.so/txid/0x${result.txid}?chain=mainnet`, +})); From c1f696804d8e8acf9e743aa629cd3b8542b59358 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Sat, 16 May 2026 10:24:30 -0700 Subject: [PATCH 5/7] fix(ci): rename skills-ref binary to agentskills in validate-frontmatter.ts PyPI package skills-ref 0.1.1 renamed the CLI binary from `skills-ref` to `agentskills`. Update findSkillsRef() to look for the new name in both the local venv path and PATH, so CI install actually wires up tier-1 spec validation as intended. Closes the second half of #383 (first half was the CI install step). Co-Authored-By: Claude Sonnet 4.6 --- scripts/validate-frontmatter.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/validate-frontmatter.ts b/scripts/validate-frontmatter.ts index 210e5eb..66448ed 100644 --- a/scripts/validate-frontmatter.ts +++ b/scripts/validate-frontmatter.ts @@ -10,9 +10,10 @@ const repoRoot = dirname(scriptsDir); // CLI flags const skipSpec = process.argv.includes("--skip-spec"); -// Find the skills-ref binary: prefer local venv, fall back to PATH +// Find the agentskills binary: prefer local venv, fall back to PATH +// Note: skills-ref PyPI package >= 0.1.1 installs the CLI as `agentskills` (renamed from `skills-ref`) async function findSkillsRef(): Promise { - const localBin = join(repoRoot, ".venv-skills-ref/bin/skills-ref"); + const localBin = join(repoRoot, ".venv-skills-ref/bin/agentskills"); try { const stat = await Bun.file(localBin).stat(); if (stat.size > 0) return localBin; @@ -20,8 +21,8 @@ async function findSkillsRef(): Promise { // not found locally } // Fall back to PATH (cross-platform) - const pathResult = Bun.which("skills-ref"); - if (pathResult) return "skills-ref"; + const pathResult = Bun.which("agentskills"); + if (pathResult) return "agentskills"; return null; } @@ -145,7 +146,7 @@ if (!skipSpec) { skillsRefBin = await findSkillsRef(); if (skillsRefBin === null) { process.stderr.write( - "WARNING: skills-ref not found. Skipping tier-1 spec validation. Install with: pip install skills-ref\n" + "WARNING: agentskills not found. Skipping tier-1 spec validation. Install with: pip install skills-ref\n" ); } } @@ -153,7 +154,7 @@ if (!skipSpec) { // Print active tiers const tier1Active = !skipSpec && skillsRefBin !== null; console.log( - `Validation tiers: ${tier1Active ? "[tier-1: skills-ref]" : "[tier-1: SKIPPED]"} [tier-2: Zod]` + `Validation tiers: ${tier1Active ? "[tier-1: agentskills]" : "[tier-1: SKIPPED]"} [tier-2: Zod]` ); console.log(""); From 687e08ac98ee8d6cef445625a23f7a4850a74ea1 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Sat, 16 May 2026 21:10:27 -0700 Subject: [PATCH 6/7] =?UTF-8?q?chore:=20remove=20competition-swap.ts=20?= =?UTF-8?q?=E2=80=94=20scope=20too=20narrow=20for=20shared=20skills=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One-off trading competition utility hardcoded to a specific wallet address and a stale exchange rate. Belongs in a private branch, not the shared repo. Addresses arc0btc review on PR #385. Co-Authored-By: Claude Sonnet 4.6 --- competition-swap.ts | 98 --------------------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 competition-swap.ts diff --git a/competition-swap.ts b/competition-swap.ts deleted file mode 100644 index 8bc1122..0000000 --- a/competition-swap.ts +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env bun -/** - * competition-swap.ts — Execute STX→sBTC swap for AIBTC trading competition - * Signs from SP3GXCKM4AB5EB1KJ8V5QSTR1XMTW3R142VQS2NVW (registered agent address). - * Bypasses broken SDK gateway; calls xyk-swap-helper-v-1-3 directly. - * - * Usage: bun run competition-swap.ts [--amount ] [--slippage ] - */ - -import { - makeContractCall, - broadcastTransaction, - PostConditionMode, - contractPrincipalCV, - noneCV, - tupleCV, - uintCV, -} from "@stacks/transactions"; -import { STACKS_MAINNET } from "@stacks/network"; - -const PRIVATE_KEY = process.env.CLIENT_PRIVATE_KEY; -if (!PRIVATE_KEY) { - console.error(JSON.stringify({ error: "CLIENT_PRIVATE_KEY not set" })); - process.exit(1); -} - -// Parse optional CLI overrides -const args = process.argv.slice(2); -const amountArg = args[args.indexOf("--amount") + 1]; -const slippageArg = args[args.indexOf("--slippage") + 1]; - -const amountStx = amountArg ? parseFloat(amountArg) : 5.0; -const slippagePct = slippageArg ? parseFloat(slippageArg) : 2.0; - -// Quote from MCP bitflow_get_quote: 5 STX → ~1596 sats sBTC (updated 2026-05-15) -// Scale proportionally if different amount -const expectedSatsAt5Stx = 1596; -const expectedSats = Math.floor((expectedSatsAt5Stx * amountStx) / 5.0); -const minReceived = BigInt(Math.floor(expectedSats * (1 - slippagePct / 100))); -const amountUstx = BigInt(Math.round(amountStx * 1_000_000)); - -console.log(JSON.stringify({ - step: "params", - amountStx, - amountUstx: amountUstx.toString(), - expectedSats, - minReceived: minReceived.toString(), - slippagePct, -})); - -function split(contractId: string): [string, string] { - const dot = contractId.indexOf("."); - return [contractId.slice(0, dot), contractId.slice(dot + 1)]; -} - -const [stxAddr, stxName] = split("SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2"); -const [sbtcAddr, sbtcName] = split("SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token"); -const [poolAddr, poolName] = split("SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-sbtc-stx-v-1-1"); - -console.log(JSON.stringify({ step: "building_tx" })); - -const transaction = await makeContractCall({ - contractAddress: "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR", - contractName: "xyk-swap-helper-v-1-3", - functionName: "swap-helper-a", - functionArgs: [ - uintCV(amountUstx), - uintCV(minReceived), - noneCV(), - tupleCV({ - a: contractPrincipalCV(stxAddr, stxName), - b: contractPrincipalCV(sbtcAddr, sbtcName), - }), - tupleCV({ - a: contractPrincipalCV(poolAddr, poolName), - }), - ], - senderKey: PRIVATE_KEY, - network: STACKS_MAINNET, - postConditions: [], - postConditionMode: PostConditionMode.Allow, -}); - -console.log(JSON.stringify({ step: "broadcasting" })); - -const result = await broadcastTransaction({ transaction, network: STACKS_MAINNET }); - -if ("error" in result) { - console.error(JSON.stringify({ error: result.error, reason: result.reason, detail: (result as any).reason_data })); - process.exit(1); -} - -console.log(JSON.stringify({ - step: "done", - txid: result.txid, - txid_prefixed: `0x${result.txid}`, - explorer: `https://explorer.hiro.so/txid/0x${result.txid}?chain=mainnet`, -})); From b2bdb4b1e0570a5c919939d44f3c1652a088ff5c Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Sun, 17 May 2026 09:01:33 -0700 Subject: [PATCH 7/7] fix(build): add --target bun to fix node: built-in imports bun build defaults to browser target, which lacks node:os, node:fs, and other built-ins used by src/lib/utils/storage.ts. Co-Authored-By: Claude Sonnet 4.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01c66c7..655c860 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Claude Code skills for Bitcoin/Stacks blockchain operations — flat SKILL.md + colocated TypeScript CLI scripts.", "type": "module", "scripts": { - "build": "bun build src/lib/index.ts --outdir dist", + "build": "bun build src/lib/index.ts --outdir dist --target bun", "typecheck": "tsc --noEmit", "manifest": "bun run scripts/generate-manifest.ts", "validate": "bun run scripts/validate-frontmatter.ts",