@ravefox/space 0.0.0-stage → 0.2.1

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 (152) hide show
  1. package/LICENSE +205 -0
  2. package/NOTICE +55 -0
  3. package/README.md +63 -2
  4. package/assets/webhook-sdk/python/bot.py +63 -0
  5. package/assets/webhook-sdk/python/commonly.py +232 -0
  6. package/node_modules/@commonlyai/seats/README.md +25 -0
  7. package/node_modules/@commonlyai/seats/package.json +22 -0
  8. package/node_modules/@commonlyai/seats/src/adapters/hermes.js +264 -0
  9. package/node_modules/@commonlyai/seats/src/adapters/stub.js +24 -0
  10. package/node_modules/@commonlyai/seats/src/contract.js +48 -0
  11. package/node_modules/@commonlyai/seats/src/failures.js +44 -0
  12. package/node_modules/@commonlyai/seats/src/harness-plan.js +329 -0
  13. package/node_modules/@commonlyai/seats/src/index.js +22 -0
  14. package/node_modules/@commonlyai/seats/src/process-group.js +269 -0
  15. package/node_modules/@commonlyai/seats/src/record/format.js +737 -0
  16. package/node_modules/@commonlyai/seats/src/record/otel.js +238 -0
  17. package/node_modules/@commonlyai/seats/src/runtime-observation.js +29 -0
  18. package/node_modules/@commonlyai/seats/src/seat-model.js +17 -0
  19. package/node_modules/@commonlyai/seats/src/supervisor.js +308 -0
  20. package/node_modules/@commonlyai/seats/src/trace/events.js +46 -0
  21. package/node_modules/@commonlyai/seats/src/trace/store.js +276 -0
  22. package/node_modules/@commonlyai/seats/src/turn-processes.js +226 -0
  23. package/node_modules/@commonlyai/seats/src/upstream-refusal.js +418 -0
  24. package/node_modules/@commonlyai/seats/src/valet/env.js +201 -0
  25. package/node_modules/@commonlyai/seats/src/valet/grant.js +123 -0
  26. package/node_modules/@commonlyai/seats/src/valet/permissions.js +213 -0
  27. package/node_modules/@commonlyai/seats/src/wire/provider-proxy.js +529 -0
  28. package/package.json +63 -4
  29. package/skills/commonly/SKILL.md +233 -0
  30. package/src/commands/agent.js +6334 -0
  31. package/src/commands/daemon.js +933 -0
  32. package/src/commands/dev.js +153 -0
  33. package/src/commands/doctor.js +141 -0
  34. package/src/commands/inbox.js +330 -0
  35. package/src/commands/login.js +194 -0
  36. package/src/commands/mcp.js +56 -0
  37. package/src/commands/pod.js +120 -0
  38. package/src/commands/task.js +279 -0
  39. package/src/commands/verify.js +48 -0
  40. package/src/index.js +99 -0
  41. package/src/lib/adapter-login.js +76 -0
  42. package/src/lib/adapters/broker-bridge-entry.js +76 -0
  43. package/src/lib/adapters/claude.js +2207 -0
  44. package/src/lib/adapters/codex-broker-bridge.mjs +298 -0
  45. package/src/lib/adapters/codex.js +1898 -0
  46. package/src/lib/adapters/dsh.js +513 -0
  47. package/src/lib/adapters/goose.js +510 -0
  48. package/src/lib/adapters/hermes.js +18 -0
  49. package/src/lib/adapters/index.js +68 -0
  50. package/src/lib/adapters/opencode.js +1681 -0
  51. package/src/lib/adapters/pi-commonly-mcp.mjs +71 -0
  52. package/src/lib/adapters/pi-mcp-client.mjs +617 -0
  53. package/src/lib/adapters/pi-shell-env.mjs +41 -0
  54. package/src/lib/adapters/pi.js +1025 -0
  55. package/src/lib/adapters/qwen.js +523 -0
  56. package/src/lib/adapters/seat-model.js +8 -0
  57. package/src/lib/adapters/stub.js +1 -0
  58. package/src/lib/adapters/tested-version.js +106 -0
  59. package/src/lib/api.js +205 -0
  60. package/src/lib/claim-outcome.js +128 -0
  61. package/src/lib/claimed-work-gate.js +73 -0
  62. package/src/lib/cli-hint.js +33 -0
  63. package/src/lib/commit-attribution.js +391 -0
  64. package/src/lib/config.js +155 -0
  65. package/src/lib/content-refusal.js +94 -0
  66. package/src/lib/credential-file.js +208 -0
  67. package/src/lib/daemon-agent-states.js +95 -0
  68. package/src/lib/daemon-hint.js +18 -0
  69. package/src/lib/daemon-logs.js +43 -0
  70. package/src/lib/daemon-service-windows.js +263 -0
  71. package/src/lib/daemon-service.js +486 -0
  72. package/src/lib/daemon-state.js +84 -0
  73. package/src/lib/daemon-store.js +119 -0
  74. package/src/lib/daemon-supervisor.js +629 -0
  75. package/src/lib/daemon-watch.js +115 -0
  76. package/src/lib/declared-mcp-guard.js +284 -0
  77. package/src/lib/default-environment.js +207 -0
  78. package/src/lib/device-login.js +126 -0
  79. package/src/lib/digest-frame.js +151 -0
  80. package/src/lib/doctor.js +291 -0
  81. package/src/lib/egress-proxy.js +160 -0
  82. package/src/lib/enforcement.js +946 -0
  83. package/src/lib/environment.js +681 -0
  84. package/src/lib/first-output-watchdog.js +191 -0
  85. package/src/lib/git-readonly-server.js +138 -0
  86. package/src/lib/git-readonly.js +463 -0
  87. package/src/lib/git-remote-commonly.mjs +100 -0
  88. package/src/lib/grant-broker-guard.js +345 -0
  89. package/src/lib/hooks-config.js +238 -0
  90. package/src/lib/host-gh-broker.js +152 -0
  91. package/src/lib/host-gh-shim.mjs +98 -0
  92. package/src/lib/inbox.js +483 -0
  93. package/src/lib/instance-proxy.js +76 -0
  94. package/src/lib/machine-host.js +29 -0
  95. package/src/lib/mcp-credential-delivery.js +121 -0
  96. package/src/lib/mcp-first-run.js +50 -0
  97. package/src/lib/mcp-home.js +644 -0
  98. package/src/lib/mcp-ready.js +68 -0
  99. package/src/lib/mcp-server-version.js +123 -0
  100. package/src/lib/mcp-token.js +36 -0
  101. package/src/lib/mcp-warm-child.mjs +412 -0
  102. package/src/lib/memory-bridge.js +191 -0
  103. package/src/lib/memory-import.js +156 -0
  104. package/src/lib/missing-harness.js +31 -0
  105. package/src/lib/model-unavailable.js +154 -0
  106. package/src/lib/native-runtime-inventory.js +40 -0
  107. package/src/lib/outsider-grant-mcp.js +82 -0
  108. package/src/lib/own-key-launch.js +42 -0
  109. package/src/lib/pod-catch-up.js +55 -0
  110. package/src/lib/pod-focus.js +224 -0
  111. package/src/lib/pod-tail.js +68 -0
  112. package/src/lib/poll-liveness.js +103 -0
  113. package/src/lib/poll-retry.js +81 -0
  114. package/src/lib/poller.js +200 -0
  115. package/src/lib/provider-proxy.js +42 -0
  116. package/src/lib/public-seat-mcp-flag.js +36 -0
  117. package/src/lib/public-tool-error.js +60 -0
  118. package/src/lib/public-withheld-tools.js +48 -0
  119. package/src/lib/reply-receipt.js +55 -0
  120. package/src/lib/resolve-on-path.js +22 -0
  121. package/src/lib/runtime-inventory.js +56 -0
  122. package/src/lib/runtime-observation.js +37 -0
  123. package/src/lib/sandbox/bwrap.js +275 -0
  124. package/src/lib/sandbox/codex-perimeter.js +16 -0
  125. package/src/lib/sandbox/host-check.js +268 -0
  126. package/src/lib/sandbox/mode.js +49 -0
  127. package/src/lib/sandbox/opencode-loopback.mjs +68 -0
  128. package/src/lib/sandbox/seatbelt.js +684 -0
  129. package/src/lib/sandbox/turn-dir.js +56 -0
  130. package/src/lib/sandbox/windows-unsandboxed.js +183 -0
  131. package/src/lib/sandbox/workspace-git-config.js +243 -0
  132. package/src/lib/sandbox/workspace-pin.js +158 -0
  133. package/src/lib/seat-runtime-controls.js +61 -0
  134. package/src/lib/seat-stop.js +97 -0
  135. package/src/lib/server-skills.js +32 -0
  136. package/src/lib/session-recycle.js +219 -0
  137. package/src/lib/session-store.js +215 -0
  138. package/src/lib/skill-prompt.js +74 -0
  139. package/src/lib/skills-import.js +113 -0
  140. package/src/lib/spawn-credential.js +402 -0
  141. package/src/lib/spawn-retry.js +311 -0
  142. package/src/lib/stable-install.js +176 -0
  143. package/src/lib/supervised-turn.js +352 -0
  144. package/src/lib/task.js +235 -0
  145. package/src/lib/turn-failure-notice.js +177 -0
  146. package/src/lib/unconfined-seat-guard.js +94 -0
  147. package/src/lib/update-check.js +192 -0
  148. package/src/lib/upstream-refusal.js +1 -0
  149. package/src/lib/webhook-server.js +109 -0
  150. package/src/lib/windows-command.js +393 -0
  151. package/src/lib/workspace-git.js +87 -0
  152. package/src/lib/workspace-trust.js +162 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Per-spawn GitHub command bridge for a confined host seat. The socket carries
3
+ * no secret: its trusted owner holds the runtime token and chooses the backend
4
+ * URL. The Codex permission profile must allow only this seat's exact socket.
5
+ */
6
+ import { createServer } from 'net';
7
+ import { chmod, lstat, mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
8
+ import { homedir } from 'os';
9
+ import { fileURLToPath } from 'url';
10
+ import { join, resolve } from 'path';
11
+
12
+ const MAX_REQUEST_BYTES = 64 * 1024;
13
+ const MAX_RESPONSE_BYTES = 128 * 1024;
14
+ const SHIM_SOURCE = fileURLToPath(new URL('./host-gh-shim.mjs', import.meta.url));
15
+ const PUSH_HELPER_SOURCE = fileURLToPath(new URL('./git-remote-commonly.mjs', import.meta.url));
16
+ const MAX_PUSH_REQUEST_BYTES = 9 * 1024 * 1024;
17
+
18
+ const reply = (socket, status, body) => {
19
+ if (!socket.destroyed) socket.end(JSON.stringify({ status, body }));
20
+ };
21
+
22
+ export const startSeatGhBroker = async ({
23
+ runtimeToken, instanceUrl, shimRoot, fetchImpl = fetch,
24
+ root = join(homedir(), '.commonly', 'host-gh'),
25
+ }) => {
26
+ if (typeof runtimeToken !== 'string' || !runtimeToken.startsWith('cm_agent_')) {
27
+ throw new Error('host GitHub broker requires a runtime token');
28
+ }
29
+ const endpoint = new URL(instanceUrl);
30
+ if (!['https:', 'http:'].includes(endpoint.protocol) || endpoint.username || endpoint.password) {
31
+ throw new Error('host GitHub broker requires an HTTP instance URL');
32
+ }
33
+ if (endpoint.protocol === 'http:' && !['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname)) {
34
+ throw new Error('host GitHub broker requires HTTPS outside localhost');
35
+ }
36
+ if (typeof shimRoot !== 'string' || !shimRoot) {
37
+ throw new Error('host GitHub broker requires a seat-visible shim root');
38
+ }
39
+ if (resolve(shimRoot) === resolve(root)) {
40
+ throw new Error('host GitHub shims cannot share the protected socket root');
41
+ }
42
+ await mkdir(root, { recursive: true, mode: 0o700 });
43
+ const rootStats = await lstat(root);
44
+ if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
45
+ throw new Error('host GitHub broker root must be a real directory');
46
+ }
47
+ await chmod(root, 0o700);
48
+ const shimRootStats = await lstat(shimRoot);
49
+ if (!shimRootStats.isDirectory() || shimRootStats.isSymbolicLink()) {
50
+ throw new Error('host GitHub shim root must be a real directory');
51
+ }
52
+ let socketDirectory;
53
+ let directory;
54
+ let server;
55
+ const connections = new Set();
56
+ try {
57
+ socketDirectory = await mkdtemp(join(root, 'seat-'));
58
+ directory = await mkdtemp(join(shimRoot, '.commonly-gh-'));
59
+ const socketPath = join(socketDirectory, 'broker.sock');
60
+ const shimPath = join(directory, 'gh');
61
+ const pushHelperPath = join(directory, 'git-remote-commonly');
62
+ const shimSource = await readFile(SHIM_SOURCE, 'utf8');
63
+ await writeFile(shimPath, `#!${process.execPath}\n${shimSource.replace(/^#![^\n]*\n/, '')}`, { mode: 0o500 });
64
+ await chmod(shimPath, 0o555);
65
+ const helperSource = await readFile(PUSH_HELPER_SOURCE, 'utf8');
66
+ await writeFile(pushHelperPath, `#!${process.execPath}\n${helperSource.replace(/^#![^\n]*\n/, '')}`, { mode: 0o500 });
67
+ await chmod(pushHelperPath, 0o555);
68
+ server = createServer({ allowHalfOpen: true }, (socket) => {
69
+ connections.add(socket);
70
+ socket.on('close', () => connections.delete(socket));
71
+ let chunks = [];
72
+ let size = 0;
73
+ socket.setTimeout(15_000, () => socket.destroy());
74
+ socket.on('error', () => {});
75
+ socket.on('data', (chunk) => {
76
+ size += chunk.length;
77
+ if (size > MAX_PUSH_REQUEST_BYTES) {
78
+ reply(socket, 413, { error: 'request_too_large' });
79
+ chunks = [];
80
+ } else {
81
+ chunks.push(chunk);
82
+ }
83
+ });
84
+ socket.on('end', async () => {
85
+ if (socket.destroyed || size > MAX_PUSH_REQUEST_BYTES) return;
86
+ let request;
87
+ try { request = JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch {
88
+ reply(socket, 400, { error: 'invalid_request' });
89
+ return;
90
+ }
91
+ const { grantId, operation, args } = request || {};
92
+ if (!/^[A-Za-z0-9_-]{1,128}$/.test(grantId)
93
+ || typeof operation !== 'string' || !args || typeof args !== 'object'
94
+ || Array.isArray(args) || Object.keys(request).some((key) => !['grantId', 'operation', 'args'].includes(key))) {
95
+ reply(socket, 400, { error: 'invalid_request' });
96
+ return;
97
+ }
98
+ if (operation !== 'push.branch' && size > MAX_REQUEST_BYTES) {
99
+ reply(socket, 413, { error: 'request_too_large' });
100
+ return;
101
+ }
102
+ if (operation === 'push.branch') socket.setTimeout(180_000, () => socket.destroy());
103
+ try {
104
+ const suffix = operation === 'push.branch' ? 'push' : 'cli';
105
+ const url = new URL(`/api/mcp/grants/${encodeURIComponent(grantId)}/${suffix}`, endpoint);
106
+ const response = await fetchImpl(url, {
107
+ method: 'POST',
108
+ headers: { Authorization: `Bearer ${runtimeToken}`, 'Content-Type': 'application/json' },
109
+ body: JSON.stringify(operation === 'push.branch' ? args : { operation, args }),
110
+ signal: AbortSignal.timeout(operation === 'push.branch' ? 180_000 : 15_000),
111
+ });
112
+ const bodyText = await response.text();
113
+ if (Buffer.byteLength(bodyText, 'utf8') > MAX_RESPONSE_BYTES) {
114
+ reply(socket, 502, { error: 'broker_response_too_large' });
115
+ return;
116
+ }
117
+ let body;
118
+ try { body = JSON.parse(bodyText); } catch { body = { error: 'broker_response_invalid' }; }
119
+ reply(socket, response.status, body);
120
+ } catch {
121
+ reply(socket, 502, { error: 'broker_unavailable' });
122
+ }
123
+ });
124
+ });
125
+ await new Promise((resolve, reject) => {
126
+ server.once('error', reject);
127
+ server.listen(socketPath, () => {
128
+ server.off('error', reject);
129
+ resolve();
130
+ });
131
+ });
132
+ return {
133
+ socketPath,
134
+ shimPath,
135
+ pushHelperPath,
136
+ directory,
137
+ socketDirectory,
138
+ async close() {
139
+ for (const socket of connections) socket.destroy();
140
+ await new Promise((resolve) => server.close(resolve));
141
+ await rm(directory, { recursive: true, force: true });
142
+ await rm(socketDirectory, { recursive: true, force: true });
143
+ },
144
+ };
145
+ } catch (error) {
146
+ for (const socket of connections) socket.destroy();
147
+ if (server?.listening) await new Promise((resolve) => server.close(resolve));
148
+ if (directory) await rm(directory, { recursive: true, force: true });
149
+ if (socketDirectory) await rm(socketDirectory, { recursive: true, force: true });
150
+ throw error;
151
+ }
152
+ };
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ /** Narrow gh-compatible entrypoint for confined Commonly host seats. */
3
+ import { connect } from 'net';
4
+
5
+ const fail = (message) => {
6
+ process.stderr.write(`${message}\n`);
7
+ process.exitCode = 2;
8
+ };
9
+
10
+ const parse = (argv) => {
11
+ const parts = [...argv];
12
+ const grantFlag = parts.indexOf('--grant-id');
13
+ if (grantFlag < 0 || grantFlag + 1 >= parts.length) throw new Error('pass --grant-id <grant>');
14
+ const [grantId] = parts.splice(grantFlag + 1, 1);
15
+ parts.splice(grantFlag, 1);
16
+ if (!/^[A-Za-z0-9_-]{1,128}$/.test(grantId)) throw new Error('invalid grant id');
17
+
18
+ const [area, action, ...rest] = parts;
19
+ let operation;
20
+ let requiredFlags = [];
21
+ let allowedFlags = [];
22
+ let numberField;
23
+ if (area === 'pr' && action === 'create') {
24
+ operation = 'pr.create';
25
+ requiredFlags = ['--title', '--head', '--base'];
26
+ allowedFlags = [...requiredFlags, '--body', '--draft'];
27
+ } else if (area === 'pr' && action === 'view') {
28
+ operation = 'pr.view'; numberField = 'pullNumber';
29
+ } else if (area === 'pr' && action === 'comment') {
30
+ operation = 'pr.comment'; numberField = 'pullNumber';
31
+ requiredFlags = ['--body']; allowedFlags = requiredFlags;
32
+ } else if (area === 'pr' && action === 'review') {
33
+ operation = 'pr.review_comment'; numberField = 'pullNumber';
34
+ requiredFlags = ['--comment', '--body']; allowedFlags = requiredFlags;
35
+ } else if (area === 'issue' && action === 'comment') {
36
+ operation = 'issue.comment'; numberField = 'issueNumber';
37
+ requiredFlags = ['--body']; allowedFlags = requiredFlags;
38
+ } else {
39
+ throw new Error('gh operation is not allowed for this seat');
40
+ }
41
+
42
+ const args = {};
43
+ if (numberField) {
44
+ const value = rest.shift();
45
+ if (!/^[1-9][0-9]*$/.test(value || '') || !Number.isSafeInteger(Number(value))) {
46
+ throw new Error('pass a positive issue or PR number');
47
+ }
48
+ args[numberField] = Number(value);
49
+ }
50
+ const flags = new Set();
51
+ while (rest.length) {
52
+ const flag = rest.shift();
53
+ if (!allowedFlags.includes(flag) || flags.has(flag)) throw new Error(`flag is not allowed: ${flag}`);
54
+ flags.add(flag);
55
+ if (flag === '--draft' || flag === '--comment') continue;
56
+ const value = rest.shift();
57
+ if (value === undefined || value.startsWith('--')) throw new Error(`missing value for ${flag}`);
58
+ if (value.length > 32 * 1024) throw new Error(`value is too long for ${flag}`);
59
+ args[flag.slice(2)] = value;
60
+ }
61
+ if (requiredFlags.some((flag) => !flags.has(flag))) throw new Error('required flag is missing');
62
+ if (flags.has('--draft')) args.draft = true;
63
+ return { grantId, operation, args };
64
+ };
65
+
66
+ const main = async () => {
67
+ const request = parse(process.argv.slice(2));
68
+ const socketPath = process.env.COMMONLY_GH_SOCKET;
69
+ if (!socketPath || !socketPath.startsWith('/')) throw new Error('seat GitHub broker is unavailable');
70
+ const answer = await new Promise((resolve, reject) => {
71
+ const socket = connect(socketPath);
72
+ const chunks = [];
73
+ let size = 0;
74
+ socket.setTimeout(20_000, () => socket.destroy(new Error('seat GitHub broker timed out')));
75
+ socket.on('connect', () => socket.end(JSON.stringify(request)));
76
+ socket.on('data', (chunk) => {
77
+ size += chunk.length;
78
+ if (size > 128 * 1024) socket.destroy(new Error('seat GitHub response is too large'));
79
+ else chunks.push(chunk);
80
+ });
81
+ socket.on('error', reject);
82
+ socket.on('end', () => {
83
+ try { resolve(JSON.parse(Buffer.concat(chunks).toString('utf8'))); } catch {
84
+ reject(new Error('seat GitHub response is invalid'));
85
+ }
86
+ });
87
+ });
88
+ if (answer.status === 202 && answer.body?.status === 'pending_approval') {
89
+ process.stdout.write(`${JSON.stringify(answer.body, null, 2)}\n`);
90
+ return;
91
+ }
92
+ if (answer.status < 200 || answer.status >= 300) {
93
+ throw new Error(answer.body?.error || answer.body?.status || 'GitHub operation refused');
94
+ }
95
+ process.stdout.write(`${JSON.stringify(answer.body, null, 2)}\n`);
96
+ };
97
+
98
+ main().catch((error) => fail(error.message));