@litfamily/litopencode 1.0.4 → 1.0.5

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 (72) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README-Ko-KR.md +146 -115
  3. package/README.md +144 -116
  4. package/dist/activation-workflow-prompts.js +1 -1
  5. package/dist/agents/registry.js +30 -26
  6. package/dist/cli/args.js +3 -3
  7. package/dist/cli/host-limits.d.ts +1 -1
  8. package/dist/cli/host-limits.js +3 -2
  9. package/dist/cli/install-config.js +2 -2
  10. package/dist/cli/install-report.js +2 -1
  11. package/dist/cli/managed-skill-assets.d.ts +1 -1
  12. package/dist/cli/managed-skill-assets.js +3 -1
  13. package/dist/cli/model-catalog.d.ts +56 -0
  14. package/dist/cli/model-catalog.js +78 -17
  15. package/dist/cli/model-policy.js +7 -6
  16. package/dist/cli/types.d.ts +1 -1
  17. package/dist/cli.js +8 -7
  18. package/dist/config-parser.js +3 -2
  19. package/dist/config.d.ts +1 -1
  20. package/dist/config.js +13 -12
  21. package/dist/features.d.ts +17 -1
  22. package/dist/features.js +10 -0
  23. package/dist/model-route-policy.d.ts +1 -1
  24. package/dist/model-route-policy.js +24 -7
  25. package/dist/skills.d.ts +8 -1
  26. package/dist/skills.js +8 -0
  27. package/dist/uiux-visual-catalog.js +5 -5
  28. package/docs/assets/cover-motion-still.webp +0 -0
  29. package/docs/assets/cover-motion.webp +0 -0
  30. package/docs/assets/readme/JetBrainsMono-OFL.txt +93 -0
  31. package/docs/assets/readme/Lucide-LICENSE.txt +43 -0
  32. package/docs/assets/readme/ascii-readme.svg +5 -0
  33. package/docs/assets/readme/badge-version.svg +1 -1
  34. package/docs/assets/readme/ignition-film.mp4 +0 -0
  35. package/docs/assets/readme/ignition-readme.gif +0 -0
  36. package/docs/assets/readme/litfamily-machines.png +0 -0
  37. package/docs/assets/readme/lucide-book-open.svg +14 -0
  38. package/docs/assets/readme/lucide-play.svg +13 -0
  39. package/docs/assets/readme/lucide-shield-check.svg +14 -0
  40. package/docs/assets/readme/poster.png +0 -0
  41. package/docs/migration.md +2 -2
  42. package/docs/reference-Ko-KR.md +21 -4
  43. package/docs/reference.md +30 -10
  44. package/package.json +1 -1
  45. package/skills/frontend-ui-ux/SKILL.md +25 -31
  46. package/skills/frontend-ui-ux/references/complete-contract.md +12 -12
  47. package/skills/frontend-ui-ux/references/default-editorial-pixel.json +19 -0
  48. package/skills/frontend-ui-ux/references/production.md +15 -0
  49. package/skills/managed-skill-manifest.json +92 -1
  50. package/skills/readme-studio/SKILL.md +76 -0
  51. package/skills/readme-studio/references/decoration-patterns.md +105 -0
  52. package/skills/readme-studio/references/motion.md +38 -0
  53. package/skills/readme-studio/references/production.md +13 -0
  54. package/skills/readme-studio/references/typography.md +16 -0
  55. package/skills/readme-studio/scripts/check-facts.mjs +28 -0
  56. package/skills/readme-studio/templates/cover-source.json +1 -0
  57. package/skills/readme-studio/templates/facts.json +1 -0
  58. package/skills/readme-studio/templates/hyperframes/index.html +62 -0
  59. package/skills/readme-studio/templates/hyperframes/index.motion.json +1 -0
  60. package/skills/readme-studio/templates/hyperframes/package-lock.json +1966 -0
  61. package/skills/readme-studio/templates/hyperframes/package.json +1 -0
  62. package/skills/readme-studio/templates/readme-cover-section.md +53 -0
  63. package/skills/readme-studio/templates/remotion/package-lock.json +3783 -0
  64. package/skills/readme-studio/templates/remotion/package.json +1 -0
  65. package/skills/readme-studio/templates/remotion/src/index.tsx +32 -0
  66. package/skills/readme-studio/templates/typography/files.mjs +46 -0
  67. package/skills/readme-studio/templates/typography/outline.mjs +47 -0
  68. package/skills/readme-studio/templates/typography/package-lock.json +133 -0
  69. package/skills/readme-studio/templates/typography/package.json +1 -0
  70. package/tools/check-pack-payload.mjs +34 -2
  71. package/tools/payload-substance-parity.json +4 -3
  72. package/tools/version-manifests.json +10 -4
@@ -13,6 +13,62 @@ export type ProviderMenuRow = {
13
13
  readonly credentialEnv: string;
14
14
  };
15
15
  export declare const providerMenu: readonly ProviderMenuRow[];
16
+ export declare const installModelEfforts: readonly ["low", "medium", "high", "xhigh", "max", "ultra"];
17
+ export declare const nativeReasoningEfforts: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
18
+ export declare const defaultOpenAiRoutes: Readonly<{
19
+ lead: Readonly<{
20
+ provider: "openai";
21
+ model: "gpt-6-astra";
22
+ effort: "xhigh";
23
+ }>;
24
+ helper: Readonly<{
25
+ provider: "openai";
26
+ model: "gpt-6-luna";
27
+ effort: "max";
28
+ }>;
29
+ }>;
30
+ export declare const newGenerationOpenAiModels: Readonly<{
31
+ readonly astra: "gpt-6-astra";
32
+ readonly sol: "gpt-6-sol";
33
+ readonly luna: "gpt-6-luna";
34
+ }>;
35
+ export declare const previousGenerationOpenAiModels: Readonly<{
36
+ readonly sol: "gpt-5.6-sol";
37
+ readonly terra: "gpt-5.6-terra";
38
+ readonly luna: "gpt-5.6-luna";
39
+ readonly family: "gpt-5.6";
40
+ }>;
41
+ export declare const legacyManagedModelIds: readonly ["gpt-5.4", "gpt-5.5"];
42
+ export declare const legacyFastAliasModels: readonly ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.6"];
43
+ export declare const hostLimitModelIds: readonly ["gpt-6-luna", "gpt-5.6-luna"];
44
+ export declare const openaiRows: readonly ModelMenuRow[];
45
+ export declare const openaiProviderModels: Readonly<{
46
+ "gpt-6-astra": Readonly<{
47
+ name: "GPT-6 Astra";
48
+ reasoning: true;
49
+ temperature: false;
50
+ tool_call: true;
51
+ }>;
52
+ "gpt-6-sol": Readonly<{
53
+ name: "GPT-6 Sol";
54
+ reasoning: true;
55
+ temperature: false;
56
+ tool_call: true;
57
+ }>;
58
+ "gpt-6-luna": Readonly<{
59
+ name: "GPT-6 Luna";
60
+ reasoning: true;
61
+ temperature: false;
62
+ tool_call: true;
63
+ }>;
64
+ }>;
65
+ export declare function openAiModelRow(model: string): ModelMenuRow | undefined;
66
+ export declare function openAiModelEfforts(model: string): readonly InstallModelEffort[];
67
+ export declare function isInstallModelEffort(value: string): value is InstallModelEffort;
68
+ export declare function openaiModelHelpLine(): string;
69
+ export declare function shippedDefaultsSummary(): string;
70
+ export declare function legacyFastAliasHelp(): string;
71
+ export declare function modelEffortHelp(): string;
16
72
  export declare function hostCatalogPath(): string;
17
73
  export declare function modelMenuRows(provider: ModelProvider): readonly ModelMenuRow[];
18
74
  export declare function isModelProvider(value: string): value is ModelProvider;
@@ -3,20 +3,77 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { isRecord } from "./json.js";
5
5
  export const providerMenu = [
6
- { provider: "openai", label: "OpenAI GPT-6 Astra / GPT-5.6 family", credentialEnv: "OPENAI_API_KEY" },
6
+ { provider: "openai", label: "OpenAI GPT-6 family / GPT-5.6 previous generation", credentialEnv: "OPENAI_API_KEY" },
7
7
  { provider: "xai", label: "xAI Grok", credentialEnv: "XAI_API_KEY" }
8
8
  ];
9
- const effortRank = ["low", "medium", "high", "xhigh", "max"];
10
- // The OpenAI rows are the product policy, not the host catalog. Astra is
11
- // reasoning-only: all five host-supported effort names are carried through
12
- // the native `variant`/`reasoningEffort` fields.
13
- const openaiRows = [
14
- { provider: "openai", model: "gpt-6-astra", effort: "xhigh", efforts: ["low", "medium", "high", "xhigh", "max"], hint: "frontier reasoning (recommended lead)" },
15
- { provider: "openai", model: "gpt-5.6-sol", effort: "xhigh", efforts: ["high", "xhigh", "max"], hint: "deepest reasoning, slowest (legacy lead)" },
16
- { provider: "openai", model: "gpt-5.6-luna", effort: "max", efforts: ["high", "max"], hint: "balanced (recommended helper)" },
17
- { provider: "openai", model: "gpt-5.6", effort: "high", efforts: ["high", "xhigh", "max"], hint: "" },
18
- { provider: "openai", model: "gpt-5.6-terra", effort: "xhigh", efforts: ["high", "xhigh"], hint: "" }
9
+ export const installModelEfforts = Object.freeze(["low", "medium", "high", "xhigh", "max", "ultra"]);
10
+ export const nativeReasoningEfforts = Object.freeze(["none", "minimal", ...installModelEfforts]);
11
+ export const defaultOpenAiRoutes = Object.freeze({
12
+ lead: Object.freeze({ provider: "openai", model: "gpt-6-astra", effort: "xhigh" }),
13
+ helper: Object.freeze({ provider: "openai", model: "gpt-6-luna", effort: "max" })
14
+ });
15
+ export const newGenerationOpenAiModels = Object.freeze({
16
+ astra: defaultOpenAiRoutes.lead.model,
17
+ sol: "gpt-6-sol",
18
+ luna: defaultOpenAiRoutes.helper.model
19
+ });
20
+ export const previousGenerationOpenAiModels = Object.freeze({
21
+ sol: "gpt-5.6-sol",
22
+ terra: "gpt-5.6-terra",
23
+ luna: "gpt-5.6-luna",
24
+ family: "gpt-5.6"
25
+ });
26
+ export const legacyManagedModelIds = Object.freeze(["gpt-5.4", "gpt-5.5"]);
27
+ export const legacyFastAliasModels = Object.freeze([
28
+ previousGenerationOpenAiModels.sol,
29
+ previousGenerationOpenAiModels.terra,
30
+ previousGenerationOpenAiModels.luna,
31
+ previousGenerationOpenAiModels.family
32
+ ]);
33
+ export const hostLimitModelIds = Object.freeze([
34
+ defaultOpenAiRoutes.helper.model,
35
+ previousGenerationOpenAiModels.luna
36
+ ]);
37
+ // The OpenAI rows are the product policy, not the host catalog. Keep every
38
+ // supported effort here so the picker, flags, config reader, and route guard
39
+ // all consume one catalog rather than maintaining independent literal lists.
40
+ export const openaiRows = [
41
+ { provider: "openai", model: defaultOpenAiRoutes.lead.model, effort: defaultOpenAiRoutes.lead.effort, efforts: installModelEfforts, hint: "frontier reasoning (recommended lead)" },
42
+ { provider: "openai", model: newGenerationOpenAiModels.sol, effort: "xhigh", efforts: installModelEfforts, hint: "coding lead (recommended alternative)" },
43
+ { provider: "openai", model: defaultOpenAiRoutes.helper.model, effort: defaultOpenAiRoutes.helper.effort, efforts: installModelEfforts.slice(0, 5), hint: "balanced (recommended helper)" },
44
+ { provider: "openai", model: previousGenerationOpenAiModels.sol, effort: "xhigh", efforts: ["high", "xhigh", "max"], hint: "deepest reasoning, previous generation" },
45
+ { provider: "openai", model: previousGenerationOpenAiModels.luna, effort: "max", efforts: ["high", "max"], hint: "balanced, previous generation" },
46
+ { provider: "openai", model: previousGenerationOpenAiModels.family, effort: "high", efforts: ["high", "xhigh", "max"], hint: "previous generation" },
47
+ { provider: "openai", model: previousGenerationOpenAiModels.terra, effort: "xhigh", efforts: ["high", "xhigh"], hint: "previous generation" }
19
48
  ];
49
+ export const openaiProviderModels = Object.freeze({
50
+ [newGenerationOpenAiModels.astra]: Object.freeze({ name: "GPT-6 Astra", reasoning: true, temperature: false, tool_call: true }),
51
+ [newGenerationOpenAiModels.sol]: Object.freeze({ name: "GPT-6 Sol", reasoning: true, temperature: false, tool_call: true }),
52
+ [newGenerationOpenAiModels.luna]: Object.freeze({ name: "GPT-6 Luna", reasoning: true, temperature: false, tool_call: true })
53
+ });
54
+ export function openAiModelRow(model) {
55
+ return openaiRows.find((row) => row.model === model);
56
+ }
57
+ export function openAiModelEfforts(model) {
58
+ return openAiModelRow(model)?.efforts ?? [];
59
+ }
60
+ export function isInstallModelEffort(value) {
61
+ return installModelEfforts.includes(value);
62
+ }
63
+ export function openaiModelHelpLine() {
64
+ return openaiRows
65
+ .map((row) => `${row.model}·${row.effort} (${row.efforts.join("/")})`)
66
+ .join(", ");
67
+ }
68
+ export function shippedDefaultsSummary() {
69
+ return `GPT-6 Astra/${defaultOpenAiRoutes.lead.effort} lead + planning/review; GPT-6 Luna/${defaultOpenAiRoutes.helper.effort} execution/research helpers`;
70
+ }
71
+ export function legacyFastAliasHelp() {
72
+ return "The previous-generation GPT-5.6 rows retain their <id>-fast aliases; GPT-6 rows have no inferred -fast alias.";
73
+ }
74
+ export function modelEffortHelp() {
75
+ return `GPT-6 Astra and Sol accept ${installModelEfforts.join(", ")}; GPT-6 Luna accepts ${openAiModelEfforts(newGenerationOpenAiModels.luna).join(", ")} and rejects ultra.`;
76
+ }
20
77
  // Used only when the host catalog (~/.cache/opencode/models.json) is absent or unreadable.
21
78
  const fallbackXaiRows = [
22
79
  { provider: "xai", model: "grok-4.6", effort: "xhigh", efforts: ["low", "medium", "high", "xhigh"], hint: "frontier reasoning (catalog unavailable)" },
@@ -30,7 +87,7 @@ export function hostCatalogPath() {
30
87
  return path.join(base, "opencode", "models.json");
31
88
  }
32
89
  function isEffort(value) {
33
- return typeof value === "string" && effortRank.includes(value);
90
+ return typeof value === "string" && isInstallModelEffort(value);
34
91
  }
35
92
  function catalogEfforts(entry) {
36
93
  if (!Array.isArray(entry.reasoning_options))
@@ -43,7 +100,7 @@ function catalogEfforts(entry) {
43
100
  if (isEffort(value) && !values.includes(value))
44
101
  values.push(value);
45
102
  }
46
- return values.sort((left, right) => effortRank.indexOf(left) - effortRank.indexOf(right));
103
+ return values.sort((left, right) => installModelEfforts.indexOf(left) - installModelEfforts.indexOf(right));
47
104
  }
48
105
  function xaiRowsFromCatalog() {
49
106
  let parsed;
@@ -84,10 +141,14 @@ export function isModelProvider(value) {
84
141
  export function providerCredentialEnv(provider) {
85
142
  return providerMenu.find((row) => row.provider === provider)?.credentialEnv;
86
143
  }
87
- // OpenCode exposes `<id>-fast` as a priority-tier alias for legacy OpenAI
88
- // rows; Astra has no inferred `-fast` alias and remains an exact model id.
144
+ // OpenCode exposes `<id>-fast` as a priority-tier alias for previous-generation
145
+ // OpenAI rows; GPT-6 rows remain exact model ids.
89
146
  export function stripFastSuffix(model) {
90
- return model !== "gpt-6-astra-fast" && model.endsWith("-fast") ? model.slice(0, -"-fast".length) : model;
147
+ return legacyFastAliasModels.includes(model)
148
+ ? model
149
+ : model.endsWith("-fast") && legacyFastAliasModels.includes(model.slice(0, -"-fast".length))
150
+ ? model.slice(0, -"-fast".length)
151
+ : model;
91
152
  }
92
153
  export function resolveModelRoute(provider, model, effort, optionName) {
93
154
  if (!isModelProvider(provider)) {
@@ -99,7 +160,7 @@ export function resolveModelRoute(provider, model, effort, optionName) {
99
160
  throw new Error(optionName + " model " + provider + "/" + model + " is not offered; choose one of " + rows.map((candidate) => candidate.model).join(", "));
100
161
  }
101
162
  if (effort !== undefined && !row.efforts.includes(effort)) {
102
- if (row.model === "gpt-5.6-luna")
163
+ if (row.model === previousGenerationOpenAiModels.luna)
103
164
  throw new Error("Luna effort must be high or max");
104
165
  throw new Error(provider + "/" + model + " accepts effort " + row.efforts.join(", ") + " (got " + effort + ")");
105
166
  }
@@ -1,11 +1,12 @@
1
1
  import { defaultGlobalConfigJson } from "../config.js";
2
2
  import { isRecord } from "./json.js";
3
+ import { defaultOpenAiRoutes, legacyManagedModelIds, openAiModelEfforts, previousGenerationOpenAiModels } from "./model-catalog.js";
3
4
  const categoryIds = ["planning", "execution", "review", "research"];
4
5
  const leadCategoryIds = new Set(["planning", "review"]);
5
- const canonicalModels = new Set(["gpt-5.6-luna"]);
6
- const legacyModels = new Set(["gpt-5.4", "gpt-5.5"]);
7
- const offeredEfforts = new Set(["medium", "high", "max"]);
8
- const astraEfforts = new Set(["low", "medium", "high", "xhigh", "max"]);
6
+ const canonicalModels = new Set([defaultOpenAiRoutes.helper.model, previousGenerationOpenAiModels.luna]);
7
+ const offeredEfforts = new Set(openAiModelEfforts(previousGenerationOpenAiModels.luna));
8
+ const astraEfforts = new Set(openAiModelEfforts(defaultOpenAiRoutes.lead.model));
9
+ const legacyModels = new Set(legacyManagedModelIds);
9
10
  const managedLegacyRouteKeys = new Set(["provider", "model", "variant", "textVerbosity"]);
10
11
  function normalizedRoute(value) {
11
12
  if (!isRecord(value) || typeof value.model !== "string")
@@ -93,7 +94,7 @@ export function classifyModelConfig(rawConfig) {
93
94
  if (first.qualifiedModel)
94
95
  return result("custom", first.dispatchId);
95
96
  if (first.provider === "openai" &&
96
- first.model === "gpt-6-astra" &&
97
+ first.model === defaultOpenAiRoutes.lead.model &&
97
98
  first.variant !== undefined &&
98
99
  astraEfforts.has(first.variant)) {
99
100
  return result("astra_managed", first.dispatchId);
@@ -103,7 +104,7 @@ export function classifyModelConfig(rawConfig) {
103
104
  (first.variant === undefined || offeredEfforts.has(first.variant))) {
104
105
  return result("gpt56_managed", first.dispatchId);
105
106
  }
106
- if (first.provider === "openai" && /^gpt-5\.6(?:$|-)/u.test(first.model)) {
107
+ if (first.provider === "openai" && (first.model === previousGenerationOpenAiModels.family || first.model.startsWith(previousGenerationOpenAiModels.family + "-"))) {
107
108
  return result("gpt56_other", first.dispatchId);
108
109
  }
109
110
  return result("custom", first.dispatchId);
@@ -52,7 +52,7 @@ export type InstallModelRoute = {
52
52
  export type InstallModelSelection = InstallModelRoute & {
53
53
  readonly helper?: InstallModelRoute;
54
54
  };
55
- export type InstallModelEffort = "low" | "medium" | "high" | "xhigh" | "max";
55
+ export type InstallModelEffort = "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
56
56
  export type ModelConfigClass = "fresh" | "managed_legacy" | "gpt56_managed" | "astra_managed" | "gpt56_other" | "custom" | "mixed";
57
57
  export type ModelConfigClassification = {
58
58
  readonly class: ModelConfigClass;
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import { createInstallTui, renderLitOpenCodeWordmark, shouldRenderInstallTui } f
6
6
  import { runUpdateNotifier } from "./cli/update-notifier.js";
7
7
  import { autoUpdateDiagnostic, canContinueAfterAutoUpdate, runInteractiveAutoUpdate } from "./cli/auto-update.js";
8
8
  import { LitOpenCodeConfigError } from "./config.js";
9
+ import { defaultOpenAiRoutes, legacyFastAliasHelp, modelEffortHelp, openaiModelHelpLine, shippedDefaultsSummary } from "./cli/model-catalog.js";
9
10
  import { fetchPublicSource } from "./lit-fetch.js";
10
11
  import { readPackageMetadata } from "./cli/json.js";
11
12
  import path from "node:path";
@@ -22,9 +23,9 @@ function helpText() {
22
23
  " npm exec --package @litfamily/litopencode -- litopencode install --permission-prompt",
23
24
  " npm exec --package @litfamily/litopencode -- litopencode install --permission-mode balanced",
24
25
  " npm exec --package @litfamily/litopencode -- litopencode install --yolo",
25
- " npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model gpt-6-astra --effort xhigh",
26
- " npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model gpt-5.6-luna --effort max",
27
- " npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model gpt-5.6-luna --effort high",
26
+ ` npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model ${defaultOpenAiRoutes.lead.model} --effort ${defaultOpenAiRoutes.lead.effort}`,
27
+ ` npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model ${defaultOpenAiRoutes.helper.model} --effort ${defaultOpenAiRoutes.helper.effort}`,
28
+ ` npm exec --package @litfamily/litopencode -- litopencode install --provider openai --model ${defaultOpenAiRoutes.helper.model} --effort high`,
28
29
  "",
29
30
  "Usage:",
30
31
  " litopencode install [--dry-run] [--root <dir>] --provider <openai|xai> --model <id> [--effort <e>] [--subagent-model <provider/id>] [--subagent-effort <e>] [--yolo]",
@@ -84,12 +85,12 @@ function helpText() {
84
85
  "Model routing:",
85
86
  " Interactive terminal installs ask provider (openai | xai), LEAD model (planning/review) and HELPER model (execution/research),",
86
87
  " preselecting the current managed route; --yes and --no-model-prompt keep the current non-picker behavior.",
87
- " openai rows: gpt-6-astra·xhigh (low/medium/high/xhigh/max), gpt-5.6-sol·xhigh, gpt-5.6-luna·max, gpt-5.6·high, gpt-5.6-terra·xhigh.",
88
- " The legacy GPT-5.6 rows retain their <id>-fast aliases; gpt-6-astra-fast is not a model alias.",
88
+ " openai rows: " + openaiModelHelpLine() + ".",
89
+ " " + legacyFastAliasHelp(),
89
90
  " xai rows: reasoning-capable Grok models from the host catalog, grok-4.6 first; XAI_API_KEY is warned about, never required.",
90
91
  " --provider <p> --model <id> [--effort <e>] writes the lead route; --subagent-model <provider/id> [--subagent-effort <e>] the helper route.",
91
- " Astra accepts low, medium, high, xhigh, or max and uses native reasoning effort; LUNA accepts high or max and rejects xhigh.",
92
- " Without flags/reset, planning and review (including lit-loop) use Astra/xhigh; execution and research helpers use LUNA/max.",
92
+ " " + modelEffortHelp(),
93
+ " Without flags/reset, planning and review (including lit-loop) use Astra/xhigh; execution and research helpers use GPT-6 Luna/max.",
93
94
  " --model-prompt forces the picker on any existing route (managed keys only); --no-model-prompt and --yes keep current model routes.",
94
95
  "",
95
96
  "Permission behavior:",
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
+ import { nativeReasoningEfforts } from "./cli/model-catalog.js";
2
3
  export class LitOpenCodeConfigError extends Error {
3
4
  constructor(message) {
4
5
  super(message);
@@ -8,7 +9,7 @@ export class LitOpenCodeConfigError extends Error {
8
9
  const logLevels = new Set(["silent", "error", "info", "debug"]);
9
10
  const permissionModes = new Set(["safe", "balanced", "yolo"]);
10
11
  const outputStyleIds = new Set(["off", "asd-ste100", "asd-ste100-ko", "eli5", "eli5-ko"]);
11
- const reasoningEfforts = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
12
+ const reasoningEfforts = new Set(nativeReasoningEfforts);
12
13
  const textVerbosities = new Set(["low", "medium", "high"]);
13
14
  const toolIds = new Set(["read", "write", "edit", "bash", "webfetch", "grep"]);
14
15
  const permissions = new Set(["ask", "allow", "deny"]);
@@ -87,7 +88,7 @@ function optionalReasoningEffort(value, filePath, field) {
87
88
  if (value === undefined || value === null)
88
89
  return undefined;
89
90
  if (typeof value !== "string" || !reasoningEfforts.has(value)) {
90
- throw new LitOpenCodeConfigError(`Malformed LitOpenCode config at ${filePath}: ${field} must be one of none, minimal, low, medium, high, xhigh, max.`);
91
+ throw new LitOpenCodeConfigError(`Malformed LitOpenCode config at ${filePath}: ${field} must be one of ${nativeReasoningEfforts.join(", ")}.`);
91
92
  }
92
93
  return value;
93
94
  }
package/dist/config.d.ts CHANGED
@@ -4,7 +4,7 @@ export { LitOpenCodeConfigError, readLitOpenCodeConfigFile } from "./config-pars
4
4
  export type LogLevel = "silent" | "error" | "info" | "debug";
5
5
  export type LitOpenCodeConfigSource = "defaults" | "global" | "project" | "merged";
6
6
  export type LitOpenCodePermissionMode = "safe" | "balanced" | "yolo";
7
- export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
7
+ export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
8
8
  export type TextVerbosity = "low" | "medium" | "high";
9
9
  export type BoundedAuthorityConfig = {
10
10
  readonly maxEvents: number;
package/dist/config.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createRuntimePaths } from "./state.js";
2
2
  import { readLitOpenCodeConfigFile } from "./config-parser.js";
3
+ import { defaultOpenAiRoutes } from "./cli/model-catalog.js";
3
4
  export { LitOpenCodeConfigError, readLitOpenCodeConfigFile } from "./config-parser.js";
4
5
  // The runtime receives a merged config, so keep source ownership alongside
5
6
  // (rather than inside) the JSON-shaped config. This never serializes into a
@@ -23,27 +24,27 @@ export const defaultConfig = Object.freeze({
23
24
  knowledge: Object.freeze({ capture: true }),
24
25
  categories: Object.freeze({
25
26
  planning: Object.freeze({
26
- provider: "openai",
27
- model: "gpt-6-astra",
28
- variant: "xhigh",
27
+ provider: defaultOpenAiRoutes.lead.provider,
28
+ model: defaultOpenAiRoutes.lead.model,
29
+ variant: defaultOpenAiRoutes.lead.effort,
29
30
  textVerbosity: "medium"
30
31
  }),
31
32
  execution: Object.freeze({
32
- provider: "openai",
33
- model: "gpt-5.6-luna",
34
- variant: "max",
33
+ provider: defaultOpenAiRoutes.helper.provider,
34
+ model: defaultOpenAiRoutes.helper.model,
35
+ variant: defaultOpenAiRoutes.helper.effort,
35
36
  textVerbosity: "medium"
36
37
  }),
37
38
  review: Object.freeze({
38
- provider: "openai",
39
- model: "gpt-6-astra",
40
- variant: "xhigh",
39
+ provider: defaultOpenAiRoutes.lead.provider,
40
+ model: defaultOpenAiRoutes.lead.model,
41
+ variant: defaultOpenAiRoutes.lead.effort,
41
42
  textVerbosity: "medium"
42
43
  }),
43
44
  research: Object.freeze({
44
- provider: "openai",
45
- model: "gpt-5.6-luna",
46
- variant: "max",
45
+ provider: defaultOpenAiRoutes.helper.provider,
46
+ model: defaultOpenAiRoutes.helper.model,
47
+ variant: defaultOpenAiRoutes.helper.effort,
47
48
  textVerbosity: "medium"
48
49
  })
49
50
  }),
@@ -1,5 +1,5 @@
1
1
  export type LitOpenCodeBindingKind = "agent" | "cli" | "command" | "config" | "hook" | "tool";
2
- export type LitOpenCodeFeatureId = "planning-start-work-loop" | "lit-litwork-activation" | "start-work" | "review-work" | "litresearch" | "durable-ledger" | "bounded-authority-lifecycle" | "agent-roster" | "lit-plan" | "reference-benchmark-claims" | "native-goal-verdict" | "doctor-install" | "search-workflow-ideas" | "lit-fetch" | "guardrails" | "lit-init" | "lit-crucible" | "refactor" | "lit-burnoff" | "lit-burnoff-file" | "comment-checker" | "lit-code" | "debugging" | "lit-commit" | "lsp" | "lsp-setup" | "rules" | "deep-interview" | "structural-search" | "browser-drive" | "lit-korean" | "lit-recap" | "lit-comprehend" | "lit-handoff" | "lit-scientific-visualization" | "frontend-ui-ux" | "visual-qa" | "autoresearch" | "autoconference" | "wikify";
2
+ export type LitOpenCodeFeatureId = "planning-start-work-loop" | "lit-litwork-activation" | "start-work" | "review-work" | "litresearch" | "durable-ledger" | "bounded-authority-lifecycle" | "agent-roster" | "lit-plan" | "reference-benchmark-claims" | "native-goal-verdict" | "doctor-install" | "search-workflow-ideas" | "lit-fetch" | "guardrails" | "lit-init" | "lit-crucible" | "refactor" | "lit-burnoff" | "lit-burnoff-file" | "comment-checker" | "lit-code" | "debugging" | "lit-commit" | "lsp" | "lsp-setup" | "rules" | "deep-interview" | "structural-search" | "browser-drive" | "lit-korean" | "lit-recap" | "lit-comprehend" | "lit-handoff" | "lit-scientific-visualization" | "readme-studio" | "frontend-ui-ux" | "visual-qa" | "autoresearch" | "autoconference" | "wikify";
3
3
  export type LitOpenCodeFeatureBinding = {
4
4
  readonly kind: LitOpenCodeBindingKind;
5
5
  readonly id: string;
@@ -803,5 +803,21 @@ export declare const litOpenCodeFeatures: readonly ({
803
803
  description: string;
804
804
  })[];
805
805
  verification: string[];
806
+ } | {
807
+ id: "readme-studio";
808
+ title: string;
809
+ summary: string;
810
+ bindings: ({
811
+ kind: "config";
812
+ id: string;
813
+ surface: string;
814
+ description: string;
815
+ } | {
816
+ kind: "cli";
817
+ id: string;
818
+ surface: string;
819
+ description: string;
820
+ })[];
821
+ verification: string[];
806
822
  })[];
807
823
  export declare function findLitOpenCodeFeature(id: string): LitOpenCodeFeature | undefined;
package/dist/features.js CHANGED
@@ -1059,6 +1059,16 @@ export const litOpenCodeFeatures = Object.freeze([
1059
1059
  verification: ["node --test test/lit-scientific-visualization.test.mjs", "npm run check:pack-payload"]
1060
1060
  },
1061
1061
  frontendUiUxFeature,
1062
+ {
1063
+ id: "readme-studio", title: "README Studio",
1064
+ summary: "Native-installed README production, safe local typography and portable motion assets.",
1065
+ bindings: [
1066
+ { kind: "config", id: "skills/readme-studio/SKILL.md", surface: "OpenCode native skill readme-studio", description: "Loads fact discovery, capability branches and task-local composition recipes." },
1067
+ { kind: "cli", id: "litopencode install", surface: "LitOpenCode native skill installer", description: "Copies all hash-pinned nested resources." },
1068
+ { kind: "cli", id: "litopencode doctor", surface: "LitOpenCode native skill doctor", description: "Rejects missing or altered resources." }
1069
+ ],
1070
+ verification: ["node --test test/runtime-skills.test.mjs test/cli-install-surface.test.mjs test/packed-artifact.test.mjs", "npm run check:managed-skill-manifest"]
1071
+ },
1062
1072
  visualQaFeature
1063
1073
  ]);
1064
1074
  export function findLitOpenCodeFeature(id) {
@@ -1,7 +1,7 @@
1
1
  import { type LitOpenCodeAgentModelConfig, type LitOpenCodeConfig } from "./config.ts";
2
2
  export type ModelRouteDiagnostic = {
3
3
  readonly agentId: string;
4
- readonly code: "luna_effort_below_high" | "luna_xhigh_forbidden" | "luna_effort_conflict" | "terra_effort_below_high" | "terra_effort_conflict" | "astra_effort_unsupported" | "astra_effort_conflict";
4
+ readonly code: "luna_effort_below_high" | "luna_xhigh_forbidden" | "luna_effort_conflict" | "terra_effort_below_high" | "terra_effort_conflict" | "astra_effort_unsupported" | "astra_effort_conflict" | "model_effort_unsupported" | "model_effort_conflict";
5
5
  readonly model: string;
6
6
  readonly effort: string;
7
7
  };
@@ -1,7 +1,8 @@
1
1
  import { effectiveAgentConfig } from "./config.js";
2
- const safeLunaEfforts = new Set(["high", "max"]);
3
- const safeTerraEfforts = new Set(["high", "xhigh"]);
4
- const safeAstraEfforts = new Set(["low", "medium", "high", "xhigh", "max"]);
2
+ import { defaultOpenAiRoutes, newGenerationOpenAiModels, openAiModelEfforts, previousGenerationOpenAiModels, stripFastSuffix } from "./cli/model-catalog.js";
3
+ const safeLunaEfforts = new Set(openAiModelEfforts(previousGenerationOpenAiModels.luna));
4
+ const safeTerraEfforts = new Set(openAiModelEfforts(previousGenerationOpenAiModels.terra));
5
+ const safeAstraEfforts = new Set(openAiModelEfforts(defaultOpenAiRoutes.lead.model));
5
6
  function dispatchedModel(route) {
6
7
  if (route.model === undefined)
7
8
  return undefined;
@@ -12,7 +13,7 @@ function dispatchedModel(route) {
12
13
  export function unqualifiedModel(dispatchId) {
13
14
  const separator = dispatchId.lastIndexOf("/");
14
15
  const model = separator === -1 ? dispatchId : dispatchId.slice(separator + 1);
15
- return model !== "gpt-6-astra-fast" && model.endsWith("-fast") ? model.slice(0, -"-fast".length) : model;
16
+ return stripFastSuffix(model);
16
17
  }
17
18
  function dispatchedProvider(dispatchId) {
18
19
  const separator = dispatchId.indexOf("/");
@@ -41,7 +42,7 @@ export function diagnoseModelRoutes(routes) {
41
42
  continue;
42
43
  const modelId = unqualifiedModel(model);
43
44
  const effort = describedEffort(route);
44
- if (modelId === "gpt-6-astra") {
45
+ if (modelId === newGenerationOpenAiModels.astra) {
45
46
  const variantUnsafe = route.variant !== undefined && !safeAstraEfforts.has(route.variant);
46
47
  const reasoningUnsafe = route.reasoningEffort !== undefined && !safeAstraEfforts.has(route.reasoningEffort);
47
48
  if (variantUnsafe || reasoningUnsafe || (route.variant === undefined && route.reasoningEffort === undefined)) {
@@ -52,7 +53,19 @@ export function diagnoseModelRoutes(routes) {
52
53
  }
53
54
  continue;
54
55
  }
55
- if (modelId === "gpt-5.6-luna") {
56
+ if (modelId === newGenerationOpenAiModels.sol || modelId === newGenerationOpenAiModels.luna) {
57
+ const supported = new Set(openAiModelEfforts(modelId));
58
+ const variantUnsafe = route.variant !== undefined && !supported.has(route.variant);
59
+ const reasoningUnsafe = route.reasoningEffort !== undefined && !supported.has(route.reasoningEffort);
60
+ if (variantUnsafe || reasoningUnsafe || (route.variant === undefined && route.reasoningEffort === undefined)) {
61
+ diagnostics.push({ agentId, code: "model_effort_unsupported", model, effort });
62
+ }
63
+ if (route.variant !== undefined && route.reasoningEffort !== undefined && route.variant !== route.reasoningEffort) {
64
+ diagnostics.push({ agentId, code: "model_effort_conflict", model, effort });
65
+ }
66
+ continue;
67
+ }
68
+ if (modelId === previousGenerationOpenAiModels.luna) {
56
69
  const hasXhigh = route.variant === "xhigh" || route.reasoningEffort === "xhigh";
57
70
  if ((route.variant !== undefined && route.variant !== "xhigh" && !safeLunaEfforts.has(route.variant)) ||
58
71
  (route.reasoningEffort !== undefined && route.reasoningEffort !== "xhigh" && !safeLunaEfforts.has(route.reasoningEffort)) ||
@@ -66,7 +79,7 @@ export function diagnoseModelRoutes(routes) {
66
79
  }
67
80
  continue;
68
81
  }
69
- if (modelId !== "gpt-5.6-terra")
82
+ if (modelId !== previousGenerationOpenAiModels.terra)
70
83
  continue;
71
84
  if ((route.variant !== undefined && !safeTerraEfforts.has(route.variant)) ||
72
85
  (route.reasoningEffort !== undefined && !safeTerraEfforts.has(route.reasoningEffort)) ||
@@ -115,6 +128,10 @@ export class UnsafeModelRouteError extends Error {
115
128
  return `${diagnostic.agentId}: Astra requires low, medium, high, xhigh, or max (${diagnostic.model}, ${diagnostic.effort})`;
116
129
  case "astra_effort_conflict":
117
130
  return `${diagnostic.agentId}: Astra effort fields conflict (${diagnostic.model}, ${diagnostic.effort})`;
131
+ case "model_effort_unsupported":
132
+ return `${diagnostic.agentId}: ${diagnostic.model} accepts a supported catalog effort (${diagnostic.model}, ${diagnostic.effort})`;
133
+ case "model_effort_conflict":
134
+ return `${diagnostic.agentId}: ${diagnostic.model} effort fields conflict (${diagnostic.model}, ${diagnostic.effort})`;
118
135
  }
119
136
  })
120
137
  .join("; ");
package/dist/skills.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { LitOpenCodeFeatureId } from "./features.ts";
2
- export type LitOpenCodeRuntimeSkillId = "workflow-loop" | "durable-litgoal" | "agent-roster" | "lit-plan" | "start-work" | "review-work" | "litresearch" | "reference-benchmark-claims" | "native-goal-verdict" | "doctor-installer" | "search-workflow-ideas" | "lit-fetch" | "release-guardrails" | "lit-init" | "lit-crucible" | "refactor" | "lit-burnoff" | "lit-burnoff-file" | "comment-checker" | "lit-code" | "debugging" | "lit-commit" | "lsp" | "lsp-setup" | "rules" | "deep-interview" | "structural-search" | "browser-drive" | "lit-korean" | "lit-recap" | "lit-comprehend" | "lit-handoff" | "lit-scientific-visualization" | "frontend-ui-ux" | "visual-qa" | "autoresearch" | "autoconference" | "wikify";
2
+ export type LitOpenCodeRuntimeSkillId = "workflow-loop" | "durable-litgoal" | "agent-roster" | "lit-plan" | "start-work" | "review-work" | "litresearch" | "reference-benchmark-claims" | "native-goal-verdict" | "doctor-installer" | "search-workflow-ideas" | "lit-fetch" | "release-guardrails" | "lit-init" | "lit-crucible" | "refactor" | "lit-burnoff" | "lit-burnoff-file" | "comment-checker" | "lit-code" | "debugging" | "lit-commit" | "lsp" | "lsp-setup" | "rules" | "deep-interview" | "structural-search" | "browser-drive" | "lit-korean" | "lit-recap" | "lit-comprehend" | "lit-handoff" | "lit-scientific-visualization" | "readme-studio" | "frontend-ui-ux" | "visual-qa" | "autoresearch" | "autoconference" | "wikify";
3
3
  export type LitOpenCodeRuntimeSkill = {
4
4
  readonly id: LitOpenCodeRuntimeSkillId;
5
5
  readonly title: string;
@@ -282,6 +282,13 @@ export declare const litOpenCodeRuntimeSkills: readonly ({
282
282
  featureIds: ("planning-start-work-loop" | "litresearch" | "wikify")[];
283
283
  discovery: string;
284
284
  safety: string[];
285
+ } | {
286
+ id: "readme-studio";
287
+ title: string;
288
+ summary: string;
289
+ featureIds: ("doctor-install" | "readme-studio")[];
290
+ discovery: string;
291
+ safety: string[];
285
292
  })[];
286
293
  export declare function findLitOpenCodeRuntimeSkill(id: string): LitOpenCodeRuntimeSkill | undefined;
287
294
  export declare const litOpenCodeStaticOnlySkills: readonly ({
package/dist/skills.js CHANGED
@@ -411,6 +411,14 @@ export const litOpenCodeRuntimeSkills = Object.freeze([
411
411
  ]
412
412
  },
413
413
  frontendUiUxRuntimeSkill,
414
+ {
415
+ id: "readme-studio",
416
+ title: "README Studio",
417
+ summary: "Build factual READMEs and inspected hybrid covers with local outlined type and pinned motion recipes.",
418
+ featureIds: ["readme-studio", "doctor-install"],
419
+ discovery: "Select readme-studio using OpenCode's native skill tool; install copies its managed resources and doctor verifies them. No slash or automatic chat route is claimed.",
420
+ safety: ["Honor review-only and plan-only requests without edits.", "Probe native image capability; report IMAGE_GENERATION_UNAVAILABLE, then accept a supplied background without claiming generation.", "Verify facts, font licenses, glyph coverage, output boundaries and actual renders; public README rendering remains separately gated."]
421
+ },
414
422
  visualQaRuntimeSkill
415
423
  ]);
416
424
  export function findLitOpenCodeRuntimeSkill(id) {
@@ -1,7 +1,7 @@
1
1
  export const frontendUiUxFeature = {
2
2
  id: "frontend-ui-ux",
3
3
  title: "Frontend UI/UX",
4
- summary: "Provides a native-installed, offline, read-only Design Contract workflow with deterministic packaged design intelligence.",
4
+ summary: "Builds and inspects authorized interfaces using an evolving beta2 contract and offline design intelligence.",
5
5
  bindings: [
6
6
  {
7
7
  kind: "config",
@@ -75,16 +75,16 @@ export const visualQaFeature = {
75
75
  export const frontendUiUxRuntimeSkill = {
76
76
  id: "frontend-ui-ux",
77
77
  title: "Frontend UI/UX",
78
- summary: "Create a finite evidence-eligible v1beta2 Design Contract with deterministic offline design intelligence before approved implementation.",
78
+ summary: "Produce working interfaces and rendered inspection from an authorized brief; evolve the evidence-eligible v1beta2 Design Contract as decisions settle.",
79
79
  featureIds: ["frontend-ui-ux", "doctor-install"],
80
80
  discovery: "Describe interface work in chat — a making verb aimed at a UI, screen, layout, component, or stylesheet reaches this skill before any file is edited — or select the frontend-ui-ux OpenCode native skill, inspect skills/frontend-ui-ux/SKILL.md, or verify it with litopencode doctor. The post-edit hook also names it when an interface file changes.",
81
81
  safety: [
82
82
  "Keep retrieval offline, read-only, deterministic, bounded, and honest when no record matches.",
83
- "Do not grant command, shell, browser, authentication, agent, tool, MCP, or write authority.",
84
- "Require a finite route/state/viewport/theme/permission/auth/terminal/reference inventory before handoff.",
83
+ "Selection does not grant authority; implement only within the user request and OpenCode permissions. Review-only and plan-only stay read-only.",
84
+ "Record a compact finite inventory before coding and evolve the contract through implementation.",
85
85
  "Validate the exact canonical manifest before its scanner protection or inert read route; never execute its imported scripts or grant them host authority.",
86
86
  "Keep the normalized 34-source/2,277-record dataset unchanged and separate from the byte-preserved canonical library.",
87
- "Hand off only the immutable contract hash and the evidence schema ids, never a partner skill name."
87
+ "Deliver working source, inspected renders and material gaps; keep contract hashes in evidence."
88
88
  ]
89
89
  };
90
90
  export const visualQaRuntimeSkill = {
Binary file