@litfamily/litopencode 1.0.4 → 1.0.6
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/CHANGELOG.md +12 -0
- package/README-Ko-KR.md +150 -115
- package/README.md +147 -116
- package/dist/activation-workflow-prompts.js +1 -1
- package/dist/agents/registry.js +30 -26
- package/dist/cli/args.js +3 -3
- package/dist/cli/host-limits.d.ts +1 -1
- package/dist/cli/host-limits.js +3 -2
- package/dist/cli/install-config.js +2 -2
- package/dist/cli/install-report.js +18 -1
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +3 -1
- package/dist/cli/model-catalog.d.ts +56 -0
- package/dist/cli/model-catalog.js +78 -17
- package/dist/cli/model-policy.js +7 -6
- package/dist/cli/native-skill-integrity.d.ts +16 -0
- package/dist/cli/native-skill-integrity.js +80 -0
- package/dist/cli/native-skills.d.ts +9 -1
- package/dist/cli/native-skills.js +19 -3
- package/dist/cli/types.d.ts +6 -1
- package/dist/cli.js +8 -7
- package/dist/config-parser.js +3 -2
- package/dist/config.d.ts +1 -1
- package/dist/config.js +13 -12
- package/dist/features.d.ts +17 -1
- package/dist/features.js +10 -0
- package/dist/model-route-policy.d.ts +1 -1
- package/dist/model-route-policy.js +24 -7
- package/dist/skills.d.ts +8 -1
- package/dist/skills.js +8 -0
- package/dist/uiux-visual-catalog.js +5 -5
- package/docs/assets/cover-motion-still.webp +0 -0
- package/docs/assets/cover-motion.webp +0 -0
- package/docs/assets/readme/JetBrainsMono-OFL.txt +93 -0
- package/docs/assets/readme/Lucide-LICENSE.txt +43 -0
- package/docs/assets/readme/ascii-readme.svg +5 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/assets/readme/ignition-film.mp4 +0 -0
- package/docs/assets/readme/ignition-readme.gif +0 -0
- package/docs/assets/readme/litfamily-machines.png +0 -0
- package/docs/assets/readme/lucide-book-open.svg +14 -0
- package/docs/assets/readme/lucide-play.svg +13 -0
- package/docs/assets/readme/lucide-shield-check.svg +14 -0
- package/docs/assets/readme/poster.png +0 -0
- package/docs/migration.md +2 -2
- package/docs/reference-Ko-KR.md +43 -4
- package/docs/reference.md +51 -10
- package/package.json +1 -1
- package/skills/frontend-ui-ux/SKILL.md +25 -31
- package/skills/frontend-ui-ux/references/complete-contract.md +12 -12
- package/skills/frontend-ui-ux/references/default-editorial-pixel.json +19 -0
- package/skills/frontend-ui-ux/references/production.md +15 -0
- package/skills/managed-skill-manifest.json +92 -1
- package/skills/readme-studio/SKILL.md +76 -0
- package/skills/readme-studio/references/decoration-patterns.md +105 -0
- package/skills/readme-studio/references/motion.md +38 -0
- package/skills/readme-studio/references/production.md +13 -0
- package/skills/readme-studio/references/typography.md +16 -0
- package/skills/readme-studio/scripts/check-facts.mjs +28 -0
- package/skills/readme-studio/templates/cover-source.json +1 -0
- package/skills/readme-studio/templates/facts.json +1 -0
- package/skills/readme-studio/templates/hyperframes/index.html +62 -0
- package/skills/readme-studio/templates/hyperframes/index.motion.json +1 -0
- package/skills/readme-studio/templates/hyperframes/package-lock.json +1966 -0
- package/skills/readme-studio/templates/hyperframes/package.json +1 -0
- package/skills/readme-studio/templates/readme-cover-section.md +53 -0
- package/skills/readme-studio/templates/remotion/package-lock.json +3783 -0
- package/skills/readme-studio/templates/remotion/package.json +1 -0
- package/skills/readme-studio/templates/remotion/src/index.tsx +32 -0
- package/skills/readme-studio/templates/typography/files.mjs +46 -0
- package/skills/readme-studio/templates/typography/outline.mjs +47 -0
- package/skills/readme-studio/templates/typography/package-lock.json +133 -0
- package/skills/readme-studio/templates/typography/package.json +1 -0
- package/tools/check-pack-payload.mjs +34 -2
- package/tools/payload-substance-parity.json +4 -3
- package/tools/version-manifests.json +4 -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
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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" &&
|
|
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) =>
|
|
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
|
|
88
|
-
// rows;
|
|
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
|
|
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 ===
|
|
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
|
}
|
package/dist/cli/model-policy.js
CHANGED
|
@@ -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([
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
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 ===
|
|
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" &&
|
|
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);
|
|
@@ -14,6 +14,22 @@ export type DestinationState = {
|
|
|
14
14
|
readonly reason: string;
|
|
15
15
|
};
|
|
16
16
|
export declare function nativeSkillsRoot(root: string): Promise<string>;
|
|
17
|
+
export type NativeSkillsRootLink = {
|
|
18
|
+
readonly path: string;
|
|
19
|
+
readonly target: string;
|
|
20
|
+
readonly gitRepositoryRoot?: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function nativeSkillsRootLink(root: string, homeDir?: string): Promise<NativeSkillsRootLink | undefined>;
|
|
23
|
+
export type ShadowSkillLocationId = "user-agents" | "user-claude" | "project-opencode" | "project-claude" | "project-agents";
|
|
24
|
+
export type ShadowSkillLocation = {
|
|
25
|
+
readonly id: ShadowSkillLocationId;
|
|
26
|
+
readonly root: string;
|
|
27
|
+
};
|
|
28
|
+
export type ShadowedSkill = {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly locations: readonly ShadowSkillLocation[];
|
|
31
|
+
};
|
|
32
|
+
export declare function detectShadowedSkills(skillIds: readonly string[], managedSkillsRoot: string, homeDir?: string, workDir?: string): Promise<readonly ShadowedSkill[]>;
|
|
17
33
|
export declare function sourceSkillDir(metadata: PackageMetadata, id: string): string;
|
|
18
34
|
export declare function nativeSkillContent(metadata: PackageMetadata, skill: RuntimeSkill): Promise<string>;
|
|
19
35
|
export declare function validateManagedSkillSource(metadata: PackageMetadata, id: ManagedSkillId): Promise<void>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { litOpenCodeRuntimeSkills } from "../skills.js";
|
|
5
6
|
import { hasLitOpenCodeGeneratedFileMarker, litOpenCodeGeneratedFrontmatterMarker, stripUserFacingHtmlCommentLines } from "../user-facing-markdown.js";
|
|
@@ -9,6 +10,85 @@ import { inspectCanonicalTree } from "./native-canonical-cache.js";
|
|
|
9
10
|
export async function nativeSkillsRoot(root) {
|
|
10
11
|
return resolveSafeDirectory(root, path.join(root, "skills"), "Native skills destination");
|
|
11
12
|
}
|
|
13
|
+
// Walks upward from `startDir` looking for a `.git` entry (directory or the gitdir-pointer file a
|
|
14
|
+
// worktree/submodule uses), stopping once it reaches `homeDir` or the filesystem root so an
|
|
15
|
+
// unrelated ancestor repository is never reported as the destination.
|
|
16
|
+
async function gitRepositoryRootFor(startDir, homeDir) {
|
|
17
|
+
const home = path.resolve(homeDir);
|
|
18
|
+
const fsRoot = path.parse(startDir).root;
|
|
19
|
+
let current = path.resolve(startDir);
|
|
20
|
+
while (true) {
|
|
21
|
+
if ((await lstatIfPresent(path.join(current, ".git"))) !== null)
|
|
22
|
+
return current;
|
|
23
|
+
if (current === home || current === fsRoot)
|
|
24
|
+
return undefined;
|
|
25
|
+
const parent = path.dirname(current);
|
|
26
|
+
if (parent === current)
|
|
27
|
+
return undefined;
|
|
28
|
+
current = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Reports the same symlink LitOpenCode intentionally follows for install (resolveSafeDirectory),
|
|
32
|
+
// so users can see where their managed skills actually landed and whether that is a git work tree.
|
|
33
|
+
export async function nativeSkillsRootLink(root, homeDir = os.homedir()) {
|
|
34
|
+
const skillsPath = path.join(path.resolve(root), "skills");
|
|
35
|
+
const stat = await lstatIfPresent(skillsPath);
|
|
36
|
+
if (stat === null || !stat.isSymbolicLink())
|
|
37
|
+
return undefined;
|
|
38
|
+
const target = await fs.realpath(skillsPath);
|
|
39
|
+
const gitRepositoryRoot = await gitRepositoryRootFor(target, homeDir);
|
|
40
|
+
return { path: skillsPath, target, ...(gitRepositoryRoot === undefined ? {} : { gitRepositoryRoot }) };
|
|
41
|
+
}
|
|
42
|
+
function shadowSkillCandidateRoots(homeDir, workDir) {
|
|
43
|
+
return [
|
|
44
|
+
{ id: "user-agents", root: path.join(homeDir, ".agents", "skills") },
|
|
45
|
+
{ id: "user-claude", root: path.join(homeDir, ".claude", "skills") },
|
|
46
|
+
{ id: "project-opencode", root: path.join(workDir, ".opencode", "skills") },
|
|
47
|
+
{ id: "project-claude", root: path.join(workDir, ".claude", "skills") },
|
|
48
|
+
{ id: "project-agents", root: path.join(workDir, ".agents", "skills") }
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
async function statIfPresent(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
return await fs.stat(filePath);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
|
|
57
|
+
return null;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function realpathOrResolved(candidate) {
|
|
62
|
+
try {
|
|
63
|
+
return await fs.realpath(candidate);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return path.resolve(candidate);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// OpenCode also reads skills from these other, unmanaged roots; a same-named skill there can be
|
|
70
|
+
// loaded instead of (or alongside) LitOpenCode's managed copy. This is informational only: it never
|
|
71
|
+
// changes `ok`, because LitOpenCode does not own those directories.
|
|
72
|
+
export async function detectShadowedSkills(skillIds, managedSkillsRoot, homeDir = os.homedir(), workDir = process.cwd()) {
|
|
73
|
+
const managedRealpath = await realpathOrResolved(managedSkillsRoot);
|
|
74
|
+
const candidates = shadowSkillCandidateRoots(homeDir, workDir);
|
|
75
|
+
const shadowed = [];
|
|
76
|
+
for (const id of skillIds) {
|
|
77
|
+
const locations = [];
|
|
78
|
+
for (const candidate of candidates) {
|
|
79
|
+
const entrypoint = path.join(candidate.root, id, "SKILL.md");
|
|
80
|
+
const stat = await statIfPresent(entrypoint);
|
|
81
|
+
if (stat === null || !stat.isFile())
|
|
82
|
+
continue;
|
|
83
|
+
if ((await realpathOrResolved(candidate.root)) === managedRealpath)
|
|
84
|
+
continue;
|
|
85
|
+
locations.push(candidate);
|
|
86
|
+
}
|
|
87
|
+
if (locations.length > 0)
|
|
88
|
+
shadowed.push({ id, locations });
|
|
89
|
+
}
|
|
90
|
+
return shadowed;
|
|
91
|
+
}
|
|
12
92
|
export function sourceSkillDir(metadata, id) {
|
|
13
93
|
return path.join(metadata.packageRoot, "skills", id);
|
|
14
94
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { type NativeSkillsRootLink, type ShadowedSkill } from "./native-skill-integrity.ts";
|
|
1
2
|
import { inspectScientificVisualizationDependencies } from "./scientific-visualization-dependencies.ts";
|
|
2
3
|
import type { InstallReport, PackageMetadata } from "./types.ts";
|
|
3
4
|
export { validateManagedSkillSource } from "./native-skill-integrity.ts";
|
|
4
5
|
export { ensureNativeSkills } from "./native-skill-install.ts";
|
|
6
|
+
export type { NativeSkillsRootLink, ShadowedSkill, ShadowSkillLocation, ShadowSkillLocationId } from "./native-skill-integrity.ts";
|
|
5
7
|
export declare function describeNativeSkillMutation(root: string, metadata: PackageMetadata): Promise<InstallReport["nativeSkills"]>;
|
|
6
8
|
export type NativeSkillInspection = {
|
|
7
9
|
readonly path: string;
|
|
@@ -17,6 +19,12 @@ export type NativeSkillInspection = {
|
|
|
17
19
|
readonly dependencies: {
|
|
18
20
|
readonly "lit-scientific-visualization": ReturnType<typeof inspectScientificVisualizationDependencies>;
|
|
19
21
|
};
|
|
22
|
+
readonly link?: NativeSkillsRootLink;
|
|
23
|
+
readonly shadowedSkills: readonly ShadowedSkill[];
|
|
20
24
|
readonly ok: boolean;
|
|
21
25
|
};
|
|
22
|
-
export
|
|
26
|
+
export type InspectNativeSkillsOptions = {
|
|
27
|
+
readonly homeDir?: string;
|
|
28
|
+
readonly workDir?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function inspectNativeSkills(root: string, metadata: PackageMetadata, options?: InspectNativeSkillsOptions): Promise<NativeSkillInspection>;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { litOpenCodeRuntimeSkills } from "../skills.js";
|
|
3
|
-
import { destinationState, assertInstalledCanonicalOwnership, invalidInstalledAssets, validateSkillSource } from "./native-skill-integrity.js";
|
|
3
|
+
import { destinationState, assertInstalledCanonicalOwnership, detectShadowedSkills, invalidInstalledAssets, nativeSkillsRoot, nativeSkillsRootLink, validateSkillSource } from "./native-skill-integrity.js";
|
|
4
4
|
import { inspectScientificVisualizationDependencies } from "./scientific-visualization-dependencies.js";
|
|
5
5
|
export { validateManagedSkillSource } from "./native-skill-integrity.js";
|
|
6
6
|
export { ensureNativeSkills } from "./native-skill-install.js";
|
|
7
|
+
// nativeSkillsRoot() follows the same intentional-symlink resolution install uses; if it fails,
|
|
8
|
+
// fall back to the unresolved path so link/shadow reporting stays best-effort instead of throwing.
|
|
9
|
+
async function bestEffortNativeSkillsRoot(root) {
|
|
10
|
+
try {
|
|
11
|
+
return await nativeSkillsRoot(root);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return path.join(root, "skills");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
7
17
|
export async function describeNativeSkillMutation(root, metadata) {
|
|
8
18
|
const write = [];
|
|
9
19
|
const preserve = [];
|
|
@@ -21,15 +31,17 @@ export async function describeNativeSkillMutation(root, metadata) {
|
|
|
21
31
|
collisions.push(skill.id);
|
|
22
32
|
}
|
|
23
33
|
}
|
|
34
|
+
const link = await nativeSkillsRootLink(root);
|
|
24
35
|
return {
|
|
25
36
|
path: path.join(root, "skills"),
|
|
26
37
|
changed: write.length > 0,
|
|
27
38
|
write,
|
|
28
39
|
preserve,
|
|
29
|
-
collisions
|
|
40
|
+
collisions,
|
|
41
|
+
...(link === undefined ? {} : { link })
|
|
30
42
|
};
|
|
31
43
|
}
|
|
32
|
-
export async function inspectNativeSkills(root, metadata) {
|
|
44
|
+
export async function inspectNativeSkills(root, metadata, options = {}) {
|
|
33
45
|
const present = [];
|
|
34
46
|
const missing = [];
|
|
35
47
|
const managed = [];
|
|
@@ -88,6 +100,8 @@ export async function inspectNativeSkills(root, metadata) {
|
|
|
88
100
|
}
|
|
89
101
|
}
|
|
90
102
|
const uniqueInvalid = [...new Set(invalid)];
|
|
103
|
+
const link = await nativeSkillsRootLink(root, options.homeDir);
|
|
104
|
+
const shadowedSkills = await detectShadowedSkills(litOpenCodeRuntimeSkills.map((skill) => skill.id), await bestEffortNativeSkillsRoot(root), options.homeDir, options.workDir);
|
|
91
105
|
return {
|
|
92
106
|
path: path.join(root, "skills"),
|
|
93
107
|
expected: litOpenCodeRuntimeSkills.map((skill) => skill.id),
|
|
@@ -100,6 +114,8 @@ export async function inspectNativeSkills(root, metadata) {
|
|
|
100
114
|
sourceInvalid,
|
|
101
115
|
canonicalCacheFiles,
|
|
102
116
|
dependencies: { "lit-scientific-visualization": inspectScientificVisualizationDependencies() },
|
|
117
|
+
...(link === undefined ? {} : { link }),
|
|
118
|
+
shadowedSkills,
|
|
103
119
|
ok: missing.length === 0 && uniqueInvalid.length === 0
|
|
104
120
|
};
|
|
105
121
|
}
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -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;
|
|
@@ -167,6 +167,11 @@ export type InstallReport = {
|
|
|
167
167
|
readonly write: readonly string[];
|
|
168
168
|
readonly preserve: readonly string[];
|
|
169
169
|
readonly collisions: readonly string[];
|
|
170
|
+
readonly link?: {
|
|
171
|
+
readonly path: string;
|
|
172
|
+
readonly target: string;
|
|
173
|
+
readonly gitRepositoryRoot?: string;
|
|
174
|
+
};
|
|
170
175
|
};
|
|
171
176
|
readonly hostLimits: {
|
|
172
177
|
readonly path: string;
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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:
|
|
88
|
-
"
|
|
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
|
-
"
|
|
92
|
-
" Without flags/reset, planning and review (including lit-loop) use Astra/xhigh; execution and research helpers use
|
|
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:",
|
package/dist/config-parser.js
CHANGED
|
@@ -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(
|
|
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
|
|
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:
|
|
27
|
-
model:
|
|
28
|
-
variant:
|
|
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:
|
|
33
|
-
model:
|
|
34
|
-
variant:
|
|
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:
|
|
39
|
-
model:
|
|
40
|
-
variant:
|
|
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:
|
|
45
|
-
model:
|
|
46
|
-
variant:
|
|
45
|
+
provider: defaultOpenAiRoutes.helper.provider,
|
|
46
|
+
model: defaultOpenAiRoutes.helper.model,
|
|
47
|
+
variant: defaultOpenAiRoutes.helper.effort,
|
|
47
48
|
textVerbosity: "medium"
|
|
48
49
|
})
|
|
49
50
|
}),
|
package/dist/features.d.ts
CHANGED
|
@@ -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
|
};
|