@companyhelm/runner 0.1.1 → 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 (38) hide show
  1. package/RUNTIME_IMAGE_VERSION +1 -1
  2. package/dist/commands/doctor.js +44 -0
  3. package/dist/commands/register-commands.js +2 -0
  4. package/dist/commands/root.js +172 -247
  5. package/dist/commands/runner/common.js +3 -1
  6. package/dist/commands/runner/start.js +3 -0
  7. package/dist/config.js +8 -2
  8. package/dist/preflight/check.js +2 -0
  9. package/dist/preflight/checks/linux/apparmor_restrict_unprivileged_userns_check.js +96 -0
  10. package/dist/preflight/entrypoints.js +53 -0
  11. package/dist/preflight/runner_preflight.js +56 -0
  12. package/dist/provisioning/host_provisioning/thread_metadata_store.js +249 -0
  13. package/dist/provisioning/host_provisioning/thread_metadata_types.js +2 -0
  14. package/dist/provisioning/host_provisioning/thread_workspace_provisioner.js +57 -0
  15. package/dist/provisioning/runtime_provisioning/script_renderer.js +120 -0
  16. package/dist/provisioning/runtime_provisioning/system_prompt.js +44 -0
  17. package/dist/provisioning/template_renderer.js +29 -0
  18. package/dist/service/companyhelm_api_client.js +0 -48
  19. package/dist/service/docker/app_server_container.js +16 -1
  20. package/dist/service/sdk/refresh_models.js +8 -0
  21. package/dist/service/thread_lifecycle.js +30 -41
  22. package/dist/service/thread_turn_state.js +1 -0
  23. package/dist/templates/provisioning/runtime_agent_metadata.sh.j2 +8 -0
  24. package/dist/templates/provisioning/runtime_bashrc.sh.j2 +7 -0
  25. package/dist/templates/provisioning/runtime_codex_config.sh.j2 +7 -0
  26. package/dist/templates/provisioning/runtime_git_config.sh.j2 +28 -0
  27. package/dist/templates/provisioning/runtime_identity.sh.j2 +65 -0
  28. package/dist/templates/provisioning/runtime_thread_git_skills_clone.sh.j2 +11 -0
  29. package/dist/templates/provisioning/runtime_thread_git_skills_link.sh.j2 +7 -0
  30. package/dist/templates/provisioning/runtime_tooling_validation.sh.j2 +32 -0
  31. package/dist/templates/system_prompts/common.md.j2 +37 -0
  32. package/dist/templates/system_prompts/dedicated_workspace.md.j2 +5 -0
  33. package/dist/templates/system_prompts/shared_workspace.md.j2 +6 -0
  34. package/dist/testing/vitest_reporter.js +23 -0
  35. package/dist/utils/daemon_startup_watchdog.js +27 -0
  36. package/package.json +2 -2
  37. package/dist/service/workspace_agents.js +0 -82
  38. package/dist/templates/runtime_agents.md.j2 +0 -50
@@ -0,0 +1,5 @@
1
+ ## Dedicated Workspace
2
+
3
+ - This runtime is using a dedicated per-thread host workspace mounted at `/workspace`.
4
+ - Files in `/workspace` are isolated to this thread workspace lifecycle.
5
+ - The runner may remove the host workspace when the thread is deleted.
@@ -0,0 +1,6 @@
1
+ ## Shared Workspace
2
+
3
+ - This runtime is using a shared host workspace mounted directly at `/workspace`.
4
+ - Changes made in `/workspace` may be visible to multiple threads that use the same runner workspace path.
5
+ - Do not assume `/workspace` is isolated per thread.
6
+ - you need to use git worktrees to isolate your working directory from the shared workspace.
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VitestReporterResolver = void 0;
4
+ class VitestReporterResolver {
5
+ constructor(options) {
6
+ this.stdoutIsTTY = options.stdoutIsTTY;
7
+ this.env = options.env ?? process.env;
8
+ }
9
+ resolve() {
10
+ const configured = this.env.COMPANYHELM_VITEST_REPORTER?.trim();
11
+ if (configured && configured.length > 0) {
12
+ return configured
13
+ .split(",")
14
+ .map((value) => value.trim())
15
+ .filter((value) => value.length > 0);
16
+ }
17
+ if (this.stdoutIsTTY) {
18
+ return ["basic"];
19
+ }
20
+ return undefined;
21
+ }
22
+ }
23
+ exports.VitestReporterResolver = VitestReporterResolver;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DaemonStartupWatchdog = void 0;
4
+ class DaemonStartupWatchdog {
5
+ constructor(timeoutMs, onTimeout) {
6
+ this.timeoutMs = timeoutMs;
7
+ this.onTimeout = onTimeout;
8
+ this.bump();
9
+ }
10
+ bump() {
11
+ if (this.timer) {
12
+ clearTimeout(this.timer);
13
+ }
14
+ this.timer = setTimeout(() => {
15
+ this.timer = undefined;
16
+ this.onTimeout();
17
+ }, this.timeoutMs);
18
+ }
19
+ finish() {
20
+ if (!this.timer) {
21
+ return;
22
+ }
23
+ clearTimeout(this.timer);
24
+ this.timer = undefined;
25
+ }
26
+ }
27
+ exports.DaemonStartupWatchdog = DaemonStartupWatchdog;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@companyhelm/runner",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Run the CompanyHelm runner in fully isolated Docker sandboxes.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "@bufbuild/protobuf": "^2.11.0",
34
34
  "@clack/prompts": "^1.0.1",
35
- "@companyhelm/protos": "^0.5.20",
35
+ "@companyhelm/protos": "^0.5.26",
36
36
  "@grpc/grpc-js": "^1.14.3",
37
37
  "@libsql/client": "^0.17.0",
38
38
  "commander": "^14.0.0",
@@ -1,82 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.renderRuntimeAgentsMd = renderRuntimeAgentsMd;
4
- exports.ensureWorkspaceAgentsMd = ensureWorkspaceAgentsMd;
5
- const node_fs_1 = require("node:fs");
6
- const node_path_1 = require("node:path");
7
- const RUNTIME_AGENTS_TEMPLATE_PATH = "templates/runtime_agents.md.j2";
8
- const DEFAULT_HOME_DIRECTORY = "/home/agent";
9
- function renderJinjaTemplate(template, context) {
10
- return template.replace(/{{\s*([a-zA-Z0-9_]+)\s*}}/g, (_match, key) => {
11
- const value = context[key];
12
- if (value === undefined) {
13
- throw new Error(`Missing template value for key '${key}'`);
14
- }
15
- return value;
16
- });
17
- }
18
- function resolveTemplatePath() {
19
- const distRelativePath = (0, node_path_1.join)(__dirname, "..", RUNTIME_AGENTS_TEMPLATE_PATH);
20
- if ((0, node_fs_1.existsSync)(distRelativePath)) {
21
- return distRelativePath;
22
- }
23
- const sourceRelativePath = (0, node_path_1.join)(__dirname, "..", "..", "src", RUNTIME_AGENTS_TEMPLATE_PATH);
24
- if ((0, node_fs_1.existsSync)(sourceRelativePath)) {
25
- return sourceRelativePath;
26
- }
27
- throw new Error(`Runtime AGENTS template was not found at ${distRelativePath} or ${sourceRelativePath}`);
28
- }
29
- function extractTopLevelSections(markdown) {
30
- const sections = [];
31
- const headingRegex = /^## .+$/gm;
32
- const matches = [...markdown.matchAll(headingRegex)];
33
- for (let index = 0; index < matches.length; index += 1) {
34
- const match = matches[index];
35
- const marker = match[0].trim();
36
- const start = match.index ?? 0;
37
- const end = index + 1 < matches.length ? (matches[index + 1].index ?? markdown.length) : markdown.length;
38
- const content = markdown.slice(start, end).trimEnd();
39
- sections.push({ marker, content });
40
- }
41
- return sections;
42
- }
43
- function renderRuntimeAgentsMd(homeDirectory = DEFAULT_HOME_DIRECTORY) {
44
- const template = (0, node_fs_1.readFileSync)(resolveTemplatePath(), "utf8");
45
- return renderJinjaTemplate(template, {
46
- home_directory: homeDirectory,
47
- }).trim() + "\n";
48
- }
49
- function ensureWorkspaceAgentsMd(workspaceDirectory, homeDirectory = DEFAULT_HOME_DIRECTORY) {
50
- (0, node_fs_1.mkdirSync)(workspaceDirectory, { recursive: true });
51
- const agentsPath = (0, node_path_1.join)(workspaceDirectory, "AGENTS.md");
52
- let existing = "";
53
- try {
54
- existing = (0, node_fs_1.readFileSync)(agentsPath, "utf8");
55
- }
56
- catch {
57
- existing = "";
58
- }
59
- let rendered = "";
60
- try {
61
- rendered = renderRuntimeAgentsMd(homeDirectory);
62
- }
63
- catch {
64
- return;
65
- }
66
- const templateSections = extractTopLevelSections(rendered);
67
- const pendingSections = templateSections
68
- .filter((section) => !existing.includes(section.marker))
69
- .map((section) => section.content);
70
- if (pendingSections.length === 0) {
71
- return;
72
- }
73
- const updated = existing.trim()
74
- ? `${existing.trimEnd()}\n\n${pendingSections.join("\n\n")}\n`
75
- : rendered;
76
- try {
77
- (0, node_fs_1.writeFileSync)(agentsPath, updated, "utf8");
78
- }
79
- catch {
80
- // Best-effort workspace instruction file.
81
- }
82
- }
@@ -1,50 +0,0 @@
1
- # Agent Instructions
2
-
3
- ## Workspace Structure
4
-
5
- - You are running in a thread-specific container and workspace
6
- - This workspace is not initialized as a Git repository by default. Repositories should live in a subdirectory of the workspace.
7
-
8
- ## Docker
9
-
10
- Docker is available, the docker host runs in a separate container. The network is shared with container.
11
- - only the `/workspace` is shared with the docker host
12
- - `{{home_directory}}/.codex/auth.json` is also shared with the docker host
13
- - Nested DinD is not supported in this environment because the outer runtime already uses rootless DinD.
14
- - If you need to use Docker in Docker you can mount the docker socket in the container and use this environment DinD to run containers within containers.
15
-
16
- ## GitHub Installations
17
-
18
- - Synced GitHub installation credentials are written to `/workspace/.companyhelm/installations.json`.
19
- - Use `list-installations` to inspect installation IDs, repository scopes, tokens, and expiration timestamps.
20
- - Use `gh-use-installation <installation-id>` to configure `gh` authentication for a specific installation.
21
-
22
- ```bash
23
- # Inspect synced installation credentials
24
- list-installations
25
-
26
- # Configure gh to use installation 112331765
27
- gh-use-installation 112331765
28
-
29
- # Verify gh is authenticated for github.com
30
- gh auth status --hostname github.com
31
- ```
32
-
33
- ## Available CLI Tools
34
-
35
- - `list-installations`: list synced GitHub installations with repositories, access tokens, and expirations.
36
- - `gh-use-installation <installation-id>`: configure `gh` authentication for a selected GitHub installation token.
37
- - `aws`: AWS CLI is pre-installed and available in `PATH`.
38
- - For scripted PR creation/updates, always use `gh pr create --body-file <path>` and `gh pr edit --body-file <path>` instead of inline `--body` to avoid shell interpolation of markdown backticks.
39
- - DO NOT INSTALL PLAYWRIGHT IN THE RUNTIME IMAGE. Playwright CLI is already installed and available for browser automation tasks with Chromium pre-installed: `playwright open --browser=chromium ...`
40
-
41
- ## CompanyHelm Agent CLI
42
-
43
- - `companyhelm-agent` is pre-installed in the runtime image.
44
- - Thread bootstrap writes `{{home_directory}}/.config/companyhelm-agent-cli/config.json` with:
45
- - `agent_api_url`: localhost targets are rewritten to `host.docker.internal` (for example `http://host.docker.internal:<port>`) for Docker-to-host access.
46
- - `token`: sourced from the thread secret.
47
- - Example commands:
48
- - `companyhelm-agent task get --task-id <id>`
49
- - `companyhelm-agent task dependencies --task-id <id>`
50
- - `companyhelm-agent task update-status --task-id <id> --status <draft|pending|in_progress|completed>`