@lark-project/cli
Version:
飞书项目插件开发工具
73 lines (72 loc) • 4.71 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initConfigOnlyProject = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = require("fs-extra");
const logger_1 = require("../../../utils/logger");
const utils_1 = require("../../../v1/utils");
const local_plugin_config_1 = require("../../../local-plugin-config");
const is_empty_dir_1 = require("../../../utils/is-empty-dir");
const workspace_1 = require("../../utils/workspace");
const resolve_workspace_context_1 = require("../../../utils/resolve-workspace-context");
/**
* 为"后端代码在独立仓、没有 plugin.config.json"的开发者建一个 config-only 工作区:
* 只写一份最小 plugin.config.json(身份 + app_type + 空 resources),不铺前端代码、不装依赖。
* 之后 `lpm local-config get/set` / `perm` / `update` 都能在它里面跑。
*
* 目录名固定为 `meegle-plugin-config`(不接受自定义),让 skill 的 `lpm check context`
* 能稳定识别它。幂等:已存在合法 handle 时复用、不覆盖。
*/
function initConfigOnlyProject(options, cwd = process.cwd()) {
const { pluginId, pluginSecret, siteDomain, appType } = options;
const targetDir = path_1.default.join(cwd, resolve_workspace_context_1.BACKEND_HANDLE_DIRNAME);
const pluginConfigPath = path_1.default.join(targetDir, 'plugin.config.json');
if ((0, fs_extra_1.existsSync)(pluginConfigPath)) {
const existing = (0, fs_extra_1.readJSONSync)(pluginConfigPath);
if ((0, local_plugin_config_1.isValidPluginConfig)(existing)[0]) {
if (existing.pluginId === pluginId) {
logger_1.logger.info(`Config-only workspace already exists at ${targetDir} — reusing it (not overwritten). ` +
'Run `lpm local-config get --remote` inside it to refresh the point config.');
return;
}
// pluginId 不一致 → 以用户输入为准,清掉旧锚(含旧插件的 .lpm-cache / point.config.local.json)
// 给新插件干净重建,避免旧插件的工作态泄漏进新插件的推送。
logger_1.logger.info(`Config-only workspace was for ${existing.pluginId}; re-initializing for ${pluginId} (user input wins).`);
(0, fs_extra_1.removeSync)(targetDir);
}
}
if ((0, fs_extra_1.existsSync)(targetDir) && !(0, is_empty_dir_1.isEmptyDir)(targetDir)) {
throw new Error(`Target directory "${targetDir}" already exists and is not empty, but has no valid plugin.config.json. ` +
'Refusing to overwrite. Remove it manually and retry, or cd into it if it is already a workspace.');
}
(0, fs_extra_1.mkdirpSync)(targetDir);
const pluginConfig = {
siteDomain,
pluginId,
pluginSecret: (0, utils_1.encrypt)(pluginSecret),
resources: [],
app_type: appType,
backendOnly: true,
};
(0, fs_extra_1.writeJSONSync)(pluginConfigPath, pluginConfig, { spaces: 2 });
(0, workspace_1.ensureWorkspace)(targetDir);
(0, workspace_1.ensureGitignore)(targetDir);
logger_1.logger.success(`🍻 Config-only workspace created at ${targetDir} (app_type=${appType}).`);
// 完整点位配置链路:仅打印到 `get` 会让调用方(尤其 AI agent)误以为读完远端就完事,
// 把点位塞进 plugin.config.json 之类的歧路(CLI 不读、永不生效)。这里把"写 + 推"两步显式带出来:
// get(读基线) → set --from(校验并写 point.config.local.json,仅本地) → update(推平台)。
// eslint-disable-next-line no-console
console.log(`Step 1: cd ${resolve_workspace_context_1.BACKEND_HANDLE_DIRNAME}`);
// eslint-disable-next-line no-console
console.log('Step 2: lpm local-config get --remote # snapshot current points → .lpm-cache/config/remote.json ({} = none configured yet)');
// eslint-disable-next-line no-console
console.log('Step 3: lpm ai init-draft # copy the remote.json baseline above → a draft-*.json (full config), then edit it — `lpm schema` shows the field spec');
// eslint-disable-next-line no-console
console.log('Step 4: lpm local-config set --from <draft-*.json> # validate + write point.config.local.json locally (NOT pushed; do NOT hand-edit plugin.config.json for points)');
// eslint-disable-next-line no-console
console.log('Step 5: lpm update --source-type=local # push the config to the platform');
}
exports.initConfigOnlyProject = initConfigOnlyProject;