@almyty/runner 1.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.
- package/README.md +72 -0
- package/dist/binaries.d.ts +30 -0
- package/dist/binaries.js +99 -0
- package/dist/binaries.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +128 -0
- package/dist/cli.js.map +1 -0
- package/dist/coding-agents/detect.d.ts +12 -0
- package/dist/coding-agents/detect.js +35 -0
- package/dist/coding-agents/detect.js.map +1 -0
- package/dist/coding-agents/index.d.ts +15 -0
- package/dist/coding-agents/index.js +15 -0
- package/dist/coding-agents/index.js.map +1 -0
- package/dist/coding-agents/registry.d.ts +9 -0
- package/dist/coding-agents/registry.js +260 -0
- package/dist/coding-agents/registry.js.map +1 -0
- package/dist/coding-agents/spawn-spec.d.ts +47 -0
- package/dist/coding-agents/spawn-spec.js +58 -0
- package/dist/coding-agents/spawn-spec.js.map +1 -0
- package/dist/coding-agents/status.d.ts +38 -0
- package/dist/coding-agents/status.js +111 -0
- package/dist/coding-agents/status.js.map +1 -0
- package/dist/coding-agents/types.d.ts +104 -0
- package/dist/coding-agents/types.js +18 -0
- package/dist/coding-agents/types.js.map +1 -0
- package/dist/coding-sessions.d.ts +80 -0
- package/dist/coding-sessions.js +121 -0
- package/dist/coding-sessions.js.map +1 -0
- package/dist/config.d.ts +49 -0
- package/dist/config.js +180 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon.d.ts +71 -0
- package/dist/daemon.js +353 -0
- package/dist/daemon.js.map +1 -0
- package/dist/handlers.d.ts +39 -0
- package/dist/handlers.js +299 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +16 -0
- package/dist/policy.js +134 -0
- package/dist/policy.js.map +1 -0
- package/dist/process-manager.d.ts +107 -0
- package/dist/process-manager.js +334 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/protocol.d.ts +53 -0
- package/dist/protocol.js +39 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runtime-info.d.ts +23 -0
- package/dist/runtime-info.js +35 -0
- package/dist/runtime-info.js.map +1 -0
- package/dist/streamable-client.d.ts +69 -0
- package/dist/streamable-client.js +204 -0
- package/dist/streamable-client.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import { WORKER_PROTOCOL_VERSION, isWorkerEnvelope, } from './protocol.js';
|
|
4
|
+
export class StreamableClient extends EventEmitter {
|
|
5
|
+
opts;
|
|
6
|
+
sessionId = null;
|
|
7
|
+
lastEventId = null;
|
|
8
|
+
streamAbort = null;
|
|
9
|
+
stopped = false;
|
|
10
|
+
reconnectAttempt = 0;
|
|
11
|
+
fetchImpl;
|
|
12
|
+
setTimeoutFn;
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
super();
|
|
15
|
+
this.opts = opts;
|
|
16
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
17
|
+
this.setTimeoutFn = opts.setTimeoutFn ?? setTimeout;
|
|
18
|
+
}
|
|
19
|
+
/** Returns the session id once the first POST has assigned one. */
|
|
20
|
+
getSessionId() {
|
|
21
|
+
return this.sessionId;
|
|
22
|
+
}
|
|
23
|
+
/** Send an envelope. Returns the parsed response envelope when the
|
|
24
|
+
* backend hands one back inline (for unary requests); otherwise null. */
|
|
25
|
+
async send(env) {
|
|
26
|
+
const headers = {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
'Authorization': `Bearer ${this.opts.token}`,
|
|
29
|
+
};
|
|
30
|
+
if (this.sessionId)
|
|
31
|
+
headers['Mcp-Session-Id'] = this.sessionId;
|
|
32
|
+
const res = await this.fetchImpl(`${this.opts.baseUrl}/mcp/streamable`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers,
|
|
35
|
+
body: JSON.stringify(env),
|
|
36
|
+
});
|
|
37
|
+
const sid = res.headers.get('mcp-session-id') ?? res.headers.get('Mcp-Session-Id');
|
|
38
|
+
if (sid)
|
|
39
|
+
this.sessionId = sid;
|
|
40
|
+
if (res.status === 202)
|
|
41
|
+
return null;
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
const text = await safeText(res);
|
|
44
|
+
throw new Error(`backend POST failed: ${res.status} ${text}`);
|
|
45
|
+
}
|
|
46
|
+
const json = await res.json();
|
|
47
|
+
if (isWorkerEnvelope(json))
|
|
48
|
+
return json;
|
|
49
|
+
// JSON-RPC response shape (when the runner posts an MCP-shaped
|
|
50
|
+
// body, which it shouldn't, but the transport supports both).
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** Open the GET stream and dispatch envelopes via emit('envelope'). */
|
|
54
|
+
async openStream() {
|
|
55
|
+
if (this.stopped)
|
|
56
|
+
return;
|
|
57
|
+
if (!this.sessionId) {
|
|
58
|
+
throw new Error('cannot open stream before any POST has assigned a session id');
|
|
59
|
+
}
|
|
60
|
+
this.streamAbort = new AbortController();
|
|
61
|
+
const headers = {
|
|
62
|
+
'Authorization': `Bearer ${this.opts.token}`,
|
|
63
|
+
'Mcp-Session-Id': this.sessionId,
|
|
64
|
+
'Accept': 'text/event-stream',
|
|
65
|
+
};
|
|
66
|
+
if (this.lastEventId)
|
|
67
|
+
headers['Last-Event-ID'] = this.lastEventId;
|
|
68
|
+
let res;
|
|
69
|
+
try {
|
|
70
|
+
res = await this.fetchImpl(`${this.opts.baseUrl}/mcp/streamable`, {
|
|
71
|
+
method: 'GET',
|
|
72
|
+
headers,
|
|
73
|
+
signal: this.streamAbort.signal,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.scheduleReconnect(err);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
const text = await safeText(res);
|
|
82
|
+
// 404 UNKNOWN_SESSION means the server forgot us; we have to
|
|
83
|
+
// re-establish a session by POSTing again. Drop the saved
|
|
84
|
+
// session id and let the next send() mint a new one.
|
|
85
|
+
if (res.status === 404) {
|
|
86
|
+
this.sessionId = null;
|
|
87
|
+
this.lastEventId = null;
|
|
88
|
+
this.emit('session-lost', text);
|
|
89
|
+
}
|
|
90
|
+
this.scheduleReconnect(new Error(`stream open failed: ${res.status} ${text}`));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!res.body) {
|
|
94
|
+
this.scheduleReconnect(new Error('stream open: no body'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.reconnectAttempt = 0;
|
|
98
|
+
this.emit('open');
|
|
99
|
+
try {
|
|
100
|
+
await this.consumeStream(res.body);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
this.emit('disconnect', err);
|
|
104
|
+
}
|
|
105
|
+
if (!this.stopped)
|
|
106
|
+
this.scheduleReconnect(new Error('stream ended'));
|
|
107
|
+
}
|
|
108
|
+
stop() {
|
|
109
|
+
this.stopped = true;
|
|
110
|
+
this.streamAbort?.abort();
|
|
111
|
+
}
|
|
112
|
+
// ── internals ───────────────────────────────────────────────────────
|
|
113
|
+
/**
|
|
114
|
+
* SSE parser. The MCP Streamable HTTP wire format follows the SSE
|
|
115
|
+
* spec: events are separated by blank lines, fields are `id:`,
|
|
116
|
+
* `event:`, `data:`. We accept arbitrary header order and ignore
|
|
117
|
+
* unknown fields.
|
|
118
|
+
*
|
|
119
|
+
* Buffers across chunk boundaries because TCP doesn't respect SSE
|
|
120
|
+
* frame boundaries; one fetch chunk often contains a half-event.
|
|
121
|
+
*/
|
|
122
|
+
async consumeStream(body) {
|
|
123
|
+
const reader = body.getReader();
|
|
124
|
+
const decoder = new TextDecoder('utf-8');
|
|
125
|
+
let buffer = '';
|
|
126
|
+
while (true) {
|
|
127
|
+
const { value, done } = await reader.read();
|
|
128
|
+
if (done)
|
|
129
|
+
return;
|
|
130
|
+
buffer += decoder.decode(value, { stream: true });
|
|
131
|
+
// Frames are double-newline separated.
|
|
132
|
+
let frameEnd = buffer.indexOf('\n\n');
|
|
133
|
+
while (frameEnd !== -1) {
|
|
134
|
+
const frame = buffer.slice(0, frameEnd);
|
|
135
|
+
buffer = buffer.slice(frameEnd + 2);
|
|
136
|
+
this.handleFrame(frame);
|
|
137
|
+
frameEnd = buffer.indexOf('\n\n');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
handleFrame(frame) {
|
|
142
|
+
if (!frame)
|
|
143
|
+
return;
|
|
144
|
+
let id = '';
|
|
145
|
+
let dataLines = [];
|
|
146
|
+
for (const line of frame.split('\n')) {
|
|
147
|
+
if (line.startsWith('id:'))
|
|
148
|
+
id = line.slice(3).trim();
|
|
149
|
+
else if (line.startsWith('data:'))
|
|
150
|
+
dataLines.push(line.slice(5).trim());
|
|
151
|
+
else if (line.startsWith('event:')) { /* event name unused on this side */ }
|
|
152
|
+
}
|
|
153
|
+
if (dataLines.length === 0)
|
|
154
|
+
return;
|
|
155
|
+
if (id)
|
|
156
|
+
this.lastEventId = id;
|
|
157
|
+
const dataText = dataLines.join('\n');
|
|
158
|
+
let parsed;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(dataText);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
this.emit('parse-error', dataText);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (!isWorkerEnvelope(parsed)) {
|
|
167
|
+
this.emit('parse-error', dataText);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.emit('envelope', parsed);
|
|
171
|
+
}
|
|
172
|
+
scheduleReconnect(reason) {
|
|
173
|
+
if (this.stopped)
|
|
174
|
+
return;
|
|
175
|
+
this.reconnectAttempt++;
|
|
176
|
+
const delays = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000];
|
|
177
|
+
const delay = delays[Math.min(this.reconnectAttempt - 1, delays.length - 1)];
|
|
178
|
+
this.emit('reconnect', { attempt: this.reconnectAttempt, delayMs: delay, reason: reason.message });
|
|
179
|
+
const t = this.setTimeoutFn(() => {
|
|
180
|
+
if (!this.stopped)
|
|
181
|
+
this.openStream().catch(err => this.emit('error', err));
|
|
182
|
+
}, delay);
|
|
183
|
+
t.unref?.();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function safeText(res) {
|
|
187
|
+
try {
|
|
188
|
+
return await res.text();
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return '';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/** Helper to mint an envelope on the runner side. */
|
|
195
|
+
export function envelope(type, payload, correlationId) {
|
|
196
|
+
return {
|
|
197
|
+
v: WORKER_PROTOCOL_VERSION,
|
|
198
|
+
type,
|
|
199
|
+
id: correlationId ?? randomUUID(),
|
|
200
|
+
ts: Date.now(),
|
|
201
|
+
payload,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=streamable-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-client.js","sourceRoot":"","sources":["../src/streamable-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the runner package. Mirrored against the backend
|
|
3
|
+
* Runner / Workspace shapes; we keep them duplicated rather than
|
|
4
|
+
* importing from the backend so the runner can be installed and
|
|
5
|
+
* versioned without dragging the backend's dep graph in.
|
|
6
|
+
*/
|
|
7
|
+
import type { DetectedCodingAgent } from './coding-agents/index.js';
|
|
8
|
+
export type RunnerIsolationTier = 'container' | 'host';
|
|
9
|
+
export interface RunnerRuntimeInfo {
|
|
10
|
+
os: string;
|
|
11
|
+
arch: string;
|
|
12
|
+
hostname: string;
|
|
13
|
+
cpuCount: number;
|
|
14
|
+
memoryMb: number;
|
|
15
|
+
runnerVersion: string;
|
|
16
|
+
binaries: Record<string, string | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Coding-agent platforms detected on this machine (claude, codex, gemini,
|
|
19
|
+
* …). Lets the backend route an agent to a runner that can actually drive
|
|
20
|
+
* the requested CLI, rather than just inferring it from the binary map.
|
|
21
|
+
*/
|
|
22
|
+
codingAgents: DetectedCodingAgent[];
|
|
23
|
+
}
|
|
24
|
+
export interface RunnerConfig {
|
|
25
|
+
defaultIsolation: RunnerIsolationTier;
|
|
26
|
+
maxConcurrent: number;
|
|
27
|
+
allowedCwdRoots: string[];
|
|
28
|
+
denyPatterns: string[];
|
|
29
|
+
networkBlocked: boolean;
|
|
30
|
+
installBlocked: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolved runner-side configuration. Combines the user-set fields
|
|
34
|
+
* (name, labels, RunnerConfig) with the binary probe list and the
|
|
35
|
+
* backend URL. Result of merging defaults < global < project < env <
|
|
36
|
+
* flags.
|
|
37
|
+
*/
|
|
38
|
+
export interface ResolvedConfig {
|
|
39
|
+
name: string;
|
|
40
|
+
labels: Record<string, string>;
|
|
41
|
+
config: RunnerConfig;
|
|
42
|
+
binaryProbeList: string[];
|
|
43
|
+
backendUrl: string;
|
|
44
|
+
}
|
|
45
|
+
export interface RunnerInfo {
|
|
46
|
+
name: string;
|
|
47
|
+
labels: Record<string, string>;
|
|
48
|
+
runtime: RunnerRuntimeInfo;
|
|
49
|
+
runnerVersion: string;
|
|
50
|
+
binaries: Record<string, string | null>;
|
|
51
|
+
capacity: {
|
|
52
|
+
maxConcurrent: number;
|
|
53
|
+
inUse: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export type ProcessStatus = 'running' | 'exited' | 'killed';
|
|
57
|
+
export interface ProcessHandle {
|
|
58
|
+
processId: string;
|
|
59
|
+
binary: string;
|
|
60
|
+
startedAt: Date;
|
|
61
|
+
status: ProcessStatus;
|
|
62
|
+
/** Workspace this process is scoped to. Cross-workspace access is denied. */
|
|
63
|
+
workspaceId: string;
|
|
64
|
+
}
|
|
65
|
+
export interface SpawnOptions {
|
|
66
|
+
binary: string;
|
|
67
|
+
args: string[];
|
|
68
|
+
env?: Record<string, string>;
|
|
69
|
+
/** Default true; set false for raw-pipe mode without a TTY. */
|
|
70
|
+
pty?: boolean;
|
|
71
|
+
cwd?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface ReadResult {
|
|
74
|
+
data: string;
|
|
75
|
+
/** True when more output is buffered beyond what we returned now. */
|
|
76
|
+
moreAvailable: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface WaitForIdleOptions {
|
|
79
|
+
/** Return when the process produces no output for this long (ms). */
|
|
80
|
+
idleMs: number;
|
|
81
|
+
/** Hard cap on how long to wait regardless of activity (ms). */
|
|
82
|
+
maxWaitMs: number;
|
|
83
|
+
}
|
|
84
|
+
export interface WaitForIdleResult {
|
|
85
|
+
data: string;
|
|
86
|
+
/** True when we returned because of idle, false when max-wait fired. */
|
|
87
|
+
idle: boolean;
|
|
88
|
+
}
|
|
89
|
+
export interface WaitResult {
|
|
90
|
+
exitCode: number | null;
|
|
91
|
+
signal: string | null;
|
|
92
|
+
}
|
|
93
|
+
export type ProcessSignal = 'TERM' | 'INT' | 'KILL';
|
|
94
|
+
export interface ShellExecResult {
|
|
95
|
+
stdout: string;
|
|
96
|
+
stderr: string;
|
|
97
|
+
exitCode: number | null;
|
|
98
|
+
}
|
|
99
|
+
export declare class RunnerError extends Error {
|
|
100
|
+
readonly code: string;
|
|
101
|
+
readonly data?: unknown | undefined;
|
|
102
|
+
constructor(message: string, code: string, data?: unknown | undefined);
|
|
103
|
+
}
|
|
104
|
+
export declare const RUNNER_ERROR_CODES: {
|
|
105
|
+
readonly PROCESS_NOT_FOUND: "process_not_found";
|
|
106
|
+
readonly PROCESS_CROSS_WORKSPACE: "process_cross_workspace";
|
|
107
|
+
readonly CAPACITY_EXCEEDED: "capacity_exceeded";
|
|
108
|
+
readonly PATH_DENIED: "path_denied";
|
|
109
|
+
readonly COMMAND_DENIED: "command_denied";
|
|
110
|
+
readonly PROCESS_ALREADY_EXITED: "process_already_exited";
|
|
111
|
+
readonly TIMEOUT: "timeout";
|
|
112
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Errors ─────────────────────────────────────────────────────────────
|
|
2
|
+
export class RunnerError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
data;
|
|
5
|
+
constructor(message, code, data) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.data = data;
|
|
9
|
+
this.name = 'RunnerError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export const RUNNER_ERROR_CODES = {
|
|
13
|
+
PROCESS_NOT_FOUND: 'process_not_found',
|
|
14
|
+
PROCESS_CROSS_WORKSPACE: 'process_cross_workspace',
|
|
15
|
+
CAPACITY_EXCEEDED: 'capacity_exceeded',
|
|
16
|
+
PATH_DENIED: 'path_denied',
|
|
17
|
+
COMMAND_DENIED: 'command_denied',
|
|
18
|
+
PROCESS_ALREADY_EXITED: 'process_already_exited',
|
|
19
|
+
TIMEOUT: 'timeout',
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAgHA,uEAAuE;AAEvE,MAAM,OAAO,WAAY,SAAQ,KAAK;IACS;IAA8B;IAA3E,YAAY,OAAe,EAAkB,IAAY,EAAkB,IAAc;QACvF,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,SAAI,GAAJ,IAAI,CAAQ;QAAkB,SAAI,GAAJ,IAAI,CAAU;QAEvF,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,iBAAiB,EAAE,mBAAmB;IACtC,uBAAuB,EAAE,yBAAyB;IAClD,iBAAiB,EAAE,mBAAmB;IACtC,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,gBAAgB;IAChC,sBAAsB,EAAE,wBAAwB;IAChD,OAAO,EAAE,SAAS;CACV,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@almyty/runner",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "Connect your own machine to almyty \u2014 a small daemon that lets agents run tools and coding CLIs locally, with code and credentials staying on your box.",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"bin": {
|
|
11
|
+
"almyty-runner": "dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
18
|
+
"dev": "tsx src/cli.ts",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"node-pty": "^1.0.0",
|
|
28
|
+
"@almyty/client": "^1.2.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^25.4.0",
|
|
32
|
+
"tsx": "^4.7.0",
|
|
33
|
+
"typescript": "^5.3.0",
|
|
34
|
+
"vitest": "^4.1.0"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"almyty",
|
|
38
|
+
"runner",
|
|
39
|
+
"daemon",
|
|
40
|
+
"agent",
|
|
41
|
+
"cli"
|
|
42
|
+
],
|
|
43
|
+
"author": "almyty",
|
|
44
|
+
"license": "Apache-2.0",
|
|
45
|
+
"homepage": "https://almyty.com",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/almyty-inc/almyty.git",
|
|
49
|
+
"directory": "packages/runner"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/almyty-inc/almyty/issues"
|
|
53
|
+
}
|
|
54
|
+
}
|