import path from "path"
import { Effect, Schema } from "effect"
import * as Tool from "./tool"
import { InstanceState } from "@/effect/instance-state"
import WRITE_DESCRIPTION from "./spec-write.txt"
import { validateDocumentSimple } from "./document-validation/document-validate-tool"
import { WriteTool } from "./write"
const DOC_TYPE_MAP: Record<string, "spec" | "design" | "tasks"> = {
"spec.md": "spec",
"plan.md": "design",
"tasks.md": "tasks",
}
const WriteParameters = Schema.Struct({
filePath: Schema.String.annotate({
description: "The absolute path to the file to write (must be absolute, not relative)",
}),
content: Schema.String.annotate({ description: "The content to write." }),
})
export const SpecWriteTool = Tool.define(
"spec_write",
Effect.gen(function* () {
const writeInfo = yield* WriteTool
const writeDef = yield* Tool.init(writeInfo)
return {
description: WRITE_DESCRIPTION,
parameters: WriteParameters,
execute: (params: Schema.Schema.Type<typeof WriteParameters>, ctx: Tool.Context) =>
Effect.gen(function* () {
const instance = yield* InstanceState.context
const filepath = path.isAbsolute(params.filePath)
? params.filePath
: path.join(instance.directory, params.filePath)
const writeResult = yield* writeDef.execute({ filePath: filepath, content: params.content }, ctx)
const basename = path.basename(filepath)
const docType = DOC_TYPE_MAP[basename]
const validationResult = docType ? validateDocumentSimple(filepath, docType) : ""
return {
title: "Spec Artifact Written",
output: `${writeResult.output}${validationResult}`,
metadata: writeResult.metadata,
...(writeResult.attachments ? { attachments: writeResult.attachments } : {}),
}
}).pipe(Effect.orDie),
}
}),
)