@hasna/skills 0.5.2 → 0.5.3
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/README.md +169 -1
- package/bin/index.js +1182 -623
- package/bin/mcp.js +28155 -26920
- package/bin/migrate.js +172 -1
- package/bin/server.js +187 -1
- package/bin/worker.js +225 -40
- package/dist/cli/commands/invitation-recovery.d.ts +2 -0
- package/dist/cli/commands/invitation-verification.d.ts +8 -0
- package/dist/cli/commands/workspace-invitations.d.ts +2 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +987 -165
- package/dist/lib/invitation-customer-action.d.ts +14 -0
- package/dist/lib/invitation-recovery-target.d.ts +5 -0
- package/dist/lib/remote-auth.d.ts +12 -0
- package/dist/lib/remote-client.d.ts +12 -0
- package/dist/lib/remote-invitation-recovery.d.ts +62 -0
- package/dist/lib/remote-invitations.d.ts +128 -0
- package/dist/lib/skill-bundle.d.ts +54 -1
- package/dist/lib/skill-entry-path.d.ts +6 -0
- package/dist/lib/skill-hash.d.ts +33 -0
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/invitation-recovery.d.ts +2 -0
- package/dist/mcp/remote-invitation-tools.d.ts +2 -0
- package/dist/sdk/index.d.ts +3 -0
- package/dist/sdk/index.js +932 -105
- package/dist/sdk/registry.d.ts +6 -0
- package/package.json +1 -1
package/bin/migrate.js
CHANGED
|
@@ -7,7 +7,7 @@ import { join as join6 } from "path";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@hasna/skills",
|
|
10
|
-
version: "0.5.
|
|
10
|
+
version: "0.5.3",
|
|
11
11
|
description: "Skills library for AI coding agents",
|
|
12
12
|
type: "module",
|
|
13
13
|
bin: {
|
|
@@ -461,7 +461,40 @@ function publicPrincipal(partial = {}) {
|
|
|
461
461
|
// src/server/rows.ts
|
|
462
462
|
import { randomUUID } from "crypto";
|
|
463
463
|
|
|
464
|
+
// src/lib/skill-entry-path.ts
|
|
465
|
+
class SkillEntryPaths {
|
|
466
|
+
files = new Set;
|
|
467
|
+
directories = new Set;
|
|
468
|
+
add(path, maxBytes, invalid, limit) {
|
|
469
|
+
if (path.length > maxBytes)
|
|
470
|
+
limit();
|
|
471
|
+
const encoded = new TextEncoder().encode(path);
|
|
472
|
+
if (encoded.byteLength > maxBytes)
|
|
473
|
+
limit();
|
|
474
|
+
if (new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(encoded) !== path)
|
|
475
|
+
invalid("Invalid UTF-8 entry path");
|
|
476
|
+
if (!path || /[\\:\x00-\x1f\x7f]/u.test(path))
|
|
477
|
+
invalid("Unsafe entry path");
|
|
478
|
+
if (path.split("/").some((segment) => !segment || segment === "." || segment === ".."))
|
|
479
|
+
invalid("Unsafe entry path segment");
|
|
480
|
+
const key = path.normalize("NFC").toLowerCase().normalize("NFC");
|
|
481
|
+
if (this.files.has(key) || this.directories.has(key))
|
|
482
|
+
invalid("Duplicate or conflicting entry path");
|
|
483
|
+
const parents = key.split("/");
|
|
484
|
+
parents.pop();
|
|
485
|
+
while (parents.length) {
|
|
486
|
+
const parent = parents.join("/");
|
|
487
|
+
if (this.files.has(parent))
|
|
488
|
+
invalid("Conflicting entry file ancestor");
|
|
489
|
+
this.directories.add(parent);
|
|
490
|
+
parents.pop();
|
|
491
|
+
}
|
|
492
|
+
this.files.add(key);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
464
496
|
// src/lib/skill-bundle.ts
|
|
497
|
+
var BLOCK = 512;
|
|
465
498
|
var ANY_SEGMENT_EXCLUDES = new Set([
|
|
466
499
|
".git",
|
|
467
500
|
".ds_store",
|
|
@@ -589,6 +622,144 @@ function ownBytes(view) {
|
|
|
589
622
|
out.set(source);
|
|
590
623
|
return out;
|
|
591
624
|
}
|
|
625
|
+
var SKILL_BUNDLE_INSPECTION_LIMITS = Object.freeze({
|
|
626
|
+
compressedBytes: 16 * 1024 * 1024,
|
|
627
|
+
decompressedBytes: 64 * 1024 * 1024,
|
|
628
|
+
entries: 1024,
|
|
629
|
+
fileBytes: 16 * 1024 * 1024,
|
|
630
|
+
pathBytes: 100,
|
|
631
|
+
timeoutMs: 5000
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
class SkillBundleInspectionError extends Error {
|
|
635
|
+
code;
|
|
636
|
+
constructor(code, message) {
|
|
637
|
+
super(message);
|
|
638
|
+
this.code = code;
|
|
639
|
+
this.name = "SkillBundleInspectionError";
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function invalidBundle(message) {
|
|
643
|
+
throw new SkillBundleInspectionError("BUNDLE_INVALID", message);
|
|
644
|
+
}
|
|
645
|
+
class BoundedTarReader {
|
|
646
|
+
limits;
|
|
647
|
+
check;
|
|
648
|
+
header = new Uint8Array(BLOCK);
|
|
649
|
+
headerOffset = 0;
|
|
650
|
+
pending;
|
|
651
|
+
bodyOffset = 0;
|
|
652
|
+
padding = 0;
|
|
653
|
+
zeroBlocks = 0;
|
|
654
|
+
entries = [];
|
|
655
|
+
paths = new SkillEntryPaths;
|
|
656
|
+
fileBytes = 0;
|
|
657
|
+
constructor(limits, check) {
|
|
658
|
+
this.limits = limits;
|
|
659
|
+
this.check = check;
|
|
660
|
+
}
|
|
661
|
+
push(chunk) {
|
|
662
|
+
let offset = 0;
|
|
663
|
+
while (offset < chunk.byteLength) {
|
|
664
|
+
this.check();
|
|
665
|
+
if (this.pending) {
|
|
666
|
+
const count = Math.min(this.pending.bytes.byteLength - this.bodyOffset, chunk.byteLength - offset);
|
|
667
|
+
this.pending.bytes.set(chunk.subarray(offset, offset + count), this.bodyOffset);
|
|
668
|
+
offset += count;
|
|
669
|
+
this.bodyOffset += count;
|
|
670
|
+
if (this.bodyOffset === this.pending.bytes.byteLength) {
|
|
671
|
+
this.entries.push(this.pending);
|
|
672
|
+
this.pending = undefined;
|
|
673
|
+
}
|
|
674
|
+
} else if (this.padding) {
|
|
675
|
+
const count = Math.min(this.padding, chunk.byteLength - offset);
|
|
676
|
+
if (chunk.subarray(offset, offset + count).some((byte) => byte !== 0))
|
|
677
|
+
invalidBundle("Nonzero tar body padding");
|
|
678
|
+
offset += count;
|
|
679
|
+
this.padding -= count;
|
|
680
|
+
} else {
|
|
681
|
+
const count = Math.min(BLOCK - this.headerOffset, chunk.byteLength - offset);
|
|
682
|
+
this.header.set(chunk.subarray(offset, offset + count), this.headerOffset);
|
|
683
|
+
offset += count;
|
|
684
|
+
this.headerOffset += count;
|
|
685
|
+
if (this.headerOffset === BLOCK) {
|
|
686
|
+
this.readHeader();
|
|
687
|
+
this.headerOffset = 0;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
finish() {
|
|
693
|
+
this.check();
|
|
694
|
+
if (this.pending || this.padding || this.headerOffset || this.zeroBlocks < 2)
|
|
695
|
+
invalidBundle("Truncated tar bundle");
|
|
696
|
+
return this.entries;
|
|
697
|
+
}
|
|
698
|
+
readHeader() {
|
|
699
|
+
this.check();
|
|
700
|
+
const h = this.header;
|
|
701
|
+
if (h.every((byte) => byte === 0)) {
|
|
702
|
+
this.zeroBlocks++;
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
if (this.zeroBlocks)
|
|
706
|
+
invalidBundle("Nonzero tar data after terminator");
|
|
707
|
+
if (this.entries.length >= this.limits.entries)
|
|
708
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle entry limit exceeded");
|
|
709
|
+
let checksum = 0;
|
|
710
|
+
for (let i = 0;i < BLOCK; i++)
|
|
711
|
+
checksum += i >= 148 && i < 156 ? 32 : h[i];
|
|
712
|
+
if (tarOctal(h.subarray(148, 156)) !== checksum)
|
|
713
|
+
invalidBundle("Invalid tar header checksum");
|
|
714
|
+
if (new TextDecoder().decode(h.subarray(257, 265)) !== "ustar\x00" + "00")
|
|
715
|
+
invalidBundle("Unsupported tar format");
|
|
716
|
+
if (h[156] !== 48 && h[156] !== 0 || h.subarray(157, 257).some((b) => b !== 0) || h.subarray(345).some((b) => b !== 0))
|
|
717
|
+
invalidBundle("Unsupported tar entry or path prefix");
|
|
718
|
+
const mode = tarOctal(h.subarray(100, 108));
|
|
719
|
+
if (mode > 511)
|
|
720
|
+
invalidBundle("Unsupported tar permission bits");
|
|
721
|
+
tarOctal(h.subarray(108, 116));
|
|
722
|
+
tarOctal(h.subarray(116, 124));
|
|
723
|
+
tarOctal(h.subarray(136, 148));
|
|
724
|
+
const size = tarOctal(h.subarray(124, 136));
|
|
725
|
+
if (size > this.limits.fileBytes || this.fileBytes + size > this.limits.decompressedBytes) {
|
|
726
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle file byte limit exceeded");
|
|
727
|
+
}
|
|
728
|
+
const name = h.subarray(0, 100);
|
|
729
|
+
const end = name.indexOf(0);
|
|
730
|
+
if (end !== -1 && name.subarray(end).some((b) => b !== 0))
|
|
731
|
+
invalidBundle("Invalid tar path padding");
|
|
732
|
+
const raw = end === -1 ? name : name.subarray(0, end);
|
|
733
|
+
if (raw.byteLength > this.limits.pathBytes)
|
|
734
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
|
|
735
|
+
let path;
|
|
736
|
+
try {
|
|
737
|
+
path = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(raw);
|
|
738
|
+
} catch {
|
|
739
|
+
return invalidBundle("Invalid UTF-8 bundle path");
|
|
740
|
+
}
|
|
741
|
+
this.paths.add(path, this.limits.pathBytes, invalidBundle, () => {
|
|
742
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
|
|
743
|
+
});
|
|
744
|
+
this.fileBytes += size;
|
|
745
|
+
this.pending = { path, mode, bytes: new Uint8Array(new ArrayBuffer(size)) };
|
|
746
|
+
this.bodyOffset = 0;
|
|
747
|
+
this.padding = (BLOCK - size % BLOCK) % BLOCK;
|
|
748
|
+
if (!size) {
|
|
749
|
+
this.entries.push(this.pending);
|
|
750
|
+
this.pending = undefined;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
function tarOctal(field) {
|
|
755
|
+
const text = new TextDecoder().decode(field);
|
|
756
|
+
if (!/^[0-7]+[\0 ]*$/.test(text))
|
|
757
|
+
invalidBundle("Invalid tar octal field");
|
|
758
|
+
const value = Number.parseInt(text, 8);
|
|
759
|
+
if (!Number.isSafeInteger(value))
|
|
760
|
+
invalidBundle("Tar integer is out of range");
|
|
761
|
+
return value;
|
|
762
|
+
}
|
|
592
763
|
|
|
593
764
|
// src/server/rows.ts
|
|
594
765
|
function nowIso() {
|
package/bin/server.js
CHANGED
|
@@ -23100,7 +23100,7 @@ var init_dist_es9 = __esm(() => {
|
|
|
23100
23100
|
// package.json
|
|
23101
23101
|
var package_default = {
|
|
23102
23102
|
name: "@hasna/skills",
|
|
23103
|
-
version: "0.5.
|
|
23103
|
+
version: "0.5.3",
|
|
23104
23104
|
description: "Skills library for AI coding agents",
|
|
23105
23105
|
type: "module",
|
|
23106
23106
|
bin: {
|
|
@@ -23232,6 +23232,40 @@ import { createHmac, timingSafeEqual } from "crypto";
|
|
|
23232
23232
|
import { createHash } from "crypto";
|
|
23233
23233
|
import { readFileSync, readdirSync, statSync } from "fs";
|
|
23234
23234
|
import { join, relative } from "path";
|
|
23235
|
+
|
|
23236
|
+
// src/lib/skill-entry-path.ts
|
|
23237
|
+
class SkillEntryPaths {
|
|
23238
|
+
files = new Set;
|
|
23239
|
+
directories = new Set;
|
|
23240
|
+
add(path, maxBytes, invalid, limit) {
|
|
23241
|
+
if (path.length > maxBytes)
|
|
23242
|
+
limit();
|
|
23243
|
+
const encoded = new TextEncoder().encode(path);
|
|
23244
|
+
if (encoded.byteLength > maxBytes)
|
|
23245
|
+
limit();
|
|
23246
|
+
if (new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(encoded) !== path)
|
|
23247
|
+
invalid("Invalid UTF-8 entry path");
|
|
23248
|
+
if (!path || /[\\:\x00-\x1f\x7f]/u.test(path))
|
|
23249
|
+
invalid("Unsafe entry path");
|
|
23250
|
+
if (path.split("/").some((segment) => !segment || segment === "." || segment === ".."))
|
|
23251
|
+
invalid("Unsafe entry path segment");
|
|
23252
|
+
const key = path.normalize("NFC").toLowerCase().normalize("NFC");
|
|
23253
|
+
if (this.files.has(key) || this.directories.has(key))
|
|
23254
|
+
invalid("Duplicate or conflicting entry path");
|
|
23255
|
+
const parents = key.split("/");
|
|
23256
|
+
parents.pop();
|
|
23257
|
+
while (parents.length) {
|
|
23258
|
+
const parent = parents.join("/");
|
|
23259
|
+
if (this.files.has(parent))
|
|
23260
|
+
invalid("Conflicting entry file ancestor");
|
|
23261
|
+
this.directories.add(parent);
|
|
23262
|
+
parents.pop();
|
|
23263
|
+
}
|
|
23264
|
+
this.files.add(key);
|
|
23265
|
+
}
|
|
23266
|
+
}
|
|
23267
|
+
|
|
23268
|
+
// src/lib/skill-bundle.ts
|
|
23235
23269
|
var BLOCK = 512;
|
|
23236
23270
|
var ANY_SEGMENT_EXCLUDES = new Set([
|
|
23237
23271
|
".git",
|
|
@@ -23503,6 +23537,144 @@ function concat(chunks) {
|
|
|
23503
23537
|
}
|
|
23504
23538
|
return merged;
|
|
23505
23539
|
}
|
|
23540
|
+
var SKILL_BUNDLE_INSPECTION_LIMITS = Object.freeze({
|
|
23541
|
+
compressedBytes: 16 * 1024 * 1024,
|
|
23542
|
+
decompressedBytes: 64 * 1024 * 1024,
|
|
23543
|
+
entries: 1024,
|
|
23544
|
+
fileBytes: 16 * 1024 * 1024,
|
|
23545
|
+
pathBytes: 100,
|
|
23546
|
+
timeoutMs: 5000
|
|
23547
|
+
});
|
|
23548
|
+
|
|
23549
|
+
class SkillBundleInspectionError extends Error {
|
|
23550
|
+
code;
|
|
23551
|
+
constructor(code, message) {
|
|
23552
|
+
super(message);
|
|
23553
|
+
this.code = code;
|
|
23554
|
+
this.name = "SkillBundleInspectionError";
|
|
23555
|
+
}
|
|
23556
|
+
}
|
|
23557
|
+
function invalidBundle(message) {
|
|
23558
|
+
throw new SkillBundleInspectionError("BUNDLE_INVALID", message);
|
|
23559
|
+
}
|
|
23560
|
+
class BoundedTarReader {
|
|
23561
|
+
limits;
|
|
23562
|
+
check;
|
|
23563
|
+
header = new Uint8Array(BLOCK);
|
|
23564
|
+
headerOffset = 0;
|
|
23565
|
+
pending;
|
|
23566
|
+
bodyOffset = 0;
|
|
23567
|
+
padding = 0;
|
|
23568
|
+
zeroBlocks = 0;
|
|
23569
|
+
entries = [];
|
|
23570
|
+
paths = new SkillEntryPaths;
|
|
23571
|
+
fileBytes = 0;
|
|
23572
|
+
constructor(limits, check) {
|
|
23573
|
+
this.limits = limits;
|
|
23574
|
+
this.check = check;
|
|
23575
|
+
}
|
|
23576
|
+
push(chunk) {
|
|
23577
|
+
let offset = 0;
|
|
23578
|
+
while (offset < chunk.byteLength) {
|
|
23579
|
+
this.check();
|
|
23580
|
+
if (this.pending) {
|
|
23581
|
+
const count = Math.min(this.pending.bytes.byteLength - this.bodyOffset, chunk.byteLength - offset);
|
|
23582
|
+
this.pending.bytes.set(chunk.subarray(offset, offset + count), this.bodyOffset);
|
|
23583
|
+
offset += count;
|
|
23584
|
+
this.bodyOffset += count;
|
|
23585
|
+
if (this.bodyOffset === this.pending.bytes.byteLength) {
|
|
23586
|
+
this.entries.push(this.pending);
|
|
23587
|
+
this.pending = undefined;
|
|
23588
|
+
}
|
|
23589
|
+
} else if (this.padding) {
|
|
23590
|
+
const count = Math.min(this.padding, chunk.byteLength - offset);
|
|
23591
|
+
if (chunk.subarray(offset, offset + count).some((byte) => byte !== 0))
|
|
23592
|
+
invalidBundle("Nonzero tar body padding");
|
|
23593
|
+
offset += count;
|
|
23594
|
+
this.padding -= count;
|
|
23595
|
+
} else {
|
|
23596
|
+
const count = Math.min(BLOCK - this.headerOffset, chunk.byteLength - offset);
|
|
23597
|
+
this.header.set(chunk.subarray(offset, offset + count), this.headerOffset);
|
|
23598
|
+
offset += count;
|
|
23599
|
+
this.headerOffset += count;
|
|
23600
|
+
if (this.headerOffset === BLOCK) {
|
|
23601
|
+
this.readHeader();
|
|
23602
|
+
this.headerOffset = 0;
|
|
23603
|
+
}
|
|
23604
|
+
}
|
|
23605
|
+
}
|
|
23606
|
+
}
|
|
23607
|
+
finish() {
|
|
23608
|
+
this.check();
|
|
23609
|
+
if (this.pending || this.padding || this.headerOffset || this.zeroBlocks < 2)
|
|
23610
|
+
invalidBundle("Truncated tar bundle");
|
|
23611
|
+
return this.entries;
|
|
23612
|
+
}
|
|
23613
|
+
readHeader() {
|
|
23614
|
+
this.check();
|
|
23615
|
+
const h = this.header;
|
|
23616
|
+
if (h.every((byte) => byte === 0)) {
|
|
23617
|
+
this.zeroBlocks++;
|
|
23618
|
+
return;
|
|
23619
|
+
}
|
|
23620
|
+
if (this.zeroBlocks)
|
|
23621
|
+
invalidBundle("Nonzero tar data after terminator");
|
|
23622
|
+
if (this.entries.length >= this.limits.entries)
|
|
23623
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle entry limit exceeded");
|
|
23624
|
+
let checksum = 0;
|
|
23625
|
+
for (let i = 0;i < BLOCK; i++)
|
|
23626
|
+
checksum += i >= 148 && i < 156 ? 32 : h[i];
|
|
23627
|
+
if (tarOctal(h.subarray(148, 156)) !== checksum)
|
|
23628
|
+
invalidBundle("Invalid tar header checksum");
|
|
23629
|
+
if (new TextDecoder().decode(h.subarray(257, 265)) !== "ustar\x00" + "00")
|
|
23630
|
+
invalidBundle("Unsupported tar format");
|
|
23631
|
+
if (h[156] !== 48 && h[156] !== 0 || h.subarray(157, 257).some((b) => b !== 0) || h.subarray(345).some((b) => b !== 0))
|
|
23632
|
+
invalidBundle("Unsupported tar entry or path prefix");
|
|
23633
|
+
const mode = tarOctal(h.subarray(100, 108));
|
|
23634
|
+
if (mode > 511)
|
|
23635
|
+
invalidBundle("Unsupported tar permission bits");
|
|
23636
|
+
tarOctal(h.subarray(108, 116));
|
|
23637
|
+
tarOctal(h.subarray(116, 124));
|
|
23638
|
+
tarOctal(h.subarray(136, 148));
|
|
23639
|
+
const size = tarOctal(h.subarray(124, 136));
|
|
23640
|
+
if (size > this.limits.fileBytes || this.fileBytes + size > this.limits.decompressedBytes) {
|
|
23641
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle file byte limit exceeded");
|
|
23642
|
+
}
|
|
23643
|
+
const name = h.subarray(0, 100);
|
|
23644
|
+
const end = name.indexOf(0);
|
|
23645
|
+
if (end !== -1 && name.subarray(end).some((b) => b !== 0))
|
|
23646
|
+
invalidBundle("Invalid tar path padding");
|
|
23647
|
+
const raw = end === -1 ? name : name.subarray(0, end);
|
|
23648
|
+
if (raw.byteLength > this.limits.pathBytes)
|
|
23649
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
|
|
23650
|
+
let path;
|
|
23651
|
+
try {
|
|
23652
|
+
path = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(raw);
|
|
23653
|
+
} catch {
|
|
23654
|
+
return invalidBundle("Invalid UTF-8 bundle path");
|
|
23655
|
+
}
|
|
23656
|
+
this.paths.add(path, this.limits.pathBytes, invalidBundle, () => {
|
|
23657
|
+
throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
|
|
23658
|
+
});
|
|
23659
|
+
this.fileBytes += size;
|
|
23660
|
+
this.pending = { path, mode, bytes: new Uint8Array(new ArrayBuffer(size)) };
|
|
23661
|
+
this.bodyOffset = 0;
|
|
23662
|
+
this.padding = (BLOCK - size % BLOCK) % BLOCK;
|
|
23663
|
+
if (!size) {
|
|
23664
|
+
this.entries.push(this.pending);
|
|
23665
|
+
this.pending = undefined;
|
|
23666
|
+
}
|
|
23667
|
+
}
|
|
23668
|
+
}
|
|
23669
|
+
function tarOctal(field) {
|
|
23670
|
+
const text = new TextDecoder().decode(field);
|
|
23671
|
+
if (!/^[0-7]+[\0 ]*$/.test(text))
|
|
23672
|
+
invalidBundle("Invalid tar octal field");
|
|
23673
|
+
const value = Number.parseInt(text, 8);
|
|
23674
|
+
if (!Number.isSafeInteger(value))
|
|
23675
|
+
invalidBundle("Tar integer is out of range");
|
|
23676
|
+
return value;
|
|
23677
|
+
}
|
|
23506
23678
|
|
|
23507
23679
|
// src/lib/skill-bundles.ts
|
|
23508
23680
|
var SIGNATURE_PREFIX = "hmac-sha256:";
|
|
@@ -35781,6 +35953,20 @@ function parseSkillFrontmatter(content) {
|
|
|
35781
35953
|
|
|
35782
35954
|
// src/lib/skill-hash.ts
|
|
35783
35955
|
var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
|
|
35956
|
+
var CONTENT_HASH_LIMITS = Object.freeze({
|
|
35957
|
+
entries: 1024,
|
|
35958
|
+
rawBytes: 64 * 1024 * 1024,
|
|
35959
|
+
normalizedBytes: 64 * 1024 * 1024,
|
|
35960
|
+
fileBytes: 16 * 1024 * 1024,
|
|
35961
|
+
normalizedFileBytes: 16 * 1024 * 1024,
|
|
35962
|
+
pathBytes: 100,
|
|
35963
|
+
manifestBytes: 16 * 1024,
|
|
35964
|
+
manifestDepth: 64,
|
|
35965
|
+
timeoutMs: 5000
|
|
35966
|
+
});
|
|
35967
|
+
var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
35968
|
+
var byteLengthOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength").get;
|
|
35969
|
+
var bufferOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
|
|
35784
35970
|
|
|
35785
35971
|
// src/lib/portable-skills-types.ts
|
|
35786
35972
|
var PORTABLE_SKILL_STANDARD = "hasna.skill.v1";
|