refactor(core): replace bash tool with shell tool

This commit is contained in:
Dax Raad 2026-06-29 00:43:04 -04:00
commit 5ae93092aa
37 changed files with 2260 additions and 901 deletions

View file

@ -385,6 +385,16 @@ import type {
V2SessionSwitchModelResponses,
V2SessionWaitErrors,
V2SessionWaitResponses,
V2ShellCreateErrors,
V2ShellCreateResponses,
V2ShellGetErrors,
V2ShellGetResponses,
V2ShellListErrors,
V2ShellListResponses,
V2ShellOutputErrors,
V2ShellOutputResponses,
V2ShellRemoveErrors,
V2ShellRemoveResponses,
V2SkillListErrors,
V2SkillListResponses,
VcsApplyErrors,
@ -6849,6 +6859,179 @@ export class Pty2 extends HeyApiClient {
}
}
export class Shell extends HeyApiClient {
/**
* List running shell commands
*
* List currently running shell commands for a location. Exited commands are not included.
*/
public list<ThrowOnError extends boolean = false>(
parameters?: {
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }])
return (options?.client ?? this.client).get<V2ShellListResponses, V2ShellListErrors, ThrowOnError>({
url: "/api/shell",
...options,
...params,
})
}
/**
* Run shell command
*
* Spawn one non-interactive shell command for a location. Combined stdout/stderr is captured to a file pageable via output.
*/
public create<ThrowOnError extends boolean = false>(
parameters?: {
location?: {
directory?: string
workspace?: string
}
command?: string
cwd?: string
timeout?: number
metadata?: {
[key: string]: unknown
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "query", key: "location" },
{ in: "body", key: "command" },
{ in: "body", key: "cwd" },
{ in: "body", key: "timeout" },
{ in: "body", key: "metadata" },
],
},
],
)
return (options?.client ?? this.client).post<V2ShellCreateResponses, V2ShellCreateErrors, ThrowOnError>({
url: "/api/shell",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
/**
* Remove shell command
*
* Terminate and remove one shell command and its retained output.
*/
public remove<ThrowOnError extends boolean = false>(
parameters: {
id: string
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "id" },
{ in: "query", key: "location" },
],
},
],
)
return (options?.client ?? this.client).delete<V2ShellRemoveResponses, V2ShellRemoveErrors, ThrowOnError>({
url: "/api/shell/{id}",
...options,
...params,
})
}
/**
* Get shell command
*
* Get one shell command, including its status and exit code once exited.
*/
public get<ThrowOnError extends boolean = false>(
parameters: {
id: string
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "id" },
{ in: "query", key: "location" },
],
},
],
)
return (options?.client ?? this.client).get<V2ShellGetResponses, V2ShellGetErrors, ThrowOnError>({
url: "/api/shell/{id}",
...options,
...params,
})
}
/**
* Read shell output
*
* Page through captured combined output by absolute byte cursor.
*/
public output<ThrowOnError extends boolean = false>(
parameters: {
id: string
location?: {
directory?: string
workspace?: string
}
cursor?: string
limit?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "id" },
{ in: "query", key: "location" },
{ in: "query", key: "cursor" },
{ in: "query", key: "limit" },
],
},
],
)
return (options?.client ?? this.client).get<V2ShellOutputResponses, V2ShellOutputErrors, ThrowOnError>({
url: "/api/shell/{id}/output",
...options,
...params,
})
}
}
export class Request2 extends HeyApiClient {
/**
* List pending question requests
@ -7095,6 +7278,11 @@ export class V2 extends HeyApiClient {
return (this._pty ??= new Pty2({ client: this.client }))
}
private _shell?: Shell
get shell(): Shell {
return (this._shell ??= new Shell({ client: this.client }))
}
private _question?: Question3
get question(): Question3 {
return (this._question ??= new Question3({ client: this.client }))

View file

@ -65,6 +65,9 @@ export type Event =
| EventPtyUpdated
| EventPtyExited
| EventPtyDeleted
| EventShellCreated
| EventShellExited
| EventShellDeleted
| EventQuestionV2Asked
| EventQuestionV2Replied
| EventQuestionV2Rejected
@ -643,6 +646,7 @@ export type Prompt = {
text: string
files?: Array<PromptFileAttachment>
agents?: Array<PromptAgentAttachment>
system?: string
}
export type Pty = {
@ -656,6 +660,24 @@ export type Pty = {
exitCode?: number
}
export type Shell = {
id: string
status: "running" | "exited" | "timeout" | "killed"
command: string
cwd: string
shell: string
file: string
pid?: number
exit?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
metadata: {
[key: string]: unknown
}
time: {
started: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
completed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
}
}
export type Todo = {
/**
* Brief description of the task
@ -1338,6 +1360,29 @@ export type GlobalEvent = {
id: string
}
}
| {
id: string
type: "shell.created"
properties: {
info: Shell
}
}
| {
id: string
type: "shell.exited"
properties: {
id: string
exit?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
status: "running" | "exited" | "timeout" | "killed"
}
}
| {
id: string
type: "shell.deleted"
properties: {
id: string
}
}
| {
id: string
type: "question.v2.asked"
@ -2715,6 +2760,7 @@ export type PromptInput = {
text: string
files?: Array<PromptInputFileAttachment>
agents?: Array<PromptAgentAttachment>
system?: string
}
export type ConflictError = {
@ -2804,6 +2850,24 @@ export type OutputFormat1 =
retryCount?: number
}
export type Shell1 = {
id: string
status: "running" | "exited" | "timeout" | "killed"
command: string
cwd: string
shell: string
file: string
pid?: number
exit?: number | "NaN" | "Infinity" | "-Infinity"
metadata: {
[key: string]: unknown
}
time: {
started: number | "NaN" | "Infinity" | "-Infinity"
completed?: number | "NaN" | "Infinity" | "-Infinity"
}
}
export type SessionStatus2 = {
id: string
metadata?: {
@ -2920,6 +2984,9 @@ export type V2Event =
| PtyUpdated
| PtyExited
| PtyDeleted
| ShellCreated
| ShellExited
| ShellDeleted
| QuestionV2Asked
| QuestionV2Replied
| QuestionV2Rejected
@ -2957,6 +3024,12 @@ export type ForbiddenError = {
message: string
}
export type ShellNotFoundError = {
_tag: "ShellNotFoundError"
id: string
message: string
}
export type ProjectCopyError = {
name: "ProjectCopyError"
data: {
@ -2969,6 +3042,24 @@ export type EffectHttpApiErrorForbidden = {
_tag: "Forbidden"
}
export type Shell2 = {
id: string
status: "running" | "exited" | "timeout" | "killed"
command: string
cwd: string
shell: string
file: string
pid?: number
exit?: number | "NaN" | "Infinity" | "-Infinity"
metadata: {
[key: string]: unknown
}
time: {
started: number | "NaN" | "Infinity" | "-Infinity"
completed?: number | "NaN" | "Infinity" | "-Infinity"
}
}
export type EventTuiPromptAppend2 = {
id: string
type: "tui.prompt.append"
@ -4005,6 +4096,7 @@ export type SessionMessageUser = {
text: string
files?: Array<PromptFileAttachment>
agents?: Array<PromptAgentAttachment>
system?: string
type: "user"
}
@ -5641,6 +5733,59 @@ export type PtyDeleted = {
}
}
export type ShellCreated = {
id: string
metadata?: {
[key: string]: unknown
}
type: "shell.created"
durable?: {
aggregateID: string
seq: number
version: number
}
location?: LocationRef
data: {
info: Shell1
}
}
export type ShellExited = {
id: string
metadata?: {
[key: string]: unknown
}
type: "shell.exited"
durable?: {
aggregateID: string
seq: number
version: number
}
location?: LocationRef
data: {
id: string
exit?: number | "NaN" | "Infinity" | "-Infinity"
status: "running" | "exited" | "timeout" | "killed"
}
}
export type ShellDeleted = {
id: string
metadata?: {
[key: string]: unknown
}
type: "shell.deleted"
durable?: {
aggregateID: string
seq: number
version: number
}
location?: LocationRef
data: {
id: string
}
}
export type QuestionV2Asked = {
id: string
metadata?: {
@ -6859,6 +7004,32 @@ export type EventPtyDeleted = {
}
}
export type EventShellCreated = {
id: string
type: "shell.created"
properties: {
info: Shell2
}
}
export type EventShellExited = {
id: string
type: "shell.exited"
properties: {
id: string
exit?: number | "NaN" | "Infinity" | "-Infinity"
status: "running" | "exited" | "timeout" | "killed"
}
}
export type EventShellDeleted = {
id: string
type: "shell.deleted"
properties: {
id: string
}
}
export type EventQuestionV2Asked = {
id: string
type: "question.v2.asked"
@ -13409,6 +13580,220 @@ export type V2PtyConnectResponses = {
export type V2PtyConnectResponse = V2PtyConnectResponses[keyof V2PtyConnectResponses]
export type V2ShellListData = {
body?: never
path?: never
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/shell"
}
export type V2ShellListErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
}
export type V2ShellListError = V2ShellListErrors[keyof V2ShellListErrors]
export type V2ShellListResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: Array<Shell>
}
}
export type V2ShellListResponse = V2ShellListResponses[keyof V2ShellListResponses]
export type V2ShellCreateData = {
body: {
command: string
cwd?: string
timeout?: number
metadata?: {
[key: string]: unknown
}
}
path?: never
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/shell"
}
export type V2ShellCreateErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
}
export type V2ShellCreateError = V2ShellCreateErrors[keyof V2ShellCreateErrors]
export type V2ShellCreateResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: Shell
}
}
export type V2ShellCreateResponse = V2ShellCreateResponses[keyof V2ShellCreateResponses]
export type V2ShellRemoveData = {
body?: never
path: {
id: string
}
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/shell/{id}"
}
export type V2ShellRemoveErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
/**
* ShellNotFoundError
*/
404: ShellNotFoundError
}
export type V2ShellRemoveError = V2ShellRemoveErrors[keyof V2ShellRemoveErrors]
export type V2ShellRemoveResponses = {
/**
* <No Content>
*/
204: void
}
export type V2ShellRemoveResponse = V2ShellRemoveResponses[keyof V2ShellRemoveResponses]
export type V2ShellGetData = {
body?: never
path: {
id: string
}
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/shell/{id}"
}
export type V2ShellGetErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
/**
* ShellNotFoundError
*/
404: ShellNotFoundError
}
export type V2ShellGetError = V2ShellGetErrors[keyof V2ShellGetErrors]
export type V2ShellGetResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: Shell
}
}
export type V2ShellGetResponse = V2ShellGetResponses[keyof V2ShellGetResponses]
export type V2ShellOutputData = {
body?: never
path: {
id: string
}
query?: {
location?: {
directory?: string
workspace?: string
}
cursor?: string
limit?: string
}
url: "/api/shell/{id}/output"
}
export type V2ShellOutputErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
/**
* ShellNotFoundError
*/
404: ShellNotFoundError
}
export type V2ShellOutputError = V2ShellOutputErrors[keyof V2ShellOutputErrors]
export type V2ShellOutputResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: {
output: string
cursor: number
size: number
truncated: boolean
}
}
}
export type V2ShellOutputResponse = V2ShellOutputResponses[keyof V2ShellOutputResponses]
export type V2QuestionRequestListData = {
body?: never
path?: never