SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
68d7816 verified
Raw History Blame Contribute Delete
5.61 kB
import { mkdirSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'pathe';
import type { KimiHostIdentity } from '@moonshot-ai/kimi-code-oauth';
import { SyncDescriptor } from '#/_base/di/descriptors';
import { createDecorator, type ServiceIdentifier } from '#/_base/di/instantiation';
import { createAppScope, type Scope, type ScopeSeed } from '#/_base/di/scope';
import {
IFileSystemStorageService,
} from '#/persistence/interface/storage';
import { FileStorageService } from '#/persistence/backends/node-fs/fileStorageService';
import { FileSkillDiscovery } from '#/features/skill/catalog/fileSkillDiscovery';
import { ISkillDiscovery } from '#/features/skill/catalog/skillDiscovery';
export type HostUiCapability = 'update_panel';
export interface HostArgs {
readonly agentFiles?: readonly string[];
readonly skillDirs?: readonly string[];
readonly requestHeaders: Readonly<Record<string, string>>;
readonly displayName?: string;
readonly replyStyleGuide?: string;
readonly nonInteractive?: boolean;
readonly uiCapabilities?: readonly HostUiCapability[];
}
export interface HostArgsInput {
readonly agentFiles?: readonly string[];
readonly skillDirs?: readonly string[];
readonly requestHeaders?: Readonly<Record<string, string>>;
readonly displayName?: string;
readonly replyStyleGuide?: string;
readonly nonInteractive?: boolean;
readonly uiCapabilities?: readonly HostUiCapability[];
}
export function resolveHostArgs(input: HostArgsInput | undefined): HostArgs {
return {
agentFiles: input?.agentFiles,
skillDirs: input?.skillDirs,
requestHeaders: input?.requestHeaders ?? {},
displayName: input?.displayName,
replyStyleGuide: input?.replyStyleGuide,
nonInteractive: input?.nonInteractive,
uiCapabilities: input?.uiCapabilities,
};
}
export interface IBootstrapOptions {
readonly homeDir: string;
readonly configPath: string;
readonly osHomeDir: string;
readonly platform: NodeJS.Platform;
readonly arch: string;
readonly cwd: string;
readonly env: NodeJS.ProcessEnv;
readonly clientIdentity: KimiHostIdentity;
readonly args: HostArgs;
}
export const IBootstrapOptions: ServiceIdentifier<IBootstrapOptions> =
createDecorator<IBootstrapOptions>('bootstrapOptions');
export type PersistenceScopeName =
| 'config'
| 'sessions'
| 'blobs'
| 'store'
| 'logs'
| 'cache'
| 'credentials';
export interface IBootstrapService {
readonly _serviceBrand: undefined;
readonly platform: NodeJS.Platform;
readonly arch: string;
readonly cwd: string;
readonly osHomeDir: string;
readonly homeDir: string;
readonly configPath: string;
readonly clientIdentity: KimiHostIdentity;
readonly args: HostArgs;
readonly sessionsDir: string;
readonly blobsDir: string;
readonly storeDir: string;
readonly cacheDir: string;
readonly logsDir: string;
getEnv(name: string): string | undefined;
scope(name: PersistenceScopeName): string;
readonly configKey: string;
}
export const IBootstrapService: ServiceIdentifier<IBootstrapService> =
createDecorator<IBootstrapService>('bootstrapService');
export interface BootstrapInput {
readonly homeDir?: string;
readonly configPath?: string;
readonly env?: NodeJS.ProcessEnv;
readonly osHomeDir?: string;
readonly platform?: NodeJS.Platform;
readonly arch?: string;
readonly cwd?: string;
readonly clientIdentity: KimiHostIdentity;
readonly args?: HostArgsInput;
}
export function resolveBootstrapOptions(input: BootstrapInput): IBootstrapOptions {
const env = input.env ?? process.env;
const osHomeDir = input.osHomeDir ?? homedir();
const homeDir = resolveKimiHome(input.homeDir, env, osHomeDir);
const configPath = input.configPath ?? join(homeDir, 'config.toml');
return {
homeDir,
configPath,
osHomeDir,
platform: input.platform ?? process.platform,
arch: input.arch ?? process.arch,
cwd: input.cwd ?? process.cwd(),
env,
clientIdentity: input.clientIdentity,
args: resolveHostArgs(input.args),
};
}
export function bootstrapSeed(input: BootstrapInput): ScopeSeed {
return [
[
IBootstrapOptions as ServiceIdentifier<unknown>,
resolveBootstrapOptions(input),
],
];
}
export interface BootstrapResult {
readonly app: Scope;
}
export function bootstrap(input: BootstrapInput, extraSeeds: ScopeSeed = []): BootstrapResult {
const options = resolveBootstrapOptions(input);
const app = createAppScope({
seeds: [...bootstrapSeed(input), ...storageSeed(options), ...skillSeed(), ...extraSeeds],
});
return { app };
}
function storageSeed(options: IBootstrapOptions): ScopeSeed {
const file = (): SyncDescriptor<IFileSystemStorageService> =>
new SyncDescriptor(FileStorageService, [options.homeDir, 0o700, 0o600]);
return [
[IFileSystemStorageService as ServiceIdentifier<unknown>, file()],
];
}
function skillSeed(): ScopeSeed {
return [
[
ISkillDiscovery as ServiceIdentifier<unknown>,
new SyncDescriptor(FileSkillDiscovery, []),
],
];
}
export function resolveKimiHome(
homeDir?: string,
env: NodeJS.ProcessEnv = process.env,
osHomeDir: string = homedir(),
): string {
return homeDir ?? env['KIMI_CODE_HOME'] ?? join(osHomeDir, '.kimi-code');
}
export function resolveConfigPath(input: {
readonly homeDir?: string;
readonly configPath?: string;
}): string {
return input.configPath ?? join(resolveKimiHome(input.homeDir), 'config.toml');
}
export function ensureKimiHome(homeDir: string): void {
mkdirSync(homeDir, { recursive: true, mode: 0o700 });
}