@commonlyai/cli 0.1.163 → 0.1.164

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonlyai/cli",
3
- "version": "0.1.163",
3
+ "version": "0.1.164",
4
4
  "license": "Apache-2.0",
5
5
  "description": "The Commonly CLI — connect agents, manage pods, iterate fast",
6
6
  "type": "module",
@@ -17,7 +17,6 @@ import { homedir, tmpdir } from 'os';
17
17
  import { fileURLToPath } from 'url';
18
18
  import { createHash } from 'crypto';
19
19
 
20
- import { requireSeatModel } from '../lib/adapters/seat-model.js';
21
20
  import { createClient } from '../lib/api.js';
22
21
  import { copyHandoffMemory } from '../lib/handoff-memory.js';
23
22
  import {
@@ -1254,7 +1253,6 @@ export const performRun = ({
1254
1253
  const effectiveTurnTimeoutMs = Number.isFinite(requestedTurnTimeout) && requestedTurnTimeout > 0
1255
1254
  ? Math.min(requestedTurnTimeout, 2_147_483_647) : 15 * 60 * 1000;
1256
1255
  const client = createClient({ instance: instanceUrl, token });
1257
- const missingModelNotices = new Set();
1258
1256
  const handoffAgent = sanitizeHandoffAgent(refusalHandoff);
1259
1257
  if (refusalHandoff && !handoffAgent) {
1260
1258
  log(`--refusal-handoff ignored: '${String(refusalHandoff).slice(0, 64)}' is not an agent handle`);
@@ -1679,30 +1677,6 @@ export const performRun = ({
1679
1677
  ? `${recycleBriefing}\n\n${promptWithSkills}`
1680
1678
  : promptWithSkills;
1681
1679
 
1682
- if (adapter.requiresModel) {
1683
- try {
1684
- requireSeatModel(seatEnvironment, adapter.name);
1685
- } catch (error) {
1686
- if (error.code === 'seat_model_missing' && eventPodId && !missingModelNotices.has(eventPodId)) {
1687
- try {
1688
- const delivery = await deliverChatReply({
1689
- client,
1690
- podId: eventPodId,
1691
- text: "This agent has no model set; add environment.model to its configuration.",
1692
- limit: chatCharLimit,
1693
- maxChunks: maxChatChunks,
1694
- log,
1695
- });
1696
- if (!delivery.skipped && !delivery.refused) missingModelNotices.add(eventPodId);
1697
- } catch (noticeError) {
1698
- log(`missing model notice could not be posted: ${noticeError.message}`);
1699
- }
1700
- }
1701
- // Configuration failure is retryable: never turn a notice into an ack.
1702
- throw error;
1703
- }
1704
- }
1705
-
1706
1680
  log(`[${event.type}] spawning ${adapter.name}`);
1707
1681
  // TASK-102 part B. The CHILD gets a scoped credential; the wrapper keeps
1708
1682
  // the seat token for its own polling, claiming and posting (`client` was
@@ -43,7 +43,6 @@
43
43
  * SIGKILL escalation is a post-v1 concern (ADR-005 §Spawning semantics).
44
44
  */
45
45
 
46
- import { requireSeatModel } from './seat-model.js';
47
46
  import { spawn as childSpawn, spawnSync } from 'child_process';
48
47
  import { createHash, randomUUID } from 'crypto';
49
48
  import { accessSync, constants, realpathSync } from 'fs';
@@ -726,7 +725,6 @@ const prepareArgv = async (innerArgv, ctx) => {
726
725
  };
727
726
 
728
727
  export default {
729
- requiresModel: true,
730
728
  name: 'claude',
731
729
  // Identity-bearing runtime tag written into AgentInstallation.config.runtime
732
730
  // by `commonly agent attach`. The CLI command stays `commonly agent attach
@@ -761,7 +759,6 @@ export default {
761
759
  },
762
760
 
763
761
  async spawn(prompt, rawCtx = {}) {
764
- const seatModel = requireSeatModel(rawCtx.environment, 'claude');
765
762
  // `sandbox.trust: 'internal'` is refused for new declarations and read as
766
763
  // `public` for a record that already carries it; such a seat is confined
767
764
  // where it can be and refuses to derive where it cannot (Wren 69585).
@@ -812,7 +809,7 @@ export default {
812
809
  // session-recovery retry, or a retry runs at a different effort than the
813
810
  // turn it replaces.
814
811
  const modelArgs = [
815
- '--model', seatModel,
812
+ ...(ctx.environment?.model ? ['--model', String(ctx.environment.model)] : []),
816
813
  ...(ctx.environment?.effort ? ['--effort', String(ctx.environment.effort)] : []),
817
814
  ];
818
815
  const baseArgs = ['-p', fullPrompt, '--output-format', 'text', sessionFlag, sessionId, ...modelArgs];
@@ -37,7 +37,6 @@
37
37
  * SIGKILL escalation is a post-v1 concern (ADR-005 §Spawning semantics).
38
38
  */
39
39
 
40
- import { requireSeatModel } from './seat-model.js';
41
40
  import { spawn as childSpawn, spawnSync } from 'child_process';
42
41
  import { createHash } from 'crypto';
43
42
  import { accessSync, constants } from 'fs';
@@ -617,7 +616,6 @@ const runCodex = ({ args, cwd, env, timeoutMs, credentials = [], spawnImpl = chi
617
616
  });
618
617
 
619
618
  export default {
620
- requiresModel: true,
621
619
  name: 'codex',
622
620
  // See claude.js for the rationale — identity-bearing runtime tag persisted
623
621
  // to AgentInstallation.config.runtime (paired with host:'byo') so a CLI-
@@ -644,7 +642,6 @@ export default {
644
642
  },
645
643
 
646
644
  async spawn(prompt, ctx = {}) {
647
- const seatModel = requireSeatModel(ctx.environment, 'codex');
648
645
  // Passed through UNCOALESCED. `ctx.memoryLongTerm || ''` was here, and
649
646
  // `null || ''` is `''` — which routed the unreadable case straight into
650
647
  // the empty-memory branch and made the whole distinction unreachable from
@@ -701,7 +698,7 @@ export default {
701
698
  mcpFlags: mcp.flags,
702
699
  mcpReadDirectories: mcp.mcpReadDirectories,
703
700
  publicSandboxMode,
704
- model: seatModel,
701
+ model: ctx.environment?.model,
705
702
  effort: ctx.environment?.effort,
706
703
  commitAttributionEnv: ctx.commitAttributionEnv,
707
704
  });
@@ -1,5 +1,4 @@
1
1
  /** DeepSeek Harness 0.2.1-rc.2, private seats only. Configuration is per spawn. */
2
- import { requireSeatModel } from './seat-model.js';
3
2
  import { spawn as childSpawn, spawnSync } from 'child_process';
4
3
  import { createHash } from 'crypto';
5
4
  import { existsSync } from 'fs';
@@ -219,7 +218,6 @@ export const runDsh = ({ binary, args, cwd, env, timeoutMs, credentials, spawnIm
219
218
  });
220
219
 
221
220
  export default {
222
- requiresModel: true,
223
221
  name: 'dsh', runtimeType: 'dsh', supportsProvider: true,
224
222
 
225
223
  async validateEnvironment(environment, workspacePath) {
@@ -248,7 +246,6 @@ export default {
248
246
  },
249
247
 
250
248
  async spawn(prompt, ctx = {}) {
251
- const seatModel = requireSeatModel(ctx.environment, 'dsh');
252
249
  assertPrivateDsh(ctx.environment);
253
250
  if (!ctx.environment?.provider || !ctx.environment?.model) {
254
251
  throw new Error('dsh requires environment.provider and environment.model');
@@ -278,7 +275,7 @@ export default {
278
275
  credentialFile: credential.path, instanceUrl: ctx.instanceUrl,
279
276
  });
280
277
  const patch = JSON.stringify(buildPatch({
281
- proxyBaseURL: proxy.baseURL, model: seatModel,
278
+ proxyBaseURL: proxy.baseURL, model: ctx.environment.model,
282
279
  cwd: ctx.cwd, mcp, effort: ctx.environment.effort,
283
280
  deepseekOfficial: new URL(ctx.environment.provider.baseURL).hostname === 'api.deepseek.com',
284
281
  }), null, 2);
@@ -1,5 +1,4 @@
1
1
  /** Goose 1.54.0 wrapper. Public seats wait for TASK-236's deny-by-default proof. */
2
- import { requireSeatModel } from './seat-model.js';
3
2
  import { spawn as childSpawn, spawnSync } from 'node:child_process';
4
3
  import { mkdtemp, readFile, rm } from 'node:fs/promises';
5
4
  import { tmpdir } from 'node:os';
@@ -17,6 +16,7 @@ import { adapterFailure, spawnCredentials } from '../upstream-refusal.js';
17
16
  export const TESTED_GOOSE_VERSIONS = Object.freeze(['1.54.0']);
18
17
  const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
19
18
  const TERMINATION_GRACE_MS = 5000;
19
+ const DEFAULT_MODEL = 'deepseek-v4-flash';
20
20
  const DEFAULT_PROVIDER_HOST = 'https://litellm.commonly.me';
21
21
  const DEFAULT_PROVIDER_KEY = 'COMMONLY_LITELLM_KEY';
22
22
  const PLACEHOLDER_RE = /\$\{(COMMONLY_[A-Z_]+)\}/g;
@@ -174,7 +174,6 @@ const runGoose = ({ binary, args, cwd, env, timeoutMs, credentials, spawnImpl =
174
174
  });
175
175
 
176
176
  export default {
177
- requiresModel: true,
178
177
  name: 'goose',
179
178
  providerKeyEnv: DEFAULT_PROVIDER_KEY,
180
179
  supportsProvider: true,
@@ -194,7 +193,6 @@ export default {
194
193
  },
195
194
 
196
195
  async spawn(prompt, ctx = {}) {
197
- const seatModel = requireSeatModel(ctx.environment, 'goose');
198
196
  const keyFile = await this.validateEnvironment(ctx.environment, ctx.cwd);
199
197
  const sourceEnv = ctx.env || process.env;
200
198
  const configured = ctx.environment?.provider;
@@ -205,7 +203,7 @@ export default {
205
203
  if (!/^https?:$/.test(baseUrl.protocol) || baseUrl.username || baseUrl.password || baseUrl.search || baseUrl.hash) {
206
204
  throw new Error('goose adapter: provider.baseURL must be a plain HTTP(S) URL');
207
205
  }
208
- const model = seatModel;
206
+ const model = ctx.environment?.model || DEFAULT_MODEL;
209
207
  const binary = ctx._binaryPath || 'goose';
210
208
  const version = ctx._version || versionOf(spawnSync(binary, ['--version'], { encoding: 'utf8', timeout: 5000 }).stdout);
211
209
  if (!TESTED_GOOSE_VERSIONS.includes(version)) {
@@ -1,5 +1,4 @@
1
1
  /** Hermes 0.22.2 local CLI wrapper. Hermes owns provider I/O; this file only spawns it. */
2
- import { requireSeatModel } from './seat-model.js';
3
2
  import { spawn as childSpawn, spawnSync } from 'child_process';
4
3
  import { createHash } from 'crypto';
5
4
  import { mkdir } from 'fs/promises';
@@ -138,7 +137,6 @@ const runHermes = ({ args, prompt, cwd, env, timeoutMs, spawnImpl, credentials }
138
137
  });
139
138
 
140
139
  export default {
141
- requiresModel: true,
142
140
  name: 'hermes',
143
141
  runtimeType: 'hermes',
144
142
  supportsProvider: false,
@@ -163,7 +161,6 @@ export default {
163
161
  },
164
162
 
165
163
  async spawn(prompt, ctx = {}) {
166
- const seatModel = requireSeatModel(ctx.environment, 'hermes');
167
164
  await this.validateEnvironment(ctx.environment);
168
165
  // Keep Hermes away from the operator's default profile, including any
169
166
  // Nous Portal/Cloud credentials there. The wrapper provides the sole key.
@@ -180,7 +177,7 @@ export default {
180
177
  }
181
178
  const args = ['chat', '--oneshot', '--query-file', '-', '--format', 'stream-json',
182
179
  '--provider', 'openrouter', '--source', 'tool', '--no-restore-cwd'];
183
- args.push('--model', seatModel);
180
+ if (ctx.environment?.model) args.push('--model', ctx.environment.model);
184
181
  if (ctx.sessionId) args.push('--resume', ctx.sessionId);
185
182
  const fullPrompt = buildMemoryPreamble(prompt, ctx.memoryLongTerm, {
186
183
  freshSession: !ctx.sessionId,
@@ -19,7 +19,6 @@
19
19
  * `text.part.text`, and token counts in `step_finish.part.tokens`.
20
20
  */
21
21
 
22
- import { requireSeatModel } from './seat-model.js';
23
22
  import { spawn as childSpawn, spawnSync } from 'child_process';
24
23
  import { createHash } from 'crypto';
25
24
  import { realpathSync } from 'fs';
@@ -623,7 +622,6 @@ const describeOpenCodeVersionMismatch = (installedVersion) => {
623
622
  };
624
623
 
625
624
  export default {
626
- requiresModel: true,
627
625
  name: 'opencode',
628
626
  runtimeType: 'opencode',
629
627
  supportsProvider: true,
@@ -647,7 +645,6 @@ export default {
647
645
  },
648
646
 
649
647
  async spawn(prompt, rawCtx = {}) {
650
- const seatModel = requireSeatModel(rawCtx.environment, 'opencode');
651
648
  const sandbox = normalizeSandboxTrust(rawCtx.environment?.sandbox);
652
649
  const ctx = rawCtx.environment
653
650
  ? { ...rawCtx, environment: { ...rawCtx.environment, sandbox } }
@@ -808,7 +805,7 @@ export default {
808
805
  prompt: fullPrompt,
809
806
  sessionId: ctx.sessionId,
810
807
  cwd: ctx.cwd,
811
- model: qualifiedProviderModel(provider, seatModel),
808
+ model: qualifiedProviderModel(provider, ctx.environment?.model),
812
809
  effort: ctx.environment?.effort,
813
810
  title: ctx.agentName,
814
811
  });
@@ -32,7 +32,6 @@
32
32
  * Contract (see stub.js): detect() and spawn(prompt, ctx) → { text, newSessionId }.
33
33
  */
34
34
 
35
- import { requireSeatModel } from './seat-model.js';
36
35
  import { spawn as childSpawn, spawnSync } from 'child_process';
37
36
  import { createHash, randomUUID } from 'crypto';
38
37
  import { mkdir, readdir, writeFile } from 'fs/promises';
@@ -66,6 +65,7 @@ export const DEFAULT_PROVIDER = Object.freeze({
66
65
  api: 'openai-completions',
67
66
  apiKeyEnv: 'COMMONLY_LITELLM_KEY',
68
67
  });
68
+ export const DEFAULT_MODEL = 'deepseek-v4-flash';
69
69
 
70
70
  // ADR-008 `effort` → pi `--thinking`. pi's ladder is off/minimal/low/medium/high/xhigh/max.
71
71
  const THINKING = { none: 'off', off: 'off', minimal: 'minimal', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' };
@@ -390,7 +390,6 @@ const runPi = ({ args, cwd, env, payload, timeoutMs, credentials = [], spawnImpl
390
390
  });
391
391
 
392
392
  export default {
393
- requiresModel: true,
394
393
  name: 'pi',
395
394
 
396
395
  // TASK-049: the variable this adapter needs from the environment of whatever
@@ -410,13 +409,12 @@ export default {
410
409
  },
411
410
 
412
411
  async spawn(prompt, ctx = {}) {
413
- const seatModel = requireSeatModel(ctx.environment, 'pi');
414
412
  // pi has no enforced sandbox. claude.js and codex.js refuse a public-trust
415
413
  // seat they cannot confine; so does this adapter, and it refuses any declared
416
414
  // sandbox mode rather than run unconfined under a spec that promised one.
417
415
  assertNoSandboxDeclared(ctx.environment);
418
416
  const provider = resolveProvider(ctx.environment);
419
- const model = seatModel;
417
+ const model = ctx.environment?.model || DEFAULT_MODEL;
420
418
  const thinking = thinkingFor(ctx.environment?.effort);
421
419
  const baseEnv = ctx.env || process.env;
422
420
  if (!baseEnv[provider.apiKeyEnv]) {
@@ -1,5 +1,4 @@
1
1
  /** Qwen Code 0.25.1 wrapper. Public turns have fresh HOME, config and keys. */
2
- import { requireSeatModel } from './seat-model.js';
3
2
  import { spawn as childSpawn, spawnSync } from 'child_process';
4
3
  import { lstatSync, realpathSync } from 'fs';
5
4
  import { chmod, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
@@ -209,7 +208,6 @@ const runQwen = ({ cmd, args, cwd, env, timeoutMs, spawnImpl, credentials }) =>
209
208
  });
210
209
 
211
210
  export default {
212
- requiresModel: true,
213
211
  name: 'qwen',
214
212
  runtimeType: 'qwen',
215
213
  supportsProvider: true,
@@ -232,7 +230,6 @@ export default {
232
230
  },
233
231
 
234
232
  async spawn(prompt, ctx = {}) {
235
- const seatModel = requireSeatModel(ctx.environment, 'qwen');
236
233
  const sandbox = normalizeSandboxTrust(ctx.environment?.sandbox);
237
234
  const isPublic = sandbox?.trust === 'public';
238
235
  const mode = isPublic ? resolvePublicSandboxMode(sandbox) : null;
@@ -307,7 +304,7 @@ export default {
307
304
  freshSession: true,
308
305
  });
309
306
  const args = [
310
- '--bare', '--safe-mode', '--auth-type', 'openai', '-m', seatModel,
307
+ '--bare', '--safe-mode', '--auth-type', 'openai', '-m', ctx.environment.model,
311
308
  '--mcp-config', mcpPath, '--exclude-tools', [
312
309
  ...EXCLUDED_TOOLS, ...(isPublic ? PUBLIC_READ_TOOLS : []),
313
310
  ].join(','),
@@ -1,12 +0,0 @@
1
- /** A seat must choose its model independently of the operator's CLI defaults. */
2
- export const requireSeatModel = (environment, adapterName) => {
3
- const model = environment?.model;
4
- if (typeof model !== 'string' || !model.trim()) {
5
- const error = new Error(
6
- `${adapterName} requires environment.model; set the seat model with commonly agent config <name> --model <model> before running`,
7
- );
8
- error.code = 'seat_model_missing';
9
- throw error;
10
- }
11
- return model.trim();
12
- };