@dot-agent/cli 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-BTLKCX2G.js +756 -0
- package/dist/chunk-BTLKCX2G.js.map +1 -0
- package/dist/cli.cjs +868 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +96 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +799 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +110 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/package.json +2 -1
- package/.githooks/pre-commit +0 -2
- package/.github/workflows/publish.yml +0 -28
- package/file structure.md +0 -484
- package/plan.md +0 -665
- package/src/cli.ts +0 -111
- package/src/commands/init.ts +0 -117
- package/src/commands/pack.ts +0 -230
- package/src/commands/run.ts +0 -208
- package/src/commands/unpack.ts +0 -79
- package/src/core/envelope.ts +0 -83
- package/src/core/id.ts +0 -55
- package/src/core/lint.ts +0 -216
- package/src/core/types.ts +0 -60
- package/src/core/zip.ts +0 -90
- package/src/index.ts +0 -36
- package/src/types.kernel-dsl.d.ts +0 -35
- package/src/types.ts +0 -128
- package/src/types.wts.d.ts +0 -24
- package/tests/envelope.test.ts +0 -76
- package/tests/id.test.ts +0 -40
- package/tsconfig.json +0 -21
- package/tsup.config.ts +0 -24
- package/vitest.config.ts +0 -27
package/src/cli.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// Copyright 2026 Danilo Borges
|
|
4
|
-
//
|
|
5
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
// you may not use this file except in compliance with the License.
|
|
7
|
-
// You may obtain a copy of the License at
|
|
8
|
-
//
|
|
9
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
//
|
|
11
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
// See the License for the specific language governing permissions and
|
|
15
|
-
// limitations under the License.
|
|
16
|
-
|
|
17
|
-
import { init, pack, unpack, run } from './index.js'
|
|
18
|
-
|
|
19
|
-
const args = process.argv.slice(2)
|
|
20
|
-
const command = args[0]
|
|
21
|
-
|
|
22
|
-
function formatError(msg: string) {
|
|
23
|
-
const lines = msg.split('\n')
|
|
24
|
-
console.error(`\x1b[31m✗\x1b[0m ${lines[0]}`)
|
|
25
|
-
if (lines.length > 1) {
|
|
26
|
-
lines.slice(1).forEach(line => console.error(` ${line}`))
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function formatSuccess(msg: string) {
|
|
31
|
-
console.log(`\x1b[32m✓\x1b[0m ${msg}`)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function formatWarning(msg: string) {
|
|
35
|
-
console.warn(`\x1b[33m⚠\x1b[0m ${msg}`)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function main() {
|
|
39
|
-
try {
|
|
40
|
-
if (command === 'init') {
|
|
41
|
-
const options: any = {}
|
|
42
|
-
for (let i = 1; i < args.length; i++) {
|
|
43
|
-
if (args[i] === '--name' && i + 1 < args.length) options.name = args[++i]
|
|
44
|
-
if (args[i] === '--domain' && i + 1 < args.length) options.domain = args[++i]
|
|
45
|
-
if (args[i] === '--dir' && i + 1 < args.length) options.dir = args[++i]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const result = await init(options)
|
|
49
|
-
formatSuccess(`Scaffolded agent project in ${result.dir}`)
|
|
50
|
-
console.log(` Files: ${result.files.join(', ')}`)
|
|
51
|
-
} else if (command === 'pack') {
|
|
52
|
-
const options: any = {}
|
|
53
|
-
for (let i = 1; i < args.length; i++) {
|
|
54
|
-
if (args[i] === '--dir' && i + 1 < args.length) options.dir = args[++i]
|
|
55
|
-
if (args[i] === '--out' && i + 1 < args.length) options.out = args[++i]
|
|
56
|
-
if (args[i] === '--commit' && i + 1 < args.length) options.commit = args[++i]
|
|
57
|
-
if (args[i] === '--version' && i + 1 < args.length) options.version = args[++i]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const result = await pack(options)
|
|
61
|
-
formatSuccess(`Packed → ${result.path}`)
|
|
62
|
-
console.log(` ID: ${result.id}`)
|
|
63
|
-
if (result.warnings.length > 0) {
|
|
64
|
-
console.log(` Warnings: ${result.warnings.length}`)
|
|
65
|
-
result.warnings.forEach(w => {
|
|
66
|
-
formatWarning(`${w.file}:${w.line}:${w.col} ${w.code} ${w.message}`)
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
} else if (command === 'unpack') {
|
|
70
|
-
const file = args[1]
|
|
71
|
-
if (!file) {
|
|
72
|
-
formatError('Usage: dot-agent unpack <file.agent> [--out <dir>] [--force]')
|
|
73
|
-
process.exit(1)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const options: any = { file }
|
|
77
|
-
for (let i = 2; i < args.length; i++) {
|
|
78
|
-
if (args[i] === '--out' && i + 1 < args.length) options.out = args[++i]
|
|
79
|
-
if (args[i] === '--force') options.force = true
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const result = await unpack(options)
|
|
83
|
-
formatSuccess(`Unpacked to ${result.dir}`)
|
|
84
|
-
console.log(` ID: ${result.id}`)
|
|
85
|
-
console.log(` Files: ${result.files.length}`)
|
|
86
|
-
} else if (command === 'run') {
|
|
87
|
-
const source = args[1]
|
|
88
|
-
if (!source) {
|
|
89
|
-
formatError('Usage: dot-agent run <file.agent | dir>')
|
|
90
|
-
process.exit(1)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const context = await run({ source })
|
|
94
|
-
formatSuccess(`Agent loaded: ${context.id}`)
|
|
95
|
-
} else {
|
|
96
|
-
console.log(`dot-agent CLI v1.0.0
|
|
97
|
-
|
|
98
|
-
Usage:
|
|
99
|
-
dot-agent init [--name <name>] [--domain <domain>] [--dir <dir>]
|
|
100
|
-
dot-agent pack [--dir <dir>] [--out <file>] [--commit <hash>] [--version <tag>]
|
|
101
|
-
dot-agent unpack <file.agent> [--out <dir>] [--force]
|
|
102
|
-
dot-agent run <file.agent | dir>
|
|
103
|
-
`)
|
|
104
|
-
}
|
|
105
|
-
} catch (err: any) {
|
|
106
|
-
formatError(err.message)
|
|
107
|
-
process.exit(1)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
main()
|
package/src/commands/init.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Danilo Borges
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import { mkdir, writeFile, stat } from 'fs/promises'
|
|
16
|
-
import { join, basename } from 'path'
|
|
17
|
-
import { InitOptions, InitResult } from '../types.js'
|
|
18
|
-
|
|
19
|
-
const AGENT_DESCRIPTION_TEMPLATE = (name: string, domain: string) => `agent ${name}
|
|
20
|
-
domain ${domain}
|
|
21
|
-
license Apache-2.0
|
|
22
|
-
|
|
23
|
-
description
|
|
24
|
-
Describe what this agent does.
|
|
25
|
-
|
|
26
|
-
behavior agent.behavior
|
|
27
|
-
|
|
28
|
-
capabilities
|
|
29
|
-
ActionName "Describe this capability"
|
|
30
|
-
`
|
|
31
|
-
|
|
32
|
-
const AGENT_BEHAVIOR_TEMPLATE = `state init
|
|
33
|
-
transition to responsive
|
|
34
|
-
|
|
35
|
-
state responsive
|
|
36
|
-
goal "Help the user with their task."
|
|
37
|
-
interact
|
|
38
|
-
on intent "start" transition to responsive
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
const SOUL_TEMPLATE = (name: string) => `# ${name} — Persona
|
|
42
|
-
|
|
43
|
-
## Voice and Tone
|
|
44
|
-
|
|
45
|
-
Describe the agent's voice, personality, and communication style.
|
|
46
|
-
`
|
|
47
|
-
|
|
48
|
-
const README_TEMPLATE = (name: string) => `# ${name}
|
|
49
|
-
|
|
50
|
-
Brief description of what this agent does.
|
|
51
|
-
|
|
52
|
-
## Usage
|
|
53
|
-
|
|
54
|
-
Example of how to use this agent.
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
const LICENSE = `Apache License
|
|
58
|
-
Version 2.0, January 2004
|
|
59
|
-
|
|
60
|
-
http://www.apache.org/licenses/
|
|
61
|
-
|
|
62
|
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
export async function init(options: InitOptions = {}): Promise<InitResult> {
|
|
66
|
-
const dir = options.dir || process.cwd()
|
|
67
|
-
const name = options.name || basename(dir)
|
|
68
|
-
const domain = options.domain || 'example.com'
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
await stat(dir)
|
|
72
|
-
} catch {
|
|
73
|
-
await mkdir(dir, { recursive: true })
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const agentDescriptionPath = join(dir, 'agent.description')
|
|
77
|
-
try {
|
|
78
|
-
await stat(agentDescriptionPath)
|
|
79
|
-
throw new Error(`agent.description already exists at ${agentDescriptionPath}`)
|
|
80
|
-
} catch (err: any) {
|
|
81
|
-
if (err.code !== 'ENOENT') throw err
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const files: string[] = []
|
|
85
|
-
|
|
86
|
-
await writeFile(agentDescriptionPath, AGENT_DESCRIPTION_TEMPLATE(name, domain))
|
|
87
|
-
files.push('agent.description')
|
|
88
|
-
|
|
89
|
-
await writeFile(join(dir, 'agent.behavior'), AGENT_BEHAVIOR_TEMPLATE)
|
|
90
|
-
files.push('agent.behavior')
|
|
91
|
-
|
|
92
|
-
await writeFile(join(dir, 'SOUL.md'), SOUL_TEMPLATE(name))
|
|
93
|
-
files.push('SOUL.md')
|
|
94
|
-
|
|
95
|
-
await writeFile(join(dir, 'README.md'), README_TEMPLATE(name))
|
|
96
|
-
files.push('README.md')
|
|
97
|
-
|
|
98
|
-
await writeFile(join(dir, 'LICENSE'), LICENSE)
|
|
99
|
-
files.push('LICENSE')
|
|
100
|
-
|
|
101
|
-
await mkdir(join(dir, 'behaviors'), { recursive: true })
|
|
102
|
-
await writeFile(join(dir, 'behaviors', '.gitkeep'), '')
|
|
103
|
-
files.push('behaviors/.gitkeep')
|
|
104
|
-
|
|
105
|
-
await mkdir(join(dir, 'guides'), { recursive: true })
|
|
106
|
-
await writeFile(join(dir, 'guides', '.gitkeep'), '')
|
|
107
|
-
files.push('guides/.gitkeep')
|
|
108
|
-
|
|
109
|
-
await mkdir(join(dir, 'knowledge'), { recursive: true })
|
|
110
|
-
await writeFile(join(dir, 'knowledge', '.gitkeep'), '')
|
|
111
|
-
files.push('knowledge/.gitkeep')
|
|
112
|
-
|
|
113
|
-
await writeFile(join(dir, 'AGENTS.md'), '')
|
|
114
|
-
files.push('AGENTS.md')
|
|
115
|
-
|
|
116
|
-
return { dir, files }
|
|
117
|
-
}
|
package/src/commands/pack.ts
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Danilo Borges
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import { readFile, stat, readdir } from 'fs/promises'
|
|
16
|
-
import { join, basename, dirname } from 'path'
|
|
17
|
-
import { execSync } from 'child_process'
|
|
18
|
-
import { createHash } from 'crypto'
|
|
19
|
-
import JSZip from 'jszip'
|
|
20
|
-
import { PackOptions, PackResult, LintMessage } from '../types.js'
|
|
21
|
-
import { createLinter } from '../core/lint.js'
|
|
22
|
-
import { buildId } from '../core/id.js'
|
|
23
|
-
import { buildAboutme, aboutmeToJson } from '../core/envelope.js'
|
|
24
|
-
import { buildTypesJson } from '../core/types.js'
|
|
25
|
-
import { writeZip } from '../core/zip.js'
|
|
26
|
-
|
|
27
|
-
function gitDescribeTags(): string | null {
|
|
28
|
-
try {
|
|
29
|
-
return execSync('git describe --tags --abbrev=0', {
|
|
30
|
-
stdio: 'pipe',
|
|
31
|
-
encoding: 'utf-8',
|
|
32
|
-
}).trim()
|
|
33
|
-
} catch {
|
|
34
|
-
return null
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function gitRevParseShort(): string | null {
|
|
39
|
-
try {
|
|
40
|
-
return execSync('git rev-parse --short HEAD', {
|
|
41
|
-
stdio: 'pipe',
|
|
42
|
-
encoding: 'utf-8',
|
|
43
|
-
}).trim()
|
|
44
|
-
} catch {
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function resolveVersion(explicit?: string): Promise<string> {
|
|
50
|
-
if (explicit) return explicit
|
|
51
|
-
|
|
52
|
-
const gitTag = gitDescribeTags()
|
|
53
|
-
if (gitTag) return gitTag
|
|
54
|
-
|
|
55
|
-
return 'v1.0.0'
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function resolveCommit(explicit?: string): Promise<string | undefined> {
|
|
59
|
-
if (explicit) return explicit
|
|
60
|
-
return gitRevParseShort() || undefined
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function collectFiles(dir: string): Promise<Map<string, string>> {
|
|
64
|
-
const files = new Map<string, string>()
|
|
65
|
-
|
|
66
|
-
async function walk(subdir: string, prefix: string = '') {
|
|
67
|
-
try {
|
|
68
|
-
const entries = await readdir(subdir)
|
|
69
|
-
for (const entry of entries) {
|
|
70
|
-
if (entry === '.gitkeep' || entry.startsWith('.')) continue
|
|
71
|
-
|
|
72
|
-
const fullPath = join(subdir, entry)
|
|
73
|
-
const stats = await stat(fullPath)
|
|
74
|
-
const relativePath = prefix ? `${prefix}/${entry}` : entry
|
|
75
|
-
|
|
76
|
-
if (stats.isDirectory()) {
|
|
77
|
-
await walk(fullPath, relativePath)
|
|
78
|
-
} else {
|
|
79
|
-
const content = await readFile(fullPath, 'utf-8')
|
|
80
|
-
files.set(relativePath, content)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
// directory doesn't exist or can't be read
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const description = await readFile(join(dir, 'agent.description'), 'utf-8')
|
|
89
|
-
files.set('agent.description', description)
|
|
90
|
-
|
|
91
|
-
const behavior = await readFile(join(dir, 'agent.behavior'), 'utf-8')
|
|
92
|
-
files.set('agent.behavior', behavior)
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
const soul = await readFile(join(dir, 'SOUL.md'), 'utf-8')
|
|
96
|
-
files.set('SOUL.md', soul)
|
|
97
|
-
} catch {
|
|
98
|
-
// optional
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
await walk(join(dir, 'behaviors'), 'behaviors')
|
|
102
|
-
await walk(join(dir, 'guides'), 'guides')
|
|
103
|
-
await walk(join(dir, 'knowledge'), 'knowledge')
|
|
104
|
-
|
|
105
|
-
return files
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function parseDescription(text: string): any {
|
|
109
|
-
const domain = text.match(/domain\s+([^\n]+)/)?.[1] || ''
|
|
110
|
-
const name = text.match(/agent\s+([^\n]+)/)?.[1] || ''
|
|
111
|
-
const description = text.match(/description\s+(.+?)(?=\n\n|\n[a-z])/s)?.[1] || ''
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
domain: domain.trim(),
|
|
115
|
-
name: name.trim(),
|
|
116
|
-
description: description.trim(),
|
|
117
|
-
capabilities: [],
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export async function pack(options: PackOptions = {}): Promise<PackResult> {
|
|
122
|
-
const dir = options.dir || process.cwd()
|
|
123
|
-
const outPath = options.out || join(dir, `${basename(dir)}.agent`)
|
|
124
|
-
|
|
125
|
-
// Read files
|
|
126
|
-
let descriptionText: string
|
|
127
|
-
let behaviorText: string
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
descriptionText = await readFile(join(dir, 'agent.description'), 'utf-8')
|
|
131
|
-
} catch {
|
|
132
|
-
throw new Error('E003: File agent.description not found')
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
behaviorText = await readFile(join(dir, 'agent.behavior'), 'utf-8')
|
|
137
|
-
} catch {
|
|
138
|
-
throw new Error('E007: File agent.behavior not found')
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Lint
|
|
142
|
-
const linter = await createLinter()
|
|
143
|
-
const descriptionMessages = await linter.lintDescription(descriptionText)
|
|
144
|
-
const behaviorMessages = await linter.lintBehavior(behaviorText)
|
|
145
|
-
|
|
146
|
-
const allMessages = [...descriptionMessages, ...behaviorMessages]
|
|
147
|
-
const errors = allMessages.filter(m => m.severity === 'error')
|
|
148
|
-
const warnings = allMessages.filter(m => m.severity === 'warning')
|
|
149
|
-
|
|
150
|
-
if (errors.length > 0) {
|
|
151
|
-
throw new Error(`Lint failed: ${errors.map(e => `${e.file}:${e.line}:${e.col} ${e.code} ${e.message}`).join('\n')}`)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Parse description
|
|
155
|
-
const description = parseDescription(descriptionText)
|
|
156
|
-
|
|
157
|
-
// Resolve version & commit
|
|
158
|
-
const version = await resolveVersion(options.version)
|
|
159
|
-
const commit = await resolveCommit(options.commit)
|
|
160
|
-
|
|
161
|
-
// Collect all files
|
|
162
|
-
const allFiles = await collectFiles(dir)
|
|
163
|
-
|
|
164
|
-
// Build ID
|
|
165
|
-
const contentForHash = Array.from(allFiles.values()).join('')
|
|
166
|
-
const digest = createHash('sha256').update(contentForHash).digest('hex').substring(0, 8)
|
|
167
|
-
const id = buildId({
|
|
168
|
-
namespace: description.domain,
|
|
169
|
-
name: description.name,
|
|
170
|
-
version,
|
|
171
|
-
digest,
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// Build aboutme
|
|
175
|
-
const aboutme = buildAboutme({
|
|
176
|
-
id,
|
|
177
|
-
name: description.name,
|
|
178
|
-
description: description.description,
|
|
179
|
-
version,
|
|
180
|
-
domain: description.domain,
|
|
181
|
-
license: 'Apache-2.0',
|
|
182
|
-
persona: 'SOUL.md',
|
|
183
|
-
compiler: 'dot-agent/1.0.0',
|
|
184
|
-
commit,
|
|
185
|
-
skills: [],
|
|
186
|
-
requires: [],
|
|
187
|
-
integrity: {
|
|
188
|
-
sha256: createHash('sha256').update(contentForHash).digest('hex'),
|
|
189
|
-
files: '.agent/files.json',
|
|
190
|
-
},
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
// Build ZIP
|
|
194
|
-
const zip = new JSZip()
|
|
195
|
-
|
|
196
|
-
zip.folder('.agent')!.file('aboutme.json', aboutmeToJson(aboutme))
|
|
197
|
-
|
|
198
|
-
// Build files.json
|
|
199
|
-
const filesJson = {
|
|
200
|
-
description: 'agent.description',
|
|
201
|
-
behavior: 'agent.behavior',
|
|
202
|
-
behaviors: Array.from(allFiles.keys())
|
|
203
|
-
.filter(f => f.startsWith('behaviors/') && f !== 'behaviors/.gitkeep')
|
|
204
|
-
.map(f => f),
|
|
205
|
-
guides: Array.from(allFiles.keys())
|
|
206
|
-
.filter(f => f.startsWith('guides/') && f !== 'guides/.gitkeep')
|
|
207
|
-
.map(f => f),
|
|
208
|
-
knowledge: Array.from(allFiles.keys())
|
|
209
|
-
.filter(f => f.startsWith('knowledge/') && f !== 'knowledge/.gitkeep')
|
|
210
|
-
.map(f => f),
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
zip.folder('.agent')!.file('files.json', JSON.stringify(filesJson, null, 2))
|
|
214
|
-
|
|
215
|
-
// Add all files to ZIP root
|
|
216
|
-
for (const [path, content] of allFiles) {
|
|
217
|
-
if (path !== 'behaviors/.gitkeep' && path !== 'guides/.gitkeep' && path !== 'knowledge/.gitkeep') {
|
|
218
|
-
zip.file(path, content)
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Write ZIP
|
|
223
|
-
await writeZip(zip, outPath)
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
path: outPath,
|
|
227
|
-
id,
|
|
228
|
-
warnings,
|
|
229
|
-
}
|
|
230
|
-
}
|
package/src/commands/run.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Danilo Borges
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import { EventEmitter } from 'events'
|
|
16
|
-
import { readFile, stat } from 'fs/promises'
|
|
17
|
-
import { AgentDSLKernel, init as initKernel } from '@dot-agent/kernel-dsl'
|
|
18
|
-
import { RunOptions, AgentContext, FileEntry } from '../types.js'
|
|
19
|
-
import { readZip, validateZipBomb, validateMagicBytes, extractFiles } from '../core/zip.js'
|
|
20
|
-
import { parseAboutme } from '../core/envelope.js'
|
|
21
|
-
|
|
22
|
-
function isZipFile(source: string): boolean {
|
|
23
|
-
return source.endsWith('.agent')
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function run(options: RunOptions): Promise<AgentContext> {
|
|
27
|
-
const { source } = options
|
|
28
|
-
const context = new EventEmitter() as any as AgentContext
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
context.emit('progress', { step: 'opening', pct: 0 })
|
|
32
|
-
|
|
33
|
-
let descriptionText: string
|
|
34
|
-
let behaviorText: string
|
|
35
|
-
let aboutme: any = null
|
|
36
|
-
let id: string
|
|
37
|
-
|
|
38
|
-
if (isZipFile(source)) {
|
|
39
|
-
// Load from .agent ZIP
|
|
40
|
-
await validateMagicBytes(source)
|
|
41
|
-
await validateZipBomb(source)
|
|
42
|
-
|
|
43
|
-
const zip = await readZip(source)
|
|
44
|
-
|
|
45
|
-
const aboutmeFile = zip.file('.agent/aboutme.json')
|
|
46
|
-
if (!aboutmeFile) {
|
|
47
|
-
throw new Error('Missing .agent/aboutme.json')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const aboutmeText = await aboutmeFile.async('text')
|
|
51
|
-
aboutme = parseAboutme(JSON.parse(aboutmeText))
|
|
52
|
-
id = aboutme.id
|
|
53
|
-
|
|
54
|
-
const descFile = zip.file('agent.description')
|
|
55
|
-
if (!descFile) throw new Error('Missing agent.description')
|
|
56
|
-
descriptionText = await descFile.async('text')
|
|
57
|
-
|
|
58
|
-
const behavFile = zip.file('agent.behavior')
|
|
59
|
-
if (!behavFile) throw new Error('Missing agent.behavior')
|
|
60
|
-
behaviorText = await behavFile.async('text')
|
|
61
|
-
|
|
62
|
-
context.emit('progress', { step: 'parsing', pct: 30 })
|
|
63
|
-
|
|
64
|
-
// Load kernel-dsl
|
|
65
|
-
let kernel: any
|
|
66
|
-
try {
|
|
67
|
-
await initKernel()
|
|
68
|
-
kernel = new AgentDSLKernel()
|
|
69
|
-
kernel.load_behavior(behaviorText)
|
|
70
|
-
} catch (err: any) {
|
|
71
|
-
// Kernel failed - create a stub
|
|
72
|
-
kernel = {
|
|
73
|
-
get_current_state: () => 'init',
|
|
74
|
-
get_graph: () => ({}),
|
|
75
|
-
get_memory: () => [],
|
|
76
|
-
get_valid_intents: () => [],
|
|
77
|
-
load_behavior: () => {},
|
|
78
|
-
observe: () => {},
|
|
79
|
-
send_complete: () => {},
|
|
80
|
-
send_event: () => {},
|
|
81
|
-
send_failed: () => {},
|
|
82
|
-
send_fallback: () => {},
|
|
83
|
-
send_intent: () => {},
|
|
84
|
-
send_offtopic: () => {},
|
|
85
|
-
tick_prompt: () => {},
|
|
86
|
-
free: () => {},
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
context.emit('progress', { step: 'loading-files', pct: 60 })
|
|
91
|
-
|
|
92
|
-
// Load files
|
|
93
|
-
const soulFile = zip.file('SOUL.md')
|
|
94
|
-
const soul = soulFile ? await soulFile.async('text') : undefined
|
|
95
|
-
|
|
96
|
-
const allFiles = await extractFiles(zip)
|
|
97
|
-
const guides: FileEntry[] = []
|
|
98
|
-
const knowledge: FileEntry[] = []
|
|
99
|
-
const behaviors: FileEntry[] = []
|
|
100
|
-
|
|
101
|
-
for (const [path, content] of allFiles) {
|
|
102
|
-
if (path.startsWith('guides/') && path !== 'guides/.gitkeep') {
|
|
103
|
-
guides.push({ path, content })
|
|
104
|
-
} else if (path.startsWith('knowledge/') && path !== 'knowledge/.gitkeep') {
|
|
105
|
-
knowledge.push({ path, content })
|
|
106
|
-
} else if (path.startsWith('behaviors/') && path !== 'behaviors/.gitkeep') {
|
|
107
|
-
behaviors.push({ path, content })
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
context.id = id
|
|
112
|
-
context.description = { domain: 'example.com', name: 'Agent' }
|
|
113
|
-
context.behavior = {}
|
|
114
|
-
context.kernel = kernel
|
|
115
|
-
context.files = { soul, guides, knowledge, behaviors }
|
|
116
|
-
context.aboutme = aboutme
|
|
117
|
-
} else {
|
|
118
|
-
// Load from directory
|
|
119
|
-
const descPath = `${source}/agent.description`
|
|
120
|
-
const behavPath = `${source}/agent.behavior`
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
descriptionText = await readFile(descPath, 'utf-8')
|
|
124
|
-
} catch {
|
|
125
|
-
throw new Error(`Missing agent.description at ${descPath}`)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
behaviorText = await readFile(behavPath, 'utf-8')
|
|
130
|
-
} catch {
|
|
131
|
-
throw new Error(`Missing agent.behavior at ${behavPath}`)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
context.emit('progress', { step: 'parsing', pct: 30 })
|
|
135
|
-
|
|
136
|
-
// Load kernel-dsl
|
|
137
|
-
let kernel: any
|
|
138
|
-
try {
|
|
139
|
-
await initKernel()
|
|
140
|
-
kernel = new AgentDSLKernel()
|
|
141
|
-
kernel.load_behavior(behaviorText)
|
|
142
|
-
} catch (err: any) {
|
|
143
|
-
// Kernel failed - create a stub
|
|
144
|
-
kernel = {
|
|
145
|
-
get_current_state: () => 'init',
|
|
146
|
-
get_graph: () => ({}),
|
|
147
|
-
get_memory: () => [],
|
|
148
|
-
get_valid_intents: () => [],
|
|
149
|
-
load_behavior: () => {},
|
|
150
|
-
observe: () => {},
|
|
151
|
-
send_complete: () => {},
|
|
152
|
-
send_event: () => {},
|
|
153
|
-
send_failed: () => {},
|
|
154
|
-
send_fallback: () => {},
|
|
155
|
-
send_intent: () => {},
|
|
156
|
-
send_offtopic: () => {},
|
|
157
|
-
tick_prompt: () => {},
|
|
158
|
-
free: () => {},
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
context.emit('progress', { step: 'loading-files', pct: 60 })
|
|
163
|
-
|
|
164
|
-
id = 'local/agent:v1.0~unknown'
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
const soul = await readFile(`${source}/SOUL.md`, 'utf-8')
|
|
168
|
-
context.files = {
|
|
169
|
-
soul,
|
|
170
|
-
guides: [],
|
|
171
|
-
knowledge: [],
|
|
172
|
-
behaviors: [],
|
|
173
|
-
}
|
|
174
|
-
} catch {
|
|
175
|
-
context.files = { guides: [], knowledge: [], behaviors: [] }
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const defaultAboutme: any = {
|
|
179
|
-
schemaVersion: 'dot-agent/1.0',
|
|
180
|
-
id,
|
|
181
|
-
name: 'Agent',
|
|
182
|
-
description: '',
|
|
183
|
-
version: 'v1.0',
|
|
184
|
-
domain: 'local',
|
|
185
|
-
license: 'Apache-2.0',
|
|
186
|
-
persona: 'SOUL.md',
|
|
187
|
-
compiler: 'dot-agent/1.0.0',
|
|
188
|
-
skills: [],
|
|
189
|
-
requires: [],
|
|
190
|
-
integrity: { sha256: '', files: '' },
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
context.id = id
|
|
194
|
-
context.description = { domain: 'example.com', name: 'Agent' }
|
|
195
|
-
context.behavior = {}
|
|
196
|
-
context.kernel = kernel
|
|
197
|
-
context.aboutme = defaultAboutme
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
context.emit('progress', { step: 'ready', pct: 100 })
|
|
201
|
-
context.emit('ready', context)
|
|
202
|
-
|
|
203
|
-
return context
|
|
204
|
-
} catch (err) {
|
|
205
|
-
context.emit('error', err)
|
|
206
|
-
throw err
|
|
207
|
-
}
|
|
208
|
-
}
|