ccem 2.27.0 → 2.28.0
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/dist/index.js +169 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,8 +7,8 @@ import inquirer from "inquirer";
|
|
|
7
7
|
import chalk7 from "chalk";
|
|
8
8
|
import Table3 from "cli-table3";
|
|
9
9
|
import { spawn as spawn3 } from "child_process";
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
10
|
+
import * as fs11 from "fs";
|
|
11
|
+
import * as path9 from "path";
|
|
12
12
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13
13
|
|
|
14
14
|
// ../../packages/core/dist/chunk-DFS6BUXP.js
|
|
@@ -979,10 +979,10 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
|
|
|
979
979
|
const parsed = new URL(url);
|
|
980
980
|
const protocol = parsed.protocol + "//";
|
|
981
981
|
const host = parsed.host;
|
|
982
|
-
const
|
|
982
|
+
const path10 = parsed.pathname + parsed.search;
|
|
983
983
|
const hostStart = host.slice(0, 8);
|
|
984
984
|
const hostEnd = host.slice(-4);
|
|
985
|
-
const pathPart =
|
|
985
|
+
const pathPart = path10.length > 10 ? path10.slice(0, 7) + "..." : path10;
|
|
986
986
|
return `${protocol}${hostStart}...${hostEnd}${pathPart}`;
|
|
987
987
|
} catch {
|
|
988
988
|
return truncate(url, max);
|
|
@@ -3165,11 +3165,61 @@ function formatCronTaskTableRows(tasks) {
|
|
|
3165
3165
|
]);
|
|
3166
3166
|
}
|
|
3167
3167
|
|
|
3168
|
+
// src/desktopControl.ts
|
|
3169
|
+
import fs10 from "fs";
|
|
3170
|
+
import path8 from "path";
|
|
3171
|
+
function getDesktopControlDescriptorPath() {
|
|
3172
|
+
return process.env.CCEM_CONTROL_FILE?.trim() || path8.join(getCcemConfigDir(), "control.json");
|
|
3173
|
+
}
|
|
3174
|
+
function resolveDesktopControlDescriptor(descriptorPath = getDesktopControlDescriptorPath()) {
|
|
3175
|
+
if (!fs10.existsSync(descriptorPath)) {
|
|
3176
|
+
throw new Error(`CCEM Desktop control endpoint not found at ${descriptorPath}. Start CCEM Desktop first.`);
|
|
3177
|
+
}
|
|
3178
|
+
const parsed = JSON.parse(fs10.readFileSync(descriptorPath, "utf-8"));
|
|
3179
|
+
const endpoint = parsed.endpoint?.trim();
|
|
3180
|
+
const token = parsed.token?.trim();
|
|
3181
|
+
if (!endpoint || !token) {
|
|
3182
|
+
throw new Error(`Invalid CCEM Desktop control descriptor at ${descriptorPath}`);
|
|
3183
|
+
}
|
|
3184
|
+
return {
|
|
3185
|
+
endpoint,
|
|
3186
|
+
token,
|
|
3187
|
+
pid: typeof parsed.pid === "number" ? parsed.pid : null
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
async function requestDesktopControl(method, params, descriptor = resolveDesktopControlDescriptor()) {
|
|
3191
|
+
const id = `ccem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3192
|
+
const response = await fetch(descriptor.endpoint, {
|
|
3193
|
+
method: "POST",
|
|
3194
|
+
headers: {
|
|
3195
|
+
authorization: `Bearer ${descriptor.token}`,
|
|
3196
|
+
"content-type": "application/json"
|
|
3197
|
+
},
|
|
3198
|
+
body: JSON.stringify({
|
|
3199
|
+
jsonrpc: "2.0",
|
|
3200
|
+
id,
|
|
3201
|
+
method,
|
|
3202
|
+
params: params ?? {}
|
|
3203
|
+
})
|
|
3204
|
+
});
|
|
3205
|
+
if (!response.ok) {
|
|
3206
|
+
throw new Error(`CCEM Desktop control request failed: HTTP ${response.status}`);
|
|
3207
|
+
}
|
|
3208
|
+
const payload = await response.json();
|
|
3209
|
+
if (payload.error) {
|
|
3210
|
+
throw new Error(payload.error.message || `CCEM Desktop control error ${payload.error.code ?? ""}`.trim());
|
|
3211
|
+
}
|
|
3212
|
+
return payload.result;
|
|
3213
|
+
}
|
|
3214
|
+
function printJson(value) {
|
|
3215
|
+
console.log(JSON.stringify(value, null, 2));
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3168
3218
|
// src/index.ts
|
|
3169
3219
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3170
|
-
var __dirname2 =
|
|
3171
|
-
var pkgPath =
|
|
3172
|
-
var pkg = JSON.parse(
|
|
3220
|
+
var __dirname2 = path9.dirname(__filename2);
|
|
3221
|
+
var pkgPath = path9.resolve(__dirname2, "..", "package.json");
|
|
3222
|
+
var pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf-8"));
|
|
3173
3223
|
var program = new Command();
|
|
3174
3224
|
var DEFAULT_OFFICIAL_ENV = {
|
|
3175
3225
|
ANTHROPIC_BASE_URL: "https://api.anthropic.com",
|
|
@@ -3225,6 +3275,29 @@ var config2 = new Conf2({
|
|
|
3225
3275
|
defaultMode: null
|
|
3226
3276
|
}
|
|
3227
3277
|
});
|
|
3278
|
+
function outputDesktopResult(value, options) {
|
|
3279
|
+
if (options.json) {
|
|
3280
|
+
printJson(value);
|
|
3281
|
+
return;
|
|
3282
|
+
}
|
|
3283
|
+
console.log(JSON.stringify(value, null, 2));
|
|
3284
|
+
}
|
|
3285
|
+
function parseOptionalBoolean(value) {
|
|
3286
|
+
if (value === void 0 || value === null) {
|
|
3287
|
+
return void 0;
|
|
3288
|
+
}
|
|
3289
|
+
if (typeof value === "boolean") {
|
|
3290
|
+
return value;
|
|
3291
|
+
}
|
|
3292
|
+
const normalized = String(value).trim().toLowerCase();
|
|
3293
|
+
if (["1", "true", "yes", "y"].includes(normalized)) {
|
|
3294
|
+
return true;
|
|
3295
|
+
}
|
|
3296
|
+
if (["0", "false", "no", "n"].includes(normalized)) {
|
|
3297
|
+
return false;
|
|
3298
|
+
}
|
|
3299
|
+
return void 0;
|
|
3300
|
+
}
|
|
3228
3301
|
var recoverRegistriesFromLegacy = (registries) => {
|
|
3229
3302
|
const currentAuthCount = Object.values(registries).filter(
|
|
3230
3303
|
(env) => Boolean(env.ANTHROPIC_AUTH_TOKEN)
|
|
@@ -3233,11 +3306,11 @@ var recoverRegistriesFromLegacy = (registries) => {
|
|
|
3233
3306
|
return registries;
|
|
3234
3307
|
}
|
|
3235
3308
|
const legacyConfigPath = getLegacyConfigPath();
|
|
3236
|
-
if (!
|
|
3309
|
+
if (!fs11.existsSync(legacyConfigPath)) {
|
|
3237
3310
|
return registries;
|
|
3238
3311
|
}
|
|
3239
3312
|
try {
|
|
3240
|
-
const legacyRaw = JSON.parse(
|
|
3313
|
+
const legacyRaw = JSON.parse(fs11.readFileSync(legacyConfigPath, "utf-8"));
|
|
3241
3314
|
const legacyRegistries = legacyRaw.registries ?? {};
|
|
3242
3315
|
let changed = false;
|
|
3243
3316
|
const recovered = { ...registries };
|
|
@@ -3431,15 +3504,15 @@ var switchEnvironment = async (name) => {
|
|
|
3431
3504
|
exportCmds.forEach((cmd) => console.log(cmd));
|
|
3432
3505
|
}
|
|
3433
3506
|
};
|
|
3434
|
-
var getSessionsFilePath = () =>
|
|
3435
|
-
var getRuntimeStateFilePath = () =>
|
|
3436
|
-
var getBotBindRequestFilePath = () =>
|
|
3507
|
+
var getSessionsFilePath = () => path9.join(getCcemConfigDir(), "sessions.json");
|
|
3508
|
+
var getRuntimeStateFilePath = () => path9.join(getCcemConfigDir(), "runtime-state.json");
|
|
3509
|
+
var getBotBindRequestFilePath = () => path9.join(getCcemConfigDir(), "bot-bind-requests.jsonl");
|
|
3437
3510
|
var parseJsonFile = (filePath) => {
|
|
3438
|
-
if (!
|
|
3511
|
+
if (!fs11.existsSync(filePath)) {
|
|
3439
3512
|
return null;
|
|
3440
3513
|
}
|
|
3441
3514
|
try {
|
|
3442
|
-
return JSON.parse(
|
|
3515
|
+
return JSON.parse(fs11.readFileSync(filePath, "utf-8"));
|
|
3443
3516
|
} catch {
|
|
3444
3517
|
return null;
|
|
3445
3518
|
}
|
|
@@ -3531,8 +3604,8 @@ var resolveBotBindRuntimeId = (explicitRuntimeId) => {
|
|
|
3531
3604
|
};
|
|
3532
3605
|
var appendBotBindRequest = (payload) => {
|
|
3533
3606
|
const requestPath = getBotBindRequestFilePath();
|
|
3534
|
-
|
|
3535
|
-
|
|
3607
|
+
fs11.mkdirSync(path9.dirname(requestPath), { recursive: true });
|
|
3608
|
+
fs11.appendFileSync(requestPath, `${JSON.stringify(payload)}
|
|
3536
3609
|
`, "utf-8");
|
|
3537
3610
|
return requestPath;
|
|
3538
3611
|
};
|
|
@@ -3907,12 +3980,12 @@ setupCmd.command("migrate").description("\u8FC1\u79FB\u65E7\u7248\u914D\u7F6E\u5
|
|
|
3907
3980
|
const newConfigPath = getCcemConfigPath();
|
|
3908
3981
|
const legacyConfigPath = getLegacyConfigPath();
|
|
3909
3982
|
console.log(chalk7.cyan("\n\u{1F504} \u914D\u7F6E\u8FC1\u79FB\n"));
|
|
3910
|
-
if (!
|
|
3983
|
+
if (!fs11.existsSync(legacyConfigPath)) {
|
|
3911
3984
|
console.log(chalk7.yellow("\u672A\u627E\u5230\u65E7\u7248\u914D\u7F6E\u6587\u4EF6"));
|
|
3912
3985
|
console.log(chalk7.gray(` \u65E7\u8DEF\u5F84: ${legacyConfigPath}`));
|
|
3913
3986
|
return;
|
|
3914
3987
|
}
|
|
3915
|
-
if (
|
|
3988
|
+
if (fs11.existsSync(newConfigPath) && !options.force) {
|
|
3916
3989
|
console.log(chalk7.green("\u2713 \u914D\u7F6E\u5DF2\u5728\u65B0\u8DEF\u5F84"));
|
|
3917
3990
|
console.log(chalk7.gray(` \u8DEF\u5F84: ${newConfigPath}`));
|
|
3918
3991
|
console.log(chalk7.gray("\n\u4F7F\u7528 --force \u5F3A\u5236\u91CD\u65B0\u8FC1\u79FB"));
|
|
@@ -3920,15 +3993,15 @@ setupCmd.command("migrate").description("\u8FC1\u79FB\u65E7\u7248\u914D\u7F6E\u5
|
|
|
3920
3993
|
}
|
|
3921
3994
|
try {
|
|
3922
3995
|
ensureCcemDir();
|
|
3923
|
-
|
|
3996
|
+
fs11.copyFileSync(legacyConfigPath, newConfigPath);
|
|
3924
3997
|
console.log(chalk7.green("\u2713 \u914D\u7F6E\u5DF2\u8FC1\u79FB"));
|
|
3925
3998
|
console.log(chalk7.gray(` \u4ECE: ${legacyConfigPath}`));
|
|
3926
3999
|
console.log(chalk7.gray(` \u5230: ${newConfigPath}`));
|
|
3927
4000
|
if (options.clean) {
|
|
3928
|
-
|
|
3929
|
-
const legacyDir =
|
|
4001
|
+
fs11.unlinkSync(legacyConfigPath);
|
|
4002
|
+
const legacyDir = path9.dirname(legacyConfigPath);
|
|
3930
4003
|
try {
|
|
3931
|
-
|
|
4004
|
+
fs11.rmdirSync(legacyDir);
|
|
3932
4005
|
} catch {
|
|
3933
4006
|
}
|
|
3934
4007
|
console.log(chalk7.green("\u2713 \u5DF2\u5220\u9664\u65E7\u914D\u7F6E\u6587\u4EF6"));
|
|
@@ -3939,13 +4012,13 @@ setupCmd.command("migrate").description("\u8FC1\u79FB\u65E7\u7248\u914D\u7F6E\u5
|
|
|
3939
4012
|
});
|
|
3940
4013
|
setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude Code\uFF08~/.claude/skills/\uFF09").option("--force", "\u5F3A\u5236\u8986\u76D6\u5DF2\u6709\u6587\u4EF6").action(async function() {
|
|
3941
4014
|
const options = this.opts();
|
|
3942
|
-
const skillDir =
|
|
3943
|
-
const targetPath =
|
|
3944
|
-
if (!
|
|
3945
|
-
|
|
4015
|
+
const skillDir = path9.join(getHomeDir(), ".claude", "skills");
|
|
4016
|
+
const targetPath = path9.join(skillDir, "ccem-cron.md");
|
|
4017
|
+
if (!fs11.existsSync(skillDir)) {
|
|
4018
|
+
fs11.mkdirSync(skillDir, { recursive: true });
|
|
3946
4019
|
console.log(chalk7.gray(`\u521B\u5EFA\u76EE\u5F55: ${skillDir}`));
|
|
3947
4020
|
}
|
|
3948
|
-
if (
|
|
4021
|
+
if (fs11.existsSync(targetPath) && !options.force) {
|
|
3949
4022
|
const { overwrite } = await inquirer.prompt([
|
|
3950
4023
|
{
|
|
3951
4024
|
type: "confirm",
|
|
@@ -3959,7 +4032,7 @@ setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude
|
|
|
3959
4032
|
return;
|
|
3960
4033
|
}
|
|
3961
4034
|
}
|
|
3962
|
-
|
|
4035
|
+
fs11.writeFileSync(targetPath, CCEM_CRON_SKILL_CONTENT, "utf-8");
|
|
3963
4036
|
console.log(chalk7.green(`\u2713 \u5DF2\u5B89\u88C5 ccem-cron skill`));
|
|
3964
4037
|
console.log(chalk7.gray(` \u8DEF\u5F84: ${targetPath}`));
|
|
3965
4038
|
console.log(chalk7.cyan(`
|
|
@@ -3967,13 +4040,13 @@ setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude
|
|
|
3967
4040
|
});
|
|
3968
4041
|
setupCmd.command("bot-bind").description("\u5B89\u88C5 ccem-bot-bind skill \u5230 Claude Code\uFF08~/.claude/skills/\uFF09").option("--force", "\u5F3A\u5236\u8986\u76D6\u5DF2\u6709\u6587\u4EF6").action(async function() {
|
|
3969
4042
|
const options = this.opts();
|
|
3970
|
-
const skillDir =
|
|
3971
|
-
const targetPath =
|
|
3972
|
-
if (!
|
|
3973
|
-
|
|
4043
|
+
const skillDir = path9.join(getHomeDir(), ".claude", "skills");
|
|
4044
|
+
const targetPath = path9.join(skillDir, "ccem-bot-bind.md");
|
|
4045
|
+
if (!fs11.existsSync(skillDir)) {
|
|
4046
|
+
fs11.mkdirSync(skillDir, { recursive: true });
|
|
3974
4047
|
console.log(chalk7.gray(`\u521B\u5EFA\u76EE\u5F55: ${skillDir}`));
|
|
3975
4048
|
}
|
|
3976
|
-
if (
|
|
4049
|
+
if (fs11.existsSync(targetPath) && !options.force) {
|
|
3977
4050
|
const { overwrite } = await inquirer.prompt([
|
|
3978
4051
|
{
|
|
3979
4052
|
type: "confirm",
|
|
@@ -3987,7 +4060,7 @@ setupCmd.command("bot-bind").description("\u5B89\u88C5 ccem-bot-bind skill \u523
|
|
|
3987
4060
|
return;
|
|
3988
4061
|
}
|
|
3989
4062
|
}
|
|
3990
|
-
|
|
4063
|
+
fs11.writeFileSync(targetPath, CCEM_BOT_BIND_SKILL_CONTENT, "utf-8");
|
|
3991
4064
|
console.log(chalk7.green(`\u2713 \u5DF2\u5B89\u88C5 ccem-bot-bind skill`));
|
|
3992
4065
|
console.log(chalk7.gray(` \u8DEF\u5F84: ${targetPath}`));
|
|
3993
4066
|
console.log(chalk7.cyan(`
|
|
@@ -4078,6 +4151,68 @@ program.command("launch").description(false).option("--env <name>", "\u73AF\u588
|
|
|
4078
4151
|
silent: true
|
|
4079
4152
|
});
|
|
4080
4153
|
});
|
|
4154
|
+
var desktopCmd = program.command("desktop").description("Control the running CCEM Desktop app");
|
|
4155
|
+
desktopCmd.command("health").description("Check the running CCEM Desktop control endpoint").option("--json", "Output JSON").action(async function() {
|
|
4156
|
+
const opts = this.opts();
|
|
4157
|
+
const result = await requestDesktopControl("ccem.health");
|
|
4158
|
+
outputDesktopResult(result, opts);
|
|
4159
|
+
});
|
|
4160
|
+
desktopCmd.command("create").description("Create a workspace session in the running CCEM Desktop app").requiredOption("--provider <provider>", "Agent provider: claude or codex").requiredOption("--cwd <path>", "Working directory").requiredOption("--prompt <text>", "Initial prompt").option("--env <name>", "Environment name").option("--perm <mode>", "Permission mode").option("--runtime-perm <mode>", "Runtime permission mode").option("--provider-session-id <id>", "Provider session id to continue").option("--effort <level>", "Codex effort level").option("--open <value>", "Open the created session in Desktop (true/false)").option("--json", "Output JSON").action(async function() {
|
|
4161
|
+
const opts = this.opts();
|
|
4162
|
+
const provider = String(opts.provider).trim().toLowerCase();
|
|
4163
|
+
if (provider !== "claude" && provider !== "codex") {
|
|
4164
|
+
throw new Error("Unsupported provider. Use 'claude' or 'codex'.");
|
|
4165
|
+
}
|
|
4166
|
+
const result = await requestDesktopControl("ccem.workspace.createSession", {
|
|
4167
|
+
provider,
|
|
4168
|
+
cwd: opts.cwd,
|
|
4169
|
+
prompt: opts.prompt,
|
|
4170
|
+
envName: opts.env ?? null,
|
|
4171
|
+
permissionMode: opts.perm ?? null,
|
|
4172
|
+
runtimePermissionMode: opts.runtimePerm ?? null,
|
|
4173
|
+
providerSessionId: opts.providerSessionId ?? null,
|
|
4174
|
+
effort: opts.effort ?? null,
|
|
4175
|
+
open: parseOptionalBoolean(opts.open)
|
|
4176
|
+
});
|
|
4177
|
+
outputDesktopResult(result, opts);
|
|
4178
|
+
});
|
|
4179
|
+
desktopCmd.command("sessions").description("List CCEM Desktop workspace sessions").option("--cwd <path>", "Filter by working directory").option("--provider <provider>", "Filter by provider").option("--status <status>", "Filter by status").option("--json", "Output JSON").action(async function() {
|
|
4180
|
+
const opts = this.opts();
|
|
4181
|
+
const result = await requestDesktopControl("ccem.workspace.listSessions", {
|
|
4182
|
+
cwd: opts.cwd ?? null,
|
|
4183
|
+
provider: opts.provider ?? null,
|
|
4184
|
+
status: opts.status ?? null
|
|
4185
|
+
});
|
|
4186
|
+
outputDesktopResult(result, opts);
|
|
4187
|
+
});
|
|
4188
|
+
desktopCmd.command("status <runtimeId>").description("Get one CCEM Desktop workspace session").option("--json", "Output JSON").action(async function(runtimeId) {
|
|
4189
|
+
const opts = this.opts();
|
|
4190
|
+
const result = await requestDesktopControl("ccem.workspace.getSession", { runtimeId });
|
|
4191
|
+
outputDesktopResult(result, opts);
|
|
4192
|
+
});
|
|
4193
|
+
desktopCmd.command("events <runtimeId>").description("Read CCEM Desktop workspace session events").option("--since <seq>", "First event sequence after this value").option("--limit <count>", "Maximum events to return").option("--json", "Output JSON").action(async function(runtimeId) {
|
|
4194
|
+
const opts = this.opts();
|
|
4195
|
+
const result = await requestDesktopControl("ccem.workspace.getEvents", {
|
|
4196
|
+
runtimeId,
|
|
4197
|
+
sinceSeq: opts.since ? Number(opts.since) : null,
|
|
4198
|
+
limit: opts.limit ? Number(opts.limit) : null
|
|
4199
|
+
});
|
|
4200
|
+
outputDesktopResult(result, opts);
|
|
4201
|
+
});
|
|
4202
|
+
desktopCmd.command("send <runtimeId>").description("Send input to a CCEM Desktop workspace session").requiredOption("--text <text>", "Text to send").option("--display-text <text>", "Text to show in Desktop").option("--json", "Output JSON").action(async function(runtimeId) {
|
|
4203
|
+
const opts = this.opts();
|
|
4204
|
+
const result = await requestDesktopControl("ccem.workspace.sendInput", {
|
|
4205
|
+
runtimeId,
|
|
4206
|
+
text: opts.text,
|
|
4207
|
+
displayText: opts.displayText ?? null
|
|
4208
|
+
});
|
|
4209
|
+
outputDesktopResult(result, opts);
|
|
4210
|
+
});
|
|
4211
|
+
desktopCmd.command("open <link>").description("Open a ccem:// workspace session link in Desktop").option("--json", "Output JSON").action(async function(link) {
|
|
4212
|
+
const opts = this.opts();
|
|
4213
|
+
const result = await requestDesktopControl("ccem.workspace.openSession", { link });
|
|
4214
|
+
outputDesktopResult(result, opts);
|
|
4215
|
+
});
|
|
4081
4216
|
program.command("usage").description("\u663E\u793A\u4F7F\u7528\u7EDF\u8BA1\u5E76\u5237\u65B0\u7F13\u5B58").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action(async function() {
|
|
4082
4217
|
const opts = this.opts();
|
|
4083
4218
|
const stats = await getUsageStats();
|