@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,22 +0,0 @@
1
- {
2
- "name": "@commonlyai/seats",
3
- "version": "0.0.0",
4
- "private": true,
5
- "license": "Apache-2.0",
6
- "description": "Adapters that run agent CLIs as supervised seats. Bundled inside @commonlyai/cli; not published on its own.",
7
- "type": "module",
8
- "exports": {
9
- ".": "./src/index.js",
10
- "./*": "./src/*.js"
11
- },
12
- "files": [
13
- "src",
14
- "README.md"
15
- ],
16
- "engines": {
17
- "node": ">=22.0.0"
18
- },
19
- "scripts": {
20
- "test": "node --test $([ -z \"$CI\" ] && echo --test-concurrency=4) \"test/**/*.test.js\""
21
- }
22
- }
@@ -1,264 +0,0 @@
1
- /** Hermes 0.22 local CLI wrapper. Hermes owns provider I/O; this file only spawns it. */
2
- import { spawn as childSpawn, spawnSync } from 'child_process';
3
- import { createHash, randomBytes } from 'crypto';
4
- import { chmod, mkdir, readFile, rename, rm, writeFile } from 'fs/promises';
5
- import { homedir } from 'os';
6
- import { join } from 'path';
7
- import { StringDecoder } from 'string_decoder';
8
- import { observeSpawn, controlsFromArguments } from '../runtime-observation.js';
9
- import { requireSeatModel } from '../seat-model.js';
10
- import { adapterFailure, spawnCredentials } from '../upstream-refusal.js';
11
-
12
- export const SUPPORTED_HERMES_VERSION_RANGE = '>=0.22.5 <0.23.0';
13
- const supportsHermesVersion = (version) => {
14
- const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version || '');
15
- if (!match) return false;
16
- return Number(match[1]) === 0 && Number(match[2]) === 22 && Number(match[3]) >= 5;
17
- };
18
- const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
19
- const VERSION_TIMEOUT_MS = 15000;
20
- const MAX_STDERR_CHARS = 4096;
21
- const MAX_LINE_CHARS = 1024 * 1024;
22
- // Keys the wrapper owns in the profile's .env. Every other line is the user's.
23
- const PROFILE_ENV_KEYS = ['OPENROUTER_API_KEY', 'OPENROUTER_BASE_URL'];
24
- const PLAIN_ENV_VALUE = /^[A-Za-z0-9_\-.:/+=@%~]+$/;
25
-
26
- const definedKey = (line) => {
27
- const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line);
28
- return match ? match[1] : null;
29
- };
30
-
31
- // From 0.22.5 the detached gateway serves a profiles/<hash> home with a child
32
- // env scrubbed of credentials and overlaid with that profile's own .env
33
- // (tools/environments/local.py, served_profile_child_env), so a key in the
34
- // spawn env never reaches the model. Hermes documents <profile>/.env as where
35
- // a profile's API keys live (website/docs/user-guide/profiles.md). The file
36
- // stays after the turn: the gateway outlives the spawn and rereads it.
37
- export const syncProfileEnv = async (home, env) => {
38
- const owned = PROFILE_ENV_KEYS.filter((key) => env[key]);
39
- for (const key of owned) {
40
- if (!PLAIN_ENV_VALUE.test(env[key])) {
41
- throw new Error(`${key} contains characters a Hermes .env line cannot carry unquoted; refusing to write it`);
42
- }
43
- }
44
- const path = join(home, '.env');
45
- let current = '';
46
- try {
47
- current = await readFile(path, 'utf8');
48
- } catch (error) {
49
- if (error?.code !== 'ENOENT') throw new Error(`Cannot read the Hermes profile .env (${error?.code || 'read failed'})`);
50
- }
51
- const kept = current.split(/\r?\n/).filter((line, index, lines) => (
52
- !owned.includes(definedKey(line)) && !(index === lines.length - 1 && line === '')
53
- ));
54
- const next = `${[...kept, ...owned.map((key) => `${key}=${env[key]}`)].join('\n')}\n`;
55
- await chmod(home, 0o700);
56
- if (next === current) {
57
- await chmod(path, 0o600);
58
- return;
59
- }
60
- const temp = join(home, `.env.${process.pid}.${randomBytes(6).toString('hex')}.tmp`);
61
- try {
62
- await writeFile(temp, next, { mode: 0o600, flag: 'wx' });
63
- await chmod(temp, 0o600);
64
- await rename(temp, path);
65
- } catch (error) {
66
- await rm(temp, { force: true });
67
- throw new Error(`Cannot write the Hermes profile .env (${error?.code || 'write failed'})`);
68
- }
69
- };
70
-
71
- const readVersion = (env, spawnSyncImpl = spawnSync) => {
72
- let probe;
73
- for (let attempt = 0; attempt < 2; attempt += 1) {
74
- probe = spawnSyncImpl('hermes', ['--version'], {
75
- encoding: 'utf8', env, timeout: VERSION_TIMEOUT_MS,
76
- });
77
- if (probe.error?.code === 'ENOENT') return null;
78
- if (probe.error || probe.status !== 0) continue;
79
- const version = String(probe.stdout || '').match(/Hermes Agent v([^\s]+)/i)?.[1];
80
- if (!supportsHermesVersion(version)) {
81
- throw new Error(`Hermes ${version || 'unknown'} is unsupported; this adapter supports ${SUPPORTED_HERMES_VERSION_RANGE}. Run hermes update if yours is older than 0.22.5; releases 0.23 and later are not supported yet`);
82
- }
83
- return version;
84
- }
85
- const status = probe.status ?? 'none';
86
- const signal = probe.signal ?? 'none';
87
- const code = probe.error?.code ?? 'none';
88
- throw new Error(`Hermes version probe failed after 2 attempts (status=${status}, signal=${signal}, code=${code}, timeout=${VERSION_TIMEOUT_MS}ms); check the Hermes installation or startup log`);
89
- };
90
-
91
- export const readHermesJsonl = (line, state) => {
92
- let event;
93
- try { event = JSON.parse(line); } catch { throw new Error('Hermes emitted invalid JSONL'); }
94
- if (state.result) throw new Error('Hermes emitted data after its terminal result');
95
- if (event?.type === 'system' && event.subtype === 'init') {
96
- state.started = true;
97
- } else if (event?.type === 'result') {
98
- state.result = event;
99
- } else if (!state.started) {
100
- throw new Error('Hermes emitted an event before init');
101
- }
102
- };
103
-
104
- const runHermes = ({ args, prompt, cwd, env, timeoutMs, spawnImpl, credentials, onSpawn, controls = {} }) => new Promise((resolve, reject) => {
105
- const child = (spawnImpl || childSpawn)('hermes', args, {
106
- cwd, env, stdio: ['pipe', 'pipe', 'pipe'],
107
- });
108
- observeSpawn(child, onSpawn, controls);
109
- const state = { started: false, result: null };
110
- const decoder = new StringDecoder('utf8');
111
- let buffer = '';
112
- let stderr = '';
113
- let timedOut = false;
114
- let settled = false;
115
- let closed = false;
116
- let stopping = false;
117
- let killTimer;
118
- const finish = (error, result) => {
119
- if (settled) return;
120
- settled = true;
121
- clearTimeout(timer);
122
- if (error) reject(error); else resolve(result);
123
- };
124
- const stop = () => {
125
- if (stopping || closed) return;
126
- stopping = true;
127
- child.kill('SIGTERM');
128
- killTimer = setTimeout(() => {
129
- if (!closed) child.kill('SIGKILL');
130
- }, 5000);
131
- };
132
- const failAndStop = (error) => {
133
- stop();
134
- finish(error);
135
- };
136
- const timer = setTimeout(() => {
137
- timedOut = true;
138
- stop();
139
- }, timeoutMs);
140
- child.on('error', (error) => failAndStop(adapterFailure('Hermes', error?.message || 'spawn failed', { credentials })));
141
- child.stdout.on('data', (chunk) => {
142
- if (settled) return;
143
- buffer += decoder.write(chunk);
144
- let newline = buffer.indexOf('\n');
145
- while (newline !== -1) {
146
- if (newline > MAX_LINE_CHARS) {
147
- failAndStop(new Error('Hermes JSONL line exceeded 1 MiB'));
148
- return;
149
- }
150
- const line = buffer.slice(0, newline).trim();
151
- buffer = buffer.slice(newline + 1);
152
- if (line) {
153
- try { readHermesJsonl(line, state); } catch (error) {
154
- failAndStop(error);
155
- return;
156
- }
157
- }
158
- newline = buffer.indexOf('\n');
159
- }
160
- if (buffer.length > MAX_LINE_CHARS) {
161
- failAndStop(new Error('Hermes JSONL line exceeded 1 MiB'));
162
- }
163
- });
164
- child.stdout.on('error', (error) => failAndStop(adapterFailure('Hermes stdout', error?.message || 'read failed', { credentials })));
165
- child.stderr.on('data', (chunk) => {
166
- stderr = `${stderr}${chunk.toString()}`.slice(-MAX_STDERR_CHARS);
167
- });
168
- child.on('close', (code) => {
169
- closed = true;
170
- clearTimeout(killTimer);
171
- if (settled) return;
172
- if (timedOut) return finish(new Error(`Hermes timed out after ${timeoutMs}ms`));
173
- buffer += decoder.end();
174
- if (buffer.trim()) {
175
- try { readHermesJsonl(buffer.trim(), state); } catch (error) { return finish(error); }
176
- }
177
- const result = state.result;
178
- if (!result || !state.started) return finish(new Error('Hermes exited without a complete JSONL result'));
179
- if (code !== 0 || result.exit_code !== 0) {
180
- return finish(adapterFailure('Hermes', result.error || stderr || `exit ${code}`, {
181
- credentials, exitCode: code,
182
- }));
183
- }
184
- if (typeof result.text !== 'string' || !result.session_id) {
185
- return finish(new Error('Hermes result omitted text or session_id'));
186
- }
187
- return finish(null, { text: result.text, newSessionId: result.session_id });
188
- });
189
- child.stdin.on('error', (error) => failAndStop(adapterFailure('Hermes stdin', error?.message || 'write failed', { credentials })));
190
- child.stdin.end(prompt);
191
- });
192
-
193
- /**
194
- * @param {import('../contract.js').SeatHost & { profileRoot?: string }} [host]
195
- * profileRoot is where each seat's isolated HERMES_HOME is created.
196
- */
197
- export const createHermesAdapter = ({
198
- memoryPreamble = (prompt) => prompt,
199
- effectiveTrust = (trust) => trust,
200
- seatModelRequired = () => false,
201
- profileRoot = join(homedir(), '.seats', 'hermes', 'profiles'),
202
- } = {}) => ({
203
- get requiresModel() { return seatModelRequired(); },
204
- name: 'hermes',
205
- runtimeType: 'hermes',
206
- supportsProvider: false,
207
- providerKeyEnv: 'OPENROUTER_API_KEY',
208
-
209
- async validateEnvironment(environment) {
210
- if (environment?.provider !== undefined) {
211
- throw new Error('Hermes adapter does not consume environment.provider; supply OPENROUTER_API_KEY in the host environment');
212
- }
213
- if (environment?.mcp?.length) {
214
- throw new Error('Hermes adapter does not yet consume environment.mcp declarations');
215
- }
216
- if (effectiveTrust(environment?.sandbox?.trust) === 'public'
217
- || (environment?.sandbox?.mode && environment.sandbox.mode !== 'none')) {
218
- throw new Error('Hermes public or sandbox-declared seats are unsupported: no enforced confinement adapter exists');
219
- }
220
- },
221
-
222
- async detect() {
223
- const version = readVersion(process.env);
224
- return version ? { path: 'hermes', version } : null;
225
- },
226
-
227
- async spawn(prompt, ctx = {}) {
228
- const seatModel = requireSeatModel(ctx.environment, 'hermes', seatModelRequired());
229
- await this.validateEnvironment(ctx.environment);
230
- // Keep Hermes away from the operator's default profile, including any
231
- // Nous Portal/Cloud credentials there. The wrapper provides the sole key.
232
- const seat = `${ctx.agentName || ''}\0${ctx.cwd || ''}`;
233
- const home = ctx._hermesHome || join(profileRoot,
234
- createHash('sha256').update(seat).digest('hex').slice(0, 24));
235
- await mkdir(home, { recursive: true, mode: 0o700 });
236
- const env = { ...(ctx.env || process.env), HERMES_HOME: home };
237
- if (!readVersion(env, ctx._spawnSyncImpl)) {
238
- throw new Error(`Hermes Agent ${SUPPORTED_HERMES_VERSION_RANGE} is not on PATH; install for your OS: https://hermes-agent.nousresearch.com/docs/getting-started/installation`);
239
- }
240
- if (!env.OPENROUTER_API_KEY) {
241
- throw new Error('Supply the operator OPENROUTER_API_KEY through Secret Manager before running Hermes');
242
- }
243
- await syncProfileEnv(home, env);
244
- const cwd = ctx.cwd || process.cwd();
245
- // 0.22.5's gateway rejects --no-restore-cwd; --in pins the workspace on
246
- // both fresh and resumed turns. 0.22.2-0.22.4 are refused above, so no
247
- // version-keyed flag is needed.
248
- const args = ['chat', '--oneshot', '--query-file', '-', '--format', 'stream-json',
249
- '--provider', 'openrouter', '--source', 'tool', '--in', cwd];
250
- if (seatModel) args.push('--model', seatModel);
251
- if (ctx.sessionId) args.push('--resume', ctx.sessionId);
252
- const fullPrompt = memoryPreamble(prompt, ctx.memoryLongTerm, {
253
- freshSession: !ctx.sessionId,
254
- });
255
- const requestedTimeout = Number(ctx.timeoutMs);
256
- const timeoutMs = Number.isFinite(requestedTimeout) && requestedTimeout > 0
257
- ? Math.min(requestedTimeout, DEFAULT_TIMEOUT_MS) : DEFAULT_TIMEOUT_MS;
258
- return runHermes({
259
- args, prompt: fullPrompt, cwd, env, timeoutMs,
260
- spawnImpl: ctx._spawnImpl, onSpawn: ctx.onSpawn, controls: controlsFromArguments(args, { modelFlag: '--model', valueFlags: ['--query-file', '--format', '--provider', '--source', '--in', '--resume'] }),
261
- credentials: spawnCredentials(ctx, ['OPENROUTER_API_KEY']),
262
- });
263
- },
264
- });
@@ -1,24 +0,0 @@
1
- /**
2
- * Stub adapter — the no-op reference implementation of the ADR-005 adapter
3
- * contract. Used by `commonly agent attach stub` and the Phase-1a test
4
- * harness so the run loop can be reviewed end-to-end without a real CLI
5
- * on PATH.
6
- *
7
- * Contract (ADR-005 §Adapter pattern):
8
- * detect(): Promise<{ path, version } | null>
9
- * spawn(prompt, ctx): Promise<{ text, newSessionId?, memorySummary? }>
10
- *
11
- * The adapter MUST be pure: input (argv + env + prompt) → output (text + optional
12
- * next session-id + optional memory summary). No direct network, no direct API
13
- * calls, no hidden state. The run loop handles all Commonly-facing I/O.
14
- */
15
-
16
- export default {
17
- name: 'stub',
18
- async detect() {
19
- return { path: '(builtin)', version: '0.0.0' };
20
- },
21
- async spawn(prompt, _ctx) {
22
- return { text: `(stub) received: ${String(prompt ?? '').slice(0, 200)}` };
23
- },
24
- };
@@ -1,48 +0,0 @@
1
- /**
2
- * The adapter contract (ADR-005 §Adapter pattern). An adapter turns one prompt
3
- * into one CLI run and one reply. It owns argv, env and output parsing for its
4
- * CLI; the caller owns everything that talks to a Commonly instance.
5
- *
6
- * @typedef {object} Adapter
7
- * @property {string} name
8
- * @property {string} [runtimeType]
9
- * @property {string} [providerKeyEnv] host env var the adapter's provider key arrives in
10
- * @property {() => Promise<{ path: string, version: string } | null>} detect
11
- * @property {(environment: object) => Promise<void>} [validateEnvironment] refuse before spawn
12
- * @property {(prompt: string, ctx: object) => Promise<SpawnResult>} spawn
13
- *
14
- * @typedef {object} SpawnResult
15
- * @property {string} text
16
- * @property {string} [newSessionId]
17
- * @property {number} [contextTokens]
18
- * @property {string} [memorySummary]
19
- *
20
- * Adapters that need host policy are built by a factory that takes a SeatHost.
21
- * Every field is optional; an absent field takes the neutral default named.
22
- *
23
- * @typedef {object} SeatHost
24
- * @property {(prompt: string, longTerm: string | null | undefined, opts: { freshSession: boolean }) => string} [memoryPreamble] default: the prompt unchanged
25
- * @property {(trust: string | undefined) => string | undefined} [effectiveTrust] default: the declared trust unchanged
26
- * @property {() => boolean} [seatModelRequired] default: false
27
- */
28
-
29
- /**
30
- * @param {Adapter[]} adapters
31
- */
32
- export const createRegistry = (adapters) => {
33
- const byName = {};
34
- for (const adapter of adapters) {
35
- if (!adapter?.name) throw new Error('every adapter needs a name');
36
- if (byName[adapter.name]) throw new Error(`duplicate adapter name: ${adapter.name}`);
37
- byName[adapter.name] = adapter;
38
- }
39
- return {
40
- adapters: byName,
41
- names: () => Object.keys(byName),
42
- get: (name) => byName[name] || null,
43
- };
44
- };
45
-
46
- export const providerKeyEnvNames = (adapters) => [...new Set(
47
- Object.values(adapters).map((adapter) => adapter.providerKeyEnv).filter(Boolean),
48
- )];
@@ -1,44 +0,0 @@
1
- /**
2
- * Named run failures. Every way a run can end badly has one kind, so a trace,
3
- * a retry policy and a dashboard all read the same word. A kind is a contract:
4
- * add one here, never mint one at a call site.
5
- */
6
- import { scrubAdapterFailure } from './upstream-refusal.js';
7
-
8
- export const FAILURE_KINDS = Object.freeze({
9
- stuck: { retryable: true, meaning: 'no progress signal within the liveness window' },
10
- timeout: { retryable: true, meaning: 'the run exceeded its wall-clock budget' },
11
- exited: { retryable: true, meaning: 'the CLI process ended before the turn settled' },
12
- protocol: { retryable: false, meaning: 'the CLI broke its wire protocol' },
13
- refusal: { retryable: false, meaning: 'the model or provider refused; never retried' },
14
- max_tokens: { retryable: false, meaning: 'the turn hit its token limit' },
15
- max_turn_requests: { retryable: false, meaning: 'the turn hit its request limit' },
16
- cancelled: { retryable: false, meaning: 'the run was cancelled' },
17
- credential_denied: { retryable: false, meaning: 'the run asked for a credential its grant does not allow' },
18
- unsupported: { retryable: false, meaning: 'the CLI or its version is outside what this adapter supports' },
19
- // The harness cannot serve anyone right now. Retrying on the same harness is
20
- // pointless; a run config's fallback moves to its next entry (harness-plan.js).
21
- not_authenticated: { retryable: false, meaning: 'the CLI is not signed in, or its sign-in was rejected' },
22
- quota: { retryable: false, meaning: 'the account behind the CLI is out of quota or credits' },
23
- provider_unsupported: { retryable: false, meaning: 'the provider does not serve this model to this account' },
24
- capacity: { retryable: true, meaning: 'every entry the run config allows is at a host cap or held; it may run once one frees' },
25
- });
26
-
27
- export class RunFailure extends Error {
28
- constructor(kind, detail, { cause } = {}) {
29
- if (!FAILURE_KINDS[kind]) throw new Error(`unknown failure kind: ${kind}`);
30
- super(detail ? `${kind}: ${detail}` : kind, cause ? { cause } : undefined);
31
- this.name = 'RunFailure';
32
- this.kind = kind;
33
- this.retryable = FAILURE_KINDS[kind].retryable;
34
- this.detail = detail || '';
35
- }
36
- }
37
-
38
- /** Build a failure whose detail has known credentials and secret shapes scrubbed. */
39
- export const runFailure = (kind, text, { credentials = [], limit } = {}) => {
40
- const { detail } = scrubAdapterFailure(String(text ?? ''), { credentials, limit });
41
- return new RunFailure(kind, detail);
42
- };
43
-
44
- export const failureKindOf = (error) => (error instanceof RunFailure ? error.kind : null);