@jmanuelcorral/openteam 0.10.0 → 0.11.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.
package/AGENTS.md CHANGED
@@ -7,7 +7,7 @@ openteam is an opencode plugin built with **TypeScript + Bun** with **local-firs
7
7
  - Tests: `bun test`
8
8
  - Typecheck: `bun run typecheck`
9
9
  - Lint+format: `biome check .`
10
- - Required coverage: global lines >= 85% and branches >= 80%; `src/router/**` at 100%.
10
+ - Required coverage: global lines/functions >= 85%; `scripts/check-coverage.mjs` keeps `TARGET_PREFIXES` at 100% and `src/local/**` / `src/telemetry/**` at >= 90%; Bun lcov does not emit branch/statement records.
11
11
  - Determinism: run the specific router test when it exists (`bun test tests/router/determinism.test.ts` or an equivalent selector).
12
12
 
13
13
  ## Architecture rules
package/README.es.md CHANGED
@@ -473,7 +473,9 @@ openteam report --telemetry .opencode/openteam-local/telemetry.jsonl
473
473
  openteam yolo status
474
474
  openteam yolo on
475
475
  openteam local status
476
+ openteam local only
476
477
  openteam local off
478
+ openteam local on
477
479
  openteam clear-cache
478
480
  openteam clear-cache --delete
479
481
  ```
@@ -518,17 +520,18 @@ También puedes activarlo durante `openteam setup` (te lo pregunta), o al vuelo
518
520
 
519
521
  > **YOLO no desactiva la privacidad de openteam.** Solo afecta a las aprobaciones de permisos de opencode; con `privacyMode: "forceLocalOnSensitive"`, los prompts sensibles siguen sin salir a frontier. Úsalo solo en entornos de confianza: auto-aprueba también `bash`, escrituras y accesos fuera del workspace (salvo reglas `deny` explícitas).
520
522
 
521
- ### Solo frontier (sin runtime local): `openteam local`
523
+ ### Modo de routing: `openteam local`
522
524
 
523
- Si **no tienes ningún runtime local** (Ollama/LM Studio/Foundry Local) o prefieres no usarlo, puedes forzar que openteam enrute **siempre a modelos frontier**. `openteam setup` ya activa este modo automáticamente cuando no habilitas ningún runtime, pero puedes alternarlo en cualquier momento sin repetir el setup:
525
+ Usa `openteam local` para alternar entre los tres modos globales de routing sin repetir el setup:
524
526
 
525
527
  ```powershell
526
- openteam local status # ¿local-first o solo frontier? + runtimes configurados
528
+ openteam local status # ¿local-first, solo local o solo frontier? + runtimes configurados
527
529
  openteam local off # solo frontier (desactiva el routing local-first)
530
+ openteam local only # solo local (nunca escala a frontier)
528
531
  openteam local on # vuelve al routing local-first
529
532
  ```
530
533
 
531
- Esto persiste el flag `router.frontierOnly` en `.opencode/openteam.json`. Con `frontierOnly` activo, el router escoge el **frontier cheapest-capable** en lugar de la heurística local-first, pero **respeta la privacidad, los presupuestos y los overrides explícitos por tarea**: los prompts sensibles con `forceLocalOnSensitive` no salen a frontier, y `local off` degrada esa política a `consentBeforeFrontier` (imposible forzar local sin runtime) informándote del cambio.
534
+ `local off` persiste `router.frontierOnly=true`: el router escoge el **frontier cheapest-capable**, pero respeta privacidad, presupuestos y overrides explícitos por tarea. Los prompts sensibles con `forceLocalOnSensitive` no salen a frontier; `local off` degrada esa política a `consentBeforeFrontier` (imposible forzar local sin runtime) e informa del cambio. `local only` persiste `router.localOnly=true` y limpia `frontierOnly`; se niega a escribir la config salvo que haya al menos un runtime local habilitado.
532
535
 
533
536
  ### Actualizar el plugin y limpiar la caché: `openteam clear-cache`
534
537
 
@@ -819,7 +822,7 @@ Consulta [docs/compatibility.md](docs/compatibility.md). Resumen verificado el `
819
822
 
820
823
  | Superficie | Versión / contrato |
821
824
  | --- | --- |
822
- | openteam | `0.10.0`; versión actual del paquete |
825
+ | openteam | `0.11.0`; versión actual del paquete |
823
826
  | `@opencode-ai/plugin` | `1.18.19` |
824
827
  | `@opencode-ai/sdk` | `1.18.19` |
825
828
  | Hook de routing | `chat.message`; no `chat.params` para cambiar modelo |
package/README.md CHANGED
@@ -424,6 +424,9 @@ openteam console
424
424
  openteam report --telemetry .opencode/openteam-local/telemetry.jsonl
425
425
  openteam yolo status
426
426
  openteam local status
427
+ openteam local only
428
+ openteam local off
429
+ openteam local on
427
430
  openteam clear-cache
428
431
  openteam clear-cache --delete
429
432
  ```
@@ -448,17 +451,25 @@ openteam yolo off # disable YOLO
448
451
 
449
452
  > **YOLO does not disable openteam privacy.** It only affects opencode permission approvals; with `privacyMode: "forceLocalOnSensitive"`, sensitive prompts still never leave for frontier. Use it only in trusted environments.
450
453
 
451
- ### Frontier-only (no local runtime): `openteam local`
454
+ ### Routing mode: `openteam local`
452
455
 
453
- If you have **no local runtime** or prefer not to use one, you can force openteam to route **always to frontier models**:
456
+ Use `openteam local` to switch between the three global routing modes without
457
+ re-running setup:
454
458
 
455
459
  ```powershell
456
- openteam local status # local-first or frontier-only? + configured runtimes
460
+ openteam local status # local-first, local-only, or frontier-only? + configured runtimes
457
461
  openteam local off # frontier-only (disable local-first routing)
462
+ openteam local only # local-only (never escalate to frontier)
458
463
  openteam local on # back to local-first routing
459
464
  ```
460
465
 
461
- This persists the `router.frontierOnly` flag in `.opencode/openteam.json`. With `frontierOnly` active the router picks the **cheapest-capable frontier**, but still **respects privacy, budgets and explicit per-task overrides**. Sensitive prompts with `forceLocalOnSensitive` don't leave for frontier; `local off` degrades that policy to `consentBeforeFrontier` (local can't be forced without a runtime) and tells you about the change.
466
+ `local off` persists `router.frontierOnly=true`: the router picks the
467
+ **cheapest-capable frontier**, but still respects privacy, budgets and explicit
468
+ per-task overrides. Sensitive prompts with `forceLocalOnSensitive` don't leave
469
+ for frontier; `local off` degrades that policy to `consentBeforeFrontier` (local
470
+ can't be forced without a runtime) and tells you about the change. `local only`
471
+ persists `router.localOnly=true` and clears `frontierOnly`; it refuses to write
472
+ the config unless at least one local runtime is enabled.
462
473
 
463
474
  ### Updating the plugin and clearing the cache: `openteam clear-cache`
464
475
 
@@ -700,7 +711,7 @@ See [docs/compatibility.md](docs/compatibility.md). Verified summary as of `2026
700
711
 
701
712
  | Surface | Version / contract |
702
713
  | --- | --- |
703
- | openteam | `0.10.0`; current package version |
714
+ | openteam | `0.11.0`; current package version |
704
715
  | `@opencode-ai/plugin` | `1.18.19` |
705
716
  | `@opencode-ai/sdk` | `1.18.19` |
706
717
  | Routing hook | `chat.message`; not `chat.params` for model changes |
package/dist/cli.js CHANGED
@@ -9939,6 +9939,123 @@ function isGateApplicable(mode) {
9939
9939
  return mode === "active";
9940
9940
  }
9941
9941
 
9942
+ // src/messages/commands.ts
9943
+ var clearCacheMessages = {
9944
+ header: "openteam clear-cache — frozen plugin cache entries:",
9945
+ columns: {
9946
+ specDir: "spec dir",
9947
+ pinned: "spec-pinned",
9948
+ installed: "installed",
9949
+ mtime: "mtime"
9950
+ },
9951
+ reparseSkipSuffix: " [SKIP — reparse point]",
9952
+ deletedLabel: "deleted.",
9953
+ lockedLabel: (message) => `[LOCKED] ${message}`,
9954
+ pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
9955
+ processed: (count) => `${count} entry(ies) processed.`,
9956
+ found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
9957
+ };
9958
+ var baselineMessages = {
9959
+ effectiveAuto: "cheapest-capable (auto)",
9960
+ pinnedSuffix: (ref) => `${ref} (pinned)`,
9961
+ summary: (params) => [
9962
+ "openteam baseline:",
9963
+ ` mode: ${params.mode}`,
9964
+ ` pinned: ${params.pinned}`,
9965
+ ` hardDefault: ${params.hardDefault}`,
9966
+ ` effective: ${params.effective}`
9967
+ ],
9968
+ invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
9969
+ pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
9970
+ autoMode: "Baseline set to auto mode (cheapest-capable)."
9971
+ };
9972
+ var localMessages = {
9973
+ help: {
9974
+ status: " openteam local status Show the routing mode (local-first / local-only / frontier-only)",
9975
+ off: " openteam local off Use frontier models only (no local runtime)",
9976
+ only: " openteam local only Use local models only (never frontier)",
9977
+ on: " openteam local on Re-enable local-first routing"
9978
+ },
9979
+ noRuntimes: "none",
9980
+ modeFrontierOnly: "frontier-only (frontierOnly)",
9981
+ modeLocalOnly: "local-only (localOnly)",
9982
+ modeLocalFirst: "local-first",
9983
+ summary: (params) => [
9984
+ "openteam local:",
9985
+ ` mode: ${params.mode}`,
9986
+ ` frontierOnly: ${params.frontierOnly}`,
9987
+ ` localOnly: ${params.localOnly}`,
9988
+ ` privacy: ${params.privacy}`,
9989
+ ` runtimes: ${params.runtimes}`
9990
+ ],
9991
+ frontierOnlyNoChange: "No change: already in frontier-only mode.",
9992
+ privacyAdjustedNote: " Privacy adjusted to 'consentBeforeFrontier' (forceLocalOnSensitive requires a local runtime).",
9993
+ frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true, localOnly=false).",
9994
+ localOnlyNoRuntimes: "Cannot enable local-only mode: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.",
9995
+ localOnlyNoChange: "No change: already in local-only mode.",
9996
+ localOnlyEnabled: "Local-only mode enabled (localOnly=true, frontierOnly=false).",
9997
+ localFirstNoChange: "No change: local-first routing is already active.",
9998
+ localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false, localOnly=false). Make sure a local runtime is reachable.",
9999
+ unknownSubcommand: (subcommand, help) => `Unknown local subcommand: ${subcommand}
10000
+
10001
+ ${help}`
10002
+ };
10003
+ var frontierCatalogMessages = {
10004
+ free: "free",
10005
+ costPerMillion: (inputUSD, outputUSD) => `$${inputUSD}/$${outputUSD} per 1M`
10006
+ };
10007
+ var migrateMessages = {
10008
+ header: "openteam migrate:",
10009
+ nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
10010
+ counts: (params) => [
10011
+ ` moved: ${params.moved} file(s)`,
10012
+ ` deduped: ${params.deduped} file(s) (destination already identical)`,
10013
+ ` conflicts: ${params.conflicts} file(s)`
10014
+ ],
10015
+ relocatedHeader: " relocated:",
10016
+ relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
10017
+ conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
10018
+ conflictEntry: (from, to) => ` · ${from} → ${to}`,
10019
+ manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
10020
+ manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
10021
+ success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
10022
+ };
10023
+ var rolesInitMessages = {
10024
+ header: "openteam roles init:",
10025
+ title: "openteam roles init",
10026
+ noRoster: (path) => ` ✗ no roster at ${path}.`,
10027
+ noRosterRemedy: " Cast the team first: run `openteam setup`, then ask the orchestrator to register the cast.",
10028
+ unparseableRoster: (path, error) => ` ✗ ${path} is present but unparseable: ${error}`,
10029
+ unparseableRosterRemedy: " Run `openteam doctor` for the remedy, then re-run this command.",
10030
+ allProfiled: (count) => ` ✓ ${count} roster role(s) checked; no unprofiled roles — every role resolves a routing profile.`,
10031
+ whyTitle: "Why you are being asked",
10032
+ why: (count) => [
10033
+ `${count} roster role(s) resolve no routing profile.`,
10034
+ "Until a profile exists they are frontier-eligible: their work can escalate",
10035
+ "to a frontier model. A 'local only' note in the roster prose does not",
10036
+ "prevent this — prose outside the JSON fence is never read."
10037
+ ].join(`
10038
+ `),
10039
+ policyQuestion: (roleID, agentName) => `Routing policy for "${roleID}" (${agentName})`,
10040
+ localOnlyLabel: (roleID, agentName) => `Local only — ${roleID} (${agentName}) never leaves this machine`,
10041
+ localOnlyHint: "sets requiresLocalRuntime; the role fails closed when no local runtime is reachable",
10042
+ frontierOkLabel: "Local first, frontier allowed",
10043
+ frontierOkHint: "records today's implicit behaviour: cheapest-capable frontier when the task warrants it",
10044
+ skipLabel: "Skip for now",
10045
+ skipHint: "leaves the role unprofiled, so it stays frontier-eligible and doctor keeps reporting it",
10046
+ runtimeQuestion: (roleID) => `Preferred local runtime(s) for "${roleID}" (in failover order)`,
10047
+ runtimeHint: "machine-local — written to the git-ignored overlay",
10048
+ cancelled: (reason) => ` ✗ cancelled (${reason}); nothing was written.`,
10049
+ invalidResult: (reason) => ` ✗ refusing to write: the resulting config is invalid — ${reason}`,
10050
+ nothingWritten: (skipped) => ` · skipped ${skipped}; nothing written.`,
10051
+ nothingToWriteOutro: "Nothing to write.",
10052
+ pinnedLocal: (roleIDs, path) => ` ✓ pinned local-only: ${roleIDs} → ${path} (tracked, travels with the roster)`,
10053
+ frontierAllowed: (roleIDs, path) => ` ✓ frontier allowed: ${roleIDs} → ${path} (model choice stays "auto": cheapest-capable per task)`,
10054
+ runtimeBinding: (path) => ` ✓ runtime binding: ${path} (git-ignored, machine-local)`,
10055
+ skippedSummary: (roleIDs) => ` · skipped: ${roleIDs} — still frontier-eligible; re-run this command to revisit.`,
10056
+ outro: "Role policy updated."
10057
+ };
10058
+
9942
10059
  // src/orchestrator/ralphLoop.ts
9943
10060
  var RALPH_ROLE_ID = "ralph";
9944
10061
  var DEFAULT_RALPH_MAX_ITERATIONS = 10;
@@ -10293,109 +10410,6 @@ function describeOtelBackendForDoctor(config, env) {
10293
10410
  };
10294
10411
  }
10295
10412
 
10296
- // src/messages/commands.ts
10297
- var clearCacheMessages = {
10298
- header: "openteam clear-cache — frozen plugin cache entries:",
10299
- columns: {
10300
- specDir: "spec dir",
10301
- pinned: "spec-pinned",
10302
- installed: "installed",
10303
- mtime: "mtime"
10304
- },
10305
- reparseSkipSuffix: " [SKIP — reparse point]",
10306
- deletedLabel: "deleted.",
10307
- lockedLabel: (message) => `[LOCKED] ${message}`,
10308
- pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
10309
- processed: (count) => `${count} entry(ies) processed.`,
10310
- found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
10311
- };
10312
- var baselineMessages = {
10313
- effectiveAuto: "cheapest-capable (auto)",
10314
- pinnedSuffix: (ref) => `${ref} (pinned)`,
10315
- summary: (params) => [
10316
- "openteam baseline:",
10317
- ` mode: ${params.mode}`,
10318
- ` pinned: ${params.pinned}`,
10319
- ` hardDefault: ${params.hardDefault}`,
10320
- ` effective: ${params.effective}`
10321
- ],
10322
- invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
10323
- pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
10324
- autoMode: "Baseline set to auto mode (cheapest-capable)."
10325
- };
10326
- var localMessages = {
10327
- noRuntimes: "none",
10328
- modeFrontierOnly: "frontier-only (frontierOnly)",
10329
- modeLocalFirst: "local-first",
10330
- summary: (params) => [
10331
- "openteam local:",
10332
- ` mode: ${params.mode}`,
10333
- ` frontierOnly: ${params.frontierOnly}`,
10334
- ` privacy: ${params.privacy}`,
10335
- ` runtimes: ${params.runtimes}`
10336
- ],
10337
- frontierOnlyNoChange: "No change: already in frontier-only mode.",
10338
- privacyAdjustedNote: " Privacy adjusted to 'consentBeforeFrontier' (forceLocalOnSensitive requires a local runtime).",
10339
- frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true).",
10340
- localFirstNoChange: "No change: local-first routing is already active.",
10341
- localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false). Make sure a local runtime is reachable."
10342
- };
10343
- var frontierCatalogMessages = {
10344
- free: "free",
10345
- costPerMillion: (inputUSD, outputUSD) => `$${inputUSD}/$${outputUSD} per 1M`
10346
- };
10347
- var migrateMessages = {
10348
- header: "openteam migrate:",
10349
- nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
10350
- counts: (params) => [
10351
- ` moved: ${params.moved} file(s)`,
10352
- ` deduped: ${params.deduped} file(s) (destination already identical)`,
10353
- ` conflicts: ${params.conflicts} file(s)`
10354
- ],
10355
- relocatedHeader: " relocated:",
10356
- relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
10357
- conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
10358
- conflictEntry: (from, to) => ` · ${from} → ${to}`,
10359
- manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
10360
- manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
10361
- success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
10362
- };
10363
- var rolesInitMessages = {
10364
- header: "openteam roles init:",
10365
- title: "openteam roles init",
10366
- noRoster: (path) => ` ✗ no roster at ${path}.`,
10367
- noRosterRemedy: " Cast the team first: run `openteam setup`, then ask the orchestrator to register the cast.",
10368
- unparseableRoster: (path, error) => ` ✗ ${path} is present but unparseable: ${error}`,
10369
- unparseableRosterRemedy: " Run `openteam doctor` for the remedy, then re-run this command.",
10370
- allProfiled: (count) => ` ✓ ${count} roster role(s) checked; no unprofiled roles — every role resolves a routing profile.`,
10371
- whyTitle: "Why you are being asked",
10372
- why: (count) => [
10373
- `${count} roster role(s) resolve no routing profile.`,
10374
- "Until a profile exists they are frontier-eligible: their work can escalate",
10375
- "to a frontier model. A 'local only' note in the roster prose does not",
10376
- "prevent this — prose outside the JSON fence is never read."
10377
- ].join(`
10378
- `),
10379
- policyQuestion: (roleID, agentName) => `Routing policy for "${roleID}" (${agentName})`,
10380
- localOnlyLabel: (roleID, agentName) => `Local only — ${roleID} (${agentName}) never leaves this machine`,
10381
- localOnlyHint: "sets requiresLocalRuntime; the role fails closed when no local runtime is reachable",
10382
- frontierOkLabel: "Local first, frontier allowed",
10383
- frontierOkHint: "records today's implicit behaviour: cheapest-capable frontier when the task warrants it",
10384
- skipLabel: "Skip for now",
10385
- skipHint: "leaves the role unprofiled, so it stays frontier-eligible and doctor keeps reporting it",
10386
- runtimeQuestion: (roleID) => `Preferred local runtime(s) for "${roleID}" (in failover order)`,
10387
- runtimeHint: "machine-local — written to the git-ignored overlay",
10388
- cancelled: (reason) => ` ✗ cancelled (${reason}); nothing was written.`,
10389
- invalidResult: (reason) => ` ✗ refusing to write: the resulting config is invalid — ${reason}`,
10390
- nothingWritten: (skipped) => ` · skipped ${skipped}; nothing written.`,
10391
- nothingToWriteOutro: "Nothing to write.",
10392
- pinnedLocal: (roleIDs, path) => ` ✓ pinned local-only: ${roleIDs} → ${path} (tracked, travels with the roster)`,
10393
- frontierAllowed: (roleIDs, path) => ` ✓ frontier allowed: ${roleIDs} → ${path} (model choice stays "auto": cheapest-capable per task)`,
10394
- runtimeBinding: (path) => ` ✓ runtime binding: ${path} (git-ignored, machine-local)`,
10395
- skippedSummary: (roleIDs) => ` · skipped: ${roleIDs} — still frontier-eligible; re-run this command to revisit.`,
10396
- outro: "Role policy updated."
10397
- };
10398
-
10399
10413
  // src/commands/baseline.ts
10400
10414
  function formatRef(ref) {
10401
10415
  return ref === null ? "—" : `${ref.providerID}/${ref.modelID}`;
@@ -10897,6 +10911,9 @@ function renderWorktreeReconciliation(report) {
10897
10911
  }
10898
10912
 
10899
10913
  // src/commands/local.ts
10914
+ function hasEnabledLocalRuntime(config) {
10915
+ return config.local.runtimes.some((runtime) => runtime.enabled);
10916
+ }
10900
10917
  function enabledRuntimesSummary(config) {
10901
10918
  const enabled = config.local.runtimes.filter((runtime) => runtime.enabled);
10902
10919
  if (enabled.length === 0) {
@@ -10909,10 +10926,11 @@ function enabledRuntimesSummary(config) {
10909
10926
  }).join(", ");
10910
10927
  }
10911
10928
  function showLocal(config) {
10912
- const mode = config.router.frontierOnly ? localMessages.modeFrontierOnly : localMessages.modeLocalFirst;
10929
+ const mode = config.router.localOnly ? localMessages.modeLocalOnly : config.router.frontierOnly ? localMessages.modeFrontierOnly : localMessages.modeLocalFirst;
10913
10930
  const lines = localMessages.summary({
10914
10931
  mode,
10915
10932
  frontierOnly: config.router.frontierOnly,
10933
+ localOnly: config.router.localOnly,
10916
10934
  privacy: config.privacyMode,
10917
10935
  runtimes: enabledRuntimesSummary(config)
10918
10936
  });
@@ -10920,13 +10938,13 @@ function showLocal(config) {
10920
10938
  `) };
10921
10939
  }
10922
10940
  function setFrontierOnly(config) {
10923
- if (config.router.frontierOnly) {
10941
+ if (config.router.frontierOnly && !config.router.localOnly) {
10924
10942
  return { message: localMessages.frontierOnlyNoChange };
10925
10943
  }
10926
10944
  const flipsPrivacy = config.privacyMode === "forceLocalOnSensitive";
10927
10945
  const next = {
10928
10946
  ...config,
10929
- router: { ...config.router, frontierOnly: true },
10947
+ router: { ...config.router, frontierOnly: true, localOnly: false },
10930
10948
  privacyMode: flipsPrivacy ? "consentBeforeFrontier" : config.privacyMode
10931
10949
  };
10932
10950
  const privacyNote = flipsPrivacy ? localMessages.privacyAdjustedNote : "";
@@ -10935,13 +10953,29 @@ function setFrontierOnly(config) {
10935
10953
  message: `${localMessages.frontierOnlyEnabled}${privacyNote}`
10936
10954
  };
10937
10955
  }
10956
+ function setLocalOnly(config) {
10957
+ if (!hasEnabledLocalRuntime(config)) {
10958
+ return { message: localMessages.localOnlyNoRuntimes };
10959
+ }
10960
+ if (config.router.localOnly && !config.router.frontierOnly) {
10961
+ return { message: localMessages.localOnlyNoChange };
10962
+ }
10963
+ const next = {
10964
+ ...config,
10965
+ router: { ...config.router, frontierOnly: false, localOnly: true }
10966
+ };
10967
+ return {
10968
+ config: next,
10969
+ message: localMessages.localOnlyEnabled
10970
+ };
10971
+ }
10938
10972
  function setLocalFirst(config) {
10939
- if (!config.router.frontierOnly) {
10973
+ if (!config.router.frontierOnly && !config.router.localOnly) {
10940
10974
  return { message: localMessages.localFirstNoChange };
10941
10975
  }
10942
10976
  const next = {
10943
10977
  ...config,
10944
- router: { ...config.router, frontierOnly: false }
10978
+ router: { ...config.router, frontierOnly: false, localOnly: false }
10945
10979
  };
10946
10980
  return {
10947
10981
  config: next,
@@ -12406,9 +12440,10 @@ var HELP = [
12406
12440
  " openteam baseline show Show the effective baseline",
12407
12441
  " openteam baseline set <p/model> Pin the baseline (pinned mode)",
12408
12442
  " openteam baseline auto Cheapest-capable baseline (auto mode)",
12409
- " openteam local status Show the routing mode (local-first / frontier-only)",
12410
- " openteam local off Use frontier models only (no local runtime)",
12411
- " openteam local on Re-enable local-first routing",
12443
+ localMessages.help.status,
12444
+ localMessages.help.off,
12445
+ localMessages.help.only,
12446
+ localMessages.help.on,
12412
12447
  " openteam doctor Diagnose runtimes and config",
12413
12448
  " openteam roles init Compose per-role routing policy for unprofiled roster roles",
12414
12449
  " openteam migrate Relocate pre-P15b artifacts to their split homes (idempotent)",
@@ -12579,23 +12614,40 @@ ${HELP}`
12579
12614
  }
12580
12615
  async function runLocal(positionals, deps, configPath, configResolution) {
12581
12616
  const sub = positionals[1] ?? "status";
12582
- if (sub !== "status" && sub !== "off" && sub !== "on") {
12617
+ if (sub !== "status" && sub !== "off" && sub !== "only" && sub !== "on") {
12583
12618
  return {
12584
12619
  exitCode: 1,
12585
- stdout: `Unknown local subcommand: ${sub}
12586
-
12587
- ${HELP}`
12620
+ stdout: localMessages.unknownSubcommand(sub, HELP)
12588
12621
  };
12589
12622
  }
12590
12623
  const config = await deps.loadConfig(configPath, configResolution);
12591
12624
  if (sub === "status") {
12592
12625
  return { exitCode: 0, stdout: showLocal(config).message };
12593
12626
  }
12594
- const outcome = sub === "off" ? setFrontierOnly(config) : setLocalFirst(config);
12627
+ let outcome;
12628
+ switch (sub) {
12629
+ case "off":
12630
+ outcome = setFrontierOnly(config);
12631
+ break;
12632
+ case "only":
12633
+ outcome = setLocalOnly(config);
12634
+ break;
12635
+ case "on":
12636
+ outcome = setLocalFirst(config);
12637
+ break;
12638
+ default:
12639
+ return {
12640
+ exitCode: 1,
12641
+ stdout: localMessages.unknownSubcommand(sub, HELP)
12642
+ };
12643
+ }
12595
12644
  if (outcome.config !== undefined) {
12596
12645
  await deps.saveConfig(outcome.config, configPath, configResolution);
12597
12646
  }
12598
- return { exitCode: 0, stdout: outcome.message };
12647
+ return {
12648
+ exitCode: sub === "only" && !hasEnabledLocalRuntime(config) ? 1 : 0,
12649
+ stdout: outcome.message
12650
+ };
12599
12651
  }
12600
12652
  async function runYolo(positionals, deps, opencodeConfigPaths) {
12601
12653
  const sub = positionals[1] ?? "status";
@@ -15263,7 +15315,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
15263
15315
  // package.json
15264
15316
  var package_default = {
15265
15317
  name: "@jmanuelcorral/openteam",
15266
- version: "0.10.0",
15318
+ version: "0.11.0",
15267
15319
  packageManager: "bun@1.3.14",
15268
15320
  description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
15269
15321
  license: "MIT",
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/commands/dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/commands/dispatch.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,19 @@
1
1
  import type { OpenTeamConfig } from "../config/schema";
2
2
  import type { CommandOutcome } from "./types";
3
+ /**
4
+ * `openteam local <status|off|only|on>` commands: toggle global routing modes.
5
+ *
6
+ * - `off` enables `router.frontierOnly`: the team routes only to frontier models
7
+ * (useful when no local runtime is installed or reachable).
8
+ * - `only` enables `router.localOnly`: the team never escalates to frontier.
9
+ * - `on` disables both flags: normal local-first routing.
10
+ *
11
+ * Pure and deterministic: they take the config and return a new config (when it
12
+ * changes) plus a message. Persistence is the caller's responsibility.
13
+ */
14
+ export declare function hasEnabledLocalRuntime(config: OpenTeamConfig): boolean;
3
15
  export declare function showLocal(config: OpenTeamConfig): CommandOutcome;
4
16
  export declare function setFrontierOnly(config: OpenTeamConfig): CommandOutcome;
17
+ export declare function setLocalOnly(config: OpenTeamConfig): CommandOutcome;
5
18
  export declare function setLocalFirst(config: OpenTeamConfig): CommandOutcome;
6
19
  //# sourceMappingURL=local.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/commands/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAkC9C,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAYhE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAoBtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAcpE"}
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/commands/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;;;;;;;;;GAUG;AAEH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAEtE;AAuBD,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAehE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAoBtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAkBnE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAcpE"}
package/dist/index.js CHANGED
@@ -7177,6 +7177,84 @@ function activityEventFrom(event, now) {
7177
7177
  // src/plugin/commandTool.ts
7178
7178
  import { tool } from "@opencode-ai/plugin";
7179
7179
 
7180
+ // src/messages/commands.ts
7181
+ var clearCacheMessages = {
7182
+ header: "openteam clear-cache — frozen plugin cache entries:",
7183
+ columns: {
7184
+ specDir: "spec dir",
7185
+ pinned: "spec-pinned",
7186
+ installed: "installed",
7187
+ mtime: "mtime"
7188
+ },
7189
+ reparseSkipSuffix: " [SKIP — reparse point]",
7190
+ deletedLabel: "deleted.",
7191
+ lockedLabel: (message) => `[LOCKED] ${message}`,
7192
+ pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
7193
+ processed: (count) => `${count} entry(ies) processed.`,
7194
+ found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
7195
+ };
7196
+ var baselineMessages = {
7197
+ effectiveAuto: "cheapest-capable (auto)",
7198
+ pinnedSuffix: (ref) => `${ref} (pinned)`,
7199
+ summary: (params) => [
7200
+ "openteam baseline:",
7201
+ ` mode: ${params.mode}`,
7202
+ ` pinned: ${params.pinned}`,
7203
+ ` hardDefault: ${params.hardDefault}`,
7204
+ ` effective: ${params.effective}`
7205
+ ],
7206
+ invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
7207
+ pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
7208
+ autoMode: "Baseline set to auto mode (cheapest-capable)."
7209
+ };
7210
+ var localMessages = {
7211
+ help: {
7212
+ status: " openteam local status Show the routing mode (local-first / local-only / frontier-only)",
7213
+ off: " openteam local off Use frontier models only (no local runtime)",
7214
+ only: " openteam local only Use local models only (never frontier)",
7215
+ on: " openteam local on Re-enable local-first routing"
7216
+ },
7217
+ noRuntimes: "none",
7218
+ modeFrontierOnly: "frontier-only (frontierOnly)",
7219
+ modeLocalOnly: "local-only (localOnly)",
7220
+ modeLocalFirst: "local-first",
7221
+ summary: (params) => [
7222
+ "openteam local:",
7223
+ ` mode: ${params.mode}`,
7224
+ ` frontierOnly: ${params.frontierOnly}`,
7225
+ ` localOnly: ${params.localOnly}`,
7226
+ ` privacy: ${params.privacy}`,
7227
+ ` runtimes: ${params.runtimes}`
7228
+ ],
7229
+ frontierOnlyNoChange: "No change: already in frontier-only mode.",
7230
+ privacyAdjustedNote: " Privacy adjusted to 'consentBeforeFrontier' (forceLocalOnSensitive requires a local runtime).",
7231
+ frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true, localOnly=false).",
7232
+ localOnlyNoRuntimes: "Cannot enable local-only mode: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.",
7233
+ localOnlyNoChange: "No change: already in local-only mode.",
7234
+ localOnlyEnabled: "Local-only mode enabled (localOnly=true, frontierOnly=false).",
7235
+ localFirstNoChange: "No change: local-first routing is already active.",
7236
+ localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false, localOnly=false). Make sure a local runtime is reachable.",
7237
+ unknownSubcommand: (subcommand, help) => `Unknown local subcommand: ${subcommand}
7238
+
7239
+ ${help}`
7240
+ };
7241
+ var migrateMessages = {
7242
+ header: "openteam migrate:",
7243
+ nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
7244
+ counts: (params) => [
7245
+ ` moved: ${params.moved} file(s)`,
7246
+ ` deduped: ${params.deduped} file(s) (destination already identical)`,
7247
+ ` conflicts: ${params.conflicts} file(s)`
7248
+ ],
7249
+ relocatedHeader: " relocated:",
7250
+ relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
7251
+ conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
7252
+ conflictEntry: (from, to) => ` · ${from} → ${to}`,
7253
+ manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
7254
+ manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
7255
+ success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
7256
+ };
7257
+
7180
7258
  // src/orchestrator/worktreeReconciler.ts
7181
7259
  function planOne(wt) {
7182
7260
  const base = { runID: wt.runID, path: wt.path };
@@ -7730,70 +7808,6 @@ function diagnoseAgentModels(files, context) {
7730
7808
  });
7731
7809
  }
7732
7810
 
7733
- // src/messages/commands.ts
7734
- var clearCacheMessages = {
7735
- header: "openteam clear-cache — frozen plugin cache entries:",
7736
- columns: {
7737
- specDir: "spec dir",
7738
- pinned: "spec-pinned",
7739
- installed: "installed",
7740
- mtime: "mtime"
7741
- },
7742
- reparseSkipSuffix: " [SKIP — reparse point]",
7743
- deletedLabel: "deleted.",
7744
- lockedLabel: (message) => `[LOCKED] ${message}`,
7745
- pathOutsideWarning: (specDir, absolutePath) => ` ⚠ ${specDir}: path outside cacheRoot (${absolutePath}), skipped.`,
7746
- processed: (count) => `${count} entry(ies) processed.`,
7747
- found: (count) => `${count} entry(ies) found. Use --delete to remove them.`
7748
- };
7749
- var baselineMessages = {
7750
- effectiveAuto: "cheapest-capable (auto)",
7751
- pinnedSuffix: (ref) => `${ref} (pinned)`,
7752
- summary: (params) => [
7753
- "openteam baseline:",
7754
- ` mode: ${params.mode}`,
7755
- ` pinned: ${params.pinned}`,
7756
- ` hardDefault: ${params.hardDefault}`,
7757
- ` effective: ${params.effective}`
7758
- ],
7759
- invalidModel: (input) => `Invalid model "${input}". Use the provider/model format, e.g. anthropic/claude-sonnet-4-5.`,
7760
- pinnedTo: (ref) => `Baseline pinned to ${ref} (pinned mode).`,
7761
- autoMode: "Baseline set to auto mode (cheapest-capable)."
7762
- };
7763
- var localMessages = {
7764
- noRuntimes: "none",
7765
- modeFrontierOnly: "frontier-only (frontierOnly)",
7766
- modeLocalFirst: "local-first",
7767
- summary: (params) => [
7768
- "openteam local:",
7769
- ` mode: ${params.mode}`,
7770
- ` frontierOnly: ${params.frontierOnly}`,
7771
- ` privacy: ${params.privacy}`,
7772
- ` runtimes: ${params.runtimes}`
7773
- ],
7774
- frontierOnlyNoChange: "No change: already in frontier-only mode.",
7775
- privacyAdjustedNote: " Privacy adjusted to 'consentBeforeFrontier' (forceLocalOnSensitive requires a local runtime).",
7776
- frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true).",
7777
- localFirstNoChange: "No change: local-first routing is already active.",
7778
- localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false). Make sure a local runtime is reachable."
7779
- };
7780
- var migrateMessages = {
7781
- header: "openteam migrate:",
7782
- nothingToMigrate: " nothing to migrate — the P15b layout is already in place.",
7783
- counts: (params) => [
7784
- ` moved: ${params.moved} file(s)`,
7785
- ` deduped: ${params.deduped} file(s) (destination already identical)`,
7786
- ` conflicts: ${params.conflicts} file(s)`
7787
- ],
7788
- relocatedHeader: " relocated:",
7789
- relocatedEntry: (from, to, deduped) => ` · ${from} → ${to}${deduped ? " (deduped)" : ""}`,
7790
- conflictsHeader: " ⚠ left in place (destination exists with different content — no data lost):",
7791
- conflictEntry: (from, to) => ` · ${from} → ${to}`,
7792
- manualWorktreesHeader: " ⚠ legacy git worktree(s) need a manual move (run `git worktree move`):",
7793
- manualWorktreeEntry: (label, from, to) => ` · ${label}: ${from} → ${to}`,
7794
- success: " ✓ machine-local runtime output relocated under .opencode/openteam-local/."
7795
- };
7796
-
7797
7811
  // src/commands/baseline.ts
7798
7812
  function formatRef(ref) {
7799
7813
  return ref === null ? "—" : `${ref.providerID}/${ref.modelID}`;
@@ -8310,6 +8324,9 @@ function renderWorktreeReconciliation(report) {
8310
8324
  }
8311
8325
 
8312
8326
  // src/commands/local.ts
8327
+ function hasEnabledLocalRuntime(config) {
8328
+ return config.local.runtimes.some((runtime) => runtime.enabled);
8329
+ }
8313
8330
  function enabledRuntimesSummary(config) {
8314
8331
  const enabled = config.local.runtimes.filter((runtime) => runtime.enabled);
8315
8332
  if (enabled.length === 0) {
@@ -8322,10 +8339,11 @@ function enabledRuntimesSummary(config) {
8322
8339
  }).join(", ");
8323
8340
  }
8324
8341
  function showLocal(config) {
8325
- const mode = config.router.frontierOnly ? localMessages.modeFrontierOnly : localMessages.modeLocalFirst;
8342
+ const mode = config.router.localOnly ? localMessages.modeLocalOnly : config.router.frontierOnly ? localMessages.modeFrontierOnly : localMessages.modeLocalFirst;
8326
8343
  const lines = localMessages.summary({
8327
8344
  mode,
8328
8345
  frontierOnly: config.router.frontierOnly,
8346
+ localOnly: config.router.localOnly,
8329
8347
  privacy: config.privacyMode,
8330
8348
  runtimes: enabledRuntimesSummary(config)
8331
8349
  });
@@ -8333,13 +8351,13 @@ function showLocal(config) {
8333
8351
  `) };
8334
8352
  }
8335
8353
  function setFrontierOnly(config) {
8336
- if (config.router.frontierOnly) {
8354
+ if (config.router.frontierOnly && !config.router.localOnly) {
8337
8355
  return { message: localMessages.frontierOnlyNoChange };
8338
8356
  }
8339
8357
  const flipsPrivacy = config.privacyMode === "forceLocalOnSensitive";
8340
8358
  const next = {
8341
8359
  ...config,
8342
- router: { ...config.router, frontierOnly: true },
8360
+ router: { ...config.router, frontierOnly: true, localOnly: false },
8343
8361
  privacyMode: flipsPrivacy ? "consentBeforeFrontier" : config.privacyMode
8344
8362
  };
8345
8363
  const privacyNote = flipsPrivacy ? localMessages.privacyAdjustedNote : "";
@@ -8348,13 +8366,29 @@ function setFrontierOnly(config) {
8348
8366
  message: `${localMessages.frontierOnlyEnabled}${privacyNote}`
8349
8367
  };
8350
8368
  }
8369
+ function setLocalOnly(config) {
8370
+ if (!hasEnabledLocalRuntime(config)) {
8371
+ return { message: localMessages.localOnlyNoRuntimes };
8372
+ }
8373
+ if (config.router.localOnly && !config.router.frontierOnly) {
8374
+ return { message: localMessages.localOnlyNoChange };
8375
+ }
8376
+ const next = {
8377
+ ...config,
8378
+ router: { ...config.router, frontierOnly: false, localOnly: true }
8379
+ };
8380
+ return {
8381
+ config: next,
8382
+ message: localMessages.localOnlyEnabled
8383
+ };
8384
+ }
8351
8385
  function setLocalFirst(config) {
8352
- if (!config.router.frontierOnly) {
8386
+ if (!config.router.frontierOnly && !config.router.localOnly) {
8353
8387
  return { message: localMessages.localFirstNoChange };
8354
8388
  }
8355
8389
  const next = {
8356
8390
  ...config,
8357
- router: { ...config.router, frontierOnly: false }
8391
+ router: { ...config.router, frontierOnly: false, localOnly: false }
8358
8392
  };
8359
8393
  return {
8360
8394
  config: next,
@@ -9195,9 +9229,10 @@ var HELP = [
9195
9229
  " openteam baseline show Show the effective baseline",
9196
9230
  " openteam baseline set <p/model> Pin the baseline (pinned mode)",
9197
9231
  " openteam baseline auto Cheapest-capable baseline (auto mode)",
9198
- " openteam local status Show the routing mode (local-first / frontier-only)",
9199
- " openteam local off Use frontier models only (no local runtime)",
9200
- " openteam local on Re-enable local-first routing",
9232
+ localMessages.help.status,
9233
+ localMessages.help.off,
9234
+ localMessages.help.only,
9235
+ localMessages.help.on,
9201
9236
  " openteam doctor Diagnose runtimes and config",
9202
9237
  " openteam roles init Compose per-role routing policy for unprofiled roster roles",
9203
9238
  " openteam migrate Relocate pre-P15b artifacts to their split homes (idempotent)",
@@ -9368,23 +9403,40 @@ ${HELP}`
9368
9403
  }
9369
9404
  async function runLocal(positionals, deps, configPath, configResolution) {
9370
9405
  const sub = positionals[1] ?? "status";
9371
- if (sub !== "status" && sub !== "off" && sub !== "on") {
9406
+ if (sub !== "status" && sub !== "off" && sub !== "only" && sub !== "on") {
9372
9407
  return {
9373
9408
  exitCode: 1,
9374
- stdout: `Unknown local subcommand: ${sub}
9375
-
9376
- ${HELP}`
9409
+ stdout: localMessages.unknownSubcommand(sub, HELP)
9377
9410
  };
9378
9411
  }
9379
9412
  const config = await deps.loadConfig(configPath, configResolution);
9380
9413
  if (sub === "status") {
9381
9414
  return { exitCode: 0, stdout: showLocal(config).message };
9382
9415
  }
9383
- const outcome = sub === "off" ? setFrontierOnly(config) : setLocalFirst(config);
9416
+ let outcome;
9417
+ switch (sub) {
9418
+ case "off":
9419
+ outcome = setFrontierOnly(config);
9420
+ break;
9421
+ case "only":
9422
+ outcome = setLocalOnly(config);
9423
+ break;
9424
+ case "on":
9425
+ outcome = setLocalFirst(config);
9426
+ break;
9427
+ default:
9428
+ return {
9429
+ exitCode: 1,
9430
+ stdout: localMessages.unknownSubcommand(sub, HELP)
9431
+ };
9432
+ }
9384
9433
  if (outcome.config !== undefined) {
9385
9434
  await deps.saveConfig(outcome.config, configPath, configResolution);
9386
9435
  }
9387
- return { exitCode: 0, stdout: outcome.message };
9436
+ return {
9437
+ exitCode: sub === "only" && !hasEnabledLocalRuntime(config) ? 1 : 0,
9438
+ stdout: outcome.message
9439
+ };
9388
9440
  }
9389
9441
  async function runYolo(positionals, deps, opencodeConfigPaths) {
9390
9442
  const sub = positionals[1] ?? "status";
@@ -12970,7 +13022,7 @@ var createOtlpSpanExporter = (connection, config) => {
12970
13022
  // package.json
12971
13023
  var package_default = {
12972
13024
  name: "@jmanuelcorral/openteam",
12973
- version: "0.10.0",
13025
+ version: "0.11.0",
12974
13026
  packageManager: "bun@1.3.14",
12975
13027
  description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
12976
13028
  license: "MIT",
@@ -44,20 +44,32 @@ export declare const baselineMessages: {
44
44
  };
45
45
  /** Messages for `openteam local`. */
46
46
  export declare const localMessages: {
47
+ readonly help: {
48
+ readonly status: " openteam local status Show the routing mode (local-first / local-only / frontier-only)";
49
+ readonly off: " openteam local off Use frontier models only (no local runtime)";
50
+ readonly only: " openteam local only Use local models only (never frontier)";
51
+ readonly on: " openteam local on Re-enable local-first routing";
52
+ };
47
53
  readonly noRuntimes: "none";
48
54
  readonly modeFrontierOnly: "frontier-only (frontierOnly)";
55
+ readonly modeLocalOnly: "local-only (localOnly)";
49
56
  readonly modeLocalFirst: "local-first";
50
57
  readonly summary: (params: {
51
58
  mode: string;
52
59
  frontierOnly: boolean;
60
+ localOnly: boolean;
53
61
  privacy: string;
54
62
  runtimes: string;
55
63
  }) => string[];
56
64
  readonly frontierOnlyNoChange: "No change: already in frontier-only mode.";
57
65
  readonly privacyAdjustedNote: " Privacy adjusted to 'consentBeforeFrontier' (forceLocalOnSensitive requires a local runtime).";
58
- readonly frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true).";
66
+ readonly frontierOnlyEnabled: "Frontier-only mode enabled (frontierOnly=true, localOnly=false).";
67
+ readonly localOnlyNoRuntimes: "Cannot enable local-only mode: no enabled local runtime is configured. Run 'openteam setup' or enable a local runtime in .opencode/openteam.json first.";
68
+ readonly localOnlyNoChange: "No change: already in local-only mode.";
69
+ readonly localOnlyEnabled: "Local-only mode enabled (localOnly=true, frontierOnly=false).";
59
70
  readonly localFirstNoChange: "No change: local-first routing is already active.";
60
- readonly localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false). Make sure a local runtime is reachable.";
71
+ readonly localFirstReEnabled: "Local-first routing re-enabled (frontierOnly=false, localOnly=false). Make sure a local runtime is reachable.";
72
+ readonly unknownSubcommand: (subcommand: string, help: string) => string;
61
73
  };
62
74
  /** Messages for the frontier catalog rendered during `init`. */
63
75
  export declare const frontierCatalogMessages: {
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/messages/commands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/messages/commands.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmanuelcorral/openteam",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "packageManager": "bun@1.3.14",
5
5
  "description": "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
6
6
  "license": "MIT",