forked from anomalyco/opencode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmolecule.ts
More file actions
117 lines (106 loc) · 4.41 KB
/
molecule.ts
File metadata and controls
117 lines (106 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import type { Argv } from "yargs"
import { cmd } from "./cmd"
import { bootstrap } from "../bootstrap"
import { UI } from "../ui"
import { Executor } from "../../molecule/executor"
import type { Molecule } from "../../molecule/types"
import { BashTool } from "../../tool/bash"
import { WriteTool } from "../../tool/write"
import { EditTool } from "../../tool/edit"
import { ReadTool } from "../../tool/read"
import { GrepTool } from "../../tool/grep"
import { GlobTool } from "../../tool/glob"
import { ListTool } from "../../tool/ls"
export const MoleculeCommand = cmd({
command: "molecule",
describe: "Execute molecules - atomic, auditable work units",
builder: (yargs: Argv) => {
return yargs.command(
"run <spec-file>",
"Execute a molecule from spec file",
(yargs) => {
return yargs
.positional("spec-file", {
describe: "Path to molecule spec file (JSON or TypeScript)",
type: "string",
demandOption: true,
})
.option("dry-run", {
describe: "Validate without executing",
type: "boolean",
default: false,
})
},
async (args) => {
const specFile = args["spec-file"] as string
await bootstrap(process.cwd(), async () => {
const file = Bun.file(specFile)
if (!(await file.exists())) {
UI.error(`Spec file not found: ${specFile}`)
process.exit(1)
}
const content = await file.text()
let spec: Molecule.Spec
if (specFile.endsWith(".json")) {
spec = JSON.parse(content)
} else if (specFile.endsWith(".ts") || specFile.endsWith(".js")) {
const module = await import(specFile)
spec = module.default || module.spec
} else {
UI.error("Spec file must be .json, .ts, or .js")
process.exit(1)
}
if (args["dry-run"]) {
UI.println(UI.Style.TEXT_SUCCESS_BOLD + "✓ Spec is valid")
UI.println(UI.Style.TEXT_NORMAL + " ID: " + spec.id)
UI.println(UI.Style.TEXT_NORMAL + " Description: " + spec.description)
UI.println(UI.Style.TEXT_NORMAL + " Actions: " + spec.actions.length)
UI.println(UI.Style.TEXT_NORMAL + " Oracles: " + spec.oracles.length)
return
}
const toolRegistry = new Map()
toolRegistry.set("bash", BashTool)
toolRegistry.set("write", WriteTool)
toolRegistry.set("edit", EditTool)
toolRegistry.set("read", ReadTool)
toolRegistry.set("grep", GrepTool)
toolRegistry.set("glob", GlobTool)
toolRegistry.set("list", ListTool)
const ctx: Executor.Context = {
sessionID: "molecule-" + Date.now(),
messageID: "msg-" + Date.now(),
agent: "build",
toolRegistry,
}
UI.println(UI.Style.TEXT_INFO_BOLD + "▸ Executing molecule: " + spec.id)
UI.println(UI.Style.TEXT_DIM + " " + spec.description)
const startTime = Date.now()
const result = await Executor.execute(spec, ctx)
const duration = Date.now() - startTime
if (result.success) {
UI.println(UI.Style.TEXT_SUCCESS_BOLD + "✓ Success" + UI.Style.TEXT_DIM + ` (${duration}ms)`)
UI.println(UI.Style.TEXT_NORMAL + " Input hash: " + result.attestation.inputHash.slice(0, 16) + "...")
UI.println(UI.Style.TEXT_NORMAL + " Output hash: " + result.attestation.outputHash.slice(0, 16) + "...")
if (result.attestation.oracleResults.length > 0) {
UI.println(UI.Style.TEXT_INFO_BOLD + " Oracles:")
for (const oracle of result.attestation.oracleResults) {
const status = oracle.passed ? "✓" : "✗"
const color = oracle.passed ? UI.Style.TEXT_SUCCESS : UI.Style.TEXT_DANGER
UI.println(color + " " + status + " " + oracle.oracle.check)
}
}
} else {
UI.println(UI.Style.TEXT_DANGER_BOLD + "✗ Failed" + UI.Style.TEXT_DIM + ` (${duration}ms)`)
if (result.errors) {
for (const error of result.errors) {
UI.println(UI.Style.TEXT_DANGER + " " + error.message)
}
}
process.exit(1)
}
})
},
)
},
handler: () => {},
})