runtimeuse 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 (120) hide show
  1. package/.env.example +4 -0
  2. package/README.md +222 -0
  3. package/dist/agent-handler.d.ts +26 -0
  4. package/dist/agent-handler.d.ts.map +1 -0
  5. package/dist/agent-handler.js +2 -0
  6. package/dist/agent-handler.js.map +1 -0
  7. package/dist/artifact-manager.d.ts +27 -0
  8. package/dist/artifact-manager.d.ts.map +1 -0
  9. package/dist/artifact-manager.js +125 -0
  10. package/dist/artifact-manager.js.map +1 -0
  11. package/dist/artifact-manager.test.d.ts +2 -0
  12. package/dist/artifact-manager.test.d.ts.map +1 -0
  13. package/dist/artifact-manager.test.js +251 -0
  14. package/dist/artifact-manager.test.js.map +1 -0
  15. package/dist/claude-handler.d.ts +3 -0
  16. package/dist/claude-handler.d.ts.map +1 -0
  17. package/dist/claude-handler.js +76 -0
  18. package/dist/claude-handler.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +87 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/command-handler.d.ts +22 -0
  24. package/dist/command-handler.d.ts.map +1 -0
  25. package/dist/command-handler.js +75 -0
  26. package/dist/command-handler.js.map +1 -0
  27. package/dist/command-handler.test.d.ts +2 -0
  28. package/dist/command-handler.test.d.ts.map +1 -0
  29. package/dist/command-handler.test.js +267 -0
  30. package/dist/command-handler.test.js.map +1 -0
  31. package/dist/constants.d.ts +3 -0
  32. package/dist/constants.d.ts.map +1 -0
  33. package/dist/constants.js +13 -0
  34. package/dist/constants.js.map +1 -0
  35. package/dist/default-handler.d.ts +3 -0
  36. package/dist/default-handler.d.ts.map +1 -0
  37. package/dist/default-handler.js +76 -0
  38. package/dist/default-handler.js.map +1 -0
  39. package/dist/download-handler.d.ts +8 -0
  40. package/dist/download-handler.d.ts.map +1 -0
  41. package/dist/download-handler.js +36 -0
  42. package/dist/download-handler.js.map +1 -0
  43. package/dist/download-handler.test.d.ts +2 -0
  44. package/dist/download-handler.test.d.ts.map +1 -0
  45. package/dist/download-handler.test.js +123 -0
  46. package/dist/download-handler.test.js.map +1 -0
  47. package/dist/index.d.ts +20 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +21 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/logger.d.ts +8 -0
  52. package/dist/logger.d.ts.map +1 -0
  53. package/dist/logger.js +14 -0
  54. package/dist/logger.js.map +1 -0
  55. package/dist/openai-handler.d.ts +3 -0
  56. package/dist/openai-handler.d.ts.map +1 -0
  57. package/dist/openai-handler.js +86 -0
  58. package/dist/openai-handler.js.map +1 -0
  59. package/dist/server.d.ts +21 -0
  60. package/dist/server.d.ts.map +1 -0
  61. package/dist/server.js +52 -0
  62. package/dist/server.js.map +1 -0
  63. package/dist/session.d.ts +29 -0
  64. package/dist/session.d.ts.map +1 -0
  65. package/dist/session.js +244 -0
  66. package/dist/session.js.map +1 -0
  67. package/dist/session.test.d.ts +2 -0
  68. package/dist/session.test.d.ts.map +1 -0
  69. package/dist/session.test.js +339 -0
  70. package/dist/session.test.js.map +1 -0
  71. package/dist/storage.d.ts +3 -0
  72. package/dist/storage.d.ts.map +1 -0
  73. package/dist/storage.js +21 -0
  74. package/dist/storage.js.map +1 -0
  75. package/dist/types.d.ts +62 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +2 -0
  78. package/dist/types.js.map +1 -0
  79. package/dist/upload-tracker.d.ts +10 -0
  80. package/dist/upload-tracker.d.ts.map +1 -0
  81. package/dist/upload-tracker.js +27 -0
  82. package/dist/upload-tracker.js.map +1 -0
  83. package/dist/upload-tracker.test.d.ts +2 -0
  84. package/dist/upload-tracker.test.d.ts.map +1 -0
  85. package/dist/upload-tracker.test.js +89 -0
  86. package/dist/upload-tracker.test.js.map +1 -0
  87. package/dist/utils.d.ts +7 -0
  88. package/dist/utils.d.ts.map +1 -0
  89. package/dist/utils.js +32 -0
  90. package/dist/utils.js.map +1 -0
  91. package/dist/utils.test.d.ts +2 -0
  92. package/dist/utils.test.d.ts.map +1 -0
  93. package/dist/utils.test.js +92 -0
  94. package/dist/utils.test.js.map +1 -0
  95. package/package.json +40 -0
  96. package/scripts/dev-publish.sh +45 -0
  97. package/src/agent-handler.ts +26 -0
  98. package/src/artifact-manager.test.ts +320 -0
  99. package/src/artifact-manager.ts +170 -0
  100. package/src/claude-handler.ts +95 -0
  101. package/src/cli.ts +107 -0
  102. package/src/command-handler.test.ts +507 -0
  103. package/src/command-handler.ts +102 -0
  104. package/src/constants.ts +12 -0
  105. package/src/download-handler.test.ts +183 -0
  106. package/src/download-handler.ts +45 -0
  107. package/src/index.ts +59 -0
  108. package/src/logger.ts +20 -0
  109. package/src/openai-handler.ts +120 -0
  110. package/src/server.ts +68 -0
  111. package/src/session.test.ts +448 -0
  112. package/src/session.ts +319 -0
  113. package/src/storage.ts +28 -0
  114. package/src/types.ts +101 -0
  115. package/src/upload-tracker.test.ts +112 -0
  116. package/src/upload-tracker.ts +30 -0
  117. package/src/utils.test.ts +120 -0
  118. package/src/utils.ts +35 -0
  119. package/tsconfig.json +20 -0
  120. package/vitest.config.ts +7 -0
package/.env.example ADDED
@@ -0,0 +1,4 @@
1
+ # If you need to run npm run dev-publish, then you need to set these variables
2
+ # S3_BUCKET='runtimeuse-dev-builds'
3
+ # S3_PREFIX='your-prefix' # optional, defaults to 'local-dev'
4
+ # PRESIGN_EXPIRY=3600 # optional, defaults to 3600
package/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # runtimeuse (Runtime)
2
+
3
+ TypeScript runtime package for [runtimeuse](https://github.com/getlark/runtimeuse). Runs inside the sandbox and handles the agent lifecycle: receives invocations over WebSocket, executes your agent handler, manages artifact uploads, runs pre-commands, downloads runtime files, and sends structured results back to the client.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install runtimeuse
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ Run the runtime inside any sandbox:
14
+
15
+ ```bash
16
+ npx -y runtimeuse
17
+ ```
18
+
19
+ This starts a WebSocket server on port 8080 using the OpenAI agent handler (default). You can choose between built-in handlers:
20
+
21
+ - **`openai`** (default) -- uses `@openai/agents` SDK
22
+ - **`claude`** -- uses `@anthropic-ai/claude-agent-sdk` with Claude Code tools and `bypassPermissions` mode
23
+
24
+ ```bash
25
+ npx -y runtimeuse # OpenAI (default)
26
+ npx -y runtimeuse --agent claude # Claude
27
+ ```
28
+
29
+ Use it programmatically:
30
+
31
+ ```typescript
32
+ import { RuntimeUseServer, openaiHandler, claudeHandler } from "runtimeuse";
33
+
34
+ const server = new RuntimeUseServer({ handler: openaiHandler, port: 8080 });
35
+ await server.start();
36
+ ```
37
+
38
+ ### Custom Handler
39
+
40
+ Implement `AgentHandler` to plug in your own agent:
41
+
42
+ ```typescript
43
+ import { RuntimeUseServer } from "runtimeuse";
44
+ import type {
45
+ AgentHandler,
46
+ AgentInvocation,
47
+ AgentResult,
48
+ MessageSender,
49
+ } from "runtimeuse";
50
+
51
+ const handler: AgentHandler = {
52
+ async run(
53
+ invocation: AgentInvocation,
54
+ sender: MessageSender,
55
+ ): Promise<AgentResult> {
56
+ sender.sendAssistantMessage(["Running agent..."]);
57
+
58
+ const output = await myAgent(
59
+ invocation.systemPrompt,
60
+ invocation.userPrompt,
61
+ );
62
+
63
+ return {
64
+ structuredOutput: output,
65
+ metadata: { duration_ms: 1500 },
66
+ };
67
+ },
68
+ };
69
+
70
+ const server = new RuntimeUseServer({ handler, port: 8080 });
71
+ await server.start();
72
+ ```
73
+
74
+ ## Core Concept: AgentHandler
75
+
76
+ The `AgentHandler` interface is the single integration point. Implement `run()` to plug in any agent.
77
+
78
+ ```typescript
79
+ interface AgentHandler {
80
+ run(invocation: AgentInvocation, sender: MessageSender): Promise<AgentResult>;
81
+ }
82
+ ```
83
+
84
+ **`AgentInvocation`** -- everything your agent needs:
85
+
86
+ | Field | Type | Description |
87
+ | -------------- | ---------------------------------------------------------- | ------------------------------------ |
88
+ | `systemPrompt` | `string` | System prompt for the agent |
89
+ | `userPrompt` | `string` | User prompt / task description |
90
+ | `outputFormat` | `{ type: "json_schema"; schema: Record<string, unknown> }` | Expected output schema |
91
+ | `model` | `string` | Model identifier |
92
+ | `secrets` | `string[]` | Values to redact from logs |
93
+ | `env` | `Record<string, string>` | Environment variables for the agent |
94
+ | `signal` | `AbortSignal` | Observe for cancellation (read-only) |
95
+ | `logger` | `Logger` | Prefixed logger for this invocation |
96
+
97
+ **`MessageSender`** -- send intermediate messages back to the client:
98
+
99
+ ```typescript
100
+ sender.sendAssistantMessage(["Step 1: Navigating to login page..."]);
101
+ sender.sendErrorMessage("Something went wrong", { code: "TIMEOUT" });
102
+ ```
103
+
104
+ **`AgentResult`** -- what your handler returns:
105
+
106
+ ```typescript
107
+ interface AgentResult {
108
+ structuredOutput: Record<string, unknown>; // the main result payload
109
+ metadata?: Record<string, unknown>; // optional metadata (timing, cost, etc.)
110
+ }
111
+ ```
112
+
113
+ ## Server Options
114
+
115
+ ### CLI
116
+
117
+ ```bash
118
+ npx runtimeuse # OpenAI handler (default)
119
+ npx runtimeuse --agent claude # Claude handler
120
+ npx runtimeuse --handler ./my-handler.js # custom handler
121
+ npx runtimeuse --port 3000 # custom port
122
+ ```
123
+
124
+ ### Programmatic
125
+
126
+ ```typescript
127
+ import { RuntimeUseServer } from "runtimeuse";
128
+
129
+ const server = new RuntimeUseServer({
130
+ handler: myHandler,
131
+ port: 8080, // default: 8080
132
+ defaultModel: "gpt-4.1",
133
+ uploadTimeoutMs: 30_000,
134
+ artifactWaitMs: 60_000,
135
+ postInvocationDelayMs: 3_000,
136
+ });
137
+
138
+ await server.start();
139
+ // ... later
140
+ await server.stop();
141
+ ```
142
+
143
+ ### Direct Session Usage
144
+
145
+ For custom WebSocket servers:
146
+
147
+ ```typescript
148
+ import { WebSocketSession, UploadTracker } from "runtimeuse";
149
+
150
+ wss.on("connection", (ws) => {
151
+ const session = new WebSocketSession(ws, {
152
+ handler: myHandler,
153
+ uploadTracker: new UploadTracker(),
154
+ });
155
+ session.run();
156
+ });
157
+ ```
158
+
159
+ ## Invocation Lifecycle
160
+
161
+ When a client sends an `invocation_message`, the session:
162
+
163
+ 1. **Downloads runtime files** -- if `runtime_environment_downloadables` is set, fetches and extracts them
164
+ 2. **Runs pre-commands** -- if `pre_agent_invocation_commands` is set, executes them. If a command exits 0, its result becomes the final result (agent is skipped). If it exits non-zero, a failure result is sent
165
+ 3. **Calls `handler.run()`** -- your agent logic runs with the invocation context and a `MessageSender`
166
+ 4. **Sends `result_message`** -- the `AgentResult` from your handler is sent back to the client
167
+ 5. **Finalizes** -- stops artifact watching, waits for pending uploads, closes the WebSocket
168
+
169
+ ## Artifact Management
170
+
171
+ Files written to the artifacts directory are automatically detected via `chokidar` file watching and uploaded through a presigned URL handshake with the client. The artifacts directory is specified per-invocation via the `artifacts_dir` field in the `InvocationMessage` (defaults to `/tmp/artifacts`).
172
+
173
+ - File type is inferred from extension (`.png` -> `screenshot`, `.webm` -> `video`, etc.)
174
+ - `.artifactignore` files are respected (same syntax as `.gitignore`)
175
+ - Default ignore patterns exclude `node_modules/`, `dist/`, `__pycache__/`, virtual environments, etc.
176
+
177
+ ## Secret Redaction
178
+
179
+ The `redactSecrets` utility recursively replaces secret values in strings, arrays, and objects:
180
+
181
+ ```typescript
182
+ import { redactSecrets } from "runtimeuse";
183
+
184
+ const safe = redactSecrets("token=sk-abc123", ["sk-abc123"]);
185
+ // "token=[REDACTED]"
186
+ ```
187
+
188
+ Command output (stdout/stderr) from pre-commands is automatically redacted using the command's environment variable values.
189
+
190
+ ## API Reference
191
+
192
+ ### Classes
193
+
194
+ | Class | Description |
195
+ | ------------------ | ---------------------------------------------------------------- |
196
+ | `RuntimeUseServer` | Standalone WebSocket server that creates sessions per connection |
197
+ | `WebSocketSession` | Manages a single WebSocket connection lifecycle |
198
+ | `ArtifactManager` | Watches a directory and handles the upload handshake |
199
+ | `UploadTracker` | Tracks in-flight uploads with timeout support |
200
+ | `CommandHandler` | Executes shell commands with secret redaction and abort support |
201
+ | `DownloadHandler` | Downloads files via `fetch()` with automatic zip extraction |
202
+
203
+ ### Functions
204
+
205
+ | Function | Description |
206
+ | ------------------------------------ | -------------------------------------------------- |
207
+ | `uploadFile(path, url, contentType)` | Upload a file to a presigned URL |
208
+ | `redactSecrets(value, secrets)` | Recursively redact secrets from any data structure |
209
+ | `createLogger(sourceId)` | Create a prefixed logger |
210
+ | `sleep(ms)` | Promise-based sleep |
211
+
212
+ ### Protocol Message Types
213
+
214
+ | Type | Direction | Description |
215
+ | ------------------------------- | ----------------- | --------------------------------------- |
216
+ | `InvocationMessage` | Client -> Runtime | Start an agent invocation |
217
+ | `CancelMessage` | Client -> Runtime | Cancel a running invocation |
218
+ | `ArtifactUploadResponseMessage` | Client -> Runtime | Presigned URL for artifact upload |
219
+ | `ResultMessage` | Runtime -> Client | Structured agent result |
220
+ | `AssistantMessage` | Runtime -> Client | Intermediate text from the agent |
221
+ | `ArtifactUploadRequestMessage` | Runtime -> Client | Request a presigned URL for an artifact |
222
+ | `ErrorMessage` | Runtime -> Client | Error during execution |
@@ -0,0 +1,26 @@
1
+ import type { Logger } from "./logger.js";
2
+ export interface AgentInvocation {
3
+ systemPrompt: string;
4
+ userPrompt: string;
5
+ outputFormat: {
6
+ type: "json_schema";
7
+ schema: Record<string, unknown>;
8
+ };
9
+ model: string;
10
+ secrets: string[];
11
+ env: Record<string, string>;
12
+ signal: AbortSignal;
13
+ logger: Logger;
14
+ }
15
+ export interface AgentResult {
16
+ structuredOutput: Record<string, unknown>;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export interface MessageSender {
20
+ sendAssistantMessage(textBlocks: string[]): void;
21
+ sendErrorMessage(error: string, metadata?: Record<string, unknown>): void;
22
+ }
23
+ export interface AgentHandler {
24
+ run(invocation: AgentInvocation, sender: MessageSender): Promise<AgentResult>;
25
+ }
26
+ //# sourceMappingURL=agent-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-handler.d.ts","sourceRoot":"","sources":["../src/agent-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACjD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3E;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-handler.js","sourceRoot":"","sources":["../src/agent-handler.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import type { UploadTracker } from "./upload-tracker.js";
2
+ import type { ArtifactUploadRequestMessage, ArtifactUploadResponseMessage } from "./types.js";
3
+ import { type Logger } from "./logger.js";
4
+ export interface ArtifactManagerConfig {
5
+ artifactsDir: string;
6
+ uploadTracker: UploadTracker;
7
+ send: (message: ArtifactUploadRequestMessage) => void;
8
+ }
9
+ export declare class ArtifactManager {
10
+ private readonly watcher;
11
+ private readonly pendingRequests;
12
+ private readonly artifactsDir;
13
+ private readonly uploadTracker;
14
+ private readonly send;
15
+ private ig;
16
+ private logger;
17
+ private loggingLevel;
18
+ constructor(config: ArtifactManagerConfig);
19
+ private reloadIgnorePatterns;
20
+ setLogger(logger: Logger): void;
21
+ handleUploadResponse(message: ArtifactUploadResponseMessage): Promise<void>;
22
+ waitForPendingRequests(timeoutMs: number): Promise<void>;
23
+ stopWatching(): Promise<void>;
24
+ private onFileEvent;
25
+ private requestUpload;
26
+ }
27
+ //# sourceMappingURL=artifact-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-manager.d.ts","sourceRoot":"","sources":["../src/artifact-manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAczD,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,IAAI,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,IAAI,CAAC;CACvD;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG5B;IACJ,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkD;IACvE,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,YAAY,CAA4B;gBAEpC,MAAM,EAAE,qBAAqB;IAgBzC,OAAO,CAAC,oBAAoB;IAW5B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIzB,oBAAoB,CACxB,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,IAAI,CAAC;IA8BV,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC,OAAO,CAAC,WAAW;IA8BnB,OAAO,CAAC,aAAa;CAkBtB"}
@@ -0,0 +1,125 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import chokidar from "chokidar";
4
+ import ignore from "ignore";
5
+ import { uploadFile } from "./storage.js";
6
+ import { DEFAULT_ARTIFACT_IGNORE } from "./constants.js";
7
+ import { defaultLogger } from "./logger.js";
8
+ const EXTENSION_TO_TYPE = {
9
+ ".webm": "video",
10
+ ".png": "screenshot",
11
+ ".ndjson": "tool_calls",
12
+ ".js": "javascript",
13
+ ".ts": "javascript",
14
+ ".py": "python",
15
+ ".sh": "shellscript",
16
+ };
17
+ export class ArtifactManager {
18
+ watcher;
19
+ pendingRequests = new Map();
20
+ artifactsDir;
21
+ uploadTracker;
22
+ send;
23
+ ig = ignore();
24
+ logger = defaultLogger;
25
+ loggingLevel = "info";
26
+ constructor(config) {
27
+ this.artifactsDir = config.artifactsDir;
28
+ this.uploadTracker = config.uploadTracker;
29
+ this.send = config.send;
30
+ this.reloadIgnorePatterns();
31
+ this.watcher = chokidar.watch(config.artifactsDir, {
32
+ awaitWriteFinish: true,
33
+ alwaysStat: true,
34
+ });
35
+ this.watcher.on("add", (p, s) => this.onFileEvent(p, s));
36
+ this.watcher.on("change", (p, s) => this.onFileEvent(p, s));
37
+ }
38
+ reloadIgnorePatterns() {
39
+ this.ig = ignore();
40
+ const ignorePath = path.join(this.artifactsDir, ".artifactignore");
41
+ if (fs.existsSync(ignorePath)) {
42
+ this.ig.add(fs.readFileSync(ignorePath, "utf-8"));
43
+ this.logger.log(`Loaded .artifactignore from ${ignorePath}`);
44
+ }
45
+ else {
46
+ this.ig.add(DEFAULT_ARTIFACT_IGNORE);
47
+ }
48
+ }
49
+ setLogger(logger) {
50
+ this.logger = logger;
51
+ }
52
+ async handleUploadResponse(message) {
53
+ this.logger.log(`Uploading artifact: ${message.filename} ${message.filepath}`);
54
+ const promise = uploadFile(message.filepath, message.presigned_url, message.content_type, this.logger);
55
+ this.uploadTracker.track(promise);
56
+ try {
57
+ await promise;
58
+ }
59
+ catch (error) {
60
+ if (error instanceof Error && error.name === "ENOENT") {
61
+ this.logger.log(`Artifact file not found: ${message.filepath}`);
62
+ return;
63
+ }
64
+ throw error;
65
+ }
66
+ const pending = this.pendingRequests.get(message.filename);
67
+ if (pending) {
68
+ pending.resolve();
69
+ this.pendingRequests.delete(message.filename);
70
+ }
71
+ }
72
+ async waitForPendingRequests(timeoutMs) {
73
+ const promises = [...this.pendingRequests.values()].map((r) => r.promise);
74
+ if (promises.length === 0)
75
+ return;
76
+ this.logger.log(`Waiting for ${promises.length} artifact round-trips...`);
77
+ await Promise.race([
78
+ Promise.allSettled(promises),
79
+ new Promise((r) => setTimeout(r, timeoutMs)),
80
+ ]);
81
+ }
82
+ async stopWatching() {
83
+ await this.watcher.close();
84
+ }
85
+ onFileEvent(filePath, stats) {
86
+ if (this.loggingLevel === "debug") {
87
+ this.logger.log(`Artifact event: ${filePath}. Size: ${stats?.size ?? 0} bytes`);
88
+ }
89
+ if (path.basename(filePath) === ".artifactignore") {
90
+ this.reloadIgnorePatterns();
91
+ return;
92
+ }
93
+ if (!stats?.isFile() || !stats.size) {
94
+ if (this.loggingLevel === "debug") {
95
+ this.logger.debug(`Skipping: ${filePath}`);
96
+ }
97
+ return;
98
+ }
99
+ const relativePath = path.relative(this.artifactsDir, filePath);
100
+ if (!relativePath.startsWith("..") && this.ig.ignores(relativePath)) {
101
+ if (this.loggingLevel === "debug") {
102
+ this.logger.debug(`Skipping ignored artifact: ${relativePath}`);
103
+ }
104
+ return;
105
+ }
106
+ this.requestUpload(filePath);
107
+ }
108
+ requestUpload(filePath) {
109
+ const filename = path.basename(filePath);
110
+ const ext = path.extname(filePath);
111
+ let resolve;
112
+ const promise = new Promise((r) => {
113
+ resolve = r;
114
+ });
115
+ this.pendingRequests.set(filename, { promise, resolve });
116
+ this.logger.log(`Requesting upload for artifact: ${filename}`);
117
+ this.send({
118
+ message_type: "artifact_upload_request_message",
119
+ artifact_type: EXTENSION_TO_TYPE[ext] ?? "other",
120
+ filename,
121
+ filepath: filePath,
122
+ });
123
+ }
124
+ }
125
+ //# sourceMappingURL=artifact-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-manager.js","sourceRoot":"","sources":["../src/artifact-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,MAAuB,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAe,MAAM,aAAa,CAAC;AAIzD,MAAM,iBAAiB,GAAiC;IACtD,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,YAAY;IACpB,SAAS,EAAE,YAAY;IACvB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,aAAa;CACrB,CAAC;AAQF,MAAM,OAAO,eAAe;IACT,OAAO,CAAoC;IAC3C,eAAe,GAAG,IAAI,GAAG,EAGvC,CAAC;IACa,YAAY,CAAS;IACrB,aAAa,CAAgB;IAC7B,IAAI,CAAkD;IAC/D,EAAE,GAAW,MAAM,EAAE,CAAC;IACtB,MAAM,GAAW,aAAa,CAAC;IAC/B,YAAY,GAAqB,MAAM,CAAC;IAEhD,YAAY,MAA6B;QACvC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAExB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE;YACjD,gBAAgB,EAAE,IAAI;YACtB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;QACnB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;QACnE,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,OAAsC;QAEtC,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,uBAAuB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAC9D,CAAC;QAEF,MAAM,OAAO,GAAG,UAAU,CACxB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,YAAY,EACpB,IAAI,CAAC,MAAM,CACZ,CAAC;QACF,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAElC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4BAA4B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAChE,OAAO;YACT,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,SAAiB;QAC5C,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC1E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,MAAM,0BAA0B,CAAC,CAAC;QAC1E,MAAM,OAAO,CAAC,IAAI,CAAC;YACjB,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC5B,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAEO,WAAW,CAAC,QAAgB,EAAE,KAAgB;QACpD,IAAI,IAAI,CAAC,YAAY,KAAK,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,mBAAmB,QAAQ,WAAW,KAAK,EAAE,IAAI,IAAI,CAAC,QAAQ,CAC/D,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,iBAAiB,EAAE,CAAC;YAClD,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,YAAY,KAAK,OAAO,EAAE,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,YAAY,KAAK,OAAO,EAAE,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAEO,aAAa,CAAC,QAAgB;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,OAAoB,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE;YACtC,OAAO,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAEzD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC;YACR,YAAY,EAAE,iCAAiC;YAC/C,aAAa,EAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,OAAO;YAChD,QAAQ;YACR,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=artifact-manager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-manager.test.d.ts","sourceRoot":"","sources":["../src/artifact-manager.test.ts"],"names":[],"mappings":""}