@lark-project/cli
Version:
飞书项目插件开发工具
128 lines (127 loc) • 5.97 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.archiveFile = exports.cleanWorkspace = exports.ensureGitignore = exports.ensureWorkspace = exports.assertPluginRoot = exports.workspacePaths = exports.WORKSPACE_DIR = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = require("fs-extra");
const get_project_directory_1 = require("../../utils/get-project-directory");
const logger_1 = require("../../utils/logger");
exports.WORKSPACE_DIR = '.lpm-cache';
const workspacePaths = (projectDirOverride) => {
const projectDir = projectDirOverride !== null && projectDirOverride !== void 0 ? projectDirOverride : (0, get_project_directory_1.getProjectDirectory)();
const root = path_1.default.join(projectDir, exports.WORKSPACE_DIR);
const schemaDir = path_1.default.join(root, 'schema');
const configDir = path_1.default.join(root, 'config');
const mcpDir = path_1.default.join(root, 'mcp');
return {
root,
state: path_1.default.join(root, 'state.json'),
schema: path_1.default.join(schemaDir, 'point-schema.json'),
schemaDir,
configRemote: path_1.default.join(configDir, 'remote.json'),
configLastSet: path_1.default.join(configDir, 'last-set.json'),
configDir,
historyDir: path_1.default.join(root, 'history'),
mcpDir,
configDraft: (timestamp) => path_1.default.join(configDir, `draft-${timestamp}.json`),
mcp: (slug) => path_1.default.join(mcpDir, `${slug}.md`),
relative: (absolute) => path_1.default.relative(projectDir, absolute),
};
};
exports.workspacePaths = workspacePaths;
/**
* 守卫:projectDir 必须是 plugin 工程根(含 plugin.config.json 或 manifest.json),否则 throw。
* 任何会创建 .lpm-cache 子内容的入口都应先调用此守卫,防错误目录污染(ISS-O)。
*/
const assertPluginRoot = (projectDir) => {
const hasPluginConfig = (0, fs_extra_1.existsSync)(path_1.default.join(projectDir, 'plugin.config.json')) ||
(0, fs_extra_1.existsSync)(path_1.default.join(projectDir, 'manifest.json'));
if (!hasPluginConfig) {
throw new Error(`Refusing to create ${exports.WORKSPACE_DIR}: ${projectDir} is not a plugin project root.\n` +
'Hint: cd into a plugin directory (containing plugin.config.json or manifest.json), or pass --cwd <plugin_dir>.');
}
};
exports.assertPluginRoot = assertPluginRoot;
const ensureWorkspace = (projectDirOverride) => {
const projectDir = projectDirOverride !== null && projectDirOverride !== void 0 ? projectDirOverride : (0, get_project_directory_1.getProjectDirectory)();
(0, exports.assertPluginRoot)(projectDir);
const p = (0, exports.workspacePaths)(projectDir);
(0, fs_extra_1.ensureDirSync)(p.root);
(0, fs_extra_1.ensureDirSync)(p.schemaDir);
(0, fs_extra_1.ensureDirSync)(p.configDir);
(0, fs_extra_1.ensureDirSync)(p.mcpDir);
};
exports.ensureWorkspace = ensureWorkspace;
const ensureGitignore = (projectDirOverride) => {
const projectDir = projectDirOverride !== null && projectDirOverride !== void 0 ? projectDirOverride : (0, get_project_directory_1.getProjectDirectory)();
const gitignorePath = path_1.default.join(projectDir, '.gitignore');
const line = `${exports.WORKSPACE_DIR}/`;
const block = `\n# lpm cli workspace (schema snapshots, config drafts, mcp cache)\n${line}\n`;
if (!(0, fs_extra_1.existsSync)(gitignorePath)) {
(0, fs_extra_1.writeFileSync)(gitignorePath, block.trimStart());
return;
}
const current = (0, fs_extra_1.readFileSync)(gitignorePath, 'utf8');
if (current.split('\n').some(l => l.trim() === line || l.trim() === exports.WORKSPACE_DIR)) {
return;
}
(0, fs_extra_1.appendFileSync)(gitignorePath, block);
};
exports.ensureGitignore = ensureGitignore;
const cleanWorkspace = ({ scope = 'all', keepState = true, silent = false } = {}) => {
const p = (0, exports.workspacePaths)();
if (!(0, fs_extra_1.existsSync)(p.root))
return;
const report = (target) => {
if (!silent)
logger_1.logger.info(`Cleaned ${p.relative(target)}`);
};
if (scope === 'schema') {
(0, fs_extra_1.removeSync)(p.schemaDir);
report(p.schemaDir);
return;
}
if (scope === 'config') {
(0, fs_extra_1.removeSync)(p.configDir);
report(p.configDir);
return;
}
if (scope === 'mcp') {
(0, fs_extra_1.removeSync)(p.mcpDir);
report(p.mcpDir);
return;
}
// scope === 'all'
let preservedState = null;
if (keepState && (0, fs_extra_1.existsSync)(p.state)) {
preservedState = (0, fs_extra_1.readFileSync)(p.state);
}
(0, fs_extra_1.removeSync)(p.root);
if (preservedState) {
(0, fs_extra_1.ensureDirSync)(p.root);
(0, fs_extra_1.writeFileSync)(p.state, preservedState);
}
report(p.root);
};
exports.cleanWorkspace = cleanWorkspace;
/**
* 把已消费的中间产物移出活跃目录、归档到 historyDir(保留可追溯,不硬删)。
* 文件名前缀 timestamp 避免多次 set 撞名。归档失败时兜底仍清掉源文件——
* 守住"活跃目录里不留陈旧基线/草稿"这条不变量(remote.json 留原地会坑后续 diff/删除闸口)。
*/
const archiveFile = (absolutePath, historyDir) => {
if (!(0, fs_extra_1.existsSync)(absolutePath))
return;
try {
(0, fs_extra_1.ensureDirSync)(historyDir);
(0, fs_extra_1.moveSync)(absolutePath, path_1.default.join(historyDir, `${Date.now()}-${path_1.default.basename(absolutePath)}`), {
overwrite: true,
});
}
catch (_a) {
(0, fs_extra_1.removeSync)(absolutePath);
}
};
exports.archiveFile = archiveFile;