refactor(credentials): remove skills.env.json5 support
Remove centralized skills.env.json5 in favor of per-skill .env files. Clean up CredentialManager by removing hasEnv/getEnv/getResolvedEnvSnapshot methods and skills env loading. Update CLI credentials and skills commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9f98ccca58
commit
bd0b380e2e
6 changed files with 47 additions and 264 deletions
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import { existsSync, mkdirSync, writeFileSync, chmodSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
import { getCredentialsPath, getSkillsEnvPath } from "@multica/core";
|
||||
import { getCredentialsPath } from "@multica/core";
|
||||
import { cyan, yellow, green, dim, red } from "../colors.js";
|
||||
|
||||
type Command = "init" | "show" | "edit" | "help";
|
||||
|
|
@ -17,10 +17,7 @@ type Command = "init" | "show" | "edit" | "help";
|
|||
interface CredentialsOptions {
|
||||
command: Command;
|
||||
force: boolean;
|
||||
coreOnly: boolean;
|
||||
skillsOnly: boolean;
|
||||
pathOverride?: string | undefined;
|
||||
skillsPathOverride?: string | undefined;
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
|
|
@ -28,21 +25,20 @@ function printHelp() {
|
|||
${cyan("Usage:")} multica credentials <command> [options]
|
||||
|
||||
${cyan("Commands:")}
|
||||
${yellow("init")} Create credentials.json5 and skills.env.json5
|
||||
${yellow("init")} Create credentials.json5
|
||||
${yellow("show")} Show credential file paths
|
||||
${yellow("edit")} Open credentials directory in file manager
|
||||
${yellow("help")} Show this help
|
||||
|
||||
${cyan("Options for 'init':")}
|
||||
${yellow("--force")} Overwrite existing files
|
||||
${yellow("--core-only")} Only create credentials.json5
|
||||
${yellow("--skills-only")} Only create skills.env.json5
|
||||
${yellow("--path")} PATH Override credentials path
|
||||
${yellow("--skills-path")} PATH Override skills env path
|
||||
|
||||
${cyan("Files Created:")}
|
||||
~/.super-multica/credentials.json5 LLM providers + tools config
|
||||
~/.super-multica/skills.env.json5 Skills/plugins/integrations env vars
|
||||
|
||||
${dim("Skill-specific API keys are stored in .env files within each skill's directory.")}
|
||||
${dim("Example: ~/.super-multica/skills/<skill-id>/.env")}
|
||||
|
||||
${cyan("Examples:")}
|
||||
${dim("# Initialize credentials")}
|
||||
|
|
@ -50,9 +46,6 @@ ${cyan("Examples:")}
|
|||
|
||||
${dim("# Force overwrite")}
|
||||
multica credentials init --force
|
||||
|
||||
${dim("# Only create core credentials")}
|
||||
multica credentials init --core-only
|
||||
`);
|
||||
}
|
||||
|
||||
|
|
@ -61,8 +54,6 @@ function parseArgs(argv: string[]): CredentialsOptions {
|
|||
const opts: CredentialsOptions = {
|
||||
command: "help",
|
||||
force: false,
|
||||
coreOnly: false,
|
||||
skillsOnly: false,
|
||||
};
|
||||
|
||||
const positional: string[] = [];
|
||||
|
|
@ -79,22 +70,10 @@ function parseArgs(argv: string[]): CredentialsOptions {
|
|||
opts.force = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--core-only") {
|
||||
opts.coreOnly = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--skills-only") {
|
||||
opts.skillsOnly = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--path") {
|
||||
opts.pathOverride = args.shift();
|
||||
continue;
|
||||
}
|
||||
if (arg === "--skills-path") {
|
||||
opts.skillsPathOverride = args.shift();
|
||||
continue;
|
||||
}
|
||||
positional.push(arg);
|
||||
}
|
||||
|
||||
|
|
@ -119,58 +98,25 @@ function buildCoreTemplate(): string {
|
|||
`;
|
||||
}
|
||||
|
||||
function buildSkillsTemplate(): string {
|
||||
return `{
|
||||
env: {
|
||||
// Dynamic keys (skills, plugins, integrations)
|
||||
// LINEAR_API_KEY: "lin-..."
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function cmdInit(opts: CredentialsOptions): void {
|
||||
const createCore = !opts.skillsOnly;
|
||||
const createSkills = !opts.coreOnly;
|
||||
|
||||
if (!createCore && !createSkills) {
|
||||
console.error(`${red("Error:")} Both --core-only and --skills-only were provided.`);
|
||||
const path = opts.pathOverride ?? getCredentialsPath();
|
||||
if (existsSync(path) && !opts.force) {
|
||||
console.error(`${red("Error:")} Credentials file already exists at ${path}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (createCore) {
|
||||
const path = opts.pathOverride ?? getCredentialsPath();
|
||||
if (existsSync(path) && !opts.force) {
|
||||
console.error(`${red("Error:")} Credentials file already exists at ${path}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, buildCoreTemplate(), "utf8");
|
||||
chmodSync(path, 0o600);
|
||||
console.log(`${green("Created:")} ${path}`);
|
||||
}
|
||||
|
||||
if (createSkills) {
|
||||
const skillsPath = opts.skillsPathOverride ?? getSkillsEnvPath();
|
||||
if (existsSync(skillsPath) && !opts.force) {
|
||||
console.error(`${red("Error:")} Skills env file already exists at ${skillsPath}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
mkdirSync(dirname(skillsPath), { recursive: true });
|
||||
writeFileSync(skillsPath, buildSkillsTemplate(), "utf8");
|
||||
chmodSync(skillsPath, 0o600);
|
||||
console.log(`${green("Created:")} ${skillsPath}`);
|
||||
}
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, buildCoreTemplate(), "utf8");
|
||||
chmodSync(path, 0o600);
|
||||
console.log(`${green("Created:")} ${path}`);
|
||||
|
||||
console.log("");
|
||||
console.log("Edit these files to add your credentials.");
|
||||
console.log("Edit this file to add your LLM provider credentials.");
|
||||
console.log(`${dim("Skill-specific API keys go in .env files within each skill's directory.")}`);
|
||||
}
|
||||
|
||||
function cmdShow(): void {
|
||||
const credentialsPath = getCredentialsPath();
|
||||
const skillsEnvPath = getSkillsEnvPath();
|
||||
|
||||
console.log(`\n${cyan("Credential Files:")}\n`);
|
||||
|
||||
|
|
@ -179,12 +125,10 @@ function cmdShow(): void {
|
|||
console.log(` Exists: ${existsSync(credentialsPath) ? green("Yes") : red("No")}`);
|
||||
console.log("");
|
||||
|
||||
console.log(`${yellow("skills.env.json5")}`);
|
||||
console.log(` Path: ${skillsEnvPath}`);
|
||||
console.log(` Exists: ${existsSync(skillsEnvPath) ? green("Yes") : red("No")}`);
|
||||
console.log(`${dim("Skill-specific API keys are stored in .env files within each skill's directory.")}`);
|
||||
console.log("");
|
||||
|
||||
if (!existsSync(credentialsPath) || !existsSync(skillsEnvPath)) {
|
||||
if (!existsSync(credentialsPath)) {
|
||||
console.log(`${dim("Run 'multica credentials init' to create missing files.")}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import {
|
|||
checkEligibilityDetailed,
|
||||
type DiagnosticItem,
|
||||
} from "@multica/core";
|
||||
import { credentialManager } from "@multica/core";
|
||||
import { cyan, yellow, green, dim, red } from "../colors.js";
|
||||
|
||||
type Command = "list" | "status" | "install" | "add" | "remove" | "help";
|
||||
|
|
@ -268,7 +267,7 @@ function cmdStatusDetail(manager: SkillManager, skillId: string, verbose?: boole
|
|||
|
||||
if (hasEnvs > 0) {
|
||||
const envs = requirements?.env ?? metadata?.requiresEnv ?? [];
|
||||
printRequirementStatus("Environment vars", envs, checkEnvVars);
|
||||
printRequirementStatus("Environment vars", envs, (e) => checkEnvVars(e, skill.env));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,10 +359,11 @@ function checkBinaries(bins: string[]): Map<string, boolean> {
|
|||
return result;
|
||||
}
|
||||
|
||||
function checkEnvVars(envs: string[]): Map<string, boolean> {
|
||||
function checkEnvVars(envs: string[], skillEnv: Record<string, string>): Map<string, boolean> {
|
||||
const result = new Map<string, boolean>();
|
||||
for (const env of envs) {
|
||||
result.set(env, credentialManager.hasEnv(env));
|
||||
const found = Object.prototype.hasOwnProperty.call(skillEnv, env) || env in process.env;
|
||||
result.set(env, found);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import {
|
|||
checkEligibilityDetailed,
|
||||
type DiagnosticItem,
|
||||
} from "@multica/core";
|
||||
import { credentialManager } from "@multica/core";
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
|
|
@ -268,7 +267,7 @@ function cmdStatusDetail(manager: SkillManager, skillId: string, verbose?: boole
|
|||
|
||||
if (hasEnvs > 0) {
|
||||
const envs = requirements?.env ?? metadata?.requiresEnv ?? [];
|
||||
printRequirementStatus("Environment vars", envs, checkEnvVars);
|
||||
printRequirementStatus("Environment vars", envs, (e) => checkEnvVars(e, skill.env));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,10 +362,11 @@ function checkBinaries(bins: string[]): Map<string, boolean> {
|
|||
return result;
|
||||
}
|
||||
|
||||
function checkEnvVars(envs: string[]): Map<string, boolean> {
|
||||
function checkEnvVars(envs: string[], skillEnv: Record<string, string>): Map<string, boolean> {
|
||||
const result = new Map<string, boolean>();
|
||||
for (const env of envs) {
|
||||
result.set(env, credentialManager.hasEnv(env));
|
||||
const found = Object.prototype.hasOwnProperty.call(skillEnv, env) || env in process.env;
|
||||
result.set(env, found);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
* Credentials CLI
|
||||
*
|
||||
* Commands:
|
||||
* init Create credentials.json5 and skills.env.json5
|
||||
* init Create credentials.json5
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, writeFileSync, chmodSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
import { getCredentialsPath, getSkillsEnvPath } from "./credentials.js";
|
||||
import { getCredentialsPath } from "./credentials.js";
|
||||
|
||||
type Command = "init" | "help";
|
||||
|
||||
|
|
@ -16,21 +16,19 @@ function printUsage(): void {
|
|||
console.log("Usage: pnpm credentials:cli <command> [options]");
|
||||
console.log("");
|
||||
console.log("Commands:");
|
||||
console.log(" init Create credentials.json5 and skills.env.json5 (empty templates)");
|
||||
console.log(" init Create credentials.json5 (empty template)");
|
||||
console.log(" help Show this help");
|
||||
console.log("");
|
||||
console.log("Options:");
|
||||
console.log(" --force Overwrite existing files");
|
||||
console.log(" --core-only Only create credentials.json5");
|
||||
console.log(" --skills-only Only create skills.env.json5");
|
||||
console.log(" --path Override credentials path (SMC_CREDENTIALS_PATH)");
|
||||
console.log(" --skills-path Override skills env path (SMC_SKILLS_ENV_PATH)");
|
||||
console.log("");
|
||||
console.log("Skill-specific API keys are stored in .env files within each skill's directory.");
|
||||
console.log("Example: ~/.super-multica/skills/<skill-id>/.env");
|
||||
console.log("");
|
||||
console.log("Examples:");
|
||||
console.log(" pnpm credentials:cli init");
|
||||
console.log(" pnpm credentials:cli init --force");
|
||||
console.log(" pnpm credentials:cli init --core-only");
|
||||
console.log(" pnpm credentials:cli init --skills-only");
|
||||
}
|
||||
|
||||
function buildCoreTemplate(): string {
|
||||
|
|
@ -51,23 +49,10 @@ function buildCoreTemplate(): string {
|
|||
`;
|
||||
}
|
||||
|
||||
function buildSkillsTemplate(): string {
|
||||
return `{
|
||||
env: {
|
||||
// Dynamic keys (skills, plugins, integrations)
|
||||
// LINEAR_API_KEY: "lin-..."
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function parseArgs(argv: string[]) {
|
||||
const args = [...argv];
|
||||
let force = false;
|
||||
let pathOverride: string | undefined;
|
||||
let skillsPathOverride: string | undefined;
|
||||
let coreOnly = false;
|
||||
let skillsOnly = false;
|
||||
const positional: string[] = [];
|
||||
|
||||
while (args.length > 0) {
|
||||
|
|
@ -77,76 +62,42 @@ function parseArgs(argv: string[]) {
|
|||
force = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--core-only") {
|
||||
coreOnly = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--skills-only") {
|
||||
skillsOnly = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--path") {
|
||||
pathOverride = args.shift();
|
||||
continue;
|
||||
}
|
||||
if (arg === "--skills-path") {
|
||||
skillsPathOverride = args.shift();
|
||||
continue;
|
||||
}
|
||||
if (arg === "--help" || arg === "-h") {
|
||||
return { command: "help" as Command, force, pathOverride, skillsPathOverride, coreOnly, skillsOnly };
|
||||
return { command: "help" as Command, force, pathOverride };
|
||||
}
|
||||
positional.push(arg);
|
||||
}
|
||||
|
||||
const command = (positional[0] || "help") as Command;
|
||||
return { command, force, pathOverride, skillsPathOverride, coreOnly, skillsOnly };
|
||||
return { command, force, pathOverride };
|
||||
}
|
||||
|
||||
function cmdInit(force: boolean, pathOverride?: string, skillsPathOverride?: string, coreOnly?: boolean, skillsOnly?: boolean): void {
|
||||
const createCore = skillsOnly ? false : true;
|
||||
const createSkills = coreOnly ? false : true;
|
||||
|
||||
if (!createCore && !createSkills) {
|
||||
console.error("Error: both --core-only and --skills-only were provided.");
|
||||
function cmdInit(force: boolean, pathOverride?: string): void {
|
||||
const path = pathOverride ?? getCredentialsPath();
|
||||
if (existsSync(path) && !force) {
|
||||
console.error(`Error: credentials file already exists at ${path}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, buildCoreTemplate(), "utf8");
|
||||
chmodSync(path, 0o600);
|
||||
console.log(`Created: ${path}`);
|
||||
|
||||
if (createCore) {
|
||||
const path = pathOverride ?? getCredentialsPath();
|
||||
if (existsSync(path) && !force) {
|
||||
console.error(`Error: credentials file already exists at ${path}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, buildCoreTemplate(), "utf8");
|
||||
chmodSync(path, 0o600);
|
||||
console.log(`Created: ${path}`);
|
||||
}
|
||||
|
||||
if (createSkills) {
|
||||
const skillsPath = skillsPathOverride ?? getSkillsEnvPath();
|
||||
if (existsSync(skillsPath) && !force) {
|
||||
console.error(`Error: skills env file already exists at ${skillsPath}`);
|
||||
console.error("Use --force to overwrite.");
|
||||
process.exit(1);
|
||||
}
|
||||
mkdirSync(dirname(skillsPath), { recursive: true });
|
||||
writeFileSync(skillsPath, buildSkillsTemplate(), "utf8");
|
||||
chmodSync(skillsPath, 0o600);
|
||||
console.log(`Created: ${skillsPath}`);
|
||||
}
|
||||
|
||||
console.log("Edit these files to add your credentials.");
|
||||
console.log("Edit this file to add your credentials.");
|
||||
console.log("Skill-specific API keys go in .env files within each skill's directory.");
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { command, force, pathOverride, skillsPathOverride, coreOnly, skillsOnly } = parseArgs(process.argv.slice(2));
|
||||
const { command, force, pathOverride } = parseArgs(process.argv.slice(2));
|
||||
|
||||
switch (command) {
|
||||
case "init":
|
||||
cmdInit(force, pathOverride, skillsPathOverride, coreOnly, skillsOnly);
|
||||
cmdInit(force, pathOverride);
|
||||
break;
|
||||
case "help":
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -35,12 +35,7 @@ export type CredentialsConfig = {
|
|||
channels?: Record<string, Record<string, Record<string, unknown>> | undefined> | undefined;
|
||||
};
|
||||
|
||||
type SkillsEnvConfig = {
|
||||
env?: Record<string, string> | undefined;
|
||||
};
|
||||
|
||||
const DEFAULT_CREDENTIALS_PATH = join(DATA_DIR, "credentials.json5");
|
||||
const DEFAULT_SKILLS_ENV_PATH = join(DATA_DIR, "skills.env.json5");
|
||||
|
||||
function expandHome(value: string): string {
|
||||
if (value === "~") return homedir();
|
||||
|
|
@ -58,42 +53,16 @@ function isTestEnv(): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
function isString(value: unknown): value is string {
|
||||
return typeof value === "string";
|
||||
}
|
||||
|
||||
function setEnvValue(target: Record<string, string>, key: string, value: unknown): void {
|
||||
if (isString(value)) {
|
||||
target[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function applyEnvMap(target: Record<string, string>, env?: Record<string, string>): void {
|
||||
if (!env) return;
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
setEnvValue(target, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCredentialsPath(): string {
|
||||
const raw = process.env.SMC_CREDENTIALS_PATH ?? DEFAULT_CREDENTIALS_PATH;
|
||||
return expandHome(raw);
|
||||
}
|
||||
|
||||
export function getSkillsEnvPath(): string {
|
||||
const raw = process.env.SMC_SKILLS_ENV_PATH ?? DEFAULT_SKILLS_ENV_PATH;
|
||||
return expandHome(raw);
|
||||
}
|
||||
|
||||
export class CredentialManager {
|
||||
private corePath: string | null = null;
|
||||
private skillsPath: string | null = null;
|
||||
private disabledState: boolean | null = null;
|
||||
private coreConfig: CredentialsConfig | null = null;
|
||||
private skillsConfig: SkillsEnvConfig | null = null;
|
||||
private resolvedSkillsEnv: Record<string, string> | null = null;
|
||||
private coreMtimeMs: number | null = null;
|
||||
private skillsMtimeMs: number | null = null;
|
||||
|
||||
private isDisabled(): boolean {
|
||||
if (process.env.SMC_CREDENTIALS_DISABLE === "1") return true;
|
||||
|
|
@ -139,63 +108,6 @@ export class CredentialManager {
|
|||
}
|
||||
}
|
||||
|
||||
private loadSkillsEnv(): void {
|
||||
const path = getSkillsEnvPath();
|
||||
const disabled = this.isDisabled();
|
||||
let mtimeMs: number | null = null;
|
||||
|
||||
if (!disabled && existsSync(path)) {
|
||||
try {
|
||||
mtimeMs = statSync(path).mtimeMs;
|
||||
} catch {
|
||||
mtimeMs = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.skillsPath === path
|
||||
&& this.disabledState === disabled
|
||||
&& this.resolvedSkillsEnv
|
||||
&& this.skillsMtimeMs === mtimeMs
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.skillsPath = path;
|
||||
this.disabledState = disabled;
|
||||
this.skillsConfig = null;
|
||||
this.resolvedSkillsEnv = null;
|
||||
this.skillsMtimeMs = mtimeMs;
|
||||
|
||||
if (disabled) return;
|
||||
if (mtimeMs === null) return;
|
||||
|
||||
const raw = readFileSync(path, "utf8");
|
||||
try {
|
||||
this.skillsConfig = JSON5.parse(raw) as SkillsEnvConfig;
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`Failed to parse skills env file (${path}): ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private buildSkillsEnv(): Record<string, string> {
|
||||
const env: Record<string, string> = {};
|
||||
if (!this.skillsConfig) return env;
|
||||
|
||||
applyEnvMap(env, this.skillsConfig.env);
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
private getResolvedSkillsEnv(): Record<string, string> {
|
||||
this.loadSkillsEnv();
|
||||
if (!this.resolvedSkillsEnv) {
|
||||
this.resolvedSkillsEnv = this.buildSkillsEnv();
|
||||
}
|
||||
return this.resolvedSkillsEnv;
|
||||
}
|
||||
|
||||
getLlmProvider(): string | undefined {
|
||||
this.loadCore();
|
||||
return this.coreConfig?.llm?.provider;
|
||||
|
|
@ -211,22 +123,6 @@ export class CredentialManager {
|
|||
return this.coreConfig?.tools?.[toolName];
|
||||
}
|
||||
|
||||
getEnv(name: string): string | undefined {
|
||||
const resolved = this.getResolvedSkillsEnv();
|
||||
if (Object.prototype.hasOwnProperty.call(resolved, name)) {
|
||||
return resolved[name];
|
||||
}
|
||||
return process.env[name];
|
||||
}
|
||||
|
||||
hasEnv(name: string): boolean {
|
||||
const resolved = this.getResolvedSkillsEnv();
|
||||
if (Object.prototype.hasOwnProperty.call(resolved, name)) {
|
||||
return true;
|
||||
}
|
||||
return name in process.env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get explicit profile order for a provider from credentials.json5 `llm.order`.
|
||||
* Returns undefined if no explicit order is configured.
|
||||
|
|
@ -257,19 +153,11 @@ export class CredentialManager {
|
|||
return this.coreConfig?.channels ?? {};
|
||||
}
|
||||
|
||||
getResolvedEnvSnapshot(): Record<string, string> {
|
||||
return { ...this.getResolvedSkillsEnv() };
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.corePath = null;
|
||||
this.skillsPath = null;
|
||||
this.disabledState = null;
|
||||
this.coreConfig = null;
|
||||
this.skillsConfig = null;
|
||||
this.resolvedSkillsEnv = null;
|
||||
this.coreMtimeMs = null;
|
||||
this.skillsMtimeMs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export * from "./skills/index.js";
|
|||
export * from "./channel.js";
|
||||
export * from "./sync-agent.js";
|
||||
export * from "./async-agent.js";
|
||||
export { credentialManager, getCredentialsPath, getSkillsEnvPath, type CredentialsConfig } from "./credentials.js";
|
||||
export { credentialManager, getCredentialsPath, type CredentialsConfig } from "./credentials.js";
|
||||
export * from "./providers/index.js";
|
||||
export * from "./tools.js";
|
||||
export * from "./tools/policy.js";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue