ccem 2.25.0 → 2.26.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 +168 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1466,7 +1466,7 @@ function startCliClaudeProvenanceTracking(options) {
|
|
|
1466
1466
|
if (!workingDir) {
|
|
1467
1467
|
return null;
|
|
1468
1468
|
}
|
|
1469
|
-
const ccemSessionId = `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1469
|
+
const ccemSessionId = normalizeText(options.ccemSessionId) ?? `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1470
1470
|
try {
|
|
1471
1471
|
registerLaunch({
|
|
1472
1472
|
ccemSessionId,
|
|
@@ -1826,6 +1826,7 @@ function ensureSessionsDir() {
|
|
|
1826
1826
|
}
|
|
1827
1827
|
async function launchClaude(options) {
|
|
1828
1828
|
const { envName, envConfig, permMode, workingDir, sessionId, resumeSessionId, silent } = options;
|
|
1829
|
+
const ccemRuntimeId = sessionId ?? `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1829
1830
|
const env = { ...process.env };
|
|
1830
1831
|
for (const key of MANAGED_CLAUDE_ENV_KEYS) {
|
|
1831
1832
|
delete env[key];
|
|
@@ -1834,6 +1835,8 @@ async function launchClaude(options) {
|
|
|
1834
1835
|
Object.assign(env, buildEnvVars(envConfig));
|
|
1835
1836
|
}
|
|
1836
1837
|
delete env.CLAUDECODE;
|
|
1838
|
+
env.CCEM_RUNTIME_ID = ccemRuntimeId;
|
|
1839
|
+
env.CCEM_SESSION_ID = ccemRuntimeId;
|
|
1837
1840
|
const args = [];
|
|
1838
1841
|
if (permMode) {
|
|
1839
1842
|
const preset = PERMISSION_PRESETS[permMode];
|
|
@@ -1870,6 +1873,7 @@ async function launchClaude(options) {
|
|
|
1870
1873
|
return;
|
|
1871
1874
|
}
|
|
1872
1875
|
provenanceTracking = startCliClaudeProvenanceTracking({
|
|
1876
|
+
ccemSessionId: ccemRuntimeId,
|
|
1873
1877
|
envName: envName ?? "unknown",
|
|
1874
1878
|
workingDir: effectiveWorkingDir,
|
|
1875
1879
|
permMode,
|
|
@@ -2769,6 +2773,66 @@ Loaded ${results.length} environment(s) from remote:`));
|
|
|
2769
2773
|
return results;
|
|
2770
2774
|
};
|
|
2771
2775
|
|
|
2776
|
+
// src/bot-bind-skill.ts
|
|
2777
|
+
var CCEM_BOT_BIND_SKILL_CONTENT = `# ccem-bot-bind
|
|
2778
|
+
|
|
2779
|
+
Bind the current CCEM-launched Claude Code session to a bot target such as WeCom or Weixin.
|
|
2780
|
+
|
|
2781
|
+
Use this skill when the user asks to bind, attach, connect, or push the current task/session to a bot, chat, WeCom, Weixin, Telegram, or a remote task card.
|
|
2782
|
+
|
|
2783
|
+
## What this skill does
|
|
2784
|
+
|
|
2785
|
+
- Creates a bot-binding request for the current CCEM runtime.
|
|
2786
|
+
- Relies on \`CCEM_RUNTIME_ID\` or \`CCEM_SESSION_ID\`, which CCEM injects into sessions it launches.
|
|
2787
|
+
- Writes the request to \`~/.ccem/bot-bind-requests.jsonl\`.
|
|
2788
|
+
- CCEM Desktop consumes the request and binds the matching session to the bot outbox.
|
|
2789
|
+
|
|
2790
|
+
## Required inputs
|
|
2791
|
+
|
|
2792
|
+
Ask for any missing target information:
|
|
2793
|
+
|
|
2794
|
+
- \`platform\`: one of \`wecom\`, \`weixin\`, or \`telegram\`.
|
|
2795
|
+
- \`peer_id\`: user id, chat id, group id, or equivalent target id.
|
|
2796
|
+
- For WeCom, include \`bot_id\` when known.
|
|
2797
|
+
|
|
2798
|
+
## Command
|
|
2799
|
+
|
|
2800
|
+
Run:
|
|
2801
|
+
|
|
2802
|
+
\`\`\`bash
|
|
2803
|
+
ccem bot-bind --platform <platform> --peer-id <peer_id> --title "<short task title>" --summary "<one sentence summary>"
|
|
2804
|
+
\`\`\`
|
|
2805
|
+
|
|
2806
|
+
For WeCom:
|
|
2807
|
+
|
|
2808
|
+
\`\`\`bash
|
|
2809
|
+
ccem bot-bind --platform wecom --bot-id <bot_id> --peer-id <userid_or_chatid> --title "<short task title>" --summary "<one sentence summary>"
|
|
2810
|
+
\`\`\`
|
|
2811
|
+
|
|
2812
|
+
If the user only wants to create the binding without pushing a task card, add \`--no-send-card\`.
|
|
2813
|
+
|
|
2814
|
+
If CCEM did not inject a runtime id, ask the user for the runtime id or list sessions with:
|
|
2815
|
+
|
|
2816
|
+
\`\`\`bash
|
|
2817
|
+
ccem sessions
|
|
2818
|
+
\`\`\`
|
|
2819
|
+
|
|
2820
|
+
Then pass:
|
|
2821
|
+
|
|
2822
|
+
\`\`\`bash
|
|
2823
|
+
ccem bot-bind --runtime-id <runtime_id> --platform <platform> --peer-id <peer_id>
|
|
2824
|
+
\`\`\`
|
|
2825
|
+
|
|
2826
|
+
## Behavior rules
|
|
2827
|
+
|
|
2828
|
+
- Do not invent peer ids or bot ids.
|
|
2829
|
+
- Keep the title short enough for a task card.
|
|
2830
|
+
- Include a summary that explains what this session is currently doing.
|
|
2831
|
+
- After the command succeeds, tell the user the request was queued and CCEM Desktop will consume it when running.
|
|
2832
|
+
- Do not ask the bot target to execute shell commands; user commands should flow back through the CCEM binding.
|
|
2833
|
+
- For WeCom, authorization and target membership are owned by the configured WeCom bot; do not create a separate allowlist.
|
|
2834
|
+
`;
|
|
2835
|
+
|
|
2772
2836
|
// src/cron-skill.ts
|
|
2773
2837
|
var CCEM_CRON_SKILL_CONTENT = `# ccem-cron
|
|
2774
2838
|
|
|
@@ -3308,6 +3372,7 @@ var switchEnvironment = async (name) => {
|
|
|
3308
3372
|
};
|
|
3309
3373
|
var getSessionsFilePath = () => path8.join(getCcemConfigDir(), "sessions.json");
|
|
3310
3374
|
var getRuntimeStateFilePath = () => path8.join(getCcemConfigDir(), "runtime-state.json");
|
|
3375
|
+
var getBotBindRequestFilePath = () => path8.join(getCcemConfigDir(), "bot-bind-requests.jsonl");
|
|
3311
3376
|
var parseJsonFile = (filePath) => {
|
|
3312
3377
|
if (!fs10.existsSync(filePath)) {
|
|
3313
3378
|
return null;
|
|
@@ -3387,6 +3452,29 @@ var attachTmuxTarget = (target) => {
|
|
|
3387
3452
|
});
|
|
3388
3453
|
});
|
|
3389
3454
|
};
|
|
3455
|
+
var normalizeBotBindPlatform = (value) => {
|
|
3456
|
+
const normalized = value.trim().toLowerCase();
|
|
3457
|
+
return normalized === "telegram" || normalized === "weixin" || normalized === "wecom" ? normalized : null;
|
|
3458
|
+
};
|
|
3459
|
+
var resolveBotBindRuntimeId = (explicitRuntimeId) => {
|
|
3460
|
+
const explicit = explicitRuntimeId?.trim();
|
|
3461
|
+
if (explicit) {
|
|
3462
|
+
return explicit;
|
|
3463
|
+
}
|
|
3464
|
+
const fromEnv = process.env.CCEM_RUNTIME_ID?.trim() || process.env.CCEM_SESSION_ID?.trim();
|
|
3465
|
+
if (fromEnv) {
|
|
3466
|
+
return fromEnv;
|
|
3467
|
+
}
|
|
3468
|
+
const sessions = readInteractiveAttachSessions();
|
|
3469
|
+
return sessions.length === 1 ? sessions[0].id : null;
|
|
3470
|
+
};
|
|
3471
|
+
var appendBotBindRequest = (payload) => {
|
|
3472
|
+
const requestPath = getBotBindRequestFilePath();
|
|
3473
|
+
fs10.mkdirSync(path8.dirname(requestPath), { recursive: true });
|
|
3474
|
+
fs10.appendFileSync(requestPath, `${JSON.stringify(payload)}
|
|
3475
|
+
`, "utf-8");
|
|
3476
|
+
return requestPath;
|
|
3477
|
+
};
|
|
3390
3478
|
program.command("ls").description("List all configured environments").action(() => {
|
|
3391
3479
|
const registries = getRegistries();
|
|
3392
3480
|
const current = config2.get("current");
|
|
@@ -3442,6 +3530,57 @@ program.command("attach [id]").description("Attach to a tmux-backed interactive
|
|
|
3442
3530
|
process.exit(1);
|
|
3443
3531
|
}
|
|
3444
3532
|
});
|
|
3533
|
+
program.command("bot-bind").description("Request binding the current ccem session to a chat bot target").requiredOption("--platform <platform>", "target platform: telegram, weixin, or wecom").option("--peer-id <peerId>", "target user/chat id").option("--peer <peerId>", "alias for --peer-id").option("--runtime-id <runtimeId>", "ccem runtime id; defaults to CCEM_RUNTIME_ID").option("--bot-id <botId>", "WeCom bot id or platform bot id").option("--thread-id <threadId>", "thread/topic id for platforms that support it").option("--title <title>", "task card title").option("--summary <summary>", "task card summary").option("--no-send-card", "bind without sending the initial task card").option("--json", "print the queued request as JSON").action((options) => {
|
|
3534
|
+
const platform = normalizeBotBindPlatform(options.platform);
|
|
3535
|
+
if (!platform) {
|
|
3536
|
+
console.error(chalk7.red("\u2717 --platform must be telegram, weixin, or wecom"));
|
|
3537
|
+
process.exitCode = 1;
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
const peerId = (options.peerId ?? options.peer ?? "").trim();
|
|
3541
|
+
if (!peerId) {
|
|
3542
|
+
console.error(chalk7.red("\u2717 --peer-id is required"));
|
|
3543
|
+
process.exitCode = 1;
|
|
3544
|
+
return;
|
|
3545
|
+
}
|
|
3546
|
+
const runtimeId = resolveBotBindRuntimeId(options.runtimeId);
|
|
3547
|
+
if (!runtimeId) {
|
|
3548
|
+
console.error(chalk7.red("\u2717 Unable to resolve ccem runtime id"));
|
|
3549
|
+
console.error(chalk7.gray(" Run from a ccem-launched session or pass --runtime-id explicitly."));
|
|
3550
|
+
process.exitCode = 1;
|
|
3551
|
+
return;
|
|
3552
|
+
}
|
|
3553
|
+
const botId = options.botId?.trim() || void 0;
|
|
3554
|
+
if (platform === "wecom" && !botId) {
|
|
3555
|
+
console.error(chalk7.red("\u2717 --bot-id is required for WeCom bot bindings"));
|
|
3556
|
+
process.exitCode = 1;
|
|
3557
|
+
return;
|
|
3558
|
+
}
|
|
3559
|
+
const payload = {
|
|
3560
|
+
request_id: `botbind-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
3561
|
+
runtime_id: runtimeId,
|
|
3562
|
+
platform,
|
|
3563
|
+
peer_id: peerId,
|
|
3564
|
+
bot_id: botId,
|
|
3565
|
+
thread_id: options.threadId?.trim() || void 0,
|
|
3566
|
+
task_title: options.title?.trim() || void 0,
|
|
3567
|
+
task_summary: options.summary?.trim() || void 0,
|
|
3568
|
+
send_task_card: options.sendCard !== false,
|
|
3569
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3570
|
+
};
|
|
3571
|
+
const requestPath = appendBotBindRequest(payload);
|
|
3572
|
+
if (options.json) {
|
|
3573
|
+
console.log(JSON.stringify({ requestPath, payload }, null, 2));
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
console.log(chalk7.green("\u2713 \u5DF2\u63D0\u4EA4 bot \u7ED1\u5B9A\u8BF7\u6C42"));
|
|
3577
|
+
console.log(chalk7.gray(` runtime: ${runtimeId}`));
|
|
3578
|
+
console.log(chalk7.gray(` target: ${platform}/${peerId}`));
|
|
3579
|
+
console.log(chalk7.gray(` queue: ${requestPath}`));
|
|
3580
|
+
console.log(chalk7.cyan(
|
|
3581
|
+
options.sendCard === false ? " \u5982\u679C CCEM Desktop \u6B63\u5728\u8FD0\u884C\uFF0C\u4F1A\u81EA\u52A8\u6D88\u8D39\u8BE5\u8BF7\u6C42\u5E76\u5EFA\u7ACB\u7ED1\u5B9A\u3002" : " \u5982\u679C CCEM Desktop \u6B63\u5728\u8FD0\u884C\uFF0C\u4F1A\u81EA\u52A8\u6D88\u8D39\u8BE5\u8BF7\u6C42\u5E76\u53D1\u9001\u4EFB\u52A1\u5361\u7247\u5230\u7ED1\u5B9A\u76EE\u6807\u3002"
|
|
3582
|
+
));
|
|
3583
|
+
});
|
|
3445
3584
|
program.command("add <name>").description("Add a new environment configuration").action(async (name) => {
|
|
3446
3585
|
const registries = getRegistries();
|
|
3447
3586
|
if (registries[name]) {
|
|
@@ -3760,6 +3899,34 @@ setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude
|
|
|
3760
3899
|
console.log(chalk7.cyan(`
|
|
3761
3900
|
\u5728 Claude Code \u4E2D\u4F7F\u7528 /ccem-cron \u5373\u53EF\u8C03\u7528\u6B64 skill`));
|
|
3762
3901
|
});
|
|
3902
|
+
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() {
|
|
3903
|
+
const options = this.opts();
|
|
3904
|
+
const skillDir = path8.join(getHomeDir(), ".claude", "skills");
|
|
3905
|
+
const targetPath = path8.join(skillDir, "ccem-bot-bind.md");
|
|
3906
|
+
if (!fs10.existsSync(skillDir)) {
|
|
3907
|
+
fs10.mkdirSync(skillDir, { recursive: true });
|
|
3908
|
+
console.log(chalk7.gray(`\u521B\u5EFA\u76EE\u5F55: ${skillDir}`));
|
|
3909
|
+
}
|
|
3910
|
+
if (fs10.existsSync(targetPath) && !options.force) {
|
|
3911
|
+
const { overwrite } = await inquirer.prompt([
|
|
3912
|
+
{
|
|
3913
|
+
type: "confirm",
|
|
3914
|
+
name: "overwrite",
|
|
3915
|
+
message: `${targetPath} \u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6\uFF1F`,
|
|
3916
|
+
default: false
|
|
3917
|
+
}
|
|
3918
|
+
]);
|
|
3919
|
+
if (!overwrite) {
|
|
3920
|
+
console.log(chalk7.yellow("\u5DF2\u53D6\u6D88"));
|
|
3921
|
+
return;
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
fs10.writeFileSync(targetPath, CCEM_BOT_BIND_SKILL_CONTENT, "utf-8");
|
|
3925
|
+
console.log(chalk7.green(`\u2713 \u5DF2\u5B89\u88C5 ccem-bot-bind skill`));
|
|
3926
|
+
console.log(chalk7.gray(` \u8DEF\u5F84: ${targetPath}`));
|
|
3927
|
+
console.log(chalk7.cyan(`
|
|
3928
|
+
\u5728 Claude Code \u4E2D\u8BA9\u5B83\u4F7F\u7528 ccem-bot-bind skill \u5373\u53EF\u7ED1\u5B9A\u5F53\u524D\u4F1A\u8BDD\u5230 bot`));
|
|
3929
|
+
});
|
|
3763
3930
|
var skillCmd = program.command("skill").description("\u7BA1\u7406 Claude Code skills");
|
|
3764
3931
|
skillCmd.command("add [url]").description("\u6DFB\u52A0 skill\uFF08\u4ECE\u5B98\u65B9\u9884\u8BBE\u6216 GitHub URL\uFF09").action(async (url) => {
|
|
3765
3932
|
if (url) {
|