@dot-agent/compiler 0.5.0-alpha.2 → 0.10.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/dist/{chunk-P5LFGJ6P.js → chunk-AYXHOOUX.js} +14 -7
- package/dist/chunk-AYXHOOUX.js.map +1 -0
- package/dist/{core-b-7c6X6q.d.cts → core-D2X2Eohl.d.cts} +3 -3
- package/dist/{core-b-7c6X6q.d.ts → core-D2X2Eohl.d.ts} +3 -3
- package/dist/core.cjs +3 -5
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/index.cjs +139 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +131 -26
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-P5LFGJ6P.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
extractDigest,
|
|
8
8
|
extractFiles,
|
|
9
9
|
extractName,
|
|
10
|
+
isValidVersion,
|
|
10
11
|
parseAboutme,
|
|
11
12
|
parseId,
|
|
13
|
+
slugify,
|
|
12
14
|
validateMagicBytes,
|
|
13
15
|
validateZipBomb
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-AYXHOOUX.js";
|
|
15
17
|
|
|
16
18
|
// src/parser.ts
|
|
17
19
|
import { createRequire } from "module";
|
|
@@ -705,13 +707,6 @@ function buildTypesJson(df) {
|
|
|
705
707
|
}
|
|
706
708
|
|
|
707
709
|
// src/pack.ts
|
|
708
|
-
function gitDescribeTags() {
|
|
709
|
-
try {
|
|
710
|
-
return execSync("git describe --tags --abbrev=0", { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
711
|
-
} catch {
|
|
712
|
-
return null;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
710
|
function gitRevParseShort() {
|
|
716
711
|
try {
|
|
717
712
|
return execSync("git rev-parse --short HEAD", { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
@@ -719,14 +714,65 @@ function gitRevParseShort() {
|
|
|
719
714
|
return null;
|
|
720
715
|
}
|
|
721
716
|
}
|
|
722
|
-
async function resolveVersion(explicit) {
|
|
723
|
-
if (explicit) return explicit;
|
|
724
|
-
return gitDescribeTags() ?? "v1.0.0";
|
|
725
|
-
}
|
|
726
717
|
async function resolveCommit(explicit) {
|
|
727
718
|
if (explicit) return explicit;
|
|
728
719
|
return gitRevParseShort() ?? void 0;
|
|
729
720
|
}
|
|
721
|
+
function recentTagCandidates(limit = 5) {
|
|
722
|
+
let tags;
|
|
723
|
+
try {
|
|
724
|
+
tags = execSync("git tag --sort=-creatordate", { stdio: "pipe", encoding: "utf-8" }).trim().split("\n").filter(Boolean);
|
|
725
|
+
} catch {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
return tags.slice(0, limit).map((tag) => {
|
|
729
|
+
const atIdx = tag.lastIndexOf("@");
|
|
730
|
+
const version = atIdx === -1 ? tag : tag.slice(atIdx + 1);
|
|
731
|
+
const label = atIdx === -1 ? tag : `${version} (tag: ${tag})`;
|
|
732
|
+
return { version, label };
|
|
733
|
+
}).filter((c) => isValidVersion(c.version));
|
|
734
|
+
}
|
|
735
|
+
var CUSTOM_VERSION = "__dot-agent-custom-version__";
|
|
736
|
+
var BARE_VERSION = "__dot-agent-bare-version__";
|
|
737
|
+
async function resolveVersionInteractive(explicit) {
|
|
738
|
+
if (explicit) {
|
|
739
|
+
if (!isValidVersion(explicit)) {
|
|
740
|
+
throw new Error(`E019: Invalid version format '${explicit}' \u2014 expected vX.Y[.Z][-prerelease] or X.Y[.Z][-prerelease]`);
|
|
741
|
+
}
|
|
742
|
+
return explicit;
|
|
743
|
+
}
|
|
744
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
745
|
+
process.stderr.write("[dot-agent] no TTY and no --version \u2014 packing without a version\n");
|
|
746
|
+
return void 0;
|
|
747
|
+
}
|
|
748
|
+
const candidates = recentTagCandidates();
|
|
749
|
+
const clack = await import("@clack/prompts");
|
|
750
|
+
const choice = await clack.select({
|
|
751
|
+
message: "Choose a version for this package",
|
|
752
|
+
options: [
|
|
753
|
+
...candidates.map((c) => ({ value: c.version, label: c.label })),
|
|
754
|
+
{ value: CUSTOM_VERSION, label: "Type a custom version\u2026" },
|
|
755
|
+
{ value: BARE_VERSION, label: "None (bare \u2014 no version)" }
|
|
756
|
+
]
|
|
757
|
+
});
|
|
758
|
+
if (clack.isCancel(choice)) {
|
|
759
|
+
clack.cancel("Pack cancelled.");
|
|
760
|
+
process.exit(1);
|
|
761
|
+
}
|
|
762
|
+
if (choice === BARE_VERSION) return void 0;
|
|
763
|
+
if (choice === CUSTOM_VERSION) {
|
|
764
|
+
const typed = await clack.text({
|
|
765
|
+
message: "Version",
|
|
766
|
+
validate: (v) => v && isValidVersion(v) ? void 0 : "Invalid version format \u2014 expected vX.Y[.Z][-prerelease] or X.Y[.Z][-prerelease]"
|
|
767
|
+
});
|
|
768
|
+
if (clack.isCancel(typed)) {
|
|
769
|
+
clack.cancel("Pack cancelled.");
|
|
770
|
+
process.exit(1);
|
|
771
|
+
}
|
|
772
|
+
return typed;
|
|
773
|
+
}
|
|
774
|
+
return choice;
|
|
775
|
+
}
|
|
730
776
|
function isExternalPath(agentRoot, declaredPath) {
|
|
731
777
|
if (isAbsolute(declaredPath)) return true;
|
|
732
778
|
const normRoot = normalize(resolve2(agentRoot));
|
|
@@ -801,7 +847,35 @@ async function consolidate(agentRoot, entryFile) {
|
|
|
801
847
|
mergeSources: order
|
|
802
848
|
};
|
|
803
849
|
}
|
|
804
|
-
|
|
850
|
+
var FILE_REF_RE = /\.(txt|md)$/i;
|
|
851
|
+
function collectFileRefs(stmts, out) {
|
|
852
|
+
for (const s of stmts) {
|
|
853
|
+
switch (s.type) {
|
|
854
|
+
case "guide_stmt":
|
|
855
|
+
if (FILE_REF_RE.test(s.text)) out.set(`guide:${s.text}`, { kind: "guide", text: s.text });
|
|
856
|
+
break;
|
|
857
|
+
case "teach_stmt":
|
|
858
|
+
if (FILE_REF_RE.test(s.text)) out.set(`teach:${s.text}`, { kind: "teach", text: s.text });
|
|
859
|
+
break;
|
|
860
|
+
case "interact_stmt":
|
|
861
|
+
collectFileRefs(s.handlers, out);
|
|
862
|
+
break;
|
|
863
|
+
case "intent_handler":
|
|
864
|
+
if (Array.isArray(s.body)) collectFileRefs(s.body, out);
|
|
865
|
+
break;
|
|
866
|
+
case "offtopic_handler":
|
|
867
|
+
case "after_stmt":
|
|
868
|
+
case "parallel_stmt":
|
|
869
|
+
collectFileRefs(s.body, out);
|
|
870
|
+
break;
|
|
871
|
+
case "conditional_stmt":
|
|
872
|
+
collectFileRefs(s.then, out);
|
|
873
|
+
if (s.else) collectFileRefs(s.else, out);
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSources, personaFile) {
|
|
805
879
|
const files = /* @__PURE__ */ new Map();
|
|
806
880
|
async function walk(subdir, prefix = "") {
|
|
807
881
|
try {
|
|
@@ -826,17 +900,47 @@ async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSourc
|
|
|
826
900
|
for (const relPath of mergeSources) {
|
|
827
901
|
files.set(`behaviors/${relPath}`, await readFile2(join(dir, relPath), "utf-8"));
|
|
828
902
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
903
|
+
if (personaFile) {
|
|
904
|
+
if (isExternalPath(dir, personaFile)) {
|
|
905
|
+
throw new Error(`E014: persona path '${personaFile}' in '${descriptionFile}' is absolute or escapes the agent root`);
|
|
906
|
+
}
|
|
907
|
+
let personaText;
|
|
908
|
+
try {
|
|
909
|
+
personaText = await readFile2(join(dir, personaFile), "utf-8");
|
|
910
|
+
} catch {
|
|
911
|
+
throw new Error(`E_DESC: persona file '${personaFile}' declared in '${descriptionFile}' not found`);
|
|
912
|
+
}
|
|
913
|
+
files.set(personaFile, personaText);
|
|
832
914
|
}
|
|
833
915
|
await walk(join(dir, "guides"), "guides");
|
|
834
916
|
await walk(join(dir, "knowledge"), "knowledge");
|
|
917
|
+
await initBehaviorParser();
|
|
918
|
+
const behaviorAst = parseBehaviorFile(mergedBehaviorText).ok;
|
|
919
|
+
if (behaviorAst) {
|
|
920
|
+
const refs = /* @__PURE__ */ new Map();
|
|
921
|
+
for (const state of behaviorAst.states) collectFileRefs(state.body, refs);
|
|
922
|
+
for (const trigger of behaviorAst.global_triggers) collectFileRefs(trigger.body, refs);
|
|
923
|
+
for (const { kind, text } of refs.values()) {
|
|
924
|
+
if (isExternalPath(dir, text)) {
|
|
925
|
+
throw new Error(`E014: '${kind}' path '${text}' is absolute or escapes the agent root`);
|
|
926
|
+
}
|
|
927
|
+
let content;
|
|
928
|
+
try {
|
|
929
|
+
content = await readFile2(join(dir, text), "utf-8");
|
|
930
|
+
} catch {
|
|
931
|
+
throw new Error(`E018: '${kind}' file '${text}' referenced in agent.behavior not found in ${dir}`);
|
|
932
|
+
}
|
|
933
|
+
files.set(`${kind === "guide" ? "guides" : "knowledge"}/${text}`, content);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
835
936
|
return files;
|
|
836
937
|
}
|
|
938
|
+
function withAgentExtension(path) {
|
|
939
|
+
return path.endsWith(".agent") ? path : `${path}.agent`;
|
|
940
|
+
}
|
|
837
941
|
async function pack(options = {}) {
|
|
838
942
|
const dir = options.dir ?? process.cwd();
|
|
839
|
-
const outPath = options.out ?? join(dir,
|
|
943
|
+
const outPath = withAgentExtension(options.out ?? join(dir, basename(dir)));
|
|
840
944
|
const descriptionFileName = await discoverDescriptionFile(dir, options.description);
|
|
841
945
|
const descriptionText = await readFile2(join(dir, descriptionFileName), "utf-8");
|
|
842
946
|
const descriptionMessages = await lintDescription(descriptionText, descriptionFileName);
|
|
@@ -871,13 +975,13 @@ ${descErrors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`)
|
|
|
871
975
|
${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
|
|
872
976
|
);
|
|
873
977
|
}
|
|
874
|
-
const version = await
|
|
978
|
+
const version = await resolveVersionInteractive(options.version);
|
|
875
979
|
const commit = await resolveCommit(options.commit);
|
|
876
|
-
const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
|
|
980
|
+
const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources, df.persona ?? void 0);
|
|
877
981
|
const contentForHash = Array.from(allFiles.values()).join("");
|
|
878
982
|
const sha256 = createHash("sha256").update(contentForHash).digest("hex");
|
|
879
983
|
const namespace = df.agent.domain ?? "unknown";
|
|
880
|
-
const id = buildId({ namespace, name: df.agent.name, version, digest: commit });
|
|
984
|
+
const id = buildId({ namespace, name: slugify(df.agent.name), version, digest: version ? commit : void 0 });
|
|
881
985
|
const typesJson = buildTypesJson(df);
|
|
882
986
|
const integrity = {
|
|
883
987
|
sha256,
|
|
@@ -888,10 +992,10 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
|
|
|
888
992
|
id,
|
|
889
993
|
name: df.agent.name,
|
|
890
994
|
description: df.description ?? "",
|
|
891
|
-
version,
|
|
995
|
+
version: version ?? "",
|
|
892
996
|
domain: df.agent.domain ?? "",
|
|
893
997
|
license: df.agent.license ?? "",
|
|
894
|
-
persona: df.persona ??
|
|
998
|
+
persona: df.persona ?? void 0,
|
|
895
999
|
purpose: "unknown",
|
|
896
1000
|
compiler: `dot-agent/${COMPILER_VERSION}`,
|
|
897
1001
|
commit,
|
|
@@ -909,6 +1013,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
|
|
|
909
1013
|
const filesJson = {
|
|
910
1014
|
description: descriptionFileName,
|
|
911
1015
|
behavior: "agent.behavior",
|
|
1016
|
+
...df.persona ? { persona: df.persona } : {},
|
|
912
1017
|
behaviors: Array.from(allFiles.keys()).filter((f) => f.startsWith("behaviors/")),
|
|
913
1018
|
guides: Array.from(allFiles.keys()).filter((f) => f.startsWith("guides/") && !gitkeepPaths.has(f)),
|
|
914
1019
|
knowledge: Array.from(allFiles.keys()).filter((f) => f.startsWith("knowledge/") && !gitkeepPaths.has(f))
|
|
@@ -962,9 +1067,9 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
|
|
|
962
1067
|
process.stderr.write(`\x1B[33m\u26A0\x1B[0m ${w.file}:${w.line}:${w.col} ${w.code} ${w.message}
|
|
963
1068
|
`);
|
|
964
1069
|
}
|
|
965
|
-
const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
|
|
1070
|
+
const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources, df.persona ?? void 0);
|
|
966
1071
|
const sha256 = createHash2("sha256").update(Array.from(allFiles.values()).join("")).digest("hex");
|
|
967
|
-
const id = buildId({ namespace: df.agent.domain ?? "
|
|
1072
|
+
const id = buildId({ namespace: df.agent.domain ?? "unknown", name: slugify(df.agent.name), version: "dev" });
|
|
968
1073
|
const aboutme = buildAboutme({
|
|
969
1074
|
id,
|
|
970
1075
|
name: df.agent.name,
|
|
@@ -972,7 +1077,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
|
|
|
972
1077
|
version: "dev",
|
|
973
1078
|
domain: df.agent.domain ?? "",
|
|
974
1079
|
license: df.agent.license ?? "",
|
|
975
|
-
persona: df.persona ??
|
|
1080
|
+
persona: df.persona ?? void 0,
|
|
976
1081
|
purpose: "development",
|
|
977
1082
|
compiler: `dot-agent/${COMPILER_VERSION}`,
|
|
978
1083
|
capabilities: df.capabilities.map((c) => ({ id: c.name, description: c.description ?? "" })),
|
|
@@ -985,7 +1090,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
|
|
|
985
1090
|
// mergedText — it has redundant `merge "..."` lines stripped (see
|
|
986
1091
|
// collectFiles() for why they're dead weight once flattened).
|
|
987
1092
|
behavior: allFiles.get("agent.behavior") ?? mergedText,
|
|
988
|
-
|
|
1093
|
+
persona: df.persona ? allFiles.get(df.persona) : void 0,
|
|
989
1094
|
guides: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("guides/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
|
|
990
1095
|
knowledge: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("knowledge/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
|
|
991
1096
|
behaviors: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("behaviors/")).map(([path, content]) => ({ path, content }))
|