@ravefox/space 0.2.1 → 0.4.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 (167) hide show
  1. package/LICENSE +21 -205
  2. package/README.md +104 -31
  3. package/bin/space.js +113 -0
  4. package/lib/agents.js +181 -0
  5. package/lib/boardTools.js +89 -0
  6. package/lib/credentials.js +95 -0
  7. package/lib/daemon.js +294 -0
  8. package/lib/harness.js +166 -0
  9. package/lib/http.js +101 -0
  10. package/lib/login.js +68 -0
  11. package/lib/mcp.js +39 -0
  12. package/lib/runtime.js +253 -0
  13. package/lib/store.js +96 -0
  14. package/lib/tools.js +93 -0
  15. package/lib/workspaceSandbox.js +77 -0
  16. package/lib/workspaceTools.js +160 -0
  17. package/lib/workspaceWorker.js +17 -0
  18. package/package.json +27 -46
  19. package/NOTICE +0 -55
  20. package/assets/webhook-sdk/python/bot.py +0 -63
  21. package/assets/webhook-sdk/python/commonly.py +0 -232
  22. package/node_modules/@commonlyai/seats/README.md +0 -25
  23. package/node_modules/@commonlyai/seats/package.json +0 -22
  24. package/node_modules/@commonlyai/seats/src/adapters/hermes.js +0 -264
  25. package/node_modules/@commonlyai/seats/src/adapters/stub.js +0 -24
  26. package/node_modules/@commonlyai/seats/src/contract.js +0 -48
  27. package/node_modules/@commonlyai/seats/src/failures.js +0 -44
  28. package/node_modules/@commonlyai/seats/src/harness-plan.js +0 -329
  29. package/node_modules/@commonlyai/seats/src/index.js +0 -22
  30. package/node_modules/@commonlyai/seats/src/process-group.js +0 -269
  31. package/node_modules/@commonlyai/seats/src/record/format.js +0 -737
  32. package/node_modules/@commonlyai/seats/src/record/otel.js +0 -238
  33. package/node_modules/@commonlyai/seats/src/runtime-observation.js +0 -29
  34. package/node_modules/@commonlyai/seats/src/seat-model.js +0 -17
  35. package/node_modules/@commonlyai/seats/src/supervisor.js +0 -308
  36. package/node_modules/@commonlyai/seats/src/trace/events.js +0 -46
  37. package/node_modules/@commonlyai/seats/src/trace/store.js +0 -276
  38. package/node_modules/@commonlyai/seats/src/turn-processes.js +0 -226
  39. package/node_modules/@commonlyai/seats/src/upstream-refusal.js +0 -418
  40. package/node_modules/@commonlyai/seats/src/valet/env.js +0 -201
  41. package/node_modules/@commonlyai/seats/src/valet/grant.js +0 -123
  42. package/node_modules/@commonlyai/seats/src/valet/permissions.js +0 -213
  43. package/node_modules/@commonlyai/seats/src/wire/provider-proxy.js +0 -529
  44. package/skills/commonly/SKILL.md +0 -233
  45. package/src/commands/agent.js +0 -6334
  46. package/src/commands/daemon.js +0 -933
  47. package/src/commands/dev.js +0 -153
  48. package/src/commands/doctor.js +0 -141
  49. package/src/commands/inbox.js +0 -330
  50. package/src/commands/login.js +0 -194
  51. package/src/commands/mcp.js +0 -56
  52. package/src/commands/pod.js +0 -120
  53. package/src/commands/task.js +0 -279
  54. package/src/commands/verify.js +0 -48
  55. package/src/index.js +0 -99
  56. package/src/lib/adapter-login.js +0 -76
  57. package/src/lib/adapters/broker-bridge-entry.js +0 -76
  58. package/src/lib/adapters/claude.js +0 -2207
  59. package/src/lib/adapters/codex-broker-bridge.mjs +0 -298
  60. package/src/lib/adapters/codex.js +0 -1898
  61. package/src/lib/adapters/dsh.js +0 -513
  62. package/src/lib/adapters/goose.js +0 -510
  63. package/src/lib/adapters/hermes.js +0 -18
  64. package/src/lib/adapters/index.js +0 -68
  65. package/src/lib/adapters/opencode.js +0 -1681
  66. package/src/lib/adapters/pi-commonly-mcp.mjs +0 -71
  67. package/src/lib/adapters/pi-mcp-client.mjs +0 -617
  68. package/src/lib/adapters/pi-shell-env.mjs +0 -41
  69. package/src/lib/adapters/pi.js +0 -1025
  70. package/src/lib/adapters/qwen.js +0 -523
  71. package/src/lib/adapters/seat-model.js +0 -8
  72. package/src/lib/adapters/stub.js +0 -1
  73. package/src/lib/adapters/tested-version.js +0 -106
  74. package/src/lib/api.js +0 -205
  75. package/src/lib/claim-outcome.js +0 -128
  76. package/src/lib/claimed-work-gate.js +0 -73
  77. package/src/lib/cli-hint.js +0 -33
  78. package/src/lib/commit-attribution.js +0 -391
  79. package/src/lib/config.js +0 -155
  80. package/src/lib/content-refusal.js +0 -94
  81. package/src/lib/credential-file.js +0 -208
  82. package/src/lib/daemon-agent-states.js +0 -95
  83. package/src/lib/daemon-hint.js +0 -18
  84. package/src/lib/daemon-logs.js +0 -43
  85. package/src/lib/daemon-service-windows.js +0 -263
  86. package/src/lib/daemon-service.js +0 -486
  87. package/src/lib/daemon-state.js +0 -84
  88. package/src/lib/daemon-store.js +0 -119
  89. package/src/lib/daemon-supervisor.js +0 -629
  90. package/src/lib/daemon-watch.js +0 -115
  91. package/src/lib/declared-mcp-guard.js +0 -284
  92. package/src/lib/default-environment.js +0 -207
  93. package/src/lib/device-login.js +0 -126
  94. package/src/lib/digest-frame.js +0 -151
  95. package/src/lib/doctor.js +0 -291
  96. package/src/lib/egress-proxy.js +0 -160
  97. package/src/lib/enforcement.js +0 -946
  98. package/src/lib/environment.js +0 -681
  99. package/src/lib/first-output-watchdog.js +0 -191
  100. package/src/lib/git-readonly-server.js +0 -138
  101. package/src/lib/git-readonly.js +0 -463
  102. package/src/lib/git-remote-commonly.mjs +0 -100
  103. package/src/lib/grant-broker-guard.js +0 -345
  104. package/src/lib/hooks-config.js +0 -238
  105. package/src/lib/host-gh-broker.js +0 -152
  106. package/src/lib/host-gh-shim.mjs +0 -98
  107. package/src/lib/inbox.js +0 -483
  108. package/src/lib/instance-proxy.js +0 -76
  109. package/src/lib/machine-host.js +0 -29
  110. package/src/lib/mcp-credential-delivery.js +0 -121
  111. package/src/lib/mcp-first-run.js +0 -50
  112. package/src/lib/mcp-home.js +0 -644
  113. package/src/lib/mcp-ready.js +0 -68
  114. package/src/lib/mcp-server-version.js +0 -123
  115. package/src/lib/mcp-token.js +0 -36
  116. package/src/lib/mcp-warm-child.mjs +0 -412
  117. package/src/lib/memory-bridge.js +0 -191
  118. package/src/lib/memory-import.js +0 -156
  119. package/src/lib/missing-harness.js +0 -31
  120. package/src/lib/model-unavailable.js +0 -154
  121. package/src/lib/native-runtime-inventory.js +0 -40
  122. package/src/lib/outsider-grant-mcp.js +0 -82
  123. package/src/lib/own-key-launch.js +0 -42
  124. package/src/lib/pod-catch-up.js +0 -55
  125. package/src/lib/pod-focus.js +0 -224
  126. package/src/lib/pod-tail.js +0 -68
  127. package/src/lib/poll-liveness.js +0 -103
  128. package/src/lib/poll-retry.js +0 -81
  129. package/src/lib/poller.js +0 -200
  130. package/src/lib/provider-proxy.js +0 -42
  131. package/src/lib/public-seat-mcp-flag.js +0 -36
  132. package/src/lib/public-tool-error.js +0 -60
  133. package/src/lib/public-withheld-tools.js +0 -48
  134. package/src/lib/reply-receipt.js +0 -55
  135. package/src/lib/resolve-on-path.js +0 -22
  136. package/src/lib/runtime-inventory.js +0 -56
  137. package/src/lib/runtime-observation.js +0 -37
  138. package/src/lib/sandbox/bwrap.js +0 -275
  139. package/src/lib/sandbox/codex-perimeter.js +0 -16
  140. package/src/lib/sandbox/host-check.js +0 -268
  141. package/src/lib/sandbox/mode.js +0 -49
  142. package/src/lib/sandbox/opencode-loopback.mjs +0 -68
  143. package/src/lib/sandbox/seatbelt.js +0 -684
  144. package/src/lib/sandbox/turn-dir.js +0 -56
  145. package/src/lib/sandbox/windows-unsandboxed.js +0 -183
  146. package/src/lib/sandbox/workspace-git-config.js +0 -243
  147. package/src/lib/sandbox/workspace-pin.js +0 -158
  148. package/src/lib/seat-runtime-controls.js +0 -61
  149. package/src/lib/seat-stop.js +0 -97
  150. package/src/lib/server-skills.js +0 -32
  151. package/src/lib/session-recycle.js +0 -219
  152. package/src/lib/session-store.js +0 -215
  153. package/src/lib/skill-prompt.js +0 -74
  154. package/src/lib/skills-import.js +0 -113
  155. package/src/lib/spawn-credential.js +0 -402
  156. package/src/lib/spawn-retry.js +0 -311
  157. package/src/lib/stable-install.js +0 -176
  158. package/src/lib/supervised-turn.js +0 -352
  159. package/src/lib/task.js +0 -235
  160. package/src/lib/turn-failure-notice.js +0 -177
  161. package/src/lib/unconfined-seat-guard.js +0 -94
  162. package/src/lib/update-check.js +0 -192
  163. package/src/lib/upstream-refusal.js +0 -1
  164. package/src/lib/webhook-server.js +0 -109
  165. package/src/lib/windows-command.js +0 -393
  166. package/src/lib/workspace-git.js +0 -87
  167. package/src/lib/workspace-trust.js +0 -162
@@ -1,298 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * The grant broker, as a stdio MCP server codex can run (F175b).
4
- *
5
- * codex is admitted for the grant broker (ADAPTERS_WITH_GRANT_BROKER), but the
6
- * broker is a Streamable HTTP server (`grantBrokerServer`) and codex.js wires
7
- * stdio servers only, so a granted codex seat used to receive the entry and
8
- * drop it. codex's own url transport is no way round that: it reads a bearer
9
- * token from an environment variable (`bearer_token_env_var`), which would put
10
- * the token back in codex's environment and in every MCP child it spawns, the
11
- * thing TASK-083 took out.
12
- *
13
- * So codex runs this file, and this file speaks HTTP to the broker. It holds no
14
- * token of its own. It is told three things, none of them a secret:
15
- * - COMMONLY_BROKER_URL: the broker url, already resolved to this instance;
16
- * - COMMONLY_BROKER_HEADERS: the declared headers as TEMPLATES, still holding
17
- * `${COMMONLY_AGENT_TOKEN}`;
18
- * - COMMONLY_TOKEN_FILE: the path of this spawn's 0600 credential file, the
19
- * same file the commonly MCP server reads.
20
- * The token is read from that file once, at start, and kept in this process's
21
- * memory and the request header only. On a public seat the file is deleted as
22
- * soon as its readers have it (F460): this bridge then writes
23
- * COMMONLY_MCP_READY_FILE, as the commonly MCP server does, on the host's first
24
- * tools/list.
25
- *
26
- * It is a pass-through: each JSON-RPC line from codex is POSTed as it is, and
27
- * every message in the answer (plain JSON or an event stream) is written back
28
- * as a line. The broker is stateless, but a session id and the negotiated
29
- * protocol version are carried the way the spec asks, so a stateful server
30
- * would work too.
31
- *
32
- * It imports node builtins only. On a public seat codex runs it under the
33
- * seat's permission profile, which is granted read on THIS file alone; an
34
- * import from elsewhere in the CLI would need a wider grant. So the two small
35
- * pieces it shares with the rest of the CLI are restated here, and a test pins
36
- * the import list.
37
- */
38
- import { readFileSync, realpathSync, writeFileSync } from 'node:fs';
39
- import { isAbsolute } from 'node:path';
40
- import { createInterface } from 'node:readline';
41
- import { fileURLToPath } from 'node:url';
42
-
43
-
44
- export const BRIDGE_PATH = fileURLToPath(import.meta.url);
45
- export const BRIDGE_URL_VAR = 'COMMONLY_BROKER_URL';
46
- export const BRIDGE_HEADERS_VAR = 'COMMONLY_BROKER_HEADERS';
47
- export const TOKEN_PLACEHOLDER = '${COMMONLY_AGENT_TOKEN}';
48
-
49
- // The same name as credential-file.js CREDENTIAL_FILE_VAR (a test pins it).
50
- export const CREDENTIAL_FILE_VAR = 'COMMONLY_TOKEN_FILE';
51
- // The same name as commonly-mcp's READY_FILE_ENV (a test pins it).
52
- export const READY_FILE_VAR = 'COMMONLY_MCP_READY_FILE';
53
-
54
- const MAX_ERROR_TEXT = 2048;
55
-
56
- // Streamable HTTP answers a POST with one JSON object or with an event stream
57
- // of `data:` payloads. Same reading as pi-mcp-client.mjs parseMessages: the body
58
- // decides before the header does.
59
- const ssePayloads = (text) => text.split(/\r?\n\r?\n/)
60
- .map((block) => block.split(/\r?\n/)
61
- .filter((line) => line.startsWith('data:'))
62
- .map((line) => line.slice(5).trimStart())
63
- .join('\n'))
64
- .filter(Boolean);
65
-
66
- const parseMessages = (text, contentType) => {
67
- const body = text.trim();
68
- if (!body) return [];
69
- if (contentType.includes('text/event-stream')) return ssePayloads(body);
70
- if (body.startsWith('{') || body.startsWith('[')) return [body];
71
- return ssePayloads(body);
72
- };
73
-
74
- const rpcError = (id, code, message) => ({ jsonrpc: '2.0', id: id ?? null, error: { code, message } });
75
-
76
- export const createBrokerBridge = ({
77
- url,
78
- headerTemplates = {},
79
- tokenFile,
80
- readyFile = null,
81
- fetchImpl = globalThis.fetch,
82
- write,
83
- writeReady = writeFileSync,
84
- warn = (text) => process.stderr.write(`[commonly-broker-bridge] ${text}\n`),
85
- timeoutMs = 120_000,
86
- }) => {
87
- let sessionId = null;
88
- let protocolVersion = null;
89
- let lastToken = null;
90
- let readyWritten = !readyFile;
91
- // Nothing the bridge writes back may hold the token, whatever produced it.
92
- const scrub = (text) => (lastToken ? String(text).split(lastToken).join('[token]') : String(text));
93
-
94
- // Once: the file is deleted after its readers have it (F460).
95
- const readToken = () => {
96
- if (lastToken) return lastToken;
97
- if (!tokenFile) throw new Error(`no credential file (${CREDENTIAL_FILE_VAR} is unset)`);
98
- let token;
99
- try {
100
- token = readFileSync(tokenFile, 'utf8').trim();
101
- } catch (error) {
102
- throw new Error(`cannot read the credential file: ${error?.code || error?.message || error}`);
103
- }
104
- if (!token) throw new Error('the credential file is empty');
105
- lastToken = token;
106
- return token;
107
- };
108
-
109
- const needsToken = () => Object.values(headerTemplates).some((v) => String(v).includes(TOKEN_PLACEHOLDER));
110
- // Read at start, before the host asks for anything, so a file deleted at the
111
- // ready deadline finds the token already held. A file that cannot be read
112
- // now is reported on the first request instead.
113
- const prime = () => {
114
- if (!needsToken()) return true;
115
- try {
116
- readToken();
117
- return true;
118
- } catch {
119
- return false;
120
- }
121
- };
122
- // Exclusive, 0600, holds nothing secret; written once the token is held.
123
- const markReady = () => {
124
- if (readyWritten) return;
125
- readyWritten = true;
126
- if (!isAbsolute(readyFile)) {
127
- warn(`${READY_FILE_VAR} is not an absolute path; not writing it`);
128
- return;
129
- }
130
- try {
131
- writeReady(readyFile, 'ready\n', { flag: 'wx', mode: 0o600 });
132
- } catch (error) {
133
- warn(`could not write the ready file: ${error?.code || error?.message || error}`);
134
- }
135
- };
136
-
137
- const headers = () => {
138
- const templates = Object.entries(headerTemplates);
139
- const token = needsToken() ? readToken() : null;
140
- return {
141
- 'content-type': 'application/json',
142
- accept: 'application/json, text/event-stream',
143
- ...Object.fromEntries(templates.map(([k, v]) => [k, String(v).split(TOKEN_PLACEHOLDER).join(token)])),
144
- ...(sessionId ? { 'mcp-session-id': sessionId } : {}),
145
- ...(protocolVersion ? { 'mcp-protocol-version': protocolVersion } : {}),
146
- };
147
- };
148
-
149
- // One exchange: POST the line, then hand each JSON-RPC message in the answer
150
- // to `onMessage` as it arrives. An event stream is read event by event, so a
151
- // notification sent before the response reaches codex then, and reading stops
152
- // once `onMessage` says the request is answered, whether or not the server
153
- // closes the stream. The timer covers the whole exchange, body included: a
154
- // stream that never answers still ends in an error, not a wait forever.
155
- const exchange = async (body, onMessage) => {
156
- const controller = new AbortController();
157
- const timer = setTimeout(() => controller.abort(), timeoutMs);
158
- try {
159
- const res = await fetchImpl(url, {
160
- method: 'POST',
161
- headers: headers(),
162
- body,
163
- signal: controller.signal,
164
- // The request carries the seat token, so no redirect is followed: a
165
- // redirect may point at another origin (same rule as connectHttpMcp).
166
- redirect: 'error',
167
- });
168
- const contentType = res.headers?.get?.('content-type') || '';
169
- const reader = res.ok && contentType.includes('text/event-stream') ? res.body?.getReader?.() : null;
170
- if (!reader) return { res, text: await res.text() };
171
- // Not every fetch errors a body it has already handed over when the
172
- // signal fires, so the timeout ends the read itself.
173
- const stopReading = () => reader.cancel().catch(() => {});
174
- controller.signal.addEventListener('abort', stopReading, { once: true });
175
- const decoder = new TextDecoder();
176
- let buffered = '';
177
- const drain = (final) => {
178
- const blocks = buffered.split(/\r?\n\r?\n/);
179
- buffered = final ? '' : blocks.pop();
180
- return blocks.flatMap((block) => ssePayloads(`${block}\n\n`)).some((raw) => onMessage(raw));
181
- };
182
- for (;;) {
183
- // eslint-disable-next-line no-await-in-loop
184
- const { value, done } = await reader.read();
185
- if (done) {
186
- buffered += decoder.decode();
187
- drain(true);
188
- break;
189
- }
190
- buffered += decoder.decode(value, { stream: true });
191
- if (drain(false)) {
192
- stopReading();
193
- break;
194
- }
195
- }
196
- if (controller.signal.aborted) throw Object.assign(new Error('aborted'), { name: 'AbortError' });
197
- return { res, text: null };
198
- } finally {
199
- clearTimeout(timer);
200
- }
201
- };
202
-
203
- const handleLine = async (line) => {
204
- if (!line.trim()) return;
205
- let message;
206
- try {
207
- message = JSON.parse(line);
208
- } catch {
209
- write(JSON.stringify(rpcError(null, -32700, 'parse error')));
210
- return;
211
- }
212
- const id = message?.id;
213
- const isRequest = id !== undefined && id !== null && typeof message?.method === 'string';
214
- let answered = false;
215
- const fail = (text) => {
216
- if (isRequest && !answered) write(JSON.stringify(rpcError(id, -32000, `grant broker: ${scrub(text)}`)));
217
- else process.stderr.write(`[commonly-broker-bridge] ${scrub(text)}\n`);
218
- };
219
- // Writes one message back to codex; true once this request is answered.
220
- const forward = (raw) => {
221
- let answer;
222
- try {
223
- answer = JSON.parse(raw);
224
- } catch {
225
- return false;
226
- }
227
- if (message?.method === 'initialize' && answer?.id === id
228
- && typeof answer?.result?.protocolVersion === 'string') {
229
- protocolVersion = answer.result.protocolVersion;
230
- }
231
- write(JSON.stringify(answer));
232
- if (isRequest && answer?.id === id && ('result' in answer || 'error' in answer)) answered = true;
233
- if (answered && message?.method === 'tools/list' && 'result' in answer && (lastToken || !needsToken())) markReady();
234
- return answered;
235
- };
236
- let res;
237
- let text;
238
- try {
239
- ({ res, text } = await exchange(line, forward));
240
- } catch (error) {
241
- fail(error?.name === 'AbortError' ? `timed out after ${timeoutMs}ms` : (error?.message || String(error)));
242
- return;
243
- }
244
- const header = res.headers?.get?.('mcp-session-id');
245
- if (header && !sessionId) sessionId = header;
246
- if (!res.ok) {
247
- fail(`HTTP ${res.status}${text ? `: ${text.slice(0, MAX_ERROR_TEXT)}` : ''}`);
248
- return;
249
- }
250
- if (text !== null) {
251
- for (const raw of parseMessages(text || '', res.headers?.get?.('content-type') || '')) forward(raw);
252
- }
253
- };
254
-
255
- return { handleLine, prime };
256
- };
257
-
258
- const isMain = () => {
259
- try {
260
- return realpathSync(process.argv[1] || '') === realpathSync(BRIDGE_PATH);
261
- } catch {
262
- return false;
263
- }
264
- };
265
-
266
- if (isMain()) {
267
- const url = process.env[BRIDGE_URL_VAR];
268
- let headerTemplates = {};
269
- try {
270
- headerTemplates = JSON.parse(process.env[BRIDGE_HEADERS_VAR] || '{}');
271
- } catch {
272
- process.stderr.write(`[commonly-broker-bridge] ${BRIDGE_HEADERS_VAR} is not JSON\n`);
273
- process.exit(1);
274
- }
275
- if (!url) {
276
- process.stderr.write(`[commonly-broker-bridge] ${BRIDGE_URL_VAR} is unset\n`);
277
- process.exit(1);
278
- }
279
- const bridge = createBrokerBridge({
280
- url,
281
- headerTemplates,
282
- tokenFile: process.env[CREDENTIAL_FILE_VAR],
283
- readyFile: process.env[READY_FILE_VAR] || null,
284
- // A closed stdout (codex gone) must not become an unhandled rejection.
285
- write: (line) => { try { process.stdout.write(`${line}\n`); } catch { /* codex has gone */ } },
286
- });
287
- bridge.prime();
288
- const pending = new Set();
289
- const lines = createInterface({ input: process.stdin });
290
- lines.on('line', (line) => {
291
- const task = bridge.handleLine(line).finally(() => pending.delete(task));
292
- pending.add(task);
293
- });
294
- lines.on('close', async () => {
295
- await Promise.allSettled([...pending]);
296
- process.exit(0);
297
- });
298
- }