omnara 0.5.3 → 0.6.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/dist/cli.js +350 -57
- package/dist/cli.js.map +3 -3
- package/dist/daemon/machine-supervisor.d.ts +2 -0
- package/dist/daemon/session-runner.d.ts +10 -0
- package/dist/orchestrator/ai-client.d.ts +1 -0
- package/dist/orchestrator/session.d.ts +1 -0
- package/dist/utils/version-check.d.ts +0 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -177,9 +177,11 @@ var BASE_ALLOWED_WORKER_TOOLS = [
|
|
|
177
177
|
"Skill",
|
|
178
178
|
"SlashCommand"
|
|
179
179
|
];
|
|
180
|
+
var INTERRUPT_TIMEOUT_MS = 5e3;
|
|
180
181
|
var AIClient = class {
|
|
181
182
|
baseOptions;
|
|
182
183
|
query;
|
|
184
|
+
abortController;
|
|
183
185
|
currentModel = "sonnet";
|
|
184
186
|
constructor(config) {
|
|
185
187
|
const defaultOptions = {
|
|
@@ -202,17 +204,23 @@ var AIClient = class {
|
|
|
202
204
|
this.ensureWorkingDirectory(this.baseOptions.cwd);
|
|
203
205
|
}
|
|
204
206
|
async *streamUserMessage(prompt2, overrides) {
|
|
207
|
+
this.abortController = new AbortController();
|
|
205
208
|
const q = this.createQuery(prompt2, overrides);
|
|
206
209
|
this.query = q;
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
try {
|
|
211
|
+
for await (const message of q) {
|
|
212
|
+
yield message;
|
|
213
|
+
}
|
|
214
|
+
} finally {
|
|
215
|
+
this.query = void 0;
|
|
216
|
+
this.abortController = void 0;
|
|
209
217
|
}
|
|
210
|
-
this.query = void 0;
|
|
211
218
|
}
|
|
212
219
|
createQuery(prompt2, overrides) {
|
|
213
220
|
const merged = {
|
|
214
221
|
...this.baseOptions,
|
|
215
|
-
...overrides
|
|
222
|
+
...overrides,
|
|
223
|
+
abortController: this.abortController
|
|
216
224
|
};
|
|
217
225
|
this.ensureWorkingDirectory(merged.cwd);
|
|
218
226
|
return query2({
|
|
@@ -221,10 +229,25 @@ var AIClient = class {
|
|
|
221
229
|
});
|
|
222
230
|
}
|
|
223
231
|
async cancel() {
|
|
224
|
-
if (this.query) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
if (!this.query) {
|
|
233
|
+
console.warn("[AIClient] No query to interrupt. Ignoring");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const interruptPromise = this.query.interrupt();
|
|
238
|
+
const timeoutPromise = new Promise(
|
|
239
|
+
(resolve) => setTimeout(() => resolve("timeout"), INTERRUPT_TIMEOUT_MS)
|
|
240
|
+
);
|
|
241
|
+
const result = await Promise.race([interruptPromise, timeoutPromise]);
|
|
242
|
+
if (result === "timeout") {
|
|
243
|
+
console.warn(
|
|
244
|
+
`[AIClient] interrupt() timed out after ${INTERRUPT_TIMEOUT_MS}ms, falling back to abort`
|
|
245
|
+
);
|
|
246
|
+
this.abortController?.abort();
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn("[AIClient] interrupt() failed, falling back to abort:", error);
|
|
250
|
+
this.abortController?.abort();
|
|
228
251
|
}
|
|
229
252
|
}
|
|
230
253
|
isGenerating() {
|
|
@@ -602,8 +625,22 @@ function createEnvelope(sessionId, content, senderId, metadata, payloadMetadata)
|
|
|
602
625
|
}
|
|
603
626
|
function toMessageEnvelopes(message, sessionId) {
|
|
604
627
|
const envelopes = [];
|
|
628
|
+
const messageAny = message;
|
|
629
|
+
const subagentSessionId = typeof messageAny.session_id === "string" ? messageAny.session_id : void 0;
|
|
630
|
+
const parentToolUseId = typeof messageAny.parent_tool_use_id === "string" ? messageAny.parent_tool_use_id : void 0;
|
|
631
|
+
const buildSubagentPayloadMetadata = () => {
|
|
632
|
+
const metadata = {};
|
|
633
|
+
if (parentToolUseId) {
|
|
634
|
+
metadata.parent_tool_use_id = parentToolUseId;
|
|
635
|
+
}
|
|
636
|
+
if (subagentSessionId && subagentSessionId !== sessionId) {
|
|
637
|
+
metadata.subagent_session_id = subagentSessionId;
|
|
638
|
+
}
|
|
639
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
640
|
+
};
|
|
605
641
|
switch (message.type) {
|
|
606
642
|
case "assistant": {
|
|
643
|
+
const subagentMetadata = buildSubagentPayloadMetadata();
|
|
607
644
|
for (const block of message.message.content) {
|
|
608
645
|
if (isTextBlock(block)) {
|
|
609
646
|
const content = {
|
|
@@ -611,9 +648,15 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
611
648
|
text: block.text
|
|
612
649
|
};
|
|
613
650
|
envelopes.push(
|
|
614
|
-
createEnvelope(
|
|
615
|
-
|
|
616
|
-
|
|
651
|
+
createEnvelope(
|
|
652
|
+
sessionId,
|
|
653
|
+
content,
|
|
654
|
+
sessionId,
|
|
655
|
+
{
|
|
656
|
+
role: "assistant"
|
|
657
|
+
},
|
|
658
|
+
subagentMetadata
|
|
659
|
+
)
|
|
617
660
|
);
|
|
618
661
|
} else if (isToolUseBlock(block)) {
|
|
619
662
|
const content = {
|
|
@@ -623,15 +666,29 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
623
666
|
arguments: normalizeToolArguments(block.input)
|
|
624
667
|
};
|
|
625
668
|
envelopes.push(
|
|
626
|
-
createEnvelope(
|
|
627
|
-
|
|
628
|
-
|
|
669
|
+
createEnvelope(
|
|
670
|
+
sessionId,
|
|
671
|
+
content,
|
|
672
|
+
sessionId,
|
|
673
|
+
{
|
|
674
|
+
role: "assistant"
|
|
675
|
+
},
|
|
676
|
+
subagentMetadata
|
|
677
|
+
)
|
|
629
678
|
);
|
|
630
679
|
}
|
|
631
680
|
}
|
|
632
681
|
break;
|
|
633
682
|
}
|
|
634
683
|
case "user": {
|
|
684
|
+
if (parentToolUseId) {
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
const firstBlock = message.message.content[0];
|
|
688
|
+
if (isTextBlock(firstBlock) && (firstBlock.text === "[Request interrupted by user]" || firstBlock.text === "[Request interrupted by user for tool use]")) {
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
const subagentMetadata = buildSubagentPayloadMetadata();
|
|
635
692
|
for (const block of message.message.content) {
|
|
636
693
|
if (isToolResultBlock(block)) {
|
|
637
694
|
const content = {
|
|
@@ -641,9 +698,15 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
641
698
|
is_error: Boolean(block.is_error)
|
|
642
699
|
};
|
|
643
700
|
envelopes.push(
|
|
644
|
-
createEnvelope(
|
|
645
|
-
|
|
646
|
-
|
|
701
|
+
createEnvelope(
|
|
702
|
+
sessionId,
|
|
703
|
+
content,
|
|
704
|
+
sessionId,
|
|
705
|
+
{
|
|
706
|
+
role: "assistant"
|
|
707
|
+
},
|
|
708
|
+
subagentMetadata
|
|
709
|
+
)
|
|
647
710
|
);
|
|
648
711
|
} else if (isTextBlock(block)) {
|
|
649
712
|
const content = {
|
|
@@ -651,9 +714,15 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
651
714
|
text: block.text
|
|
652
715
|
};
|
|
653
716
|
envelopes.push(
|
|
654
|
-
createEnvelope(
|
|
655
|
-
|
|
656
|
-
|
|
717
|
+
createEnvelope(
|
|
718
|
+
sessionId,
|
|
719
|
+
content,
|
|
720
|
+
sessionId,
|
|
721
|
+
{
|
|
722
|
+
role: "user"
|
|
723
|
+
},
|
|
724
|
+
subagentMetadata
|
|
725
|
+
)
|
|
657
726
|
);
|
|
658
727
|
}
|
|
659
728
|
}
|
|
@@ -666,6 +735,13 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
666
735
|
type: "text",
|
|
667
736
|
text: delta
|
|
668
737
|
};
|
|
738
|
+
const streamPayloadMetadata = {
|
|
739
|
+
stream_delta: true
|
|
740
|
+
};
|
|
741
|
+
const subagentMeta = buildSubagentPayloadMetadata();
|
|
742
|
+
if (subagentMeta) {
|
|
743
|
+
Object.assign(streamPayloadMetadata, subagentMeta);
|
|
744
|
+
}
|
|
669
745
|
envelopes.push(
|
|
670
746
|
createEnvelope(
|
|
671
747
|
sessionId,
|
|
@@ -674,9 +750,7 @@ function toMessageEnvelopes(message, sessionId) {
|
|
|
674
750
|
{
|
|
675
751
|
role: "assistant"
|
|
676
752
|
},
|
|
677
|
-
|
|
678
|
-
stream_delta: true
|
|
679
|
-
}
|
|
753
|
+
streamPayloadMetadata
|
|
680
754
|
)
|
|
681
755
|
);
|
|
682
756
|
}
|
|
@@ -783,6 +857,7 @@ var Session = class {
|
|
|
783
857
|
sessionInitSubscribers = [];
|
|
784
858
|
queue = [];
|
|
785
859
|
generating = false;
|
|
860
|
+
waitingForMessage = null;
|
|
786
861
|
announcementPromise = null;
|
|
787
862
|
announced = false;
|
|
788
863
|
shouldSummarize = false;
|
|
@@ -804,19 +879,29 @@ var Session = class {
|
|
|
804
879
|
sessionId: this.id,
|
|
805
880
|
queueLength: this.queue.length
|
|
806
881
|
});
|
|
807
|
-
if (
|
|
882
|
+
if (this.waitingForMessage) {
|
|
883
|
+
const resolver = this.waitingForMessage;
|
|
884
|
+
this.waitingForMessage = null;
|
|
885
|
+
const batch = this.queue.splice(0, this.queue.length);
|
|
886
|
+
void this.emitProgress("running", "Generating response");
|
|
887
|
+
resolver(batch);
|
|
888
|
+
} else if (!this.generating && !this.ai.isGenerating()) {
|
|
808
889
|
this.startGenerate();
|
|
809
890
|
}
|
|
810
891
|
}
|
|
811
892
|
async *[Symbol.asyncIterator]() {
|
|
812
893
|
while (true) {
|
|
813
|
-
|
|
814
|
-
|
|
894
|
+
let batch;
|
|
895
|
+
if (this.queue.length > 0) {
|
|
896
|
+
batch = this.queue.splice(0, this.queue.length);
|
|
897
|
+
} else {
|
|
898
|
+
logger.debug("[Session] Iterator waiting for messages", {
|
|
815
899
|
sessionId: this.id
|
|
816
900
|
});
|
|
817
|
-
|
|
901
|
+
batch = await new Promise((resolve) => {
|
|
902
|
+
this.waitingForMessage = resolve;
|
|
903
|
+
});
|
|
818
904
|
}
|
|
819
|
-
const batch = this.queue.splice(0, this.queue.length);
|
|
820
905
|
logger.debug("[Session] Yielding batch to SDK", {
|
|
821
906
|
sessionId: this.id,
|
|
822
907
|
batchSize: batch.length
|
|
@@ -849,28 +934,40 @@ var Session = class {
|
|
|
849
934
|
const summaryTextBlocks = [];
|
|
850
935
|
let resultMessage = null;
|
|
851
936
|
await this.emitProgress("running", "Generating response");
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
937
|
+
try {
|
|
938
|
+
for await (const message of this.ai.streamUserMessage(this, {
|
|
939
|
+
...this.sdkSessionIdentifier ? { resume: this.sdkSessionIdentifier } : {}
|
|
940
|
+
})) {
|
|
941
|
+
this.captureSdkSessionId(message);
|
|
942
|
+
if (message.type === "assistant") {
|
|
943
|
+
this.collectAssistantSummaryBlocks(message, summaryTextBlocks);
|
|
944
|
+
}
|
|
945
|
+
if (message.type === "result") {
|
|
946
|
+
resultMessage = message;
|
|
947
|
+
this.resetRetryState();
|
|
948
|
+
const complete = await this.buildCompletionEnvelope(resultMessage, summaryTextBlocks);
|
|
949
|
+
await Promise.all([
|
|
950
|
+
this.emitProgress("idle", "Ready for next message"),
|
|
951
|
+
this.dispatchEnvelope(complete)
|
|
952
|
+
]);
|
|
953
|
+
summaryTextBlocks.length = 0;
|
|
954
|
+
resultMessage = null;
|
|
955
|
+
}
|
|
956
|
+
for (const envelope of toMessageEnvelopes(message, this.id)) {
|
|
957
|
+
await this.dispatchEnvelope(envelope);
|
|
958
|
+
}
|
|
861
959
|
}
|
|
862
|
-
|
|
863
|
-
|
|
960
|
+
} catch (error) {
|
|
961
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
962
|
+
logger.info("[Session] Generation aborted", { sessionId: this.id });
|
|
963
|
+
await this.emitProgress("idle", "Generation cancelled");
|
|
964
|
+
return;
|
|
864
965
|
}
|
|
966
|
+
throw error;
|
|
865
967
|
}
|
|
866
|
-
this.resetRetryState();
|
|
867
|
-
const complete = await this.buildCompletionEnvelope(resultMessage, summaryTextBlocks);
|
|
868
|
-
await Promise.all([
|
|
869
|
-
this.emitProgress("idle", "Ready for next message"),
|
|
870
|
-
this.dispatchEnvelope(complete)
|
|
871
|
-
]);
|
|
872
968
|
} finally {
|
|
873
969
|
this.generating = false;
|
|
970
|
+
this.waitingForMessage = null;
|
|
874
971
|
logger.debug("[Session] Generation finished", {
|
|
875
972
|
sessionId: this.id,
|
|
876
973
|
pendingMessages: this.queue.length
|
|
@@ -2690,6 +2787,33 @@ var AgentOrchestrator = class {
|
|
|
2690
2787
|
commit_sha: commitSha
|
|
2691
2788
|
};
|
|
2692
2789
|
}
|
|
2790
|
+
if (req.action === "commit_checkout") {
|
|
2791
|
+
try {
|
|
2792
|
+
const currentBranch = await git.revparse(["--abbrev-ref", "HEAD"]);
|
|
2793
|
+
const branchTrimmed = currentBranch.trim();
|
|
2794
|
+
const repoPath = this.workerManager.repoPath;
|
|
2795
|
+
const mainGit = simpleGit2(repoPath);
|
|
2796
|
+
await mainGit.raw(["checkout", "-d", branchTrimmed]);
|
|
2797
|
+
logger2.info(`[AgentOrchestrator] Checked out ${branchTrimmed} in main worktree`);
|
|
2798
|
+
return {
|
|
2799
|
+
type: "git_write",
|
|
2800
|
+
success: true,
|
|
2801
|
+
message: `Committed changes. The main workspace checked out the changes on this branch.`,
|
|
2802
|
+
commit_sha: commitSha
|
|
2803
|
+
};
|
|
2804
|
+
} catch (checkoutError) {
|
|
2805
|
+
logger2.error("[AgentOrchestrator] Failed to checkout in main worktree", {
|
|
2806
|
+
error: checkoutError
|
|
2807
|
+
});
|
|
2808
|
+
return {
|
|
2809
|
+
type: "git_write",
|
|
2810
|
+
success: true,
|
|
2811
|
+
message: `Committed successfully but failed to checkout in main worktree: ${checkoutError instanceof Error ? checkoutError.message : String(checkoutError)}`,
|
|
2812
|
+
commit_sha: commitSha,
|
|
2813
|
+
error: `Checkout failed: ${checkoutError instanceof Error ? checkoutError.message : String(checkoutError)}`
|
|
2814
|
+
};
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2693
2817
|
return {
|
|
2694
2818
|
type: "git_write",
|
|
2695
2819
|
success: true,
|
|
@@ -3653,7 +3777,7 @@ var control_message_schema_default = {
|
|
|
3653
3777
|
},
|
|
3654
3778
|
GitWriteRequest: {
|
|
3655
3779
|
additionalProperties: false,
|
|
3656
|
-
description: 'Request to commit and optionally push changes.\n\nThe action field specifies what operation to perform:\n- "commit": Create a git commit with a generated message\n- "commit_push": Create a commit and push to origin\n- "commit_push_pr": Create a commit, push, and create a PR (not yet implemented)',
|
|
3780
|
+
description: 'Request to commit and optionally push changes.\n\nThe action field specifies what operation to perform:\n- "commit": Create a git commit with a generated message\n- "commit_push": Create a commit and push to origin\n- "commit_push_pr": Create a commit, push, and create a PR (not yet implemented)\n- "commit_checkout": Create a commit and checkout the branch in the main worktree',
|
|
3657
3781
|
properties: {
|
|
3658
3782
|
type: {
|
|
3659
3783
|
const: "git_write",
|
|
@@ -3665,7 +3789,8 @@ var control_message_schema_default = {
|
|
|
3665
3789
|
enum: [
|
|
3666
3790
|
"commit",
|
|
3667
3791
|
"commit_push",
|
|
3668
|
-
"commit_push_pr"
|
|
3792
|
+
"commit_push_pr",
|
|
3793
|
+
"commit_checkout"
|
|
3669
3794
|
],
|
|
3670
3795
|
title: "Action",
|
|
3671
3796
|
type: "string"
|
|
@@ -4747,12 +4872,23 @@ var machine_message_schema_default = {
|
|
|
4747
4872
|
type: "string"
|
|
4748
4873
|
},
|
|
4749
4874
|
method: {
|
|
4750
|
-
|
|
4875
|
+
enum: [
|
|
4876
|
+
"start_session",
|
|
4877
|
+
"stop_session"
|
|
4878
|
+
],
|
|
4751
4879
|
title: "Method",
|
|
4752
4880
|
type: "string"
|
|
4753
4881
|
},
|
|
4754
4882
|
payload: {
|
|
4755
|
-
|
|
4883
|
+
anyOf: [
|
|
4884
|
+
{
|
|
4885
|
+
$ref: "#/$defs/MachineStartSessionPayload"
|
|
4886
|
+
},
|
|
4887
|
+
{
|
|
4888
|
+
$ref: "#/$defs/MachineStopSessionPayload"
|
|
4889
|
+
}
|
|
4890
|
+
],
|
|
4891
|
+
title: "Payload"
|
|
4756
4892
|
}
|
|
4757
4893
|
},
|
|
4758
4894
|
required: [
|
|
@@ -4926,6 +5062,22 @@ var machine_message_schema_default = {
|
|
|
4926
5062
|
title: "MachineStatus",
|
|
4927
5063
|
type: "string"
|
|
4928
5064
|
},
|
|
5065
|
+
MachineStopSessionPayload: {
|
|
5066
|
+
additionalProperties: false,
|
|
5067
|
+
description: "Payload instructing the daemon to terminate a running session.",
|
|
5068
|
+
properties: {
|
|
5069
|
+
user_session_id: {
|
|
5070
|
+
format: "uuid",
|
|
5071
|
+
title: "User Session Id",
|
|
5072
|
+
type: "string"
|
|
5073
|
+
}
|
|
5074
|
+
},
|
|
5075
|
+
required: [
|
|
5076
|
+
"user_session_id"
|
|
5077
|
+
],
|
|
5078
|
+
title: "MachineStopSessionPayload",
|
|
5079
|
+
type: "object"
|
|
5080
|
+
},
|
|
4929
5081
|
WorkspaceConfig: {
|
|
4930
5082
|
additionalProperties: false,
|
|
4931
5083
|
description: "Workspace-level configuration persisted alongside metadata.",
|
|
@@ -9908,7 +10060,7 @@ function extractErrorMessage11(error) {
|
|
|
9908
10060
|
// src/daemon/machine-supervisor.ts
|
|
9909
10061
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
9910
10062
|
import os5 from "node:os";
|
|
9911
|
-
import { setTimeout as
|
|
10063
|
+
import { setTimeout as delay5 } from "node:timers/promises";
|
|
9912
10064
|
import WebSocket3 from "ws";
|
|
9913
10065
|
import * as Sentry21 from "@sentry/node";
|
|
9914
10066
|
|
|
@@ -17735,9 +17887,11 @@ async function ensureWorkspace(client, accessToken, payload) {
|
|
|
17735
17887
|
|
|
17736
17888
|
// src/daemon/session-runner.ts
|
|
17737
17889
|
import { spawn as spawn3 } from "node:child_process";
|
|
17890
|
+
import { setTimeout as delay4 } from "node:timers/promises";
|
|
17738
17891
|
import * as Sentry20 from "@sentry/node";
|
|
17739
17892
|
import fs11 from "node:fs";
|
|
17740
17893
|
import path13 from "node:path";
|
|
17894
|
+
var GRACEFUL_STOP_DELAY_MS = 2e3;
|
|
17741
17895
|
var SessionManager = class {
|
|
17742
17896
|
backendUrl;
|
|
17743
17897
|
frontendUrl;
|
|
@@ -17770,6 +17924,47 @@ var SessionManager = class {
|
|
|
17770
17924
|
throw error;
|
|
17771
17925
|
}
|
|
17772
17926
|
}
|
|
17927
|
+
/**
|
|
17928
|
+
* Stop a running session by user session ID.
|
|
17929
|
+
*
|
|
17930
|
+
* Looks up the session in the PID registry, sends SIGTERM for graceful
|
|
17931
|
+
* shutdown, waits briefly, then sends SIGKILL if still alive.
|
|
17932
|
+
*
|
|
17933
|
+
* @returns true if a running session was found and terminated, false if
|
|
17934
|
+
* the session was not running.
|
|
17935
|
+
*/
|
|
17936
|
+
async stopSession(userSessionId) {
|
|
17937
|
+
return await withSessionRegistry(async (registry) => {
|
|
17938
|
+
const record = registry[userSessionId];
|
|
17939
|
+
if (!record) {
|
|
17940
|
+
return [registry, false];
|
|
17941
|
+
}
|
|
17942
|
+
const alive = await isSessionProcessAlive(record);
|
|
17943
|
+
if (!alive) {
|
|
17944
|
+
delete registry[userSessionId];
|
|
17945
|
+
return [registry, false];
|
|
17946
|
+
}
|
|
17947
|
+
try {
|
|
17948
|
+
process.kill(record.pid, "SIGTERM");
|
|
17949
|
+
this.logger.debug(`Sent SIGTERM to session ${userSessionId} (pid ${record.pid})`);
|
|
17950
|
+
} catch (error) {
|
|
17951
|
+
this.logger.debug(`SIGTERM failed for pid ${record.pid}: ${String(error)}`);
|
|
17952
|
+
delete registry[userSessionId];
|
|
17953
|
+
return [registry, false];
|
|
17954
|
+
}
|
|
17955
|
+
await delay4(GRACEFUL_STOP_DELAY_MS);
|
|
17956
|
+
const stillAlive = await isProcessAlive3(record.pid);
|
|
17957
|
+
if (stillAlive) {
|
|
17958
|
+
try {
|
|
17959
|
+
process.kill(record.pid, "SIGKILL");
|
|
17960
|
+
this.logger.debug(`Sent SIGKILL to session ${userSessionId} (pid ${record.pid})`);
|
|
17961
|
+
} catch {
|
|
17962
|
+
}
|
|
17963
|
+
}
|
|
17964
|
+
delete registry[userSessionId];
|
|
17965
|
+
return [registry, true];
|
|
17966
|
+
});
|
|
17967
|
+
}
|
|
17773
17968
|
};
|
|
17774
17969
|
var SessionRunner = class {
|
|
17775
17970
|
spec;
|
|
@@ -17900,7 +18095,7 @@ async function createSessionLogPath(workspaceId, launchId) {
|
|
|
17900
18095
|
|
|
17901
18096
|
// src/package-info.ts
|
|
17902
18097
|
var isBundled = true;
|
|
17903
|
-
var PACKAGE_VERSION = isBundled ? "0.
|
|
18098
|
+
var PACKAGE_VERSION = isBundled ? "0.6.0" : "0.0.0-dev";
|
|
17904
18099
|
var PACKAGE_DESCRIPTION = isBundled ? "Command-line interface for Omnara." : "Command-line interface for Omnara.";
|
|
17905
18100
|
|
|
17906
18101
|
// src/daemon/machine-supervisor.ts
|
|
@@ -18009,13 +18204,13 @@ var MachineSupervisor = class {
|
|
|
18009
18204
|
} else {
|
|
18010
18205
|
this.logger.debug("Machine supervisor still waiting for login\u2026");
|
|
18011
18206
|
}
|
|
18012
|
-
await
|
|
18207
|
+
await delay5(LOGIN_WAIT_DELAY_MS2);
|
|
18013
18208
|
} else {
|
|
18014
18209
|
Sentry21.captureException(error);
|
|
18015
18210
|
this.logger.warn(
|
|
18016
18211
|
`Machine supervisor error: ${error.message}. Retrying in ${Math.round(retryDelayMs / 1e3)}s.`
|
|
18017
18212
|
);
|
|
18018
|
-
await
|
|
18213
|
+
await delay5(retryDelayMs);
|
|
18019
18214
|
retryDelayMs = calculateBackoff(retryDelayMs);
|
|
18020
18215
|
}
|
|
18021
18216
|
}
|
|
@@ -18172,12 +18367,18 @@ var MachineSupervisor = class {
|
|
|
18172
18367
|
}
|
|
18173
18368
|
}
|
|
18174
18369
|
async handleRpcRequest(message) {
|
|
18175
|
-
if (message.method
|
|
18370
|
+
if (message.method === "start_session") {
|
|
18371
|
+
await this.handleStartSession(message);
|
|
18372
|
+
} else if (message.method === "stop_session") {
|
|
18373
|
+
await this.handleStopSession(message);
|
|
18374
|
+
} else {
|
|
18176
18375
|
await this.sendRpcResponse(message.request_id, "error", `Unknown method ${message.method}`);
|
|
18177
|
-
return;
|
|
18178
18376
|
}
|
|
18377
|
+
}
|
|
18378
|
+
async handleStartSession(message) {
|
|
18179
18379
|
try {
|
|
18180
|
-
const
|
|
18380
|
+
const payload = message.payload;
|
|
18381
|
+
const result = await this.launchWorkspaceSessionFromRpc(payload);
|
|
18181
18382
|
await this.sendRpcResponse(message.request_id, "ok", void 0, {
|
|
18182
18383
|
launch_id: result.launchId,
|
|
18183
18384
|
user_session_id: result.userSessionId,
|
|
@@ -18196,6 +18397,25 @@ var MachineSupervisor = class {
|
|
|
18196
18397
|
await this.sendRpcResponse(message.request_id, "error", messageText);
|
|
18197
18398
|
}
|
|
18198
18399
|
}
|
|
18400
|
+
async handleStopSession(message) {
|
|
18401
|
+
const payload = message.payload;
|
|
18402
|
+
const userSessionId = payload.user_session_id;
|
|
18403
|
+
try {
|
|
18404
|
+
const stopped = await this.sessionManager.stopSession(userSessionId);
|
|
18405
|
+
if (stopped) {
|
|
18406
|
+
this.logger.info(`Stopped session ${userSessionId}`);
|
|
18407
|
+
await this.sendRpcResponse(message.request_id, "ok");
|
|
18408
|
+
} else {
|
|
18409
|
+
this.logger.debug(`Session ${userSessionId} was not running`);
|
|
18410
|
+
await this.sendRpcResponse(message.request_id, "not_found", "Session not running");
|
|
18411
|
+
}
|
|
18412
|
+
} catch (error) {
|
|
18413
|
+
Sentry21.captureException(error);
|
|
18414
|
+
const messageText = error instanceof Error ? error.message : String(error);
|
|
18415
|
+
this.logger.warn(`Failed to stop session ${userSessionId}: ${messageText}`);
|
|
18416
|
+
await this.sendRpcResponse(message.request_id, "error", messageText);
|
|
18417
|
+
}
|
|
18418
|
+
}
|
|
18199
18419
|
async sendRpcResponse(requestId, status, error, body) {
|
|
18200
18420
|
const response = {
|
|
18201
18421
|
type: "rpc_response",
|
|
@@ -18317,7 +18537,7 @@ var MachineSupervisor = class {
|
|
|
18317
18537
|
return;
|
|
18318
18538
|
}
|
|
18319
18539
|
}
|
|
18320
|
-
await
|
|
18540
|
+
await delay5(250);
|
|
18321
18541
|
}
|
|
18322
18542
|
throw new Error("Machine has not finished registering yet. Try again in a few seconds.");
|
|
18323
18543
|
}
|
|
@@ -18606,6 +18826,44 @@ function compareVersions(v1, v2) {
|
|
|
18606
18826
|
}
|
|
18607
18827
|
return 0;
|
|
18608
18828
|
}
|
|
18829
|
+
function isNpmInstallation() {
|
|
18830
|
+
if (isBunSingleFileExecutable()) {
|
|
18831
|
+
return false;
|
|
18832
|
+
}
|
|
18833
|
+
const execPath = process.argv[1] ?? "";
|
|
18834
|
+
if (execPath.includes("node_modules")) {
|
|
18835
|
+
return true;
|
|
18836
|
+
}
|
|
18837
|
+
if (execPath.includes("/lib/node_modules/") || execPath.includes("\\node_modules\\")) {
|
|
18838
|
+
return true;
|
|
18839
|
+
}
|
|
18840
|
+
try {
|
|
18841
|
+
const realPath = realpathSync(execPath);
|
|
18842
|
+
if (realPath.includes("node_modules")) {
|
|
18843
|
+
return true;
|
|
18844
|
+
}
|
|
18845
|
+
} catch {
|
|
18846
|
+
}
|
|
18847
|
+
return false;
|
|
18848
|
+
}
|
|
18849
|
+
function uninstallNpmVersion() {
|
|
18850
|
+
console.log(chalk4.blue("Uninstalling npm version of Omnara..."));
|
|
18851
|
+
try {
|
|
18852
|
+
execSync2("npm uninstall -g omnara", { stdio: "inherit" });
|
|
18853
|
+
return true;
|
|
18854
|
+
} catch {
|
|
18855
|
+
try {
|
|
18856
|
+
if (platform() !== "win32") {
|
|
18857
|
+
execSync2("sudo npm uninstall -g omnara", { stdio: "inherit" });
|
|
18858
|
+
return true;
|
|
18859
|
+
}
|
|
18860
|
+
} catch {
|
|
18861
|
+
}
|
|
18862
|
+
}
|
|
18863
|
+
console.log(chalk4.yellow("Could not automatically uninstall npm version."));
|
|
18864
|
+
console.log(chalk4.yellow("Please run manually: npm uninstall -g omnara"));
|
|
18865
|
+
return false;
|
|
18866
|
+
}
|
|
18609
18867
|
async function runInstallScript(options) {
|
|
18610
18868
|
const os6 = platform();
|
|
18611
18869
|
const silent = options?.silent ?? false;
|
|
@@ -18649,6 +18907,38 @@ async function runInstallScript(options) {
|
|
|
18649
18907
|
return false;
|
|
18650
18908
|
}
|
|
18651
18909
|
}
|
|
18910
|
+
async function handleNpmInstallation() {
|
|
18911
|
+
const os6 = platform();
|
|
18912
|
+
const installCmd = os6 === "win32" ? `irm ${INSTALL_SCRIPT_URL_WINDOWS} | iex` : `curl -fsSL ${INSTALL_SCRIPT_URL_UNIX} | bash`;
|
|
18913
|
+
const border = chalk4.yellow("=".repeat(60));
|
|
18914
|
+
console.log("\n" + border);
|
|
18915
|
+
console.log(chalk4.yellow.bold(" npm Installation Detected"));
|
|
18916
|
+
console.log(border);
|
|
18917
|
+
console.log(
|
|
18918
|
+
chalk4.white(`
|
|
18919
|
+
Omnara CLI is now distributed as a standalone executable
|
|
18920
|
+
with automatic updates and improved performance.
|
|
18921
|
+
|
|
18922
|
+
Migrating to the new installation method...
|
|
18923
|
+
`)
|
|
18924
|
+
);
|
|
18925
|
+
uninstallNpmVersion();
|
|
18926
|
+
const success = await runInstallScript();
|
|
18927
|
+
if (success) {
|
|
18928
|
+
console.log(chalk4.green("\nMigration complete!"));
|
|
18929
|
+
console.log(chalk4.white("Please restart your terminal and run `omnara` again.\n"));
|
|
18930
|
+
return true;
|
|
18931
|
+
} else {
|
|
18932
|
+
console.log(
|
|
18933
|
+
chalk4.yellow(`
|
|
18934
|
+
To complete migration manually, run:
|
|
18935
|
+
|
|
18936
|
+
${chalk4.cyan(installCmd)}
|
|
18937
|
+
`)
|
|
18938
|
+
);
|
|
18939
|
+
return false;
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18652
18942
|
async function checkForUpdate() {
|
|
18653
18943
|
const currentVersion = PACKAGE_VERSION;
|
|
18654
18944
|
if (!currentVersion) {
|
|
@@ -18704,6 +18994,9 @@ async function attemptUpdate() {
|
|
|
18704
18994
|
if (!currentVersion) {
|
|
18705
18995
|
return false;
|
|
18706
18996
|
}
|
|
18997
|
+
if (isNpmInstallation()) {
|
|
18998
|
+
return await handleNpmInstallation();
|
|
18999
|
+
}
|
|
18707
19000
|
const updateInfo = await checkForUpdate();
|
|
18708
19001
|
if (!updateInfo.available) {
|
|
18709
19002
|
const channel = IS_PRERELEASE ? " (prerelease channel)" : "";
|