|
@@ -1,21 +1,14 @@
|
|
|
import type { Argv } from "yargs"
|
|
import type { Argv } from "yargs"
|
|
|
import path from "path"
|
|
import path from "path"
|
|
|
-import { Bus } from "../../bus"
|
|
|
|
|
-import { Provider } from "../../provider/provider"
|
|
|
|
|
-import { Session } from "../../session"
|
|
|
|
|
import { UI } from "../ui"
|
|
import { UI } from "../ui"
|
|
|
import { cmd } from "./cmd"
|
|
import { cmd } from "./cmd"
|
|
|
import { Flag } from "../../flag/flag"
|
|
import { Flag } from "../../flag/flag"
|
|
|
-import { Config } from "../../config/config"
|
|
|
|
|
import { bootstrap } from "../bootstrap"
|
|
import { bootstrap } from "../bootstrap"
|
|
|
-import { MessageV2 } from "../../session/message-v2"
|
|
|
|
|
-import { Identifier } from "../../id/id"
|
|
|
|
|
-import { Agent } from "../../agent/agent"
|
|
|
|
|
import { Command } from "../../command"
|
|
import { Command } from "../../command"
|
|
|
-import { SessionPrompt } from "../../session/prompt"
|
|
|
|
|
import { EOL } from "os"
|
|
import { EOL } from "os"
|
|
|
-import { Permission } from "@/permission"
|
|
|
|
|
import { select } from "@clack/prompts"
|
|
import { select } from "@clack/prompts"
|
|
|
|
|
+import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk"
|
|
|
|
|
+import { Server } from "../../server/server"
|
|
|
|
|
|
|
|
const TOOL: Record<string, [string, string]> = {
|
|
const TOOL: Record<string, [string, string]> = {
|
|
|
todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD],
|
|
todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD],
|
|
@@ -84,11 +77,19 @@ export const RunCommand = cmd({
|
|
|
type: "string",
|
|
type: "string",
|
|
|
describe: "title for the session (uses truncated prompt if no value provided)",
|
|
describe: "title for the session (uses truncated prompt if no value provided)",
|
|
|
})
|
|
})
|
|
|
|
|
+ .option("attach", {
|
|
|
|
|
+ type: "string",
|
|
|
|
|
+ describe: "attach to a running opencode server (e.g., http://localhost:4096)",
|
|
|
|
|
+ })
|
|
|
|
|
+ .option("port", {
|
|
|
|
|
+ type: "number",
|
|
|
|
|
+ describe: "port for the local server (defaults to random port if no value provided)",
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
handler: async (args) => {
|
|
handler: async (args) => {
|
|
|
let message = args.message.join(" ")
|
|
let message = args.message.join(" ")
|
|
|
|
|
|
|
|
- let fileParts: any[] = []
|
|
|
|
|
|
|
+ const fileParts: any[] = []
|
|
|
if (args.file) {
|
|
if (args.file) {
|
|
|
const files = Array.isArray(args.file) ? args.file : [args.file]
|
|
const files = Array.isArray(args.file) ? args.file : [args.file]
|
|
|
|
|
|
|
@@ -124,216 +125,228 @@ export const RunCommand = cmd({
|
|
|
process.exit(1)
|
|
process.exit(1)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await bootstrap(process.cwd(), async () => {
|
|
|
|
|
- if (args.command) {
|
|
|
|
|
- const exists = await Command.get(args.command)
|
|
|
|
|
- if (!exists) {
|
|
|
|
|
- UI.error(`Command "${args.command}" not found`)
|
|
|
|
|
- process.exit(1)
|
|
|
|
|
|
|
+ const execute = async (sdk: OpencodeClient, sessionID: string) => {
|
|
|
|
|
+ const printEvent = (color: string, type: string, title: string) => {
|
|
|
|
|
+ UI.println(
|
|
|
|
|
+ color + `|`,
|
|
|
|
|
+ UI.Style.TEXT_NORMAL + UI.Style.TEXT_DIM + ` ${type.padEnd(7, " ")}`,
|
|
|
|
|
+ "",
|
|
|
|
|
+ UI.Style.TEXT_NORMAL + title,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const outputJsonEvent = (type: string, data: any) => {
|
|
|
|
|
+ if (args.format === "json") {
|
|
|
|
|
+ process.stdout.write(JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL)
|
|
|
|
|
+ return true
|
|
|
}
|
|
}
|
|
|
|
|
+ return false
|
|
|
}
|
|
}
|
|
|
- const session = await (async () => {
|
|
|
|
|
- if (args.continue) {
|
|
|
|
|
- const it = Session.list()
|
|
|
|
|
- try {
|
|
|
|
|
- for await (const s of it) {
|
|
|
|
|
- if (s.parentID === undefined) {
|
|
|
|
|
- return s
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const events = await sdk.event.subscribe()
|
|
|
|
|
+ let errorMsg: string | undefined
|
|
|
|
|
+
|
|
|
|
|
+ const eventProcessor = (async () => {
|
|
|
|
|
+ for await (const event of events.stream) {
|
|
|
|
|
+ if (event.type === "message.part.updated") {
|
|
|
|
|
+ const part = event.properties.part
|
|
|
|
|
+ if (part.sessionID !== sessionID) continue
|
|
|
|
|
+
|
|
|
|
|
+ if (part.type === "tool" && part.state.status === "completed") {
|
|
|
|
|
+ if (outputJsonEvent("tool_use", { part })) continue
|
|
|
|
|
+ const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD]
|
|
|
|
|
+ const title =
|
|
|
|
|
+ part.state.title ||
|
|
|
|
|
+ (Object.keys(part.state.input).length > 0 ? JSON.stringify(part.state.input) : "Unknown")
|
|
|
|
|
+ printEvent(color, tool, title)
|
|
|
|
|
+ if (part.tool === "bash" && part.state.output?.trim()) {
|
|
|
|
|
+ UI.println()
|
|
|
|
|
+ UI.println(part.state.output)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return
|
|
|
|
|
- } finally {
|
|
|
|
|
- await it.return()
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- if (args.session) return Session.get(args.session)
|
|
|
|
|
|
|
+ if (part.type === "step-start") {
|
|
|
|
|
+ if (outputJsonEvent("step_start", { part })) continue
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const title = (() => {
|
|
|
|
|
- if (args.title !== undefined) {
|
|
|
|
|
- if (args.title === "") {
|
|
|
|
|
- return message.slice(0, 50) + (message.length > 50 ? "..." : "")
|
|
|
|
|
|
|
+ if (part.type === "step-finish") {
|
|
|
|
|
+ if (outputJsonEvent("step_finish", { part })) continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (part.type === "text" && part.time?.end) {
|
|
|
|
|
+ if (outputJsonEvent("text", { part })) continue
|
|
|
|
|
+ const isPiped = !process.stdout.isTTY
|
|
|
|
|
+ if (!isPiped) UI.println()
|
|
|
|
|
+ process.stdout.write((isPiped ? part.text : UI.markdown(part.text)) + EOL)
|
|
|
|
|
+ if (!isPiped) UI.println()
|
|
|
}
|
|
}
|
|
|
- return args.title
|
|
|
|
|
}
|
|
}
|
|
|
- return undefined
|
|
|
|
|
- })()
|
|
|
|
|
|
|
|
|
|
- return Session.create({
|
|
|
|
|
- title,
|
|
|
|
|
- })
|
|
|
|
|
- })()
|
|
|
|
|
|
|
+ if (event.type === "session.error") {
|
|
|
|
|
+ const props = event.properties
|
|
|
|
|
+ if (props.sessionID !== sessionID || !props.error) continue
|
|
|
|
|
+ let err = String(props.error.name)
|
|
|
|
|
+ if ("data" in props.error && props.error.data && "message" in props.error.data) {
|
|
|
|
|
+ err = String(props.error.data.message)
|
|
|
|
|
+ }
|
|
|
|
|
+ errorMsg = errorMsg ? errorMsg + EOL + err : err
|
|
|
|
|
+ if (outputJsonEvent("error", { error: props.error })) continue
|
|
|
|
|
+ UI.error(err)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (!session) {
|
|
|
|
|
- UI.error("Session not found")
|
|
|
|
|
- process.exit(1)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (event.type === "session.idle" && event.properties.sessionID === sessionID) {
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const cfg = await Config.get()
|
|
|
|
|
- if (cfg.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) {
|
|
|
|
|
- try {
|
|
|
|
|
- await Session.share(session.id)
|
|
|
|
|
- UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + session.id.slice(-8))
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- if (error instanceof Error && error.message.includes("disabled")) {
|
|
|
|
|
- UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
|
|
|
|
- } else {
|
|
|
|
|
- throw error
|
|
|
|
|
|
|
+ if (event.type === "permission.updated") {
|
|
|
|
|
+ const permission = event.properties
|
|
|
|
|
+ if (permission.sessionID !== sessionID) continue
|
|
|
|
|
+ const result = await select({
|
|
|
|
|
+ message: `Permission required to run: ${permission.title}`,
|
|
|
|
|
+ options: [
|
|
|
|
|
+ { value: "once", label: "Allow once" },
|
|
|
|
|
+ { value: "always", label: "Always allow" },
|
|
|
|
|
+ { value: "reject", label: "Reject" },
|
|
|
|
|
+ ],
|
|
|
|
|
+ initialValue: "once",
|
|
|
|
|
+ }).catch(() => "reject")
|
|
|
|
|
+ const response = (result.toString().includes("cancel") ? "reject" : result) as
|
|
|
|
|
+ | "once"
|
|
|
|
|
+ | "always"
|
|
|
|
|
+ | "reject"
|
|
|
|
|
+ await sdk.postSessionIdPermissionsPermissionId({
|
|
|
|
|
+ path: { id: sessionID, permissionID: permission.id },
|
|
|
|
|
+ body: { response },
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const agent = await (async () => {
|
|
|
|
|
- if (args.agent) return Agent.get(args.agent)
|
|
|
|
|
- const build = Agent.get("build")
|
|
|
|
|
- if (build) return build
|
|
|
|
|
- return Agent.list().then((x) => x[0])
|
|
|
|
|
})()
|
|
})()
|
|
|
|
|
|
|
|
- const { providerID, modelID } = await (async () => {
|
|
|
|
|
- if (args.model) return Provider.parseModel(args.model)
|
|
|
|
|
- if (agent.model) return agent.model
|
|
|
|
|
- return await Provider.defaultModel()
|
|
|
|
|
- })()
|
|
|
|
|
-
|
|
|
|
|
- function printEvent(color: string, type: string, title: string) {
|
|
|
|
|
- UI.println(
|
|
|
|
|
- color + `|`,
|
|
|
|
|
- UI.Style.TEXT_NORMAL + UI.Style.TEXT_DIM + ` ${type.padEnd(7, " ")}`,
|
|
|
|
|
- "",
|
|
|
|
|
- UI.Style.TEXT_NORMAL + title,
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ if (args.command) {
|
|
|
|
|
+ await sdk.session.command({
|
|
|
|
|
+ path: { id: sessionID },
|
|
|
|
|
+ body: {
|
|
|
|
|
+ agent: args.agent || "build",
|
|
|
|
|
+ model: args.model,
|
|
|
|
|
+ command: args.command,
|
|
|
|
|
+ arguments: message,
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const modelParam = args.model
|
|
|
|
|
+ ? (() => {
|
|
|
|
|
+ const [providerID, modelID] = args.model.split("/")
|
|
|
|
|
+ return { providerID, modelID }
|
|
|
|
|
+ })()
|
|
|
|
|
+ : undefined
|
|
|
|
|
+ await sdk.session.prompt({
|
|
|
|
|
+ path: { id: sessionID },
|
|
|
|
|
+ body: {
|
|
|
|
|
+ agent: args.agent || "build",
|
|
|
|
|
+ model: modelParam,
|
|
|
|
|
+ parts: [...fileParts, { type: "text", text: message }],
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function outputJsonEvent(type: string, data: any) {
|
|
|
|
|
- if (args.format === "json") {
|
|
|
|
|
- const jsonEvent = {
|
|
|
|
|
- type,
|
|
|
|
|
- timestamp: Date.now(),
|
|
|
|
|
- sessionID: session?.id,
|
|
|
|
|
- ...data,
|
|
|
|
|
- }
|
|
|
|
|
- process.stdout.write(JSON.stringify(jsonEvent) + EOL)
|
|
|
|
|
- return true
|
|
|
|
|
- }
|
|
|
|
|
- return false
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ await eventProcessor
|
|
|
|
|
+ if (errorMsg) process.exit(1)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const messageID = Identifier.ascending("message")
|
|
|
|
|
|
|
+ if (args.attach) {
|
|
|
|
|
+ const sdk = createOpencodeClient({ baseUrl: args.attach })
|
|
|
|
|
|
|
|
- Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
|
|
|
|
- if (evt.properties.part.sessionID !== session.id) return
|
|
|
|
|
- if (evt.properties.part.messageID === messageID) return
|
|
|
|
|
- const part = evt.properties.part
|
|
|
|
|
|
|
+ const sessionID = await (async () => {
|
|
|
|
|
+ if (args.continue) {
|
|
|
|
|
+ const result = await sdk.session.list()
|
|
|
|
|
+ return result.data?.find((s) => !s.parentID)?.id
|
|
|
|
|
+ }
|
|
|
|
|
+ if (args.session) return args.session
|
|
|
|
|
|
|
|
- if (part.type === "tool" && part.state.status === "completed") {
|
|
|
|
|
- if (outputJsonEvent("tool_use", { part })) return
|
|
|
|
|
- const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD]
|
|
|
|
|
- const title =
|
|
|
|
|
- part.state.title ||
|
|
|
|
|
- (Object.keys(part.state.input).length > 0
|
|
|
|
|
- ? JSON.stringify(part.state.input)
|
|
|
|
|
- : "Unknown")
|
|
|
|
|
|
|
+ const title =
|
|
|
|
|
+ args.title !== undefined
|
|
|
|
|
+ ? args.title === ""
|
|
|
|
|
+ ? message.slice(0, 50) + (message.length > 50 ? "..." : "")
|
|
|
|
|
+ : args.title
|
|
|
|
|
+ : undefined
|
|
|
|
|
|
|
|
- printEvent(color, tool, title)
|
|
|
|
|
|
|
+ const result = await sdk.session.create({ body: title ? { title } : {} })
|
|
|
|
|
+ return result.data?.id
|
|
|
|
|
+ })()
|
|
|
|
|
|
|
|
- if (part.tool === "bash" && part.state.output && part.state.output.trim()) {
|
|
|
|
|
- UI.println()
|
|
|
|
|
- UI.println(part.state.output)
|
|
|
|
|
|
|
+ if (!sessionID) {
|
|
|
|
|
+ UI.error("Session not found")
|
|
|
|
|
+ process.exit(1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const cfgResult = await sdk.config.get()
|
|
|
|
|
+ if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) {
|
|
|
|
|
+ const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => {
|
|
|
|
|
+ if (error instanceof Error && error.message.includes("disabled")) {
|
|
|
|
|
+ UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
|
|
}
|
|
}
|
|
|
|
|
+ return { error }
|
|
|
|
|
+ })
|
|
|
|
|
+ if (!shareResult.error) {
|
|
|
|
|
+ UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + sessionID.slice(-8))
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (part.type === "step-start") {
|
|
|
|
|
- if (outputJsonEvent("step_start", { part })) return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return await execute(sdk, sessionID)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (part.type === "step-finish") {
|
|
|
|
|
- if (outputJsonEvent("step_finish", { part })) return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ await bootstrap(process.cwd(), async () => {
|
|
|
|
|
+ const server = Server.listen({ port: args.port ?? 0, hostname: "127.0.0.1" })
|
|
|
|
|
+ const sdk = createOpencodeClient({ baseUrl: `http://${server.hostname}:${server.port}` })
|
|
|
|
|
|
|
|
- if (part.type === "text") {
|
|
|
|
|
- const text = part.text
|
|
|
|
|
- const isPiped = !process.stdout.isTTY
|
|
|
|
|
|
|
+ if (args.command) {
|
|
|
|
|
+ const exists = await Command.get(args.command)
|
|
|
|
|
+ if (!exists) {
|
|
|
|
|
+ server.stop()
|
|
|
|
|
+ UI.error(`Command "${args.command}" not found`)
|
|
|
|
|
+ process.exit(1)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (part.time?.end) {
|
|
|
|
|
- if (outputJsonEvent("text", { part })) return
|
|
|
|
|
- if (!isPiped) UI.println()
|
|
|
|
|
- process.stdout.write((isPiped ? text : UI.markdown(text)) + EOL)
|
|
|
|
|
- if (!isPiped) UI.println()
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const sessionID = await (async () => {
|
|
|
|
|
+ if (args.continue) {
|
|
|
|
|
+ const result = await sdk.session.list()
|
|
|
|
|
+ return result.data?.find((s) => !s.parentID)?.id
|
|
|
}
|
|
}
|
|
|
- })
|
|
|
|
|
|
|
+ if (args.session) return args.session
|
|
|
|
|
|
|
|
- let errorMsg: string | undefined
|
|
|
|
|
- Bus.subscribe(Session.Event.Error, async (evt) => {
|
|
|
|
|
- const { sessionID, error } = evt.properties
|
|
|
|
|
- if (sessionID !== session.id || !error) return
|
|
|
|
|
- let err = String(error.name)
|
|
|
|
|
|
|
+ const title =
|
|
|
|
|
+ args.title !== undefined
|
|
|
|
|
+ ? args.title === ""
|
|
|
|
|
+ ? message.slice(0, 50) + (message.length > 50 ? "..." : "")
|
|
|
|
|
+ : args.title
|
|
|
|
|
+ : undefined
|
|
|
|
|
|
|
|
- if ("data" in error && error.data && "message" in error.data) {
|
|
|
|
|
- err = error.data.message
|
|
|
|
|
- }
|
|
|
|
|
- errorMsg = errorMsg ? errorMsg + EOL + err : err
|
|
|
|
|
|
|
+ const result = await sdk.session.create({ body: title ? { title } : {} })
|
|
|
|
|
+ return result.data?.id
|
|
|
|
|
+ })()
|
|
|
|
|
|
|
|
- if (outputJsonEvent("error", { error })) return
|
|
|
|
|
- UI.error(err)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ if (!sessionID) {
|
|
|
|
|
+ server.stop()
|
|
|
|
|
+ UI.error("Session not found")
|
|
|
|
|
+ process.exit(1)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- Bus.subscribe(Permission.Event.Updated, async (evt) => {
|
|
|
|
|
- const permission = evt.properties
|
|
|
|
|
- const message = `Permission required to run: ${permission.title}`
|
|
|
|
|
-
|
|
|
|
|
- const result = await select({
|
|
|
|
|
- message,
|
|
|
|
|
- options: [
|
|
|
|
|
- { value: "once", label: "Allow once" },
|
|
|
|
|
- { value: "always", label: "Always allow" },
|
|
|
|
|
- { value: "reject", label: "Reject" },
|
|
|
|
|
- ],
|
|
|
|
|
- initialValue: "once",
|
|
|
|
|
- }).catch(() => "reject")
|
|
|
|
|
- const response = (result.toString().includes("cancel") ? "reject" : result) as
|
|
|
|
|
- | "once"
|
|
|
|
|
- | "always"
|
|
|
|
|
- | "reject"
|
|
|
|
|
-
|
|
|
|
|
- Permission.respond({
|
|
|
|
|
- sessionID: session.id,
|
|
|
|
|
- permissionID: permission.id,
|
|
|
|
|
- response,
|
|
|
|
|
|
|
+ const cfgResult = await sdk.config.get()
|
|
|
|
|
+ if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) {
|
|
|
|
|
+ const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => {
|
|
|
|
|
+ if (error instanceof Error && error.message.includes("disabled")) {
|
|
|
|
|
+ UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
|
|
|
|
+ }
|
|
|
|
|
+ return { error }
|
|
|
})
|
|
})
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- await (async () => {
|
|
|
|
|
- if (args.command) {
|
|
|
|
|
- return await SessionPrompt.command({
|
|
|
|
|
- messageID,
|
|
|
|
|
- sessionID: session.id,
|
|
|
|
|
- agent: agent.name,
|
|
|
|
|
- model: providerID + "/" + modelID,
|
|
|
|
|
- command: args.command,
|
|
|
|
|
- arguments: message,
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ if (!shareResult.error) {
|
|
|
|
|
+ UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + sessionID.slice(-8))
|
|
|
}
|
|
}
|
|
|
- return await SessionPrompt.prompt({
|
|
|
|
|
- sessionID: session.id,
|
|
|
|
|
- messageID,
|
|
|
|
|
- model: {
|
|
|
|
|
- providerID,
|
|
|
|
|
- modelID,
|
|
|
|
|
- },
|
|
|
|
|
- agent: agent.name,
|
|
|
|
|
- parts: [
|
|
|
|
|
- ...fileParts,
|
|
|
|
|
- {
|
|
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
- type: "text",
|
|
|
|
|
- text: message,
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- })
|
|
|
|
|
- })()
|
|
|
|
|
- if (errorMsg) process.exit(1)
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await execute(sdk, sessionID)
|
|
|
|
|
+ server.stop()
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
})
|
|
})
|