fastclaw-cli 0.2.1 → 0.3.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/README.md CHANGED
@@ -49,9 +49,10 @@ fastclaw setup # Interactive one-step bot creation
49
49
 
50
50
  fastclaw config set|get|show # Manage local config (~/.fastclaw/config.json)
51
51
 
52
- fastclaw admin apps create|list|delete|rotate-token
52
+ fastclaw admin apps create|list [-t]|delete|rotate-token
53
53
 
54
54
  fastclaw bot create|list|get|update|delete
55
+ fastclaw bot list -A [--user-id <uid>] # List bots across all apps (requires admin token)
55
56
  fastclaw bot start|stop|restart|status|connect|reset-token <id>
56
57
 
57
58
  fastclaw model add|list|get|delete <bot-id> [provider]
package/dist/index.js CHANGED
@@ -156,7 +156,8 @@ function resolveConfig(opts) {
156
156
  appToken: opts.appToken || process.env.FASTCLAW_APP_TOKEN || file.app_token,
157
157
  userId: opts.userId || process.env.FASTCLAW_USER_ID || file.default_user_id || "default",
158
158
  botId: opts.botId || process.env.FASTCLAW_BOT_ID || file.default_bot_id,
159
- json: opts.json ?? false
159
+ json: opts.json ?? false,
160
+ yes: opts.yes ?? false
160
161
  };
161
162
  }
162
163
  function getConfigPath() {
@@ -165,6 +166,31 @@ function getConfigPath() {
165
166
 
166
167
  // src/utils/error.ts
167
168
  import chalk from "chalk";
169
+
170
+ // src/utils/prompt.ts
171
+ import { input, select, password, confirm } from "@inquirer/prompts";
172
+ async function promptText(message, defaultValue) {
173
+ return input({ message, default: defaultValue });
174
+ }
175
+ async function promptPassword(message) {
176
+ return password({ message, mask: "\u2022" });
177
+ }
178
+ async function promptSelect(message, choices) {
179
+ return select({ message, choices });
180
+ }
181
+ async function promptConfirm(message, defaultValue = true) {
182
+ return confirm({ message, default: defaultValue });
183
+ }
184
+
185
+ // src/utils/error.ts
186
+ async function confirmAction(cfg, message) {
187
+ if (cfg.yes) return;
188
+ const ok = await promptConfirm(message, false);
189
+ if (!ok) {
190
+ console.log(chalk.dim("Cancelled."));
191
+ process.exit(0);
192
+ }
193
+ }
168
194
  var ApiError = class extends Error {
169
195
  constructor(statusCode, apiCode, message) {
170
196
  super(message);
@@ -293,7 +319,7 @@ function maskToken(token) {
293
319
  return token.slice(0, 4) + "\u2022\u2022\u2022\u2022" + token.slice(-4);
294
320
  }
295
321
 
296
- // src/commands/admin/apps.ts
322
+ // src/commands/app/index.ts
297
323
  import chalk4 from "chalk";
298
324
 
299
325
  // src/client.ts
@@ -379,7 +405,9 @@ var FastClawClient = class {
379
405
  return this.request("POST", "/bots", { body: req });
380
406
  }
381
407
  async listBots(userId) {
382
- return this.request("GET", "/bots", { query: { user_id: userId } });
408
+ const query = {};
409
+ if (userId) query.user_id = userId;
410
+ return this.request("GET", "/bots", { query });
383
411
  }
384
412
  async getBot(id) {
385
413
  return this.request("GET", `/bots/${id}`);
@@ -482,6 +510,58 @@ var FastClawClient = class {
482
510
  async deleteSkill(botId, name) {
483
511
  return this.request("DELETE", `/bots/${botId}/skills/${name}`);
484
512
  }
513
+ // ── Bot Logs ──
514
+ async getBotLogs(botId, opts) {
515
+ const query = {};
516
+ if (opts?.tail !== void 0) query.tail = String(opts.tail);
517
+ if (opts?.sinceSeconds !== void 0) query.sinceSeconds = String(opts.sinceSeconds);
518
+ if (opts?.sinceTime) query.sinceTime = opts.sinceTime;
519
+ if (opts?.timestamps) query.timestamps = "true";
520
+ return this.request("GET", `/bots/${botId}/logs`, { query });
521
+ }
522
+ // ── Bot Runtime (OpenClaw CLI exec) ──
523
+ async getRuntimeStatus(botId, opts) {
524
+ const query = {};
525
+ if (opts?.all) query.all = "true";
526
+ if (opts?.usage) query.usage = "true";
527
+ if (opts?.deep) query.deep = "true";
528
+ if (opts?.timeout) query.timeout = opts.timeout;
529
+ return this.request("GET", `/bots/${botId}/runtime/status`, { query });
530
+ }
531
+ async getRuntimeSessions(botId, opts) {
532
+ const query = {};
533
+ if (opts?.agent) query.agent = opts.agent;
534
+ if (opts?.allAgents) query["all-agents"] = "true";
535
+ if (opts?.active) query.active = "true";
536
+ return this.request("GET", `/bots/${botId}/runtime/sessions`, { query });
537
+ }
538
+ async getRuntimeConfig(botId, path) {
539
+ const query = {};
540
+ if (path) query.path = path;
541
+ return this.request("GET", `/bots/${botId}/runtime/config`, { query });
542
+ }
543
+ async getRuntimeConfigValidate(botId) {
544
+ return this.request("GET", `/bots/${botId}/runtime/config/validate`);
545
+ }
546
+ async getRuntimeModels(botId, opts) {
547
+ const query = {};
548
+ if (opts?.all) query.all = "true";
549
+ if (opts?.agent) query.agent = opts.agent;
550
+ if (opts?.provider) query.provider = opts.provider;
551
+ return this.request("GET", `/bots/${botId}/runtime/models`, { query });
552
+ }
553
+ async getRuntimeSkills(botId, opts) {
554
+ const query = {};
555
+ if (opts?.eligible) query.eligible = "true";
556
+ if (opts?.verbose) query.verbose = "true";
557
+ return this.request("GET", `/bots/${botId}/runtime/skills`, { query });
558
+ }
559
+ async getRuntimeSkillsCheck(botId) {
560
+ return this.request("GET", `/bots/${botId}/runtime/skills/check`);
561
+ }
562
+ async runtimeExec(botId, req) {
563
+ return this.request("POST", `/bots/${botId}/runtime/exec`, { body: req });
564
+ }
485
565
  // ── Utility: wait for bot ready ──
486
566
  async waitForReady(botId, timeoutMs = 12e4, intervalMs = 3e3) {
487
567
  const start = Date.now();
@@ -505,19 +585,20 @@ var FastClawClient = class {
505
585
  }
506
586
  };
507
587
 
508
- // src/commands/admin/apps.ts
509
- function getClient(program2) {
510
- const opts = program2.parent.parent.opts();
588
+ // src/commands/app/index.ts
589
+ function getClient(app) {
590
+ const opts = app.parent.opts();
511
591
  const cfg = resolveConfig(opts);
512
592
  requireOption(cfg.adminToken, "admin-token");
513
593
  return { client: new FastClawClient({ url: cfg.url, adminToken: cfg.adminToken }), cfg };
514
594
  }
515
- function registerAppsCommand(admin) {
516
- const apps = admin.command("apps").description("Manage apps");
517
- apps.command("create").description("Create a new app").requiredOption("-n, --name <name>", "App name").option("--url <url>", "App website URL").option("--description <desc>", "App description").option("--owner-email <email>", "Owner email").option("--bot-domain-template <tpl>", "Bot domain template").action(
595
+ function registerAppCommand(program2) {
596
+ const app = program2.command("app").description("Manage apps (requires admin token)");
597
+ app.command("create").description("Create a new app").requiredOption("-n, --name <name>", "App name").option("--url <url>", "App website URL").option("--description <desc>", "App description").option("--owner-email <email>", "Owner email").option("--bot-domain-template <tpl>", "Bot domain template").action(
518
598
  withErrorHandler(async (cmdOpts) => {
519
- const { client, cfg } = getClient(apps);
520
- const app = await client.createApp({
599
+ const { client, cfg } = getClient(app);
600
+ await confirmAction(cfg, `Create app '${cmdOpts.name}'?`);
601
+ const result = await client.createApp({
521
602
  name: cmdOpts.name,
522
603
  url: cmdOpts.url,
523
604
  description: cmdOpts.description,
@@ -525,21 +606,21 @@ function registerAppsCommand(admin) {
525
606
  bot_domain_template: cmdOpts.botDomainTemplate
526
607
  });
527
608
  if (cfg.json) {
528
- printJson(app);
609
+ printJson(result);
529
610
  } else {
530
- printSuccess(`App created: ${app.id}`);
611
+ printSuccess(`App created: ${result.id}`);
531
612
  printKeyValue({
532
- ID: app.id,
533
- Name: app.name,
534
- Token: app.api_token,
535
- Status: app.status
613
+ ID: result.id,
614
+ Name: result.name,
615
+ Token: result.api_token,
616
+ Status: result.status
536
617
  });
537
618
  }
538
619
  })
539
620
  );
540
- apps.command("list").description("List all apps").option("-t, --show-token", "Show full API token (masked by default)").action(
621
+ app.command("list").description("List all apps").option("-t, --show-token", "Show full API token (masked by default)").action(
541
622
  withErrorHandler(async (cmdOpts) => {
542
- const { client, cfg } = getClient(apps);
623
+ const { client, cfg } = getClient(app);
543
624
  const list = await client.listApps();
544
625
  if (cfg.json) {
545
626
  printJson(list);
@@ -560,9 +641,46 @@ function registerAppsCommand(admin) {
560
641
  }
561
642
  })
562
643
  );
563
- apps.command("delete <id>").description("Delete an app").action(
644
+ app.command("get <id>").description("Get app details").action(
564
645
  withErrorHandler(async (id) => {
565
- const { client, cfg } = getClient(apps);
646
+ const { client, cfg } = getClient(app);
647
+ const result = await client.getApp(id);
648
+ if (cfg.json) {
649
+ printJson(result);
650
+ } else {
651
+ printKeyValue({
652
+ ID: result.id,
653
+ Name: result.name,
654
+ URL: result.url || "(none)",
655
+ Description: result.description || "(none)",
656
+ Status: result.status,
657
+ Created: result.created_at
658
+ });
659
+ }
660
+ })
661
+ );
662
+ app.command("update <id>").description("Update an app").option("-n, --name <name>", "App name").option("--url <url>", "App website URL").option("--description <desc>", "App description").option("--owner-email <email>", "Owner email").option("--status <status>", "App status (active/disabled)").action(
663
+ withErrorHandler(async (id, cmdOpts) => {
664
+ const { client, cfg } = getClient(app);
665
+ await confirmAction(cfg, `Update app ${id}?`);
666
+ const result = await client.updateApp(id, {
667
+ name: cmdOpts.name,
668
+ url: cmdOpts.url,
669
+ description: cmdOpts.description,
670
+ owner_email: cmdOpts.ownerEmail,
671
+ status: cmdOpts.status
672
+ });
673
+ if (cfg.json) {
674
+ printJson(result);
675
+ } else {
676
+ printSuccess(`App ${id} updated`);
677
+ }
678
+ })
679
+ );
680
+ app.command("delete <id>").description("Delete an app").action(
681
+ withErrorHandler(async (id) => {
682
+ const { client, cfg } = getClient(app);
683
+ await confirmAction(cfg, `Delete app ${id}? This cannot be undone.`);
566
684
  const res = await client.deleteApp(id);
567
685
  if (cfg.json) {
568
686
  printJson(res);
@@ -571,9 +689,10 @@ function registerAppsCommand(admin) {
571
689
  }
572
690
  })
573
691
  );
574
- apps.command("rotate-token <id>").description("Reset an app's API token").action(
692
+ app.command("rotate-token <id>").description("Reset an app's API token").action(
575
693
  withErrorHandler(async (id) => {
576
- const { client, cfg } = getClient(apps);
694
+ const { client, cfg } = getClient(app);
695
+ await confirmAction(cfg, `Rotate API token for app ${id}?`);
577
696
  const res = await client.rotateAppToken(id);
578
697
  if (cfg.json) {
579
698
  printJson(res);
@@ -585,31 +704,27 @@ function registerAppsCommand(admin) {
585
704
  );
586
705
  }
587
706
 
588
- // src/commands/admin/index.ts
589
- function registerAdminCommand(program2) {
590
- const admin = program2.command("admin").description("Admin operations");
591
- registerAppsCommand(admin);
592
- }
593
-
594
707
  // src/commands/bot/crud.ts
595
708
  import chalk5 from "chalk";
596
709
 
597
710
  // src/commands/bot/resolve.ts
711
+ function getRootOpts(cmd) {
712
+ let root = cmd;
713
+ while (root.parent) root = root.parent;
714
+ return root.opts();
715
+ }
598
716
  function getClient2(cmd) {
599
- const opts = { ...cmd.parent.opts(), ...cmd.opts() };
600
- const cfg = resolveConfig(opts);
717
+ const cfg = resolveConfig(getRootOpts(cmd));
601
718
  requireOption(cfg.appToken, "app-token");
602
719
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
603
720
  }
604
721
  function getAdminClient(cmd) {
605
- const opts = { ...cmd.parent.opts(), ...cmd.opts() };
606
- const cfg = resolveConfig(opts);
722
+ const cfg = resolveConfig(getRootOpts(cmd));
607
723
  requireOption(cfg.adminToken, "admin-token");
608
724
  return { client: new FastClawClient({ url: cfg.url, adminToken: cfg.adminToken }), cfg };
609
725
  }
610
726
  async function resolveClientForBot(cmd, botId) {
611
- const opts = { ...cmd.parent.opts(), ...cmd.opts() };
612
- const cfg = resolveConfig(opts);
727
+ const cfg = resolveConfig(getRootOpts(cmd));
613
728
  if (cfg.appToken) {
614
729
  try {
615
730
  const client = new FastClawClient({ url: cfg.url, appToken: cfg.appToken });
@@ -641,6 +756,7 @@ function registerBotCrudCommands(bot) {
641
756
  bot.command("create").description("Create a new bot").requiredOption("-n, --name <name>", "Bot name").option("--slug <slug>", "URL slug").option("--user-id <userId>", "User ID").option("--expires-at <date>", "Expiration date (ISO-8601)").action(
642
757
  withErrorHandler(async (cmdOpts) => {
643
758
  const { client, cfg } = getClient2(bot);
759
+ await confirmAction(cfg, `Create bot '${cmdOpts.name}'?`);
644
760
  const userId = cmdOpts.userId || cfg.userId;
645
761
  const result = await client.createBot({
646
762
  user_id: userId,
@@ -667,7 +783,7 @@ function registerBotCrudCommands(bot) {
667
783
  withErrorHandler(async (cmdOpts) => {
668
784
  if (cmdOpts.all) {
669
785
  const { client: adminClient, cfg } = getAdminClient(bot);
670
- const userId = cmdOpts.userId || cfg.userId;
786
+ const userId = cmdOpts.userId;
671
787
  const apps = await adminClient.listApps();
672
788
  const allBots = [];
673
789
  for (const app of apps) {
@@ -694,13 +810,13 @@ function registerBotCrudCommands(bot) {
694
810
  console.log(chalk5.dim("No bots found."));
695
811
  } else {
696
812
  printTable(
697
- ["App", "ID", "Name", "Slug", "Status", "Ready", "Created"],
698
- allBots.map((x) => [x.app_name, x.bot.id, x.bot.name, x.bot.slug, x.bot.status, x.ready, x.bot.created_at])
813
+ ["App", "User", "ID", "Name", "Slug", "Status", "Ready", "Created"],
814
+ allBots.map((x) => [x.app_name, x.bot.user_id, x.bot.id, x.bot.name, x.bot.slug, x.bot.status, x.ready, x.bot.created_at])
699
815
  );
700
816
  }
701
817
  } else {
702
818
  const { client, cfg } = getClient2(bot);
703
- const userId = cmdOpts.userId || cfg.userId;
819
+ const userId = cmdOpts.userId;
704
820
  const list = await client.listBots(userId);
705
821
  if (cfg.json) {
706
822
  printJson(list);
@@ -717,9 +833,9 @@ function registerBotCrudCommands(bot) {
717
833
  } catch {
718
834
  }
719
835
  }
720
- rows.push([b.id, b.name, b.slug, b.status, ready, b.created_at]);
836
+ rows.push([b.user_id, b.id, b.name, b.slug, b.status, ready, b.created_at]);
721
837
  }
722
- printTable(["ID", "Name", "Slug", "Status", "Ready", "Created"], rows);
838
+ printTable(["User", "ID", "Name", "Slug", "Status", "Ready", "Created"], rows);
723
839
  }
724
840
  }
725
841
  })
@@ -751,6 +867,7 @@ function registerBotCrudCommands(bot) {
751
867
  bot.command("update <id>").description("Update a bot").option("-n, --name <name>", "New name").option("--slug <slug>", "New slug").option("--expires-at <date>", "New expiration date").action(
752
868
  withErrorHandler(async (id, cmdOpts) => {
753
869
  const { client, cfg } = await resolveClientForBot(bot, id);
870
+ await confirmAction(cfg, `Update bot ${id}?`);
754
871
  const result = await client.updateBot(id, {
755
872
  name: cmdOpts.name,
756
873
  slug: cmdOpts.slug,
@@ -766,6 +883,7 @@ function registerBotCrudCommands(bot) {
766
883
  bot.command("delete <id>").description("Delete a bot").action(
767
884
  withErrorHandler(async (id) => {
768
885
  const { client, cfg } = await resolveClientForBot(bot, id);
886
+ await confirmAction(cfg, `Delete bot ${id}? This cannot be undone.`);
769
887
  const res = await client.deleteBot(id);
770
888
  if (cfg.json) {
771
889
  printJson(res);
@@ -809,6 +927,7 @@ function registerBotLifecycleCommands(bot) {
809
927
  bot.command("stop <id>").description("Stop a bot").action(
810
928
  withErrorHandler(async (id) => {
811
929
  const { client, cfg } = await resolveClientForBot(bot, id);
930
+ await confirmAction(cfg, `Stop bot ${id}?`);
812
931
  const res = await client.stopBot(id);
813
932
  if (cfg.json) {
814
933
  printJson(res);
@@ -820,6 +939,7 @@ function registerBotLifecycleCommands(bot) {
820
939
  bot.command("restart <id>").description("Restart a bot").action(
821
940
  withErrorHandler(async (id) => {
822
941
  const { client, cfg } = await resolveClientForBot(bot, id);
942
+ await confirmAction(cfg, `Restart bot ${id}?`);
823
943
  const res = await client.restartBot(id);
824
944
  if (cfg.json) {
825
945
  printJson(res);
@@ -880,6 +1000,7 @@ function registerBotLifecycleCommands(bot) {
880
1000
  bot.command("reset-token <id>").description("Reset bot access token").action(
881
1001
  withErrorHandler(async (id) => {
882
1002
  const { client, cfg } = await resolveClientForBot(bot, id);
1003
+ await confirmAction(cfg, `Reset access token for bot ${id}?`);
883
1004
  const res = await client.resetBotToken(id);
884
1005
  if (cfg.json) {
885
1006
  printJson(res);
@@ -894,32 +1015,175 @@ function registerBotLifecycleCommands(bot) {
894
1015
  );
895
1016
  }
896
1017
 
897
- // src/commands/bot/index.ts
898
- function registerBotCommand(program2) {
899
- const bot = program2.command("bot").description("Manage bots").option("--user-id <userId>", "User ID for bot operations");
900
- registerBotCrudCommands(bot);
901
- registerBotLifecycleCommands(bot);
1018
+ // src/commands/bot/logs.ts
1019
+ function registerBotLogsCommands(bot) {
1020
+ bot.command("logs <id>").description("Get pod logs for a running bot").option("--tail <lines>", "Number of lines from the end (default: 100)").option("--since <seconds>", "Logs newer than N seconds").option("--since-time <time>", "Logs newer than RFC3339 timestamp").option("--timestamps", "Show timestamps on each line").action(
1021
+ withErrorHandler(async (id, cmdOpts) => {
1022
+ const { client, cfg } = await resolveClientForBot(bot, id);
1023
+ const res = await client.getBotLogs(id, {
1024
+ tail: cmdOpts.tail ? parseInt(cmdOpts.tail, 10) : void 0,
1025
+ sinceSeconds: cmdOpts.since ? parseInt(cmdOpts.since, 10) : void 0,
1026
+ sinceTime: cmdOpts.sinceTime,
1027
+ timestamps: cmdOpts.timestamps
1028
+ });
1029
+ if (cfg.json) {
1030
+ printJson(res);
1031
+ } else {
1032
+ process.stdout.write(res.logs);
1033
+ }
1034
+ })
1035
+ );
902
1036
  }
903
1037
 
904
- // src/commands/model/provider.ts
905
- import chalk7 from "chalk";
906
-
907
- // src/utils/prompt.ts
908
- import { input, select, password, confirm } from "@inquirer/prompts";
909
- async function promptText(message, defaultValue) {
910
- return input({ message, default: defaultValue });
911
- }
912
- async function promptPassword(message) {
913
- return password({ message, mask: "\u2022" });
914
- }
915
- async function promptSelect(message, choices) {
916
- return select({ message, choices });
1038
+ // src/commands/bot/runtime.ts
1039
+ function registerBotRuntimeCommands(bot) {
1040
+ const runtime = bot.command("runtime").description("OpenClaw runtime introspection (requires running bot)");
1041
+ runtime.command("status <id>").description("Get OpenClaw runtime status").option("--all", "Include all status sections").option("--usage", "Include usage info").option("--deep", "Deep connectivity check").option("--timeout <ms>", "Timeout for deep checks").action(
1042
+ withErrorHandler(async (id, cmdOpts) => {
1043
+ const { client, cfg } = await resolveClientForBot(bot, id);
1044
+ const res = await client.getRuntimeStatus(id, {
1045
+ all: cmdOpts.all,
1046
+ usage: cmdOpts.usage,
1047
+ deep: cmdOpts.deep,
1048
+ timeout: cmdOpts.timeout
1049
+ });
1050
+ if (cfg.json) {
1051
+ printJson(res);
1052
+ } else {
1053
+ const data = res;
1054
+ const gw = data.gateway;
1055
+ const os = data.os;
1056
+ const sessions = data.sessions;
1057
+ printKeyValue({
1058
+ "OS": os?.label ?? "unknown",
1059
+ "Gateway": gw?.reachable ? `reachable (${gw.mode})` : `${gw?.error ?? "unreachable"}`,
1060
+ "Sessions": String(sessions?.count ?? "?"),
1061
+ "Update Channel": data.updateChannel ?? "unknown"
1062
+ });
1063
+ }
1064
+ })
1065
+ );
1066
+ runtime.command("sessions <id>").description("List OpenClaw sessions").option("--agent <name>", "Filter by agent").option("--all-agents", "Show sessions from all agents").option("--active", "Show only active sessions").action(
1067
+ withErrorHandler(async (id, cmdOpts) => {
1068
+ const { client, cfg } = await resolveClientForBot(bot, id);
1069
+ const res = await client.getRuntimeSessions(id, {
1070
+ agent: cmdOpts.agent,
1071
+ allAgents: cmdOpts.allAgents,
1072
+ active: cmdOpts.active
1073
+ });
1074
+ if (cfg.json) {
1075
+ printJson(res);
1076
+ } else {
1077
+ const data = res;
1078
+ const sessions = data.sessions ?? [];
1079
+ if (sessions.length === 0) {
1080
+ console.log(" No sessions found");
1081
+ return;
1082
+ }
1083
+ printTable(
1084
+ ["Session ID", "Agent", "Model", "Kind"],
1085
+ sessions.map((s) => [
1086
+ s.sessionId?.slice(0, 8) ?? "?",
1087
+ s.agentId ?? "?",
1088
+ s.model ?? "?",
1089
+ s.kind ?? "?"
1090
+ ])
1091
+ );
1092
+ }
1093
+ })
1094
+ );
1095
+ runtime.command("config <id>").description("Get OpenClaw runtime config").option("--path <path>", "Config path (e.g. gateway, models)").action(
1096
+ withErrorHandler(async (id, cmdOpts) => {
1097
+ const { client } = await resolveClientForBot(bot, id);
1098
+ const res = await client.getRuntimeConfig(id, cmdOpts.path);
1099
+ printJson(res);
1100
+ })
1101
+ );
1102
+ runtime.command("config-validate <id>").description("Validate OpenClaw runtime config").action(
1103
+ withErrorHandler(async (id) => {
1104
+ const { client, cfg } = await resolveClientForBot(bot, id);
1105
+ const res = await client.getRuntimeConfigValidate(id);
1106
+ if (cfg.json) {
1107
+ printJson(res);
1108
+ } else {
1109
+ const data = res;
1110
+ printKeyValue({
1111
+ "Path": data.path ?? "?",
1112
+ "Valid": data.valid ? "yes" : "no"
1113
+ });
1114
+ }
1115
+ })
1116
+ );
1117
+ runtime.command("models <id>").description("Get OpenClaw runtime model status").option("--all", "Show all model info").option("--agent <name>", "Filter by agent").option("--provider <name>", "Filter by provider").action(
1118
+ withErrorHandler(async (id, cmdOpts) => {
1119
+ const { client } = await resolveClientForBot(bot, id);
1120
+ const res = await client.getRuntimeModels(id, {
1121
+ all: cmdOpts.all,
1122
+ agent: cmdOpts.agent,
1123
+ provider: cmdOpts.provider
1124
+ });
1125
+ printJson(res);
1126
+ })
1127
+ );
1128
+ runtime.command("skills <id>").description("List OpenClaw runtime skills").option("--eligible", "Show only eligible skills").option("--verbose", "Show detailed skill info").action(
1129
+ withErrorHandler(async (id, cmdOpts) => {
1130
+ const { client, cfg } = await resolveClientForBot(bot, id);
1131
+ const res = await client.getRuntimeSkills(id, {
1132
+ eligible: cmdOpts.eligible,
1133
+ verbose: cmdOpts.verbose
1134
+ });
1135
+ if (cfg.json) {
1136
+ printJson(res);
1137
+ } else {
1138
+ const data = res;
1139
+ const skills = data.skills ?? [];
1140
+ if (skills.length === 0) {
1141
+ console.log(" No skills found");
1142
+ return;
1143
+ }
1144
+ printTable(
1145
+ ["Name", "Eligible", "Source"],
1146
+ skills.map((s) => [
1147
+ s.name ?? "?",
1148
+ s.eligible ? "yes" : "no",
1149
+ s.source ?? "?"
1150
+ ])
1151
+ );
1152
+ }
1153
+ })
1154
+ );
1155
+ runtime.command("skills-check <id>").description("Check OpenClaw skill requirements").action(
1156
+ withErrorHandler(async (id) => {
1157
+ const { client, cfg } = await resolveClientForBot(bot, id);
1158
+ const res = await client.getRuntimeSkillsCheck(id);
1159
+ if (cfg.json) {
1160
+ printJson(res);
1161
+ } else {
1162
+ const data = res;
1163
+ const eligible = data.eligible ?? [];
1164
+ const blocked = data.blocked ?? [];
1165
+ const disabled = data.disabled ?? [];
1166
+ printKeyValue({
1167
+ "Eligible": eligible.join(", ") || "(none)",
1168
+ "Blocked": blocked.join(", ") || "(none)",
1169
+ "Disabled": disabled.join(", ") || "(none)"
1170
+ });
1171
+ }
1172
+ })
1173
+ );
1174
+ runtime.command("exec <id>").description("Execute arbitrary openclaw CLI command (e.g. --cmd 'status --all --json')").requiredOption("-c, --cmd <command>", "The openclaw CLI command to execute").action(
1175
+ withErrorHandler(async (id, cmdOpts) => {
1176
+ const { client } = await resolveClientForBot(bot, id);
1177
+ const res = await client.runtimeExec(id, { command: cmdOpts.cmd });
1178
+ printJson(res);
1179
+ })
1180
+ );
917
1181
  }
918
1182
 
919
1183
  // src/commands/model/provider.ts
920
- function getClient3(model) {
921
- const opts = model.parent.opts();
922
- const cfg = resolveConfig(opts);
1184
+ import chalk7 from "chalk";
1185
+ function getClient3(cmd) {
1186
+ const cfg = resolveConfig(getRootOpts(cmd));
923
1187
  requireOption(cfg.appToken, "app-token");
924
1188
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
925
1189
  }
@@ -959,6 +1223,7 @@ function registerModelProviderCommands(model) {
959
1223
  apiKey = apiKey || await promptPassword("API Key:");
960
1224
  provider = { name: providerName, apiKey, models: [] };
961
1225
  }
1226
+ await confirmAction(cfg, `Add provider '${provider.name}' to bot ${botId}?`);
962
1227
  const result = await client.addProvider(botId, provider);
963
1228
  if (cfg.json) {
964
1229
  printJson(result);
@@ -1004,6 +1269,7 @@ function registerModelProviderCommands(model) {
1004
1269
  model.command("delete <bot-id> <provider>").description("Delete a model provider").action(
1005
1270
  withErrorHandler(async (botId, provider) => {
1006
1271
  const { client, cfg } = getClient3(model);
1272
+ await confirmAction(cfg, `Delete provider '${provider}' from bot ${botId}?`);
1007
1273
  await client.deleteProvider(botId, provider);
1008
1274
  if (cfg.json) {
1009
1275
  printJson({ message: "deleted" });
@@ -1033,6 +1299,7 @@ function registerModelProviderCommands(model) {
1033
1299
  const body = {};
1034
1300
  if (cmdOpts.primary) body.primary_model = cmdOpts.primary;
1035
1301
  if (cmdOpts.fallback) body.fallback_model = cmdOpts.fallback;
1302
+ await confirmAction(cfg, `Update default model for bot ${botId}?`);
1036
1303
  const d = await client.setDefaults(botId, body);
1037
1304
  if (cfg.json) {
1038
1305
  printJson(d);
@@ -1055,9 +1322,8 @@ function registerModelCommand(program2) {
1055
1322
 
1056
1323
  // src/commands/channel/crud.ts
1057
1324
  import chalk8 from "chalk";
1058
- function getClient4(parent) {
1059
- const opts = parent.parent.opts();
1060
- const cfg = resolveConfig(opts);
1325
+ function getClient4(cmd) {
1326
+ const cfg = resolveConfig(getRootOpts(cmd));
1061
1327
  requireOption(cfg.appToken, "app-token");
1062
1328
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
1063
1329
  }
@@ -1095,6 +1361,7 @@ function registerChannelCrudCommands(channel) {
1095
1361
  { name: "Disabled", value: "disabled" }
1096
1362
  ]);
1097
1363
  }
1364
+ await confirmAction(cfg, `Add channel '${channelType}' to bot ${botId}?`);
1098
1365
  const result = await client.addChannel(botId, req);
1099
1366
  if (cfg.json) {
1100
1367
  printJson(result);
@@ -1125,6 +1392,7 @@ function registerChannelCrudCommands(channel) {
1125
1392
  channel.command("remove <bot-id> <channel>").description("Remove a channel").option("--account <name>", "Specific account to remove").action(
1126
1393
  withErrorHandler(async (botId, ch, cmdOpts) => {
1127
1394
  const { client, cfg } = getClient4(channel);
1395
+ await confirmAction(cfg, `Remove channel '${ch}' from bot ${botId}?`);
1128
1396
  const result = await client.removeChannel(botId, ch, cmdOpts.account);
1129
1397
  if (cfg.json) {
1130
1398
  printJson(result);
@@ -1136,10 +1404,8 @@ function registerChannelCrudCommands(channel) {
1136
1404
  }
1137
1405
 
1138
1406
  // src/commands/channel/pairing.ts
1139
- function getClient5(parent) {
1140
- const root = parent.parent.parent;
1141
- const opts = root.opts();
1142
- const cfg = resolveConfig(opts);
1407
+ function getClient5(cmd) {
1408
+ const cfg = resolveConfig(getRootOpts(cmd));
1143
1409
  requireOption(cfg.appToken, "app-token");
1144
1410
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
1145
1411
  }
@@ -1159,6 +1425,7 @@ function registerPairingCommands(channel) {
1159
1425
  pairing.command("approve <bot-id> <channel>").description("Approve a pairing request").requiredOption("--code <code>", "Pairing code").action(
1160
1426
  withErrorHandler(async (botId, ch, cmdOpts) => {
1161
1427
  const { client, cfg } = getClient5(pairing);
1428
+ await confirmAction(cfg, `Approve pairing for channel '${ch}'?`);
1162
1429
  const result = await client.approvePairing(botId, ch, { code: cmdOpts.code });
1163
1430
  if (cfg.json) {
1164
1431
  printJson(result);
@@ -1170,6 +1437,7 @@ function registerPairingCommands(channel) {
1170
1437
  pairing.command("revoke <bot-id> <channel>").description("Revoke a user's pairing").requiredOption("--user-id <userId>", "User ID to revoke").action(
1171
1438
  withErrorHandler(async (botId, ch, cmdOpts) => {
1172
1439
  const { client, cfg } = getClient5(pairing);
1440
+ await confirmAction(cfg, `Revoke pairing for user '${cmdOpts.userId}' on channel '${ch}'?`);
1173
1441
  const result = await client.revokePairing(botId, ch, { user_id: cmdOpts.userId });
1174
1442
  if (cfg.json) {
1175
1443
  printJson(result);
@@ -1200,9 +1468,8 @@ function registerChannelCommand(program2) {
1200
1468
 
1201
1469
  // src/commands/device/crud.ts
1202
1470
  import chalk9 from "chalk";
1203
- function getClient6(device) {
1204
- const opts = device.parent.opts();
1205
- const cfg = resolveConfig(opts);
1471
+ function getClient6(cmd) {
1472
+ const cfg = resolveConfig(getRootOpts(cmd));
1206
1473
  requireOption(cfg.appToken, "app-token");
1207
1474
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
1208
1475
  }
@@ -1237,6 +1504,7 @@ function registerDeviceCrudCommands(device) {
1237
1504
  device.command("approve <bot-id> <request-id>").description("Approve a device pairing request").action(
1238
1505
  withErrorHandler(async (botId, requestId) => {
1239
1506
  const { client, cfg } = getClient6(device);
1507
+ await confirmAction(cfg, `Approve device ${requestId}?`);
1240
1508
  const result = await client.approveDevice(botId, requestId);
1241
1509
  if (cfg.json) {
1242
1510
  printJson(result);
@@ -1248,6 +1516,7 @@ function registerDeviceCrudCommands(device) {
1248
1516
  device.command("revoke <bot-id> <device-id>").description("Revoke a paired device").option("--role <role>", "Role to revoke", "operator").action(
1249
1517
  withErrorHandler(async (botId, deviceId, cmdOpts) => {
1250
1518
  const { client, cfg } = getClient6(device);
1519
+ await confirmAction(cfg, `Revoke device ${deviceId}?`);
1251
1520
  const result = await client.revokeDevice(botId, deviceId, cmdOpts.role);
1252
1521
  if (cfg.json) {
1253
1522
  printJson(result);
@@ -1267,9 +1536,8 @@ function registerDeviceCommand(program2) {
1267
1536
  // src/commands/skill/crud.ts
1268
1537
  import { readFileSync as readFileSync2 } from "fs";
1269
1538
  import chalk10 from "chalk";
1270
- function getClient7(skill) {
1271
- const opts = skill.parent.opts();
1272
- const cfg = resolveConfig(opts);
1539
+ function getClient7(cmd) {
1540
+ const cfg = resolveConfig(getRootOpts(cmd));
1273
1541
  requireOption(cfg.appToken, "app-token");
1274
1542
  return { client: new FastClawClient({ url: cfg.url, appToken: cfg.appToken }), cfg };
1275
1543
  }
@@ -1298,6 +1566,7 @@ function registerSkillCrudCommands(skill) {
1298
1566
  } else {
1299
1567
  throw new Error("Either --content or --file is required");
1300
1568
  }
1569
+ await confirmAction(cfg, `Set skill '${name}' on bot ${botId}?`);
1301
1570
  const result = await client.setSkill(botId, name, { content });
1302
1571
  if (cfg.json) {
1303
1572
  printJson(result);
@@ -1309,6 +1578,7 @@ function registerSkillCrudCommands(skill) {
1309
1578
  skill.command("delete <bot-id> <name>").description("Delete a skill").action(
1310
1579
  withErrorHandler(async (botId, name) => {
1311
1580
  const { client, cfg } = getClient7(skill);
1581
+ await confirmAction(cfg, `Delete skill '${name}' from bot ${botId}?`);
1312
1582
  const result = await client.deleteSkill(botId, name);
1313
1583
  if (cfg.json) {
1314
1584
  printJson(result);
@@ -1325,6 +1595,19 @@ function registerSkillCommand(program2) {
1325
1595
  registerSkillCrudCommands(skill);
1326
1596
  }
1327
1597
 
1598
+ // src/commands/bot/index.ts
1599
+ function registerBotCommand(program2) {
1600
+ const bot = program2.command("bot").description("Manage bots").option("--user-id <userId>", "User ID for bot operations");
1601
+ registerBotCrudCommands(bot);
1602
+ registerBotLifecycleCommands(bot);
1603
+ registerBotLogsCommands(bot);
1604
+ registerBotRuntimeCommands(bot);
1605
+ registerModelCommand(bot);
1606
+ registerChannelCommand(bot);
1607
+ registerDeviceCommand(bot);
1608
+ registerSkillCommand(bot);
1609
+ }
1610
+
1328
1611
  // src/commands/setup.ts
1329
1612
  import chalk11 from "chalk";
1330
1613
 
@@ -1479,8 +1762,8 @@ function registerSetupCommand(program2) {
1479
1762
  console.log(chalk11.dim("\nUseful commands:"));
1480
1763
  console.log(chalk11.dim(` fastclaw bot status ${bot.id}`));
1481
1764
  console.log(chalk11.dim(` fastclaw bot connect ${bot.id}`));
1482
- console.log(chalk11.dim(` fastclaw model list ${bot.id}`));
1483
- console.log(chalk11.dim(` fastclaw channel add ${bot.id}`));
1765
+ console.log(chalk11.dim(` fastclaw bot model list ${bot.id}`));
1766
+ console.log(chalk11.dim(` fastclaw bot channel add ${bot.id}`));
1484
1767
  console.log("");
1485
1768
  })
1486
1769
  );
@@ -1489,13 +1772,9 @@ function registerSetupCommand(program2) {
1489
1772
  // src/index.ts
1490
1773
  var __dirname = dirname(fileURLToPath(import.meta.url));
1491
1774
  var pkg = JSON.parse(readFileSync3(join2(__dirname, "..", "package.json"), "utf-8"));
1492
- var program = new Command().name("fastclaw").description("CLI for managing FastClaw bots").version(pkg.version).option("--url <url>", "FastClaw server URL").option("--admin-token <token>", "Admin API token").option("--app-token <token>", "App API token").option("--json", "Output as JSON");
1775
+ var program = new Command().name("fastclaw").description("CLI for managing FastClaw bots").version(pkg.version).option("--url <url>", "FastClaw server URL").option("--admin-token <token>", "Admin API token").option("--app-token <token>", "App API token").option("--json", "Output as JSON").option("-y, --yes", "Skip confirmation prompts");
1493
1776
  registerSetupCommand(program);
1494
1777
  registerConfigCommand(program);
1495
- registerAdminCommand(program);
1778
+ registerAppCommand(program);
1496
1779
  registerBotCommand(program);
1497
- registerModelCommand(program);
1498
- registerChannelCommand(program);
1499
- registerDeviceCommand(program);
1500
- registerSkillCommand(program);
1501
1780
  program.parse();
package/dist/sdk.d.ts CHANGED
@@ -172,6 +172,13 @@ interface SkillInfo {
172
172
  interface SetSkillRequest {
173
173
  content: string;
174
174
  }
175
+ interface BotLogsResponse {
176
+ logs: string;
177
+ }
178
+ interface RuntimeExecRequest {
179
+ command?: string;
180
+ args?: string[];
181
+ }
175
182
  interface UpgradeRequest {
176
183
  image?: string;
177
184
  }
@@ -217,7 +224,7 @@ declare class FastClawClient {
217
224
  upgradeBot(id: string, req?: UpgradeRequest): Promise<UpgradeResponse>;
218
225
  upgradeAllBots(req?: UpgradeRequest): Promise<BulkUpgradeResponse>;
219
226
  createBot(req: CreateBotRequest): Promise<Bot>;
220
- listBots(userId: string): Promise<Bot[]>;
227
+ listBots(userId?: string): Promise<Bot[]>;
221
228
  getBot(id: string): Promise<Bot>;
222
229
  updateBot(id: string, req: UpdateBotRequest): Promise<Bot>;
223
230
  deleteBot(id: string): Promise<{
@@ -252,6 +259,36 @@ declare class FastClawClient {
252
259
  listSkills(botId: string): Promise<SkillInfo[]>;
253
260
  setSkill(botId: string, name: string, req: SetSkillRequest): Promise<unknown>;
254
261
  deleteSkill(botId: string, name: string): Promise<unknown>;
262
+ getBotLogs(botId: string, opts?: {
263
+ tail?: number;
264
+ sinceSeconds?: number;
265
+ sinceTime?: string;
266
+ timestamps?: boolean;
267
+ }): Promise<BotLogsResponse>;
268
+ getRuntimeStatus(botId: string, opts?: {
269
+ all?: boolean;
270
+ usage?: boolean;
271
+ deep?: boolean;
272
+ timeout?: string;
273
+ }): Promise<unknown>;
274
+ getRuntimeSessions(botId: string, opts?: {
275
+ agent?: string;
276
+ allAgents?: boolean;
277
+ active?: boolean;
278
+ }): Promise<unknown>;
279
+ getRuntimeConfig(botId: string, path?: string): Promise<unknown>;
280
+ getRuntimeConfigValidate(botId: string): Promise<unknown>;
281
+ getRuntimeModels(botId: string, opts?: {
282
+ all?: boolean;
283
+ agent?: string;
284
+ provider?: string;
285
+ }): Promise<unknown>;
286
+ getRuntimeSkills(botId: string, opts?: {
287
+ eligible?: boolean;
288
+ verbose?: boolean;
289
+ }): Promise<unknown>;
290
+ getRuntimeSkillsCheck(botId: string): Promise<unknown>;
291
+ runtimeExec(botId: string, req: RuntimeExecRequest): Promise<unknown>;
255
292
  waitForReady(botId: string, timeoutMs?: number, intervalMs?: number): Promise<BotStatusResponse>;
256
293
  health(): Promise<boolean>;
257
294
  }
@@ -273,6 +310,7 @@ interface ResolvedConfig {
273
310
  userId: string;
274
311
  botId?: string;
275
312
  json: boolean;
313
+ yes: boolean;
276
314
  }
277
315
  /**
278
316
  * Resolve config with priority: CLI flags > env vars > config file > defaults.
@@ -285,6 +323,7 @@ declare function resolveConfig(opts: {
285
323
  userId?: string;
286
324
  botId?: string;
287
325
  json?: boolean;
326
+ yes?: boolean;
288
327
  }): ResolvedConfig;
289
328
  declare function getConfigPath(): string;
290
329
 
@@ -309,4 +348,4 @@ declare function isValidSlug(slug: string): boolean;
309
348
  declare function isValidUrl(url: string): boolean;
310
349
  declare function slugify(name: string): string;
311
350
 
312
- export { API_BASE, type AddChannelRequest, ApiError, type ApiResponse, type App, type Bot, type BotConnectResponse, type BotStatus, type BotStatusResponse, type BulkUpgradeResponse, CHANNEL_FIELDS, type ChannelResponse, type ChannelsMap, type ClientOptions, type CreateAppRequest, type CreateBotRequest, DEFAULT_URL, DM_POLICIES, type DeviceInfo, type DeviceListResponse, FastClawClient, type FastClawConfig, GROUP_POLICIES, MODEL_PRESETS, type ModelDefaults, type ModelProvider, PROVIDER_DEFAULTS, type PairedUsersResponse, type PairingApproveRequest, type PairingRequest, type PairingRevokeRequest, type ProviderModel, type ResetTokenResponse, type ResolvedConfig, type SetSkillRequest, type SkillInfo, type UpdateAppRequest, type UpdateBotRequest, type UpgradeRequest, type UpgradeResponse, getConfigPath, isValidSlug, isValidUrl, loadConfig, resolveConfig, saveConfig, slugify, updateConfig };
351
+ export { API_BASE, type AddChannelRequest, ApiError, type ApiResponse, type App, type Bot, type BotConnectResponse, type BotLogsResponse, type BotStatus, type BotStatusResponse, type BulkUpgradeResponse, CHANNEL_FIELDS, type ChannelResponse, type ChannelsMap, type ClientOptions, type CreateAppRequest, type CreateBotRequest, DEFAULT_URL, DM_POLICIES, type DeviceInfo, type DeviceListResponse, FastClawClient, type FastClawConfig, GROUP_POLICIES, MODEL_PRESETS, type ModelDefaults, type ModelProvider, PROVIDER_DEFAULTS, type PairedUsersResponse, type PairingApproveRequest, type PairingRequest, type PairingRevokeRequest, type ProviderModel, type ResetTokenResponse, type ResolvedConfig, type RuntimeExecRequest, type SetSkillRequest, type SkillInfo, type UpdateAppRequest, type UpdateBotRequest, type UpgradeRequest, type UpgradeResponse, getConfigPath, isValidSlug, isValidUrl, loadConfig, resolveConfig, saveConfig, slugify, updateConfig };
package/dist/sdk.js CHANGED
@@ -114,6 +114,11 @@ var GROUP_POLICIES = ["open", "allowlist", "disabled"];
114
114
 
115
115
  // src/utils/error.ts
116
116
  import chalk from "chalk";
117
+
118
+ // src/utils/prompt.ts
119
+ import { input, select, password, confirm } from "@inquirer/prompts";
120
+
121
+ // src/utils/error.ts
117
122
  var ApiError = class extends Error {
118
123
  constructor(statusCode, apiCode, message) {
119
124
  super(message);
@@ -206,7 +211,9 @@ var FastClawClient = class {
206
211
  return this.request("POST", "/bots", { body: req });
207
212
  }
208
213
  async listBots(userId) {
209
- return this.request("GET", "/bots", { query: { user_id: userId } });
214
+ const query = {};
215
+ if (userId) query.user_id = userId;
216
+ return this.request("GET", "/bots", { query });
210
217
  }
211
218
  async getBot(id) {
212
219
  return this.request("GET", `/bots/${id}`);
@@ -309,6 +316,58 @@ var FastClawClient = class {
309
316
  async deleteSkill(botId, name) {
310
317
  return this.request("DELETE", `/bots/${botId}/skills/${name}`);
311
318
  }
319
+ // ── Bot Logs ──
320
+ async getBotLogs(botId, opts) {
321
+ const query = {};
322
+ if (opts?.tail !== void 0) query.tail = String(opts.tail);
323
+ if (opts?.sinceSeconds !== void 0) query.sinceSeconds = String(opts.sinceSeconds);
324
+ if (opts?.sinceTime) query.sinceTime = opts.sinceTime;
325
+ if (opts?.timestamps) query.timestamps = "true";
326
+ return this.request("GET", `/bots/${botId}/logs`, { query });
327
+ }
328
+ // ── Bot Runtime (OpenClaw CLI exec) ──
329
+ async getRuntimeStatus(botId, opts) {
330
+ const query = {};
331
+ if (opts?.all) query.all = "true";
332
+ if (opts?.usage) query.usage = "true";
333
+ if (opts?.deep) query.deep = "true";
334
+ if (opts?.timeout) query.timeout = opts.timeout;
335
+ return this.request("GET", `/bots/${botId}/runtime/status`, { query });
336
+ }
337
+ async getRuntimeSessions(botId, opts) {
338
+ const query = {};
339
+ if (opts?.agent) query.agent = opts.agent;
340
+ if (opts?.allAgents) query["all-agents"] = "true";
341
+ if (opts?.active) query.active = "true";
342
+ return this.request("GET", `/bots/${botId}/runtime/sessions`, { query });
343
+ }
344
+ async getRuntimeConfig(botId, path) {
345
+ const query = {};
346
+ if (path) query.path = path;
347
+ return this.request("GET", `/bots/${botId}/runtime/config`, { query });
348
+ }
349
+ async getRuntimeConfigValidate(botId) {
350
+ return this.request("GET", `/bots/${botId}/runtime/config/validate`);
351
+ }
352
+ async getRuntimeModels(botId, opts) {
353
+ const query = {};
354
+ if (opts?.all) query.all = "true";
355
+ if (opts?.agent) query.agent = opts.agent;
356
+ if (opts?.provider) query.provider = opts.provider;
357
+ return this.request("GET", `/bots/${botId}/runtime/models`, { query });
358
+ }
359
+ async getRuntimeSkills(botId, opts) {
360
+ const query = {};
361
+ if (opts?.eligible) query.eligible = "true";
362
+ if (opts?.verbose) query.verbose = "true";
363
+ return this.request("GET", `/bots/${botId}/runtime/skills`, { query });
364
+ }
365
+ async getRuntimeSkillsCheck(botId) {
366
+ return this.request("GET", `/bots/${botId}/runtime/skills/check`);
367
+ }
368
+ async runtimeExec(botId, req) {
369
+ return this.request("POST", `/bots/${botId}/runtime/exec`, { body: req });
370
+ }
312
371
  // ── Utility: wait for bot ready ──
313
372
  async waitForReady(botId, timeoutMs = 12e4, intervalMs = 3e3) {
314
373
  const start = Date.now();
@@ -365,7 +424,8 @@ function resolveConfig(opts) {
365
424
  appToken: opts.appToken || process.env.FASTCLAW_APP_TOKEN || file.app_token,
366
425
  userId: opts.userId || process.env.FASTCLAW_USER_ID || file.default_user_id || "default",
367
426
  botId: opts.botId || process.env.FASTCLAW_BOT_ID || file.default_bot_id,
368
- json: opts.json ?? false
427
+ json: opts.json ?? false,
428
+ yes: opts.yes ?? false
369
429
  };
370
430
  }
371
431
  function getConfigPath() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastclaw-cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "CLI and SDK for managing FastClaw bots",
5
5
  "type": "module",
6
6
  "main": "dist/sdk.js",