@otto-code/cli 0.5.2 → 0.5.4

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.
@@ -21,6 +21,7 @@ export interface AgentRunOptions extends CommandOptions {
21
21
  model?: string;
22
22
  thinking?: string;
23
23
  mode?: string;
24
+ personality?: string;
24
25
  worktree?: string;
25
26
  base?: string;
26
27
  workspace?: string;
@@ -19,6 +19,7 @@ export function addRunOptions(cmd) {
19
19
  .option("--model <model>", "Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)")
20
20
  .option("--thinking <id>", "Thinking option ID to use for this run")
21
21
  .option("--mode <mode>", "Provider-specific mode (e.g., plan, default, bypass)")
22
+ .option("--personality <name>", "Spawn as a host personality (name or id): applies its provider/model/mode and identity/prompt. Explicit --provider/--model/--mode override.")
22
23
  .option("--worktree <name>", "Create agent in a new git worktree")
23
24
  .option("--base <branch>", "Base branch for worktree (default: current branch)")
24
25
  .option("--workspace <id>", "Run in an existing workspace (default: a new workspace is created per run; falls back to $OTTO_WORKSPACE_ID)")
@@ -132,6 +133,50 @@ async function fetchStructuredOutput(caller, prompt, outputSchema) {
132
133
  throw err;
133
134
  }
134
135
  }
136
+ // Resolve --personality (name or id) against the host roster. Returns the
137
+ // personality's brain (provider/model/mode) to seed the run config and its id so
138
+ // the daemon overlays the personality's identity + system prompt (e.g. the
139
+ // orchestrator directive). Explicit --provider/--model/--mode still override.
140
+ async function resolveRunPersonality(client, nameOrId) {
141
+ if (!nameOrId) {
142
+ return undefined;
143
+ }
144
+ const query = nameOrId.trim();
145
+ const { config } = await client.getDaemonConfig();
146
+ const roster = config.agentPersonalities?.personalities ?? [];
147
+ const match = roster.find((p) => p.id === query) ??
148
+ roster.find((p) => p.name.toLowerCase() === query.toLowerCase());
149
+ if (!match) {
150
+ const available = roster.map((p) => p.name).join(", ") || "none configured";
151
+ throw {
152
+ code: "PERSONALITY_NOT_FOUND",
153
+ message: `No personality matches "${query}"`,
154
+ details: `Available personalities: ${available}`,
155
+ };
156
+ }
157
+ return {
158
+ id: match.id,
159
+ provider: match.provider,
160
+ model: match.model,
161
+ ...(match.modeId ? { modeId: match.modeId } : {}),
162
+ };
163
+ }
164
+ // Resolve the agent's brain for a run: a --personality (if any) seeds
165
+ // provider/model/mode + identity; explicit --provider/--model/--mode override.
166
+ // Without a personality, provider stays required (resolveProviderAndModel throws).
167
+ async function resolveRunBrain(client, options) {
168
+ const personality = await resolveRunPersonality(client, options.personality);
169
+ const providerModel = resolveProviderAndModel({
170
+ provider: options.provider,
171
+ model: options.model,
172
+ ...(personality ? { defaultProvider: `${personality.provider}/${personality.model}` } : {}),
173
+ });
174
+ return {
175
+ providerModel,
176
+ modeId: options.mode ?? personality?.modeId,
177
+ personalityId: personality?.id,
178
+ };
179
+ }
135
180
  export async function resolveStructuredResponseMessage(options) {
136
181
  const direct = options.lastMessage?.trim();
137
182
  if (direct) {
@@ -336,10 +381,10 @@ export async function runRunCommand(prompt, options, _command) {
336
381
  const outputSchema = options.outputSchema ? loadOutputSchema(options.outputSchema) : undefined;
337
382
  validateRunOptions(prompt, options, outputSchema);
338
383
  const waitTimeoutMs = parseWaitTimeoutOption(options.waitTimeout);
339
- const resolvedProviderModel = resolveProviderAndModel(options);
340
384
  const resolvedTitle = options.title ?? options.name;
341
385
  const client = await connectToDaemonOrThrow(options.host, host);
342
386
  try {
387
+ const { providerModel: resolvedProviderModel, modeId: resolvedMode, personalityId, } = await resolveRunBrain(client, options);
343
388
  // Resolve working directory
344
389
  const cwd = options.cwd ?? process.cwd();
345
390
  const thinkingOptionId = options.thinking?.trim();
@@ -367,9 +412,10 @@ export async function runRunCommand(prompt, options, _command) {
367
412
  cwd: runCwd,
368
413
  workspaceId,
369
414
  title: resolvedTitle,
370
- modeId: options.mode,
415
+ modeId: resolvedMode,
371
416
  model: resolvedProviderModel.model,
372
417
  thinkingOptionId,
418
+ personality: personalityId,
373
419
  initialPrompt: structuredPrompt,
374
420
  outputSchema,
375
421
  images,
@@ -421,9 +467,10 @@ export async function runRunCommand(prompt, options, _command) {
421
467
  cwd: runCwd,
422
468
  workspaceId,
423
469
  title: resolvedTitle,
424
- modeId: options.mode,
470
+ modeId: resolvedMode,
425
471
  model: resolvedProviderModel.model,
426
472
  thinkingOptionId,
473
+ personality: personalityId,
427
474
  initialPrompt: prompt,
428
475
  images,
429
476
  env: requestEnv,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-code/cli",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Otto CLI - control your AI coding agents from the command line",
5
5
  "bin": {
6
6
  "otto": "bin/otto"
@@ -27,9 +27,9 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@clack/prompts": "^1.0.0",
30
- "@otto-code/client": "0.5.2",
31
- "@otto-code/protocol": "0.5.2",
32
- "@otto-code/server": "0.5.2",
30
+ "@otto-code/client": "0.5.4",
31
+ "@otto-code/protocol": "0.5.4",
32
+ "@otto-code/server": "0.5.4",
33
33
  "chalk": "^5.3.0",
34
34
  "commander": "^12.0.0",
35
35
  "mime-types": "^2.1.35",