clisbot 0.1.32 → 0.1.38
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/config/clisbot.json.template +2 -0
- package/dist/main.js +702 -294
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -54623,6 +54623,12 @@ function parseCliArgs(argv) {
|
|
|
54623
54623
|
args: args.slice(1)
|
|
54624
54624
|
};
|
|
54625
54625
|
}
|
|
54626
|
+
if (command === "runner") {
|
|
54627
|
+
return {
|
|
54628
|
+
name: "runner",
|
|
54629
|
+
args: args.slice(1)
|
|
54630
|
+
};
|
|
54631
|
+
}
|
|
54626
54632
|
if (command === "pairing") {
|
|
54627
54633
|
return {
|
|
54628
54634
|
name: "pairing",
|
|
@@ -54685,6 +54691,7 @@ function renderCliHelp() {
|
|
|
54685
54691
|
" clisbot message <subcommand>",
|
|
54686
54692
|
" clisbot agents <subcommand>",
|
|
54687
54693
|
" clisbot auth <subcommand>",
|
|
54694
|
+
" clisbot runner <subcommand>",
|
|
54688
54695
|
" clisbot pairing <subcommand>",
|
|
54689
54696
|
" clisbot init [--cli <codex|claude|gemini>] [--bot-type <personal|team>] [--persist]",
|
|
54690
54697
|
" [--slack-account <id> --slack-app-token <ENV_NAME|${ENV_NAME}|literal> --slack-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
@@ -54713,8 +54720,8 @@ function renderCliHelp() {
|
|
|
54713
54720
|
" clear-token <slack-app|slack-bot|telegram-bot>",
|
|
54714
54721
|
" See `clisbot channels --help` for route policy notes and defaults such as `requireMention`.",
|
|
54715
54722
|
" 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]",
|
|
54723
|
+
" add telegram --account <id> (--token|--telegram-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
|
|
54724
|
+
" 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
54725
|
" persist --channel <slack|telegram> --account <id>",
|
|
54719
54726
|
" persist --all",
|
|
54720
54727
|
" See `clisbot accounts --help` for env-vs-mem-vs-persist behavior.",
|
|
@@ -54728,6 +54735,8 @@ function renderCliHelp() {
|
|
|
54728
54735
|
" agents Manage configured agents and top-level bindings.",
|
|
54729
54736
|
" See `clisbot agents --help` for focused add/bootstrap/binding help.",
|
|
54730
54737
|
" auth Manage app and agent auth roles, principals, and permissions in config. See `clisbot auth --help`.",
|
|
54738
|
+
" runner Validate and inspect runner-facing operator contracts such as `runner smoke`.",
|
|
54739
|
+
" See `clisbot runner --help` for the current smoke surface.",
|
|
54731
54740
|
" pairing Run the pairing control CLI. See `clisbot pairing --help`.",
|
|
54732
54741
|
` init Seed ${configPath} and optionally create the first agent without starting clisbot.`,
|
|
54733
54742
|
" See `clisbot init --help` for bootstrap-focused flags and examples.",
|
|
@@ -55261,6 +55270,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
|
|
|
55261
55270
|
],
|
|
55262
55271
|
trustWorkspace: true,
|
|
55263
55272
|
startupDelayMs: 3000,
|
|
55273
|
+
startupRetryCount: 2,
|
|
55274
|
+
startupRetryDelayMs: 1000,
|
|
55264
55275
|
promptSubmitDelayMs: 150,
|
|
55265
55276
|
sessionId: {
|
|
55266
55277
|
create: {
|
|
@@ -55292,6 +55303,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
|
|
|
55292
55303
|
startupOptions: ["--dangerously-skip-permissions"],
|
|
55293
55304
|
trustWorkspace: true,
|
|
55294
55305
|
startupDelayMs: 3000,
|
|
55306
|
+
startupRetryCount: 2,
|
|
55307
|
+
startupRetryDelayMs: 1000,
|
|
55295
55308
|
promptSubmitDelayMs: 150,
|
|
55296
55309
|
sessionId: {
|
|
55297
55310
|
create: {
|
|
@@ -55320,6 +55333,8 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
|
|
|
55320
55333
|
startupOptions: ["--approval-mode=yolo", "--sandbox=false"],
|
|
55321
55334
|
trustWorkspace: true,
|
|
55322
55335
|
startupDelayMs: 15000,
|
|
55336
|
+
startupRetryCount: 2,
|
|
55337
|
+
startupRetryDelayMs: 1000,
|
|
55323
55338
|
startupReadyPattern: "Type your message or @path/to/file",
|
|
55324
55339
|
startupBlockers: [
|
|
55325
55340
|
{
|
|
@@ -55359,6 +55374,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
|
|
|
55359
55374
|
args: [...options, "-C", "{workspace}"],
|
|
55360
55375
|
trustWorkspace: template.trustWorkspace,
|
|
55361
55376
|
startupDelayMs: template.startupDelayMs,
|
|
55377
|
+
startupRetryCount: template.startupRetryCount,
|
|
55378
|
+
startupRetryDelayMs: template.startupRetryDelayMs,
|
|
55362
55379
|
startupReadyPattern: template.startupReadyPattern,
|
|
55363
55380
|
startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
|
|
55364
55381
|
promptSubmitDelayMs: template.promptSubmitDelayMs,
|
|
@@ -55383,6 +55400,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
|
|
|
55383
55400
|
args: [...options],
|
|
55384
55401
|
trustWorkspace: template.trustWorkspace,
|
|
55385
55402
|
startupDelayMs: template.startupDelayMs,
|
|
55403
|
+
startupRetryCount: template.startupRetryCount,
|
|
55404
|
+
startupRetryDelayMs: template.startupRetryDelayMs,
|
|
55386
55405
|
startupReadyPattern: template.startupReadyPattern,
|
|
55387
55406
|
startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
|
|
55388
55407
|
promptSubmitDelayMs: template.promptSubmitDelayMs,
|
|
@@ -60047,6 +60066,8 @@ var runnerSchema = exports_external.object({
|
|
|
60047
60066
|
]),
|
|
60048
60067
|
trustWorkspace: exports_external.boolean().default(true),
|
|
60049
60068
|
startupDelayMs: exports_external.number().int().positive().default(3000),
|
|
60069
|
+
startupRetryCount: exports_external.number().int().min(0).default(2),
|
|
60070
|
+
startupRetryDelayMs: exports_external.number().int().min(0).default(1000),
|
|
60050
60071
|
startupReadyPattern: exports_external.string().min(1).optional(),
|
|
60051
60072
|
startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
|
|
60052
60073
|
promptSubmitDelayMs: exports_external.number().int().min(0).default(150),
|
|
@@ -60083,6 +60104,8 @@ var runnerOverrideSchema = exports_external.object({
|
|
|
60083
60104
|
args: exports_external.array(exports_external.string()).optional(),
|
|
60084
60105
|
trustWorkspace: exports_external.boolean().optional(),
|
|
60085
60106
|
startupDelayMs: exports_external.number().int().positive().optional(),
|
|
60107
|
+
startupRetryCount: exports_external.number().int().min(0).optional(),
|
|
60108
|
+
startupRetryDelayMs: exports_external.number().int().min(0).optional(),
|
|
60086
60109
|
startupReadyPattern: exports_external.string().min(1).optional(),
|
|
60087
60110
|
startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
|
|
60088
60111
|
promptSubmitDelayMs: exports_external.number().int().min(0).optional(),
|
|
@@ -60125,6 +60148,8 @@ var agentDefaultsSchema = exports_external.object({
|
|
|
60125
60148
|
],
|
|
60126
60149
|
trustWorkspace: true,
|
|
60127
60150
|
startupDelayMs: 3000,
|
|
60151
|
+
startupRetryCount: 2,
|
|
60152
|
+
startupRetryDelayMs: 1000,
|
|
60128
60153
|
promptSubmitDelayMs: 150,
|
|
60129
60154
|
sessionId: defaultRunnerSessionIdConfig
|
|
60130
60155
|
}),
|
|
@@ -60789,6 +60814,8 @@ function renderDefaultConfigTemplate(options = {}) {
|
|
|
60789
60814
|
],
|
|
60790
60815
|
trustWorkspace: true,
|
|
60791
60816
|
startupDelayMs: 3000,
|
|
60817
|
+
startupRetryCount: 2,
|
|
60818
|
+
startupRetryDelayMs: 1000,
|
|
60792
60819
|
startupReadyPattern: undefined,
|
|
60793
60820
|
promptSubmitDelayMs: 150,
|
|
60794
60821
|
sessionId: {
|
|
@@ -61148,6 +61175,157 @@ function resolveTopLevelBoundAgentId(config, match) {
|
|
|
61148
61175
|
});
|
|
61149
61176
|
}
|
|
61150
61177
|
|
|
61178
|
+
// src/control/channel-bootstrap-flags.ts
|
|
61179
|
+
function isLiteralToken(token) {
|
|
61180
|
+
return token?.kind === "mem";
|
|
61181
|
+
}
|
|
61182
|
+
function parseBotType(rawValue) {
|
|
61183
|
+
const value = rawValue.trim().toLowerCase();
|
|
61184
|
+
if (value === "personal") {
|
|
61185
|
+
return "personal-assistant";
|
|
61186
|
+
}
|
|
61187
|
+
if (value === "team") {
|
|
61188
|
+
return "team-assistant";
|
|
61189
|
+
}
|
|
61190
|
+
throw new Error(`Invalid bot type: ${rawValue}. Expected personal or team.`);
|
|
61191
|
+
}
|
|
61192
|
+
function parseOptionValue(args, name, index) {
|
|
61193
|
+
const value = args[index + 1]?.trim();
|
|
61194
|
+
if (!value) {
|
|
61195
|
+
throw new Error(`Missing value for ${name}`);
|
|
61196
|
+
}
|
|
61197
|
+
return value;
|
|
61198
|
+
}
|
|
61199
|
+
function getOrCreateSlackAccount(accounts, accountId) {
|
|
61200
|
+
let account = accounts.find((entry) => entry.accountId === accountId);
|
|
61201
|
+
if (!account) {
|
|
61202
|
+
account = { accountId };
|
|
61203
|
+
accounts.push(account);
|
|
61204
|
+
}
|
|
61205
|
+
return account;
|
|
61206
|
+
}
|
|
61207
|
+
function getOrCreateTelegramAccount(accounts, accountId) {
|
|
61208
|
+
let account = accounts.find((entry) => entry.accountId === accountId);
|
|
61209
|
+
if (!account) {
|
|
61210
|
+
account = { accountId };
|
|
61211
|
+
accounts.push(account);
|
|
61212
|
+
}
|
|
61213
|
+
return account;
|
|
61214
|
+
}
|
|
61215
|
+
function ensureUniqueAccount(accounts, accountId, flagName) {
|
|
61216
|
+
if (accounts.some((entry) => entry.accountId === accountId)) {
|
|
61217
|
+
throw new Error(`Duplicate ${flagName} ${accountId}`);
|
|
61218
|
+
}
|
|
61219
|
+
}
|
|
61220
|
+
function validateSlackAccount(account) {
|
|
61221
|
+
if (!account.appToken || !account.botToken) {
|
|
61222
|
+
throw new Error(`Slack account ${account.accountId} requires both app token and bot token`);
|
|
61223
|
+
}
|
|
61224
|
+
if (account.appToken.kind !== account.botToken.kind) {
|
|
61225
|
+
throw new Error(`Slack account ${account.accountId} must use one credential source kind for both app and bot tokens`);
|
|
61226
|
+
}
|
|
61227
|
+
}
|
|
61228
|
+
function validateTelegramAccount(account) {
|
|
61229
|
+
if (!account.botToken) {
|
|
61230
|
+
throw new Error(`Telegram account ${account.accountId} requires a bot token`);
|
|
61231
|
+
}
|
|
61232
|
+
}
|
|
61233
|
+
function parseBootstrapFlags(args) {
|
|
61234
|
+
const slackAccounts = [];
|
|
61235
|
+
const telegramAccounts = [];
|
|
61236
|
+
let currentSlackAccountId;
|
|
61237
|
+
let currentTelegramAccountId;
|
|
61238
|
+
let cliTool;
|
|
61239
|
+
let bootstrap;
|
|
61240
|
+
let persist = false;
|
|
61241
|
+
let sawCredentialFlags = false;
|
|
61242
|
+
let sawSlackFlags = false;
|
|
61243
|
+
let sawTelegramFlags = false;
|
|
61244
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
61245
|
+
const arg = args[index];
|
|
61246
|
+
if (arg === "--cli") {
|
|
61247
|
+
cliTool = parseOptionValue(args, arg, index);
|
|
61248
|
+
index += 1;
|
|
61249
|
+
continue;
|
|
61250
|
+
}
|
|
61251
|
+
if (arg === "--bot-type") {
|
|
61252
|
+
bootstrap = parseBotType(parseOptionValue(args, arg, index));
|
|
61253
|
+
index += 1;
|
|
61254
|
+
continue;
|
|
61255
|
+
}
|
|
61256
|
+
if (arg === "--persist") {
|
|
61257
|
+
persist = true;
|
|
61258
|
+
continue;
|
|
61259
|
+
}
|
|
61260
|
+
if (arg === "--slack-account") {
|
|
61261
|
+
const accountId = parseOptionValue(args, arg, index);
|
|
61262
|
+
ensureUniqueAccount(slackAccounts, accountId, "--slack-account");
|
|
61263
|
+
currentSlackAccountId = accountId;
|
|
61264
|
+
getOrCreateSlackAccount(slackAccounts, accountId);
|
|
61265
|
+
sawSlackFlags = true;
|
|
61266
|
+
index += 1;
|
|
61267
|
+
continue;
|
|
61268
|
+
}
|
|
61269
|
+
if (arg === "--telegram-account") {
|
|
61270
|
+
const accountId = parseOptionValue(args, arg, index);
|
|
61271
|
+
ensureUniqueAccount(telegramAccounts, accountId, "--telegram-account");
|
|
61272
|
+
currentTelegramAccountId = accountId;
|
|
61273
|
+
getOrCreateTelegramAccount(telegramAccounts, accountId);
|
|
61274
|
+
sawTelegramFlags = true;
|
|
61275
|
+
index += 1;
|
|
61276
|
+
continue;
|
|
61277
|
+
}
|
|
61278
|
+
if (arg === "--slack-app-token") {
|
|
61279
|
+
const token = parseTokenInput(parseOptionValue(args, arg, index));
|
|
61280
|
+
const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
|
|
61281
|
+
account.appToken = token;
|
|
61282
|
+
sawCredentialFlags = true;
|
|
61283
|
+
sawSlackFlags = true;
|
|
61284
|
+
index += 1;
|
|
61285
|
+
continue;
|
|
61286
|
+
}
|
|
61287
|
+
if (arg === "--slack-bot-token") {
|
|
61288
|
+
const token = parseTokenInput(parseOptionValue(args, arg, index));
|
|
61289
|
+
const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
|
|
61290
|
+
account.botToken = token;
|
|
61291
|
+
sawCredentialFlags = true;
|
|
61292
|
+
sawSlackFlags = true;
|
|
61293
|
+
index += 1;
|
|
61294
|
+
continue;
|
|
61295
|
+
}
|
|
61296
|
+
if (arg === "--telegram-bot-token") {
|
|
61297
|
+
const token = parseTokenInput(parseOptionValue(args, arg, index));
|
|
61298
|
+
const account = getOrCreateTelegramAccount(telegramAccounts, currentTelegramAccountId ?? "default");
|
|
61299
|
+
account.botToken = token;
|
|
61300
|
+
sawCredentialFlags = true;
|
|
61301
|
+
sawTelegramFlags = true;
|
|
61302
|
+
index += 1;
|
|
61303
|
+
continue;
|
|
61304
|
+
}
|
|
61305
|
+
throw new Error(`Unknown option for start/init: ${arg}`);
|
|
61306
|
+
}
|
|
61307
|
+
for (const account of slackAccounts) {
|
|
61308
|
+
validateSlackAccount(account);
|
|
61309
|
+
}
|
|
61310
|
+
for (const account of telegramAccounts) {
|
|
61311
|
+
validateTelegramAccount(account);
|
|
61312
|
+
}
|
|
61313
|
+
return {
|
|
61314
|
+
cliTool,
|
|
61315
|
+
bootstrap,
|
|
61316
|
+
persist,
|
|
61317
|
+
slackAccounts,
|
|
61318
|
+
telegramAccounts,
|
|
61319
|
+
sawCredentialFlags,
|
|
61320
|
+
sawSlackFlags,
|
|
61321
|
+
sawTelegramFlags,
|
|
61322
|
+
literalWarnings: []
|
|
61323
|
+
};
|
|
61324
|
+
}
|
|
61325
|
+
function hasLiteralBootstrapCredentials(flags) {
|
|
61326
|
+
return flags.slackAccounts.some((account) => isLiteralToken(account.appToken) || isLiteralToken(account.botToken)) || flags.telegramAccounts.some((account) => isLiteralToken(account.botToken));
|
|
61327
|
+
}
|
|
61328
|
+
|
|
61151
61329
|
// src/control/agents-cli.ts
|
|
61152
61330
|
function getEditableConfigPath() {
|
|
61153
61331
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
@@ -61194,8 +61372,8 @@ function renderAgentsHelp() {
|
|
|
61194
61372
|
" clisbot agents --help",
|
|
61195
61373
|
" clisbot agents help",
|
|
61196
61374
|
" clisbot agents list [--bindings] [--json]",
|
|
61197
|
-
" clisbot agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--
|
|
61198
|
-
" clisbot agents bootstrap <id> --
|
|
61375
|
+
" clisbot agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bot-type <personal|team>] [--bind <channel[:accountId]>]...",
|
|
61376
|
+
" clisbot agents bootstrap <id> --bot-type <personal|team> [--force]",
|
|
61199
61377
|
" clisbot agents bindings [--agent <id>] [--json]",
|
|
61200
61378
|
" clisbot agents bind --agent <id> --bind <channel[:accountId]>",
|
|
61201
61379
|
" clisbot agents unbind --agent <id> [--bind <channel[:accountId]> | --all]",
|
|
@@ -61372,7 +61550,13 @@ async function addAgentToEditableConfig(params) {
|
|
|
61372
61550
|
async function addAgent(args) {
|
|
61373
61551
|
const agentId = args[0]?.trim();
|
|
61374
61552
|
if (!agentId) {
|
|
61375
|
-
throw new Error("Usage: agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--
|
|
61553
|
+
throw new Error("Usage: agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bot-type <personal|team>] [--bind <channel[:accountId]>]...");
|
|
61554
|
+
}
|
|
61555
|
+
if (hasFlag(args, "--bootstrap")) {
|
|
61556
|
+
throw new Error("agents add no longer accepts --bootstrap; use --bot-type personal or --bot-type team");
|
|
61557
|
+
}
|
|
61558
|
+
if (hasFlag(args, "--mode")) {
|
|
61559
|
+
throw new Error("agents add does not use --mode; use --bot-type personal or --bot-type team");
|
|
61376
61560
|
}
|
|
61377
61561
|
const cliTool = parseSingleOption(args, "--cli");
|
|
61378
61562
|
if (!cliTool || !(cliTool in DEFAULT_AGENT_TOOL_TEMPLATES)) {
|
|
@@ -61380,9 +61564,10 @@ async function addAgent(args) {
|
|
|
61380
61564
|
}
|
|
61381
61565
|
const workspace = parseSingleOption(args, "--workspace");
|
|
61382
61566
|
const startupOptions = parseRepeatedOption(args, "--startup-option");
|
|
61383
|
-
|
|
61384
|
-
|
|
61385
|
-
|
|
61567
|
+
let bootstrap;
|
|
61568
|
+
const botType = parseSingleOption(args, "--bot-type");
|
|
61569
|
+
if (botType) {
|
|
61570
|
+
bootstrap = parseBotType(botType);
|
|
61386
61571
|
}
|
|
61387
61572
|
const bindings = parseRepeatedOption(args, "--bind").map(parseBinding);
|
|
61388
61573
|
const result = await addAgentToEditableConfig({
|
|
@@ -61404,12 +61589,19 @@ async function addAgent(args) {
|
|
|
61404
61589
|
async function bootstrapAgent(args) {
|
|
61405
61590
|
const agentId = args[0]?.trim();
|
|
61406
61591
|
if (!agentId) {
|
|
61407
|
-
throw new Error("Usage: agents bootstrap <id> --
|
|
61592
|
+
throw new Error("Usage: agents bootstrap <id> --bot-type <personal|team> [--force]");
|
|
61593
|
+
}
|
|
61594
|
+
if (hasFlag(args, "--mode")) {
|
|
61595
|
+
throw new Error("agents bootstrap no longer accepts --mode; use --bot-type personal or --bot-type team");
|
|
61408
61596
|
}
|
|
61409
|
-
|
|
61410
|
-
|
|
61411
|
-
throw new Error("agents bootstrap requires --mode personal-assistant or --mode team-assistant");
|
|
61597
|
+
if (hasFlag(args, "--bootstrap")) {
|
|
61598
|
+
throw new Error("agents bootstrap does not use --bootstrap; use --bot-type personal or --bot-type team");
|
|
61412
61599
|
}
|
|
61600
|
+
const botType = parseSingleOption(args, "--bot-type");
|
|
61601
|
+
if (!botType) {
|
|
61602
|
+
throw new Error("agents bootstrap requires --bot-type personal or --bot-type team");
|
|
61603
|
+
}
|
|
61604
|
+
const mode = parseBotType(botType);
|
|
61413
61605
|
const force = hasFlag(args, "--force");
|
|
61414
61606
|
const { config, configPath } = await readEditableConfig(getEditableConfigPath());
|
|
61415
61607
|
const entry = ensureAgentExists(config, agentId);
|
|
@@ -64072,6 +64264,8 @@ function resolveAgentTargetInternal(loadedConfig, target) {
|
|
|
64072
64264
|
}
|
|
64073
64265
|
|
|
64074
64266
|
// src/agents/job-queue.ts
|
|
64267
|
+
var QUEUE_PENDING_POLL_INTERVAL_MS = 25;
|
|
64268
|
+
|
|
64075
64269
|
class ClearedQueuedTaskError extends Error {
|
|
64076
64270
|
constructor() {
|
|
64077
64271
|
super("Queued task was cleared before execution.");
|
|
@@ -64099,6 +64293,7 @@ class AgentJobQueue {
|
|
|
64099
64293
|
text: options.text,
|
|
64100
64294
|
createdAt: Date.now(),
|
|
64101
64295
|
status: "pending",
|
|
64296
|
+
canStart: options.canStart,
|
|
64102
64297
|
task,
|
|
64103
64298
|
resolve,
|
|
64104
64299
|
reject,
|
|
@@ -64166,6 +64361,10 @@ class AgentJobQueue {
|
|
|
64166
64361
|
if (!nextEntry) {
|
|
64167
64362
|
break;
|
|
64168
64363
|
}
|
|
64364
|
+
if (nextEntry.canStart && !await nextEntry.canStart()) {
|
|
64365
|
+
await sleep(QUEUE_PENDING_POLL_INTERVAL_MS);
|
|
64366
|
+
continue;
|
|
64367
|
+
}
|
|
64169
64368
|
nextEntry.status = "running";
|
|
64170
64369
|
try {
|
|
64171
64370
|
nextEntry.resolve(await nextEntry.task());
|
|
@@ -64426,12 +64625,22 @@ function isInterruptStatusLine(line) {
|
|
|
64426
64625
|
}
|
|
64427
64626
|
return CODEX_WORKING_STATUS_PATTERN.test(trimmed) || CODEX_INTERRUPT_FOOTER_PATTERN.test(trimmed);
|
|
64428
64627
|
}
|
|
64628
|
+
function isActiveTimerStatusLine(line) {
|
|
64629
|
+
const trimmed = line.trim();
|
|
64630
|
+
if (!trimmed) {
|
|
64631
|
+
return false;
|
|
64632
|
+
}
|
|
64633
|
+
return isInterruptStatusLine(trimmed) || GEMINI_THINKING_STATUS_PATTERN.test(trimmed) || CLAUDE_TIMER_FOOTER_PATTERN.test(trimmed);
|
|
64634
|
+
}
|
|
64429
64635
|
function isTimerDrivenStatusLine(line) {
|
|
64430
64636
|
const trimmed = line.trim();
|
|
64431
64637
|
if (!trimmed) {
|
|
64432
64638
|
return false;
|
|
64433
64639
|
}
|
|
64434
|
-
return
|
|
64640
|
+
return isActiveTimerStatusLine(trimmed) || CLAUDE_WORKED_STATUS_PATTERN.test(trimmed);
|
|
64641
|
+
}
|
|
64642
|
+
function hasActiveTimerStatus(snapshot) {
|
|
64643
|
+
return splitNormalizedLines(snapshot).some((line) => isActiveTimerStatusLine(line));
|
|
64435
64644
|
}
|
|
64436
64645
|
function shouldDropCodexChromeLine(line) {
|
|
64437
64646
|
const trimmed = line.trim();
|
|
@@ -64959,6 +65168,8 @@ var PASTE_CAPTURE_REVALIDATE_POLL_INTERVAL_MS = 40;
|
|
|
64959
65168
|
var PASTE_CAPTURE_REVALIDATE_MAX_WAIT_MS = 160;
|
|
64960
65169
|
var SUBMIT_CONFIRM_POLL_INTERVAL_MS = 40;
|
|
64961
65170
|
var SUBMIT_CONFIRM_MAX_WAIT_MS = 160;
|
|
65171
|
+
var SUBMIT_SNAPSHOT_CONFIRM_POLL_INTERVAL_MS = 40;
|
|
65172
|
+
var SUBMIT_SNAPSHOT_CONFIRM_MAX_WAIT_MS = 320;
|
|
64962
65173
|
var TMUX_MISSING_TARGET_PATTERN = /(?:no current target|can't find pane|can't find window)/i;
|
|
64963
65174
|
var TMUX_MISSING_SESSION_PATTERN = /(?:can't find session:|no server running on )/i;
|
|
64964
65175
|
var TMUX_SERVER_UNAVAILABLE_PATTERN = /(?:No such file or directory|error connecting to|failed to connect to server)/i;
|
|
@@ -64998,15 +65209,18 @@ async function submitTmuxSessionInput(params) {
|
|
|
64998
65209
|
logLatencyDebug("tmux-paste-unconfirmed", params.timingContext, {
|
|
64999
65210
|
sessionName: params.sessionName
|
|
65000
65211
|
});
|
|
65001
|
-
|
|
65212
|
+
preSubmitState = prePasteState;
|
|
65213
|
+
} else {
|
|
65214
|
+
preSubmitState = await params.tmux.getPaneState(params.sessionName);
|
|
65002
65215
|
}
|
|
65003
|
-
preSubmitState = await params.tmux.getPaneState(params.sessionName);
|
|
65004
65216
|
}
|
|
65005
65217
|
await params.tmux.sendKey(params.sessionName, "Enter");
|
|
65006
65218
|
if (await waitForPaneSubmitConfirmation({
|
|
65007
65219
|
tmux: params.tmux,
|
|
65008
65220
|
sessionName: params.sessionName,
|
|
65009
|
-
baseline: preSubmitState
|
|
65221
|
+
baseline: preSubmitState,
|
|
65222
|
+
baselineSnapshot: prePasteSnapshot,
|
|
65223
|
+
captureLines
|
|
65010
65224
|
})) {
|
|
65011
65225
|
return;
|
|
65012
65226
|
}
|
|
@@ -65017,10 +65231,15 @@ async function submitTmuxSessionInput(params) {
|
|
|
65017
65231
|
if (await waitForPaneSubmitConfirmation({
|
|
65018
65232
|
tmux: params.tmux,
|
|
65019
65233
|
sessionName: params.sessionName,
|
|
65020
|
-
baseline: preSubmitState
|
|
65234
|
+
baseline: preSubmitState,
|
|
65235
|
+
baselineSnapshot: prePasteSnapshot,
|
|
65236
|
+
captureLines
|
|
65021
65237
|
})) {
|
|
65022
65238
|
return;
|
|
65023
65239
|
}
|
|
65240
|
+
if (!pasteSettlement.visible) {
|
|
65241
|
+
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.");
|
|
65242
|
+
}
|
|
65024
65243
|
logLatencyDebug("tmux-submit-unconfirmed", params.timingContext, {
|
|
65025
65244
|
sessionName: params.sessionName
|
|
65026
65245
|
});
|
|
@@ -65190,6 +65409,16 @@ async function waitForPaneSubmitConfirmation(params) {
|
|
|
65190
65409
|
if (hasPaneStateChanged(params.baseline, state)) {
|
|
65191
65410
|
return true;
|
|
65192
65411
|
}
|
|
65412
|
+
const snapshotChanged = await waitForPaneSubmitSnapshotConfirmation({
|
|
65413
|
+
tmux: params.tmux,
|
|
65414
|
+
sessionName: params.sessionName,
|
|
65415
|
+
baselineSnapshot: params.baselineSnapshot,
|
|
65416
|
+
captureLines: params.captureLines,
|
|
65417
|
+
maxWaitMs: Math.min(SUBMIT_SNAPSHOT_CONFIRM_MAX_WAIT_MS, Math.max(0, deadline - Date.now()))
|
|
65418
|
+
});
|
|
65419
|
+
if (snapshotChanged) {
|
|
65420
|
+
return true;
|
|
65421
|
+
}
|
|
65193
65422
|
const remainingMs = deadline - Date.now();
|
|
65194
65423
|
if (remainingMs <= 0) {
|
|
65195
65424
|
return false;
|
|
@@ -65197,6 +65426,20 @@ async function waitForPaneSubmitConfirmation(params) {
|
|
|
65197
65426
|
await sleep(Math.min(SUBMIT_CONFIRM_POLL_INTERVAL_MS, remainingMs));
|
|
65198
65427
|
}
|
|
65199
65428
|
}
|
|
65429
|
+
async function waitForPaneSubmitSnapshotConfirmation(params) {
|
|
65430
|
+
const deadline = Date.now() + params.maxWaitMs;
|
|
65431
|
+
while (true) {
|
|
65432
|
+
const snapshot = normalizePaneText(await params.tmux.capturePane(params.sessionName, params.captureLines));
|
|
65433
|
+
if (snapshot !== params.baselineSnapshot) {
|
|
65434
|
+
return true;
|
|
65435
|
+
}
|
|
65436
|
+
const remainingMs = deadline - Date.now();
|
|
65437
|
+
if (remainingMs <= 0) {
|
|
65438
|
+
return false;
|
|
65439
|
+
}
|
|
65440
|
+
await sleep(Math.min(SUBMIT_SNAPSHOT_CONFIRM_POLL_INTERVAL_MS, remainingMs));
|
|
65441
|
+
}
|
|
65442
|
+
}
|
|
65200
65443
|
async function waitForPanePasteSettlement(params) {
|
|
65201
65444
|
await sleep(params.minDelayMs);
|
|
65202
65445
|
let currentState = await params.tmux.getPaneState(params.sessionName);
|
|
@@ -65513,32 +65756,38 @@ class RunnerService {
|
|
|
65513
65756
|
pollIntervalMs: capture.pollIntervalMs
|
|
65514
65757
|
});
|
|
65515
65758
|
}
|
|
65516
|
-
async retryFreshStartWithClearedSessionId(target, resolved,
|
|
65517
|
-
if (
|
|
65759
|
+
async retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries) {
|
|
65760
|
+
if (remainingFreshRetries <= 0) {
|
|
65518
65761
|
return null;
|
|
65519
65762
|
}
|
|
65520
65763
|
await this.tmux.killSession(resolved.sessionName);
|
|
65521
65764
|
await this.sessionState.clearSessionIdEntry(resolved, {
|
|
65522
65765
|
runnerCommand: resolved.runner.command
|
|
65523
65766
|
});
|
|
65767
|
+
if (resolved.runner.startupRetryDelayMs > 0) {
|
|
65768
|
+
await sleep(resolved.runner.startupRetryDelayMs);
|
|
65769
|
+
}
|
|
65524
65770
|
return this.ensureSessionReady(target, {
|
|
65525
|
-
|
|
65771
|
+
remainingFreshRetries: remainingFreshRetries - 1
|
|
65526
65772
|
});
|
|
65527
65773
|
}
|
|
65528
|
-
async retryAfterStartupFault(target, resolved, error,
|
|
65774
|
+
async retryAfterStartupFault(target, resolved, error, remainingFreshRetries) {
|
|
65529
65775
|
if (!isRecoverableStartupSessionLoss(error)) {
|
|
65530
65776
|
return null;
|
|
65531
65777
|
}
|
|
65532
|
-
return this.retryFreshStartWithClearedSessionId(target, resolved,
|
|
65533
|
-
allowRetry: allowFreshRetry,
|
|
65534
|
-
nextAllowFreshRetry: false
|
|
65535
|
-
});
|
|
65778
|
+
return this.retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries);
|
|
65536
65779
|
}
|
|
65537
|
-
async retryAfterStartupTimeout(target, resolved,
|
|
65538
|
-
return this.retryFreshStartWithClearedSessionId(target, resolved,
|
|
65539
|
-
|
|
65540
|
-
|
|
65541
|
-
|
|
65780
|
+
async retryAfterStartupTimeout(target, resolved, remainingFreshRetries) {
|
|
65781
|
+
return this.retryFreshStartWithClearedSessionId(target, resolved, remainingFreshRetries);
|
|
65782
|
+
}
|
|
65783
|
+
resolveRemainingFreshRetries(resolved, options) {
|
|
65784
|
+
if (typeof options.remainingFreshRetries === "number") {
|
|
65785
|
+
return options.remainingFreshRetries;
|
|
65786
|
+
}
|
|
65787
|
+
if (options.allowFreshRetry === false) {
|
|
65788
|
+
return 0;
|
|
65789
|
+
}
|
|
65790
|
+
return resolved.runner.startupRetryCount;
|
|
65542
65791
|
}
|
|
65543
65792
|
async abortUnreadySession(resolved, reason, snapshot) {
|
|
65544
65793
|
await this.tmux.killSession(resolved.sessionName);
|
|
@@ -65612,6 +65861,7 @@ class RunnerService {
|
|
|
65612
65861
|
sessionKey: resolved.sessionKey,
|
|
65613
65862
|
sessionName: resolved.sessionName
|
|
65614
65863
|
};
|
|
65864
|
+
const remainingFreshRetries = this.resolveRemainingFreshRetries(resolved, options);
|
|
65615
65865
|
logLatencyDebug("ensure-session-ready-start", timingContext);
|
|
65616
65866
|
await ensureDir2(resolved.workspacePath);
|
|
65617
65867
|
await ensureDir2(dirname11(this.loadedConfig.raw.tmux.socketPath));
|
|
@@ -65684,7 +65934,7 @@ class RunnerService {
|
|
|
65684
65934
|
await this.abortUnreadySession(resolved, bootstrapResult.message, bootstrapResult.snapshot);
|
|
65685
65935
|
}
|
|
65686
65936
|
if (bootstrapResult.status === "timeout" && resolved.runner.startupReadyPattern) {
|
|
65687
|
-
const retried = await this.retryAfterStartupTimeout(target, resolved,
|
|
65937
|
+
const retried = await this.retryAfterStartupTimeout(target, resolved, remainingFreshRetries);
|
|
65688
65938
|
if (retried) {
|
|
65689
65939
|
return retried;
|
|
65690
65940
|
}
|
|
@@ -65695,7 +65945,7 @@ class RunnerService {
|
|
|
65695
65945
|
runnerCommand: runnerLaunch.command
|
|
65696
65946
|
});
|
|
65697
65947
|
} catch (error) {
|
|
65698
|
-
const retried = await this.retryAfterStartupFault(target, resolved, error,
|
|
65948
|
+
const retried = await this.retryAfterStartupFault(target, resolved, error, remainingFreshRetries);
|
|
65699
65949
|
if (retried) {
|
|
65700
65950
|
return retried;
|
|
65701
65951
|
}
|
|
@@ -65750,10 +66000,7 @@ class RunnerService {
|
|
|
65750
66000
|
if (options.allowFreshRetryBeforePrompt === false || !isRecoverableStartupSessionLoss(error)) {
|
|
65751
66001
|
throw await this.mapSessionError(error, resolved.sessionName, "before prompt submission", resolved.sessionName ? await this.captureSessionSnapshot(resolved).catch(() => "") : "");
|
|
65752
66002
|
}
|
|
65753
|
-
const retried = await this.retryFreshStartWithClearedSessionId(target, resolved,
|
|
65754
|
-
allowRetry: true,
|
|
65755
|
-
nextAllowFreshRetry: false
|
|
65756
|
-
});
|
|
66003
|
+
const retried = await this.retryFreshStartWithClearedSessionId(target, resolved, resolved.runner.startupRetryCount);
|
|
65757
66004
|
if (!retried) {
|
|
65758
66005
|
throw await this.mapSessionError(error, resolved.sessionName, "before prompt submission", resolved.sessionName ? await this.captureSessionSnapshot(resolved).catch(() => "") : "");
|
|
65759
66006
|
}
|
|
@@ -65924,8 +66171,10 @@ var FIRST_OUTPUT_POLL_INTERVAL_MS = 250;
|
|
|
65924
66171
|
async function monitorTmuxRun(params) {
|
|
65925
66172
|
let previousSnapshot = params.initialSnapshot;
|
|
65926
66173
|
let previousRunningSnapshot = "";
|
|
65927
|
-
let
|
|
66174
|
+
let lastPaneChangeAt = params.startedAt;
|
|
65928
66175
|
let sawActivity = false;
|
|
66176
|
+
let sawPaneChange = false;
|
|
66177
|
+
let sawPromptSubmission = Boolean(params.prompt);
|
|
65929
66178
|
let detachedNotified = params.detachedAlready;
|
|
65930
66179
|
let firstMeaningfulDeltaLogged = false;
|
|
65931
66180
|
let noOutputThresholdLogged = false;
|
|
@@ -65941,6 +66190,8 @@ async function monitorTmuxRun(params) {
|
|
|
65941
66190
|
promptSubmitDelayMs: params.promptSubmitDelayMs,
|
|
65942
66191
|
timingContext: params.timingContext
|
|
65943
66192
|
});
|
|
66193
|
+
sawPromptSubmission = true;
|
|
66194
|
+
lastPaneChangeAt = Date.now();
|
|
65944
66195
|
await params.onPromptSubmitted?.();
|
|
65945
66196
|
logLatencyDebug("tmux-submit-complete", params.timingContext, {
|
|
65946
66197
|
sessionName: params.sessionName,
|
|
@@ -65952,11 +66203,16 @@ async function monitorTmuxRun(params) {
|
|
|
65952
66203
|
await sleep(sawActivity ? params.updateIntervalMs : Math.min(params.updateIntervalMs, FIRST_OUTPUT_POLL_INTERVAL_MS));
|
|
65953
66204
|
const snapshot = normalizePaneText(await params.tmux.capturePane(params.sessionName, params.captureLines));
|
|
65954
66205
|
const now = Date.now();
|
|
66206
|
+
const paneChanged = snapshot !== previousSnapshot;
|
|
66207
|
+
if (paneChanged) {
|
|
66208
|
+
lastPaneChangeAt = now;
|
|
66209
|
+
sawPaneChange = true;
|
|
66210
|
+
}
|
|
66211
|
+
const hasActiveTimer = hasActiveTimerStatus(snapshot);
|
|
65955
66212
|
const runningSnapshot = params.initialSnapshot ? deriveRunningInteractionText(params.initialSnapshot, snapshot) : deriveRunningInteractionSnapshot(snapshot);
|
|
65956
66213
|
previousSnapshot = snapshot;
|
|
65957
66214
|
if (runningSnapshot && runningSnapshot !== previousRunningSnapshot) {
|
|
65958
66215
|
previousRunningSnapshot = runningSnapshot;
|
|
65959
|
-
lastActivityAt = now;
|
|
65960
66216
|
sawActivity = true;
|
|
65961
66217
|
if (!firstMeaningfulDeltaLogged) {
|
|
65962
66218
|
firstMeaningfulDeltaLogged = true;
|
|
@@ -65979,7 +66235,7 @@ async function monitorTmuxRun(params) {
|
|
|
65979
66235
|
initialSnapshot: params.initialSnapshot
|
|
65980
66236
|
});
|
|
65981
66237
|
}
|
|
65982
|
-
if (sawActivity && now -
|
|
66238
|
+
if (!hasActiveTimer && (sawActivity || sawPaneChange || sawPromptSubmission) && now - lastPaneChangeAt >= params.idleTimeoutMs) {
|
|
65983
66239
|
await params.onCompleted({
|
|
65984
66240
|
snapshot: deriveInteractionText(params.initialSnapshot, previousSnapshot),
|
|
65985
66241
|
fullSnapshot: previousSnapshot,
|
|
@@ -66000,9 +66256,20 @@ async function monitorTmuxRun(params) {
|
|
|
66000
66256
|
// src/agents/session-service.ts
|
|
66001
66257
|
var OBSERVER_RETRYABLE_FAILURE_LIMIT = 3;
|
|
66002
66258
|
var DETACHED_OBSERVER_INTERVAL_MS = 5 * 60000;
|
|
66259
|
+
var TMUX_MISSING_SESSION_PATTERN3 = /(?:can't find session:|no server running on )/i;
|
|
66260
|
+
var TMUX_SERVER_UNAVAILABLE_PATTERN3 = /(?:No such file or directory|error connecting to|failed to connect to server)/i;
|
|
66003
66261
|
function formatObserverError(error) {
|
|
66004
66262
|
return error instanceof Error ? error.stack ?? error.message : String(error);
|
|
66005
66263
|
}
|
|
66264
|
+
function isMissingTmuxSessionError2(error) {
|
|
66265
|
+
return error instanceof Error && TMUX_MISSING_SESSION_PATTERN3.test(error.message);
|
|
66266
|
+
}
|
|
66267
|
+
function isTmuxServerUnavailableError2(error) {
|
|
66268
|
+
return error instanceof Error && TMUX_SERVER_UNAVAILABLE_PATTERN3.test(error.message);
|
|
66269
|
+
}
|
|
66270
|
+
function isBootstrapSessionLostError2(error) {
|
|
66271
|
+
return error instanceof Error && /tmux session disappeared before startup finished|tmux server became unavailable before startup finished/i.test(error.message);
|
|
66272
|
+
}
|
|
66006
66273
|
function listObserverErrorCodes(error) {
|
|
66007
66274
|
const codes = new Set;
|
|
66008
66275
|
const visit = (value) => {
|
|
@@ -66074,6 +66341,7 @@ class SessionService {
|
|
|
66074
66341
|
runnerSessions;
|
|
66075
66342
|
resolveTarget;
|
|
66076
66343
|
activeRuns = new Map;
|
|
66344
|
+
nextRunId = 1;
|
|
66077
66345
|
stopping = false;
|
|
66078
66346
|
constructor(tmux, sessionState, runnerSessions, resolveTarget) {
|
|
66079
66347
|
this.tmux = tmux;
|
|
@@ -66087,42 +66355,10 @@ class SessionService {
|
|
|
66087
66355
|
if (!entry.runtime || entry.runtime.state === "idle") {
|
|
66088
66356
|
continue;
|
|
66089
66357
|
}
|
|
66090
|
-
|
|
66358
|
+
await this.reconcilePersistedActiveRun({
|
|
66091
66359
|
agentId: entry.agentId,
|
|
66092
66360
|
sessionKey: entry.sessionKey
|
|
66093
66361
|
});
|
|
66094
|
-
if (!await this.tmux.hasSession(resolved.sessionName)) {
|
|
66095
|
-
await this.sessionState.setSessionRuntime(resolved, {
|
|
66096
|
-
state: "idle"
|
|
66097
|
-
});
|
|
66098
|
-
continue;
|
|
66099
|
-
}
|
|
66100
|
-
const fullSnapshot = normalizePaneText(await this.tmux.capturePane(resolved.sessionName, resolved.stream.captureLines));
|
|
66101
|
-
const initialResult = createDeferred();
|
|
66102
|
-
const update = this.createRunUpdate({
|
|
66103
|
-
resolved,
|
|
66104
|
-
status: entry.runtime.state === "detached" ? "detached" : "running",
|
|
66105
|
-
snapshot: deriveInteractionText("", fullSnapshot),
|
|
66106
|
-
fullSnapshot,
|
|
66107
|
-
initialSnapshot: "",
|
|
66108
|
-
note: entry.runtime.state === "detached" ? this.buildDetachedNote(resolved) : undefined
|
|
66109
|
-
});
|
|
66110
|
-
this.activeRuns.set(resolved.sessionKey, {
|
|
66111
|
-
resolved,
|
|
66112
|
-
observers: new Map,
|
|
66113
|
-
observerFailures: new Map,
|
|
66114
|
-
initialResult,
|
|
66115
|
-
latestUpdate: update,
|
|
66116
|
-
steeringReady: true,
|
|
66117
|
-
startedAt: entry.runtime.startedAt ?? Date.now()
|
|
66118
|
-
});
|
|
66119
|
-
this.startRunMonitor(resolved.sessionKey, {
|
|
66120
|
-
prompt: undefined,
|
|
66121
|
-
initialSnapshot: fullSnapshot,
|
|
66122
|
-
startedAt: entry.runtime.startedAt ?? Date.now(),
|
|
66123
|
-
detachedAlready: entry.runtime.state === "detached",
|
|
66124
|
-
timingContext: undefined
|
|
66125
|
-
});
|
|
66126
66362
|
}
|
|
66127
66363
|
}
|
|
66128
66364
|
async executePrompt(target, prompt, observer, options = {}) {
|
|
@@ -66133,21 +66369,15 @@ class SessionService {
|
|
|
66133
66369
|
if (existingActiveRun) {
|
|
66134
66370
|
throw new ActiveRunInProgressError(existingActiveRun.latestUpdate);
|
|
66135
66371
|
}
|
|
66136
|
-
const
|
|
66137
|
-
if (
|
|
66138
|
-
|
|
66139
|
-
throw new ActiveRunInProgressError(this.createRunUpdate({
|
|
66140
|
-
resolved: resolvedExisting,
|
|
66141
|
-
status: existingEntry.runtime.state === "detached" ? "detached" : "running",
|
|
66142
|
-
snapshot: "",
|
|
66143
|
-
fullSnapshot: "",
|
|
66144
|
-
initialSnapshot: "",
|
|
66145
|
-
note: existingEntry.runtime.state === "detached" ? this.buildDetachedNote(resolvedExisting) : "This session already has an active run. Use `/attach`, `/watch every 30s`, or `/stop` before sending a new prompt."
|
|
66146
|
-
}));
|
|
66372
|
+
const reconciledRun = await this.reconcilePersistedActiveRun(target);
|
|
66373
|
+
if (reconciledRun) {
|
|
66374
|
+
throw new ActiveRunInProgressError(reconciledRun.latestUpdate);
|
|
66147
66375
|
}
|
|
66148
66376
|
const initialResult = createDeferred();
|
|
66149
66377
|
const provisionalResolved = this.resolveTarget(target);
|
|
66378
|
+
const runId = this.allocateRunId();
|
|
66150
66379
|
this.activeRuns.set(provisionalResolved.sessionKey, {
|
|
66380
|
+
runId,
|
|
66151
66381
|
resolved: provisionalResolved,
|
|
66152
66382
|
observers: new Map([[observer.id, { ...observer }]]),
|
|
66153
66383
|
observerFailures: new Map,
|
|
@@ -66195,6 +66425,7 @@ class SessionService {
|
|
|
66195
66425
|
startedAt
|
|
66196
66426
|
});
|
|
66197
66427
|
this.startRunMonitor(resolved.sessionKey, {
|
|
66428
|
+
runId,
|
|
66198
66429
|
prompt,
|
|
66199
66430
|
initialSnapshot,
|
|
66200
66431
|
startedAt,
|
|
@@ -66203,12 +66434,12 @@ class SessionService {
|
|
|
66203
66434
|
});
|
|
66204
66435
|
return initialResult.promise;
|
|
66205
66436
|
} catch (error) {
|
|
66206
|
-
await this.failActiveRun(provisionalResolved.sessionKey, error);
|
|
66437
|
+
await this.failActiveRun(provisionalResolved.sessionKey, runId, error);
|
|
66207
66438
|
throw error;
|
|
66208
66439
|
}
|
|
66209
66440
|
}
|
|
66210
66441
|
async observeRun(target, observer) {
|
|
66211
|
-
const existingRun = this.activeRuns.get(target.sessionKey);
|
|
66442
|
+
const existingRun = this.activeRuns.get(target.sessionKey) ?? await this.reconcilePersistedActiveRun(target);
|
|
66212
66443
|
if (existingRun) {
|
|
66213
66444
|
existingRun.observers.set(observer.id, {
|
|
66214
66445
|
...observer
|
|
@@ -66262,6 +66493,29 @@ class SessionService {
|
|
|
66262
66493
|
canSteerActiveRun(target) {
|
|
66263
66494
|
return this.activeRuns.get(target.sessionKey)?.steeringReady ?? false;
|
|
66264
66495
|
}
|
|
66496
|
+
async submitSessionInput(target, text) {
|
|
66497
|
+
const result = await this.runnerSessions.submitSessionInput(target, text);
|
|
66498
|
+
const run = this.activeRuns.get(target.sessionKey);
|
|
66499
|
+
if (!run) {
|
|
66500
|
+
return result;
|
|
66501
|
+
}
|
|
66502
|
+
const startedAt = Date.now();
|
|
66503
|
+
run.startedAt = startedAt;
|
|
66504
|
+
if (run.latestUpdate.status === "detached") {
|
|
66505
|
+
run.latestUpdate = this.createRunUpdate({
|
|
66506
|
+
resolved: run.resolved,
|
|
66507
|
+
status: "running",
|
|
66508
|
+
snapshot: run.latestUpdate.snapshot,
|
|
66509
|
+
fullSnapshot: run.latestUpdate.fullSnapshot,
|
|
66510
|
+
initialSnapshot: run.latestUpdate.initialSnapshot
|
|
66511
|
+
});
|
|
66512
|
+
}
|
|
66513
|
+
await this.sessionState.setSessionRuntime(run.resolved, {
|
|
66514
|
+
state: "running",
|
|
66515
|
+
startedAt
|
|
66516
|
+
});
|
|
66517
|
+
return result;
|
|
66518
|
+
}
|
|
66265
66519
|
async stop() {
|
|
66266
66520
|
this.stopping = true;
|
|
66267
66521
|
const activeRuns = [...this.activeRuns.values()];
|
|
@@ -66348,8 +66602,8 @@ class SessionService {
|
|
|
66348
66602
|
}
|
|
66349
66603
|
}
|
|
66350
66604
|
}
|
|
66351
|
-
async finishActiveRun(sessionKey, update) {
|
|
66352
|
-
const run = this.
|
|
66605
|
+
async finishActiveRun(sessionKey, runId, update) {
|
|
66606
|
+
const run = this.getRun(sessionKey, runId);
|
|
66353
66607
|
if (!run) {
|
|
66354
66608
|
return;
|
|
66355
66609
|
}
|
|
@@ -66360,8 +66614,8 @@ class SessionService {
|
|
|
66360
66614
|
run.initialResult.resolve(update);
|
|
66361
66615
|
this.activeRuns.delete(run.resolved.sessionKey);
|
|
66362
66616
|
}
|
|
66363
|
-
async failActiveRun(sessionKey, error) {
|
|
66364
|
-
const run = this.
|
|
66617
|
+
async failActiveRun(sessionKey, runId, error) {
|
|
66618
|
+
const run = this.getRun(sessionKey, runId);
|
|
66365
66619
|
if (!run) {
|
|
66366
66620
|
return;
|
|
66367
66621
|
}
|
|
@@ -66387,7 +66641,7 @@ class SessionService {
|
|
|
66387
66641
|
if (!this.runnerSessions.canRecoverMidRun(error)) {
|
|
66388
66642
|
return false;
|
|
66389
66643
|
}
|
|
66390
|
-
const run = this.
|
|
66644
|
+
const run = this.getRun(sessionKey, params.runId);
|
|
66391
66645
|
if (!run) {
|
|
66392
66646
|
return true;
|
|
66393
66647
|
}
|
|
@@ -66404,7 +66658,7 @@ class SessionService {
|
|
|
66404
66658
|
}));
|
|
66405
66659
|
try {
|
|
66406
66660
|
const recovered = await this.runnerSessions.reopenRunContext(target, params.timingContext);
|
|
66407
|
-
const currentRun = this.
|
|
66661
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66408
66662
|
if (!currentRun) {
|
|
66409
66663
|
return true;
|
|
66410
66664
|
}
|
|
@@ -66420,6 +66674,7 @@ class SessionService {
|
|
|
66420
66674
|
});
|
|
66421
66675
|
await this.notifyRunObservers(currentRun, currentRun.latestUpdate);
|
|
66422
66676
|
this.startRunMonitor(sessionKey, {
|
|
66677
|
+
runId: currentRun.runId,
|
|
66423
66678
|
prompt: MID_RUN_RECOVERY_CONTINUE_PROMPT,
|
|
66424
66679
|
initialSnapshot: recovered.initialSnapshot,
|
|
66425
66680
|
startedAt: currentRun.startedAt,
|
|
@@ -66432,11 +66687,12 @@ class SessionService {
|
|
|
66432
66687
|
} catch (reopenError) {
|
|
66433
66688
|
if (recoveryAttempt < MID_RUN_RECOVERY_MAX_ATTEMPTS && this.runnerSessions.canRecoverMidRun(reopenError)) {
|
|
66434
66689
|
return await this.recoverLostMidRun(sessionKey, {
|
|
66690
|
+
runId: params.runId,
|
|
66435
66691
|
timingContext: params.timingContext,
|
|
66436
66692
|
recoveryAttempt: recoveryAttempt + 1
|
|
66437
66693
|
}, reopenError);
|
|
66438
66694
|
}
|
|
66439
|
-
const currentRun = this.
|
|
66695
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66440
66696
|
if (!currentRun) {
|
|
66441
66697
|
return true;
|
|
66442
66698
|
}
|
|
@@ -66444,15 +66700,15 @@ class SessionService {
|
|
|
66444
66700
|
try {
|
|
66445
66701
|
await this.runnerSessions.startFreshSession(target, params.timingContext);
|
|
66446
66702
|
} catch (freshError) {
|
|
66447
|
-
await this.failActiveRun(sessionKey, await this.runnerSessions.mapRunError(freshError, currentRun.resolved.sessionName, currentRun.latestUpdate.fullSnapshot));
|
|
66703
|
+
await this.failActiveRun(sessionKey, currentRun.runId, await this.runnerSessions.mapRunError(freshError, currentRun.resolved.sessionName, currentRun.latestUpdate.fullSnapshot));
|
|
66448
66704
|
return true;
|
|
66449
66705
|
}
|
|
66450
|
-
await this.failActiveRun(sessionKey, new Error(buildRunRecoveryNote("fresh-required")));
|
|
66706
|
+
await this.failActiveRun(sessionKey, currentRun.runId, new Error(buildRunRecoveryNote("fresh-required")));
|
|
66451
66707
|
return true;
|
|
66452
66708
|
}
|
|
66453
66709
|
}
|
|
66454
66710
|
startRunMonitor(sessionKey, params) {
|
|
66455
|
-
const run = this.
|
|
66711
|
+
const run = this.getRun(sessionKey, params.runId);
|
|
66456
66712
|
if (!run) {
|
|
66457
66713
|
return;
|
|
66458
66714
|
}
|
|
@@ -66476,14 +66732,14 @@ class SessionService {
|
|
|
66476
66732
|
detachedAlready: params.detachedAlready,
|
|
66477
66733
|
timingContext: params.timingContext,
|
|
66478
66734
|
onPromptSubmitted: async () => {
|
|
66479
|
-
const currentRun = this.
|
|
66735
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66480
66736
|
if (!currentRun) {
|
|
66481
66737
|
return;
|
|
66482
66738
|
}
|
|
66483
66739
|
currentRun.steeringReady = true;
|
|
66484
66740
|
},
|
|
66485
66741
|
onRunning: async (update) => {
|
|
66486
|
-
const currentRun = this.
|
|
66742
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66487
66743
|
if (!currentRun) {
|
|
66488
66744
|
return;
|
|
66489
66745
|
}
|
|
@@ -66499,7 +66755,7 @@ class SessionService {
|
|
|
66499
66755
|
}));
|
|
66500
66756
|
},
|
|
66501
66757
|
onDetached: async (update) => {
|
|
66502
|
-
const currentRun = this.
|
|
66758
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66503
66759
|
if (!currentRun) {
|
|
66504
66760
|
return;
|
|
66505
66761
|
}
|
|
@@ -66521,27 +66777,111 @@ class SessionService {
|
|
|
66521
66777
|
currentRun.initialResult.resolve(detachedUpdate);
|
|
66522
66778
|
},
|
|
66523
66779
|
onCompleted: async (update) => {
|
|
66780
|
+
const currentRun = this.getRun(sessionKey, params.runId);
|
|
66781
|
+
if (!currentRun) {
|
|
66782
|
+
return;
|
|
66783
|
+
}
|
|
66524
66784
|
const runUpdate = this.createRunUpdate({
|
|
66525
|
-
resolved:
|
|
66785
|
+
resolved: currentRun.resolved,
|
|
66526
66786
|
status: "completed",
|
|
66527
66787
|
snapshot: mergeRunSnapshot(params.snapshotPrefix ?? "", update.snapshot),
|
|
66528
66788
|
fullSnapshot: update.fullSnapshot,
|
|
66529
66789
|
initialSnapshot: update.initialSnapshot
|
|
66530
66790
|
});
|
|
66531
|
-
await this.finishActiveRun(sessionKey, runUpdate);
|
|
66791
|
+
await this.finishActiveRun(sessionKey, params.runId, runUpdate);
|
|
66532
66792
|
}
|
|
66533
66793
|
});
|
|
66534
66794
|
} catch (error) {
|
|
66535
66795
|
if (await this.recoverLostMidRun(sessionKey, {
|
|
66796
|
+
runId: params.runId,
|
|
66536
66797
|
timingContext: params.timingContext,
|
|
66537
66798
|
recoveryAttempt: (params.recoveryAttempt ?? 0) + 1
|
|
66538
66799
|
}, error)) {
|
|
66539
66800
|
return;
|
|
66540
66801
|
}
|
|
66541
|
-
await this.failActiveRun(sessionKey, await this.runnerSessions.mapRunError(error, run.resolved.sessionName, run.latestUpdate.fullSnapshot));
|
|
66802
|
+
await this.failActiveRun(sessionKey, params.runId, await this.runnerSessions.mapRunError(error, run.resolved.sessionName, run.latestUpdate.fullSnapshot));
|
|
66542
66803
|
}
|
|
66543
66804
|
})();
|
|
66544
66805
|
}
|
|
66806
|
+
allocateRunId() {
|
|
66807
|
+
return String(this.nextRunId++);
|
|
66808
|
+
}
|
|
66809
|
+
async reconcilePersistedActiveRun(target) {
|
|
66810
|
+
const activeRun = this.activeRuns.get(target.sessionKey);
|
|
66811
|
+
if (activeRun) {
|
|
66812
|
+
return activeRun;
|
|
66813
|
+
}
|
|
66814
|
+
const entry = await this.sessionState.getEntry(target.sessionKey);
|
|
66815
|
+
if (!entry?.runtime || entry.runtime.state === "idle") {
|
|
66816
|
+
return null;
|
|
66817
|
+
}
|
|
66818
|
+
const resolved = this.resolveTarget(target);
|
|
66819
|
+
if (!await this.tmux.hasSession(resolved.sessionName)) {
|
|
66820
|
+
await this.sessionState.setSessionRuntime(resolved, {
|
|
66821
|
+
state: "idle"
|
|
66822
|
+
});
|
|
66823
|
+
return null;
|
|
66824
|
+
}
|
|
66825
|
+
try {
|
|
66826
|
+
return await this.rehydratePersistedActiveRun(resolved, {
|
|
66827
|
+
runtimeState: entry.runtime.state,
|
|
66828
|
+
startedAt: entry.runtime.startedAt
|
|
66829
|
+
});
|
|
66830
|
+
} catch (error) {
|
|
66831
|
+
if (isMissingTmuxSessionError2(error) || isTmuxServerUnavailableError2(error) || isBootstrapSessionLostError2(error)) {
|
|
66832
|
+
await this.sessionState.setSessionRuntime(resolved, {
|
|
66833
|
+
state: "idle"
|
|
66834
|
+
});
|
|
66835
|
+
return null;
|
|
66836
|
+
}
|
|
66837
|
+
throw error;
|
|
66838
|
+
}
|
|
66839
|
+
}
|
|
66840
|
+
async rehydratePersistedActiveRun(resolved, params) {
|
|
66841
|
+
const existingRun = this.activeRuns.get(resolved.sessionKey);
|
|
66842
|
+
if (existingRun) {
|
|
66843
|
+
return existingRun;
|
|
66844
|
+
}
|
|
66845
|
+
const fullSnapshot = normalizePaneText(await this.tmux.capturePane(resolved.sessionName, resolved.stream.captureLines));
|
|
66846
|
+
const startedAt = params.startedAt ?? Date.now();
|
|
66847
|
+
const runId = this.allocateRunId();
|
|
66848
|
+
const initialResult = createDeferred();
|
|
66849
|
+
const update = this.createRunUpdate({
|
|
66850
|
+
resolved,
|
|
66851
|
+
status: params.runtimeState === "detached" ? "detached" : "running",
|
|
66852
|
+
snapshot: deriveInteractionText("", fullSnapshot),
|
|
66853
|
+
fullSnapshot,
|
|
66854
|
+
initialSnapshot: "",
|
|
66855
|
+
note: params.runtimeState === "detached" ? this.buildDetachedNote(resolved) : undefined
|
|
66856
|
+
});
|
|
66857
|
+
const run = {
|
|
66858
|
+
runId,
|
|
66859
|
+
resolved,
|
|
66860
|
+
observers: new Map,
|
|
66861
|
+
observerFailures: new Map,
|
|
66862
|
+
initialResult,
|
|
66863
|
+
latestUpdate: update,
|
|
66864
|
+
steeringReady: true,
|
|
66865
|
+
startedAt
|
|
66866
|
+
};
|
|
66867
|
+
this.activeRuns.set(resolved.sessionKey, run);
|
|
66868
|
+
this.startRunMonitor(resolved.sessionKey, {
|
|
66869
|
+
runId,
|
|
66870
|
+
prompt: undefined,
|
|
66871
|
+
initialSnapshot: fullSnapshot,
|
|
66872
|
+
startedAt,
|
|
66873
|
+
detachedAlready: params.runtimeState === "detached",
|
|
66874
|
+
timingContext: undefined
|
|
66875
|
+
});
|
|
66876
|
+
return run;
|
|
66877
|
+
}
|
|
66878
|
+
getRun(sessionKey, runId) {
|
|
66879
|
+
const run = this.activeRuns.get(sessionKey);
|
|
66880
|
+
if (!run || run.runId !== runId) {
|
|
66881
|
+
return null;
|
|
66882
|
+
}
|
|
66883
|
+
return run;
|
|
66884
|
+
}
|
|
66545
66885
|
}
|
|
66546
66886
|
|
|
66547
66887
|
// src/agents/agent-service.ts
|
|
@@ -66706,7 +67046,7 @@ class AgentService {
|
|
|
66706
67046
|
return this.activeRuns.canSteerActiveRun(target);
|
|
66707
67047
|
}
|
|
66708
67048
|
async submitSessionInput(target, text) {
|
|
66709
|
-
return this.
|
|
67049
|
+
return this.activeRuns.submitSessionInput(target, text);
|
|
66710
67050
|
}
|
|
66711
67051
|
isSessionBusy(target) {
|
|
66712
67052
|
return this.activeRuns.hasActiveRun(target) || this.queue.isBusy(target.sessionKey);
|
|
@@ -66889,7 +67229,8 @@ class AgentService {
|
|
|
66889
67229
|
timingContext: callbacks.timingContext,
|
|
66890
67230
|
onUpdate: callbacks.onUpdate
|
|
66891
67231
|
}), {
|
|
66892
|
-
text: prompt
|
|
67232
|
+
text: prompt,
|
|
67233
|
+
canStart: async () => !this.activeRuns.hasActiveRun(target)
|
|
66893
67234
|
});
|
|
66894
67235
|
}
|
|
66895
67236
|
getMaxMessageChars(agentId) {
|
|
@@ -69221,6 +69562,7 @@ async function clearSlackAssistantThreadStatus(client, target) {
|
|
|
69221
69562
|
}
|
|
69222
69563
|
|
|
69223
69564
|
// src/channels/processing-indicator.ts
|
|
69565
|
+
var ACTIVE_RUN_WAIT_POLL_INTERVAL_MS = 250;
|
|
69224
69566
|
function shouldResolveIndicatorWait(update) {
|
|
69225
69567
|
return isTerminalRunStatus(update.status);
|
|
69226
69568
|
}
|
|
@@ -69247,6 +69589,18 @@ async function waitForProcessingIndicatorLifecycle(params) {
|
|
|
69247
69589
|
settled = true;
|
|
69248
69590
|
resolve();
|
|
69249
69591
|
};
|
|
69592
|
+
(async () => {
|
|
69593
|
+
while (!settled) {
|
|
69594
|
+
await sleep(ACTIVE_RUN_WAIT_POLL_INTERVAL_MS);
|
|
69595
|
+
if (settled) {
|
|
69596
|
+
return;
|
|
69597
|
+
}
|
|
69598
|
+
if (!params.agentService.hasActiveRun(params.sessionTarget)) {
|
|
69599
|
+
resolveOnce();
|
|
69600
|
+
return;
|
|
69601
|
+
}
|
|
69602
|
+
}
|
|
69603
|
+
})();
|
|
69250
69604
|
try {
|
|
69251
69605
|
const observation = await params.agentService.observeRun(params.sessionTarget, {
|
|
69252
69606
|
id: params.observerId,
|
|
@@ -74523,7 +74877,7 @@ function extractLinuxProcState(raw) {
|
|
|
74523
74877
|
function getEditableConfigPath5() {
|
|
74524
74878
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
74525
74879
|
}
|
|
74526
|
-
function
|
|
74880
|
+
function parseOptionValue2(args, name) {
|
|
74527
74881
|
const index = args.findIndex((arg) => arg === name);
|
|
74528
74882
|
if (index === -1) {
|
|
74529
74883
|
return;
|
|
@@ -74534,6 +74888,21 @@ function parseOptionValue(args, name) {
|
|
|
74534
74888
|
}
|
|
74535
74889
|
return value;
|
|
74536
74890
|
}
|
|
74891
|
+
function parseAliasedOptionValue(args, names, label) {
|
|
74892
|
+
const values = names.flatMap((name) => {
|
|
74893
|
+
const value = parseOptionValue2(args, name);
|
|
74894
|
+
return value === undefined ? [] : [{ name, value }];
|
|
74895
|
+
});
|
|
74896
|
+
if (values.length === 0) {
|
|
74897
|
+
return;
|
|
74898
|
+
}
|
|
74899
|
+
const distinctValues = Array.from(new Set(values.map((entry) => entry.value)));
|
|
74900
|
+
if (distinctValues.length > 1) {
|
|
74901
|
+
const seen = values.map((entry) => `${entry.name}=${entry.value}`).join(", ");
|
|
74902
|
+
throw new Error(`Conflicting values for ${label}: ${seen}`);
|
|
74903
|
+
}
|
|
74904
|
+
return values[values.length - 1]?.value;
|
|
74905
|
+
}
|
|
74537
74906
|
function hasFlag2(args, name) {
|
|
74538
74907
|
return args.includes(name);
|
|
74539
74908
|
}
|
|
@@ -74564,13 +74933,14 @@ function renderAccountsHelp() {
|
|
|
74564
74933
|
"Usage:",
|
|
74565
74934
|
" clisbot accounts --help",
|
|
74566
74935
|
" 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]",
|
|
74936
|
+
" clisbot accounts add telegram --account <id> (--token | --telegram-bot-token) <ENV_NAME|${ENV_NAME}|literal> [--persist]",
|
|
74937
|
+
" 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
74938
|
" clisbot accounts persist --channel <slack|telegram> --account <id>",
|
|
74570
74939
|
" clisbot accounts persist --all",
|
|
74571
74940
|
"",
|
|
74572
74941
|
"Notes:",
|
|
74573
74942
|
" - env-style input such as `TELEGRAM_BOT_TOKEN` or `${TELEGRAM_BOT_TOKEN}` keeps the account env-backed in config",
|
|
74943
|
+
" - `accounts add` accepts both the short account-local flags and the bootstrap-style channel flags",
|
|
74574
74944
|
" - literal token input without `--persist` stays runtime-only and requires a running clisbot runtime",
|
|
74575
74945
|
" - `--persist` writes canonical token files so later plain `clisbot start` can reuse the account safely",
|
|
74576
74946
|
" - `persist --all` converts every configured `credentialType=mem` account into canonical token files"
|
|
@@ -74578,8 +74948,8 @@ function renderAccountsHelp() {
|
|
|
74578
74948
|
`);
|
|
74579
74949
|
}
|
|
74580
74950
|
async function addTelegramAccount(args, deps) {
|
|
74581
|
-
const accountId =
|
|
74582
|
-
const token = parseTokenInput(
|
|
74951
|
+
const accountId = parseOptionValue2(args, "--account") ?? "default";
|
|
74952
|
+
const token = parseTokenInput(parseAliasedOptionValue(args, ["--token", "--telegram-bot-token"], "telegram bot token") ?? "");
|
|
74583
74953
|
const persist = hasFlag2(args, "--persist");
|
|
74584
74954
|
const runtimeStatus = await deps.getRuntimeStatus();
|
|
74585
74955
|
if (token.kind === "mem" && !persist && !runtimeStatus.running) {
|
|
@@ -74615,9 +74985,9 @@ async function addTelegramAccount(args, deps) {
|
|
|
74615
74985
|
console.log(`config: ${configPath}`);
|
|
74616
74986
|
}
|
|
74617
74987
|
async function addSlackAccount(args, deps) {
|
|
74618
|
-
const accountId =
|
|
74619
|
-
const appToken = parseTokenInput(
|
|
74620
|
-
const botToken = parseTokenInput(
|
|
74988
|
+
const accountId = parseOptionValue2(args, "--account") ?? "default";
|
|
74989
|
+
const appToken = parseTokenInput(parseAliasedOptionValue(args, ["--app-token", "--slack-app-token"], "slack app token") ?? "");
|
|
74990
|
+
const botToken = parseTokenInput(parseAliasedOptionValue(args, ["--bot-token", "--slack-bot-token"], "slack bot token") ?? "");
|
|
74621
74991
|
const persist = hasFlag2(args, "--persist");
|
|
74622
74992
|
const runtimeStatus = await deps.getRuntimeStatus();
|
|
74623
74993
|
if (appToken.kind !== botToken.kind) {
|
|
@@ -74772,8 +75142,8 @@ async function runAccountsCli(args, deps = {}) {
|
|
|
74772
75142
|
await persistAllConfiguredAccounts(resolvedDeps);
|
|
74773
75143
|
return;
|
|
74774
75144
|
}
|
|
74775
|
-
const provider =
|
|
74776
|
-
const accountId =
|
|
75145
|
+
const provider = parseOptionValue2(args, "--channel");
|
|
75146
|
+
const accountId = parseOptionValue2(args, "--account") ?? "default";
|
|
74777
75147
|
if (provider !== "slack" && provider !== "telegram") {
|
|
74778
75148
|
throw new Error(renderAccountsHelp());
|
|
74779
75149
|
}
|
|
@@ -75273,7 +75643,7 @@ function parseResponseModeTarget(channel, raw) {
|
|
|
75273
75643
|
}
|
|
75274
75644
|
return target;
|
|
75275
75645
|
}
|
|
75276
|
-
function
|
|
75646
|
+
function parseOptionValue3(args, name) {
|
|
75277
75647
|
const index = args.findIndex((arg) => arg === name);
|
|
75278
75648
|
if (index === -1) {
|
|
75279
75649
|
return;
|
|
@@ -75285,7 +75655,7 @@ function parseOptionValue2(args, name) {
|
|
|
75285
75655
|
return value;
|
|
75286
75656
|
}
|
|
75287
75657
|
function parseBooleanOption(args, name, fallback) {
|
|
75288
|
-
const raw =
|
|
75658
|
+
const raw = parseOptionValue3(args, name);
|
|
75289
75659
|
if (!raw) {
|
|
75290
75660
|
return fallback;
|
|
75291
75661
|
}
|
|
@@ -75298,7 +75668,7 @@ function parseBooleanOption(args, name, fallback) {
|
|
|
75298
75668
|
throw new Error(`${name} requires true or false`);
|
|
75299
75669
|
}
|
|
75300
75670
|
function getAgentId(args) {
|
|
75301
|
-
return
|
|
75671
|
+
return parseOptionValue3(args, "--agent") ?? "default";
|
|
75302
75672
|
}
|
|
75303
75673
|
async function setChannelEnabled(action, channel) {
|
|
75304
75674
|
const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
|
|
@@ -75322,7 +75692,7 @@ async function addTelegramGroup(args) {
|
|
|
75322
75692
|
throw new Error("Usage: clisbot channels add telegram-group <chatId> [--topic <topicId>] [--agent <id>] [--require-mention true|false]");
|
|
75323
75693
|
}
|
|
75324
75694
|
const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
|
|
75325
|
-
const topicId =
|
|
75695
|
+
const topicId = parseOptionValue3(args, "--topic");
|
|
75326
75696
|
const agentId = getAgentId(args);
|
|
75327
75697
|
const requireMention = parseBooleanOption(args, "--require-mention", true);
|
|
75328
75698
|
const groupRoute = config.channels.telegram.groups[chatId] ?? {
|
|
@@ -75375,7 +75745,7 @@ async function removeTelegramGroup(args) {
|
|
|
75375
75745
|
throw new Error("Usage: clisbot channels remove telegram-group <chatId> [--topic <topicId>]");
|
|
75376
75746
|
}
|
|
75377
75747
|
const { config, configPath } = await readEditableConfig(getEditableConfigPath7());
|
|
75378
|
-
const topicId =
|
|
75748
|
+
const topicId = parseOptionValue3(args, "--topic");
|
|
75379
75749
|
const groupRoute = config.channels.telegram.groups[chatId];
|
|
75380
75750
|
if (!groupRoute) {
|
|
75381
75751
|
console.log(`telegram group route ${chatId} is not configured`);
|
|
@@ -75517,9 +75887,9 @@ async function runResponseModeCli(args) {
|
|
|
75517
75887
|
}
|
|
75518
75888
|
const responseMode = action === "set" ? parseResponseMode2(args[1]) : undefined;
|
|
75519
75889
|
const optionArgs = action === "set" ? args.slice(2) : args.slice(1);
|
|
75520
|
-
const channel = parseResponseModeChannel(
|
|
75521
|
-
const target = parseResponseModeTarget(channel,
|
|
75522
|
-
const topic =
|
|
75890
|
+
const channel = parseResponseModeChannel(parseOptionValue3(optionArgs, "--channel"));
|
|
75891
|
+
const target = parseResponseModeTarget(channel, parseOptionValue3(optionArgs, "--target"));
|
|
75892
|
+
const topic = parseOptionValue3(optionArgs, "--topic");
|
|
75523
75893
|
if (channel === "slack" && topic) {
|
|
75524
75894
|
throw new Error("Slack response-mode commands do not support --topic");
|
|
75525
75895
|
}
|
|
@@ -75551,9 +75921,9 @@ async function runAdditionalMessageModeCli(args) {
|
|
|
75551
75921
|
}
|
|
75552
75922
|
const additionalMessageMode = action === "set" ? parseAdditionalMessageMode2(args[1]) : undefined;
|
|
75553
75923
|
const optionArgs = action === "set" ? args.slice(2) : args.slice(1);
|
|
75554
|
-
const channel = parseResponseModeChannel(
|
|
75555
|
-
const target = parseResponseModeTarget(channel,
|
|
75556
|
-
const topic =
|
|
75924
|
+
const channel = parseResponseModeChannel(parseOptionValue3(optionArgs, "--channel"));
|
|
75925
|
+
const target = parseResponseModeTarget(channel, parseOptionValue3(optionArgs, "--target"));
|
|
75926
|
+
const topic = parseOptionValue3(optionArgs, "--topic");
|
|
75557
75927
|
if (channel === "slack" && topic) {
|
|
75558
75928
|
throw new Error("Slack additional-message-mode commands do not support --topic");
|
|
75559
75929
|
}
|
|
@@ -75843,7 +76213,7 @@ function parseRepeatedOption3(args, name) {
|
|
|
75843
76213
|
}
|
|
75844
76214
|
return values;
|
|
75845
76215
|
}
|
|
75846
|
-
function
|
|
76216
|
+
function parseOptionValue4(args, name) {
|
|
75847
76217
|
const values = parseRepeatedOption3(args, name);
|
|
75848
76218
|
return values.length > 0 ? values.at(-1) : undefined;
|
|
75849
76219
|
}
|
|
@@ -75856,7 +76226,7 @@ function parseMessageBodyFileOption(args) {
|
|
|
75856
76226
|
return bodyFileValues.at(-1) ?? messageFileValues.at(-1);
|
|
75857
76227
|
}
|
|
75858
76228
|
function parseIntegerOption(args, name) {
|
|
75859
|
-
const raw =
|
|
76229
|
+
const raw = parseOptionValue4(args, name);
|
|
75860
76230
|
if (!raw) {
|
|
75861
76231
|
return;
|
|
75862
76232
|
}
|
|
@@ -75885,34 +76255,34 @@ function parseMessageCommand(args) {
|
|
|
75885
76255
|
}
|
|
75886
76256
|
const action = rawAction;
|
|
75887
76257
|
const rest = args.slice(1);
|
|
75888
|
-
const channel =
|
|
76258
|
+
const channel = parseOptionValue4(rest, "--channel");
|
|
75889
76259
|
if (channel !== "slack" && channel !== "telegram") {
|
|
75890
76260
|
throw new Error("--channel <slack|telegram> is required");
|
|
75891
76261
|
}
|
|
75892
76262
|
return {
|
|
75893
76263
|
action,
|
|
75894
76264
|
channel,
|
|
75895
|
-
account:
|
|
75896
|
-
target:
|
|
75897
|
-
message:
|
|
76265
|
+
account: parseOptionValue4(rest, "--account"),
|
|
76266
|
+
target: parseOptionValue4(rest, "--target"),
|
|
76267
|
+
message: parseOptionValue4(rest, "--message") ?? parseOptionValue4(rest, "-m"),
|
|
75898
76268
|
messageFile: parseMessageBodyFileOption(rest),
|
|
75899
|
-
media:
|
|
75900
|
-
messageId:
|
|
75901
|
-
emoji:
|
|
76269
|
+
media: parseOptionValue4(rest, "--media"),
|
|
76270
|
+
messageId: parseOptionValue4(rest, "--message-id"),
|
|
76271
|
+
emoji: parseOptionValue4(rest, "--emoji"),
|
|
75902
76272
|
remove: hasFlag4(rest, "--remove"),
|
|
75903
|
-
threadId:
|
|
75904
|
-
replyTo:
|
|
76273
|
+
threadId: parseOptionValue4(rest, "--thread-id"),
|
|
76274
|
+
replyTo: parseOptionValue4(rest, "--reply-to"),
|
|
75905
76275
|
limit: parseIntegerOption(rest, "--limit"),
|
|
75906
|
-
query:
|
|
75907
|
-
pollQuestion:
|
|
76276
|
+
query: parseOptionValue4(rest, "--query"),
|
|
76277
|
+
pollQuestion: parseOptionValue4(rest, "--poll-question"),
|
|
75908
76278
|
pollOptions: parseRepeatedOption3(rest, "--poll-option"),
|
|
75909
76279
|
forceDocument: hasFlag4(rest, "--force-document"),
|
|
75910
76280
|
silent: hasFlag4(rest, "--silent"),
|
|
75911
76281
|
progress: hasFlag4(rest, "--progress"),
|
|
75912
76282
|
final: hasFlag4(rest, "--final"),
|
|
75913
76283
|
json: hasFlag4(rest, "--json"),
|
|
75914
|
-
inputFormat: parseMessageInputFormat(
|
|
75915
|
-
renderMode: parseMessageRenderMode(
|
|
76284
|
+
inputFormat: parseMessageInputFormat(parseOptionValue4(rest, "--input")),
|
|
76285
|
+
renderMode: parseMessageRenderMode(parseOptionValue4(rest, "--render"))
|
|
75916
76286
|
};
|
|
75917
76287
|
}
|
|
75918
76288
|
function renderMessageHelp() {
|
|
@@ -76017,160 +76387,214 @@ async function runMessageCli(args, dependencies = defaultMessageCliDependencies)
|
|
|
76017
76387
|
dependencies.print(JSON.stringify(execution.result, null, 2));
|
|
76018
76388
|
}
|
|
76019
76389
|
|
|
76020
|
-
// src/control/
|
|
76021
|
-
|
|
76022
|
-
|
|
76390
|
+
// src/control/runtime-cli-shared.ts
|
|
76391
|
+
class CliCommandError extends Error {
|
|
76392
|
+
exitCode;
|
|
76393
|
+
constructor(message, exitCode = 1) {
|
|
76394
|
+
super(message);
|
|
76395
|
+
this.exitCode = exitCode;
|
|
76396
|
+
}
|
|
76023
76397
|
}
|
|
76024
|
-
function
|
|
76025
|
-
|
|
76026
|
-
|
|
76027
|
-
|
|
76398
|
+
function printCommandOutcomeBanner(outcome) {
|
|
76399
|
+
console.log("");
|
|
76400
|
+
console.log("+---------+");
|
|
76401
|
+
console.log(outcome === "success" ? "| SUCCESS |" : "| FAILED |");
|
|
76402
|
+
console.log("+---------+");
|
|
76403
|
+
console.log("");
|
|
76404
|
+
}
|
|
76405
|
+
function printCommandOutcomeFooter(outcome) {
|
|
76406
|
+
printCommandOutcomeBanner(outcome);
|
|
76407
|
+
}
|
|
76408
|
+
function assertSupportedPlatform(command) {
|
|
76409
|
+
if (process.platform !== "win32") {
|
|
76410
|
+
return;
|
|
76028
76411
|
}
|
|
76029
|
-
if (
|
|
76030
|
-
return
|
|
76412
|
+
if (command.name === "help" || command.name === "version") {
|
|
76413
|
+
return;
|
|
76031
76414
|
}
|
|
76032
|
-
throw new Error(
|
|
76415
|
+
throw new Error("Native Windows is not supported yet. Run clisbot from WSL2 or use Linux/macOS instead.");
|
|
76033
76416
|
}
|
|
76034
|
-
function
|
|
76035
|
-
|
|
76036
|
-
if (!value) {
|
|
76037
|
-
throw new Error(`Missing value for ${name}`);
|
|
76038
|
-
}
|
|
76039
|
-
return value;
|
|
76417
|
+
function getCliErrorExitCode(error) {
|
|
76418
|
+
return error instanceof CliCommandError ? error.exitCode : 1;
|
|
76040
76419
|
}
|
|
76041
|
-
|
|
76042
|
-
|
|
76043
|
-
|
|
76044
|
-
|
|
76045
|
-
|
|
76420
|
+
|
|
76421
|
+
// src/control/runner-cli.ts
|
|
76422
|
+
var SMOKE_BACKENDS = ["codex", "claude", "gemini", "all"];
|
|
76423
|
+
var SMOKE_SCENARIOS = [
|
|
76424
|
+
"startup_ready",
|
|
76425
|
+
"first_prompt_roundtrip",
|
|
76426
|
+
"session_id_roundtrip",
|
|
76427
|
+
"interrupt_during_run",
|
|
76428
|
+
"recover_after_runner_loss"
|
|
76429
|
+
];
|
|
76430
|
+
var SMOKE_SUITES = ["launch-trio"];
|
|
76431
|
+
function parseRepeatedOption4(args, name) {
|
|
76432
|
+
const values = [];
|
|
76433
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
76434
|
+
if (args[index] !== name) {
|
|
76435
|
+
continue;
|
|
76436
|
+
}
|
|
76437
|
+
const value = args[index + 1]?.trim();
|
|
76438
|
+
if (!value) {
|
|
76439
|
+
throw new CliCommandError(`Missing value for ${name}`, 2);
|
|
76440
|
+
}
|
|
76441
|
+
values.push(value);
|
|
76046
76442
|
}
|
|
76047
|
-
return
|
|
76443
|
+
return values;
|
|
76048
76444
|
}
|
|
76049
|
-
function
|
|
76050
|
-
|
|
76051
|
-
if (
|
|
76052
|
-
|
|
76053
|
-
accounts.push(account);
|
|
76445
|
+
function parseSingleOption3(args, name) {
|
|
76446
|
+
const values = parseRepeatedOption4(args, name);
|
|
76447
|
+
if (values.length === 0) {
|
|
76448
|
+
return;
|
|
76054
76449
|
}
|
|
76055
|
-
return
|
|
76450
|
+
return values[values.length - 1];
|
|
76056
76451
|
}
|
|
76057
|
-
function
|
|
76058
|
-
|
|
76059
|
-
throw new Error(`Duplicate ${flagName} ${accountId}`);
|
|
76060
|
-
}
|
|
76452
|
+
function hasFlag5(args, name) {
|
|
76453
|
+
return args.includes(name);
|
|
76061
76454
|
}
|
|
76062
|
-
function
|
|
76063
|
-
|
|
76064
|
-
|
|
76455
|
+
function isOneOf(value, allowed) {
|
|
76456
|
+
return allowed.includes(value);
|
|
76457
|
+
}
|
|
76458
|
+
function parseTimeoutMs(raw) {
|
|
76459
|
+
if (!raw) {
|
|
76460
|
+
return;
|
|
76065
76461
|
}
|
|
76066
|
-
|
|
76067
|
-
|
|
76462
|
+
const parsed = Number.parseInt(raw, 10);
|
|
76463
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
76464
|
+
throw new CliCommandError("Invalid value for --timeout-ms", 2);
|
|
76068
76465
|
}
|
|
76466
|
+
return parsed;
|
|
76069
76467
|
}
|
|
76070
|
-
function
|
|
76071
|
-
|
|
76072
|
-
|
|
76073
|
-
|
|
76468
|
+
function renderRunnerHelp() {
|
|
76469
|
+
return [
|
|
76470
|
+
"clisbot runner",
|
|
76471
|
+
"",
|
|
76472
|
+
"Usage:",
|
|
76473
|
+
" clisbot runner",
|
|
76474
|
+
" clisbot runner --help",
|
|
76475
|
+
" clisbot runner smoke --backend <codex|claude|gemini> --scenario <name> [--workspace <path>] [--agent <id>] [--artifact-dir <path>] [--timeout-ms <n>] [--keep-session] [--json]",
|
|
76476
|
+
" clisbot runner smoke --backend all --suite launch-trio [--workspace <path>] [--agent <id>] [--artifact-dir <path>] [--timeout-ms <n>] [--keep-session] [--json]",
|
|
76477
|
+
"",
|
|
76478
|
+
"Smoke scenarios:",
|
|
76479
|
+
" - startup_ready",
|
|
76480
|
+
" - first_prompt_roundtrip",
|
|
76481
|
+
" - session_id_roundtrip",
|
|
76482
|
+
" - interrupt_during_run",
|
|
76483
|
+
" - recover_after_runner_loss",
|
|
76484
|
+
"",
|
|
76485
|
+
"Smoke suites:",
|
|
76486
|
+
" - launch-trio",
|
|
76487
|
+
"",
|
|
76488
|
+
"Current status:",
|
|
76489
|
+
" - the `runner` CLI surface now validates the smoke command contract",
|
|
76490
|
+
" - real smoke execution is the next implementation batch"
|
|
76491
|
+
].join(`
|
|
76492
|
+
`);
|
|
76074
76493
|
}
|
|
76075
|
-
function
|
|
76076
|
-
const
|
|
76077
|
-
|
|
76078
|
-
|
|
76079
|
-
|
|
76080
|
-
|
|
76081
|
-
|
|
76082
|
-
|
|
76083
|
-
|
|
76084
|
-
|
|
76085
|
-
|
|
76086
|
-
|
|
76087
|
-
|
|
76088
|
-
|
|
76089
|
-
|
|
76090
|
-
|
|
76091
|
-
|
|
76092
|
-
|
|
76093
|
-
|
|
76094
|
-
|
|
76095
|
-
|
|
76096
|
-
|
|
76097
|
-
|
|
76098
|
-
if (
|
|
76099
|
-
|
|
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;
|
|
76494
|
+
function parseSmokeCommand(args) {
|
|
76495
|
+
const backend = parseSingleOption3(args, "--backend");
|
|
76496
|
+
if (!backend) {
|
|
76497
|
+
throw new CliCommandError(`Usage: clisbot runner smoke --backend <codex|claude|gemini> --scenario <name> [--json]
|
|
76498
|
+
clisbot runner smoke --backend all --suite launch-trio [--json]`, 2);
|
|
76499
|
+
}
|
|
76500
|
+
if (!isOneOf(backend, SMOKE_BACKENDS)) {
|
|
76501
|
+
throw new CliCommandError(`Unsupported --backend value: ${backend}`, 2);
|
|
76502
|
+
}
|
|
76503
|
+
const rawScenario = parseSingleOption3(args, "--scenario");
|
|
76504
|
+
const rawSuite = parseSingleOption3(args, "--suite");
|
|
76505
|
+
if (rawScenario && rawSuite) {
|
|
76506
|
+
throw new CliCommandError("--scenario and --suite are mutually exclusive", 2);
|
|
76507
|
+
}
|
|
76508
|
+
if (rawScenario && !isOneOf(rawScenario, SMOKE_SCENARIOS)) {
|
|
76509
|
+
throw new CliCommandError(`Unsupported --scenario value: ${rawScenario}`, 2);
|
|
76510
|
+
}
|
|
76511
|
+
if (rawSuite && !isOneOf(rawSuite, SMOKE_SUITES)) {
|
|
76512
|
+
throw new CliCommandError(`Unsupported --suite value: ${rawSuite}`, 2);
|
|
76513
|
+
}
|
|
76514
|
+
const scenario = rawScenario;
|
|
76515
|
+
const suite = rawSuite;
|
|
76516
|
+
if (backend === "all") {
|
|
76517
|
+
if (scenario) {
|
|
76518
|
+
throw new CliCommandError("--backend all is only valid with --suite", 2);
|
|
76115
76519
|
}
|
|
76116
|
-
if (
|
|
76117
|
-
|
|
76118
|
-
ensureUniqueAccount(telegramAccounts, accountId, "--telegram-account");
|
|
76119
|
-
currentTelegramAccountId = accountId;
|
|
76120
|
-
getOrCreateTelegramAccount(telegramAccounts, accountId);
|
|
76121
|
-
sawTelegramFlags = true;
|
|
76122
|
-
index += 1;
|
|
76123
|
-
continue;
|
|
76520
|
+
if (!suite) {
|
|
76521
|
+
throw new CliCommandError("--backend all requires --suite launch-trio", 2);
|
|
76124
76522
|
}
|
|
76125
|
-
|
|
76126
|
-
|
|
76127
|
-
|
|
76128
|
-
account.appToken = token;
|
|
76129
|
-
sawCredentialFlags = true;
|
|
76130
|
-
sawSlackFlags = true;
|
|
76131
|
-
index += 1;
|
|
76132
|
-
continue;
|
|
76523
|
+
} else {
|
|
76524
|
+
if (suite) {
|
|
76525
|
+
throw new CliCommandError(`--suite is only valid with --backend all`, 2);
|
|
76133
76526
|
}
|
|
76134
|
-
if (
|
|
76135
|
-
|
|
76136
|
-
const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
|
|
76137
|
-
account.botToken = token;
|
|
76138
|
-
sawCredentialFlags = true;
|
|
76139
|
-
sawSlackFlags = true;
|
|
76140
|
-
index += 1;
|
|
76141
|
-
continue;
|
|
76527
|
+
if (!scenario) {
|
|
76528
|
+
throw new CliCommandError(`--backend ${backend} requires --scenario`, 2);
|
|
76142
76529
|
}
|
|
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
76530
|
}
|
|
76154
|
-
|
|
76155
|
-
|
|
76531
|
+
return {
|
|
76532
|
+
backend,
|
|
76533
|
+
scenario,
|
|
76534
|
+
suite,
|
|
76535
|
+
workspace: parseSingleOption3(args, "--workspace"),
|
|
76536
|
+
agent: parseSingleOption3(args, "--agent"),
|
|
76537
|
+
artifactDir: parseSingleOption3(args, "--artifact-dir"),
|
|
76538
|
+
timeoutMs: parseTimeoutMs(parseSingleOption3(args, "--timeout-ms")),
|
|
76539
|
+
keepSession: hasFlag5(args, "--keep-session"),
|
|
76540
|
+
json: hasFlag5(args, "--json")
|
|
76541
|
+
};
|
|
76542
|
+
}
|
|
76543
|
+
function renderSmokeNotImplementedResult(options) {
|
|
76544
|
+
return {
|
|
76545
|
+
kind: "runner-smoke-framework-error",
|
|
76546
|
+
version: "v0",
|
|
76547
|
+
ok: false,
|
|
76548
|
+
backendId: options.backend,
|
|
76549
|
+
scenario: options.scenario ?? null,
|
|
76550
|
+
suite: options.suite ?? null,
|
|
76551
|
+
error: {
|
|
76552
|
+
code: "NOT_IMPLEMENTED",
|
|
76553
|
+
message: "clisbot runner smoke is not implemented yet. The command surface and contract validation are ready; the real execution batch is next."
|
|
76554
|
+
},
|
|
76555
|
+
options: {
|
|
76556
|
+
workspace: options.workspace ?? null,
|
|
76557
|
+
agent: options.agent ?? null,
|
|
76558
|
+
artifactDir: options.artifactDir ?? null,
|
|
76559
|
+
timeoutMs: options.timeoutMs ?? null,
|
|
76560
|
+
keepSession: options.keepSession,
|
|
76561
|
+
json: options.json
|
|
76562
|
+
}
|
|
76563
|
+
};
|
|
76564
|
+
}
|
|
76565
|
+
async function runSmokeCli(args) {
|
|
76566
|
+
if (args.length === 0 || hasFlag5(args, "--help") || hasFlag5(args, "-h")) {
|
|
76567
|
+
console.log(renderRunnerHelp());
|
|
76568
|
+
return;
|
|
76156
76569
|
}
|
|
76157
|
-
|
|
76158
|
-
|
|
76570
|
+
const options = parseSmokeCommand(args);
|
|
76571
|
+
const result = renderSmokeNotImplementedResult(options);
|
|
76572
|
+
if (options.json) {
|
|
76573
|
+
console.log(JSON.stringify(result, null, 2));
|
|
76574
|
+
} else {
|
|
76575
|
+
console.log([
|
|
76576
|
+
"clisbot runner smoke",
|
|
76577
|
+
"",
|
|
76578
|
+
`backend: ${options.backend}`,
|
|
76579
|
+
options.scenario ? `scenario: ${options.scenario}` : `suite: ${options.suite}`,
|
|
76580
|
+
"status: not implemented yet",
|
|
76581
|
+
"note: the smoke contract is validated, but real CLI execution is the next batch"
|
|
76582
|
+
].join(`
|
|
76583
|
+
`));
|
|
76159
76584
|
}
|
|
76160
|
-
|
|
76161
|
-
cliTool,
|
|
76162
|
-
bootstrap,
|
|
76163
|
-
persist,
|
|
76164
|
-
slackAccounts,
|
|
76165
|
-
telegramAccounts,
|
|
76166
|
-
sawCredentialFlags,
|
|
76167
|
-
sawSlackFlags,
|
|
76168
|
-
sawTelegramFlags,
|
|
76169
|
-
literalWarnings: []
|
|
76170
|
-
};
|
|
76585
|
+
process.exitCode = 3;
|
|
76171
76586
|
}
|
|
76172
|
-
function
|
|
76173
|
-
|
|
76587
|
+
async function runRunnerCli(args) {
|
|
76588
|
+
const subcommand = args[0];
|
|
76589
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
76590
|
+
console.log(renderRunnerHelp());
|
|
76591
|
+
return;
|
|
76592
|
+
}
|
|
76593
|
+
if (subcommand === "smoke") {
|
|
76594
|
+
await runSmokeCli(args.slice(1));
|
|
76595
|
+
return;
|
|
76596
|
+
}
|
|
76597
|
+
throw new CliCommandError(renderRunnerHelp(), 2);
|
|
76174
76598
|
}
|
|
76175
76599
|
|
|
76176
76600
|
// src/control/activity-store.ts
|
|
@@ -76413,10 +76837,11 @@ function appendBootstrapGuidance(lines, summary) {
|
|
|
76413
76837
|
lines.push("");
|
|
76414
76838
|
lines.push("Guidance:");
|
|
76415
76839
|
for (const agent of pendingBootstrap) {
|
|
76840
|
+
const botType = agent.bootstrapMode === "team-assistant" ? "team" : "personal";
|
|
76416
76841
|
if (agent.bootstrapState === "missing") {
|
|
76417
76842
|
lines.push(` Agent ${agent.id} is missing bootstrap files.`);
|
|
76418
76843
|
lines.push(` workspace: ${agent.workspacePath}`);
|
|
76419
|
-
lines.push(` run: clisbot agents bootstrap ${agent.id} --
|
|
76844
|
+
lines.push(` run: clisbot agents bootstrap ${agent.id} --bot-type ${botType}`);
|
|
76420
76845
|
continue;
|
|
76421
76846
|
}
|
|
76422
76847
|
lines.push(` Agent ${agent.id} still needs bootstrap completion.`);
|
|
@@ -76707,27 +77132,6 @@ function renderOperatorErrorWithHelpLines(error) {
|
|
|
76707
77132
|
];
|
|
76708
77133
|
}
|
|
76709
77134
|
|
|
76710
|
-
// src/control/runtime-cli-shared.ts
|
|
76711
|
-
function printCommandOutcomeBanner(outcome) {
|
|
76712
|
-
console.log("");
|
|
76713
|
-
console.log("+---------+");
|
|
76714
|
-
console.log(outcome === "success" ? "| SUCCESS |" : "| FAILED |");
|
|
76715
|
-
console.log("+---------+");
|
|
76716
|
-
console.log("");
|
|
76717
|
-
}
|
|
76718
|
-
function printCommandOutcomeFooter(outcome) {
|
|
76719
|
-
printCommandOutcomeBanner(outcome);
|
|
76720
|
-
}
|
|
76721
|
-
function assertSupportedPlatform(command) {
|
|
76722
|
-
if (process.platform !== "win32") {
|
|
76723
|
-
return;
|
|
76724
|
-
}
|
|
76725
|
-
if (command.name === "help" || command.name === "version") {
|
|
76726
|
-
return;
|
|
76727
|
-
}
|
|
76728
|
-
throw new Error("Native Windows is not supported yet. Run clisbot from WSL2 or use Linux/macOS instead.");
|
|
76729
|
-
}
|
|
76730
|
-
|
|
76731
77135
|
// src/control/runtime-bootstrap-cli.ts
|
|
76732
77136
|
function hasHelpFlag(args) {
|
|
76733
77137
|
return args.includes("--help") || args.includes("-h") || args.includes("help");
|
|
@@ -77817,6 +78221,10 @@ async function runControlCommand(command) {
|
|
|
77817
78221
|
await runAuthCli(command.args);
|
|
77818
78222
|
return true;
|
|
77819
78223
|
}
|
|
78224
|
+
if (command.name === "runner") {
|
|
78225
|
+
await runRunnerCli(command.args);
|
|
78226
|
+
return true;
|
|
78227
|
+
}
|
|
77820
78228
|
if (command.name === "pairing") {
|
|
77821
78229
|
await runPairingCli(command.args);
|
|
77822
78230
|
return true;
|
|
@@ -77838,5 +78246,5 @@ try {
|
|
|
77838
78246
|
printCommandOutcomeBanner("failure");
|
|
77839
78247
|
}
|
|
77840
78248
|
await printCliError(error);
|
|
77841
|
-
process.exit(
|
|
78249
|
+
process.exit(getCliErrorExitCode(error));
|
|
77842
78250
|
}
|