@dot-agent/compiler 0.1.0 → 0.5.0-alpha.1

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/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ COMPILER_VERSION,
2
3
  aboutmeToJson,
3
4
  buildAboutme,
4
5
  buildId,
@@ -7,13 +8,15 @@ import {
7
8
  extractFiles,
8
9
  extractName,
9
10
  parseAboutme,
10
- parseId
11
- } from "./chunk-IT25ILTQ.js";
11
+ parseId,
12
+ validateMagicBytes,
13
+ validateZipBomb
14
+ } from "./chunk-JIYQMCQQ.js";
12
15
 
13
16
  // src/parser.ts
14
17
  import { createRequire } from "module";
15
18
  import { Parser, Language } from "web-tree-sitter";
16
- import bpInit, { parse_behavior as bpParseBehavior, parse_description as bpParseDescription, get_graph } from "@dot-agent/parser-dsl";
19
+ import { init as bpInit, parse_behavior as bpParseBehavior, parse_description as bpParseDescription, get_graph } from "@dot-agent/parser-dsl";
17
20
  var require2 = createRequire(import.meta.url);
18
21
  var { descriptionWasmPath, behaviorWasmPath } = require2("@dot-agent/tree-sitter");
19
22
  var _initialized = false;
@@ -177,6 +180,18 @@ async function lintDescription(text, file = "agent.description") {
177
180
  message: "No domain declared \u2014 agent will be packaged as unknown/name. Interoperability between runtimes is not guaranteed."
178
181
  });
179
182
  }
183
+ const behaviorBlocks = nodesOfType(tree, "behavior_block");
184
+ if (behaviorBlocks.length > 1) {
185
+ const { line, col } = nodePosition(behaviorBlocks[1]);
186
+ messages.push({
187
+ file,
188
+ line,
189
+ col,
190
+ severity: "error",
191
+ code: "E017",
192
+ message: "Multiple 'behavior' declarations \u2014 only one is allowed. To combine multiple files, use 'merge' in your .behavior file."
193
+ });
194
+ }
180
195
  const declaredTypes = new Set(
181
196
  nodesOfType(tree, "type_decl").map((n) => n.childForFieldName("name")?.text).filter(Boolean)
182
197
  );
@@ -275,7 +290,7 @@ function collectMergedStates(tree, docDir, states, visited = /* @__PURE__ */ new
275
290
  collectMergedStates(mergedTree, dirname(absPath), states, visited);
276
291
  }
277
292
  }
278
- async function lintBehavior(text, file = "agent.behavior", docPath) {
293
+ async function lintBehavior(text, file = "agent.behavior", docPath, consolidated = false, externalStates, mergedText) {
279
294
  await initBehaviorParser();
280
295
  if (!text.endsWith("\n")) text = text + "\n";
281
296
  const tree = await parse("behavior", text);
@@ -296,7 +311,7 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
296
311
  col,
297
312
  severity: "warning",
298
313
  code: "W013",
299
- message: `'interact' without 'goal' \u2014 the prettifier will insert one. To set it explicitly, add 'goal "..."' before 'interact'.`
314
+ message: `'interact' without 'goal'. Add 'goal "..."' before 'interact'.`
300
315
  });
301
316
  }
302
317
  if (hasGoal && !hasInteract) {
@@ -307,7 +322,7 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
307
322
  col,
308
323
  severity: "warning",
309
324
  code: "W012",
310
- message: `'goal' is only valid in an oriented state. Add 'interact' or remove 'goal' \u2014 the prettifier can adjust this.`
325
+ message: `'goal' is only valid in an oriented state. Add 'interact' or remove 'goal'.`
311
326
  });
312
327
  }
313
328
  if (hasInteract && intentHandlers.length === 0) {
@@ -438,7 +453,7 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
438
453
  col,
439
454
  severity: "warning",
440
455
  code: "W002",
441
- message: `Text block exceeds 280 characters (${content.length}). Consider using 'teach' to load long goal text from an external file.`
456
+ message: `Text block exceeds 280 characters (${content.length}). Consider using 'guide' to load long orientation text from an external text file.`
442
457
  });
443
458
  }
444
459
  }
@@ -457,7 +472,7 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
457
472
  col,
458
473
  severity: "warning",
459
474
  code: "W010",
460
- message: `'guide' text in state '${stateName}' is ${content.length} characters (limit: 280). Consider using an external file.`
475
+ message: `'guide' text in state '${stateName}' is ${content.length} characters. Consider using an external file.`
461
476
  });
462
477
  }
463
478
  }
@@ -470,6 +485,9 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
470
485
  } catch {
471
486
  }
472
487
  }
488
+ if (externalStates) {
489
+ for (const name of externalStates) definedStates.add(name);
490
+ }
473
491
  const stateNameList = Array.from(definedStates);
474
492
  for (const transitionNode of nodesOfType(tree, "transition_stmt")) {
475
493
  const stateNode = transitionNode.childForFieldName("state");
@@ -521,7 +539,9 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
521
539
  return messages;
522
540
  }
523
541
  const fsm = fsmResult.ok;
524
- const allTargets = new Set(collectTransitionTargets(fsm.states.flatMap((s) => s.body)));
542
+ const wholeFsm = mergedText !== void 0 ? parseBehaviorFile(mergedText).ok : null;
543
+ const reachabilityStates = wholeFsm?.states ?? fsm.states;
544
+ const allTargets = new Set(collectTransitionTargets(reachabilityStates.flatMap((s) => s.body)));
525
545
  for (const state of fsm.states) {
526
546
  const hasOutgoing = collectTransitionTargets(state.body).length > 0;
527
547
  const hasIncoming = allTargets.has(state.name);
@@ -551,6 +571,49 @@ async function lintBehavior(text, file = "agent.behavior", docPath) {
551
571
  });
552
572
  }
553
573
  }
574
+ if (consolidated) {
575
+ const wholeTreeFsm = wholeFsm ?? fsm;
576
+ const seenStates = /* @__PURE__ */ new Set();
577
+ for (const state of wholeTreeFsm.states) {
578
+ if (seenStates.has(state.name)) {
579
+ messages.push({
580
+ file,
581
+ line: 1,
582
+ col: 1,
583
+ severity: "error",
584
+ code: "E015",
585
+ message: `Duplicate state '${state.name}' across merged files \u2014 each state name must be unique in the consolidated FSM.`
586
+ });
587
+ } else {
588
+ seenStates.add(state.name);
589
+ }
590
+ }
591
+ if (!wholeTreeFsm.states.some((s) => s.name === "init")) {
592
+ messages.push({
593
+ file,
594
+ line: 1,
595
+ col: 1,
596
+ severity: "error",
597
+ code: "E016",
598
+ message: `Required 'init' state is missing. Add a state named 'init' as the entry point of your behavior.`
599
+ });
600
+ }
601
+ const seenTriggers = /* @__PURE__ */ new Set();
602
+ for (const trigger of wholeTreeFsm.global_triggers) {
603
+ if (seenTriggers.has(trigger.event)) {
604
+ messages.push({
605
+ file,
606
+ line: 1,
607
+ col: 1,
608
+ severity: "warning",
609
+ code: "W014",
610
+ message: `Duplicate global trigger '${trigger.event}' across merged files \u2014 only the last definition takes effect.`
611
+ });
612
+ } else {
613
+ seenTriggers.add(trigger.event);
614
+ }
615
+ }
616
+ }
554
617
  return messages;
555
618
  }
556
619
  async function createLinter() {
@@ -560,37 +623,19 @@ async function createLinter() {
560
623
  // src/zip.ts
561
624
  import JSZip from "jszip";
562
625
  import { readFile, writeFile } from "fs/promises";
563
- var MAX_ZIP_SIZE = 500 * 1024 * 1024;
564
- var MAX_COMPRESSION_RATIO = 100;
565
626
  async function readZip(filePath) {
566
627
  const data = await readFile(filePath);
567
628
  return JSZip.loadAsync(data);
568
629
  }
569
- async function validateZipBomb(filePath) {
630
+ async function validateZipBomb2(filePath) {
570
631
  const data = await readFile(filePath);
571
632
  const zip = await JSZip.loadAsync(data);
572
- let totalUncompressed = 0;
573
- zip.forEach((_relativePath, file) => {
574
- if (!file.dir) {
575
- totalUncompressed += file._data?.uncompressedSize || 0;
576
- }
577
- });
578
- const compressedSize = data.length;
579
- const ratio = totalUncompressed / compressedSize;
580
- if (totalUncompressed > MAX_ZIP_SIZE) {
581
- throw new Error(`ZIP uncompressed size exceeds 500MB limit: ${totalUncompressed}`);
582
- }
583
- if (ratio > MAX_COMPRESSION_RATIO) {
584
- throw new Error(`ZIP compression ratio exceeds 100x limit: ${ratio.toFixed(1)}x`);
585
- }
633
+ validateZipBomb(zip, data.length);
586
634
  return true;
587
635
  }
588
- async function validateMagicBytes(filePath) {
636
+ async function validateMagicBytes2(filePath) {
589
637
  const data = await readFile(filePath);
590
- const magic = data.subarray(0, 4);
591
- if (!(magic[0] === 80 && magic[1] === 75 && magic[2] === 3 && magic[3] === 4)) {
592
- throw new Error("File is not a valid ZIP (invalid magic bytes)");
593
- }
638
+ validateMagicBytes(data);
594
639
  return true;
595
640
  }
596
641
  async function writeZip(zip, outPath) {
@@ -600,7 +645,7 @@ async function writeZip(zip, outPath) {
600
645
 
601
646
  // src/pack.ts
602
647
  import { readFile as readFile2, stat, readdir } from "fs/promises";
603
- import { join, basename } from "path";
648
+ import { join, basename, resolve as resolve2, relative, isAbsolute, normalize, dirname as dirname2 } from "path";
604
649
  import { execSync } from "child_process";
605
650
  import { createHash } from "crypto";
606
651
  import JSZip2 from "jszip";
@@ -682,7 +727,81 @@ async function resolveCommit(explicit) {
682
727
  if (explicit) return explicit;
683
728
  return gitRevParseShort() ?? void 0;
684
729
  }
685
- async function collectFiles(dir) {
730
+ function isExternalPath(agentRoot, declaredPath) {
731
+ if (isAbsolute(declaredPath)) return true;
732
+ const normRoot = normalize(resolve2(agentRoot));
733
+ const resolved = resolve2(normRoot, declaredPath);
734
+ return relative(normRoot, resolved).startsWith("..");
735
+ }
736
+ async function discoverDescriptionFile(dir, explicit) {
737
+ if (explicit) {
738
+ try {
739
+ await stat(join(dir, explicit));
740
+ return explicit;
741
+ } catch {
742
+ throw new Error(`E003: Description file '${explicit}' not found in ${dir}`);
743
+ }
744
+ }
745
+ const entries = await readdir(dir);
746
+ const descFiles = entries.filter((f) => f.endsWith(".description"));
747
+ if (descFiles.length === 0) {
748
+ throw new Error(`E003: No .description file found in ${dir}`);
749
+ }
750
+ if (descFiles.length > 1) {
751
+ throw new Error(`E003: Multiple .description files found: ${descFiles.join(", ")} \u2014 use PackOptions.description to specify one`);
752
+ }
753
+ const name = descFiles[0];
754
+ if (name !== "agent.description") {
755
+ console.info(`[dot-agent] using description file: ${name}`);
756
+ }
757
+ return name;
758
+ }
759
+ async function consolidate(agentRoot, entryFile) {
760
+ await initBehaviorParser();
761
+ const normRoot = normalize(resolve2(agentRoot));
762
+ const visiting = /* @__PURE__ */ new Set();
763
+ const visited = /* @__PURE__ */ new Set();
764
+ const order = [];
765
+ const textCache = /* @__PURE__ */ new Map();
766
+ async function dfs(relPath) {
767
+ const absPath = resolve2(normRoot, relPath);
768
+ if (visiting.has(absPath)) {
769
+ throw new Error(`E013: Circular merge dependency involving '${relPath}'`);
770
+ }
771
+ if (visited.has(absPath)) return;
772
+ visiting.add(absPath);
773
+ let fileText;
774
+ try {
775
+ fileText = await readFile2(absPath, "utf-8");
776
+ } catch {
777
+ throw new Error(`E012: Merge target not found: '${relPath}'`);
778
+ }
779
+ textCache.set(absPath, fileText);
780
+ const result = parseBehaviorFile(fileText);
781
+ const merges = result.ok?.merges ?? [];
782
+ for (const mergePath of merges) {
783
+ if (isAbsolute(mergePath)) {
784
+ throw new Error(`E014: Merge path '${mergePath}' in '${relPath}' is absolute \u2014 only paths within the agent root are allowed`);
785
+ }
786
+ const mergeAbs = resolve2(dirname2(absPath), mergePath);
787
+ const mergeRel = relative(normRoot, mergeAbs);
788
+ if (mergeRel.startsWith("..")) {
789
+ throw new Error(`E014: Merge path '${mergePath}' in '${relPath}' escapes the agent root`);
790
+ }
791
+ await dfs(mergeRel);
792
+ }
793
+ visiting.delete(absPath);
794
+ visited.add(absPath);
795
+ order.push(relPath);
796
+ }
797
+ await dfs(entryFile);
798
+ const texts = order.map((relPath) => textCache.get(resolve2(normRoot, relPath)));
799
+ return {
800
+ mergedText: texts.join("\n"),
801
+ mergeSources: order
802
+ };
803
+ }
804
+ async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSources) {
686
805
  const files = /* @__PURE__ */ new Map();
687
806
  async function walk(subdir, prefix = "") {
688
807
  try {
@@ -701,13 +820,16 @@ async function collectFiles(dir) {
701
820
  } catch {
702
821
  }
703
822
  }
704
- files.set("agent.description", await readFile2(join(dir, "agent.description"), "utf-8"));
705
- files.set("agent.behavior", await readFile2(join(dir, "agent.behavior"), "utf-8"));
823
+ files.set(descriptionFile, await readFile2(join(dir, descriptionFile), "utf-8"));
824
+ const flatBehaviorText = mergedBehaviorText.replace(/^\s*merge\s+"[^"]*"\s*$/gm, "");
825
+ files.set("agent.behavior", flatBehaviorText);
826
+ for (const relPath of mergeSources) {
827
+ files.set(`behaviors/${relPath}`, await readFile2(join(dir, relPath), "utf-8"));
828
+ }
706
829
  try {
707
830
  files.set("SOUL.md", await readFile2(join(dir, "SOUL.md"), "utf-8"));
708
831
  } catch {
709
832
  }
710
- await walk(join(dir, "behaviors"), "behaviors");
711
833
  await walk(join(dir, "guides"), "guides");
712
834
  await walk(join(dir, "knowledge"), "knowledge");
713
835
  return files;
@@ -715,29 +837,14 @@ async function collectFiles(dir) {
715
837
  async function pack(options = {}) {
716
838
  const dir = options.dir ?? process.cwd();
717
839
  const outPath = options.out ?? join(dir, `${basename(dir)}.agent`);
718
- let descriptionText;
719
- let behaviorText;
720
- try {
721
- descriptionText = await readFile2(join(dir, "agent.description"), "utf-8");
722
- } catch {
723
- throw new Error("E003: File agent.description not found");
724
- }
725
- try {
726
- behaviorText = await readFile2(join(dir, "agent.behavior"), "utf-8");
727
- } catch {
728
- throw new Error("E007: File agent.behavior not found");
729
- }
730
- const [descriptionMessages, behaviorMessages] = await Promise.all([
731
- lintDescription(descriptionText),
732
- lintBehavior(behaviorText)
733
- ]);
734
- const allMessages = [...descriptionMessages, ...behaviorMessages];
735
- const errors = allMessages.filter((m) => m.severity === "error");
736
- const warnings = allMessages.filter((m) => m.severity === "warning");
737
- if (errors.length > 0) {
840
+ const descriptionFileName = await discoverDescriptionFile(dir, options.description);
841
+ const descriptionText = await readFile2(join(dir, descriptionFileName), "utf-8");
842
+ const descriptionMessages = await lintDescription(descriptionText, descriptionFileName);
843
+ const descErrors = descriptionMessages.filter((m) => m.severity === "error");
844
+ if (descErrors.length > 0) {
738
845
  throw new Error(
739
846
  `Lint failed:
740
- ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
847
+ ${descErrors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
741
848
  );
742
849
  }
743
850
  await initBehaviorParser();
@@ -747,9 +854,26 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
747
854
  throw new Error(`E_DESC: ${firstError?.message ?? "parse failed"}`);
748
855
  }
749
856
  const df = descResult.ok;
857
+ if (!df.behavior) {
858
+ throw new Error(`E_DESC: '${descriptionFileName}' must declare a behavior file \u2014 add 'behavior "agent.behavior"' (or the name of your entry .behavior file)`);
859
+ }
860
+ if (isExternalPath(dir, df.behavior)) {
861
+ throw new Error(`E014: behavior path '${df.behavior}' in '${descriptionFileName}' is absolute or escapes the agent root`);
862
+ }
863
+ const { mergedText, mergeSources } = await consolidate(dir, df.behavior);
864
+ const behaviorMessages = await lintBehavior(mergedText, "agent.behavior", void 0, true);
865
+ const allMessages = [...descriptionMessages, ...behaviorMessages];
866
+ const errors = allMessages.filter((m) => m.severity === "error");
867
+ const warnings = allMessages.filter((m) => m.severity === "warning");
868
+ if (errors.length > 0) {
869
+ throw new Error(
870
+ `Lint failed:
871
+ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
872
+ );
873
+ }
750
874
  const version = await resolveVersion(options.version);
751
875
  const commit = await resolveCommit(options.commit);
752
- const allFiles = await collectFiles(dir);
876
+ const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
753
877
  const contentForHash = Array.from(allFiles.values()).join("");
754
878
  const sha256 = createHash("sha256").update(contentForHash).digest("hex");
755
879
  const namespace = df.agent.domain ?? "unknown";
@@ -769,7 +893,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
769
893
  license: df.agent.license ?? "",
770
894
  persona: df.persona ?? "SOUL.md",
771
895
  purpose: "unknown",
772
- compiler: "dot-agent/1.0.0",
896
+ compiler: `dot-agent/${COMPILER_VERSION}`,
773
897
  commit,
774
898
  capabilities: df.capabilities.map((c) => ({ id: c.name, description: c.description ?? "" })),
775
899
  requires: df.requires,
@@ -781,26 +905,100 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
781
905
  if (typesJson) {
782
906
  agentFolder.file("types.json", typesJson);
783
907
  }
784
- const gitkeepPaths = /* @__PURE__ */ new Set(["behaviors/.gitkeep", "guides/.gitkeep", "knowledge/.gitkeep"]);
908
+ const gitkeepPaths = /* @__PURE__ */ new Set(["guides/.gitkeep", "knowledge/.gitkeep"]);
785
909
  const filesJson = {
786
- description: "agent.description",
910
+ description: descriptionFileName,
787
911
  behavior: "agent.behavior",
788
- behaviors: Array.from(allFiles.keys()).filter((f) => f.startsWith("behaviors/") && !gitkeepPaths.has(f)),
912
+ behaviors: Array.from(allFiles.keys()).filter((f) => f.startsWith("behaviors/")),
789
913
  guides: Array.from(allFiles.keys()).filter((f) => f.startsWith("guides/") && !gitkeepPaths.has(f)),
790
914
  knowledge: Array.from(allFiles.keys()).filter((f) => f.startsWith("knowledge/") && !gitkeepPaths.has(f))
791
915
  };
792
916
  agentFolder.file("files.json", JSON.stringify(filesJson, null, 2));
793
917
  for (const [path, content] of allFiles) {
794
- if (!gitkeepPaths.has(path)) zip.file(path, content);
918
+ zip.file(path, content);
795
919
  }
796
920
  await writeZip(zip, outPath);
797
921
  return { path: outPath, id, warnings };
798
922
  }
923
+
924
+ // src/bundle.ts
925
+ import { readFile as readFile3 } from "fs/promises";
926
+ import { join as join2 } from "path";
927
+ import { createHash as createHash2 } from "crypto";
928
+ var GITKEEP = /* @__PURE__ */ new Set(["guides/.gitkeep", "knowledge/.gitkeep"]);
929
+ async function bundleFromDir(dir) {
930
+ const descriptionFileName = await discoverDescriptionFile(dir);
931
+ const descriptionText = await readFile3(join2(dir, descriptionFileName), "utf-8");
932
+ const descMessages = await lintDescription(descriptionText, descriptionFileName);
933
+ const descErrors = descMessages.filter((m) => m.severity === "error");
934
+ if (descErrors.length > 0) {
935
+ throw new Error(
936
+ `Lint failed:
937
+ ${descErrors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
938
+ );
939
+ }
940
+ await initBehaviorParser();
941
+ const descResult = parseDescriptionFile(descriptionText);
942
+ if (descResult.ok === null) {
943
+ const firstError = descResult.diagnostics.find((d) => d.severity === "error");
944
+ throw new Error(`E_DESC: ${firstError?.message ?? "parse failed"}`);
945
+ }
946
+ const df = descResult.ok;
947
+ if (!df.behavior) {
948
+ throw new Error(`E_DESC: '${descriptionFileName}' must declare a behavior file`);
949
+ }
950
+ const { mergedText, mergeSources } = await consolidate(dir, df.behavior);
951
+ const behaviorMessages = await lintBehavior(mergedText, "agent.behavior", void 0, true);
952
+ const allMessages = [...descMessages, ...behaviorMessages];
953
+ const errors = allMessages.filter((m) => m.severity === "error");
954
+ const warnings = allMessages.filter((m) => m.severity === "warning");
955
+ if (errors.length > 0) {
956
+ throw new Error(
957
+ `Lint failed:
958
+ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
959
+ );
960
+ }
961
+ for (const w of warnings) {
962
+ process.stderr.write(`\x1B[33m\u26A0\x1B[0m ${w.file}:${w.line}:${w.col} ${w.code} ${w.message}
963
+ `);
964
+ }
965
+ const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
966
+ const sha256 = createHash2("sha256").update(Array.from(allFiles.values()).join("")).digest("hex");
967
+ const id = buildId({ namespace: df.agent.domain ?? "local", name: df.agent.name, version: "dev" });
968
+ const aboutme = buildAboutme({
969
+ id,
970
+ name: df.agent.name,
971
+ description: df.description ?? "",
972
+ version: "dev",
973
+ domain: df.agent.domain ?? "",
974
+ license: df.agent.license ?? "",
975
+ persona: df.persona ?? "SOUL.md",
976
+ purpose: "development",
977
+ compiler: `dot-agent/${COMPILER_VERSION}`,
978
+ capabilities: df.capabilities.map((c) => ({ id: c.name, description: c.description ?? "" })),
979
+ requires: df.requires,
980
+ integrity: { sha256, files: ".agent/files.json" }
981
+ });
982
+ const files = {
983
+ description: descriptionText,
984
+ // Reuse collectFiles()'s 'agent.behavior' entry rather than the raw
985
+ // mergedText — it has redundant `merge "..."` lines stripped (see
986
+ // collectFiles() for why they're dead weight once flattened).
987
+ behavior: allFiles.get("agent.behavior") ?? mergedText,
988
+ soul: allFiles.get("SOUL.md"),
989
+ guides: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("guides/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
990
+ knowledge: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("knowledge/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
991
+ behaviors: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("behaviors/")).map(([path, content]) => ({ path, content }))
992
+ };
993
+ return { id, aboutme, files };
994
+ }
799
995
  export {
800
996
  aboutmeToJson,
801
997
  buildAboutme,
802
998
  buildId,
999
+ bundleFromDir,
803
1000
  collectFiles,
1001
+ consolidate,
804
1002
  createLinter,
805
1003
  createZip,
806
1004
  extractDigest,
@@ -824,8 +1022,8 @@ export {
824
1022
  parseSync,
825
1023
  positionToOffset,
826
1024
  readZip,
827
- validateMagicBytes,
828
- validateZipBomb,
1025
+ validateMagicBytes2 as validateMagicBytes,
1026
+ validateZipBomb2 as validateZipBomb,
829
1027
  writeZip
830
1028
  };
831
1029
  //# sourceMappingURL=index.js.map