@suwujs/king-ai 0.2.0
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/README.md +96 -0
- package/dist/src/agent-config-validation.d.ts +9 -0
- package/dist/src/agent-config-validation.js +30 -0
- package/dist/src/api.d.ts +4 -0
- package/dist/src/api.js +48 -0
- package/dist/src/attachments.d.ts +45 -0
- package/dist/src/attachments.js +322 -0
- package/dist/src/cli.d.ts +20 -0
- package/dist/src/cli.js +1697 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +20 -0
- package/dist/src/cron.d.ts +11 -0
- package/dist/src/cron.js +65 -0
- package/dist/src/daemon.d.ts +36 -0
- package/dist/src/daemon.js +373 -0
- package/dist/src/engine.d.ts +32 -0
- package/dist/src/engine.js +1014 -0
- package/dist/src/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat.js +28 -0
- package/dist/src/host-api.d.ts +40 -0
- package/dist/src/host-api.js +59 -0
- package/dist/src/host-control.d.ts +48 -0
- package/dist/src/host-control.js +1279 -0
- package/dist/src/host-export.d.ts +50 -0
- package/dist/src/host-export.js +187 -0
- package/dist/src/host-feedback.d.ts +78 -0
- package/dist/src/host-feedback.js +178 -0
- package/dist/src/host-home.d.ts +13 -0
- package/dist/src/host-home.js +54 -0
- package/dist/src/host-ledger.d.ts +261 -0
- package/dist/src/host-ledger.js +554 -0
- package/dist/src/host-loop-events.d.ts +69 -0
- package/dist/src/host-loop-events.js +288 -0
- package/dist/src/host-permission.d.ts +36 -0
- package/dist/src/host-permission.js +180 -0
- package/dist/src/host-policy.d.ts +15 -0
- package/dist/src/host-policy.js +36 -0
- package/dist/src/host-run-executor.d.ts +13 -0
- package/dist/src/host-run-executor.js +221 -0
- package/dist/src/host-run-heartbeat.d.ts +40 -0
- package/dist/src/host-run-heartbeat.js +103 -0
- package/dist/src/host-run-layout.d.ts +17 -0
- package/dist/src/host-run-layout.js +387 -0
- package/dist/src/host-run-meta.d.ts +41 -0
- package/dist/src/host-run-meta.js +115 -0
- package/dist/src/host-run-spec.d.ts +149 -0
- package/dist/src/host-run-spec.js +465 -0
- package/dist/src/host-runs.d.ts +77 -0
- package/dist/src/host-runs.js +195 -0
- package/dist/src/host-sdk.d.ts +412 -0
- package/dist/src/host-sdk.js +628 -0
- package/dist/src/host-server.d.ts +26 -0
- package/dist/src/host-server.js +921 -0
- package/dist/src/host-timeline.d.ts +24 -0
- package/dist/src/host-timeline.js +161 -0
- package/dist/src/jsonl.d.ts +13 -0
- package/dist/src/jsonl.js +47 -0
- package/dist/src/lifecycle.d.ts +5 -0
- package/dist/src/lifecycle.js +18 -0
- package/dist/src/message-routing.d.ts +32 -0
- package/dist/src/message-routing.js +119 -0
- package/dist/src/paths.d.ts +19 -0
- package/dist/src/paths.js +26 -0
- package/dist/src/project-profile.d.ts +49 -0
- package/dist/src/project-profile.js +356 -0
- package/dist/src/remediation.d.ts +14 -0
- package/dist/src/remediation.js +114 -0
- package/dist/src/remote-devices.d.ts +41 -0
- package/dist/src/remote-devices.js +156 -0
- package/dist/src/remote-diagnostics.d.ts +39 -0
- package/dist/src/remote-diagnostics.js +199 -0
- package/dist/src/remote-ssh.d.ts +39 -0
- package/dist/src/remote-ssh.js +129 -0
- package/dist/src/run-stream.d.ts +57 -0
- package/dist/src/run-stream.js +119 -0
- package/dist/src/runner.d.ts +131 -0
- package/dist/src/runner.js +1161 -0
- package/dist/src/runtime-data.d.ts +68 -0
- package/dist/src/runtime-data.js +172 -0
- package/dist/src/service.d.ts +114 -0
- package/dist/src/service.js +631 -0
- package/dist/src/shared-skills.d.ts +26 -0
- package/dist/src/shared-skills.js +85 -0
- package/dist/src/shim.d.ts +1 -0
- package/dist/src/shim.js +64 -0
- package/dist/src/skill-check.d.ts +17 -0
- package/dist/src/skill-check.js +158 -0
- package/dist/src/sse.d.ts +9 -0
- package/dist/src/sse.js +36 -0
- package/dist/src/team-routing.d.ts +55 -0
- package/dist/src/team-routing.js +131 -0
- package/dist/src/team-workflow.d.ts +78 -0
- package/dist/src/team-workflow.js +253 -0
- package/dist/src/text.d.ts +7 -0
- package/dist/src/text.js +27 -0
- package/dist/src/types.d.ts +98 -0
- package/dist/src/types.js +1 -0
- package/dist/src/usage.d.ts +116 -0
- package/dist/src/usage.js +350 -0
- package/dist/src/workspace.d.ts +9 -0
- package/dist/src/workspace.js +56 -0
- package/dist/src/worktree.d.ts +47 -0
- package/dist/src/worktree.js +201 -0
- package/package.json +63 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { appendHostLoopEvent } from "./host-loop-events.js";
|
|
2
|
+
import { hostRunHeartbeatPathForOutputDir, writeHostRunHeartbeat } from "./host-run-heartbeat.js";
|
|
3
|
+
import { hostRunMetaPathForOutputDir, updateHostRunMeta } from "./host-run-meta.js";
|
|
4
|
+
import { formatHostRunRequestSummary, listHostRunRequests, updateHostRunRequest } from "./host-runs.js";
|
|
5
|
+
import { runHostCommand } from "./host-control.js";
|
|
6
|
+
const EXECUTOR_SAFE_COMMANDS = new Set([
|
|
7
|
+
"status",
|
|
8
|
+
"usage",
|
|
9
|
+
"expenses",
|
|
10
|
+
"events",
|
|
11
|
+
"timeline",
|
|
12
|
+
"policy",
|
|
13
|
+
"doctor",
|
|
14
|
+
"plan-run",
|
|
15
|
+
"preflight",
|
|
16
|
+
"plan-export"
|
|
17
|
+
]);
|
|
18
|
+
export function listSafeHostExecutorCommands() {
|
|
19
|
+
return [...EXECUTOR_SAFE_COMMANDS];
|
|
20
|
+
}
|
|
21
|
+
export async function executeNextHostRunRequest(input = {}, deps = {}) {
|
|
22
|
+
const request = await selectExecutableRequest(input, deps);
|
|
23
|
+
if (!request) {
|
|
24
|
+
return { summary: "no executable host run requests" };
|
|
25
|
+
}
|
|
26
|
+
if (!request.executor) {
|
|
27
|
+
return { request, summary: `host run request ${request.id} has no executor` };
|
|
28
|
+
}
|
|
29
|
+
const command = request.executor.command.trim().toLowerCase();
|
|
30
|
+
if (!EXECUTOR_SAFE_COMMANDS.has(command)) {
|
|
31
|
+
const failed = await updateHostRunRequest({
|
|
32
|
+
id: request.id,
|
|
33
|
+
status: "failed",
|
|
34
|
+
detail: `executor command is not allowed: ${request.executor.command}`,
|
|
35
|
+
result: {
|
|
36
|
+
command: request.executor.command,
|
|
37
|
+
ok: false,
|
|
38
|
+
exitCode: 64,
|
|
39
|
+
error: "executor command is not allowed"
|
|
40
|
+
}
|
|
41
|
+
}, {
|
|
42
|
+
path: deps.runsPath,
|
|
43
|
+
now: deps.now
|
|
44
|
+
});
|
|
45
|
+
await writeRequestHeartbeat(failed.request, "failed", {
|
|
46
|
+
detail: failed.request.detail,
|
|
47
|
+
command: request.executor.command,
|
|
48
|
+
exitCode: 64,
|
|
49
|
+
loopCount: 0,
|
|
50
|
+
now: deps.now
|
|
51
|
+
});
|
|
52
|
+
await writeRequestMeta(failed.request, "failed", {
|
|
53
|
+
detail: failed.request.detail,
|
|
54
|
+
command: request.executor.command,
|
|
55
|
+
exitCode: 64,
|
|
56
|
+
actualLoops: 0,
|
|
57
|
+
now: deps.now
|
|
58
|
+
});
|
|
59
|
+
await writeRequestLoopEvent(failed.request, "failed", {
|
|
60
|
+
detail: failed.request.detail,
|
|
61
|
+
command: request.executor.command,
|
|
62
|
+
exitCode: 64,
|
|
63
|
+
loop: 0,
|
|
64
|
+
now: deps.now
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
request: failed.request,
|
|
68
|
+
summary: failed.summary
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
await updateHostRunRequest({
|
|
72
|
+
id: request.id,
|
|
73
|
+
status: "running",
|
|
74
|
+
detail: `executing ${command}`
|
|
75
|
+
}, {
|
|
76
|
+
path: deps.runsPath,
|
|
77
|
+
now: deps.now
|
|
78
|
+
});
|
|
79
|
+
await writeRequestHeartbeat(request, "running", {
|
|
80
|
+
detail: `executing ${command}`,
|
|
81
|
+
command,
|
|
82
|
+
loopCount: 0,
|
|
83
|
+
now: deps.now
|
|
84
|
+
});
|
|
85
|
+
await writeRequestMeta(request, "running", {
|
|
86
|
+
detail: `executing ${command}`,
|
|
87
|
+
command,
|
|
88
|
+
actualLoops: 0,
|
|
89
|
+
now: deps.now
|
|
90
|
+
});
|
|
91
|
+
await writeRequestLoopEvent(request, "running", {
|
|
92
|
+
detail: `executing ${command}`,
|
|
93
|
+
command,
|
|
94
|
+
loop: 0,
|
|
95
|
+
now: deps.now
|
|
96
|
+
});
|
|
97
|
+
const commandResult = await runHostCommand({
|
|
98
|
+
command,
|
|
99
|
+
format: request.executor.format,
|
|
100
|
+
input: request.executor.input,
|
|
101
|
+
actorRole: request.executor.actorRole
|
|
102
|
+
}, {
|
|
103
|
+
...deps,
|
|
104
|
+
recordTimeline: deps.recordTimeline ?? true,
|
|
105
|
+
enforcePermission: request.executor.trusted === true ? false : deps.enforcePermission
|
|
106
|
+
});
|
|
107
|
+
const completed = await updateHostRunRequest({
|
|
108
|
+
id: request.id,
|
|
109
|
+
status: commandResult.ok ? "completed" : "failed",
|
|
110
|
+
detail: commandResult.ok ? `completed ${command}` : `failed ${command}`,
|
|
111
|
+
result: {
|
|
112
|
+
command,
|
|
113
|
+
ok: commandResult.ok,
|
|
114
|
+
exitCode: commandResult.exitCode,
|
|
115
|
+
textPreview: compact(commandResult.text),
|
|
116
|
+
error: commandResult.error
|
|
117
|
+
}
|
|
118
|
+
}, {
|
|
119
|
+
path: deps.runsPath,
|
|
120
|
+
now: deps.now
|
|
121
|
+
});
|
|
122
|
+
await writeRequestHeartbeat(completed.request, commandResult.ok ? "completed" : "failed", {
|
|
123
|
+
detail: completed.request.detail,
|
|
124
|
+
command,
|
|
125
|
+
exitCode: commandResult.exitCode,
|
|
126
|
+
loopCount: 1,
|
|
127
|
+
now: deps.now
|
|
128
|
+
});
|
|
129
|
+
await writeRequestMeta(completed.request, commandResult.ok ? "completed" : "failed", {
|
|
130
|
+
detail: completed.request.detail,
|
|
131
|
+
command,
|
|
132
|
+
exitCode: commandResult.exitCode,
|
|
133
|
+
actualLoops: 1,
|
|
134
|
+
now: deps.now
|
|
135
|
+
});
|
|
136
|
+
await writeRequestLoopEvent(completed.request, commandResult.ok ? "completed" : "failed", {
|
|
137
|
+
detail: completed.request.detail,
|
|
138
|
+
command,
|
|
139
|
+
exitCode: commandResult.exitCode,
|
|
140
|
+
loop: 1,
|
|
141
|
+
now: deps.now
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
request: completed.request,
|
|
145
|
+
commandResult,
|
|
146
|
+
summary: completed.summary
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function writeRequestMeta(request, status, input) {
|
|
150
|
+
const outputDir = request.spec.options?.outputDir;
|
|
151
|
+
if (!outputDir)
|
|
152
|
+
return;
|
|
153
|
+
await updateHostRunMeta({
|
|
154
|
+
file: hostRunMetaPathForOutputDir(outputDir),
|
|
155
|
+
runId: request.id,
|
|
156
|
+
status,
|
|
157
|
+
actualLoops: input.actualLoops,
|
|
158
|
+
detail: input.detail,
|
|
159
|
+
command: input.command,
|
|
160
|
+
exitCode: input.exitCode,
|
|
161
|
+
now: input.now
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async function writeRequestLoopEvent(request, status, input) {
|
|
165
|
+
const outputDir = request.spec.options?.outputDir;
|
|
166
|
+
if (!outputDir)
|
|
167
|
+
return;
|
|
168
|
+
await appendHostLoopEvent({
|
|
169
|
+
outputDir,
|
|
170
|
+
event: {
|
|
171
|
+
type: "run.status",
|
|
172
|
+
runId: request.id,
|
|
173
|
+
timestamp: (input.now ?? (() => new Date()))().toISOString(),
|
|
174
|
+
status,
|
|
175
|
+
detail: input.detail,
|
|
176
|
+
command: input.command,
|
|
177
|
+
exitCode: input.exitCode,
|
|
178
|
+
loop: input.loop,
|
|
179
|
+
source: "execute-run"
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
export function formatHostRunExecuteResult(result) {
|
|
184
|
+
if (!result.request)
|
|
185
|
+
return result.summary;
|
|
186
|
+
return [
|
|
187
|
+
result.summary,
|
|
188
|
+
result.commandResult ? `command: ${result.commandResult.command} exit=${result.commandResult.exitCode}` : "",
|
|
189
|
+
formatHostRunRequestSummary(result.request)
|
|
190
|
+
].filter(Boolean).join("\n");
|
|
191
|
+
}
|
|
192
|
+
async function selectExecutableRequest(input, deps) {
|
|
193
|
+
const requests = await listHostRunRequests({ limit: 100, status: "pending" }, deps.runsPath);
|
|
194
|
+
const oldestFirst = [...requests].reverse();
|
|
195
|
+
if (input.id)
|
|
196
|
+
return oldestFirst.find((request) => request.id === input.id);
|
|
197
|
+
return oldestFirst.find((request) => request.executor?.kind === "host-command");
|
|
198
|
+
}
|
|
199
|
+
function compact(value) {
|
|
200
|
+
const text = value.replace(/\s+/g, " ").trim();
|
|
201
|
+
if (!text)
|
|
202
|
+
return undefined;
|
|
203
|
+
return text.length > 240 ? `${text.slice(0, 237)}...` : text;
|
|
204
|
+
}
|
|
205
|
+
async function writeRequestHeartbeat(request, status, input) {
|
|
206
|
+
const outputDir = request.spec.options?.outputDir;
|
|
207
|
+
if (!outputDir)
|
|
208
|
+
return;
|
|
209
|
+
await writeHostRunHeartbeat({
|
|
210
|
+
path: hostRunHeartbeatPathForOutputDir(outputDir),
|
|
211
|
+
runId: request.id,
|
|
212
|
+
status,
|
|
213
|
+
outputDir,
|
|
214
|
+
pid: process.pid,
|
|
215
|
+
detail: input.detail,
|
|
216
|
+
command: input.command,
|
|
217
|
+
exitCode: input.exitCode,
|
|
218
|
+
loopCount: input.loopCount,
|
|
219
|
+
now: input.now
|
|
220
|
+
});
|
|
221
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type HostRunHeartbeatStatus = "prepared" | "running" | "completed" | "failed" | "cancelled";
|
|
2
|
+
export interface HostRunHeartbeatData {
|
|
3
|
+
schema: "king-ai.host-run-heartbeat.v1";
|
|
4
|
+
status: HostRunHeartbeatStatus;
|
|
5
|
+
runId: string;
|
|
6
|
+
lastTick: string;
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
loopCount: number;
|
|
9
|
+
outputDir?: string;
|
|
10
|
+
pid?: number;
|
|
11
|
+
detail?: string;
|
|
12
|
+
command?: string;
|
|
13
|
+
exitCode?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface HostRunHeartbeatInput {
|
|
16
|
+
path: string;
|
|
17
|
+
runId: string;
|
|
18
|
+
status: HostRunHeartbeatStatus;
|
|
19
|
+
outputDir?: string;
|
|
20
|
+
loopCount?: number;
|
|
21
|
+
pid?: number;
|
|
22
|
+
detail?: string;
|
|
23
|
+
command?: string;
|
|
24
|
+
exitCode?: number;
|
|
25
|
+
now?: () => Date;
|
|
26
|
+
}
|
|
27
|
+
export interface HostRunHeartbeatReadInput {
|
|
28
|
+
file?: string;
|
|
29
|
+
outputDir?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface HostRunHeartbeatReadResult {
|
|
32
|
+
file: string;
|
|
33
|
+
heartbeat: HostRunHeartbeatData | null;
|
|
34
|
+
exists: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function hostRunHeartbeatPathForOutputDir(outputDir: string): string;
|
|
37
|
+
export declare function resolveHostRunHeartbeatPath(input?: HostRunHeartbeatReadInput): string;
|
|
38
|
+
export declare function readHostRunHeartbeat(input?: HostRunHeartbeatReadInput): Promise<HostRunHeartbeatReadResult>;
|
|
39
|
+
export declare function formatHostRunHeartbeat(result: HostRunHeartbeatReadResult): string;
|
|
40
|
+
export declare function writeHostRunHeartbeat(input: HostRunHeartbeatInput): Promise<HostRunHeartbeatData>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
export function hostRunHeartbeatPathForOutputDir(outputDir) {
|
|
4
|
+
return join(resolve(outputDir), ".king-ai", "heartbeat.json");
|
|
5
|
+
}
|
|
6
|
+
export function resolveHostRunHeartbeatPath(input = {}) {
|
|
7
|
+
if (input.file && input.file.trim())
|
|
8
|
+
return resolve(input.file);
|
|
9
|
+
const outputDir = input.outputDir && input.outputDir.trim() ? input.outputDir : "deliverables";
|
|
10
|
+
return hostRunHeartbeatPathForOutputDir(outputDir);
|
|
11
|
+
}
|
|
12
|
+
export async function readHostRunHeartbeat(input = {}) {
|
|
13
|
+
const file = resolveHostRunHeartbeatPath(input);
|
|
14
|
+
const text = await readFile(file, "utf8").catch((err) => {
|
|
15
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT")
|
|
16
|
+
return undefined;
|
|
17
|
+
throw err;
|
|
18
|
+
});
|
|
19
|
+
if (text === undefined) {
|
|
20
|
+
return {
|
|
21
|
+
file,
|
|
22
|
+
heartbeat: null,
|
|
23
|
+
exists: false
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
file,
|
|
28
|
+
heartbeat: parseHostRunHeartbeat(text),
|
|
29
|
+
exists: true
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function formatHostRunHeartbeat(result) {
|
|
33
|
+
if (!result.heartbeat)
|
|
34
|
+
return `host run heartbeat: ${result.file}\nnot found`;
|
|
35
|
+
return [
|
|
36
|
+
`host run heartbeat: ${result.file}`,
|
|
37
|
+
`run: ${result.heartbeat.runId}`,
|
|
38
|
+
`status: ${result.heartbeat.status}`,
|
|
39
|
+
`last tick: ${result.heartbeat.lastTick}`,
|
|
40
|
+
`loops: ${result.heartbeat.loopCount}`,
|
|
41
|
+
result.heartbeat.command ? `command: ${result.heartbeat.command}${result.heartbeat.exitCode !== undefined ? ` exit=${result.heartbeat.exitCode}` : ""}` : "",
|
|
42
|
+
result.heartbeat.detail ? `detail: ${result.heartbeat.detail}` : ""
|
|
43
|
+
].filter(Boolean).join("\n");
|
|
44
|
+
}
|
|
45
|
+
export async function writeHostRunHeartbeat(input) {
|
|
46
|
+
const now = (input.now ?? (() => new Date()))().toISOString();
|
|
47
|
+
const data = {
|
|
48
|
+
schema: "king-ai.host-run-heartbeat.v1",
|
|
49
|
+
status: input.status,
|
|
50
|
+
runId: input.runId,
|
|
51
|
+
lastTick: now,
|
|
52
|
+
updatedAt: now,
|
|
53
|
+
loopCount: Math.max(0, Math.floor(input.loopCount ?? 0)),
|
|
54
|
+
outputDir: input.outputDir,
|
|
55
|
+
pid: input.pid,
|
|
56
|
+
detail: cleanString(input.detail),
|
|
57
|
+
command: cleanString(input.command),
|
|
58
|
+
exitCode: normalizeExitCode(input.exitCode)
|
|
59
|
+
};
|
|
60
|
+
await mkdir(dirname(input.path), { recursive: true });
|
|
61
|
+
await writeFile(input.path, `${JSON.stringify(dropUndefined({ ...data }), null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
function cleanString(value) {
|
|
65
|
+
return typeof value === "string" && value.trim() ? value.trim().slice(0, 1000) : undefined;
|
|
66
|
+
}
|
|
67
|
+
function normalizeExitCode(value) {
|
|
68
|
+
if (value === undefined)
|
|
69
|
+
return undefined;
|
|
70
|
+
const parsed = Number(value);
|
|
71
|
+
return Number.isFinite(parsed) ? Math.floor(parsed) : undefined;
|
|
72
|
+
}
|
|
73
|
+
function parseHostRunHeartbeat(text) {
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(text);
|
|
76
|
+
if (!parsed || parsed.schema !== "king-ai.host-run-heartbeat.v1" || typeof parsed.runId !== "string")
|
|
77
|
+
return null;
|
|
78
|
+
if (!isHostRunHeartbeatStatus(parsed.status))
|
|
79
|
+
return null;
|
|
80
|
+
return {
|
|
81
|
+
schema: "king-ai.host-run-heartbeat.v1",
|
|
82
|
+
status: parsed.status,
|
|
83
|
+
runId: parsed.runId,
|
|
84
|
+
lastTick: typeof parsed.lastTick === "string" ? parsed.lastTick : "",
|
|
85
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : "",
|
|
86
|
+
loopCount: typeof parsed.loopCount === "number" ? parsed.loopCount : 0,
|
|
87
|
+
outputDir: typeof parsed.outputDir === "string" ? parsed.outputDir : undefined,
|
|
88
|
+
pid: typeof parsed.pid === "number" ? parsed.pid : undefined,
|
|
89
|
+
detail: typeof parsed.detail === "string" ? parsed.detail : undefined,
|
|
90
|
+
command: typeof parsed.command === "string" ? parsed.command : undefined,
|
|
91
|
+
exitCode: typeof parsed.exitCode === "number" ? parsed.exitCode : undefined
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function isHostRunHeartbeatStatus(value) {
|
|
99
|
+
return value === "prepared" || value === "running" || value === "completed" || value === "failed" || value === "cancelled";
|
|
100
|
+
}
|
|
101
|
+
function dropUndefined(value) {
|
|
102
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
103
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HostLaunchPlan, HostRunSpecInput } from "./host-run-spec.js";
|
|
2
|
+
import { toJsonSafeHostLaunchPlan } from "./host-run-spec.js";
|
|
3
|
+
export interface HostRunLayoutInput extends HostRunSpecInput {
|
|
4
|
+
force?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface HostRunLayoutResult {
|
|
7
|
+
launchPlan: ReturnType<typeof toJsonSafeHostLaunchPlan>;
|
|
8
|
+
writtenFiles: string[];
|
|
9
|
+
copiedDirectories: string[];
|
|
10
|
+
summary: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function prepareHostRunLayout(input: HostRunLayoutInput, options?: {
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
availableEngines?: Array<"claude" | "codex">;
|
|
15
|
+
}): Promise<HostRunLayoutResult>;
|
|
16
|
+
export declare function formatHostRunLayoutResult(plan: HostLaunchPlan, writtenFiles: string[], copiedDirectories: string[]): string;
|
|
17
|
+
export declare function createDefaultHostRunConfigText(plan: HostLaunchPlan): string;
|