clisbot 0.1.32 → 0.1.36

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.
@@ -97,6 +97,8 @@
97
97
  ],
98
98
  "trustWorkspace": true,
99
99
  "startupDelayMs": 3000,
100
+ "startupRetryCount": 2,
101
+ "startupRetryDelayMs": 1000,
100
102
  "promptSubmitDelayMs": 150,
101
103
  "sessionId": {
102
104
  "create": {
package/dist/main.js CHANGED
@@ -54713,8 +54713,8 @@ function renderCliHelp() {
54713
54713
  " clear-token <slack-app|slack-bot|telegram-bot>",
54714
54714
  " See `clisbot channels --help` for route policy notes and defaults such as `requireMention`.",
54715
54715
  " accounts Manage Slack and Telegram provider accounts plus persistence state.",
54716
- " add telegram --account <id> --token <ENV_NAME|${ENV_NAME}|literal> [--persist]",
54717
- " add slack --account <id> --app-token <ENV_NAME|${ENV_NAME}|literal> --bot-token <ENV_NAME|${ENV_NAME}|literal> [--persist]",
54716
+ " add telegram --account <id> (--token|--telegram-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
54717
+ " add slack --account <id> (--app-token|--slack-app-token) <ENV_NAME|${ENV_NAME}|literal> (--bot-token|--slack-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
54718
54718
  " persist --channel <slack|telegram> --account <id>",
54719
54719
  " persist --all",
54720
54720
  " See `clisbot accounts --help` for env-vs-mem-vs-persist behavior.",
@@ -55261,6 +55261,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
55261
55261
  ],
55262
55262
  trustWorkspace: true,
55263
55263
  startupDelayMs: 3000,
55264
+ startupRetryCount: 2,
55265
+ startupRetryDelayMs: 1000,
55264
55266
  promptSubmitDelayMs: 150,
55265
55267
  sessionId: {
55266
55268
  create: {
@@ -55292,6 +55294,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
55292
55294
  startupOptions: ["--dangerously-skip-permissions"],
55293
55295
  trustWorkspace: true,
55294
55296
  startupDelayMs: 3000,
55297
+ startupRetryCount: 2,
55298
+ startupRetryDelayMs: 1000,
55295
55299
  promptSubmitDelayMs: 150,
55296
55300
  sessionId: {
55297
55301
  create: {
@@ -55320,6 +55324,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
55320
55324
  startupOptions: ["--approval-mode=yolo", "--sandbox=false"],
55321
55325
  trustWorkspace: true,
55322
55326
  startupDelayMs: 15000,
55327
+ startupRetryCount: 2,
55328
+ startupRetryDelayMs: 1000,
55323
55329
  startupReadyPattern: "Type your message or @path/to/file",
55324
55330
  startupBlockers: [
55325
55331
  {
@@ -55359,6 +55365,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
55359
55365
  args: [...options, "-C", "{workspace}"],
55360
55366
  trustWorkspace: template.trustWorkspace,
55361
55367
  startupDelayMs: template.startupDelayMs,
55368
+ startupRetryCount: template.startupRetryCount,
55369
+ startupRetryDelayMs: template.startupRetryDelayMs,
55362
55370
  startupReadyPattern: template.startupReadyPattern,
55363
55371
  startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
55364
55372
  promptSubmitDelayMs: template.promptSubmitDelayMs,
@@ -55383,6 +55391,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
55383
55391
  args: [...options],
55384
55392
  trustWorkspace: template.trustWorkspace,
55385
55393
  startupDelayMs: template.startupDelayMs,
55394
+ startupRetryCount: template.startupRetryCount,
55395
+ startupRetryDelayMs: template.startupRetryDelayMs,
55386
55396
  startupReadyPattern: template.startupReadyPattern,
55387
55397
  startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
55388
55398
  promptSubmitDelayMs: template.promptSubmitDelayMs,
@@ -60047,6 +60057,8 @@ var runnerSchema = exports_external.object({
60047
60057
  ]),
60048
60058
  trustWorkspace: exports_external.boolean().default(true),
60049
60059
  startupDelayMs: exports_external.number().int().positive().default(3000),
60060
+ startupRetryCount: exports_external.number().int().min(0).default(2),
60061
+ startupRetryDelayMs: exports_external.number().int().min(0).default(1000),
60050
60062
  startupReadyPattern: exports_external.string().min(1).optional(),
60051
60063
  startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
60052
60064
  promptSubmitDelayMs: exports_external.number().int().min(0).default(150),
@@ -60083,6 +60095,8 @@ var runnerOverrideSchema = exports_external.object({
60083
60095
  args: exports_external.array(exports_external.string()).optional(),
60084
60096
  trustWorkspace: exports_external.boolean().optional(),
60085
60097
  startupDelayMs: exports_external.number().int().positive().optional(),
60098
+ startupRetryCount: exports_external.number().int().min(0).optional(),
60099
+ startupRetryDelayMs: exports_external.number().int().min(0).optional(),
60086
60100
  startupReadyPattern: exports_external.string().min(1).optional(),
60087
60101
  startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
60088
60102
  promptSubmitDelayMs: exports_external.number().int().min(0).optional(),
@@ -60125,6 +60139,8 @@ var agentDefaultsSchema = exports_external.object({
60125
60139
  ],
60126
60140
  trustWorkspace: true,
60127
60141
  startupDelayMs: 3000,
60142
+ startupRetryCount: 2,
60143
+ startupRetryDelayMs: 1000,
60128
60144
  promptSubmitDelayMs: 150,
60129
60145
  sessionId: defaultRunnerSessionIdConfig
60130
60146
  }),
@@ -60789,6 +60805,8 @@ function renderDefaultConfigTemplate(options = {}) {
60789
60805
  ],
60790
60806
  trustWorkspace: true,
60791
60807
  startupDelayMs: 3000,
60808
+ startupRetryCount: 2,
60809
+ startupRetryDelayMs: 1000,
60792
60810
  startupReadyPattern: undefined,
60793
60811
  promptSubmitDelayMs: 150,
60794
60812
  sessionId: {
@@ -61148,6 +61166,157 @@ function resolveTopLevelBoundAgentId(config, match) {
61148
61166
  });
61149
61167
  }
61150
61168
 
61169
+ // src/control/channel-bootstrap-flags.ts
61170
+ function isLiteralToken(token) {
61171
+ return token?.kind === "mem";
61172
+ }
61173
+ function parseBotType(rawValue) {
61174
+ const value = rawValue.trim().toLowerCase();
61175
+ if (value === "personal") {
61176
+ return "personal-assistant";
61177
+ }
61178
+ if (value === "team") {
61179
+ return "team-assistant";
61180
+ }
61181
+ throw new Error(`Invalid bot type: ${rawValue}. Expected personal or team.`);
61182
+ }
61183
+ function parseOptionValue(args, name, index) {
61184
+ const value = args[index + 1]?.trim();
61185
+ if (!value) {
61186
+ throw new Error(`Missing value for ${name}`);
61187
+ }
61188
+ return value;
61189
+ }
61190
+ function getOrCreateSlackAccount(accounts, accountId) {
61191
+ let account = accounts.find((entry) => entry.accountId === accountId);
61192
+ if (!account) {
61193
+ account = { accountId };
61194
+ accounts.push(account);
61195
+ }
61196
+ return account;
61197
+ }
61198
+ function getOrCreateTelegramAccount(accounts, accountId) {
61199
+ let account = accounts.find((entry) => entry.accountId === accountId);
61200
+ if (!account) {
61201
+ account = { accountId };
61202
+ accounts.push(account);
61203
+ }
61204
+ return account;
61205
+ }
61206
+ function ensureUniqueAccount(accounts, accountId, flagName) {
61207
+ if (accounts.some((entry) => entry.accountId === accountId)) {
61208
+ throw new Error(`Duplicate ${flagName} ${accountId}`);
61209
+ }
61210
+ }
61211
+ function validateSlackAccount(account) {
61212
+ if (!account.appToken || !account.botToken) {
61213
+ throw new Error(`Slack account ${account.accountId} requires both app token and bot token`);
61214
+ }
61215
+ if (account.appToken.kind !== account.botToken.kind) {
61216
+ throw new Error(`Slack account ${account.accountId} must use one credential source kind for both app and bot tokens`);
61217
+ }
61218
+ }
61219
+ function validateTelegramAccount(account) {
61220
+ if (!account.botToken) {
61221
+ throw new Error(`Telegram account ${account.accountId} requires a bot token`);
61222
+ }
61223
+ }
61224
+ function parseBootstrapFlags(args) {
61225
+ const slackAccounts = [];
61226
+ const telegramAccounts = [];
61227
+ let currentSlackAccountId;
61228
+ let currentTelegramAccountId;
61229
+ let cliTool;
61230
+ let bootstrap;
61231
+ let persist = false;
61232
+ let sawCredentialFlags = false;
61233
+ let sawSlackFlags = false;
61234
+ let sawTelegramFlags = false;
61235
+ for (let index = 0;index < args.length; index += 1) {
61236
+ const arg = args[index];
61237
+ if (arg === "--cli") {
61238
+ cliTool = parseOptionValue(args, arg, index);
61239
+ index += 1;
61240
+ continue;
61241
+ }
61242
+ if (arg === "--bot-type") {
61243
+ bootstrap = parseBotType(parseOptionValue(args, arg, index));
61244
+ index += 1;
61245
+ continue;
61246
+ }
61247
+ if (arg === "--persist") {
61248
+ persist = true;
61249
+ continue;
61250
+ }
61251
+ if (arg === "--slack-account") {
61252
+ const accountId = parseOptionValue(args, arg, index);
61253
+ ensureUniqueAccount(slackAccounts, accountId, "--slack-account");
61254
+ currentSlackAccountId = accountId;
61255
+ getOrCreateSlackAccount(slackAccounts, accountId);
61256
+ sawSlackFlags = true;
61257
+ index += 1;
61258
+ continue;
61259
+ }
61260
+ if (arg === "--telegram-account") {
61261
+ const accountId = parseOptionValue(args, arg, index);
61262
+ ensureUniqueAccount(telegramAccounts, accountId, "--telegram-account");
61263
+ currentTelegramAccountId = accountId;
61264
+ getOrCreateTelegramAccount(telegramAccounts, accountId);
61265
+ sawTelegramFlags = true;
61266
+ index += 1;
61267
+ continue;
61268
+ }
61269
+ if (arg === "--slack-app-token") {
61270
+ const token = parseTokenInput(parseOptionValue(args, arg, index));
61271
+ const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
61272
+ account.appToken = token;
61273
+ sawCredentialFlags = true;
61274
+ sawSlackFlags = true;
61275
+ index += 1;
61276
+ continue;
61277
+ }
61278
+ if (arg === "--slack-bot-token") {
61279
+ const token = parseTokenInput(parseOptionValue(args, arg, index));
61280
+ const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
61281
+ account.botToken = token;
61282
+ sawCredentialFlags = true;
61283
+ sawSlackFlags = true;
61284
+ index += 1;
61285
+ continue;
61286
+ }
61287
+ if (arg === "--telegram-bot-token") {
61288
+ const token = parseTokenInput(parseOptionValue(args, arg, index));
61289
+ const account = getOrCreateTelegramAccount(telegramAccounts, currentTelegramAccountId ?? "default");
61290
+ account.botToken = token;
61291
+ sawCredentialFlags = true;
61292
+ sawTelegramFlags = true;
61293
+ index += 1;
61294
+ continue;
61295
+ }
61296
+ throw new Error(`Unknown option for start/init: ${arg}`);
61297
+ }
61298
+ for (const account of slackAccounts) {
61299
+ validateSlackAccount(account);
61300
+ }
61301
+ for (const account of telegramAccounts) {
61302
+ validateTelegramAccount(account);
61303
+ }
61304
+ return {
61305
+ cliTool,
61306
+ bootstrap,
61307
+ persist,
61308
+ slackAccounts,
61309
+ telegramAccounts,
61310
+ sawCredentialFlags,
61311
+ sawSlackFlags,
61312
+ sawTelegramFlags,
61313
+ literalWarnings: []
61314
+ };
61315
+ }
61316
+ function hasLiteralBootstrapCredentials(flags) {
61317
+ return flags.slackAccounts.some((account) => isLiteralToken(account.appToken) || isLiteralToken(account.botToken)) || flags.telegramAccounts.some((account) => isLiteralToken(account.botToken));
61318
+ }
61319
+
61151
61320
  // src/control/agents-cli.ts
61152
61321
  function getEditableConfigPath() {
61153
61322
  return process.env.CLISBOT_CONFIG_PATH;
@@ -61194,8 +61363,8 @@ function renderAgentsHelp() {
61194
61363
  " clisbot agents --help",
61195
61364
  " clisbot agents help",
61196
61365
  " clisbot agents list [--bindings] [--json]",
61197
- " clisbot agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bootstrap <personal-assistant|team-assistant>] [--bind <channel[:accountId]>]...",
61198
- " clisbot agents bootstrap <id> --mode <personal-assistant|team-assistant> [--force]",
61366
+ " clisbot agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bot-type <personal|team>] [--bind <channel[:accountId]>]...",
61367
+ " clisbot agents bootstrap <id> --bot-type <personal|team> [--force]",
61199
61368
  " clisbot agents bindings [--agent <id>] [--json]",
61200
61369
  " clisbot agents bind --agent <id> --bind <channel[:accountId]>",
61201
61370
  " clisbot agents unbind --agent <id> [--bind <channel[:accountId]> | --all]",
@@ -61372,7 +61541,13 @@ async function addAgentToEditableConfig(params) {
61372
61541
  async function addAgent(args) {
61373
61542
  const agentId = args[0]?.trim();
61374
61543
  if (!agentId) {
61375
- throw new Error("Usage: agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bootstrap <personal-assistant|team-assistant>] [--bind <channel[:accountId]>]...");
61544
+ throw new Error("Usage: agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bot-type <personal|team>] [--bind <channel[:accountId]>]...");
61545
+ }
61546
+ if (hasFlag(args, "--bootstrap")) {
61547
+ throw new Error("agents add no longer accepts --bootstrap; use --bot-type personal or --bot-type team");
61548
+ }
61549
+ if (hasFlag(args, "--mode")) {
61550
+ throw new Error("agents add does not use --mode; use --bot-type personal or --bot-type team");
61376
61551
  }
61377
61552
  const cliTool = parseSingleOption(args, "--cli");
61378
61553
  if (!cliTool || !(cliTool in DEFAULT_AGENT_TOOL_TEMPLATES)) {
@@ -61380,9 +61555,10 @@ async function addAgent(args) {
61380
61555
  }
61381
61556
  const workspace = parseSingleOption(args, "--workspace");
61382
61557
  const startupOptions = parseRepeatedOption(args, "--startup-option");
61383
- const bootstrap = parseSingleOption(args, "--bootstrap");
61384
- if (hasFlag(args, "--bootstrap") && (!bootstrap || !SUPPORTED_BOOTSTRAP_MODES.includes(bootstrap))) {
61385
- throw new Error("--bootstrap requires personal-assistant or team-assistant");
61558
+ let bootstrap;
61559
+ const botType = parseSingleOption(args, "--bot-type");
61560
+ if (botType) {
61561
+ bootstrap = parseBotType(botType);
61386
61562
  }
61387
61563
  const bindings = parseRepeatedOption(args, "--bind").map(parseBinding);
61388
61564
  const result = await addAgentToEditableConfig({
@@ -61404,12 +61580,19 @@ async function addAgent(args) {
61404
61580
  async function bootstrapAgent(args) {
61405
61581
  const agentId = args[0]?.trim();
61406
61582
  if (!agentId) {
61407
- throw new Error("Usage: agents bootstrap <id> --mode <personal-assistant|team-assistant> [--force]");
61583
+ throw new Error("Usage: agents bootstrap <id> --bot-type <personal|team> [--force]");
61584
+ }
61585
+ if (hasFlag(args, "--mode")) {
61586
+ throw new Error("agents bootstrap no longer accepts --mode; use --bot-type personal or --bot-type team");
61587
+ }
61588
+ if (hasFlag(args, "--bootstrap")) {
61589
+ throw new Error("agents bootstrap does not use --bootstrap; use --bot-type personal or --bot-type team");
61408
61590
  }
61409
- const mode = parseSingleOption(args, "--mode");
61410
- if (!mode || !SUPPORTED_BOOTSTRAP_MODES.includes(mode)) {
61411
- throw new Error("agents bootstrap requires --mode personal-assistant or --mode team-assistant");
61591
+ const botType = parseSingleOption(args, "--bot-type");
61592
+ if (!botType) {
61593
+ throw new Error("agents bootstrap requires --bot-type personal or --bot-type team");
61412
61594
  }
61595
+ const mode = parseBotType(botType);
61413
61596
  const force = hasFlag(args, "--force");
61414
61597
  const { config, configPath } = await readEditableConfig(getEditableConfigPath());
61415
61598
  const entry = ensureAgentExists(config, agentId);
@@ -64959,6 +65142,8 @@ var PASTE_CAPTURE_REVALIDATE_POLL_INTERVAL_MS = 40;
64959
65142
  var PASTE_CAPTURE_REVALIDATE_MAX_WAIT_MS = 160;
64960
65143
  var SUBMIT_CONFIRM_POLL_INTERVAL_MS = 40;
64961
65144
  var SUBMIT_CONFIRM_MAX_WAIT_MS = 160;
65145
+ var SUBMIT_SNAPSHOT_CONFIRM_POLL_INTERVAL_MS = 40;
65146
+ var SUBMIT_SNAPSHOT_CONFIRM_MAX_WAIT_MS = 320;
64962
65147
  var TMUX_MISSING_TARGET_PATTERN = /(?:no current target|can't find pane|can't find window)/i;
64963
65148
  var TMUX_MISSING_SESSION_PATTERN = /(?:can't find session:|no server running on )/i;
64964
65149
  var TMUX_SERVER_UNAVAILABLE_PATTERN = /(?:No such file or directory|error connecting to|failed to connect to server)/i;
@@ -64998,15 +65183,18 @@ async function submitTmuxSessionInput(params) {
64998
65183
  logLatencyDebug("tmux-paste-unconfirmed", params.timingContext, {
64999
65184
  sessionName: params.sessionName
65000
65185
  });
65001
- throw new Error("tmux paste was not confirmed before Enter. The pane state did not change, so clisbot did not treat the prompt as visibly delivered.");
65186
+ preSubmitState = prePasteState;
65187
+ } else {
65188
+ preSubmitState = await params.tmux.getPaneState(params.sessionName);
65002
65189
  }
65003
- preSubmitState = await params.tmux.getPaneState(params.sessionName);
65004
65190
  }
65005
65191
  await params.tmux.sendKey(params.sessionName, "Enter");
65006
65192
  if (await waitForPaneSubmitConfirmation({
65007
65193
  tmux: params.tmux,
65008
65194
  sessionName: params.sessionName,
65009
- baseline: preSubmitState
65195
+ baseline: preSubmitState,
65196
+ baselineSnapshot: prePasteSnapshot,
65197
+ captureLines
65010
65198
  })) {
65011
65199
  return;
65012
65200
  }
@@ -65017,10 +65205,15 @@ async function submitTmuxSessionInput(params) {
65017
65205
  if (await waitForPaneSubmitConfirmation({
65018
65206
  tmux: params.tmux,
65019
65207
  sessionName: params.sessionName,
65020
- baseline: preSubmitState
65208
+ baseline: preSubmitState,
65209
+ baselineSnapshot: prePasteSnapshot,
65210
+ captureLines
65021
65211
  })) {
65022
65212
  return;
65023
65213
  }
65214
+ if (!pasteSettlement.visible) {
65215
+ throw new Error("tmux paste was not confirmed before Enter, and submission still could not be confirmed after Enter. clisbot did not treat the prompt as truthfully delivered.");
65216
+ }
65024
65217
  logLatencyDebug("tmux-submit-unconfirmed", params.timingContext, {
65025
65218
  sessionName: params.sessionName
65026
65219
  });
@@ -65190,6 +65383,16 @@ async function waitForPaneSubmitConfirmation(params) {
65190
65383
  if (hasPaneStateChanged(params.baseline, state)) {
65191
65384
  return true;
65192
65385
  }
65386
+ const snapshotChanged = await waitForPaneSubmitSnapshotConfirmation({
65387
+ tmux: params.tmux,
65388
+ sessionName: params.sessionName,
65389
+ baselineSnapshot: params.baselineSnapshot,
65390
+ captureLines: params.captureLines,
65391
+ maxWaitMs: Math.min(SUBMIT_SNAPSHOT_CONFIRM_MAX_WAIT_MS, Math.max(0, deadline - Date.now()))
65392
+ });
65393
+ if (snapshotChanged) {
65394
+ return true;
65395
+ }
65193
65396
  const remainingMs = deadline - Date.now();
65194
65397
  if (remainingMs <= 0) {
65195
65398
  return false;
@@ -65197,6 +65400,20 @@ async function waitForPaneSubmitConfirmation(params) {
65197
65400
  await sleep(Math.min(SUBMIT_CONFIRM_POLL_INTERVAL_MS, remainingMs));
65198
65401
  }
65199
65402
  }
65403
+ async function waitForPaneSubmitSnapshotConfirmation(params) {
65404
+ const deadline = Date.now() + params.maxWaitMs;
65405
+ while (true) {
65406
+ const snapshot = normalizePaneText(await params.tmux.capturePane(params.sessionName, params.captureLines));
65407
+ if (snapshot !== params.baselineSnapshot) {
65408
+ return true;
65409
+ }
65410
+ const remainingMs = deadline - Date.now();
65411
+ if (remainingMs <= 0) {
65412
+ return false;
65413
+ }
65414
+ await sleep(Math.min(SUBMIT_SNAPSHOT_CONFIRM_POLL_INTERVAL_MS, remainingMs));
65415
+ }
65416
+ }
65200
65417
  async function waitForPanePasteSettlement(params) {
65201
65418
  await sleep(params.minDelayMs);
65202
65419
  let currentState = await params.tmux.getPaneState(params.sessionName);
@@ -65513,32 +65730,38 @@ class RunnerService {
65513
65730
  pollIntervalMs: capture.pollIntervalMs
65514
65731
  });
65515
65732
  }
65516
- async retryFreshStartWithClearedSessionId(target, resolved, options) {
65517
- if (options.allowRetry === false) {
65733
+ async retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries) {
65734
+ if (remainingFreshRetries <= 0) {
65518
65735
  return null;
65519
65736
  }
65520
65737
  await this.tmux.killSession(resolved.sessionName);
65521
65738
  await this.sessionState.clearSessionIdEntry(resolved, {
65522
65739
  runnerCommand: resolved.runner.command
65523
65740
  });
65741
+ if (resolved.runner.startupRetryDelayMs > 0) {
65742
+ await sleep(resolved.runner.startupRetryDelayMs);
65743
+ }
65524
65744
  return this.ensureSessionReady(target, {
65525
- allowFreshRetry: options.nextAllowFreshRetry
65745
+ remainingFreshRetries: remainingFreshRetries - 1
65526
65746
  });
65527
65747
  }
65528
- async retryAfterStartupFault(target, resolved, error, allowFreshRetry) {
65748
+ async retryAfterStartupFault(target, resolved, error, remainingFreshRetries) {
65529
65749
  if (!isRecoverableStartupSessionLoss(error)) {
65530
65750
  return null;
65531
65751
  }
65532
- return this.retryFreshStartWithClearedSessionId(target, resolved, {
65533
- allowRetry: allowFreshRetry,
65534
- nextAllowFreshRetry: false
65535
- });
65752
+ return this.retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries);
65536
65753
  }
65537
- async retryAfterStartupTimeout(target, resolved, allowFreshRetry) {
65538
- return this.retryFreshStartWithClearedSessionId(target, resolved, {
65539
- allowRetry: allowFreshRetry,
65540
- nextAllowFreshRetry: false
65541
- });
65754
+ async retryAfterStartupTimeout(target, resolved, remainingFreshRetries) {
65755
+ return this.retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries);
65756
+ }
65757
+ resolveRemainingFreshRetries(resolved, options) {
65758
+ if (typeof options.remainingFreshRetries === "number") {
65759
+ return options.remainingFreshRetries;
65760
+ }
65761
+ if (options.allowFreshRetry === false) {
65762
+ return 0;
65763
+ }
65764
+ return resolved.runner.startupRetryCount;
65542
65765
  }
65543
65766
  async abortUnreadySession(resolved, reason, snapshot) {
65544
65767
  await this.tmux.killSession(resolved.sessionName);
@@ -65612,6 +65835,7 @@ class RunnerService {
65612
65835
  sessionKey: resolved.sessionKey,
65613
65836
  sessionName: resolved.sessionName
65614
65837
  };
65838
+ const remainingFreshRetries = this.resolveRemainingFreshRetries(resolved, options);
65615
65839
  logLatencyDebug("ensure-session-ready-start", timingContext);
65616
65840
  await ensureDir2(resolved.workspacePath);
65617
65841
  await ensureDir2(dirname11(this.loadedConfig.raw.tmux.socketPath));
@@ -65684,7 +65908,7 @@ class RunnerService {
65684
65908
  await this.abortUnreadySession(resolved, bootstrapResult.message, bootstrapResult.snapshot);
65685
65909
  }
65686
65910
  if (bootstrapResult.status === "timeout" && resolved.runner.startupReadyPattern) {
65687
- const retried = await this.retryAfterStartupTimeout(target, resolved, options.allowFreshRetry);
65911
+ const retried = await this.retryAfterStartupTimeout(target, resolved, remainingFreshRetries);
65688
65912
  if (retried) {
65689
65913
  return retried;
65690
65914
  }
@@ -65695,7 +65919,7 @@ class RunnerService {
65695
65919
  runnerCommand: runnerLaunch.command
65696
65920
  });
65697
65921
  } catch (error) {
65698
- const retried = await this.retryAfterStartupFault(target, resolved, error, options.allowFreshRetry);
65922
+ const retried = await this.retryAfterStartupFault(target, resolved, error, remainingFreshRetries);
65699
65923
  if (retried) {
65700
65924
  return retried;
65701
65925
  }
@@ -65750,10 +65974,7 @@ class RunnerService {
65750
65974
  if (options.allowFreshRetryBeforePrompt === false || !isRecoverableStartupSessionLoss(error)) {
65751
65975
  throw await this.mapSessionError(error, resolved.sessionName, "before prompt submission", resolved.sessionName ? await this.captureSessionSnapshot(resolved).catch(() => "") : "");
65752
65976
  }
65753
- const retried = await this.retryFreshStartWithClearedSessionId(target, resolved, {
65754
- allowRetry: true,
65755
- nextAllowFreshRetry: false
65756
- });
65977
+ const retried = await this.retryFreshStartWithClearedSessionId(target, resolved, resolved.runner.startupRetryCount);
65757
65978
  if (!retried) {
65758
65979
  throw await this.mapSessionError(error, resolved.sessionName, "before prompt submission", resolved.sessionName ? await this.captureSessionSnapshot(resolved).catch(() => "") : "");
65759
65980
  }
@@ -66262,6 +66483,29 @@ class SessionService {
66262
66483
  canSteerActiveRun(target) {
66263
66484
  return this.activeRuns.get(target.sessionKey)?.steeringReady ?? false;
66264
66485
  }
66486
+ async submitSessionInput(target, text) {
66487
+ const result = await this.runnerSessions.submitSessionInput(target, text);
66488
+ const run = this.activeRuns.get(target.sessionKey);
66489
+ if (!run) {
66490
+ return result;
66491
+ }
66492
+ const startedAt = Date.now();
66493
+ run.startedAt = startedAt;
66494
+ if (run.latestUpdate.status === "detached") {
66495
+ run.latestUpdate = this.createRunUpdate({
66496
+ resolved: run.resolved,
66497
+ status: "running",
66498
+ snapshot: run.latestUpdate.snapshot,
66499
+ fullSnapshot: run.latestUpdate.fullSnapshot,
66500
+ initialSnapshot: run.latestUpdate.initialSnapshot
66501
+ });
66502
+ }
66503
+ await this.sessionState.setSessionRuntime(run.resolved, {
66504
+ state: "running",
66505
+ startedAt
66506
+ });
66507
+ return result;
66508
+ }
66265
66509
  async stop() {
66266
66510
  this.stopping = true;
66267
66511
  const activeRuns = [...this.activeRuns.values()];
@@ -66706,7 +66950,7 @@ class AgentService {
66706
66950
  return this.activeRuns.canSteerActiveRun(target);
66707
66951
  }
66708
66952
  async submitSessionInput(target, text) {
66709
- return this.runnerSessions.submitSessionInput(target, text);
66953
+ return this.activeRuns.submitSessionInput(target, text);
66710
66954
  }
66711
66955
  isSessionBusy(target) {
66712
66956
  return this.activeRuns.hasActiveRun(target) || this.queue.isBusy(target.sessionKey);
@@ -74523,7 +74767,7 @@ function extractLinuxProcState(raw) {
74523
74767
  function getEditableConfigPath5() {
74524
74768
  return process.env.CLISBOT_CONFIG_PATH;
74525
74769
  }
74526
- function parseOptionValue(args, name) {
74770
+ function parseOptionValue2(args, name) {
74527
74771
  const index = args.findIndex((arg) => arg === name);
74528
74772
  if (index === -1) {
74529
74773
  return;
@@ -74534,6 +74778,21 @@ function parseOptionValue(args, name) {
74534
74778
  }
74535
74779
  return value;
74536
74780
  }
74781
+ function parseAliasedOptionValue(args, names, label) {
74782
+ const values = names.flatMap((name) => {
74783
+ const value = parseOptionValue2(args, name);
74784
+ return value === undefined ? [] : [{ name, value }];
74785
+ });
74786
+ if (values.length === 0) {
74787
+ return;
74788
+ }
74789
+ const distinctValues = Array.from(new Set(values.map((entry) => entry.value)));
74790
+ if (distinctValues.length > 1) {
74791
+ const seen = values.map((entry) => `${entry.name}=${entry.value}`).join(", ");
74792
+ throw new Error(`Conflicting values for ${label}: ${seen}`);
74793
+ }
74794
+ return values[values.length - 1]?.value;
74795
+ }
74537
74796
  function hasFlag2(args, name) {
74538
74797
  return args.includes(name);
74539
74798
  }
@@ -74564,13 +74823,14 @@ function renderAccountsHelp() {
74564
74823
  "Usage:",
74565
74824
  " clisbot accounts --help",
74566
74825
  " clisbot accounts help",
74567
- " clisbot accounts add telegram --account <id> --token <ENV_NAME|${ENV_NAME}|literal> [--persist]",
74568
- " clisbot accounts add slack --account <id> --app-token <ENV_NAME|${ENV_NAME}|literal> --bot-token <ENV_NAME|${ENV_NAME}|literal> [--persist]",
74826
+ " clisbot accounts add telegram --account <id> (--token | --telegram-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
74827
+ " clisbot accounts add slack --account <id> (--app-token | --slack-app-token) <ENV_NAME|${ENV_NAME}|literal> (--bot-token | --slack-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
74569
74828
  " clisbot accounts persist --channel <slack|telegram> --account <id>",
74570
74829
  " clisbot accounts persist --all",
74571
74830
  "",
74572
74831
  "Notes:",
74573
74832
  " - env-style input such as `TELEGRAM_BOT_TOKEN` or `${TELEGRAM_BOT_TOKEN}` keeps the account env-backed in config",
74833
+ " - `accounts add` accepts both the short account-local flags and the bootstrap-style channel flags",
74574
74834
  " - literal token input without `--persist` stays runtime-only and requires a running clisbot runtime",
74575
74835
  " - `--persist` writes canonical token files so later plain `clisbot start` can reuse the account safely",
74576
74836
  " - `persist --all` converts every configured `credentialType=mem` account into canonical token files"
@@ -74578,8 +74838,8 @@ function renderAccountsHelp() {
74578
74838
  `);
74579
74839
  }
74580
74840
  async function addTelegramAccount(args, deps) {
74581
- const accountId = parseOptionValue(args, "--account") ?? "default";
74582
- const token = parseTokenInput(parseOptionValue(args, "--token") ?? "");
74841
+ const accountId = parseOptionValue2(args, "--account") ?? "default";
74842
+ const token = parseTokenInput(parseAliasedOptionValue(args, ["--token", "--telegram-bot-token"], "telegram bot token") ?? "");
74583
74843
  const persist = hasFlag2(args, "--persist");
74584
74844
  const runtimeStatus = await deps.getRuntimeStatus();
74585
74845
  if (token.kind === "mem" && !persist && !runtimeStatus.running) {
@@ -74615,9 +74875,9 @@ async function addTelegramAccount(args, deps) {
74615
74875
  console.log(`config: ${configPath}`);
74616
74876
  }
74617
74877
  async function addSlackAccount(args, deps) {
74618
- const accountId = parseOptionValue(args, "--account") ?? "default";
74619
- const appToken = parseTokenInput(parseOptionValue(args, "--app-token") ?? "");
74620
- const botToken = parseTokenInput(parseOptionValue(args, "--bot-token") ?? "");
74878
+ const accountId = parseOptionValue2(args, "--account") ?? "default";
74879
+ const appToken = parseTokenInput(parseAliasedOptionValue(args, ["--app-token", "--slack-app-token"], "slack app token") ?? "");
74880
+ const botToken = parseTokenInput(parseAliasedOptionValue(args, ["--bot-token", "--slack-bot-token"], "slack bot token") ?? "");
74621
74881
  const persist = hasFlag2(args, "--persist");
74622
74882
  const runtimeStatus = await deps.getRuntimeStatus();
74623
74883
  if (appToken.kind !== botToken.kind) {
@@ -74772,8 +75032,8 @@ async function runAccountsCli(args, deps = {}) {
74772
75032
  await persistAllConfiguredAccounts(resolvedDeps);
74773
75033
  return;
74774
75034
  }
74775
- const provider = parseOptionValue(args, "--channel");
74776
- const accountId = parseOptionValue(args, "--account") ?? "default";
75035
+ const provider = parseOptionValue2(args, "--channel");
75036
+ const accountId = parseOptionValue2(args, "--account") ?? "default";
74777
75037
  if (provider !== "slack" && provider !== "telegram") {
74778
75038
  throw new Error(renderAccountsHelp());
74779
75039
  }
@@ -75273,7 +75533,7 @@ function parseResponseModeTarget(channel, raw) {
75273
75533
  }
75274
75534
  return target;
75275
75535
  }
75276
- function parseOptionValue2(args, name) {
75536
+ function parseOptionValue3(args, name) {
75277
75537
  const index = args.findIndex((arg) => arg === name);
75278
75538
  if (index === -1) {
75279
75539
  return;
@@ -75285,7 +75545,7 @@ function parseOptionValue2(args, name) {
75285
75545
  return value;
75286
75546
  }
75287
75547
  function parseBooleanOption(args, name, fallback) {
75288
- const raw = parseOptionValue2(args, name);
75548
+ const raw = parseOptionValue3(args, name);
75289
75549
  if (!raw) {
75290
75550
  return fallback;
75291
75551
  }
@@ -75298,7 +75558,7 @@ function parseBooleanOption(args, name, fallback) {
75298
75558
  throw new Error(`${name} requires true or false`);
75299
75559
  }
75300
75560
  function getAgentId(args) {
75301
- return parseOptionValue2(args, "--agent") ?? "default";
75561
+ return parseOptionValue3(args, "--agent") ?? "default";
75302
75562
  }
75303
75563
  async function setChannelEnabled(action, channel) {
75304
75564
  const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
@@ -75322,7 +75582,7 @@ async function addTelegramGroup(args) {
75322
75582
  throw new Error("Usage: clisbot channels add telegram-group <chatId> [--topic <topicId>] [--agent <id>] [--require-mention true|false]");
75323
75583
  }
75324
75584
  const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
75325
- const topicId = parseOptionValue2(args, "--topic");
75585
+ const topicId = parseOptionValue3(args, "--topic");
75326
75586
  const agentId = getAgentId(args);
75327
75587
  const requireMention = parseBooleanOption(args, "--require-mention", true);
75328
75588
  const groupRoute = config.channels.telegram.groups[chatId] ?? {
@@ -75375,7 +75635,7 @@ async function removeTelegramGroup(args) {
75375
75635
  throw new Error("Usage: clisbot channels remove telegram-group <chatId> [--topic <topicId>]");
75376
75636
  }
75377
75637
  const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
75378
- const topicId = parseOptionValue2(args, "--topic");
75638
+ const topicId = parseOptionValue3(args, "--topic");
75379
75639
  const groupRoute = config.channels.telegram.groups[chatId];
75380
75640
  if (!groupRoute) {
75381
75641
  console.log(`telegram group route ${chatId} is not configured`);
@@ -75517,9 +75777,9 @@ async function runResponseModeCli(args) {
75517
75777
  }
75518
75778
  const responseMode = action === "set" ? parseResponseMode2(args[1]) : undefined;
75519
75779
  const optionArgs = action === "set" ? args.slice(2) : args.slice(1);
75520
- const channel = parseResponseModeChannel(parseOptionValue2(optionArgs, "--channel"));
75521
- const target = parseResponseModeTarget(channel, parseOptionValue2(optionArgs, "--target"));
75522
- const topic = parseOptionValue2(optionArgs, "--topic");
75780
+ const channel = parseResponseModeChannel(parseOptionValue3(optionArgs, "--channel"));
75781
+ const target = parseResponseModeTarget(channel, parseOptionValue3(optionArgs, "--target"));
75782
+ const topic = parseOptionValue3(optionArgs, "--topic");
75523
75783
  if (channel === "slack" && topic) {
75524
75784
  throw new Error("Slack response-mode commands do not support --topic");
75525
75785
  }
@@ -75551,9 +75811,9 @@ async function runAdditionalMessageModeCli(args) {
75551
75811
  }
75552
75812
  const additionalMessageMode = action === "set" ? parseAdditionalMessageMode2(args[1]) : undefined;
75553
75813
  const optionArgs = action === "set" ? args.slice(2) : args.slice(1);
75554
- const channel = parseResponseModeChannel(parseOptionValue2(optionArgs, "--channel"));
75555
- const target = parseResponseModeTarget(channel, parseOptionValue2(optionArgs, "--target"));
75556
- const topic = parseOptionValue2(optionArgs, "--topic");
75814
+ const channel = parseResponseModeChannel(parseOptionValue3(optionArgs, "--channel"));
75815
+ const target = parseResponseModeTarget(channel, parseOptionValue3(optionArgs, "--target"));
75816
+ const topic = parseOptionValue3(optionArgs, "--topic");
75557
75817
  if (channel === "slack" && topic) {
75558
75818
  throw new Error("Slack additional-message-mode commands do not support --topic");
75559
75819
  }
@@ -75843,7 +76103,7 @@ function parseRepeatedOption3(args, name) {
75843
76103
  }
75844
76104
  return values;
75845
76105
  }
75846
- function parseOptionValue3(args, name) {
76106
+ function parseOptionValue4(args, name) {
75847
76107
  const values = parseRepeatedOption3(args, name);
75848
76108
  return values.length > 0 ? values.at(-1) : undefined;
75849
76109
  }
@@ -75856,7 +76116,7 @@ function parseMessageBodyFileOption(args) {
75856
76116
  return bodyFileValues.at(-1) ?? messageFileValues.at(-1);
75857
76117
  }
75858
76118
  function parseIntegerOption(args, name) {
75859
- const raw = parseOptionValue3(args, name);
76119
+ const raw = parseOptionValue4(args, name);
75860
76120
  if (!raw) {
75861
76121
  return;
75862
76122
  }
@@ -75885,34 +76145,34 @@ function parseMessageCommand(args) {
75885
76145
  }
75886
76146
  const action = rawAction;
75887
76147
  const rest = args.slice(1);
75888
- const channel = parseOptionValue3(rest, "--channel");
76148
+ const channel = parseOptionValue4(rest, "--channel");
75889
76149
  if (channel !== "slack" && channel !== "telegram") {
75890
76150
  throw new Error("--channel <slack|telegram> is required");
75891
76151
  }
75892
76152
  return {
75893
76153
  action,
75894
76154
  channel,
75895
- account: parseOptionValue3(rest, "--account"),
75896
- target: parseOptionValue3(rest, "--target"),
75897
- message: parseOptionValue3(rest, "--message") ?? parseOptionValue3(rest, "-m"),
76155
+ account: parseOptionValue4(rest, "--account"),
76156
+ target: parseOptionValue4(rest, "--target"),
76157
+ message: parseOptionValue4(rest, "--message") ?? parseOptionValue4(rest, "-m"),
75898
76158
  messageFile: parseMessageBodyFileOption(rest),
75899
- media: parseOptionValue3(rest, "--media"),
75900
- messageId: parseOptionValue3(rest, "--message-id"),
75901
- emoji: parseOptionValue3(rest, "--emoji"),
76159
+ media: parseOptionValue4(rest, "--media"),
76160
+ messageId: parseOptionValue4(rest, "--message-id"),
76161
+ emoji: parseOptionValue4(rest, "--emoji"),
75902
76162
  remove: hasFlag4(rest, "--remove"),
75903
- threadId: parseOptionValue3(rest, "--thread-id"),
75904
- replyTo: parseOptionValue3(rest, "--reply-to"),
76163
+ threadId: parseOptionValue4(rest, "--thread-id"),
76164
+ replyTo: parseOptionValue4(rest, "--reply-to"),
75905
76165
  limit: parseIntegerOption(rest, "--limit"),
75906
- query: parseOptionValue3(rest, "--query"),
75907
- pollQuestion: parseOptionValue3(rest, "--poll-question"),
76166
+ query: parseOptionValue4(rest, "--query"),
76167
+ pollQuestion: parseOptionValue4(rest, "--poll-question"),
75908
76168
  pollOptions: parseRepeatedOption3(rest, "--poll-option"),
75909
76169
  forceDocument: hasFlag4(rest, "--force-document"),
75910
76170
  silent: hasFlag4(rest, "--silent"),
75911
76171
  progress: hasFlag4(rest, "--progress"),
75912
76172
  final: hasFlag4(rest, "--final"),
75913
76173
  json: hasFlag4(rest, "--json"),
75914
- inputFormat: parseMessageInputFormat(parseOptionValue3(rest, "--input")),
75915
- renderMode: parseMessageRenderMode(parseOptionValue3(rest, "--render"))
76174
+ inputFormat: parseMessageInputFormat(parseOptionValue4(rest, "--input")),
76175
+ renderMode: parseMessageRenderMode(parseOptionValue4(rest, "--render"))
75916
76176
  };
75917
76177
  }
75918
76178
  function renderMessageHelp() {
@@ -76017,162 +76277,6 @@ async function runMessageCli(args, dependencies = defaultMessageCliDependencies)
76017
76277
  dependencies.print(JSON.stringify(execution.result, null, 2));
76018
76278
  }
76019
76279
 
76020
- // src/control/channel-bootstrap-flags.ts
76021
- function isLiteralToken(token) {
76022
- return token?.kind === "mem";
76023
- }
76024
- function parseBotType(rawValue) {
76025
- const value = rawValue.trim().toLowerCase();
76026
- if (value === "personal" || value === "personal-assistant") {
76027
- return "personal-assistant";
76028
- }
76029
- if (value === "team" || value === "team-assistant") {
76030
- return "team-assistant";
76031
- }
76032
- throw new Error(`Invalid bot type: ${rawValue}`);
76033
- }
76034
- function parseOptionValue4(args, name, index) {
76035
- const value = args[index + 1]?.trim();
76036
- if (!value) {
76037
- throw new Error(`Missing value for ${name}`);
76038
- }
76039
- return value;
76040
- }
76041
- function getOrCreateSlackAccount(accounts, accountId) {
76042
- let account = accounts.find((entry) => entry.accountId === accountId);
76043
- if (!account) {
76044
- account = { accountId };
76045
- accounts.push(account);
76046
- }
76047
- return account;
76048
- }
76049
- function getOrCreateTelegramAccount(accounts, accountId) {
76050
- let account = accounts.find((entry) => entry.accountId === accountId);
76051
- if (!account) {
76052
- account = { accountId };
76053
- accounts.push(account);
76054
- }
76055
- return account;
76056
- }
76057
- function ensureUniqueAccount(accounts, accountId, flagName) {
76058
- if (accounts.some((entry) => entry.accountId === accountId)) {
76059
- throw new Error(`Duplicate ${flagName} ${accountId}`);
76060
- }
76061
- }
76062
- function validateSlackAccount(account) {
76063
- if (!account.appToken || !account.botToken) {
76064
- throw new Error(`Slack account ${account.accountId} requires both app token and bot token`);
76065
- }
76066
- if (account.appToken.kind !== account.botToken.kind) {
76067
- throw new Error(`Slack account ${account.accountId} must use one credential source kind for both app and bot tokens`);
76068
- }
76069
- }
76070
- function validateTelegramAccount(account) {
76071
- if (!account.botToken) {
76072
- throw new Error(`Telegram account ${account.accountId} requires a bot token`);
76073
- }
76074
- }
76075
- function parseBootstrapFlags(args) {
76076
- const slackAccounts = [];
76077
- const telegramAccounts = [];
76078
- let currentSlackAccountId;
76079
- let currentTelegramAccountId;
76080
- let cliTool;
76081
- let bootstrap;
76082
- let persist = false;
76083
- let sawCredentialFlags = false;
76084
- let sawSlackFlags = false;
76085
- let sawTelegramFlags = false;
76086
- for (let index = 0;index < args.length; index += 1) {
76087
- const arg = args[index];
76088
- if (arg === "--cli") {
76089
- cliTool = parseOptionValue4(args, arg, index);
76090
- index += 1;
76091
- continue;
76092
- }
76093
- if (arg === "--bootstrap") {
76094
- bootstrap = parseBotType(parseOptionValue4(args, arg, index));
76095
- index += 1;
76096
- continue;
76097
- }
76098
- if (arg === "--bot-type") {
76099
- bootstrap = parseBotType(parseOptionValue4(args, arg, index));
76100
- index += 1;
76101
- continue;
76102
- }
76103
- if (arg === "--persist") {
76104
- persist = true;
76105
- continue;
76106
- }
76107
- if (arg === "--slack-account") {
76108
- const accountId = parseOptionValue4(args, arg, index);
76109
- ensureUniqueAccount(slackAccounts, accountId, "--slack-account");
76110
- currentSlackAccountId = accountId;
76111
- getOrCreateSlackAccount(slackAccounts, accountId);
76112
- sawSlackFlags = true;
76113
- index += 1;
76114
- continue;
76115
- }
76116
- if (arg === "--telegram-account") {
76117
- const accountId = parseOptionValue4(args, arg, index);
76118
- ensureUniqueAccount(telegramAccounts, accountId, "--telegram-account");
76119
- currentTelegramAccountId = accountId;
76120
- getOrCreateTelegramAccount(telegramAccounts, accountId);
76121
- sawTelegramFlags = true;
76122
- index += 1;
76123
- continue;
76124
- }
76125
- if (arg === "--slack-app-token") {
76126
- const token = parseTokenInput(parseOptionValue4(args, arg, index));
76127
- const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
76128
- account.appToken = token;
76129
- sawCredentialFlags = true;
76130
- sawSlackFlags = true;
76131
- index += 1;
76132
- continue;
76133
- }
76134
- if (arg === "--slack-bot-token") {
76135
- const token = parseTokenInput(parseOptionValue4(args, arg, index));
76136
- const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
76137
- account.botToken = token;
76138
- sawCredentialFlags = true;
76139
- sawSlackFlags = true;
76140
- index += 1;
76141
- continue;
76142
- }
76143
- if (arg === "--telegram-bot-token") {
76144
- const token = parseTokenInput(parseOptionValue4(args, arg, index));
76145
- const account = getOrCreateTelegramAccount(telegramAccounts, currentTelegramAccountId ?? "default");
76146
- account.botToken = token;
76147
- sawCredentialFlags = true;
76148
- sawTelegramFlags = true;
76149
- index += 1;
76150
- continue;
76151
- }
76152
- throw new Error(`Unknown option for start/init: ${arg}`);
76153
- }
76154
- for (const account of slackAccounts) {
76155
- validateSlackAccount(account);
76156
- }
76157
- for (const account of telegramAccounts) {
76158
- validateTelegramAccount(account);
76159
- }
76160
- return {
76161
- cliTool,
76162
- bootstrap,
76163
- persist,
76164
- slackAccounts,
76165
- telegramAccounts,
76166
- sawCredentialFlags,
76167
- sawSlackFlags,
76168
- sawTelegramFlags,
76169
- literalWarnings: []
76170
- };
76171
- }
76172
- function hasLiteralBootstrapCredentials(flags) {
76173
- return flags.slackAccounts.some((account) => isLiteralToken(account.appToken) || isLiteralToken(account.botToken)) || flags.telegramAccounts.some((account) => isLiteralToken(account.botToken));
76174
- }
76175
-
76176
76280
  // src/control/activity-store.ts
76177
76281
  import { dirname as dirname14 } from "node:path";
76178
76282
  class ActivityStore {
@@ -76413,10 +76517,11 @@ function appendBootstrapGuidance(lines, summary) {
76413
76517
  lines.push("");
76414
76518
  lines.push("Guidance:");
76415
76519
  for (const agent of pendingBootstrap) {
76520
+ const botType = agent.bootstrapMode === "team-assistant" ? "team" : "personal";
76416
76521
  if (agent.bootstrapState === "missing") {
76417
76522
  lines.push(` Agent ${agent.id} is missing bootstrap files.`);
76418
76523
  lines.push(` workspace: ${agent.workspacePath}`);
76419
- lines.push(` run: clisbot agents bootstrap ${agent.id} --mode ${agent.bootstrapMode}`);
76524
+ lines.push(` run: clisbot agents bootstrap ${agent.id} --bot-type ${botType}`);
76420
76525
  continue;
76421
76526
  }
76422
76527
  lines.push(` Agent ${agent.id} still needs bootstrap completion.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clisbot",
3
- "version": "0.1.32",
3
+ "version": "0.1.36",
4
4
  "private": false,
5
5
  "description": "Chat surfaces for durable AI coding agents running in tmux",
6
6
  "license": "MIT",