@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.
@@ -1,6 +1,6 @@
1
1
  // src/generated-version.ts
2
- var DSL_VERSION = "0.1-alpha";
3
- var COMPILER_VERSION = "0.5.0-alpha.2";
2
+ var DSL_VERSION = "0.1";
3
+ var COMPILER_VERSION = "0.10.0";
4
4
 
5
5
  // src/manifest.ts
6
6
  function parseAboutme(json) {
@@ -8,9 +8,7 @@ function parseAboutme(json) {
8
8
  if (!json.id) throw new Error("Missing id in aboutme.json");
9
9
  if (!json.name) throw new Error("Missing name in aboutme.json");
10
10
  if (!json.description) throw new Error("Missing description in aboutme.json");
11
- if (!json.version) throw new Error("Missing version in aboutme.json");
12
11
  if (!json.domain) throw new Error("Missing domain in aboutme.json");
13
- if (!json.persona) throw new Error("Missing persona in aboutme.json");
14
12
  if (!json.compiler) throw new Error("Missing compiler in aboutme.json");
15
13
  if (!Array.isArray(json.capabilities)) throw new Error("Missing capabilities array in aboutme.json");
16
14
  if (!Array.isArray(json.requires)) throw new Error("Missing requires array in aboutme.json");
@@ -20,7 +18,7 @@ function parseAboutme(json) {
20
18
  id: json.id,
21
19
  name: json.name,
22
20
  description: json.description,
23
- version: json.version,
21
+ version: json.version ?? "",
24
22
  domain: json.domain,
25
23
  license: json.license ?? "",
26
24
  persona: json.persona,
@@ -132,7 +130,14 @@ function buildId(parts) {
132
130
  result += `:${version}`;
133
131
  if (digest) result += `~${digest}`;
134
132
  }
135
- return result;
133
+ return result.toLowerCase();
134
+ }
135
+ function slugify(name) {
136
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
137
+ }
138
+ var VERSION_RE = /^v?\d+(\.\d+){0,2}(-[0-9A-Za-z.]+)?(\+[0-9A-Za-z.]+)?$/i;
139
+ function isValidVersion(version) {
140
+ return VERSION_RE.test(version);
136
141
  }
137
142
  function extractDigest(id) {
138
143
  try {
@@ -196,6 +201,8 @@ export {
196
201
  aboutmeToJson,
197
202
  parseId,
198
203
  buildId,
204
+ slugify,
205
+ isValidVersion,
199
206
  extractDigest,
200
207
  extractName,
201
208
  validateMagicBytes,
@@ -203,4 +210,4 @@ export {
203
210
  createZip,
204
211
  extractFiles
205
212
  };
206
- //# sourceMappingURL=chunk-P5LFGJ6P.js.map
213
+ //# sourceMappingURL=chunk-AYXHOOUX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generated-version.ts","../src/manifest.ts","../src/id.ts","../src/zip-core.ts"],"sourcesContent":["// Generated by scripts/embed-version.mjs from dsl/VERSION and package.json — do not edit by hand.\nexport const DSL_VERSION = '0.1'\nexport const COMPILER_VERSION = '0.10.0'\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n\nimport type { AboutMe, BuildAboutmeOptions } from './types.js'\nimport { DSL_VERSION } from './generated-version.js'\n\nexport function parseAboutme(json: any): AboutMe {\n if (!json.dslVersion) throw new Error('Missing dslVersion in aboutme.json')\n if (!json.id) throw new Error('Missing id in aboutme.json')\n if (!json.name) throw new Error('Missing name in aboutme.json')\n if (!json.description) throw new Error('Missing description in aboutme.json')\n if (!json.domain) throw new Error('Missing domain in aboutme.json')\n if (!json.compiler) throw new Error('Missing compiler in aboutme.json')\n if (!Array.isArray(json.capabilities)) throw new Error('Missing capabilities array in aboutme.json')\n if (!Array.isArray(json.requires)) throw new Error('Missing requires array in aboutme.json')\n if (!json.integrity) throw new Error('Missing integrity in aboutme.json')\n\n return {\n dslVersion: json.dslVersion,\n id: json.id,\n name: json.name,\n description: json.description,\n version: json.version ?? '',\n domain: json.domain,\n license: json.license ?? '',\n persona: json.persona,\n purpose: json.purpose ?? 'unknown',\n compiler: json.compiler,\n commit: json.commit,\n capabilities: json.capabilities,\n requires: json.requires,\n integrity: json.integrity,\n }\n}\n\nexport function buildAboutme(opts: BuildAboutmeOptions): AboutMe {\n return {\n dslVersion: `dot-agent/${DSL_VERSION}`,\n id: opts.id,\n name: opts.name,\n description: opts.description,\n version: opts.version,\n domain: opts.domain,\n license: opts.license ?? '',\n persona: opts.persona,\n purpose: opts.purpose ?? 'unknown',\n compiler: opts.compiler,\n commit: opts.commit,\n capabilities: opts.capabilities ?? [],\n requires: opts.requires ?? [],\n integrity: opts.integrity,\n }\n}\n\nexport function aboutmeToJson(aboutme: AboutMe): string {\n return JSON.stringify(aboutme, null, 2)\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { IdParts } from './types.js'\n\n// Code hosting platforms whose namespace format is platform/user rather than plain domain.\n// The list is maintained by the compiler and updated via CLI releases.\nexport const KNOWN_PLATFORMS = ['github.com', 'gitlab.com', 'codeberg.org', 'sr.ht'] as const\n\nfunction parseNamespaceName(identifier: string): { namespace: string; name: string } {\n // Email namespace: @ appears before any /\n const atIdx = identifier.indexOf('@')\n if (atIdx !== -1 && (identifier.indexOf('/') === -1 || atIdx < identifier.indexOf('/'))) {\n const slashIdx = identifier.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(`Invalid agent ID: email namespace requires a name after '/' (got '${identifier}')`)\n }\n return {\n namespace: identifier.slice(0, slashIdx),\n name: identifier.slice(slashIdx + 1),\n }\n }\n\n // Known code-hosting platforms: namespace is platform/user, name is the next segment.\n for (const platform of KNOWN_PLATFORMS) {\n if (identifier.startsWith(platform + '/')) {\n const afterPlatform = identifier.slice(platform.length + 1)\n const slashIdx = afterPlatform.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(\n `Invalid agent ID: '${platform}' namespace requires a user segment and a name (got '${identifier}')`,\n )\n }\n return {\n namespace: platform + '/' + afterPlatform.slice(0, slashIdx),\n name: afterPlatform.slice(slashIdx + 1),\n }\n }\n }\n\n // Domain or reserved keyword (e.g. 'unknown'): last '/' separates namespace from name.\n const lastSlash = identifier.lastIndexOf('/')\n if (lastSlash === -1) {\n throw new Error(`Invalid agent ID: missing '/' separator in '${identifier}'`)\n }\n return {\n namespace: identifier.slice(0, lastSlash),\n name: identifier.slice(lastSlash + 1),\n }\n}\n\nexport function parseId(id: string): IdParts {\n if (!id) throw new Error('Invalid agent ID: empty string')\n\n // Phase 1: split on the first ':' to isolate the identifier from version~digest.\n const colonIdx = id.indexOf(':')\n\n let identifier: string\n let version: string | undefined\n let digest: string | undefined\n\n if (colonIdx === -1) {\n // Form A: namespace/name\n identifier = id\n } else {\n identifier = id.slice(0, colonIdx)\n const rest = id.slice(colonIdx + 1)\n if (!rest) throw new Error(`Invalid agent ID: empty version after ':' in '${id}'`)\n\n // Phase 2: split version~digest\n const tildeIdx = rest.indexOf('~')\n if (tildeIdx === -1) {\n // Form B: namespace/name:version\n version = rest\n } else {\n // Form D: namespace/name:version~digest\n version = rest.slice(0, tildeIdx)\n digest = rest.slice(tildeIdx + 1)\n if (!version) throw new Error(`Invalid agent ID: empty version before '~' in '${id}'`)\n if (!digest) throw new Error(`Invalid agent ID: empty digest after '~' in '${id}'`)\n }\n }\n\n // Phase 3: extract namespace and name from the identifier\n const { namespace, name } = parseNamespaceName(identifier)\n\n if (!namespace) throw new Error(`Invalid agent ID: empty namespace in '${id}'`)\n if (!name) throw new Error(`Invalid agent ID: empty name in '${id}'`)\n\n return { namespace, name, version, digest }\n}\n\nexport function buildId(parts: IdParts): string {\n const { namespace, name, version, digest } = parts\n if (!namespace || !name) {\n throw new Error('Missing required ID parts: namespace and name')\n }\n if (digest && !version) {\n throw new Error('Invalid ID parts: digest requires version')\n }\n let result = `${namespace}/${name}`\n if (version) {\n result += `:${version}`\n if (digest) result += `~${digest}`\n }\n // Ids are always lowercase — domains, platform usernames (GitHub/GitLab/\n // Codeberg/Sourcehut) and email local-parts are all case-insensitive in\n // practice, so normalizing here is safe and gives every id a single shape.\n return result.toLowerCase()\n}\n\n// Turns a human display name (e.g. \"Fridge Assistant\", from `agent Fridge\n// Assistant` in the DSL — spaces/capitalization are deliberate there) into\n// the kebab-case slug used for an id's name segment.\nexport function slugify(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\n// Accepts optional leading 'v' (id spec examples use it; monorepo tags after\n// their '@' split don't), 1-3 dot-separated numeric groups, and optional\n// -prerelease / +build suffixes — e.g. v1.0, 2.3.1, v1.0.0-alpha.1, 1.0+build.\nconst VERSION_RE = /^v?\\d+(\\.\\d+){0,2}(-[0-9A-Za-z.]+)?(\\+[0-9A-Za-z.]+)?$/i\n\nexport function isValidVersion(version: string): boolean {\n return VERSION_RE.test(version)\n}\n\nexport function extractDigest(id: string): string {\n try {\n return parseId(id).digest ?? ''\n } catch {\n return ''\n }\n}\n\nexport function extractName(id: string): string {\n try {\n return parseId(id).name\n } catch {\n return ''\n }\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport JSZip from 'jszip'\n\nexport const MAX_ZIP_SIZE = 500 * 1024 * 1024\nexport const MAX_COMPRESSION_RATIO = 100\n\nexport function validateMagicBytes(bytes: Uint8Array): void {\n if (!(bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04)) {\n throw new Error('Not a valid .agent file (invalid magic bytes)')\n }\n}\n\nexport function validateZipBomb(zip: JSZip, compressedSize: number): void {\n let totalUncompressed = 0\n zip.forEach((_path, file) => {\n if (!file.dir) totalUncompressed += (file as any)._data?.uncompressedSize || 0\n })\n if (totalUncompressed > MAX_ZIP_SIZE) {\n throw new Error(`Bundle exceeds 500MB uncompressed: ${totalUncompressed}`)\n }\n if (totalUncompressed / compressedSize > MAX_COMPRESSION_RATIO) {\n throw new Error(`Compression ratio exceeds 100x: ${(totalUncompressed / compressedSize).toFixed(1)}x`)\n }\n}\n\nexport function createZip(): JSZip {\n return new JSZip()\n}\n\nexport async function extractFiles(zip: JSZip, filter?: string[]): Promise<Map<string, string>> {\n const files = new Map<string, string>()\n const promises: Promise<void>[] = []\n\n zip.forEach((relativePath, file) => {\n if (file.dir) return\n if (filter && !filter.some(f => relativePath.startsWith(f))) return\n promises.push(\n file.async('text').then(content => {\n files.set(relativePath, content)\n })\n )\n })\n\n await Promise.all(promises)\n return files\n}\n"],"mappings":"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","names":[]}
@@ -45,7 +45,7 @@ interface AboutMe {
45
45
  version: string;
46
46
  domain: string;
47
47
  license: string;
48
- persona: string;
48
+ persona?: string;
49
49
  purpose: string;
50
50
  compiler: string;
51
51
  commit?: string;
@@ -56,7 +56,7 @@ interface AboutMe {
56
56
  interface AgentFiles {
57
57
  description: string;
58
58
  behavior: string;
59
- soul?: string;
59
+ persona?: string;
60
60
  guides: Array<{
61
61
  path: string;
62
62
  content: string;
@@ -94,7 +94,7 @@ interface BuildAboutmeOptions {
94
94
  version: string;
95
95
  domain: string;
96
96
  license?: string;
97
- persona: string;
97
+ persona?: string;
98
98
  purpose?: string;
99
99
  compiler: string;
100
100
  commit?: string;
@@ -45,7 +45,7 @@ interface AboutMe {
45
45
  version: string;
46
46
  domain: string;
47
47
  license: string;
48
- persona: string;
48
+ persona?: string;
49
49
  purpose: string;
50
50
  compiler: string;
51
51
  commit?: string;
@@ -56,7 +56,7 @@ interface AboutMe {
56
56
  interface AgentFiles {
57
57
  description: string;
58
58
  behavior: string;
59
- soul?: string;
59
+ persona?: string;
60
60
  guides: Array<{
61
61
  path: string;
62
62
  content: string;
@@ -94,7 +94,7 @@ interface BuildAboutmeOptions {
94
94
  version: string;
95
95
  domain: string;
96
96
  license?: string;
97
- persona: string;
97
+ persona?: string;
98
98
  purpose?: string;
99
99
  compiler: string;
100
100
  commit?: string;
package/dist/core.cjs CHANGED
@@ -45,7 +45,7 @@ __export(core_exports, {
45
45
  module.exports = __toCommonJS(core_exports);
46
46
 
47
47
  // src/generated-version.ts
48
- var DSL_VERSION = "0.1-alpha";
48
+ var DSL_VERSION = "0.1";
49
49
 
50
50
  // src/manifest.ts
51
51
  function parseAboutme(json) {
@@ -53,9 +53,7 @@ function parseAboutme(json) {
53
53
  if (!json.id) throw new Error("Missing id in aboutme.json");
54
54
  if (!json.name) throw new Error("Missing name in aboutme.json");
55
55
  if (!json.description) throw new Error("Missing description in aboutme.json");
56
- if (!json.version) throw new Error("Missing version in aboutme.json");
57
56
  if (!json.domain) throw new Error("Missing domain in aboutme.json");
58
- if (!json.persona) throw new Error("Missing persona in aboutme.json");
59
57
  if (!json.compiler) throw new Error("Missing compiler in aboutme.json");
60
58
  if (!Array.isArray(json.capabilities)) throw new Error("Missing capabilities array in aboutme.json");
61
59
  if (!Array.isArray(json.requires)) throw new Error("Missing requires array in aboutme.json");
@@ -65,7 +63,7 @@ function parseAboutme(json) {
65
63
  id: json.id,
66
64
  name: json.name,
67
65
  description: json.description,
68
- version: json.version,
66
+ version: json.version ?? "",
69
67
  domain: json.domain,
70
68
  license: json.license ?? "",
71
69
  persona: json.persona,
@@ -177,7 +175,7 @@ function buildId(parts) {
177
175
  result += `:${version}`;
178
176
  if (digest) result += `~${digest}`;
179
177
  }
180
- return result;
178
+ return result.toLowerCase();
181
179
  }
182
180
  function extractDigest(id) {
183
181
  try {
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/generated-version.ts","../src/manifest.ts","../src/id.ts","../src/zip-core.ts"],"sourcesContent":["// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Browser-safe sub-path export — no Node.js dependencies.\n// Import via: import { ... } from '@dot-agent/compiler/core'\n\nexport { parseAboutme, buildAboutme, aboutmeToJson } from './manifest.js'\nexport { parseId, buildId, extractDigest, extractName } from './id.js'\nexport { createZip, extractFiles, validateMagicBytes, validateZipBomb } from './zip-core.js'\n\nexport type {\n AboutMe,\n AgentBundle,\n AgentFiles,\n Capability,\n AnnotatedRef,\n DescriptionFile,\n Integrity,\n BuildAboutmeOptions,\n IdParts,\n LintMessage,\n} from './types.js'\n","// Generated by scripts/embed-version.mjs from dsl/VERSION and package.json — do not edit by hand.\nexport const DSL_VERSION = '0.1-alpha'\nexport const COMPILER_VERSION = '0.5.0-alpha.2'\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n\nimport type { AboutMe, BuildAboutmeOptions } from './types.js'\nimport { DSL_VERSION } from './generated-version.js'\n\nexport function parseAboutme(json: any): AboutMe {\n if (!json.dslVersion) throw new Error('Missing dslVersion in aboutme.json')\n if (!json.id) throw new Error('Missing id in aboutme.json')\n if (!json.name) throw new Error('Missing name in aboutme.json')\n if (!json.description) throw new Error('Missing description in aboutme.json')\n if (!json.version) throw new Error('Missing version in aboutme.json')\n if (!json.domain) throw new Error('Missing domain in aboutme.json')\n if (!json.persona) throw new Error('Missing persona in aboutme.json')\n if (!json.compiler) throw new Error('Missing compiler in aboutme.json')\n if (!Array.isArray(json.capabilities)) throw new Error('Missing capabilities array in aboutme.json')\n if (!Array.isArray(json.requires)) throw new Error('Missing requires array in aboutme.json')\n if (!json.integrity) throw new Error('Missing integrity in aboutme.json')\n\n return {\n dslVersion: json.dslVersion,\n id: json.id,\n name: json.name,\n description: json.description,\n version: json.version,\n domain: json.domain,\n license: json.license ?? '',\n persona: json.persona,\n purpose: json.purpose ?? 'unknown',\n compiler: json.compiler,\n commit: json.commit,\n capabilities: json.capabilities,\n requires: json.requires,\n integrity: json.integrity,\n }\n}\n\nexport function buildAboutme(opts: BuildAboutmeOptions): AboutMe {\n return {\n dslVersion: `dot-agent/${DSL_VERSION}`,\n id: opts.id,\n name: opts.name,\n description: opts.description,\n version: opts.version,\n domain: opts.domain,\n license: opts.license ?? '',\n persona: opts.persona,\n purpose: opts.purpose ?? 'unknown',\n compiler: opts.compiler,\n commit: opts.commit,\n capabilities: opts.capabilities ?? [],\n requires: opts.requires ?? [],\n integrity: opts.integrity,\n }\n}\n\nexport function aboutmeToJson(aboutme: AboutMe): string {\n return JSON.stringify(aboutme, null, 2)\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { IdParts } from './types.js'\n\n// Code hosting platforms whose namespace format is platform/user rather than plain domain.\n// The list is maintained by the compiler and updated via CLI releases.\nexport const KNOWN_PLATFORMS = ['github.com', 'gitlab.com', 'codeberg.org', 'sr.ht'] as const\n\nfunction parseNamespaceName(identifier: string): { namespace: string; name: string } {\n // Email namespace: @ appears before any /\n const atIdx = identifier.indexOf('@')\n if (atIdx !== -1 && (identifier.indexOf('/') === -1 || atIdx < identifier.indexOf('/'))) {\n const slashIdx = identifier.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(`Invalid agent ID: email namespace requires a name after '/' (got '${identifier}')`)\n }\n return {\n namespace: identifier.slice(0, slashIdx),\n name: identifier.slice(slashIdx + 1),\n }\n }\n\n // Known code-hosting platforms: namespace is platform/user, name is the next segment.\n for (const platform of KNOWN_PLATFORMS) {\n if (identifier.startsWith(platform + '/')) {\n const afterPlatform = identifier.slice(platform.length + 1)\n const slashIdx = afterPlatform.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(\n `Invalid agent ID: '${platform}' namespace requires a user segment and a name (got '${identifier}')`,\n )\n }\n return {\n namespace: platform + '/' + afterPlatform.slice(0, slashIdx),\n name: afterPlatform.slice(slashIdx + 1),\n }\n }\n }\n\n // Domain or reserved keyword (e.g. 'unknown'): last '/' separates namespace from name.\n const lastSlash = identifier.lastIndexOf('/')\n if (lastSlash === -1) {\n throw new Error(`Invalid agent ID: missing '/' separator in '${identifier}'`)\n }\n return {\n namespace: identifier.slice(0, lastSlash),\n name: identifier.slice(lastSlash + 1),\n }\n}\n\nexport function parseId(id: string): IdParts {\n if (!id) throw new Error('Invalid agent ID: empty string')\n\n // Phase 1: split on the first ':' to isolate the identifier from version~digest.\n const colonIdx = id.indexOf(':')\n\n let identifier: string\n let version: string | undefined\n let digest: string | undefined\n\n if (colonIdx === -1) {\n // Form A: namespace/name\n identifier = id\n } else {\n identifier = id.slice(0, colonIdx)\n const rest = id.slice(colonIdx + 1)\n if (!rest) throw new Error(`Invalid agent ID: empty version after ':' in '${id}'`)\n\n // Phase 2: split version~digest\n const tildeIdx = rest.indexOf('~')\n if (tildeIdx === -1) {\n // Form B: namespace/name:version\n version = rest\n } else {\n // Form D: namespace/name:version~digest\n version = rest.slice(0, tildeIdx)\n digest = rest.slice(tildeIdx + 1)\n if (!version) throw new Error(`Invalid agent ID: empty version before '~' in '${id}'`)\n if (!digest) throw new Error(`Invalid agent ID: empty digest after '~' in '${id}'`)\n }\n }\n\n // Phase 3: extract namespace and name from the identifier\n const { namespace, name } = parseNamespaceName(identifier)\n\n if (!namespace) throw new Error(`Invalid agent ID: empty namespace in '${id}'`)\n if (!name) throw new Error(`Invalid agent ID: empty name in '${id}'`)\n\n return { namespace, name, version, digest }\n}\n\nexport function buildId(parts: IdParts): string {\n const { namespace, name, version, digest } = parts\n if (!namespace || !name) {\n throw new Error('Missing required ID parts: namespace and name')\n }\n if (digest && !version) {\n throw new Error('Invalid ID parts: digest requires version')\n }\n let result = `${namespace}/${name}`\n if (version) {\n result += `:${version}`\n if (digest) result += `~${digest}`\n }\n return result\n}\n\nexport function extractDigest(id: string): string {\n try {\n return parseId(id).digest ?? ''\n } catch {\n return ''\n }\n}\n\nexport function extractName(id: string): string {\n try {\n return parseId(id).name\n } catch {\n return ''\n }\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport JSZip from 'jszip'\n\nexport const MAX_ZIP_SIZE = 500 * 1024 * 1024\nexport const MAX_COMPRESSION_RATIO = 100\n\nexport function validateMagicBytes(bytes: Uint8Array): void {\n if (!(bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04)) {\n throw new Error('Not a valid .agent file (invalid magic bytes)')\n }\n}\n\nexport function validateZipBomb(zip: JSZip, compressedSize: number): void {\n let totalUncompressed = 0\n zip.forEach((_path, file) => {\n if (!file.dir) totalUncompressed += (file as any)._data?.uncompressedSize || 0\n })\n if (totalUncompressed > MAX_ZIP_SIZE) {\n throw new Error(`Bundle exceeds 500MB uncompressed: ${totalUncompressed}`)\n }\n if (totalUncompressed / compressedSize > MAX_COMPRESSION_RATIO) {\n throw new Error(`Compression ratio exceeds 100x: ${(totalUncompressed / compressedSize).toFixed(1)}x`)\n }\n}\n\nexport function createZip(): JSZip {\n return new JSZip()\n}\n\nexport async function extractFiles(zip: JSZip, filter?: string[]): Promise<Map<string, string>> {\n const files = new Map<string, string>()\n const promises: Promise<void>[] = []\n\n zip.forEach((relativePath, file) => {\n if (file.dir) return\n if (filter && !filter.some(f => relativePath.startsWith(f))) return\n promises.push(\n file.async('text').then(content => {\n files.set(relativePath, content)\n })\n )\n })\n\n await Promise.all(promises)\n return files\n}\n"],"mappings":"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","names":["JSZip"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/generated-version.ts","../src/manifest.ts","../src/id.ts","../src/zip-core.ts"],"sourcesContent":["// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Browser-safe sub-path export — no Node.js dependencies.\n// Import via: import { ... } from '@dot-agent/compiler/core'\n\nexport { parseAboutme, buildAboutme, aboutmeToJson } from './manifest.js'\nexport { parseId, buildId, extractDigest, extractName } from './id.js'\nexport { createZip, extractFiles, validateMagicBytes, validateZipBomb } from './zip-core.js'\n\nexport type {\n AboutMe,\n AgentBundle,\n AgentFiles,\n Capability,\n AnnotatedRef,\n DescriptionFile,\n Integrity,\n BuildAboutmeOptions,\n IdParts,\n LintMessage,\n} from './types.js'\n","// Generated by scripts/embed-version.mjs from dsl/VERSION and package.json — do not edit by hand.\nexport const DSL_VERSION = '0.1'\nexport const COMPILER_VERSION = '0.10.0'\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n\nimport type { AboutMe, BuildAboutmeOptions } from './types.js'\nimport { DSL_VERSION } from './generated-version.js'\n\nexport function parseAboutme(json: any): AboutMe {\n if (!json.dslVersion) throw new Error('Missing dslVersion in aboutme.json')\n if (!json.id) throw new Error('Missing id in aboutme.json')\n if (!json.name) throw new Error('Missing name in aboutme.json')\n if (!json.description) throw new Error('Missing description in aboutme.json')\n if (!json.domain) throw new Error('Missing domain in aboutme.json')\n if (!json.compiler) throw new Error('Missing compiler in aboutme.json')\n if (!Array.isArray(json.capabilities)) throw new Error('Missing capabilities array in aboutme.json')\n if (!Array.isArray(json.requires)) throw new Error('Missing requires array in aboutme.json')\n if (!json.integrity) throw new Error('Missing integrity in aboutme.json')\n\n return {\n dslVersion: json.dslVersion,\n id: json.id,\n name: json.name,\n description: json.description,\n version: json.version ?? '',\n domain: json.domain,\n license: json.license ?? '',\n persona: json.persona,\n purpose: json.purpose ?? 'unknown',\n compiler: json.compiler,\n commit: json.commit,\n capabilities: json.capabilities,\n requires: json.requires,\n integrity: json.integrity,\n }\n}\n\nexport function buildAboutme(opts: BuildAboutmeOptions): AboutMe {\n return {\n dslVersion: `dot-agent/${DSL_VERSION}`,\n id: opts.id,\n name: opts.name,\n description: opts.description,\n version: opts.version,\n domain: opts.domain,\n license: opts.license ?? '',\n persona: opts.persona,\n purpose: opts.purpose ?? 'unknown',\n compiler: opts.compiler,\n commit: opts.commit,\n capabilities: opts.capabilities ?? [],\n requires: opts.requires ?? [],\n integrity: opts.integrity,\n }\n}\n\nexport function aboutmeToJson(aboutme: AboutMe): string {\n return JSON.stringify(aboutme, null, 2)\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { IdParts } from './types.js'\n\n// Code hosting platforms whose namespace format is platform/user rather than plain domain.\n// The list is maintained by the compiler and updated via CLI releases.\nexport const KNOWN_PLATFORMS = ['github.com', 'gitlab.com', 'codeberg.org', 'sr.ht'] as const\n\nfunction parseNamespaceName(identifier: string): { namespace: string; name: string } {\n // Email namespace: @ appears before any /\n const atIdx = identifier.indexOf('@')\n if (atIdx !== -1 && (identifier.indexOf('/') === -1 || atIdx < identifier.indexOf('/'))) {\n const slashIdx = identifier.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(`Invalid agent ID: email namespace requires a name after '/' (got '${identifier}')`)\n }\n return {\n namespace: identifier.slice(0, slashIdx),\n name: identifier.slice(slashIdx + 1),\n }\n }\n\n // Known code-hosting platforms: namespace is platform/user, name is the next segment.\n for (const platform of KNOWN_PLATFORMS) {\n if (identifier.startsWith(platform + '/')) {\n const afterPlatform = identifier.slice(platform.length + 1)\n const slashIdx = afterPlatform.indexOf('/')\n if (slashIdx === -1) {\n throw new Error(\n `Invalid agent ID: '${platform}' namespace requires a user segment and a name (got '${identifier}')`,\n )\n }\n return {\n namespace: platform + '/' + afterPlatform.slice(0, slashIdx),\n name: afterPlatform.slice(slashIdx + 1),\n }\n }\n }\n\n // Domain or reserved keyword (e.g. 'unknown'): last '/' separates namespace from name.\n const lastSlash = identifier.lastIndexOf('/')\n if (lastSlash === -1) {\n throw new Error(`Invalid agent ID: missing '/' separator in '${identifier}'`)\n }\n return {\n namespace: identifier.slice(0, lastSlash),\n name: identifier.slice(lastSlash + 1),\n }\n}\n\nexport function parseId(id: string): IdParts {\n if (!id) throw new Error('Invalid agent ID: empty string')\n\n // Phase 1: split on the first ':' to isolate the identifier from version~digest.\n const colonIdx = id.indexOf(':')\n\n let identifier: string\n let version: string | undefined\n let digest: string | undefined\n\n if (colonIdx === -1) {\n // Form A: namespace/name\n identifier = id\n } else {\n identifier = id.slice(0, colonIdx)\n const rest = id.slice(colonIdx + 1)\n if (!rest) throw new Error(`Invalid agent ID: empty version after ':' in '${id}'`)\n\n // Phase 2: split version~digest\n const tildeIdx = rest.indexOf('~')\n if (tildeIdx === -1) {\n // Form B: namespace/name:version\n version = rest\n } else {\n // Form D: namespace/name:version~digest\n version = rest.slice(0, tildeIdx)\n digest = rest.slice(tildeIdx + 1)\n if (!version) throw new Error(`Invalid agent ID: empty version before '~' in '${id}'`)\n if (!digest) throw new Error(`Invalid agent ID: empty digest after '~' in '${id}'`)\n }\n }\n\n // Phase 3: extract namespace and name from the identifier\n const { namespace, name } = parseNamespaceName(identifier)\n\n if (!namespace) throw new Error(`Invalid agent ID: empty namespace in '${id}'`)\n if (!name) throw new Error(`Invalid agent ID: empty name in '${id}'`)\n\n return { namespace, name, version, digest }\n}\n\nexport function buildId(parts: IdParts): string {\n const { namespace, name, version, digest } = parts\n if (!namespace || !name) {\n throw new Error('Missing required ID parts: namespace and name')\n }\n if (digest && !version) {\n throw new Error('Invalid ID parts: digest requires version')\n }\n let result = `${namespace}/${name}`\n if (version) {\n result += `:${version}`\n if (digest) result += `~${digest}`\n }\n // Ids are always lowercase — domains, platform usernames (GitHub/GitLab/\n // Codeberg/Sourcehut) and email local-parts are all case-insensitive in\n // practice, so normalizing here is safe and gives every id a single shape.\n return result.toLowerCase()\n}\n\n// Turns a human display name (e.g. \"Fridge Assistant\", from `agent Fridge\n// Assistant` in the DSL — spaces/capitalization are deliberate there) into\n// the kebab-case slug used for an id's name segment.\nexport function slugify(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\n// Accepts optional leading 'v' (id spec examples use it; monorepo tags after\n// their '@' split don't), 1-3 dot-separated numeric groups, and optional\n// -prerelease / +build suffixes — e.g. v1.0, 2.3.1, v1.0.0-alpha.1, 1.0+build.\nconst VERSION_RE = /^v?\\d+(\\.\\d+){0,2}(-[0-9A-Za-z.]+)?(\\+[0-9A-Za-z.]+)?$/i\n\nexport function isValidVersion(version: string): boolean {\n return VERSION_RE.test(version)\n}\n\nexport function extractDigest(id: string): string {\n try {\n return parseId(id).digest ?? ''\n } catch {\n return ''\n }\n}\n\nexport function extractName(id: string): string {\n try {\n return parseId(id).name\n } catch {\n return ''\n }\n}\n","// Copyright 2026 Danilo Borges\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport JSZip from 'jszip'\n\nexport const MAX_ZIP_SIZE = 500 * 1024 * 1024\nexport const MAX_COMPRESSION_RATIO = 100\n\nexport function validateMagicBytes(bytes: Uint8Array): void {\n if (!(bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04)) {\n throw new Error('Not a valid .agent file (invalid magic bytes)')\n }\n}\n\nexport function validateZipBomb(zip: JSZip, compressedSize: number): void {\n let totalUncompressed = 0\n zip.forEach((_path, file) => {\n if (!file.dir) totalUncompressed += (file as any)._data?.uncompressedSize || 0\n })\n if (totalUncompressed > MAX_ZIP_SIZE) {\n throw new Error(`Bundle exceeds 500MB uncompressed: ${totalUncompressed}`)\n }\n if (totalUncompressed / compressedSize > MAX_COMPRESSION_RATIO) {\n throw new Error(`Compression ratio exceeds 100x: ${(totalUncompressed / compressedSize).toFixed(1)}x`)\n }\n}\n\nexport function createZip(): JSZip {\n return new JSZip()\n}\n\nexport async function extractFiles(zip: JSZip, filter?: string[]): Promise<Map<string, string>> {\n const files = new Map<string, string>()\n const promises: Promise<void>[] = []\n\n zip.forEach((relativePath, file) => {\n if (file.dir) return\n if (filter && !filter.some(f => relativePath.startsWith(f))) return\n promises.push(\n file.async('text').then(content => {\n files.set(relativePath, content)\n })\n )\n })\n\n await Promise.all(promises)\n return files\n}\n"],"mappings":"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","names":["JSZip"]}
package/dist/core.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- export { d as AboutMe, A as AgentBundle, e as AgentFiles, B as BuildAboutmeOptions, C as Capability, I as IdParts, f as Integrity, a as LintMessage, g as aboutmeToJson, h as buildAboutme, i as buildId, j as createZip, k as extractDigest, l as extractFiles, m as extractName, p as parseAboutme, n as parseId, v as validateMagicBytes, o as validateZipBomb } from './core-b-7c6X6q.cjs';
1
+ export { d as AboutMe, A as AgentBundle, e as AgentFiles, B as BuildAboutmeOptions, C as Capability, I as IdParts, f as Integrity, a as LintMessage, g as aboutmeToJson, h as buildAboutme, i as buildId, j as createZip, k as extractDigest, l as extractFiles, m as extractName, p as parseAboutme, n as parseId, v as validateMagicBytes, o as validateZipBomb } from './core-D2X2Eohl.cjs';
2
2
  export { AnnotatedRef, DescriptionFile } from '@dot-agent/parser-dsl';
3
3
  import 'jszip';
package/dist/core.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { d as AboutMe, A as AgentBundle, e as AgentFiles, B as BuildAboutmeOptions, C as Capability, I as IdParts, f as Integrity, a as LintMessage, g as aboutmeToJson, h as buildAboutme, i as buildId, j as createZip, k as extractDigest, l as extractFiles, m as extractName, p as parseAboutme, n as parseId, v as validateMagicBytes, o as validateZipBomb } from './core-b-7c6X6q.js';
1
+ export { d as AboutMe, A as AgentBundle, e as AgentFiles, B as BuildAboutmeOptions, C as Capability, I as IdParts, f as Integrity, a as LintMessage, g as aboutmeToJson, h as buildAboutme, i as buildId, j as createZip, k as extractDigest, l as extractFiles, m as extractName, p as parseAboutme, n as parseId, v as validateMagicBytes, o as validateZipBomb } from './core-D2X2Eohl.js';
2
2
  export { AnnotatedRef, DescriptionFile } from '@dot-agent/parser-dsl';
3
3
  import 'jszip';
package/dist/core.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  parseId,
11
11
  validateMagicBytes,
12
12
  validateZipBomb
13
- } from "./chunk-P5LFGJ6P.js";
13
+ } from "./chunk-AYXHOOUX.js";
14
14
  export {
15
15
  aboutmeToJson,
16
16
  buildAboutme,
package/dist/index.cjs CHANGED
@@ -677,8 +677,8 @@ async function createLinter() {
677
677
  }
678
678
 
679
679
  // src/generated-version.ts
680
- var DSL_VERSION = "0.1-alpha";
681
- var COMPILER_VERSION = "0.5.0-alpha.2";
680
+ var DSL_VERSION = "0.1";
681
+ var COMPILER_VERSION = "0.10.0";
682
682
 
683
683
  // src/manifest.ts
684
684
  function parseAboutme(json) {
@@ -686,9 +686,7 @@ function parseAboutme(json) {
686
686
  if (!json.id) throw new Error("Missing id in aboutme.json");
687
687
  if (!json.name) throw new Error("Missing name in aboutme.json");
688
688
  if (!json.description) throw new Error("Missing description in aboutme.json");
689
- if (!json.version) throw new Error("Missing version in aboutme.json");
690
689
  if (!json.domain) throw new Error("Missing domain in aboutme.json");
691
- if (!json.persona) throw new Error("Missing persona in aboutme.json");
692
690
  if (!json.compiler) throw new Error("Missing compiler in aboutme.json");
693
691
  if (!Array.isArray(json.capabilities)) throw new Error("Missing capabilities array in aboutme.json");
694
692
  if (!Array.isArray(json.requires)) throw new Error("Missing requires array in aboutme.json");
@@ -698,7 +696,7 @@ function parseAboutme(json) {
698
696
  id: json.id,
699
697
  name: json.name,
700
698
  description: json.description,
701
- version: json.version,
699
+ version: json.version ?? "",
702
700
  domain: json.domain,
703
701
  license: json.license ?? "",
704
702
  persona: json.persona,
@@ -810,7 +808,14 @@ function buildId(parts) {
810
808
  result += `:${version}`;
811
809
  if (digest) result += `~${digest}`;
812
810
  }
813
- return result;
811
+ return result.toLowerCase();
812
+ }
813
+ function slugify(name) {
814
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
815
+ }
816
+ var VERSION_RE = /^v?\d+(\.\d+){0,2}(-[0-9A-Za-z.]+)?(\+[0-9A-Za-z.]+)?$/i;
817
+ function isValidVersion(version) {
818
+ return VERSION_RE.test(version);
814
819
  }
815
820
  function extractDigest(id) {
816
821
  try {
@@ -954,13 +959,6 @@ function buildTypesJson(df) {
954
959
  }
955
960
 
956
961
  // src/pack.ts
957
- function gitDescribeTags() {
958
- try {
959
- return (0, import_child_process.execSync)("git describe --tags --abbrev=0", { stdio: "pipe", encoding: "utf-8" }).trim();
960
- } catch {
961
- return null;
962
- }
963
- }
964
962
  function gitRevParseShort() {
965
963
  try {
966
964
  return (0, import_child_process.execSync)("git rev-parse --short HEAD", { stdio: "pipe", encoding: "utf-8" }).trim();
@@ -968,14 +966,65 @@ function gitRevParseShort() {
968
966
  return null;
969
967
  }
970
968
  }
971
- async function resolveVersion(explicit) {
972
- if (explicit) return explicit;
973
- return gitDescribeTags() ?? "v1.0.0";
974
- }
975
969
  async function resolveCommit(explicit) {
976
970
  if (explicit) return explicit;
977
971
  return gitRevParseShort() ?? void 0;
978
972
  }
973
+ function recentTagCandidates(limit = 5) {
974
+ let tags;
975
+ try {
976
+ tags = (0, import_child_process.execSync)("git tag --sort=-creatordate", { stdio: "pipe", encoding: "utf-8" }).trim().split("\n").filter(Boolean);
977
+ } catch {
978
+ return [];
979
+ }
980
+ return tags.slice(0, limit).map((tag) => {
981
+ const atIdx = tag.lastIndexOf("@");
982
+ const version = atIdx === -1 ? tag : tag.slice(atIdx + 1);
983
+ const label = atIdx === -1 ? tag : `${version} (tag: ${tag})`;
984
+ return { version, label };
985
+ }).filter((c) => isValidVersion(c.version));
986
+ }
987
+ var CUSTOM_VERSION = "__dot-agent-custom-version__";
988
+ var BARE_VERSION = "__dot-agent-bare-version__";
989
+ async function resolveVersionInteractive(explicit) {
990
+ if (explicit) {
991
+ if (!isValidVersion(explicit)) {
992
+ throw new Error(`E019: Invalid version format '${explicit}' \u2014 expected vX.Y[.Z][-prerelease] or X.Y[.Z][-prerelease]`);
993
+ }
994
+ return explicit;
995
+ }
996
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
997
+ process.stderr.write("[dot-agent] no TTY and no --version \u2014 packing without a version\n");
998
+ return void 0;
999
+ }
1000
+ const candidates = recentTagCandidates();
1001
+ const clack = await import("@clack/prompts");
1002
+ const choice = await clack.select({
1003
+ message: "Choose a version for this package",
1004
+ options: [
1005
+ ...candidates.map((c) => ({ value: c.version, label: c.label })),
1006
+ { value: CUSTOM_VERSION, label: "Type a custom version\u2026" },
1007
+ { value: BARE_VERSION, label: "None (bare \u2014 no version)" }
1008
+ ]
1009
+ });
1010
+ if (clack.isCancel(choice)) {
1011
+ clack.cancel("Pack cancelled.");
1012
+ process.exit(1);
1013
+ }
1014
+ if (choice === BARE_VERSION) return void 0;
1015
+ if (choice === CUSTOM_VERSION) {
1016
+ const typed = await clack.text({
1017
+ message: "Version",
1018
+ validate: (v) => v && isValidVersion(v) ? void 0 : "Invalid version format \u2014 expected vX.Y[.Z][-prerelease] or X.Y[.Z][-prerelease]"
1019
+ });
1020
+ if (clack.isCancel(typed)) {
1021
+ clack.cancel("Pack cancelled.");
1022
+ process.exit(1);
1023
+ }
1024
+ return typed;
1025
+ }
1026
+ return choice;
1027
+ }
979
1028
  function isExternalPath(agentRoot, declaredPath) {
980
1029
  if ((0, import_path2.isAbsolute)(declaredPath)) return true;
981
1030
  const normRoot = (0, import_path2.normalize)((0, import_path2.resolve)(agentRoot));
@@ -1050,7 +1099,35 @@ async function consolidate(agentRoot, entryFile) {
1050
1099
  mergeSources: order
1051
1100
  };
1052
1101
  }
1053
- async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSources) {
1102
+ var FILE_REF_RE = /\.(txt|md)$/i;
1103
+ function collectFileRefs(stmts, out) {
1104
+ for (const s of stmts) {
1105
+ switch (s.type) {
1106
+ case "guide_stmt":
1107
+ if (FILE_REF_RE.test(s.text)) out.set(`guide:${s.text}`, { kind: "guide", text: s.text });
1108
+ break;
1109
+ case "teach_stmt":
1110
+ if (FILE_REF_RE.test(s.text)) out.set(`teach:${s.text}`, { kind: "teach", text: s.text });
1111
+ break;
1112
+ case "interact_stmt":
1113
+ collectFileRefs(s.handlers, out);
1114
+ break;
1115
+ case "intent_handler":
1116
+ if (Array.isArray(s.body)) collectFileRefs(s.body, out);
1117
+ break;
1118
+ case "offtopic_handler":
1119
+ case "after_stmt":
1120
+ case "parallel_stmt":
1121
+ collectFileRefs(s.body, out);
1122
+ break;
1123
+ case "conditional_stmt":
1124
+ collectFileRefs(s.then, out);
1125
+ if (s.else) collectFileRefs(s.else, out);
1126
+ break;
1127
+ }
1128
+ }
1129
+ }
1130
+ async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSources, personaFile) {
1054
1131
  const files = /* @__PURE__ */ new Map();
1055
1132
  async function walk(subdir, prefix = "") {
1056
1133
  try {
@@ -1075,17 +1152,47 @@ async function collectFiles(dir, descriptionFile, mergedBehaviorText, mergeSourc
1075
1152
  for (const relPath of mergeSources) {
1076
1153
  files.set(`behaviors/${relPath}`, await (0, import_promises2.readFile)((0, import_path2.join)(dir, relPath), "utf-8"));
1077
1154
  }
1078
- try {
1079
- files.set("SOUL.md", await (0, import_promises2.readFile)((0, import_path2.join)(dir, "SOUL.md"), "utf-8"));
1080
- } catch {
1155
+ if (personaFile) {
1156
+ if (isExternalPath(dir, personaFile)) {
1157
+ throw new Error(`E014: persona path '${personaFile}' in '${descriptionFile}' is absolute or escapes the agent root`);
1158
+ }
1159
+ let personaText;
1160
+ try {
1161
+ personaText = await (0, import_promises2.readFile)((0, import_path2.join)(dir, personaFile), "utf-8");
1162
+ } catch {
1163
+ throw new Error(`E_DESC: persona file '${personaFile}' declared in '${descriptionFile}' not found`);
1164
+ }
1165
+ files.set(personaFile, personaText);
1081
1166
  }
1082
1167
  await walk((0, import_path2.join)(dir, "guides"), "guides");
1083
1168
  await walk((0, import_path2.join)(dir, "knowledge"), "knowledge");
1169
+ await initBehaviorParser();
1170
+ const behaviorAst = parseBehaviorFile(mergedBehaviorText).ok;
1171
+ if (behaviorAst) {
1172
+ const refs = /* @__PURE__ */ new Map();
1173
+ for (const state of behaviorAst.states) collectFileRefs(state.body, refs);
1174
+ for (const trigger of behaviorAst.global_triggers) collectFileRefs(trigger.body, refs);
1175
+ for (const { kind, text } of refs.values()) {
1176
+ if (isExternalPath(dir, text)) {
1177
+ throw new Error(`E014: '${kind}' path '${text}' is absolute or escapes the agent root`);
1178
+ }
1179
+ let content;
1180
+ try {
1181
+ content = await (0, import_promises2.readFile)((0, import_path2.join)(dir, text), "utf-8");
1182
+ } catch {
1183
+ throw new Error(`E018: '${kind}' file '${text}' referenced in agent.behavior not found in ${dir}`);
1184
+ }
1185
+ files.set(`${kind === "guide" ? "guides" : "knowledge"}/${text}`, content);
1186
+ }
1187
+ }
1084
1188
  return files;
1085
1189
  }
1190
+ function withAgentExtension(path) {
1191
+ return path.endsWith(".agent") ? path : `${path}.agent`;
1192
+ }
1086
1193
  async function pack(options = {}) {
1087
1194
  const dir = options.dir ?? process.cwd();
1088
- const outPath = options.out ?? (0, import_path2.join)(dir, `${(0, import_path2.basename)(dir)}.agent`);
1195
+ const outPath = withAgentExtension(options.out ?? (0, import_path2.join)(dir, (0, import_path2.basename)(dir)));
1089
1196
  const descriptionFileName = await discoverDescriptionFile(dir, options.description);
1090
1197
  const descriptionText = await (0, import_promises2.readFile)((0, import_path2.join)(dir, descriptionFileName), "utf-8");
1091
1198
  const descriptionMessages = await lintDescription(descriptionText, descriptionFileName);
@@ -1120,13 +1227,13 @@ ${descErrors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`)
1120
1227
  ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join("\n")}`
1121
1228
  );
1122
1229
  }
1123
- const version = await resolveVersion(options.version);
1230
+ const version = await resolveVersionInteractive(options.version);
1124
1231
  const commit = await resolveCommit(options.commit);
1125
- const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
1232
+ const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources, df.persona ?? void 0);
1126
1233
  const contentForHash = Array.from(allFiles.values()).join("");
1127
1234
  const sha256 = (0, import_crypto.createHash)("sha256").update(contentForHash).digest("hex");
1128
1235
  const namespace = df.agent.domain ?? "unknown";
1129
- const id = buildId({ namespace, name: df.agent.name, version, digest: commit });
1236
+ const id = buildId({ namespace, name: slugify(df.agent.name), version, digest: version ? commit : void 0 });
1130
1237
  const typesJson = buildTypesJson(df);
1131
1238
  const integrity = {
1132
1239
  sha256,
@@ -1137,10 +1244,10 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
1137
1244
  id,
1138
1245
  name: df.agent.name,
1139
1246
  description: df.description ?? "",
1140
- version,
1247
+ version: version ?? "",
1141
1248
  domain: df.agent.domain ?? "",
1142
1249
  license: df.agent.license ?? "",
1143
- persona: df.persona ?? "SOUL.md",
1250
+ persona: df.persona ?? void 0,
1144
1251
  purpose: "unknown",
1145
1252
  compiler: `dot-agent/${COMPILER_VERSION}`,
1146
1253
  commit,
@@ -1158,6 +1265,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
1158
1265
  const filesJson = {
1159
1266
  description: descriptionFileName,
1160
1267
  behavior: "agent.behavior",
1268
+ ...df.persona ? { persona: df.persona } : {},
1161
1269
  behaviors: Array.from(allFiles.keys()).filter((f) => f.startsWith("behaviors/")),
1162
1270
  guides: Array.from(allFiles.keys()).filter((f) => f.startsWith("guides/") && !gitkeepPaths.has(f)),
1163
1271
  knowledge: Array.from(allFiles.keys()).filter((f) => f.startsWith("knowledge/") && !gitkeepPaths.has(f))
@@ -1211,9 +1319,9 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
1211
1319
  process.stderr.write(`\x1B[33m\u26A0\x1B[0m ${w.file}:${w.line}:${w.col} ${w.code} ${w.message}
1212
1320
  `);
1213
1321
  }
1214
- const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources);
1322
+ const allFiles = await collectFiles(dir, descriptionFileName, mergedText, mergeSources, df.persona ?? void 0);
1215
1323
  const sha256 = (0, import_crypto2.createHash)("sha256").update(Array.from(allFiles.values()).join("")).digest("hex");
1216
- const id = buildId({ namespace: df.agent.domain ?? "local", name: df.agent.name, version: "dev" });
1324
+ const id = buildId({ namespace: df.agent.domain ?? "unknown", name: slugify(df.agent.name), version: "dev" });
1217
1325
  const aboutme = buildAboutme({
1218
1326
  id,
1219
1327
  name: df.agent.name,
@@ -1221,7 +1329,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
1221
1329
  version: "dev",
1222
1330
  domain: df.agent.domain ?? "",
1223
1331
  license: df.agent.license ?? "",
1224
- persona: df.persona ?? "SOUL.md",
1332
+ persona: df.persona ?? void 0,
1225
1333
  purpose: "development",
1226
1334
  compiler: `dot-agent/${COMPILER_VERSION}`,
1227
1335
  capabilities: df.capabilities.map((c) => ({ id: c.name, description: c.description ?? "" })),
@@ -1234,7 +1342,7 @@ ${errors.map((e) => ` ${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).joi
1234
1342
  // mergedText — it has redundant `merge "..."` lines stripped (see
1235
1343
  // collectFiles() for why they're dead weight once flattened).
1236
1344
  behavior: allFiles.get("agent.behavior") ?? mergedText,
1237
- soul: allFiles.get("SOUL.md"),
1345
+ persona: df.persona ? allFiles.get(df.persona) : void 0,
1238
1346
  guides: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("guides/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
1239
1347
  knowledge: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("knowledge/") && !GITKEEP.has(p)).map(([path, content]) => ({ path, content })),
1240
1348
  behaviors: Array.from(allFiles.entries()).filter(([p]) => p.startsWith("behaviors/")).map(([path, content]) => ({ path, content }))