@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.
Files changed (104) hide show
  1. package/README.md +96 -0
  2. package/dist/src/agent-config-validation.d.ts +9 -0
  3. package/dist/src/agent-config-validation.js +30 -0
  4. package/dist/src/api.d.ts +4 -0
  5. package/dist/src/api.js +48 -0
  6. package/dist/src/attachments.d.ts +45 -0
  7. package/dist/src/attachments.js +322 -0
  8. package/dist/src/cli.d.ts +20 -0
  9. package/dist/src/cli.js +1697 -0
  10. package/dist/src/config.d.ts +3 -0
  11. package/dist/src/config.js +20 -0
  12. package/dist/src/cron.d.ts +11 -0
  13. package/dist/src/cron.js +65 -0
  14. package/dist/src/daemon.d.ts +36 -0
  15. package/dist/src/daemon.js +373 -0
  16. package/dist/src/engine.d.ts +32 -0
  17. package/dist/src/engine.js +1014 -0
  18. package/dist/src/heartbeat.d.ts +18 -0
  19. package/dist/src/heartbeat.js +28 -0
  20. package/dist/src/host-api.d.ts +40 -0
  21. package/dist/src/host-api.js +59 -0
  22. package/dist/src/host-control.d.ts +48 -0
  23. package/dist/src/host-control.js +1279 -0
  24. package/dist/src/host-export.d.ts +50 -0
  25. package/dist/src/host-export.js +187 -0
  26. package/dist/src/host-feedback.d.ts +78 -0
  27. package/dist/src/host-feedback.js +178 -0
  28. package/dist/src/host-home.d.ts +13 -0
  29. package/dist/src/host-home.js +54 -0
  30. package/dist/src/host-ledger.d.ts +261 -0
  31. package/dist/src/host-ledger.js +554 -0
  32. package/dist/src/host-loop-events.d.ts +69 -0
  33. package/dist/src/host-loop-events.js +288 -0
  34. package/dist/src/host-permission.d.ts +36 -0
  35. package/dist/src/host-permission.js +180 -0
  36. package/dist/src/host-policy.d.ts +15 -0
  37. package/dist/src/host-policy.js +36 -0
  38. package/dist/src/host-run-executor.d.ts +13 -0
  39. package/dist/src/host-run-executor.js +221 -0
  40. package/dist/src/host-run-heartbeat.d.ts +40 -0
  41. package/dist/src/host-run-heartbeat.js +103 -0
  42. package/dist/src/host-run-layout.d.ts +17 -0
  43. package/dist/src/host-run-layout.js +387 -0
  44. package/dist/src/host-run-meta.d.ts +41 -0
  45. package/dist/src/host-run-meta.js +115 -0
  46. package/dist/src/host-run-spec.d.ts +149 -0
  47. package/dist/src/host-run-spec.js +465 -0
  48. package/dist/src/host-runs.d.ts +77 -0
  49. package/dist/src/host-runs.js +195 -0
  50. package/dist/src/host-sdk.d.ts +412 -0
  51. package/dist/src/host-sdk.js +628 -0
  52. package/dist/src/host-server.d.ts +26 -0
  53. package/dist/src/host-server.js +921 -0
  54. package/dist/src/host-timeline.d.ts +24 -0
  55. package/dist/src/host-timeline.js +161 -0
  56. package/dist/src/jsonl.d.ts +13 -0
  57. package/dist/src/jsonl.js +47 -0
  58. package/dist/src/lifecycle.d.ts +5 -0
  59. package/dist/src/lifecycle.js +18 -0
  60. package/dist/src/message-routing.d.ts +32 -0
  61. package/dist/src/message-routing.js +119 -0
  62. package/dist/src/paths.d.ts +19 -0
  63. package/dist/src/paths.js +26 -0
  64. package/dist/src/project-profile.d.ts +49 -0
  65. package/dist/src/project-profile.js +356 -0
  66. package/dist/src/remediation.d.ts +14 -0
  67. package/dist/src/remediation.js +114 -0
  68. package/dist/src/remote-devices.d.ts +41 -0
  69. package/dist/src/remote-devices.js +156 -0
  70. package/dist/src/remote-diagnostics.d.ts +39 -0
  71. package/dist/src/remote-diagnostics.js +199 -0
  72. package/dist/src/remote-ssh.d.ts +39 -0
  73. package/dist/src/remote-ssh.js +129 -0
  74. package/dist/src/run-stream.d.ts +57 -0
  75. package/dist/src/run-stream.js +119 -0
  76. package/dist/src/runner.d.ts +131 -0
  77. package/dist/src/runner.js +1161 -0
  78. package/dist/src/runtime-data.d.ts +68 -0
  79. package/dist/src/runtime-data.js +172 -0
  80. package/dist/src/service.d.ts +114 -0
  81. package/dist/src/service.js +631 -0
  82. package/dist/src/shared-skills.d.ts +26 -0
  83. package/dist/src/shared-skills.js +85 -0
  84. package/dist/src/shim.d.ts +1 -0
  85. package/dist/src/shim.js +64 -0
  86. package/dist/src/skill-check.d.ts +17 -0
  87. package/dist/src/skill-check.js +158 -0
  88. package/dist/src/sse.d.ts +9 -0
  89. package/dist/src/sse.js +36 -0
  90. package/dist/src/team-routing.d.ts +55 -0
  91. package/dist/src/team-routing.js +131 -0
  92. package/dist/src/team-workflow.d.ts +78 -0
  93. package/dist/src/team-workflow.js +253 -0
  94. package/dist/src/text.d.ts +7 -0
  95. package/dist/src/text.js +27 -0
  96. package/dist/src/types.d.ts +98 -0
  97. package/dist/src/types.js +1 -0
  98. package/dist/src/usage.d.ts +116 -0
  99. package/dist/src/usage.js +350 -0
  100. package/dist/src/workspace.d.ts +9 -0
  101. package/dist/src/workspace.js +56 -0
  102. package/dist/src/worktree.d.ts +47 -0
  103. package/dist/src/worktree.js +201 -0
  104. 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;