@dot-agent/cli 1.0.0 → 1.0.2

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,69 +0,0 @@
1
- import { AboutMe, Integrity, Skill } from '../types.js'
2
-
3
- export function parseAboutme(json: any): AboutMe {
4
- if (!json.schemaVersion) throw new Error('Missing schemaVersion in aboutme.json')
5
- if (!json.id) throw new Error('Missing id in aboutme.json')
6
- if (!json.name) throw new Error('Missing name in aboutme.json')
7
- if (!json.description) throw new Error('Missing description in aboutme.json')
8
- if (!json.version) throw new Error('Missing version in aboutme.json')
9
- if (!json.domain) throw new Error('Missing domain in aboutme.json')
10
- if (!json.license) throw new Error('Missing license in aboutme.json')
11
- if (!json.persona) throw new Error('Missing persona in aboutme.json')
12
- if (!json.compiler) throw new Error('Missing compiler in aboutme.json')
13
- if (!Array.isArray(json.skills)) throw new Error('Missing skills array in aboutme.json')
14
- if (!Array.isArray(json.requires)) throw new Error('Missing requires array in aboutme.json')
15
- if (!json.integrity) throw new Error('Missing integrity in aboutme.json')
16
-
17
- return {
18
- schemaVersion: json.schemaVersion,
19
- id: json.id,
20
- name: json.name,
21
- description: json.description,
22
- version: json.version,
23
- domain: json.domain,
24
- license: json.license,
25
- persona: json.persona,
26
- compiler: json.compiler,
27
- commit: json.commit,
28
- skills: json.skills,
29
- requires: json.requires,
30
- integrity: json.integrity,
31
- }
32
- }
33
-
34
- export interface BuildAboutmeOptions {
35
- id: string
36
- name: string
37
- description: string
38
- version: string
39
- domain: string
40
- license?: string
41
- persona: string
42
- compiler: string
43
- commit?: string
44
- skills?: Skill[]
45
- requires?: string[]
46
- integrity: Integrity
47
- }
48
-
49
- export function buildAboutme(opts: BuildAboutmeOptions): AboutMe {
50
- return {
51
- schemaVersion: 'dot-agent/1.0',
52
- id: opts.id,
53
- name: opts.name,
54
- description: opts.description,
55
- version: opts.version,
56
- domain: opts.domain,
57
- license: opts.license || 'Apache-2.0',
58
- persona: opts.persona,
59
- compiler: opts.compiler,
60
- commit: opts.commit,
61
- skills: opts.skills || [],
62
- requires: opts.requires || [],
63
- integrity: opts.integrity,
64
- }
65
- }
66
-
67
- export function aboutmeToJson(aboutme: AboutMe): string {
68
- return JSON.stringify(aboutme, null, 2)
69
- }
package/src/core/id.ts DELETED
@@ -1,41 +0,0 @@
1
- export interface IdParts {
2
- namespace: string
3
- name: string
4
- version: string
5
- digest: string
6
- }
7
-
8
- export function parseId(id: string): IdParts {
9
- const match = id.match(/^(.+)\/(.+):(.+)~(.+)$/)
10
- if (!match) {
11
- throw new Error(`Invalid agent ID format: ${id}. Expected: namespace/name:version~digest`)
12
- }
13
- const [, namespace, name, version, digest] = match
14
- return { namespace, name, version, digest }
15
- }
16
-
17
- export function buildId(parts: IdParts): string {
18
- const { namespace, name, version, digest } = parts
19
- if (!namespace || !name || !version || !digest) {
20
- throw new Error('Missing required ID parts: namespace, name, version, digest')
21
- }
22
- return `${namespace}/${name}:${version}~${digest}`
23
- }
24
-
25
- export function extractDigest(id: string): string {
26
- try {
27
- const parts = parseId(id)
28
- return parts.digest
29
- } catch {
30
- return ''
31
- }
32
- }
33
-
34
- export function extractName(id: string): string {
35
- try {
36
- const parts = parseId(id)
37
- return parts.name
38
- } catch {
39
- return ''
40
- }
41
- }
package/src/core/lint.ts DELETED
@@ -1,202 +0,0 @@
1
- import { createRequire } from 'module'
2
- import { Parser, Language } from 'web-tree-sitter'
3
- import { AgentDSLKernel, init as initKernel } from '@dot-agent/kernel-dsl'
4
- import { LintMessage } from '../types.js'
5
-
6
- const require = createRequire(import.meta.url)
7
- const { agentWasmPath, behaviorWasmPath } = require('@dot-agent/tree-sitter')
8
-
9
- declare module '@dot-agent/tree-sitter' {
10
- export const agentWasmPath: string
11
- export const behaviorWasmPath: string
12
- }
13
-
14
- let _initialized = false
15
- let _agentParser: Parser
16
- let _behaviorParser: Parser
17
- let _agentLang: any
18
- let _behaviorLang: any
19
-
20
- async function ensureWasmInit() {
21
- if (_initialized) return
22
-
23
- try {
24
- await Parser.init()
25
- } catch (err) {
26
- throw err
27
- }
28
-
29
- _agentParser = new Parser()
30
- _behaviorParser = new Parser()
31
-
32
- try {
33
- _agentLang = await Language.load(agentWasmPath)
34
- _behaviorLang = await Language.load(behaviorWasmPath)
35
- } catch (err) {
36
- throw err
37
- }
38
-
39
- try {
40
- await initKernel()
41
- } catch (err) {
42
- // Silently fail - kernel might not be available in all environments
43
- // We can continue with tree-sitter only for syntax checking
44
- }
45
-
46
- _initialized = true
47
- }
48
-
49
- function collectSyntaxErrors(node: Parser.SyntaxNode): Parser.SyntaxNode[] {
50
- const errors: Parser.SyntaxNode[] = []
51
- if (node.isError || node.isMissing) errors.push(node)
52
- for (const child of node.children) {
53
- errors.push(...collectSyntaxErrors(child))
54
- }
55
- return errors
56
- }
57
-
58
- function getLineCol(node: Parser.SyntaxNode): { line: number; col: number } {
59
- return { line: node.startPosition.row + 1, col: node.startPosition.column + 1 }
60
- }
61
-
62
- export async function lintDescription(text: string): Promise<LintMessage[]> {
63
- await ensureWasmInit()
64
-
65
- _agentParser.setLanguage(_agentLang)
66
- const tree = _agentParser.parse(text)
67
- const messages: LintMessage[] = []
68
-
69
- const syntaxErrors = collectSyntaxErrors(tree.rootNode)
70
- if (syntaxErrors.length > 0) {
71
- for (const error of syntaxErrors) {
72
- const { line, col } = getLineCol(error)
73
- messages.push({
74
- file: 'agent.description',
75
- line,
76
- col,
77
- severity: 'error',
78
- code: 'E004',
79
- message: 'Syntax error in description',
80
- })
81
- }
82
- }
83
-
84
- const walk = (node: Parser.SyntaxNode) => {
85
- if (node.type === 'domain_declaration' && node.childCount > 0) {
86
- const valueNode = node.child(node.childCount - 1)
87
- if (valueNode && valueNode.text === 'example.com') {
88
- const { line, col } = getLineCol(valueNode)
89
- messages.push({
90
- file: 'agent.description',
91
- line,
92
- col,
93
- severity: 'warning',
94
- code: 'W003',
95
- message: 'domain still has default value "example.com"',
96
- })
97
- }
98
- }
99
- for (const child of node.children) walk(child)
100
- }
101
- walk(tree.rootNode)
102
-
103
- return messages
104
- }
105
-
106
- export async function lintBehavior(text: string): Promise<LintMessage[]> {
107
- await ensureWasmInit()
108
-
109
- _behaviorParser.setLanguage(_behaviorLang)
110
- const tree = _behaviorParser.parse(text)
111
- const messages: LintMessage[] = []
112
-
113
- const syntaxErrors = collectSyntaxErrors(tree.rootNode)
114
- if (syntaxErrors.length > 0) {
115
- for (const error of syntaxErrors) {
116
- const { line, col } = getLineCol(error)
117
- messages.push({
118
- file: 'agent.behavior',
119
- line,
120
- col,
121
- severity: 'error',
122
- code: 'E004',
123
- message: 'Syntax error in behavior DSL',
124
- })
125
- }
126
- }
127
-
128
- const walk = (node: Parser.SyntaxNode) => {
129
- if (node.type === 'text_block') {
130
- if (node.text.length > 280) {
131
- const { line, col } = getLineCol(node)
132
- messages.push({
133
- file: 'agent.behavior',
134
- line,
135
- col,
136
- severity: 'warning',
137
- code: 'W002',
138
- message: `Text block exceeds 280 characters (${node.text.length})`,
139
- })
140
- }
141
- }
142
- for (const child of node.children) walk(child)
143
- }
144
- walk(tree.rootNode)
145
-
146
- try {
147
- const kernel = new AgentDSLKernel()
148
- try {
149
- const effects = kernel.load_behavior(text)
150
-
151
- if (Array.isArray(effects)) {
152
- for (const effect of effects) {
153
- if (effect.type === 'parse_error') {
154
- messages.push({
155
- file: 'agent.behavior',
156
- line: 1,
157
- col: 1,
158
- severity: 'error',
159
- code: 'E006',
160
- message: `Parse error: ${effect.message}`,
161
- })
162
- }
163
- }
164
- }
165
-
166
- const graph = kernel.get_graph()
167
- if (graph?.states) {
168
- for (const stateName of Object.keys(graph.states)) {
169
- const state = graph.states[stateName]
170
- const hasIncoming = graph.transitions?.some((t: any) => t.to === stateName)
171
- const hasOutgoing = graph.transitions?.some((t: any) => t.from === stateName)
172
-
173
- if (!hasIncoming && !hasOutgoing && stateName !== graph.current) {
174
- messages.push({
175
- file: 'agent.behavior',
176
- line: 1,
177
- col: 1,
178
- severity: 'warning',
179
- code: 'W001',
180
- message: `state "${stateName}" has no transitions`,
181
- })
182
- }
183
- }
184
- }
185
- } catch (kernelErr: any) {
186
- // Kernel load failed - skip semantic checks, syntax errors already caught by tree-sitter
187
- }
188
- } catch (err: any) {
189
- // Could not initialize kernel - skip semantic checks
190
- }
191
-
192
- return messages
193
- }
194
-
195
- export async function createLinter() {
196
- await ensureWasmInit()
197
-
198
- return {
199
- lintDescription,
200
- lintBehavior,
201
- }
202
- }
package/src/core/types.ts DELETED
@@ -1,46 +0,0 @@
1
- import { ParsedDescription } from '../types.js'
2
-
3
- export function buildTypesJson(description: ParsedDescription): object | null {
4
- const capabilities = description.capabilities || []
5
-
6
- const publicCapabilities = capabilities.filter((cap: any) => cap.public !== false)
7
- if (publicCapabilities.length === 0) return null
8
-
9
- const types: any = {
10
- input: [],
11
- output: [],
12
- $defs: {},
13
- }
14
-
15
- for (const cap of publicCapabilities) {
16
- if (cap.inputType) {
17
- if (typeof cap.inputType === 'string' && cap.inputType.startsWith('std.')) {
18
- types.input.push({
19
- $ref: `https://dot-agent.dev/schema/std/v1/${cap.inputType.replace('std.', '')}.json`,
20
- })
21
- } else if (typeof cap.inputType === 'object') {
22
- const typeName = cap.name ? `${cap.name}Input` : 'Input'
23
- types.input.push({ $ref: `#/$defs/${typeName}` })
24
- types.$defs[typeName] = cap.inputType
25
- }
26
- }
27
-
28
- if (cap.outputType) {
29
- if (typeof cap.outputType === 'string' && cap.outputType.startsWith('std.')) {
30
- types.output.push({
31
- $ref: `https://dot-agent.dev/schema/std/v1/${cap.outputType.replace('std.', '')}.json`,
32
- })
33
- } else if (typeof cap.outputType === 'object') {
34
- const typeName = cap.name ? `${cap.name}Output` : 'Output'
35
- types.output.push({ $ref: `#/$defs/${typeName}` })
36
- types.$defs[typeName] = cap.outputType
37
- }
38
- }
39
- }
40
-
41
- if (Object.keys(types.$defs).length === 0) delete types.$defs
42
-
43
- if (types.input.length === 0 && types.output.length === 0) return null
44
-
45
- return types
46
- }
package/src/core/zip.ts DELETED
@@ -1,76 +0,0 @@
1
- import JSZip from 'jszip'
2
- import { readFile, writeFile } from 'fs/promises'
3
-
4
- const MAX_ZIP_SIZE = 500 * 1024 * 1024
5
- const MAX_COMPRESSION_RATIO = 100
6
-
7
- export async function readZip(filePath: string): Promise<JSZip> {
8
- const data = await readFile(filePath)
9
- return JSZip.loadAsync(data)
10
- }
11
-
12
- export async function validateZipBomb(filePath: string): Promise<boolean> {
13
- const data = await readFile(filePath)
14
- const zip = await JSZip.loadAsync(data)
15
-
16
- let totalUncompressed = 0
17
- zip.forEach((relativePath, file) => {
18
- if (!file.dir) {
19
- totalUncompressed += file._data?.uncompressedSize || 0
20
- }
21
- })
22
-
23
- const compressedSize = data.length
24
- const ratio = totalUncompressed / compressedSize
25
-
26
- if (totalUncompressed > MAX_ZIP_SIZE) {
27
- throw new Error(`ZIP uncompressed size exceeds 500MB limit: ${totalUncompressed}`)
28
- }
29
-
30
- if (ratio > MAX_COMPRESSION_RATIO) {
31
- throw new Error(`ZIP compression ratio exceeds 100x limit: ${ratio.toFixed(1)}x`)
32
- }
33
-
34
- return true
35
- }
36
-
37
- export async function extractFiles(
38
- zip: JSZip,
39
- filter?: string[]
40
- ): Promise<Map<string, string>> {
41
- const files = new Map<string, string>()
42
-
43
- const promises: Promise<void>[] = []
44
- zip.forEach((relativePath, file) => {
45
- if (file.dir) return
46
- if (filter && !filter.some(f => relativePath.startsWith(f))) return
47
-
48
- promises.push(
49
- file.async('text').then(content => {
50
- files.set(relativePath, content)
51
- })
52
- )
53
- })
54
-
55
- await Promise.all(promises)
56
- return files
57
- }
58
-
59
- export function createZip(): JSZip {
60
- return new JSZip()
61
- }
62
-
63
- export async function writeZip(zip: JSZip, outPath: string): Promise<void> {
64
- const data = await zip.generateAsync({ type: 'arraybuffer' })
65
- await writeFile(outPath, Buffer.from(data))
66
- }
67
-
68
- export async function validateMagicBytes(filePath: string): Promise<boolean> {
69
- const data = await readFile(filePath)
70
- const magicBytes = data.subarray(0, 4)
71
- const isZip = magicBytes[0] === 0x50 && magicBytes[1] === 0x4b && magicBytes[2] === 0x03 && magicBytes[3] === 0x04
72
- if (!isZip) {
73
- throw new Error('File is not a valid ZIP (invalid magic bytes)')
74
- }
75
- return true
76
- }
package/src/index.ts DELETED
@@ -1,22 +0,0 @@
1
- export { init } from './commands/init.js'
2
- export { pack } from './commands/pack.js'
3
- export { unpack } from './commands/unpack.js'
4
- export { run } from './commands/run.js'
5
-
6
- export type {
7
- InitOptions,
8
- InitResult,
9
- PackOptions,
10
- PackResult,
11
- UnpackOptions,
12
- UnpackResult,
13
- RunOptions,
14
- AgentContext,
15
- FileEntry,
16
- LintMessage,
17
- AboutMe,
18
- Skill,
19
- Integrity,
20
- ParsedDescription,
21
- ParsedBehavior,
22
- } from './types.js'
@@ -1,21 +0,0 @@
1
- declare module '@dot-agent/kernel-dsl' {
2
- export class AgentDSLKernel {
3
- constructor()
4
- get_current_state(): string
5
- get_graph(): any
6
- get_memory(): any
7
- get_valid_intents(): string[]
8
- load_behavior(text: string): any
9
- observe(callback: Function): void
10
- send_complete(): any
11
- send_event(event: string): any
12
- send_failed(): any
13
- send_fallback(): any
14
- send_intent(intent: string): any
15
- send_offtopic(): any
16
- tick_prompt(): any
17
- free(): void
18
- }
19
-
20
- export function init(): Promise<void>
21
- }
package/src/types.ts DELETED
@@ -1,114 +0,0 @@
1
- export interface LintMessage {
2
- file: string
3
- line: number
4
- col: number
5
- severity: 'error' | 'warning'
6
- code: string
7
- message: string
8
- }
9
-
10
- export interface InitOptions {
11
- name?: string
12
- domain?: string
13
- dir?: string
14
- }
15
-
16
- export interface InitResult {
17
- dir: string
18
- files: string[]
19
- }
20
-
21
- export interface PackOptions {
22
- dir?: string
23
- out?: string
24
- commit?: string
25
- version?: string
26
- }
27
-
28
- export interface PackResult {
29
- path: string
30
- id: string
31
- warnings: LintMessage[]
32
- }
33
-
34
- export interface UnpackOptions {
35
- file: string
36
- out?: string
37
- force?: boolean
38
- }
39
-
40
- export interface UnpackResult {
41
- dir: string
42
- id: string
43
- files: string[]
44
- aboutme: AboutMe
45
- }
46
-
47
- export interface RunOptions {
48
- source: string
49
- }
50
-
51
- export interface FileEntry {
52
- path: string
53
- content: string
54
- }
55
-
56
- export interface AgentContext {
57
- id: string
58
- description: any
59
- behavior: any
60
- kernel: any
61
- files: {
62
- soul?: string
63
- guides: FileEntry[]
64
- knowledge: FileEntry[]
65
- behaviors: FileEntry[]
66
- }
67
- aboutme: AboutMe
68
- on(event: string, listener: (...args: any[]) => void): this
69
- emit(event: string, ...args: any[]): boolean
70
- }
71
-
72
- export interface Skill {
73
- id: string
74
- description: string
75
- }
76
-
77
- export interface Integrity {
78
- sha256: string
79
- types?: string
80
- files?: string
81
- }
82
-
83
- export interface AboutMe {
84
- schemaVersion: string
85
- id: string
86
- name: string
87
- description: string
88
- version: string
89
- domain: string
90
- license: string
91
- persona: string
92
- compiler: string
93
- commit?: string
94
- skills: Skill[]
95
- requires: string[]
96
- integrity: Integrity
97
- }
98
-
99
- export interface ParsedDescription {
100
- domain: string
101
- name: string
102
- version: string
103
- description: string
104
- capabilities: Array<{
105
- name: string
106
- type?: string
107
- description: string
108
- }>
109
- [key: string]: any
110
- }
111
-
112
- export interface ParsedBehavior {
113
- [key: string]: any
114
- }
@@ -1,10 +0,0 @@
1
- declare module 'web-tree-sitter' {
2
- export class Parser {
3
- static init(): Promise<void>
4
- static Language: {
5
- load(path: string): Promise<any>
6
- }
7
- setLanguage(lang: any): void
8
- parse(text: string): any
9
- }
10
- }
@@ -1,62 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { buildAboutme, parseAboutme, aboutmeToJson } from '../src/core/envelope.js'
3
-
4
- describe('envelope', () => {
5
- it('builds aboutme.json', () => {
6
- const aboutme = buildAboutme({
7
- id: 'example.com/test:v1.0~abc123',
8
- name: 'Test Agent',
9
- description: 'A test agent',
10
- version: 'v1.0',
11
- domain: 'example.com',
12
- persona: 'SOUL.md',
13
- compiler: 'dot-agent/1.0.0',
14
- integrity: {
15
- sha256: 'e3b0c44298fc1c149afbaf8b2b',
16
- files: '.agent/files.json',
17
- },
18
- })
19
-
20
- expect(aboutme.schemaVersion).toBe('dot-agent/1.0')
21
- expect(aboutme.id).toBe('example.com/test:v1.0~abc123')
22
- expect(aboutme.name).toBe('Test Agent')
23
- })
24
-
25
- it('parses aboutme.json', () => {
26
- const json = {
27
- schemaVersion: 'dot-agent/1.0',
28
- id: 'example.com/test:v1.0~abc123',
29
- name: 'Test Agent',
30
- description: 'A test agent',
31
- version: 'v1.0',
32
- domain: 'example.com',
33
- license: 'Apache-2.0',
34
- persona: 'SOUL.md',
35
- compiler: 'dot-agent/1.0.0',
36
- skills: [],
37
- requires: [],
38
- integrity: { sha256: 'abc123', files: '.agent/files.json' },
39
- }
40
-
41
- const parsed = parseAboutme(json)
42
- expect(parsed.name).toBe('Test Agent')
43
- expect(parsed.schemaVersion).toBe('dot-agent/1.0')
44
- })
45
-
46
- it('converts aboutme to JSON string', () => {
47
- const aboutme = buildAboutme({
48
- id: 'example.com/test:v1.0~abc123',
49
- name: 'Test Agent',
50
- description: 'A test agent',
51
- version: 'v1.0',
52
- domain: 'example.com',
53
- persona: 'SOUL.md',
54
- compiler: 'dot-agent/1.0.0',
55
- integrity: { sha256: 'abc123', files: '.agent/files.json' },
56
- })
57
-
58
- const json = aboutmeToJson(aboutme)
59
- expect(json).toContain('dot-agent/1.0')
60
- expect(json).toContain('Test Agent')
61
- })
62
- })
package/tests/id.test.ts DELETED
@@ -1,26 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { parseId, buildId } from '../src/core/id.js'
3
-
4
- describe('id', () => {
5
- it('parses a valid agent ID', () => {
6
- const parts = parseId('entelekheia.ai/doctor:v1.0~a1b2c3d')
7
- expect(parts.namespace).toBe('entelekheia.ai')
8
- expect(parts.name).toBe('doctor')
9
- expect(parts.version).toBe('v1.0')
10
- expect(parts.digest).toBe('a1b2c3d')
11
- })
12
-
13
- it('builds an ID from parts', () => {
14
- const id = buildId({
15
- namespace: 'entelekheia.ai',
16
- name: 'doctor',
17
- version: 'v1.0',
18
- digest: 'a1b2c3d',
19
- })
20
- expect(id).toBe('entelekheia.ai/doctor:v1.0~a1b2c3d')
21
- })
22
-
23
- it('throws on invalid ID format', () => {
24
- expect(() => parseId('invalid')).toThrow()
25
- })
26
- })