nextclaw 0.16.17 → 0.16.18

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +224 -68
  2. package/package.json +6 -6
package/dist/cli/index.js CHANGED
@@ -2995,45 +2995,36 @@ var ChannelCommands = class {
2995
2995
  }
2996
2996
  };
2997
2997
 
2998
- // src/cli/commands/cron.ts
2998
+ // src/cli/commands/cron/cron-local.service.ts
2999
2999
  import { CronService, getDataDir as getDataDir3 } from "@nextclaw/core";
3000
3000
  import { join as join3 } from "path";
3001
- var CronCommands = class {
3002
- cronList(opts) {
3003
- const storePath = join3(getDataDir3(), "cron", "jobs.json");
3004
- const service = new CronService(storePath);
3005
- const jobs = service.listJobs(Boolean(opts.all));
3006
- if (!jobs.length) {
3007
- console.log("No scheduled jobs.");
3008
- return;
3009
- }
3010
- for (const job of jobs) {
3011
- let schedule = "";
3012
- if (job.schedule.kind === "every") {
3013
- schedule = `every ${Math.round((job.schedule.everyMs ?? 0) / 1e3)}s`;
3014
- } else if (job.schedule.kind === "cron") {
3015
- schedule = job.schedule.expr ?? "";
3016
- } else {
3017
- schedule = job.schedule.atMs ? new Date(job.schedule.atMs).toISOString() : "";
3018
- }
3019
- console.log(`${job.id} ${job.name} ${schedule}`);
3020
- }
3001
+ function createCronService() {
3002
+ const storePath = join3(getDataDir3(), "cron", "jobs.json");
3003
+ return new CronService(storePath);
3004
+ }
3005
+ function toSchedule(opts) {
3006
+ if (opts.every) {
3007
+ return { kind: "every", everyMs: Number(opts.every) * 1e3 };
3021
3008
  }
3022
- cronAdd(opts) {
3023
- const storePath = join3(getDataDir3(), "cron", "jobs.json");
3024
- const service = new CronService(storePath);
3025
- let schedule = null;
3026
- if (opts.every) {
3027
- schedule = { kind: "every", everyMs: Number(opts.every) * 1e3 };
3028
- } else if (opts.cron) {
3029
- schedule = { kind: "cron", expr: String(opts.cron) };
3030
- } else if (opts.at) {
3031
- schedule = { kind: "at", atMs: Date.parse(String(opts.at)) };
3032
- }
3009
+ if (opts.cron) {
3010
+ return { kind: "cron", expr: String(opts.cron) };
3011
+ }
3012
+ if (opts.at) {
3013
+ return { kind: "at", atMs: Date.parse(String(opts.at)) };
3014
+ }
3015
+ return null;
3016
+ }
3017
+ var CronLocalService = class {
3018
+ list = (all) => {
3019
+ const service = createCronService();
3020
+ return service.listJobs(all);
3021
+ };
3022
+ add = (opts) => {
3023
+ const schedule = toSchedule(opts);
3033
3024
  if (!schedule) {
3034
- console.error("Error: Must specify --every, --cron, or --at");
3035
- return;
3025
+ return { job: null, error: "Error: Must specify --every, --cron, or --at" };
3036
3026
  }
3027
+ const service = createCronService();
3037
3028
  const job = service.addJob({
3038
3029
  name: opts.name,
3039
3030
  schedule,
@@ -3043,33 +3034,198 @@ var CronCommands = class {
3043
3034
  to: opts.to,
3044
3035
  accountId: opts.account
3045
3036
  });
3046
- console.log(`\u2713 Added job '${job.name}' (${job.id})`);
3037
+ return { job };
3038
+ };
3039
+ remove = (jobId) => {
3040
+ const service = createCronService();
3041
+ return service.removeJob(jobId);
3042
+ };
3043
+ enable = (jobId, enabled) => {
3044
+ const service = createCronService();
3045
+ return service.enableJob(jobId, enabled) ?? null;
3046
+ };
3047
+ run = async (jobId, force) => {
3048
+ const service = createCronService();
3049
+ return service.runJob(jobId, force);
3050
+ };
3051
+ };
3052
+
3053
+ // src/cli/commands/cron/cron-job.utils.ts
3054
+ function formatCronSchedule(schedule) {
3055
+ if (schedule.kind === "every") {
3056
+ return `every ${Math.round((schedule.everyMs ?? 0) / 1e3)}s`;
3047
3057
  }
3048
- cronRemove(jobId) {
3049
- const storePath = join3(getDataDir3(), "cron", "jobs.json");
3050
- const service = new CronService(storePath);
3051
- if (service.removeJob(jobId)) {
3058
+ if (schedule.kind === "cron") {
3059
+ return schedule.expr ?? "";
3060
+ }
3061
+ return schedule.atMs ? new Date(schedule.atMs).toISOString() : "";
3062
+ }
3063
+ function printCronJobs(jobs) {
3064
+ if (!jobs.length) {
3065
+ console.log("No scheduled jobs.");
3066
+ return;
3067
+ }
3068
+ for (const job of jobs) {
3069
+ console.log(`${job.id} ${job.name} ${formatCronSchedule(job.schedule)}`);
3070
+ }
3071
+ }
3072
+
3073
+ // src/cli/commands/shared/ui-bridge-api.service.ts
3074
+ import { ensureUiBridgeSecret } from "@nextclaw/server";
3075
+ function resolveManagedApiBase() {
3076
+ const state = readServiceState();
3077
+ if (!state?.apiUrl || !state.pid) {
3078
+ return null;
3079
+ }
3080
+ if (!isProcessRunning(state.pid)) {
3081
+ return null;
3082
+ }
3083
+ return state.apiUrl.replace(/\/+$/, "");
3084
+ }
3085
+ var UiBridgeApiClient = class {
3086
+ constructor(apiBase) {
3087
+ this.apiBase = apiBase;
3088
+ }
3089
+ cookie;
3090
+ getCookie = async () => {
3091
+ if (this.cookie !== void 0) {
3092
+ return this.cookie;
3093
+ }
3094
+ const bridgeSecret = ensureUiBridgeSecret();
3095
+ const response = await fetch(`${this.apiBase}/api/auth/bridge`, {
3096
+ method: "POST",
3097
+ headers: {
3098
+ "x-nextclaw-ui-bridge-secret": bridgeSecret
3099
+ }
3100
+ });
3101
+ if (!response.ok) {
3102
+ throw new Error(`bridge auth failed with status ${response.status}`);
3103
+ }
3104
+ const payload = await response.json();
3105
+ if (!payload.ok) {
3106
+ throw new Error(payload.error?.message ?? "bridge auth failed");
3107
+ }
3108
+ this.cookie = typeof payload.data.cookie === "string" && payload.data.cookie.trim() ? payload.data.cookie.trim() : null;
3109
+ return this.cookie;
3110
+ };
3111
+ request = async (params) => {
3112
+ const cookie = await this.getCookie();
3113
+ const response = await fetch(`${this.apiBase}${params.path}`, {
3114
+ method: params.method ?? "GET",
3115
+ headers: {
3116
+ ...params.body ? { "Content-Type": "application/json" } : {},
3117
+ ...cookie ? { Cookie: cookie } : {}
3118
+ },
3119
+ ...params.body ? { body: JSON.stringify(params.body) } : {}
3120
+ });
3121
+ if (!response.ok) {
3122
+ throw new Error(`api request failed with status ${response.status}`);
3123
+ }
3124
+ const payload = await response.json();
3125
+ if (!payload.ok) {
3126
+ throw new Error(payload.error?.message ?? "api request failed");
3127
+ }
3128
+ return payload.data;
3129
+ };
3130
+ };
3131
+
3132
+ // src/cli/commands/cron.ts
3133
+ var CronCommands = class {
3134
+ constructor(local = new CronLocalService()) {
3135
+ this.local = local;
3136
+ }
3137
+ createApiClient = () => {
3138
+ const apiBase = resolveManagedApiBase();
3139
+ if (!apiBase) {
3140
+ return null;
3141
+ }
3142
+ return new UiBridgeApiClient(apiBase);
3143
+ };
3144
+ cronList = async (opts) => {
3145
+ const apiClient = this.createApiClient();
3146
+ if (apiClient) {
3147
+ try {
3148
+ const query = opts.all ? "?all=1" : "";
3149
+ const data = await apiClient.request({
3150
+ path: `/api/cron${query}`
3151
+ });
3152
+ printCronJobs(data.jobs);
3153
+ return;
3154
+ } catch {
3155
+ }
3156
+ }
3157
+ printCronJobs(this.local.list(Boolean(opts.all)));
3158
+ };
3159
+ cronAdd = async (opts) => {
3160
+ const result = this.local.add(opts);
3161
+ if (!result.job) {
3162
+ console.error(result.error ?? "Error: Failed to add job");
3163
+ return;
3164
+ }
3165
+ console.log(`\u2713 Added job '${result.job.name}' (${result.job.id})`);
3166
+ };
3167
+ cronRemove = async (jobId) => {
3168
+ const apiClient = this.createApiClient();
3169
+ if (apiClient) {
3170
+ try {
3171
+ const data = await apiClient.request({
3172
+ path: `/api/cron/${encodeURIComponent(jobId)}`,
3173
+ method: "DELETE"
3174
+ });
3175
+ if (data.deleted) {
3176
+ console.log(`\u2713 Removed job ${jobId}`);
3177
+ return;
3178
+ }
3179
+ } catch {
3180
+ }
3181
+ }
3182
+ if (this.local.remove(jobId)) {
3052
3183
  console.log(`\u2713 Removed job ${jobId}`);
3053
3184
  } else {
3054
3185
  console.log(`Job ${jobId} not found`);
3055
3186
  }
3056
- }
3057
- cronEnable(jobId, opts) {
3058
- const storePath = join3(getDataDir3(), "cron", "jobs.json");
3059
- const service = new CronService(storePath);
3060
- const job = service.enableJob(jobId, !opts.disable);
3187
+ };
3188
+ cronEnable = async (jobId, opts) => {
3189
+ const apiClient = this.createApiClient();
3190
+ const enabled = !opts.disable;
3191
+ if (apiClient) {
3192
+ try {
3193
+ const data = await apiClient.request({
3194
+ path: `/api/cron/${encodeURIComponent(jobId)}/enable`,
3195
+ method: "PUT",
3196
+ body: { enabled }
3197
+ });
3198
+ if (data.job) {
3199
+ console.log(`\u2713 Job '${data.job.name}' ${opts.disable ? "disabled" : "enabled"}`);
3200
+ return;
3201
+ }
3202
+ } catch {
3203
+ }
3204
+ }
3205
+ const job = this.local.enable(jobId, enabled);
3061
3206
  if (job) {
3062
3207
  console.log(`\u2713 Job '${job.name}' ${opts.disable ? "disabled" : "enabled"}`);
3063
3208
  } else {
3064
3209
  console.log(`Job ${jobId} not found`);
3065
3210
  }
3066
- }
3067
- async cronRun(jobId, opts) {
3068
- const storePath = join3(getDataDir3(), "cron", "jobs.json");
3069
- const service = new CronService(storePath);
3070
- const ok = await service.runJob(jobId, Boolean(opts.force));
3211
+ };
3212
+ cronRun = async (jobId, opts) => {
3213
+ const apiClient = this.createApiClient();
3214
+ if (apiClient) {
3215
+ try {
3216
+ const data = await apiClient.request({
3217
+ path: `/api/cron/${encodeURIComponent(jobId)}/run`,
3218
+ method: "POST",
3219
+ body: { force: Boolean(opts.force) }
3220
+ });
3221
+ console.log(data.executed ? "\u2713 Job executed" : `Failed to run job ${jobId}`);
3222
+ return;
3223
+ } catch {
3224
+ }
3225
+ }
3226
+ const ok = await this.local.run(jobId, Boolean(opts.force));
3071
3227
  console.log(ok ? "\u2713 Job executed" : `Failed to run job ${jobId}`);
3072
- }
3228
+ };
3073
3229
  };
3074
3230
 
3075
3231
  // src/cli/commands/platform-auth.ts
@@ -10390,21 +10546,21 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
10390
10546
  async channelsAdd(opts) {
10391
10547
  await this.channelCommands.channelsAdd(opts);
10392
10548
  }
10393
- cronList(opts) {
10394
- this.cronCommands.cronList(opts);
10395
- }
10396
- cronAdd(opts) {
10397
- this.cronCommands.cronAdd(opts);
10398
- }
10399
- cronRemove(jobId) {
10400
- this.cronCommands.cronRemove(jobId);
10401
- }
10402
- cronEnable(jobId, opts) {
10403
- this.cronCommands.cronEnable(jobId, opts);
10404
- }
10405
- async cronRun(jobId, opts) {
10549
+ cronList = async (opts) => {
10550
+ await this.cronCommands.cronList(opts);
10551
+ };
10552
+ cronAdd = async (opts) => {
10553
+ await this.cronCommands.cronAdd(opts);
10554
+ };
10555
+ cronRemove = async (jobId) => {
10556
+ await this.cronCommands.cronRemove(jobId);
10557
+ };
10558
+ cronEnable = async (jobId, opts) => {
10559
+ await this.cronCommands.cronEnable(jobId, opts);
10560
+ };
10561
+ cronRun = async (jobId, opts) => {
10406
10562
  await this.cronCommands.cronRun(jobId, opts);
10407
- }
10563
+ };
10408
10564
  async status(opts = {}) {
10409
10565
  await this.diagnosticsCommands.status(opts);
10410
10566
  }
@@ -10529,10 +10685,10 @@ channels.command("add").description("Configure a plugin channel (OpenClaw-compat
10529
10685
  channels.command("status").description("Show channel status").action(() => runtime.channelsStatus());
10530
10686
  channels.command("login").description("Link device via QR code").option("--channel <id>", "Plugin channel id").option("--account <id>", "Channel account id").option("--url <url>", "Channel API base URL").option("--http-url <url>", "Alias for --url").option("-v, --verbose", "Verbose output", false).action(async (opts) => runtime.channelsLogin(opts));
10531
10687
  var cron = program.command("cron").description("Manage scheduled tasks");
10532
- cron.command("list").option("-a, --all", "Include disabled jobs").action((opts) => runtime.cronList(opts));
10533
- cron.command("add").requiredOption("-n, --name <name>", "Job name").requiredOption("-m, --message <message>", "Message for agent").option("-e, --every <seconds>", "Run every N seconds").option("-c, --cron <expr>", "Cron expression").option("--at <iso>", "Run once at time (ISO format)").option("-d, --deliver", "Deliver response to channel").option("--to <recipient>", "Recipient for delivery").option("--channel <channel>", "Channel for delivery").option("--account <id>", "Account id for channel delivery").action((opts) => runtime.cronAdd(opts));
10534
- cron.command("remove <jobId>").action((jobId) => runtime.cronRemove(jobId));
10535
- cron.command("enable <jobId>").option("--disable", "Disable instead of enable").action((jobId, opts) => runtime.cronEnable(jobId, opts));
10688
+ cron.command("list").option("-a, --all", "Include disabled jobs").action(async (opts) => runtime.cronList(opts));
10689
+ cron.command("add").requiredOption("-n, --name <name>", "Job name").requiredOption("-m, --message <message>", "Message for agent").option("-e, --every <seconds>", "Run every N seconds").option("-c, --cron <expr>", "Cron expression").option("--at <iso>", "Run once at time (ISO format)").option("-d, --deliver", "Deliver response to channel").option("--to <recipient>", "Recipient for delivery").option("--channel <channel>", "Channel for delivery").option("--account <id>", "Account id for channel delivery").action(async (opts) => runtime.cronAdd(opts));
10690
+ cron.command("remove <jobId>").action(async (jobId) => runtime.cronRemove(jobId));
10691
+ cron.command("enable <jobId>").option("--disable", "Disable instead of enable").action(async (jobId, opts) => runtime.cronEnable(jobId, opts));
10536
10692
  cron.command("run <jobId>").option("-f, --force", "Run even if disabled").action(async (jobId, opts) => runtime.cronRun(jobId, opts));
10537
10693
  program.command("status").description(`Show ${APP_NAME6} status`).option("--json", "Output JSON", false).option("--verbose", "Show extra diagnostics", false).option("--fix", "Fix stale service state when safe", false).action(async (opts) => runtime.status(opts));
10538
10694
  program.command("doctor").description(`Run ${APP_NAME6} diagnostics`).option("--json", "Output JSON", false).option("--verbose", "Show extra diagnostics", false).option("--fix", "Fix stale service state when safe", false).action(async (opts) => runtime.doctor(opts));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.16.17",
3
+ "version": "0.16.18",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -39,16 +39,16 @@
39
39
  "chokidar": "^3.6.0",
40
40
  "commander": "^12.1.0",
41
41
  "yaml": "^2.8.1",
42
+ "@nextclaw/mcp": "0.1.54",
42
43
  "@nextclaw/core": "0.11.7",
43
- "@nextclaw/ncp": "0.4.0",
44
44
  "@nextclaw/ncp-agent-runtime": "0.3.0",
45
- "@nextclaw/mcp": "0.1.54",
46
45
  "@nextclaw/ncp-mcp": "0.1.54",
46
+ "@nextclaw/ncp": "0.4.0",
47
47
  "@nextclaw/ncp-toolkit": "0.4.6",
48
- "@nextclaw/remote": "0.1.63",
49
- "@nextclaw/runtime": "0.2.21",
50
48
  "@nextclaw/server": "0.11.11",
51
- "@nextclaw/openclaw-compat": "0.3.45"
49
+ "@nextclaw/remote": "0.1.63",
50
+ "@nextclaw/openclaw-compat": "0.3.45",
51
+ "@nextclaw/runtime": "0.2.21"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^20.17.6",