clawchef 0.1.10 → 0.1.11

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
@@ -14,6 +14,7 @@ Recipe-driven OpenClaw environment orchestrator.
14
14
  - When installed OpenClaw version mismatches recipe version, prompts: ignore / abort / force reinstall (silent mode auto-picks force reinstall).
15
15
  - Supports scoped execution via `--scope full|files|workspace`.
16
16
  - `full` scope runs factory reset first (with confirmation prompt unless `-s/--silent` is used).
17
+ - Factory reset includes removing local `~/.openclaw` directory.
17
18
  - If `openclaw` is missing, auto-installs the recipe version and skips factory reset.
18
19
  - Starts OpenClaw gateway after each recipe execution based on `--gateway-mode`.
19
20
  - Creates workspaces and agents (default workspace path: `~/.openclaw/workspace-<workspace-name>`).
@@ -392,6 +393,7 @@ channels:
392
393
  token: "${telegram_bot_token}"
393
394
  account: "default"
394
395
  agent: "main"
396
+ group_policy: "allowlist"
395
397
 
396
398
  - channel: "telegram"
397
399
  token: "${alerts_bot_token}"
@@ -412,11 +414,12 @@ channels:
412
414
  Supported common fields:
413
415
 
414
416
  - required: `channel`
415
- - optional: `account`, `agent`, `name`, `token`, `token_file`, `use_env`, `bot_token`, `access_token`, `app_token`, `webhook_url`, `webhook_path`, `signal_number`, `password`, `login`, `login_mode`, `login_account`
417
+ - optional: `account`, `agent`, `group_policy`, `name`, `token`, `token_file`, `use_env`, `bot_token`, `access_token`, `app_token`, `webhook_url`, `webhook_path`, `signal_number`, `password`, `login`, `login_mode`, `login_account`
416
418
  - advanced passthrough: `extra_flags` (`snake_case` keys become `--kebab-case` CLI flags)
417
419
 
418
420
  `channels[].agent` currently supports `channel: "telegram"` only.
419
421
  If `agent` is set and `account` is omitted, clawchef defaults `account` to the same value as `agent`.
422
+ `channels[].group_policy` currently supports `channel: "telegram"` only and is applied after `channels add` via `openclaw config set` so it is not overwritten by add-flow writes.
420
423
 
421
424
  ## Workspace path behavior
422
425
 
@@ -1,4 +1,4 @@
1
- import { tmpdir } from "node:os";
1
+ import { homedir, tmpdir } from "node:os";
2
2
  import path from "node:path";
3
3
  import process from "node:process";
4
4
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
@@ -129,6 +129,13 @@ function parseVersionOutput(output) {
129
129
  const match = output.match(/\b(\d+\.\d+\.\d+)\b/);
130
130
  return match?.[1] ?? output.trim();
131
131
  }
132
+ function telegramGroupPolicyPath(account) {
133
+ const trimmed = account?.trim();
134
+ if (!trimmed) {
135
+ return "channels.telegram.groupPolicy";
136
+ }
137
+ return `channels.telegram.accounts[${trimmed}].groupPolicy`;
138
+ }
132
139
  async function chooseVersionMismatchAction(currentVersion, expectedVersion, silent) {
133
140
  if (silent) {
134
141
  return "force";
@@ -341,10 +348,13 @@ export class CommandOpenClawProvider {
341
348
  async factoryReset(config, dryRun) {
342
349
  const bin = config.bin ?? "openclaw";
343
350
  const resetCmd = commandFor(config, "factory_reset", { bin, version: config.version });
344
- if (!resetCmd.trim()) {
345
- return;
351
+ if (resetCmd.trim()) {
352
+ await runShell(resetCmd, dryRun);
353
+ }
354
+ const openclawHome = path.join(homedir(), ".openclaw");
355
+ if (!dryRun) {
356
+ await rm(openclawHome, { recursive: true, force: true });
346
357
  }
347
- await runShell(resetCmd, dryRun);
348
358
  }
349
359
  async installPlugin(config, pluginSpec, dryRun) {
350
360
  const trimmed = pluginSpec.trim();
@@ -443,6 +453,12 @@ export class CommandOpenClawProvider {
443
453
  }
444
454
  const cmd = `${bin} channels add ${flags.join(" ")}`;
445
455
  await runShell(cmd, dryRun);
456
+ if (channel.channel === "telegram" && channel.group_policy) {
457
+ const configPath = telegramGroupPolicyPath(channel.account);
458
+ const policyValue = JSON.stringify(channel.group_policy);
459
+ const setPolicyCmd = `${bin} config set ${shellQuote(configPath)} ${shellQuote(policyValue)} --strict-json`;
460
+ await runShell(setPolicyCmd, dryRun);
461
+ }
446
462
  }
447
463
  async bindChannelAgent(config, channel, agent, dryRun) {
448
464
  const account = channel.account?.trim();
package/dist/recipe.js CHANGED
@@ -193,6 +193,9 @@ function semanticValidate(recipe) {
193
193
  (channel.login || channel.login_mode !== undefined || channel.login_account !== undefined)) {
194
194
  throw new ClawChefError("channels[] entry for telegram does not support login/login_mode/login_account. Configure token (or use_env/token_file), then start gateway.");
195
195
  }
196
+ if (channel.group_policy !== undefined && channel.channel !== "telegram") {
197
+ throw new ClawChefError(`channels[] entry for ${channel.channel} does not support group_policy. Use channel: telegram.`);
198
+ }
196
199
  if (channel.agent?.trim()) {
197
200
  if (channel.channel !== "telegram") {
198
201
  throw new ClawChefError(`channels[] entry for ${channel.channel} does not support agent binding. Use channel: telegram with agent.`);
package/dist/schema.d.ts CHANGED
@@ -356,6 +356,7 @@ export declare const recipeSchema: z.ZodObject<{
356
356
  channel: z.ZodString;
357
357
  account: z.ZodOptional<z.ZodString>;
358
358
  agent: z.ZodOptional<z.ZodString>;
359
+ group_policy: z.ZodOptional<z.ZodEnum<["open", "allowlist", "disabled"]>>;
359
360
  login: z.ZodOptional<z.ZodBoolean>;
360
361
  login_mode: z.ZodOptional<z.ZodEnum<["interactive"]>>;
361
362
  login_account: z.ZodOptional<z.ZodString>;
@@ -376,6 +377,7 @@ export declare const recipeSchema: z.ZodObject<{
376
377
  token?: string | undefined;
377
378
  account?: string | undefined;
378
379
  agent?: string | undefined;
380
+ group_policy?: "open" | "allowlist" | "disabled" | undefined;
379
381
  login?: boolean | undefined;
380
382
  login_mode?: "interactive" | undefined;
381
383
  login_account?: string | undefined;
@@ -395,6 +397,7 @@ export declare const recipeSchema: z.ZodObject<{
395
397
  token?: string | undefined;
396
398
  account?: string | undefined;
397
399
  agent?: string | undefined;
400
+ group_policy?: "open" | "allowlist" | "disabled" | undefined;
398
401
  login?: boolean | undefined;
399
402
  login_mode?: "interactive" | undefined;
400
403
  login_account?: string | undefined;
@@ -572,6 +575,7 @@ export declare const recipeSchema: z.ZodObject<{
572
575
  token?: string | undefined;
573
576
  account?: string | undefined;
574
577
  agent?: string | undefined;
578
+ group_policy?: "open" | "allowlist" | "disabled" | undefined;
575
579
  login?: boolean | undefined;
576
580
  login_mode?: "interactive" | undefined;
577
581
  login_account?: string | undefined;
@@ -687,6 +691,7 @@ export declare const recipeSchema: z.ZodObject<{
687
691
  token?: string | undefined;
688
692
  account?: string | undefined;
689
693
  agent?: string | undefined;
694
+ group_policy?: "open" | "allowlist" | "disabled" | undefined;
690
695
  login?: boolean | undefined;
691
696
  login_mode?: "interactive" | undefined;
692
697
  login_account?: string | undefined;
package/dist/schema.js CHANGED
@@ -102,6 +102,7 @@ const channelSchema = z
102
102
  channel: z.string().min(1),
103
103
  account: z.string().min(1).optional(),
104
104
  agent: z.string().min(1).optional(),
105
+ group_policy: z.enum(["open", "allowlist", "disabled"]).optional(),
105
106
  login: z.boolean().optional(),
106
107
  login_mode: z.enum(["interactive"]).optional(),
107
108
  login_account: z.string().min(1).optional(),
package/dist/types.d.ts CHANGED
@@ -77,6 +77,7 @@ export interface ChannelDef {
77
77
  channel: string;
78
78
  account?: string;
79
79
  agent?: string;
80
+ group_policy?: "open" | "allowlist" | "disabled";
80
81
  login?: boolean;
81
82
  login_mode?: "interactive";
82
83
  login_account?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawchef",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Recipe-driven OpenClaw environment orchestrator",
5
5
  "homepage": "https://renorzr.github.io/clawchef",
6
6
  "repository": {
@@ -1,4 +1,4 @@
1
- import { tmpdir } from "node:os";
1
+ import { homedir, tmpdir } from "node:os";
2
2
  import path from "node:path";
3
3
  import process from "node:process";
4
4
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
@@ -178,6 +178,14 @@ function parseVersionOutput(output: string): string {
178
178
  return match?.[1] ?? output.trim();
179
179
  }
180
180
 
181
+ function telegramGroupPolicyPath(account: string | undefined): string {
182
+ const trimmed = account?.trim();
183
+ if (!trimmed) {
184
+ return "channels.telegram.groupPolicy";
185
+ }
186
+ return `channels.telegram.accounts[${trimmed}].groupPolicy`;
187
+ }
188
+
181
189
  type VersionMismatchChoice = "ignore" | "abort" | "force";
182
190
 
183
191
  async function chooseVersionMismatchAction(
@@ -440,10 +448,14 @@ export class CommandOpenClawProvider implements OpenClawProvider {
440
448
  async factoryReset(config: OpenClawSection, dryRun: boolean): Promise<void> {
441
449
  const bin = config.bin ?? "openclaw";
442
450
  const resetCmd = commandFor(config, "factory_reset", { bin, version: config.version });
443
- if (!resetCmd.trim()) {
444
- return;
451
+ if (resetCmd.trim()) {
452
+ await runShell(resetCmd, dryRun);
453
+ }
454
+
455
+ const openclawHome = path.join(homedir(), ".openclaw");
456
+ if (!dryRun) {
457
+ await rm(openclawHome, { recursive: true, force: true });
445
458
  }
446
- await runShell(resetCmd, dryRun);
447
459
  }
448
460
 
449
461
  async installPlugin(config: OpenClawSection, pluginSpec: string, dryRun: boolean): Promise<void> {
@@ -554,6 +566,13 @@ export class CommandOpenClawProvider implements OpenClawProvider {
554
566
 
555
567
  const cmd = `${bin} channels add ${flags.join(" ")}`;
556
568
  await runShell(cmd, dryRun);
569
+
570
+ if (channel.channel === "telegram" && channel.group_policy) {
571
+ const configPath = telegramGroupPolicyPath(channel.account);
572
+ const policyValue = JSON.stringify(channel.group_policy);
573
+ const setPolicyCmd = `${bin} config set ${shellQuote(configPath)} ${shellQuote(policyValue)} --strict-json`;
574
+ await runShell(setPolicyCmd, dryRun);
575
+ }
557
576
  }
558
577
 
559
578
  async bindChannelAgent(config: OpenClawSection, channel: ChannelDef, agent: string, dryRun: boolean): Promise<void> {
package/src/recipe.ts CHANGED
@@ -252,6 +252,12 @@ function semanticValidate(recipe: Recipe): void {
252
252
  );
253
253
  }
254
254
 
255
+ if (channel.group_policy !== undefined && channel.channel !== "telegram") {
256
+ throw new ClawChefError(
257
+ `channels[] entry for ${channel.channel} does not support group_policy. Use channel: telegram.`,
258
+ );
259
+ }
260
+
255
261
  if (channel.agent?.trim()) {
256
262
  if (channel.channel !== "telegram") {
257
263
  throw new ClawChefError(
package/src/schema.ts CHANGED
@@ -112,6 +112,7 @@ const channelSchema = z
112
112
  channel: z.string().min(1),
113
113
  account: z.string().min(1).optional(),
114
114
  agent: z.string().min(1).optional(),
115
+ group_policy: z.enum(["open", "allowlist", "disabled"]).optional(),
115
116
  login: z.boolean().optional(),
116
117
  login_mode: z.enum(["interactive"]).optional(),
117
118
  login_account: z.string().min(1).optional(),
package/src/types.ts CHANGED
@@ -85,6 +85,7 @@ export interface ChannelDef {
85
85
  channel: string;
86
86
  account?: string;
87
87
  agent?: string;
88
+ group_policy?: "open" | "allowlist" | "disabled";
88
89
  login?: boolean;
89
90
  login_mode?: "interactive";
90
91
  login_account?: string;