clisbot 0.1.50 → 0.1.52

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
@@ -69,8 +69,8 @@ It is not just a tmux bridge with chat glued on top. `clisbot` treats Slack and
69
69
  ### I Just Want To Know What Changed Recently
70
70
 
71
71
  - start with [Recent Release Highlights](#recent-release-highlights)
72
- - then read [v0.1.50 Release Notes](docs/releases/v0.1.50.md) or the
73
- [v0.1.50 Release Guide](docs/updates/releases/v0.1.50-release-guide.md)
72
+ - then read [v0.1.52 Release Notes](docs/releases/v0.1.52.md) or the
73
+ [v0.1.52 Release Guide](docs/updates/releases/v0.1.52-release-guide.md)
74
74
 
75
75
  ## Why I Built This
76
76
 
@@ -89,7 +89,7 @@ The challenge is not whether AI is useful. It is how to make it work at enterpri
89
89
  - Team-first by design, with `AGENTS`, `USER`, and `MEMORY` context bootstrapping shaped for shared team reality instead of only personal solo-assistant flows.
90
90
  - Shared-surface permission control is a first-class feature: a bot can be in a team group but still answer only the specific people you allow there, while sensitive control actions stay behind explicit auth roles and permissions.
91
91
  - Useful for coding, operations, teamwork, and general assistant work, with fast chat controls such as `!<command>`, `/bash <command>`, `/queue`, `/loop`, `/streaming`, and `/mention`.
92
- - New in `v0.1.50`: the AI-native control experience is much better. You can increasingly ask the bot in normal chat to update itself and explain what changed, help with onboarding, add or configure bots and agents, or create recurring schedules and loops for you instead of relying only on slash commands.
92
+ - New in the `v0.1.50` to `v0.1.52` stable line: the AI-native control experience is much better, the default runner startup window is now 60 seconds, and stale old startup-delay pins no longer silently keep upgraded installs on shorter timeouts.
93
93
 
94
94
  ## Who This Fits Best
95
95
 
@@ -185,12 +185,12 @@ Next steps:
185
185
  - `clisbot` also has a smart autopairing path to reduce first-run friction. If
186
186
  you send the bot a DM within the first 30 minutes, you can usually claim the
187
187
  owner role immediately and start using it without a separate pairing round.
188
- - New from `v0.1.50`: the AI-native operator experience is much stronger. You
188
+ - New from the current `v0.1.50` to `v0.1.52` stable line: the AI-native operator experience is much stronger. You
189
189
  can increasingly ask the bot through chat to explain how to use it, update
190
190
  itself and summarize what's new, help onboard you, create or add a new bot or
191
191
  agent, or set up loops and schedules for recurring work instead of relying
192
192
  only on slash commands.
193
- - Existing configs from any version before `0.1.50` update directly to `0.1.50` automatically on first run. clisbot writes a backup first under `~/.clisbot/backups/`, then rewrites the config to the current shape.
193
+ - Existing configs from any version before `0.1.50` still update directly on first run when you install `v0.1.52`. clisbot writes a backup first under `~/.clisbot/backups/`, then rewrites the config to the current `0.1.50` schema shape.
194
194
  - Shared Slack channels, Slack groups, Telegram groups, and Telegram topics are a separate gate: normal users need an explicit route such as `group:<id>` or `topic:<chatId>:<topicId>` before the bot will talk there. Legacy Slack `channel:<id>` input still works for compatibility.
195
195
  - After a shared surface is admitted, per-surface sender control comes from the bot's default shared rule `groups["*"]` plus any route-local `allowUsers` or `blockUsers`.
196
196
  - With that permission model, a bot can be added to a team group but still be
@@ -237,6 +237,10 @@ What happens next:
237
237
 
238
238
  ## Recent Release Highlights
239
239
 
240
+ - `v0.1.52`: clarifies shared-route setup so `routes add ...` clearly means “use the agent currently assigned to that bot by default,” and prunes stale short `startupDelayMs` overrides so upgraded installs can actually inherit the newer 60-second startup default.
241
+ - `v0.1.51`: raises the default runner startup window to 60 seconds across the
242
+ standard CLI families and the shared runner fallback, so slower fresh launches
243
+ are less likely to fail before the first prompt can be submitted.
240
244
  - `v0.1.50`: a much more AI-native operator experience, where you can
241
245
  increasingly talk to the bot to manage itself; plus safer personal and team
242
246
  bots in real Slack and Telegram groups, automatic direct updates from older
@@ -245,7 +249,7 @@ What happens next:
245
249
  streaming/session isolation.
246
250
  - `v0.1.43`: more durable runtime recovery, clearer routed follow-up controls, more truthful tmux prompt submission checks, better queued-start notifications, and safer Slack thread attachment behavior.
247
251
 
248
- What `v0.1.50` most likely means for you:
252
+ What the current stable line most likely means for you:
249
253
 
250
254
  - The headline is AI-native control: ask the bot in chat to queue work,
251
255
  schedule recurring briefs, help update itself, explain release changes, or
@@ -268,6 +272,8 @@ Read the full notes here:
268
272
 
269
273
  - [CHANGELOG.md](CHANGELOG.md)
270
274
  - [Release Notes Index](docs/releases/README.md)
275
+ - [v0.1.52 Release Notes](docs/releases/v0.1.52.md)
276
+ - [v0.1.51 Release Notes](docs/releases/v0.1.51.md)
271
277
  - [v0.1.50 Release Notes](docs/releases/v0.1.50.md)
272
278
  - [v0.1.43 Release Notes](docs/releases/v0.1.43.md)
273
279
  - [v0.1.39 Release Notes](docs/releases/v0.1.39.md)
@@ -302,7 +308,11 @@ Update note for existing installs:
302
308
  - Older installs before `v0.1.50` now update directly on first run with a
303
309
  backup written first, so most people can update and restart without a manual
304
310
  migration pass.
305
- - After you are on `v0.1.50`, future upgrades should feel much more AI-native:
311
+ - `v0.1.52` keeps that direct-upgrade path and does not introduce a new config
312
+ schema bump; it also cleans up stale short startup-delay overrides that would
313
+ otherwise keep some upgraded installs on older timeout behavior.
314
+ - After you are on the `v0.1.50` schema line, future upgrades should feel much
315
+ more AI-native:
306
316
  in many cases you can simply ask the bot to update `clisbot` to the latest
307
317
  version, and it can follow the update guide, perform the upgrade flow, then
308
318
  brief you on what changed.
@@ -410,7 +410,7 @@
410
410
  "--approval-mode=yolo",
411
411
  "--sandbox=false"
412
412
  ],
413
- "startupDelayMs": 15000,
413
+ "startupDelayMs": 60000,
414
414
  "startupRetryCount": 2,
415
415
  "startupRetryDelayMs": 1000,
416
416
  "startupReadyPattern": "Type your message or @path/to/file",
package/dist/main.js CHANGED
@@ -59472,7 +59472,7 @@ function convertLocalDateTimeToUtcMs(params) {
59472
59472
  var SUPPORTED_AGENT_CLI_TOOLS = ["codex", "claude", "gemini"];
59473
59473
  var SUPPORTED_BOOTSTRAP_MODES = ["personal-assistant", "team-assistant"];
59474
59474
  var SESSION_ID_PATTERN = "\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b";
59475
- var INTERACTIVE_CLI_STARTUP_DELAY_MS = 15000;
59475
+ var INTERACTIVE_CLI_STARTUP_DELAY_MS = 60000;
59476
59476
  var DEFAULT_AGENT_TOOL_TEMPLATES = {
59477
59477
  codex: {
59478
59478
  command: "codex",
@@ -60972,7 +60972,7 @@ var runnerDefaultsSchema = exports_external.object({
60972
60972
  socketPath: "~/.clisbot/state/clisbot.sock"
60973
60973
  }),
60974
60974
  trustWorkspace: exports_external.boolean().default(true),
60975
- startupDelayMs: exports_external.number().int().positive().default(3000),
60975
+ startupDelayMs: exports_external.number().int().positive().default(60000),
60976
60976
  startupRetryCount: exports_external.number().int().min(0).default(2),
60977
60977
  startupRetryDelayMs: exports_external.number().int().min(0).default(1000),
60978
60978
  promptSubmitDelayMs: exports_external.number().int().min(0).default(150),
@@ -61452,7 +61452,7 @@ var agentsDefaultsSchema = exports_external.object({
61452
61452
  socketPath: "~/.clisbot/state/clisbot.sock"
61453
61453
  },
61454
61454
  trustWorkspace: true,
61455
- startupDelayMs: 3000,
61455
+ startupDelayMs: 60000,
61456
61456
  startupRetryCount: 2,
61457
61457
  startupRetryDelayMs: 1000,
61458
61458
  promptSubmitDelayMs: 150,
@@ -61913,7 +61913,7 @@ var clisbotConfigSchema = exports_external.object({
61913
61913
  socketPath: "~/.clisbot/state/clisbot.sock"
61914
61914
  },
61915
61915
  trustWorkspace: true,
61916
- startupDelayMs: 3000,
61916
+ startupDelayMs: 60000,
61917
61917
  startupRetryCount: 2,
61918
61918
  startupRetryDelayMs: 1000,
61919
61919
  promptSubmitDelayMs: 150,
@@ -62042,7 +62042,7 @@ var clisbotConfigSchema = exports_external.object({
62042
62042
  socketPath: "~/.clisbot/state/clisbot.sock"
62043
62043
  },
62044
62044
  trustWorkspace: true,
62045
- startupDelayMs: 3000,
62045
+ startupDelayMs: 60000,
62046
62046
  startupRetryCount: 2,
62047
62047
  startupRetryDelayMs: 1000,
62048
62048
  promptSubmitDelayMs: 150,
@@ -62223,6 +62223,7 @@ function assertNoLegacyPrivilegeCommands(value, path = "root") {
62223
62223
  import { basename, dirname as dirname4, join as join5 } from "node:path";
62224
62224
 
62225
62225
  // src/config/persisted-config.ts
62226
+ var MIN_PERSISTED_AGENT_STARTUP_DELAY_MS = 30000;
62226
62227
  var defaultOwnedRunnerFields = {
62227
62228
  codex: ["startupDelayMs", "startupReadyPattern"],
62228
62229
  gemini: [
@@ -62235,7 +62236,7 @@ var defaultOwnedRunnerFields = {
62235
62236
  ]
62236
62237
  };
62237
62238
  var defaultOwnedRunnerDefaultFields = {
62238
- startupDelayMs: 3000
62239
+ startupDelayMs: 60000
62239
62240
  };
62240
62241
  function isRecord5(value) {
62241
62242
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -62265,9 +62266,22 @@ function deleteIfEmpty(owner, key) {
62265
62266
  function defaultRunner(toolId) {
62266
62267
  return buildRunnerFromToolTemplate(toolId, DEFAULT_AGENT_TOOL_TEMPLATES[toolId], undefined);
62267
62268
  }
62269
+ function isStaleStartupDelay(value) {
62270
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value < MIN_PERSISTED_AGENT_STARTUP_DELAY_MS;
62271
+ }
62272
+ function deleteStaleStartupDelay(owner) {
62273
+ if (!owner || !isStaleStartupDelay(owner.startupDelayMs)) {
62274
+ return false;
62275
+ }
62276
+ delete owner.startupDelayMs;
62277
+ return true;
62278
+ }
62268
62279
  function pruneDefaultOwnedFields(params) {
62269
62280
  const defaults = defaultRunner(params.toolId);
62270
62281
  for (const field of defaultOwnedRunnerFields[params.toolId] ?? []) {
62282
+ if (field === "startupDelayMs" && deleteStaleStartupDelay(params.target)) {
62283
+ continue;
62284
+ }
62271
62285
  if (params.force || Object.hasOwn(params.target, field) && areJsonEqual(params.target[field], defaults[field])) {
62272
62286
  delete params.target[field];
62273
62287
  }
@@ -62279,6 +62293,7 @@ function pruneAgentRunnerOverride(runner, cli) {
62279
62293
  return;
62280
62294
  }
62281
62295
  const defaults = defaultRunner(toolId);
62296
+ deleteStaleStartupDelay(runner);
62282
62297
  for (const field of [
62283
62298
  "command",
62284
62299
  "args",
@@ -62296,6 +62311,14 @@ function pruneAgentRunnerOverride(runner, cli) {
62296
62311
  }
62297
62312
  }
62298
62313
  }
62314
+ function pruneAgentRunnerDefaultOverride(runner) {
62315
+ const defaults = runner.defaults;
62316
+ if (!isRecord5(defaults)) {
62317
+ return;
62318
+ }
62319
+ deleteStaleStartupDelay(defaults);
62320
+ deleteIfEmpty(runner, "defaults");
62321
+ }
62299
62322
  function pruneRunnerDefaults(config, forceRunnerStartupDefaults) {
62300
62323
  const runner = nestedRecord(config, ["agents", "defaults", "runner"]);
62301
62324
  if (!runner) {
@@ -62304,6 +62327,9 @@ function pruneRunnerDefaults(config, forceRunnerStartupDefaults) {
62304
62327
  const runnerDefaults = runner.defaults;
62305
62328
  if (isRecord5(runnerDefaults)) {
62306
62329
  for (const [field, defaultValue] of Object.entries(defaultOwnedRunnerDefaultFields)) {
62330
+ if (field === "startupDelayMs" && deleteStaleStartupDelay(runnerDefaults)) {
62331
+ continue;
62332
+ }
62307
62333
  if (forceRunnerStartupDefaults || Object.hasOwn(runnerDefaults, field) && areJsonEqual(runnerDefaults[field], defaultValue)) {
62308
62334
  delete runnerDefaults[field];
62309
62335
  }
@@ -62329,6 +62355,7 @@ function pruneAgentOverrides(config) {
62329
62355
  if (!isRecord5(agent) || !isRecord5(agent.runner)) {
62330
62356
  continue;
62331
62357
  }
62358
+ pruneAgentRunnerDefaultOverride(agent.runner);
62332
62359
  const cli = typeof agent.cli === "string" ? inferAgentCliToolId(agent.cli) ?? undefined : undefined;
62333
62360
  pruneAgentRunnerOverride(agent.runner, cli);
62334
62361
  deleteIfEmpty(agent, "runner");
@@ -62386,15 +62413,34 @@ function pruneCurrentSchemaStartupDefaults(config) {
62386
62413
  const defaults = isRecord6(agents?.defaults) ? agents.defaults : undefined;
62387
62414
  const runner = isRecord6(defaults?.runner) ? defaults.runner : undefined;
62388
62415
  const runnerDefaults = isRecord6(runner?.defaults) ? runner.defaults : undefined;
62389
- const codexRunner = isRecord6(runner?.codex) ? runner.codex : undefined;
62416
+ const familyRunners = ["codex", "claude", "gemini"].map((family) => isRecord6(runner?.[family]) ? runner[family] : undefined);
62417
+ const agentList = Array.isArray(agents?.list) ? agents.list : [];
62390
62418
  let pruned = false;
62391
- if (runnerDefaults?.startupDelayMs === 3000) {
62392
- delete runnerDefaults.startupDelayMs;
62419
+ if (deleteStaleStartupDelay(runnerDefaults)) {
62393
62420
  pruned = true;
62394
62421
  }
62395
- if (codexRunner?.startupDelayMs === 3000) {
62396
- delete codexRunner.startupDelayMs;
62397
- pruned = true;
62422
+ for (const familyRunner of familyRunners) {
62423
+ if (deleteStaleStartupDelay(familyRunner)) {
62424
+ pruned = true;
62425
+ }
62426
+ }
62427
+ for (const agent of agentList) {
62428
+ if (!isRecord6(agent) || !isRecord6(agent.runner)) {
62429
+ continue;
62430
+ }
62431
+ if (deleteStaleStartupDelay(agent.runner)) {
62432
+ pruned = true;
62433
+ }
62434
+ const runnerDefaultsOverride = isRecord6(agent.runner.defaults) ? agent.runner.defaults : undefined;
62435
+ if (deleteStaleStartupDelay(runnerDefaultsOverride)) {
62436
+ if (runnerDefaultsOverride && Object.keys(runnerDefaultsOverride).length === 0) {
62437
+ delete agent.runner.defaults;
62438
+ }
62439
+ if (Object.keys(agent.runner).length === 0) {
62440
+ delete agent.runner;
62441
+ }
62442
+ pruned = true;
62443
+ }
62398
62444
  }
62399
62445
  if (pruned) {
62400
62446
  nextConfig.meta = {
@@ -75477,8 +75523,11 @@ function renderSlackRouteChoiceMessage(params) {
75477
75523
  return [
75478
75524
  "clisbot: this Slack channel is not configured yet.",
75479
75525
  "",
75480
- "Ask the bot owner to do these:",
75526
+ "Ask the bot owner to do this first:",
75481
75527
  `- ${renderCliCommand(`routes add --channel slack group:${params.channelId} --bot default`, { inline: true })}`,
75528
+ " This channel will use the agent currently assigned to this bot by default.",
75529
+ "",
75530
+ "Only if this channel should use a different agent than the one currently assigned to this bot by default:",
75482
75531
  `- ${renderCliCommand(`routes set-agent --channel slack group:${params.channelId} --bot default --agent <id>`, { inline: true })}`,
75483
75532
  "",
75484
75533
  `After that, ${botReference} and send \`\\start\`, \`\\status\`, or \`\\mention\` here.`
@@ -78538,16 +78587,17 @@ function renderTelegramRouteChoiceMessage(params) {
78538
78587
  const lines = [
78539
78588
  topicId != null ? "clisbot: this Telegram topic is not configured yet." : "clisbot: this Telegram group is not configured yet.",
78540
78589
  "",
78541
- "Ask the bot owner to choose one of these:",
78590
+ "Ask the bot owner to do this first:",
78542
78591
  "",
78543
- "Add the whole group to the allowlist:",
78592
+ "Add the whole group route:",
78544
78593
  renderCliCommand(`routes add --channel telegram group:${chatId} --bot default`, { inline: true }),
78594
+ "That group will use the agent currently assigned to that bot by default.",
78545
78595
  "",
78546
- "Bind the whole group to a specific agent:",
78596
+ "Only if that group should use a different agent than the one currently assigned to that bot by default:",
78547
78597
  renderCliCommand(`routes set-agent --channel telegram group:${chatId} --bot default --agent <id>`, { inline: true })
78548
78598
  ];
78549
78599
  if (topicId != null) {
78550
- lines.push("", "Or bind only this topic to a specific agent:", renderCliCommand(`routes add --channel telegram topic:${chatId}:${topicId} --bot default`, { inline: true }), renderCliCommand(`routes set-agent --channel telegram topic:${chatId}:${topicId} --bot default --agent <id>`, { inline: true }));
78600
+ lines.push("", "Or add only this topic route:", renderCliCommand(`routes add --channel telegram topic:${chatId}:${topicId} --bot default`, { inline: true }), "That topic will use the agent currently assigned to that bot by default.", "", "Only if this topic should use a different agent than the one currently assigned to that bot by default:", renderCliCommand(`routes set-agent --channel telegram topic:${chatId}:${topicId} --bot default --agent <id>`, { inline: true }));
78551
78601
  }
78552
78602
  if (params.includeConfigPath) {
78553
78603
  lines.push("", topicId != null ? `Config path: \`bots.telegram.default.groups."${chatId}".topics."${topicId}"\`` : `Config path: \`bots.telegram.default.groups."${chatId}"\``);
@@ -84868,8 +84918,8 @@ function appendChannelNextStepLines(lines, summary, prefix = "") {
84868
84918
  lines.push(`${prefix}- DM the Slack bot first to confirm it responds normally`);
84869
84919
  }
84870
84920
  lines.push(`${prefix}- after DM works, add the bot to the target Slack channel or Telegram group/topic`);
84871
- lines.push(`${prefix}- add the route with ${renderCliCommand("routes add --channel slack group:<channelId> --bot default", { inline: true })} or ${renderCliCommand("routes add --channel telegram group:<chatId> --bot default", { inline: true })}`);
84872
- lines.push(`${prefix}- bind the agent with ${renderCliCommand("routes set-agent --channel slack group:<channelId> --bot default --agent <id>", { inline: true })} or ${renderCliCommand("routes set-agent --channel telegram group:<chatId> --bot default --agent <id>", { inline: true })}`);
84921
+ lines.push(`${prefix}- add the route with ${renderCliCommand("routes add --channel slack group:<channelId> --bot default", { inline: true })} or ${renderCliCommand("routes add --channel telegram group:<chatId> --bot default", { inline: true })}; that route uses the agent currently assigned to that bot by default`);
84922
+ lines.push(`${prefix}- only if you want a different agent there than the one currently assigned to that bot by default, bind it with ${renderCliCommand("routes set-agent --channel slack group:<channelId> --bot default --agent <id>", { inline: true })} or ${renderCliCommand("routes set-agent --channel telegram group:<chatId> --bot default --agent <id>", { inline: true })}`);
84873
84923
  if (telegramEnabled) {
84874
84924
  lines.push(`${prefix}- Telegram: send \`/start\` in the target DM, group, or topic to get onboarding or pairing guidance`);
84875
84925
  }
@@ -85013,9 +85063,9 @@ function appendChannelSetupNote(lines, summary, channel, prefix) {
85013
85063
  lines.push(`${prefix} dms: ${channel.directMessagesEnabled ? `enabled (${channel.directMessagesPolicy})` : "disabled"}`);
85014
85064
  lines.push(`${prefix} sharedDefault: ${channel.sharedDefaultPolicy ?? "n/a"}`);
85015
85065
  lines.push(`${prefix} add group: ${renderCliCommand("routes add --channel telegram group:<chatId> --bot default", { inline: true })}`);
85016
- lines.push(`${prefix} bind group: ${renderCliCommand("routes set-agent --channel telegram group:<chatId> --bot default --agent <id>", { inline: true })}`);
85066
+ lines.push(`${prefix} route uses the agent currently assigned to that bot by default`);
85017
85067
  lines.push(`${prefix} add topic: ${renderCliCommand("routes add --channel telegram topic:<chatId>:<topicId> --bot default", { inline: true })}`);
85018
- lines.push(`${prefix} bind topic: ${renderCliCommand("routes set-agent --channel telegram topic:<chatId>:<topicId> --bot default --agent <id>", { inline: true })}`);
85068
+ lines.push(`${prefix} optional agent override if that surface should use a different agent than the one currently assigned to that bot by default: ${renderCliCommand("routes set-agent --channel telegram group:<chatId> --bot default --agent <id>", { inline: true })} or ${renderCliCommand("routes set-agent --channel telegram topic:<chatId>:<topicId> --bot default --agent <id>", { inline: true })}`);
85019
85069
  lines.push(`${prefix} adjust later: ${renderPrivilegedChatHint(summary, "run in-chat commands here")}`);
85020
85070
  return;
85021
85071
  }
@@ -85023,7 +85073,8 @@ function appendChannelSetupNote(lines, summary, channel, prefix) {
85023
85073
  lines.push(`${prefix} dms: ${channel.directMessagesEnabled ? `enabled (${channel.directMessagesPolicy})` : "disabled"}`);
85024
85074
  lines.push(`${prefix} sharedDefault: ${channel.sharedDefaultPolicy ?? "n/a"}`);
85025
85075
  lines.push(`${prefix} add group: ${renderCliCommand("routes add --channel slack group:<channelId> --bot default", { inline: true })}`);
85026
- lines.push(`${prefix} bind group: ${renderCliCommand("routes set-agent --channel slack group:<channelId> --bot default --agent <id>", { inline: true })}`);
85076
+ lines.push(`${prefix} route uses the agent currently assigned to that bot by default`);
85077
+ lines.push(`${prefix} optional agent override if that route should use a different agent than the one currently assigned to that bot by default: ${renderCliCommand("routes set-agent --channel slack group:<channelId> --bot default --agent <id>", { inline: true })}`);
85027
85078
  lines.push(`${prefix} adjust later: ${renderPrivilegedChatHint(summary, "run in-chat commands here")}`);
85028
85079
  }
85029
85080
  function appendBootstrapGuidance(lines, summary) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clisbot",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "private": false,
5
5
  "description": "Chat surfaces for durable AI coding agents running in tmux",
6
6
  "license": "MIT",