@abitat_reece/host-daemon 0.1.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 (81) hide show
  1. package/dist/cli/conversation-runtime.d.ts +23 -0
  2. package/dist/cli/conversation-runtime.d.ts.map +1 -0
  3. package/dist/cli/conversation-runtime.js +73 -0
  4. package/dist/cli/conversation-runtime.js.map +1 -0
  5. package/dist/cli/daemon-connection.d.ts +14 -0
  6. package/dist/cli/daemon-connection.d.ts.map +1 -0
  7. package/dist/cli/daemon-connection.js +17 -0
  8. package/dist/cli/daemon-connection.js.map +1 -0
  9. package/dist/cli/heartbeat-loop.d.ts +2 -0
  10. package/dist/cli/heartbeat-loop.d.ts.map +1 -0
  11. package/dist/cli/heartbeat-loop.js +10 -0
  12. package/dist/cli/heartbeat-loop.js.map +1 -0
  13. package/dist/cli/index.d.ts +3 -0
  14. package/dist/cli/index.d.ts.map +1 -0
  15. package/dist/cli/index.js +371 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/cli/retryable-task.d.ts +5 -0
  18. package/dist/cli/retryable-task.d.ts.map +1 -0
  19. package/dist/cli/retryable-task.js +16 -0
  20. package/dist/cli/retryable-task.js.map +1 -0
  21. package/dist/cli/start-options.d.ts +5 -0
  22. package/dist/cli/start-options.d.ts.map +1 -0
  23. package/dist/cli/start-options.js +6 -0
  24. package/dist/cli/start-options.js.map +1 -0
  25. package/dist/config/host-config.d.ts +10 -0
  26. package/dist/config/host-config.d.ts.map +1 -0
  27. package/dist/config/host-config.js +15 -0
  28. package/dist/config/host-config.js.map +1 -0
  29. package/dist/git/changeset.d.ts +9 -0
  30. package/dist/git/changeset.d.ts.map +1 -0
  31. package/dist/git/changeset.js +78 -0
  32. package/dist/git/changeset.js.map +1 -0
  33. package/dist/git/paths.d.ts +12 -0
  34. package/dist/git/paths.d.ts.map +1 -0
  35. package/dist/git/paths.js +72 -0
  36. package/dist/git/paths.js.map +1 -0
  37. package/dist/git/publish.d.ts +24 -0
  38. package/dist/git/publish.d.ts.map +1 -0
  39. package/dist/git/publish.js +23 -0
  40. package/dist/git/publish.js.map +1 -0
  41. package/dist/git/repo.d.ts +21 -0
  42. package/dist/git/repo.d.ts.map +1 -0
  43. package/dist/git/repo.js +113 -0
  44. package/dist/git/repo.js.map +1 -0
  45. package/dist/git/worktree.d.ts +25 -0
  46. package/dist/git/worktree.d.ts.map +1 -0
  47. package/dist/git/worktree.js +33 -0
  48. package/dist/git/worktree.js.map +1 -0
  49. package/dist/remote-control/manager.d.ts +46 -0
  50. package/dist/remote-control/manager.d.ts.map +1 -0
  51. package/dist/remote-control/manager.js +86 -0
  52. package/dist/remote-control/manager.js.map +1 -0
  53. package/dist/runtime/adapter.d.ts +27 -0
  54. package/dist/runtime/adapter.d.ts.map +1 -0
  55. package/dist/runtime/adapter.js +2 -0
  56. package/dist/runtime/adapter.js.map +1 -0
  57. package/dist/runtime/cli.d.ts +41 -0
  58. package/dist/runtime/cli.d.ts.map +1 -0
  59. package/dist/runtime/cli.js +540 -0
  60. package/dist/runtime/cli.js.map +1 -0
  61. package/dist/runtime/index.d.ts +10 -0
  62. package/dist/runtime/index.d.ts.map +1 -0
  63. package/dist/runtime/index.js +39 -0
  64. package/dist/runtime/index.js.map +1 -0
  65. package/dist/runtime/mock.d.ts +3 -0
  66. package/dist/runtime/mock.d.ts.map +1 -0
  67. package/dist/runtime/mock.js +34 -0
  68. package/dist/runtime/mock.js.map +1 -0
  69. package/dist/runtime/pty.d.ts +32 -0
  70. package/dist/runtime/pty.d.ts.map +1 -0
  71. package/dist/runtime/pty.js +197 -0
  72. package/dist/runtime/pty.js.map +1 -0
  73. package/dist/tools/scanner.d.ts +14 -0
  74. package/dist/tools/scanner.d.ts.map +1 -0
  75. package/dist/tools/scanner.js +53 -0
  76. package/dist/tools/scanner.js.map +1 -0
  77. package/dist/transport/api-client.d.ts +153 -0
  78. package/dist/transport/api-client.d.ts.map +1 -0
  79. package/dist/transport/api-client.js +93 -0
  80. package/dist/transport/api-client.js.map +1 -0
  81. package/package.json +41 -0
@@ -0,0 +1,15 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ export function defaultConfigPath() {
5
+ return join(homedir(), ".abitat-host", "config.json");
6
+ }
7
+ export async function loadHostConfig(path = defaultConfigPath()) {
8
+ const raw = await readFile(path, "utf8");
9
+ return JSON.parse(raw);
10
+ }
11
+ export async function saveHostConfig(config, path = defaultConfigPath()) {
12
+ await mkdir(dirname(path), { recursive: true });
13
+ await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, "utf8");
14
+ }
15
+ //# sourceMappingURL=host-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-config.js","sourceRoot":"","sources":["../../src/config/host-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AASlC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,aAAa,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAI,GAAG,iBAAiB,EAAE;IAC7D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAkB,EAAE,IAAI,GAAG,iBAAiB,EAAE;IACjF,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type RepoRuntime } from "./repo.js";
2
+ export interface CollectedChangeSet {
3
+ filesChanged: string[];
4
+ diffText: string;
5
+ summary: string;
6
+ }
7
+ export declare function collectChangeset(worktreePath: string, runtime?: RepoRuntime): Promise<CollectedChangeSet>;
8
+ export declare function parseChangedFiles(status: string): string[];
9
+ //# sourceMappingURL=changeset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset.d.ts","sourceRoot":"","sources":["../../src/git/changeset.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0C,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAErF,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,kBAAkB,CAAC,CAoB7B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,YAO/C"}
@@ -0,0 +1,78 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ import { defaultRepoRuntime, gitDiff, gitStatus } from "./repo.js";
4
+ export async function collectChangeset(worktreePath, runtime) {
5
+ const git = runtime ?? defaultRepoRuntime;
6
+ try {
7
+ await git.run("git", ["-C", worktreePath, "add", "-N", "."]);
8
+ const status = await gitStatus(worktreePath, git);
9
+ const diffText = await gitDiff(worktreePath, git);
10
+ const filesChanged = parseChangedFiles(status);
11
+ return {
12
+ filesChanged,
13
+ diffText,
14
+ summary: summaryFor(filesChanged.length)
15
+ };
16
+ }
17
+ catch (error) {
18
+ if (!isNotGitRepositoryError(error)) {
19
+ throw error;
20
+ }
21
+ return collectLocalDirectoryChangeset(worktreePath);
22
+ }
23
+ }
24
+ export function parseChangedFiles(status) {
25
+ return status
26
+ .split("\n")
27
+ .map((line) => line.trimEnd())
28
+ .filter(Boolean)
29
+ .map((line) => line.slice(3).trim())
30
+ .filter(Boolean);
31
+ }
32
+ async function collectLocalDirectoryChangeset(folderPath) {
33
+ const filesChanged = await listLocalFiles(folderPath);
34
+ const diffText = (await Promise.all(filesChanged.map(async (file) => {
35
+ const absolutePath = join(folderPath, file);
36
+ const content = await readTextPreview(absolutePath);
37
+ return [`diff --local a/${file} b/${file}`, `+++ b/${file}`, "@@", content].join("\n");
38
+ }))).join("\n");
39
+ return {
40
+ filesChanged,
41
+ diffText,
42
+ summary: summaryFor(filesChanged.length)
43
+ };
44
+ }
45
+ async function listLocalFiles(folderPath) {
46
+ const files = [];
47
+ const entries = await readdir(folderPath, { withFileTypes: true });
48
+ for (const entry of entries) {
49
+ if (entry.name.startsWith(".") || entry.name === "node_modules") {
50
+ continue;
51
+ }
52
+ const absolutePath = join(folderPath, entry.name);
53
+ if (entry.isDirectory()) {
54
+ const nestedFiles = await listLocalFiles(absolutePath);
55
+ files.push(...nestedFiles.map((file) => join(entry.name, file)));
56
+ continue;
57
+ }
58
+ if (entry.isFile()) {
59
+ files.push(relative(folderPath, absolutePath));
60
+ }
61
+ }
62
+ return files.sort();
63
+ }
64
+ async function readTextPreview(path) {
65
+ const details = await stat(path);
66
+ if (details.size > 128 * 1024) {
67
+ return "[file too large to preview]";
68
+ }
69
+ return readFile(path, "utf8").catch(() => "[binary file]");
70
+ }
71
+ function isNotGitRepositoryError(error) {
72
+ const message = error instanceof Error ? error.message : "";
73
+ return message.includes("not a git repository");
74
+ }
75
+ function summaryFor(count) {
76
+ return `Changed ${count} ${count === 1 ? "file" : "files"}.`;
77
+ }
78
+ //# sourceMappingURL=changeset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset.js","sourceRoot":"","sources":["../../src/git/changeset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ConversationType } from "@abitat_reece/shared";
2
+ interface BranchNameInput {
3
+ conversationId: string;
4
+ conversationType: ConversationType;
5
+ prompt: string;
6
+ }
7
+ export declare function branchNameForConversation(input: BranchNameInput): string;
8
+ export declare function resolveRepoPath(workspaceRoot: string, repoUrl: string): string;
9
+ export declare function resolveWorktreePath(workspaceRoot: string, conversationId: string, branchName: string): string;
10
+ export declare function assertInsideWorkspace(workspaceRoot: string, targetPath: string, message?: string): void;
11
+ export {};
12
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/git/paths.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,eAAe,UAM/D;AAED,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAUrE;AAED,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,UAUnB;AAED,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,SAAgC,QAQxC"}
@@ -0,0 +1,72 @@
1
+ import { resolve, sep } from "node:path";
2
+ export function branchNameForConversation(input) {
3
+ const shortId = input.conversationId
4
+ .replace(/^conversation_/, "")
5
+ .slice(0, 8)
6
+ .toLowerCase();
7
+ return `abitat/${input.conversationType}/${shortId}-${slugify(input.prompt)}`;
8
+ }
9
+ export function resolveRepoPath(workspaceRoot, repoUrl) {
10
+ const { owner, repo } = parseGithubRepoUrl(repoUrl);
11
+ const root = resolve(workspaceRoot);
12
+ const repoPath = resolve(root, "repos", "github.com", owner, `${repo}.git-working`);
13
+ if (!repoPath.startsWith(`${root}${sep}`)) {
14
+ throw new Error("Repo path escapes workspace root");
15
+ }
16
+ return repoPath;
17
+ }
18
+ export function resolveWorktreePath(workspaceRoot, conversationId, branchName) {
19
+ assertSafePathPart(conversationId);
20
+ const root = resolve(workspaceRoot);
21
+ const pathPart = `${conversationId}-${branchName.replace(/[^a-zA-Z0-9._-]+/g, "-")}`;
22
+ const worktreePath = resolve(root, "worktrees", pathPart);
23
+ assertInsideWorkspace(root, worktreePath, "Worktree path escapes workspace root");
24
+ return worktreePath;
25
+ }
26
+ export function assertInsideWorkspace(workspaceRoot, targetPath, message = "Path escapes workspace root") {
27
+ const root = resolve(workspaceRoot);
28
+ const path = resolve(targetPath);
29
+ if (!path.startsWith(`${root}${sep}`)) {
30
+ throw new Error(message);
31
+ }
32
+ }
33
+ function parseGithubRepoUrl(repoUrl) {
34
+ const ssh = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/.exec(repoUrl);
35
+ if (ssh) {
36
+ return normalizeParts(ssh[1], ssh[2]);
37
+ }
38
+ try {
39
+ const url = new URL(repoUrl);
40
+ if (url.hostname !== "github.com") {
41
+ throw new Error("Invalid GitHub repo URL");
42
+ }
43
+ const [owner, repo] = url.pathname
44
+ .replace(/^\/+/, "")
45
+ .replace(/\.git$/, "")
46
+ .split("/");
47
+ return normalizeParts(owner, repo);
48
+ }
49
+ catch {
50
+ throw new Error("Invalid GitHub repo URL");
51
+ }
52
+ }
53
+ function normalizeParts(owner, repo) {
54
+ if (!owner || !repo || owner.includes("..") || repo.includes("..") || repo.includes("/")) {
55
+ throw new Error("Invalid GitHub repo URL");
56
+ }
57
+ return { owner, repo };
58
+ }
59
+ function assertSafePathPart(value) {
60
+ if (!value || value.includes("..") || value.includes("/") || value.includes("\\")) {
61
+ throw new Error("Worktree path escapes workspace root");
62
+ }
63
+ }
64
+ function slugify(value) {
65
+ const slug = value
66
+ .toLowerCase()
67
+ .replace(/[^a-z0-9]+/g, "-")
68
+ .replace(/^-+|-+$/g, "")
69
+ .slice(0, 48);
70
+ return slug || "task";
71
+ }
72
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/git/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type RepoRuntime } from "./repo.js";
2
+ interface CommitAndPushInput {
3
+ worktreePath: string;
4
+ branchName: string;
5
+ commitMessage: string;
6
+ runtime?: RepoRuntime;
7
+ }
8
+ interface CreatePullRequestInput {
9
+ worktreePath: string;
10
+ branchName: string;
11
+ runtime?: RepoRuntime;
12
+ }
13
+ export declare function commitAndPushWorktree(input: CommitAndPushInput): Promise<{
14
+ commitSha: string;
15
+ }>;
16
+ export declare function tryCreatePullRequest(input: CreatePullRequestInput): Promise<{
17
+ prUrl: string;
18
+ errorMessage?: undefined;
19
+ } | {
20
+ errorMessage: string;
21
+ prUrl?: undefined;
22
+ }>;
23
+ export {};
24
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/git/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEjE,UAAU,kBAAkB;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB;;GAWpE;AAED,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,sBAAsB;;;;;;GAevE"}
@@ -0,0 +1,23 @@
1
+ import { defaultRepoRuntime } from "./repo.js";
2
+ export async function commitAndPushWorktree(input) {
3
+ const runtime = input.runtime ?? defaultRepoRuntime;
4
+ await runtime.run("git", ["-C", input.worktreePath, "add", "."]);
5
+ await runtime.run("git", ["-C", input.worktreePath, "commit", "-m", input.commitMessage]);
6
+ const commitSha = String((await runtime.run("git", ["-C", input.worktreePath, "rev-parse", "HEAD"])) ?? "").trim();
7
+ await runtime.run("git", ["-C", input.worktreePath, "push", "-u", "origin", input.branchName]);
8
+ return { commitSha };
9
+ }
10
+ export async function tryCreatePullRequest(input) {
11
+ const runtime = input.runtime ?? defaultRepoRuntime;
12
+ try {
13
+ const output = String((await runtime.run("gh", ["pr", "create", "--fill", "--head", input.branchName])) ?? "").trim();
14
+ const prUrl = output.split(/\s+/).find((token) => /^https?:\/\//.test(token));
15
+ return prUrl ? { prUrl } : { errorMessage: "GitHub CLI did not return a PR URL" };
16
+ }
17
+ catch (error) {
18
+ return {
19
+ errorMessage: error instanceof Error ? error.message : "GitHub CLI PR creation failed"
20
+ };
21
+ }
22
+ }
23
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/git/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,WAAW,CAAC;AAejE,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAyB;IACnE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,kBAAkB,CAAC;IAEpD,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACjE,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,MAAM,CACtB,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAClF,CAAC,IAAI,EAAE,CAAC;IACT,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAE/F,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAA6B;IACtE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,kBAAkB,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CACnB,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CACxF,CAAC,IAAI,EAAE,CAAC;QACT,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAE9E,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,oCAAoC,EAAE,CAAC;IACpF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,+BAA+B;SACvF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface RepoRuntime {
2
+ exists(path: string): Promise<boolean>;
3
+ run(command: string, args: string[]): Promise<string | void>;
4
+ }
5
+ interface SyncRepoInput {
6
+ repoUrl: string;
7
+ defaultBranch: string;
8
+ targetPath: string;
9
+ runtime?: RepoRuntime;
10
+ }
11
+ export declare function syncRepo(input: SyncRepoInput): Promise<"fetched" | "cloned">;
12
+ export declare function fetchRepo(repoPath: string, defaultBranch: string, runtime?: RepoRuntime): Promise<string | void>;
13
+ export declare function addWorktree(repoPath: string, worktreePath: string, branchName: string, defaultBranch: string, runtime?: RepoRuntime): Promise<string | void>;
14
+ export declare function gitStatus(worktreePath: string, runtime?: RepoRuntime): Promise<string>;
15
+ export declare function gitDiff(worktreePath: string, runtime?: RepoRuntime): Promise<string>;
16
+ export declare function commitWorktree(worktreePath: string, commitMessage: string, runtime?: RepoRuntime): Promise<string | void>;
17
+ export declare function pushBranch(repoPath: string, branchName: string, runtime?: RepoRuntime): Promise<string | void>;
18
+ export declare function removeWorktree(repoPath: string, worktreePath: string, runtime?: RepoRuntime): Promise<string | void>;
19
+ export declare const defaultRepoRuntime: RepoRuntime;
20
+ export {};
21
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/git/repo.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9D;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,wBAAsB,QAAQ,CAAC,KAAK,EAAE,aAAa,iCAiBlD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,cAAqB,0BAE9F;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,cAAqB,0BAY7B;AAED,wBAAsB,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,cAAqB,mBAEjF;AAED,wBAAsB,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,cAAqB,mBAE/E;AAED,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,OAAO,cAAqB,0BAG7B;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,cAAqB,0BAE5F;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,cAAqB,0BAG7B;AAED,eAAO,MAAM,kBAAkB,EAAE,WAuBhC,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { execFile } from "node:child_process";
2
+ import { access, mkdir } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { promisify } from "node:util";
5
+ const execFileAsync = promisify(execFile);
6
+ const DEFAULT_GIT_TIMEOUT_MS = 120_000;
7
+ export async function syncRepo(input) {
8
+ const runtime = input.runtime ?? defaultRepoRuntime;
9
+ if (await runtime.exists(input.targetPath)) {
10
+ await runtime.run("git", ["-C", input.targetPath, "fetch", "origin"]);
11
+ return "fetched";
12
+ }
13
+ await mkdir(dirname(input.targetPath), { recursive: true });
14
+ await runtime.run("git", [
15
+ "clone",
16
+ "--branch",
17
+ input.defaultBranch,
18
+ input.repoUrl,
19
+ input.targetPath
20
+ ]);
21
+ return "cloned";
22
+ }
23
+ export function fetchRepo(repoPath, defaultBranch, runtime = defaultRepoRuntime) {
24
+ return runtime.run("git", ["-C", repoPath, "fetch", "origin", defaultBranch]);
25
+ }
26
+ export function addWorktree(repoPath, worktreePath, branchName, defaultBranch, runtime = defaultRepoRuntime) {
27
+ return runtime.run("git", [
28
+ "-C",
29
+ repoPath,
30
+ "worktree",
31
+ "add",
32
+ "-B",
33
+ branchName,
34
+ worktreePath,
35
+ `origin/${defaultBranch}`
36
+ ]);
37
+ }
38
+ export async function gitStatus(worktreePath, runtime = defaultRepoRuntime) {
39
+ return String((await runtime.run("git", ["-C", worktreePath, "status", "--short"])) ?? "");
40
+ }
41
+ export async function gitDiff(worktreePath, runtime = defaultRepoRuntime) {
42
+ return String((await runtime.run("git", ["-C", worktreePath, "diff"])) ?? "");
43
+ }
44
+ export function commitWorktree(worktreePath, commitMessage, runtime = defaultRepoRuntime) {
45
+ return runtime.run("git", ["-C", worktreePath, "commit", "-am", commitMessage]);
46
+ }
47
+ export function pushBranch(repoPath, branchName, runtime = defaultRepoRuntime) {
48
+ return runtime.run("git", ["-C", repoPath, "push", "-u", "origin", branchName]);
49
+ }
50
+ export function removeWorktree(repoPath, worktreePath, runtime = defaultRepoRuntime) {
51
+ return runtime.run("git", ["-C", repoPath, "worktree", "remove", worktreePath]);
52
+ }
53
+ export const defaultRepoRuntime = {
54
+ async exists(path) {
55
+ try {
56
+ await access(path);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ },
63
+ async run(command, args) {
64
+ const timeoutMs = gitTimeoutMs();
65
+ try {
66
+ const { stdout } = await execFileAsync(command, args, {
67
+ env: gitProcessEnv(),
68
+ maxBuffer: 10 * 1024 * 1024,
69
+ timeout: timeoutMs
70
+ });
71
+ return stdout;
72
+ }
73
+ catch (error) {
74
+ throw formatProcessError(command, args, error, timeoutMs);
75
+ }
76
+ }
77
+ };
78
+ function gitTimeoutMs() {
79
+ const value = Number(process.env.ABITAT_GIT_TIMEOUT_MS ?? DEFAULT_GIT_TIMEOUT_MS);
80
+ return Number.isFinite(value) && value > 0 ? value : DEFAULT_GIT_TIMEOUT_MS;
81
+ }
82
+ function gitProcessEnv() {
83
+ return {
84
+ ...process.env,
85
+ GIT_ASKPASS: process.env.GIT_ASKPASS ?? "echo",
86
+ GIT_TERMINAL_PROMPT: "0",
87
+ SSH_ASKPASS: process.env.SSH_ASKPASS ?? "echo",
88
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes"
89
+ };
90
+ }
91
+ function formatProcessError(command, args, error, timeoutMs) {
92
+ const details = processErrorDetails(error);
93
+ const timedOut = details.killed && details.signal === "SIGTERM";
94
+ const commandLine = [command, ...args].join(" ");
95
+ const message = timedOut
96
+ ? `Command timed out after ${timeoutMs}ms`
97
+ : (details.message ?? "Command failed");
98
+ const stderr = details.stderr ? `\n${details.stderr}` : "";
99
+ return new Error(`${message}: ${commandLine}${stderr}`);
100
+ }
101
+ function processErrorDetails(error) {
102
+ if (!(error instanceof Error)) {
103
+ return {};
104
+ }
105
+ const processError = error;
106
+ return {
107
+ killed: processError.killed,
108
+ message: processError.message,
109
+ signal: processError.signal,
110
+ stderr: processError.stderr?.toString().trim()
111
+ };
112
+ }
113
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../src/git/repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ConversationType } from "@abitat_reece/shared";
2
+ import { type RepoRuntime } from "./repo.js";
3
+ interface SetupConversationWorktreeInput {
4
+ workspaceRoot: string;
5
+ conversationId: string;
6
+ conversationType: ConversationType;
7
+ prompt: string;
8
+ repoUrl: string;
9
+ defaultBranch: string;
10
+ runtime?: RepoRuntime;
11
+ }
12
+ interface CleanupConversationWorktreeInput {
13
+ workspaceRoot: string;
14
+ repoPath: string;
15
+ worktreePath: string;
16
+ runtime?: RepoRuntime;
17
+ }
18
+ export declare function setupConversationWorktree(input: SetupConversationWorktreeInput): Promise<{
19
+ branchName: string;
20
+ repoPath: string;
21
+ worktreePath: string;
22
+ }>;
23
+ export declare function cleanupConversationWorktree(input: CleanupConversationWorktreeInput): Promise<void>;
24
+ export {};
25
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQ7D,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,WAAW,CAAC;AAEnB,UAAU,8BAA8B;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,UAAU,gCAAgC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,8BAA8B;;;;GA0BpF;AAED,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,gCAAgC,iBAOxF"}
@@ -0,0 +1,33 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { assertInsideWorkspace, branchNameForConversation, resolveRepoPath, resolveWorktreePath } from "./paths.js";
4
+ import { addWorktree, defaultRepoRuntime, fetchRepo, gitStatus, removeWorktree, syncRepo } from "./repo.js";
5
+ export async function setupConversationWorktree(input) {
6
+ const runtime = input.runtime ?? defaultRepoRuntime;
7
+ const repoPath = resolveRepoPath(input.workspaceRoot, input.repoUrl);
8
+ const branchName = branchNameForConversation({
9
+ conversationId: input.conversationId,
10
+ conversationType: input.conversationType,
11
+ prompt: input.prompt
12
+ });
13
+ const worktreePath = resolveWorktreePath(input.workspaceRoot, input.conversationId, branchName);
14
+ if (await runtime?.exists(worktreePath)) {
15
+ await gitStatus(worktreePath, runtime);
16
+ return { branchName, repoPath, worktreePath };
17
+ }
18
+ await syncRepo({
19
+ repoUrl: input.repoUrl,
20
+ defaultBranch: input.defaultBranch,
21
+ targetPath: repoPath,
22
+ runtime
23
+ });
24
+ await fetchRepo(repoPath, input.defaultBranch, runtime);
25
+ await mkdir(dirname(worktreePath), { recursive: true });
26
+ await addWorktree(repoPath, worktreePath, branchName, input.defaultBranch, runtime);
27
+ return { branchName, repoPath, worktreePath };
28
+ }
29
+ export async function cleanupConversationWorktree(input) {
30
+ assertInsideWorkspace(input.workspaceRoot, input.worktreePath, "Worktree path escapes workspace root");
31
+ await removeWorktree(input.repoPath, input.worktreePath, input.runtime);
32
+ }
33
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,cAAc,EACd,QAAQ,EAET,MAAM,WAAW,CAAC;AAmBnB,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAAqC;IACnF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,kBAAkB,CAAC;IACpD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,yBAAyB,CAAC;QAC3C,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,mBAAmB,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IAEhG,IAAI,MAAM,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,QAAQ,CAAC;QACb,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,UAAU,EAAE,QAAQ;QACpB,OAAO;KACR,CAAC,CAAC;IACH,MAAM,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAEpF,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAAuC;IACvF,qBAAqB,CACnB,KAAK,CAAC,aAAa,EACnB,KAAK,CAAC,YAAY,EAClB,sCAAsC,CACvC,CAAC;IACF,MAAM,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { RemoteControlStatus } from "@abitat_reece/shared";
2
+ export interface RemoteControlSessionSummary {
3
+ id: string;
4
+ status: RemoteControlStatus;
5
+ hostMachineId: string;
6
+ clientMachineId: string;
7
+ screenEnabled: boolean;
8
+ inputEnabled: boolean;
9
+ errorMessage?: string | null;
10
+ }
11
+ export interface RemoteControlClient {
12
+ pollRemoteControlSessions(machineId: string): Promise<{
13
+ sessions: RemoteControlSessionSummary[];
14
+ }>;
15
+ updateRemoteControlSession(sessionId: string, input: {
16
+ status: RemoteControlStatus;
17
+ errorMessage?: string;
18
+ }): Promise<{
19
+ session: RemoteControlSessionSummary;
20
+ }>;
21
+ }
22
+ export interface RemoteControlHelperInput {
23
+ apiUrl: string;
24
+ clientMachineId: string;
25
+ helperPath: string;
26
+ hostToken?: string;
27
+ inputEnabled: boolean;
28
+ screenEnabled: boolean;
29
+ sessionId: string;
30
+ }
31
+ export interface RemoteControlHelperProcess {
32
+ kill(): void;
33
+ onExit(handler: (exitCode: number | null) => void): void;
34
+ }
35
+ interface RemoteControlManagerOptions {
36
+ apiUrl: string;
37
+ helperPath?: string;
38
+ hostToken?: string;
39
+ spawnHelper?: (input: RemoteControlHelperInput) => RemoteControlHelperProcess;
40
+ }
41
+ export declare function createRemoteControlManager(client: RemoteControlClient, options: RemoteControlManagerOptions): {
42
+ tick(machineId: string): Promise<void>;
43
+ stopAll(): void;
44
+ };
45
+ export {};
46
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/remote-control/manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,mBAAmB,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,yBAAyB,CACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,QAAQ,EAAE,2BAA2B,EAAE,CAAA;KAAE,CAAC,CAAC;IACxD,0BAA0B,CACxB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE;QAAE,MAAM,EAAE,mBAAmB,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5D,OAAO,CAAC;QAAE,OAAO,EAAE,2BAA2B,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,IAAI,IAAI,CAAC;IACb,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;CAC1D;AAED,UAAU,2BAA2B;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,0BAA0B,CAAC;CAC/E;AAKD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,2BAA2B;oBAMZ,MAAM;;EAuD/B"}
@@ -0,0 +1,86 @@
1
+ import { spawn } from "node:child_process";
2
+ const startableStatuses = new Set(["requested", "connecting", "active"]);
3
+ const stoppedStatuses = new Set(["ended", "failed"]);
4
+ export function createRemoteControlManager(client, options) {
5
+ const activeHelpers = new Map();
6
+ const spawnHelper = options.spawnHelper ?? defaultSpawnHelper;
7
+ return {
8
+ async tick(machineId) {
9
+ const { sessions } = await client.pollRemoteControlSessions(machineId);
10
+ for (const session of sessions) {
11
+ if (stoppedStatuses.has(session.status)) {
12
+ stopHelper(activeHelpers, session.id);
13
+ continue;
14
+ }
15
+ if (!startableStatuses.has(session.status) || activeHelpers.has(session.id)) {
16
+ continue;
17
+ }
18
+ if (!options.helperPath) {
19
+ await client.updateRemoteControlSession(session.id, {
20
+ status: "failed",
21
+ errorMessage: "Remote-control helper is not configured"
22
+ });
23
+ continue;
24
+ }
25
+ const helper = spawnHelper({
26
+ apiUrl: options.apiUrl,
27
+ clientMachineId: session.clientMachineId,
28
+ helperPath: options.helperPath,
29
+ hostToken: options.hostToken,
30
+ inputEnabled: session.inputEnabled,
31
+ screenEnabled: session.screenEnabled,
32
+ sessionId: session.id
33
+ });
34
+ activeHelpers.set(session.id, helper);
35
+ helper.onExit((exitCode) => {
36
+ if (activeHelpers.get(session.id) !== helper) {
37
+ return;
38
+ }
39
+ activeHelpers.delete(session.id);
40
+ void client.updateRemoteControlSession(session.id, {
41
+ status: exitCode === 0 ? "ended" : "failed",
42
+ ...(exitCode === 0
43
+ ? {}
44
+ : { errorMessage: `Remote helper exited with code ${exitCode}` })
45
+ });
46
+ });
47
+ await client.updateRemoteControlSession(session.id, { status: "connecting" });
48
+ }
49
+ },
50
+ stopAll() {
51
+ for (const sessionId of activeHelpers.keys()) {
52
+ stopHelper(activeHelpers, sessionId);
53
+ }
54
+ }
55
+ };
56
+ }
57
+ function stopHelper(activeHelpers, sessionId) {
58
+ const helper = activeHelpers.get(sessionId);
59
+ if (!helper) {
60
+ return;
61
+ }
62
+ activeHelpers.delete(sessionId);
63
+ helper.kill();
64
+ }
65
+ function defaultSpawnHelper(input) {
66
+ const child = spawn(input.helperPath, ["--session-id", input.sessionId, "--api-url", input.apiUrl], {
67
+ env: {
68
+ ...process.env,
69
+ ABITAT_HOST_TOKEN: input.hostToken ?? "",
70
+ ABITAT_REMOTE_CONTROL_INPUT: input.inputEnabled ? "1" : "0",
71
+ ABITAT_REMOTE_CONTROL_CLIENT_MACHINE_ID: input.clientMachineId,
72
+ ABITAT_REMOTE_CONTROL_SCREEN: input.screenEnabled ? "1" : "0",
73
+ ABITAT_REMOTE_CONTROL_SESSION_ID: input.sessionId
74
+ },
75
+ stdio: "ignore"
76
+ });
77
+ return {
78
+ kill() {
79
+ child.kill();
80
+ },
81
+ onExit(handler) {
82
+ child.once("exit", (code) => handler(code));
83
+ }
84
+ };
85
+ }
86
+ //# sourceMappingURL=manager.js.map