@companyhelm/cli 0.0.2 → 0.0.6

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 (47) hide show
  1. package/README.md +24 -62
  2. package/RUNTIME_IMAGE_VERSION +1 -1
  3. package/dist/cli.js +29 -1
  4. package/dist/commands/register-commands.js +2 -0
  5. package/dist/commands/root.js +341 -20
  6. package/dist/commands/startup.js +138 -55
  7. package/dist/commands/status.js +32 -0
  8. package/dist/service/app_server.js +23 -9
  9. package/dist/service/docker/app_server_container.js +3 -1
  10. package/dist/service/thread_lifecycle.js +4 -1
  11. package/dist/state/daemon_state.js +83 -0
  12. package/dist/state/schema.js +9 -1
  13. package/dist/templates/app_server_bootstrap.sh.j2 +46 -0
  14. package/dist/templates/runtime_agents.md.j2 +50 -0
  15. package/dist/templates/runtime_bashrc.j2 +19 -0
  16. package/dist/utils/daemon.js +15 -0
  17. package/dist/utils/process.js +22 -0
  18. package/drizzle/0011_actual_lucky.sql +7 -0
  19. package/drizzle/meta/_journal.json +8 -1
  20. package/package.json +7 -3
  21. package/dist/commands/agent/index.js +0 -10
  22. package/dist/commands/agent/list.js +0 -31
  23. package/dist/commands/agent/register-agent-commands.js +0 -10
  24. package/dist/commands/index.js +0 -15
  25. package/dist/commands/sdk/index.js +0 -12
  26. package/dist/commands/thread/index.js +0 -12
  27. package/dist/config/local.js +0 -1
  28. package/dist/config/schema.js +0 -7
  29. package/dist/model.js +0 -22
  30. package/dist/schema.js +0 -47
  31. package/dist/service/docker/docker_provider.js +0 -1
  32. package/dist/service/docker/runtime_container.js +0 -1
  33. package/dist/service/docker/runtime_image.js +0 -40
  34. package/dist/startup.js +0 -166
  35. package/dist/state/service/app_server.js +0 -392
  36. package/dist/state/service/buffered_client_message_sender.js +0 -73
  37. package/dist/state/service/companyhelm_api_client.js +0 -316
  38. package/dist/state/service/docker/app_server_container.js +0 -165
  39. package/dist/state/service/docker/dind.js +0 -114
  40. package/dist/state/service/docker/runtime_app_server_exec.js +0 -95
  41. package/dist/state/service/host.js +0 -15
  42. package/dist/state/service/runtime_shell.js +0 -23
  43. package/dist/state/service/sdk/refresh_models.js +0 -83
  44. package/dist/state/service/thread_lifecycle.js +0 -327
  45. package/dist/state/service/thread_runtime.js +0 -11
  46. package/dist/state/service/thread_turn_state.js +0 -45
  47. package/dist/state/service/workspace_agents.js +0 -115
@@ -1,392 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AppServerService = void 0;
4
- const async_queue_js_1 = require("../utils/async_queue.js");
5
- const NOOP_APP_SERVER_LOGGER = { debug: () => undefined };
6
- class AppServerTimeoutError extends Error {
7
- constructor(message) {
8
- super(message);
9
- this.name = "AppServerTimeoutError";
10
- }
11
- }
12
- function hasTag(message) {
13
- return typeof message === "object" && message !== null && "type" in message;
14
- }
15
- function isResponseMessage(message) {
16
- return (typeof message === "object" &&
17
- message !== null &&
18
- "id" in message &&
19
- !("method" in message) &&
20
- !("type" in message));
21
- }
22
- function isServerNotificationMessage(message) {
23
- return (typeof message === "object" &&
24
- message !== null &&
25
- "method" in message &&
26
- "params" in message);
27
- }
28
- function formatUnknownError(value) {
29
- if (value instanceof Error) {
30
- return value.message;
31
- }
32
- try {
33
- return JSON.stringify(value);
34
- }
35
- catch {
36
- return String(value);
37
- }
38
- }
39
- function isModelListResponse(value) {
40
- if (typeof value !== "object" || value === null) {
41
- return false;
42
- }
43
- const data = value.data;
44
- const nextCursor = value.nextCursor;
45
- return Array.isArray(data) && (typeof nextCursor === "string" || nextCursor === null);
46
- }
47
- function isJsonObject(value) {
48
- return typeof value === "object" && value !== null && !Array.isArray(value);
49
- }
50
- function hasMessageShape(value) {
51
- return isJsonObject(value) && ("method" in value || "id" in value || "result" in value || "error" in value);
52
- }
53
- class AppServerService {
54
- constructor(transport, clientName, logger) {
55
- this.stream = null;
56
- this.pumpTask = null;
57
- this.messageQueue = new async_queue_js_1.AsyncQueue();
58
- this.pendingRequests = new Map();
59
- this.pendingResponses = new Map();
60
- this.nextRequestId = 1;
61
- this.stderrLines = [];
62
- this.stdoutBuffer = Buffer.alloc(0);
63
- this.framing = "unknown";
64
- this.transport = transport;
65
- this.clientName = clientName;
66
- this.logger = logger ?? NOOP_APP_SERVER_LOGGER;
67
- }
68
- async start() {
69
- await this.transport.start();
70
- this.stream = this.transport.receiveOutput();
71
- this.pumpTask = this.pumpMessages();
72
- await this.initialize();
73
- }
74
- async stop() {
75
- const pump = this.pumpTask;
76
- this.pumpTask = null;
77
- this.stream = null;
78
- this.rejectAllPendingRequests(new Error("app-server stopped"));
79
- this.pendingResponses.clear();
80
- this.messageQueue.close();
81
- this.stdoutBuffer = Buffer.alloc(0);
82
- this.framing = "unknown";
83
- await this.transport.stop();
84
- if (pump) {
85
- await pump;
86
- }
87
- }
88
- async listModels(cursor, limit) {
89
- const result = await this.request("model/list", { cursor, limit }, 10000);
90
- if (!isModelListResponse(result)) {
91
- throw new Error("app-server returned an invalid model/list payload");
92
- }
93
- return result;
94
- }
95
- async startThread(params) {
96
- return this.request("thread/start", params, 15000);
97
- }
98
- async resumeThread(params) {
99
- return this.request("thread/resume", params, 15000);
100
- }
101
- async startTurn(params) {
102
- return this.request("turn/start", params, 15000);
103
- }
104
- async steerTurn(params) {
105
- return this.request("turn/steer", params, 15000);
106
- }
107
- async interruptTurn(params) {
108
- return this.request("turn/interrupt", params, 15000);
109
- }
110
- async waitForTurnCompletion(threadId, turnId, onNotification, timeoutMs = 2 * 60 * 60000) {
111
- const deadline = Date.now() + timeoutMs;
112
- while (Date.now() < deadline) {
113
- const remaining = Math.max(1, deadline - Date.now());
114
- const message = await this.popMessageWithTimeout(remaining);
115
- if (!message) {
116
- break;
117
- }
118
- if (hasTag(message)) {
119
- if (message.type === "parse_error") {
120
- throw new Error(`Failed to parse app-server message: ${message.reason}`);
121
- }
122
- if (message.type === "stderr") {
123
- const trimmed = message.payload.trim();
124
- if (trimmed.length > 0) {
125
- this.stderrLines.push(trimmed);
126
- }
127
- }
128
- continue;
129
- }
130
- if (isResponseMessage(message)) {
131
- continue;
132
- }
133
- if (!isServerNotificationMessage(message)) {
134
- continue;
135
- }
136
- if (onNotification) {
137
- await onNotification(message);
138
- }
139
- if (message.method === "error" &&
140
- message.params.threadId === threadId &&
141
- message.params.turnId === turnId) {
142
- throw new Error(message.params.error.message);
143
- }
144
- if (message.method === "turn/completed" &&
145
- message.params.threadId === threadId &&
146
- message.params.turn.id === turnId) {
147
- const status = message.params.turn.status;
148
- if (status === "completed" || status === "interrupted" || status === "failed") {
149
- return status;
150
- }
151
- }
152
- }
153
- throw new AppServerTimeoutError(`Timed out waiting for completion of turn '${turnId}' in thread '${threadId}'.`);
154
- }
155
- async initialize() {
156
- const params = {
157
- clientInfo: {
158
- name: this.clientName,
159
- title: null,
160
- version: "0.0.1",
161
- },
162
- capabilities: {
163
- experimentalApi: true,
164
- optOutNotificationMethods: [],
165
- },
166
- };
167
- const attempts = 5;
168
- for (let attempt = 1; attempt <= attempts; attempt += 1) {
169
- try {
170
- await this.request("initialize", params, 3000);
171
- return;
172
- }
173
- catch (error) {
174
- if (!(error instanceof AppServerTimeoutError) || attempt === attempts) {
175
- throw error;
176
- }
177
- }
178
- }
179
- }
180
- async request(method, params, timeoutMs) {
181
- const requestId = this.nextRequestId++;
182
- const request = {
183
- method,
184
- id: requestId,
185
- params,
186
- };
187
- await this.sendMessage(request);
188
- return this.waitForResponseResult(requestId, timeoutMs);
189
- }
190
- async sendMessage(message) {
191
- const payload = JSON.stringify(message);
192
- this.logger.debug(`[app-server][outgoing] ${payload}`);
193
- await this.transport.sendRaw(`${payload}\n`);
194
- }
195
- async pumpMessages() {
196
- if (!this.stream) {
197
- return;
198
- }
199
- try {
200
- for await (const event of this.stream) {
201
- if (event.type === "stdout") {
202
- this.consumeStdout(event.payload);
203
- continue;
204
- }
205
- if (event.type === "stderr") {
206
- this.messageQueue.push({ type: "stderr", payload: event.payload });
207
- continue;
208
- }
209
- this.rejectAllPendingRequests(new Error(event.reason));
210
- this.messageQueue.push({
211
- type: "parse_error",
212
- payload: "",
213
- reason: event.reason,
214
- });
215
- }
216
- }
217
- finally {
218
- this.messageQueue.close();
219
- }
220
- }
221
- consumeStdout(chunk) {
222
- this.stdoutBuffer = Buffer.concat([this.stdoutBuffer, chunk]);
223
- while (true) {
224
- if (this.framing === "unknown") {
225
- if (this.stdoutBuffer.length === 0) {
226
- return;
227
- }
228
- const head = this.stdoutBuffer.toString("utf8", 0, Math.min(this.stdoutBuffer.length, 64));
229
- if (head.startsWith("Content-Length:")) {
230
- this.framing = "content-length";
231
- }
232
- else if (this.stdoutBuffer.includes(0x0a)) {
233
- this.framing = "newline";
234
- }
235
- else {
236
- return;
237
- }
238
- }
239
- if (this.framing === "content-length") {
240
- const payload = this.tryParseContentLengthFrame();
241
- if (!payload) {
242
- return;
243
- }
244
- this.processPayload(payload);
245
- continue;
246
- }
247
- const payload = this.tryParseNewlineFrame();
248
- if (!payload) {
249
- return;
250
- }
251
- this.processPayload(payload);
252
- }
253
- }
254
- tryParseContentLengthFrame() {
255
- const crlfDelimiter = Buffer.from("\r\n\r\n");
256
- const lfDelimiter = Buffer.from("\n\n");
257
- let headerEnd = this.stdoutBuffer.indexOf(crlfDelimiter);
258
- let delimiterBytes = 4;
259
- if (headerEnd < 0) {
260
- headerEnd = this.stdoutBuffer.indexOf(lfDelimiter);
261
- delimiterBytes = 2;
262
- }
263
- if (headerEnd < 0) {
264
- return null;
265
- }
266
- const headerText = this.stdoutBuffer.subarray(0, headerEnd).toString("utf8");
267
- const match = /Content-Length:\s*(\d+)/i.exec(headerText);
268
- if (!match) {
269
- this.stdoutBuffer = this.stdoutBuffer.subarray(headerEnd + delimiterBytes);
270
- this.messageQueue.push({
271
- type: "parse_error",
272
- payload: headerText,
273
- reason: "missing Content-Length header",
274
- });
275
- return null;
276
- }
277
- const contentLength = Number.parseInt(match[1], 10);
278
- const bodyStart = headerEnd + delimiterBytes;
279
- const bodyEnd = bodyStart + contentLength;
280
- if (this.stdoutBuffer.length < bodyEnd) {
281
- return null;
282
- }
283
- const payload = this.stdoutBuffer.subarray(bodyStart, bodyEnd).toString("utf8");
284
- this.stdoutBuffer = this.stdoutBuffer.subarray(bodyEnd);
285
- return payload;
286
- }
287
- tryParseNewlineFrame() {
288
- const newlineIndex = this.stdoutBuffer.indexOf(0x0a);
289
- if (newlineIndex < 0) {
290
- return null;
291
- }
292
- const line = this.stdoutBuffer.subarray(0, newlineIndex).toString("utf8").replace(/\r$/, "");
293
- this.stdoutBuffer = this.stdoutBuffer.subarray(newlineIndex + 1);
294
- if (!line.trim()) {
295
- return "";
296
- }
297
- return line;
298
- }
299
- processPayload(payload) {
300
- if (!payload.trim()) {
301
- return;
302
- }
303
- this.logger.debug(`[app-server][incoming] ${payload}`);
304
- let parsed;
305
- try {
306
- parsed = JSON.parse(payload);
307
- }
308
- catch (error) {
309
- const reason = error instanceof Error ? error.message : "invalid JSON";
310
- this.messageQueue.push({ type: "parse_error", payload, reason });
311
- return;
312
- }
313
- if (!hasMessageShape(parsed)) {
314
- this.rejectAllPendingRequests(new Error("message does not match expected app-server envelope"));
315
- this.messageQueue.push({
316
- type: "parse_error",
317
- payload,
318
- reason: "message does not match expected app-server envelope",
319
- });
320
- return;
321
- }
322
- const message = parsed;
323
- if (isResponseMessage(message)) {
324
- this.routeResponseMessage(message);
325
- return;
326
- }
327
- this.messageQueue.push(message);
328
- }
329
- async popMessageWithTimeout(timeoutMs) {
330
- return this.messageQueue.popWithTimeout(timeoutMs);
331
- }
332
- routeResponseMessage(message) {
333
- const pendingRequest = this.pendingRequests.get(message.id);
334
- if (!pendingRequest) {
335
- this.pendingResponses.set(message.id, message);
336
- return;
337
- }
338
- this.pendingRequests.delete(message.id);
339
- clearTimeout(pendingRequest.timeout);
340
- if (message.error !== undefined) {
341
- pendingRequest.reject(new Error(`app-server returned an error for request ${String(message.id)}: ${formatUnknownError(message.error)}`));
342
- return;
343
- }
344
- pendingRequest.resolve(message.result);
345
- }
346
- rejectAllPendingRequests(error) {
347
- for (const [requestId, pendingRequest] of this.pendingRequests.entries()) {
348
- this.pendingRequests.delete(requestId);
349
- clearTimeout(pendingRequest.timeout);
350
- pendingRequest.reject(new Error(`request ${String(requestId)} failed: ${error.message}`));
351
- }
352
- }
353
- async waitForResponseResult(requestId, timeoutMs) {
354
- const immediateResponse = this.pendingResponses.get(requestId);
355
- if (immediateResponse) {
356
- this.pendingResponses.delete(requestId);
357
- if (immediateResponse.error !== undefined) {
358
- throw new Error(`app-server returned an error for request ${String(requestId)}: ${formatUnknownError(immediateResponse.error)}`);
359
- }
360
- return immediateResponse.result;
361
- }
362
- return new Promise((resolve, reject) => {
363
- const timeout = setTimeout(() => {
364
- this.pendingRequests.delete(requestId);
365
- reject(new AppServerTimeoutError(`Timed out waiting for response to request ${String(requestId)}`));
366
- }, timeoutMs);
367
- const pendingRequest = {
368
- timeout,
369
- resolve: (result) => {
370
- resolve(result);
371
- },
372
- reject: (error) => {
373
- reject(error);
374
- },
375
- };
376
- this.pendingRequests.set(requestId, pendingRequest);
377
- const bufferedResponse = this.pendingResponses.get(requestId);
378
- if (!bufferedResponse) {
379
- return;
380
- }
381
- this.pendingResponses.delete(requestId);
382
- this.pendingRequests.delete(requestId);
383
- clearTimeout(timeout);
384
- if (bufferedResponse.error !== undefined) {
385
- reject(new Error(`app-server returned an error for request ${String(requestId)}: ${formatUnknownError(bufferedResponse.error)}`));
386
- return;
387
- }
388
- resolve(bufferedResponse.result);
389
- });
390
- }
391
- }
392
- exports.AppServerService = AppServerService;
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BufferedClientMessageSender = void 0;
4
- function toErrorMessage(error) {
5
- return error instanceof Error ? error.message : String(error);
6
- }
7
- class BufferedClientMessageSender {
8
- constructor(options) {
9
- this.bufferedMessages = [];
10
- this.channel = null;
11
- this.flushing = false;
12
- this.droppedMessages = 0;
13
- this.maxBufferedMessages = Math.max(1, options.maxBufferedMessages);
14
- this.logger = options.logger;
15
- }
16
- bind(channel) {
17
- this.channel = channel;
18
- if (this.bufferedMessages.length > 0) {
19
- this.logger.debug(`Bound command channel and attempting to flush ${this.bufferedMessages.length} buffered client message(s).`);
20
- }
21
- void this.flush();
22
- }
23
- unbind(channel) {
24
- if (!channel || this.channel === channel) {
25
- this.channel = null;
26
- }
27
- }
28
- async send(message) {
29
- this.enqueue(message);
30
- await this.flush();
31
- }
32
- getBufferedMessageCount() {
33
- return this.bufferedMessages.length;
34
- }
35
- getDroppedMessageCount() {
36
- return this.droppedMessages;
37
- }
38
- enqueue(message) {
39
- if (this.bufferedMessages.length >= this.maxBufferedMessages) {
40
- this.droppedMessages += 1;
41
- if (this.droppedMessages === 1 || this.droppedMessages % 100 === 0) {
42
- this.logger.warn(`Dropping client message because outbound buffer reached ${this.maxBufferedMessages} messages ` +
43
- `(dropped=${this.droppedMessages}).`);
44
- }
45
- return;
46
- }
47
- this.bufferedMessages.push(message);
48
- }
49
- async flush() {
50
- if (this.flushing) {
51
- return;
52
- }
53
- this.flushing = true;
54
- try {
55
- while (this.channel && this.bufferedMessages.length > 0) {
56
- const nextMessage = this.bufferedMessages[0];
57
- try {
58
- await this.channel.send(nextMessage);
59
- this.bufferedMessages.shift();
60
- }
61
- catch (error) {
62
- this.logger.warn(`Failed to send buffered client message: ${toErrorMessage(error)}`);
63
- this.channel = null;
64
- break;
65
- }
66
- }
67
- }
68
- finally {
69
- this.flushing = false;
70
- }
71
- }
72
- }
73
- exports.BufferedClientMessageSender = BufferedClientMessageSender;