clisbot 0.1.11 → 0.1.13
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/dist/main.js
CHANGED
|
@@ -54670,7 +54670,7 @@ function renderCliHelp() {
|
|
|
54670
54670
|
" Fresh bootstrap only enables channels named by flags; ambient env vars alone do not auto-enable extra channels.",
|
|
54671
54671
|
"",
|
|
54672
54672
|
"Usage:",
|
|
54673
|
-
" clisbot start [--cli <codex|claude>] [--bot-type <personal|team>] [--persist]",
|
|
54673
|
+
" clisbot start [--cli <codex|claude|gemini>] [--bot-type <personal|team>] [--persist]",
|
|
54674
54674
|
" [--slack-account <id> --slack-app-token <ENV_NAME|${ENV_NAME}|literal> --slack-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
54675
54675
|
" [--telegram-account <id> --telegram-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
54676
54676
|
" clisbot restart",
|
|
@@ -54684,7 +54684,7 @@ function renderCliHelp() {
|
|
|
54684
54684
|
" clisbot message <subcommand>",
|
|
54685
54685
|
" clisbot agents <subcommand>",
|
|
54686
54686
|
" clisbot pairing <subcommand>",
|
|
54687
|
-
" clisbot init [--cli <codex|claude>] [--bot-type <personal|team>] [--persist]",
|
|
54687
|
+
" clisbot init [--cli <codex|claude|gemini>] [--bot-type <personal|team>] [--persist]",
|
|
54688
54688
|
" [--slack-account <id> --slack-app-token <ENV_NAME|${ENV_NAME}|literal> --slack-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
54689
54689
|
" [--telegram-account <id> --telegram-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
54690
54690
|
" clis <same-command>",
|
|
@@ -55104,7 +55104,7 @@ async function runPairingCli(args, writer = console) {
|
|
|
55104
55104
|
}
|
|
55105
55105
|
|
|
55106
55106
|
// src/config/agent-tool-presets.ts
|
|
55107
|
-
var SUPPORTED_AGENT_CLI_TOOLS = ["codex", "claude"];
|
|
55107
|
+
var SUPPORTED_AGENT_CLI_TOOLS = ["codex", "claude", "gemini"];
|
|
55108
55108
|
var SUPPORTED_BOOTSTRAP_MODES = ["personal-assistant", "team-assistant"];
|
|
55109
55109
|
var SESSION_ID_PATTERN = "\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b";
|
|
55110
55110
|
var DEFAULT_AGENT_TOOL_TEMPLATES = {
|
|
@@ -55169,6 +55169,41 @@ var DEFAULT_AGENT_TOOL_TEMPLATES = {
|
|
|
55169
55169
|
]
|
|
55170
55170
|
}
|
|
55171
55171
|
}
|
|
55172
|
+
},
|
|
55173
|
+
gemini: {
|
|
55174
|
+
command: "gemini",
|
|
55175
|
+
startupOptions: ["--approval-mode=yolo", "--sandbox=false"],
|
|
55176
|
+
trustWorkspace: true,
|
|
55177
|
+
startupDelayMs: 15000,
|
|
55178
|
+
startupReadyPattern: "Type your message or @path/to/file",
|
|
55179
|
+
startupBlockers: [
|
|
55180
|
+
{
|
|
55181
|
+
pattern: "Please visit the following URL to authorize the application|Enter the authorization code:",
|
|
55182
|
+
message: "Gemini CLI is waiting for manual OAuth authorization. Authenticate Gemini once in a direct interactive terminal, or configure headless auth such as GEMINI_API_KEY or Vertex AI before routing Gemini through clisbot."
|
|
55183
|
+
},
|
|
55184
|
+
{
|
|
55185
|
+
pattern: "How would you like to authenticate for this project\\?|Failed to sign in\\.|Manual authorization is required but the current session is non-interactive",
|
|
55186
|
+
message: "Gemini CLI is blocked in its authentication setup flow or sign-in recovery. Complete Gemini authentication directly first, or switch clisbot to a headless auth path such as GEMINI_API_KEY or Vertex AI before routing prompts."
|
|
55187
|
+
}
|
|
55188
|
+
],
|
|
55189
|
+
promptSubmitDelayMs: 200,
|
|
55190
|
+
sessionId: {
|
|
55191
|
+
create: {
|
|
55192
|
+
mode: "runner",
|
|
55193
|
+
args: []
|
|
55194
|
+
},
|
|
55195
|
+
capture: {
|
|
55196
|
+
mode: "status-command",
|
|
55197
|
+
statusCommand: "/stats session",
|
|
55198
|
+
pattern: SESSION_ID_PATTERN,
|
|
55199
|
+
timeoutMs: 8000,
|
|
55200
|
+
pollIntervalMs: 250
|
|
55201
|
+
},
|
|
55202
|
+
resume: {
|
|
55203
|
+
mode: "command",
|
|
55204
|
+
args: ["--resume", "{sessionId}", "--approval-mode=yolo", "--sandbox=false"]
|
|
55205
|
+
}
|
|
55206
|
+
}
|
|
55172
55207
|
}
|
|
55173
55208
|
};
|
|
55174
55209
|
function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
|
|
@@ -55179,6 +55214,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
|
|
|
55179
55214
|
args: [...options, "-C", "{workspace}"],
|
|
55180
55215
|
trustWorkspace: template.trustWorkspace,
|
|
55181
55216
|
startupDelayMs: template.startupDelayMs,
|
|
55217
|
+
startupReadyPattern: template.startupReadyPattern,
|
|
55218
|
+
startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
|
|
55182
55219
|
promptSubmitDelayMs: template.promptSubmitDelayMs,
|
|
55183
55220
|
sessionId: {
|
|
55184
55221
|
...template.sessionId,
|
|
@@ -55201,6 +55238,8 @@ function buildRunnerFromToolTemplate(toolId, template, startupOptions) {
|
|
|
55201
55238
|
args: [...options],
|
|
55202
55239
|
trustWorkspace: template.trustWorkspace,
|
|
55203
55240
|
startupDelayMs: template.startupDelayMs,
|
|
55241
|
+
startupReadyPattern: template.startupReadyPattern,
|
|
55242
|
+
startupBlockers: template.startupBlockers?.map((entry) => ({ ...entry })),
|
|
55204
55243
|
promptSubmitDelayMs: template.promptSubmitDelayMs,
|
|
55205
55244
|
sessionId: {
|
|
55206
55245
|
...template.sessionId,
|
|
@@ -55229,6 +55268,9 @@ function inferAgentCliToolId(command) {
|
|
|
55229
55268
|
if (trimmed === "claude") {
|
|
55230
55269
|
return "claude";
|
|
55231
55270
|
}
|
|
55271
|
+
if (trimmed === "gemini") {
|
|
55272
|
+
return "gemini";
|
|
55273
|
+
}
|
|
55232
55274
|
return null;
|
|
55233
55275
|
}
|
|
55234
55276
|
|
|
@@ -59759,6 +59801,10 @@ var runnerSessionIdObjectSchema = exports_external.object({
|
|
|
59759
59801
|
resume: runnerSessionIdResumeSchema.default(defaultRunnerSessionIdConfig.resume)
|
|
59760
59802
|
});
|
|
59761
59803
|
var runnerSessionIdSchema = runnerSessionIdObjectSchema.default(defaultRunnerSessionIdConfig);
|
|
59804
|
+
var runnerStartupBlockerSchema = exports_external.object({
|
|
59805
|
+
pattern: exports_external.string().min(1),
|
|
59806
|
+
message: exports_external.string().min(1)
|
|
59807
|
+
});
|
|
59762
59808
|
var runnerSchema = exports_external.object({
|
|
59763
59809
|
command: exports_external.string().min(1),
|
|
59764
59810
|
args: exports_external.array(exports_external.string()).default([
|
|
@@ -59769,6 +59815,8 @@ var runnerSchema = exports_external.object({
|
|
|
59769
59815
|
]),
|
|
59770
59816
|
trustWorkspace: exports_external.boolean().default(true),
|
|
59771
59817
|
startupDelayMs: exports_external.number().int().positive().default(3000),
|
|
59818
|
+
startupReadyPattern: exports_external.string().min(1).optional(),
|
|
59819
|
+
startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
|
|
59772
59820
|
promptSubmitDelayMs: exports_external.number().int().min(0).default(150),
|
|
59773
59821
|
sessionId: runnerSessionIdSchema.default(defaultRunnerSessionIdConfig)
|
|
59774
59822
|
});
|
|
@@ -59803,6 +59851,8 @@ var runnerOverrideSchema = exports_external.object({
|
|
|
59803
59851
|
args: exports_external.array(exports_external.string()).optional(),
|
|
59804
59852
|
trustWorkspace: exports_external.boolean().optional(),
|
|
59805
59853
|
startupDelayMs: exports_external.number().int().positive().optional(),
|
|
59854
|
+
startupReadyPattern: exports_external.string().min(1).optional(),
|
|
59855
|
+
startupBlockers: exports_external.array(runnerStartupBlockerSchema).optional(),
|
|
59806
59856
|
promptSubmitDelayMs: exports_external.number().int().min(0).optional(),
|
|
59807
59857
|
sessionId: runnerSessionIdObjectSchema.partial().extend({
|
|
59808
59858
|
create: runnerSessionIdCreateSchema.partial().optional(),
|
|
@@ -60347,6 +60397,7 @@ function renderDefaultConfigTemplate(options = {}) {
|
|
|
60347
60397
|
],
|
|
60348
60398
|
trustWorkspace: true,
|
|
60349
60399
|
startupDelayMs: 3000,
|
|
60400
|
+
startupReadyPattern: undefined,
|
|
60350
60401
|
promptSubmitDelayMs: 150,
|
|
60351
60402
|
sessionId: {
|
|
60352
60403
|
create: {
|
|
@@ -60575,7 +60626,8 @@ var CUSTOMIZED_TEMPLATE_DIR = join4(TEMPLATE_ROOT, "customized");
|
|
|
60575
60626
|
var CUSTOMIZED_DEFAULT_TEMPLATE_DIR = join4(CUSTOMIZED_TEMPLATE_DIR, "default");
|
|
60576
60627
|
var TOOL_BOOTSTRAP_FILE = {
|
|
60577
60628
|
codex: "AGENTS.md",
|
|
60578
|
-
claude: "CLAUDE.md"
|
|
60629
|
+
claude: "CLAUDE.md",
|
|
60630
|
+
gemini: "GEMINI.md"
|
|
60579
60631
|
};
|
|
60580
60632
|
function shouldIncludeTemplateFile(toolId, relativePath) {
|
|
60581
60633
|
const normalized = relativePath.replaceAll("\\", "/");
|
|
@@ -60585,6 +60637,9 @@ function shouldIncludeTemplateFile(toolId, relativePath) {
|
|
|
60585
60637
|
if (normalized.endsWith("CLAUDE.md")) {
|
|
60586
60638
|
return toolId === "claude";
|
|
60587
60639
|
}
|
|
60640
|
+
if (normalized.endsWith("GEMINI.md")) {
|
|
60641
|
+
return toolId === "gemini";
|
|
60642
|
+
}
|
|
60588
60643
|
return true;
|
|
60589
60644
|
}
|
|
60590
60645
|
function collectTemplateFiles(rootDir, toolId, prefix = "") {
|
|
@@ -60882,11 +60937,11 @@ async function addAgentToEditableConfig(params) {
|
|
|
60882
60937
|
async function addAgent(args) {
|
|
60883
60938
|
const agentId = args[0]?.trim();
|
|
60884
60939
|
if (!agentId) {
|
|
60885
|
-
throw new Error("Usage: agents add <id> --cli <codex|claude> [--workspace <path>] [--startup-option <arg>]... [--bootstrap <personal-assistant|team-assistant>] [--bind <channel[:accountId]>]...");
|
|
60940
|
+
throw new Error("Usage: agents add <id> --cli <codex|claude|gemini> [--workspace <path>] [--startup-option <arg>]... [--bootstrap <personal-assistant|team-assistant>] [--bind <channel[:accountId]>]...");
|
|
60886
60941
|
}
|
|
60887
60942
|
const cliTool = parseSingleOption(args, "--cli");
|
|
60888
60943
|
if (!cliTool || !(cliTool in DEFAULT_AGENT_TOOL_TEMPLATES)) {
|
|
60889
|
-
throw new Error("agents add requires --cli codex or --cli
|
|
60944
|
+
throw new Error("agents add requires --cli codex, --cli claude, or --cli gemini");
|
|
60890
60945
|
}
|
|
60891
60946
|
const workspace = parseSingleOption(args, "--workspace");
|
|
60892
60947
|
const startupOptions = parseRepeatedOption(args, "--startup-option");
|
|
@@ -61088,7 +61143,7 @@ async function runAgentsCli(args) {
|
|
|
61088
61143
|
|
|
61089
61144
|
// src/control/accounts-cli.ts
|
|
61090
61145
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
61091
|
-
import { existsSync as existsSync7, readFileSync as
|
|
61146
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
|
|
61092
61147
|
|
|
61093
61148
|
// src/config/channel-account-management.ts
|
|
61094
61149
|
function getFirstAccountId(accounts) {
|
|
@@ -61437,8 +61492,8 @@ class RuntimeHealthStore {
|
|
|
61437
61492
|
}
|
|
61438
61493
|
|
|
61439
61494
|
// src/control/runtime-process.ts
|
|
61440
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
61441
|
-
import { closeSync, existsSync as existsSync6, openSync, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
61495
|
+
import { execFileSync, spawn as spawn2 } from "node:child_process";
|
|
61496
|
+
import { closeSync, existsSync as existsSync6, openSync, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
61442
61497
|
import { dirname as dirname9 } from "node:path";
|
|
61443
61498
|
import { kill } from "node:process";
|
|
61444
61499
|
|
|
@@ -61807,6 +61862,12 @@ class StartDetachedRuntimeError extends Error {
|
|
|
61807
61862
|
this.name = "StartDetachedRuntimeError";
|
|
61808
61863
|
}
|
|
61809
61864
|
}
|
|
61865
|
+
var DEFAULT_PROCESS_LIVENESS_DEPENDENCIES = {
|
|
61866
|
+
platform: process.platform,
|
|
61867
|
+
signalCheck: signalCheckProcess,
|
|
61868
|
+
readLinuxProcStat: readLinuxProcStatLiveness,
|
|
61869
|
+
readPsStat: readPsStatLiveness
|
|
61870
|
+
};
|
|
61810
61871
|
function readRuntimePid(pidPath) {
|
|
61811
61872
|
const expandedPidPath = resolvePidPath(pidPath);
|
|
61812
61873
|
if (!existsSync6(expandedPidPath)) {
|
|
@@ -61819,12 +61880,28 @@ function readRuntimePid(pidPath) {
|
|
|
61819
61880
|
});
|
|
61820
61881
|
}
|
|
61821
61882
|
function isProcessRunning(pid) {
|
|
61822
|
-
|
|
61823
|
-
|
|
61824
|
-
|
|
61825
|
-
|
|
61826
|
-
|
|
61883
|
+
return getProcessLiveness(pid) === "running";
|
|
61884
|
+
}
|
|
61885
|
+
function getProcessLiveness(pid, dependencies = {}) {
|
|
61886
|
+
const resolvedDependencies = {
|
|
61887
|
+
...DEFAULT_PROCESS_LIVENESS_DEPENDENCIES,
|
|
61888
|
+
...dependencies
|
|
61889
|
+
};
|
|
61890
|
+
if (!resolvedDependencies.signalCheck(pid)) {
|
|
61891
|
+
return "missing";
|
|
61827
61892
|
}
|
|
61893
|
+
if (resolvedDependencies.platform === "win32") {
|
|
61894
|
+
return "running";
|
|
61895
|
+
}
|
|
61896
|
+
const linuxState = resolvedDependencies.readLinuxProcStat(pid);
|
|
61897
|
+
if (linuxState !== "unknown") {
|
|
61898
|
+
return linuxState;
|
|
61899
|
+
}
|
|
61900
|
+
const psState = resolvedDependencies.readPsStat(pid);
|
|
61901
|
+
if (psState !== "unknown") {
|
|
61902
|
+
return psState;
|
|
61903
|
+
}
|
|
61904
|
+
return "running";
|
|
61828
61905
|
}
|
|
61829
61906
|
async function ensureConfigFile(configPath, options = {}) {
|
|
61830
61907
|
await ensureClisbotWrapper();
|
|
@@ -61907,18 +61984,27 @@ async function startDetachedRuntime(params) {
|
|
|
61907
61984
|
logPath
|
|
61908
61985
|
};
|
|
61909
61986
|
}
|
|
61910
|
-
async function stopDetachedRuntime(params) {
|
|
61987
|
+
async function stopDetachedRuntime(params, dependencies = {}) {
|
|
61911
61988
|
const pidPath = resolvePidPath(params.pidPath);
|
|
61912
61989
|
const runtimeCredentialsPath = resolveRuntimeCredentialsPath(params.runtimeCredentialsPath);
|
|
61913
61990
|
const existingPid = await readRuntimePid(pidPath);
|
|
61914
61991
|
let stopped = false;
|
|
61915
|
-
|
|
61916
|
-
|
|
61917
|
-
|
|
61992
|
+
const processLiveness = dependencies.processLiveness ?? getProcessLiveness;
|
|
61993
|
+
const sendSignal = dependencies.sendSignal ?? kill;
|
|
61994
|
+
const sleepFn = dependencies.sleep ?? sleep;
|
|
61995
|
+
const existingLiveness = existingPid ? processLiveness(existingPid) : "missing";
|
|
61996
|
+
if (existingPid && existingLiveness === "running") {
|
|
61997
|
+
sendSignal(existingPid, "SIGTERM");
|
|
61998
|
+
const exited = await waitForProcessExit(existingPid, STOP_WAIT_TIMEOUT_MS, {
|
|
61999
|
+
processLiveness,
|
|
62000
|
+
sleep: sleepFn
|
|
62001
|
+
});
|
|
61918
62002
|
if (!exited) {
|
|
61919
62003
|
throw new Error(`clisbot did not stop within ${STOP_WAIT_TIMEOUT_MS}ms`);
|
|
61920
62004
|
}
|
|
61921
62005
|
stopped = true;
|
|
62006
|
+
} else if (existingPid && existingLiveness === "zombie") {
|
|
62007
|
+
stopped = true;
|
|
61922
62008
|
}
|
|
61923
62009
|
rmSync2(pidPath, { force: true });
|
|
61924
62010
|
removeRuntimeCredentials(runtimeCredentialsPath);
|
|
@@ -61960,9 +62046,10 @@ async function getRuntimeStatus(params = {}) {
|
|
|
61960
62046
|
const pidPath = resolvePidPath(params.pidPath);
|
|
61961
62047
|
const logPath = resolveLogPath(params.logPath);
|
|
61962
62048
|
const pid = await readRuntimePid(pidPath);
|
|
62049
|
+
const liveness = pid ? getProcessLiveness(pid) : "missing";
|
|
61963
62050
|
return {
|
|
61964
|
-
running:
|
|
61965
|
-
pid:
|
|
62051
|
+
running: liveness === "running",
|
|
62052
|
+
pid: liveness === "running" && pid ? pid : undefined,
|
|
61966
62053
|
configPath,
|
|
61967
62054
|
pidPath,
|
|
61968
62055
|
logPath,
|
|
@@ -62032,15 +62119,17 @@ async function waitForStart(params) {
|
|
|
62032
62119
|
childPid: params.childPid
|
|
62033
62120
|
};
|
|
62034
62121
|
}
|
|
62035
|
-
async function waitForProcessExit(pid, timeoutMs) {
|
|
62122
|
+
async function waitForProcessExit(pid, timeoutMs, dependencies = {}) {
|
|
62123
|
+
const processLiveness = dependencies.processLiveness ?? getProcessLiveness;
|
|
62124
|
+
const sleepFn = dependencies.sleep ?? sleep;
|
|
62036
62125
|
const deadline = Date.now() + timeoutMs;
|
|
62037
62126
|
while (Date.now() < deadline) {
|
|
62038
|
-
if (
|
|
62127
|
+
if (processLiveness(pid) !== "running") {
|
|
62039
62128
|
return true;
|
|
62040
62129
|
}
|
|
62041
|
-
await
|
|
62130
|
+
await sleepFn(PROCESS_POLL_INTERVAL_MS);
|
|
62042
62131
|
}
|
|
62043
|
-
return
|
|
62132
|
+
return processLiveness(pid) !== "running";
|
|
62044
62133
|
}
|
|
62045
62134
|
async function cleanupFailedStartChild(result) {
|
|
62046
62135
|
if (result.reason === "child-exited-before-pid") {
|
|
@@ -62087,6 +62176,66 @@ async function resolveTmuxSocketPath(configPath) {
|
|
|
62087
62176
|
}
|
|
62088
62177
|
return getDefaultTmuxSocketPath();
|
|
62089
62178
|
}
|
|
62179
|
+
function signalCheckProcess(pid) {
|
|
62180
|
+
try {
|
|
62181
|
+
kill(pid, 0);
|
|
62182
|
+
return true;
|
|
62183
|
+
} catch {
|
|
62184
|
+
return false;
|
|
62185
|
+
}
|
|
62186
|
+
}
|
|
62187
|
+
function readLinuxProcStatLiveness(pid) {
|
|
62188
|
+
if (process.platform !== "linux") {
|
|
62189
|
+
return "unknown";
|
|
62190
|
+
}
|
|
62191
|
+
try {
|
|
62192
|
+
const raw = readFileSync3(`/proc/${pid}/stat`, "utf8");
|
|
62193
|
+
const state = extractLinuxProcState(raw);
|
|
62194
|
+
if (!state) {
|
|
62195
|
+
return "unknown";
|
|
62196
|
+
}
|
|
62197
|
+
return state.includes("Z") ? "zombie" : "running";
|
|
62198
|
+
} catch (error) {
|
|
62199
|
+
const code = error.code;
|
|
62200
|
+
if (code === "ENOENT") {
|
|
62201
|
+
return "missing";
|
|
62202
|
+
}
|
|
62203
|
+
return "unknown";
|
|
62204
|
+
}
|
|
62205
|
+
}
|
|
62206
|
+
function readPsStatLiveness(pid) {
|
|
62207
|
+
try {
|
|
62208
|
+
const raw = execFileSync("ps", ["-o", "stat=", "-p", String(pid)], {
|
|
62209
|
+
encoding: "utf8",
|
|
62210
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
62211
|
+
}).trim();
|
|
62212
|
+
if (!raw) {
|
|
62213
|
+
return "missing";
|
|
62214
|
+
}
|
|
62215
|
+
return raw.includes("Z") ? "zombie" : "running";
|
|
62216
|
+
} catch (error) {
|
|
62217
|
+
const commandError = error;
|
|
62218
|
+
if (commandError.code === "ENOENT") {
|
|
62219
|
+
return "unknown";
|
|
62220
|
+
}
|
|
62221
|
+
if (commandError.status === 1) {
|
|
62222
|
+
return "missing";
|
|
62223
|
+
}
|
|
62224
|
+
return "unknown";
|
|
62225
|
+
}
|
|
62226
|
+
}
|
|
62227
|
+
function extractLinuxProcState(raw) {
|
|
62228
|
+
const closingParenIndex = raw.lastIndexOf(")");
|
|
62229
|
+
if (closingParenIndex < 0) {
|
|
62230
|
+
return null;
|
|
62231
|
+
}
|
|
62232
|
+
const remainder = raw.slice(closingParenIndex + 1).trim();
|
|
62233
|
+
if (!remainder) {
|
|
62234
|
+
return null;
|
|
62235
|
+
}
|
|
62236
|
+
const [state] = remainder.split(/\s+/, 1);
|
|
62237
|
+
return state?.trim() || null;
|
|
62238
|
+
}
|
|
62090
62239
|
|
|
62091
62240
|
// src/control/accounts-cli.ts
|
|
62092
62241
|
function getEditableConfigPath2() {
|
|
@@ -62111,7 +62260,7 @@ function readRuntimeCredentialDocument() {
|
|
|
62111
62260
|
if (!existsSync7(path2)) {
|
|
62112
62261
|
return {};
|
|
62113
62262
|
}
|
|
62114
|
-
const text =
|
|
62263
|
+
const text = readFileSync4(path2, "utf8").trim();
|
|
62115
62264
|
return text ? JSON.parse(text) : {};
|
|
62116
62265
|
}
|
|
62117
62266
|
async function waitForReloadResult(configPath, deps, timeoutMs = 12000) {
|
|
@@ -63380,6 +63529,9 @@ async function runChannelsCli(args) {
|
|
|
63380
63529
|
}
|
|
63381
63530
|
|
|
63382
63531
|
// src/control/channel-bootstrap-flags.ts
|
|
63532
|
+
function isLiteralToken(token) {
|
|
63533
|
+
return token?.kind === "mem";
|
|
63534
|
+
}
|
|
63383
63535
|
function parseBotType(rawValue) {
|
|
63384
63536
|
const value = rawValue.trim().toLowerCase();
|
|
63385
63537
|
if (value === "personal" || value === "personal-assistant") {
|
|
@@ -63434,7 +63586,6 @@ function validateTelegramAccount(account) {
|
|
|
63434
63586
|
function parseBootstrapFlags(args) {
|
|
63435
63587
|
const slackAccounts = [];
|
|
63436
63588
|
const telegramAccounts = [];
|
|
63437
|
-
const literalWarnings = [];
|
|
63438
63589
|
let currentSlackAccountId;
|
|
63439
63590
|
let currentTelegramAccountId;
|
|
63440
63591
|
let cliTool;
|
|
@@ -63486,9 +63637,6 @@ function parseBootstrapFlags(args) {
|
|
|
63486
63637
|
const token = parseTokenInput(parseOptionValue4(args, arg, index));
|
|
63487
63638
|
const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
|
|
63488
63639
|
account.appToken = token;
|
|
63489
|
-
if (token.kind === "mem") {
|
|
63490
|
-
literalWarnings.push(`Slack account ${account.accountId} uses a literal CLI token; shell history or process inspection may expose it.`);
|
|
63491
|
-
}
|
|
63492
63640
|
sawCredentialFlags = true;
|
|
63493
63641
|
sawSlackFlags = true;
|
|
63494
63642
|
index += 1;
|
|
@@ -63498,9 +63646,6 @@ function parseBootstrapFlags(args) {
|
|
|
63498
63646
|
const token = parseTokenInput(parseOptionValue4(args, arg, index));
|
|
63499
63647
|
const account = getOrCreateSlackAccount(slackAccounts, currentSlackAccountId ?? "default");
|
|
63500
63648
|
account.botToken = token;
|
|
63501
|
-
if (token.kind === "mem") {
|
|
63502
|
-
literalWarnings.push(`Slack account ${account.accountId} uses a literal CLI token; shell history or process inspection may expose it.`);
|
|
63503
|
-
}
|
|
63504
63649
|
sawCredentialFlags = true;
|
|
63505
63650
|
sawSlackFlags = true;
|
|
63506
63651
|
index += 1;
|
|
@@ -63510,9 +63655,6 @@ function parseBootstrapFlags(args) {
|
|
|
63510
63655
|
const token = parseTokenInput(parseOptionValue4(args, arg, index));
|
|
63511
63656
|
const account = getOrCreateTelegramAccount(telegramAccounts, currentTelegramAccountId ?? "default");
|
|
63512
63657
|
account.botToken = token;
|
|
63513
|
-
if (token.kind === "mem") {
|
|
63514
|
-
literalWarnings.push(`Telegram account ${account.accountId} uses a literal CLI token; shell history or process inspection may expose it.`);
|
|
63515
|
-
}
|
|
63516
63658
|
sawCredentialFlags = true;
|
|
63517
63659
|
sawTelegramFlags = true;
|
|
63518
63660
|
index += 1;
|
|
@@ -63535,9 +63677,12 @@ function parseBootstrapFlags(args) {
|
|
|
63535
63677
|
sawCredentialFlags,
|
|
63536
63678
|
sawSlackFlags,
|
|
63537
63679
|
sawTelegramFlags,
|
|
63538
|
-
literalWarnings
|
|
63680
|
+
literalWarnings: []
|
|
63539
63681
|
};
|
|
63540
63682
|
}
|
|
63683
|
+
function hasLiteralBootstrapCredentials(flags) {
|
|
63684
|
+
return flags.slackAccounts.some((account) => isLiteralToken(account.appToken) || isLiteralToken(account.botToken)) || flags.telegramAccounts.some((account) => isLiteralToken(account.botToken));
|
|
63685
|
+
}
|
|
63541
63686
|
|
|
63542
63687
|
// src/agents/session-state.ts
|
|
63543
63688
|
class AgentSessionState {
|
|
@@ -64393,6 +64538,12 @@ function looksLikeClaudeSnapshot(lines) {
|
|
|
64393
64538
|
return trimmed.includes("Claude Code v") || trimmed.includes("Welcome back!") || trimmed.includes("Tips for getting started") || trimmed.startsWith("❯") || trimmed.startsWith("⏺");
|
|
64394
64539
|
});
|
|
64395
64540
|
}
|
|
64541
|
+
function looksLikeGeminiSnapshot(lines) {
|
|
64542
|
+
return lines.some((line) => {
|
|
64543
|
+
const trimmed = line.trim();
|
|
64544
|
+
return trimmed.includes("Gemini CLI v") || trimmed.includes("Signed in with Google") || trimmed.includes("YOLO Ctrl+Y") || trimmed.includes("Type your message or @path/to/file") || trimmed.includes("workspace (/directory)");
|
|
64545
|
+
});
|
|
64546
|
+
}
|
|
64396
64547
|
function isProgressLine(line) {
|
|
64397
64548
|
const trimmed = line.trim();
|
|
64398
64549
|
const normalized = trimmed.replace(/^(?::eight_spoked_asterisk:|[✽✶])\s+/, "");
|
|
@@ -64491,6 +64642,9 @@ function dropClaudePromptBlocks(lines) {
|
|
|
64491
64642
|
}
|
|
64492
64643
|
return filtered;
|
|
64493
64644
|
}
|
|
64645
|
+
function dropGeminiPromptBlocks(lines) {
|
|
64646
|
+
return dropPromptBlocks(lines, /^\s*>\s/);
|
|
64647
|
+
}
|
|
64494
64648
|
function isInterruptStatusLine(line) {
|
|
64495
64649
|
const trimmed = line.trim();
|
|
64496
64650
|
if (!trimmed) {
|
|
@@ -64512,6 +64666,13 @@ function shouldDropClaudeChromeLine(line) {
|
|
|
64512
64666
|
}
|
|
64513
64667
|
return trimmed.includes("Claude Code v") || trimmed.includes("Welcome back!") || trimmed.includes("Tips for getting started") || trimmed.includes("Ask Claude to create a new app or clone a repository") || trimmed.includes("Recent activity") || trimmed.includes("No recent activity") || trimmed.includes("API Usage Billing") || trimmed.includes("shift+tab to cycle") || trimmed.includes("ctrl+o to expand") || trimmed.includes("ctrl+b ctrl+b") || trimmed.includes("run in background") || /^~\/\.clisbot\/(?:workspace\/)?[a-z0-9._/-]+$/i.test(trimmed) || trimmed.includes("| claude |") || /^(?:[✻*]\s*)?(?:Worked|Cooked) for \d+s$/i.test(trimmed) || trimmed.startsWith("⏵⏵") || trimmed.startsWith("❯") || isProgressLine(trimmed) || /^[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+$/.test(trimmed) || /^[╭╰│]/.test(trimmed) || /^─+$/.test(trimmed) || /^[▐▛▜▌▝▘ ]+$/.test(trimmed) || /^[▐▛▜▌▝▘ ]+.+$/.test(trimmed);
|
|
64514
64668
|
}
|
|
64669
|
+
function shouldDropGeminiChromeLine(line) {
|
|
64670
|
+
const trimmed = line.trim();
|
|
64671
|
+
if (!trimmed) {
|
|
64672
|
+
return false;
|
|
64673
|
+
}
|
|
64674
|
+
return trimmed.includes("Gemini CLI v") || trimmed.includes("Signed in with Google") || trimmed.includes("Plan:") || /^[▝▜▄▗▟▀ ]+$/.test(trimmed) || trimmed.includes("We're making changes to Gemini CLI") || trimmed.includes("What's Changing:") || trimmed.includes("How it affects you:") || trimmed.includes("Read more: https://goo.gle/geminicli-updates") || trimmed.includes("Skipping project agents due to untrusted folder.") || trimmed.includes("Do you trust the files in this folder?") || trimmed.includes("Trusting a folder allows Gemini CLI to load its local configurations") || trimmed === "1. Trust folder (default)" || trimmed === "2. Trust parent folder (workspaces)" || trimmed === "3. Don't trust" || trimmed.includes("Tips for getting started") || /^Create GEMINI\.md files to customize your interactions$/i.test(trimmed) || /^\/help for more information$/i.test(trimmed) || /^Ask coding questions, edit code or run commands$/i.test(trimmed) || /^Be specific for the best results$/i.test(trimmed) || trimmed.includes("? for shortcuts") || trimmed.includes("YOLO Ctrl+Y") || trimmed.includes("Type your message or @path/to/file") || trimmed.includes("workspace (/directory)") || /^~\/.+\s+\S+\s+no sandbox\s+\S+/i.test(trimmed) || /^Thinking\.\.\. \(esc to cancel,\s*\d+s\)$/i.test(trimmed) || /^[╭╰│]/.test(trimmed) || /^[-▀▄]{10,}$/.test(trimmed) || /^─+$/.test(trimmed);
|
|
64675
|
+
}
|
|
64515
64676
|
function normalizeBoundaryLine(line) {
|
|
64516
64677
|
return line.trim().replace(/^(?::eight_spoked_asterisk:|[-*•◦·✽✶])\s+/, "");
|
|
64517
64678
|
}
|
|
@@ -64548,7 +64709,8 @@ function cleanInteractionSnapshot(raw) {
|
|
|
64548
64709
|
const lines = splitNormalizedLines(raw);
|
|
64549
64710
|
const isCodex = looksLikeCodexSnapshot(lines);
|
|
64550
64711
|
const isClaude = looksLikeClaudeSnapshot(lines);
|
|
64551
|
-
const
|
|
64712
|
+
const isGemini = looksLikeGeminiSnapshot(lines);
|
|
64713
|
+
const promptStripped = isCodex ? dropCodexPromptBlocks(lines) : isClaude ? dropClaudePromptBlocks(lines) : isGemini ? dropGeminiPromptBlocks(lines) : lines;
|
|
64552
64714
|
const filtered = promptStripped.filter((line) => {
|
|
64553
64715
|
if (shouldDropDeliveryReportLine(line)) {
|
|
64554
64716
|
return false;
|
|
@@ -64559,9 +64721,12 @@ function cleanInteractionSnapshot(raw) {
|
|
|
64559
64721
|
if (isClaude && shouldDropClaudeChromeLine(line)) {
|
|
64560
64722
|
return false;
|
|
64561
64723
|
}
|
|
64724
|
+
if (isGemini && shouldDropGeminiChromeLine(line)) {
|
|
64725
|
+
return false;
|
|
64726
|
+
}
|
|
64562
64727
|
return true;
|
|
64563
64728
|
});
|
|
64564
|
-
const normalized = isCodex ? unwrapCodexMessageBlocks(filtered) : isClaude ? unwrapClaudeMessageBlocks(filtered) : filtered;
|
|
64729
|
+
const normalized = isCodex ? unwrapCodexMessageBlocks(filtered) : isClaude ? unwrapClaudeMessageBlocks(filtered) : isGemini ? filtered.map((line) => line.replace(/^\s*>\s*/, "")) : filtered;
|
|
64565
64730
|
const unwrapped = unwrapSoftWrappedLines(normalized);
|
|
64566
64731
|
return collapseAdjacentDuplicateLines(collapseBlankLines(trimBlankLines(unwrapped)).join(`
|
|
64567
64732
|
`));
|
|
@@ -64747,6 +64912,7 @@ function extractFinalAnswer(raw) {
|
|
|
64747
64912
|
const rawLines = splitNormalizedLines(raw);
|
|
64748
64913
|
const isCodex = looksLikeCodexSnapshot(rawLines);
|
|
64749
64914
|
const isClaude = looksLikeClaudeSnapshot(rawLines);
|
|
64915
|
+
const isGemini = looksLikeGeminiSnapshot(rawLines);
|
|
64750
64916
|
const cleaned = cleanInteractionSnapshot(raw);
|
|
64751
64917
|
if (!cleaned) {
|
|
64752
64918
|
return "";
|
|
@@ -64773,14 +64939,14 @@ function extractFinalAnswer(raw) {
|
|
|
64773
64939
|
if (answerBlocks.length > 1 && answerBlocks.every(isShortAtomicAnswerBlock)) {
|
|
64774
64940
|
const lastAnswer = answerBlocks.at(-1)?.trim() ?? "";
|
|
64775
64941
|
if (lastAnswer) {
|
|
64776
|
-
return isCodex || isClaude ? stripSingleLineAssistantEnvelope(lastAnswer) : lastAnswer;
|
|
64942
|
+
return isCodex || isClaude || isGemini ? stripSingleLineAssistantEnvelope(lastAnswer) : lastAnswer;
|
|
64777
64943
|
}
|
|
64778
64944
|
}
|
|
64779
64945
|
const answer = answerBlocks.join(`
|
|
64780
64946
|
|
|
64781
64947
|
`).trim();
|
|
64782
64948
|
const extracted = answer || cleaned;
|
|
64783
|
-
if (isCodex || isClaude) {
|
|
64949
|
+
if (isCodex || isClaude || isGemini) {
|
|
64784
64950
|
return stripSingleLineAssistantEnvelope(extracted);
|
|
64785
64951
|
}
|
|
64786
64952
|
return extracted;
|
|
@@ -64899,14 +65065,23 @@ function logLatencyDebug(stage, context = {}, details = {}) {
|
|
|
64899
65065
|
// src/runners/tmux/session-handshake.ts
|
|
64900
65066
|
var TRUST_PROMPT_POLL_INTERVAL_MS = 250;
|
|
64901
65067
|
var TRUST_PROMPT_MAX_WAIT_MS = 1e4;
|
|
64902
|
-
var TRUST_PROMPT_SETTLE_DELAY_MS = 1500;
|
|
64903
65068
|
var SESSION_BOOTSTRAP_POLL_INTERVAL_MS = 100;
|
|
65069
|
+
var PASTE_SETTLE_POLL_INTERVAL_MS = 40;
|
|
65070
|
+
var PASTE_SETTLE_QUIET_WINDOW_MS = 60;
|
|
65071
|
+
var PASTE_SETTLE_MULTILINE_MAX_WAIT_MS = 800;
|
|
65072
|
+
var PASTE_SETTLE_SINGLE_LINE_MAX_WAIT_MS = 80;
|
|
64904
65073
|
var SUBMIT_CONFIRM_POLL_INTERVAL_MS = 40;
|
|
64905
65074
|
var SUBMIT_CONFIRM_MAX_WAIT_MS = 160;
|
|
64906
65075
|
async function submitTmuxSessionInput(params) {
|
|
65076
|
+
const prePasteState = await params.tmux.getPaneState(params.sessionName);
|
|
64907
65077
|
await params.tmux.sendLiteral(params.sessionName, params.text);
|
|
64908
|
-
await
|
|
64909
|
-
|
|
65078
|
+
const preSubmitState = await waitForPanePasteSettlement({
|
|
65079
|
+
tmux: params.tmux,
|
|
65080
|
+
sessionName: params.sessionName,
|
|
65081
|
+
baseline: prePasteState,
|
|
65082
|
+
text: params.text,
|
|
65083
|
+
minDelayMs: params.promptSubmitDelayMs
|
|
65084
|
+
});
|
|
64910
65085
|
await params.tmux.sendKey(params.sessionName, "Enter");
|
|
64911
65086
|
if (await waitForPaneSubmitConfirmation({
|
|
64912
65087
|
tmux: params.tmux,
|
|
@@ -64932,7 +65107,6 @@ async function submitTmuxSessionInput(params) {
|
|
|
64932
65107
|
throw new Error("tmux submit was not confirmed after Enter. The pane state did not change, so clisbot did not treat the prompt as truthfully submitted.");
|
|
64933
65108
|
}
|
|
64934
65109
|
async function captureTmuxSessionIdentity(params) {
|
|
64935
|
-
let deadline = Date.now() + params.timeoutMs;
|
|
64936
65110
|
await submitTmuxSessionInput({
|
|
64937
65111
|
tmux: params.tmux,
|
|
64938
65112
|
sessionName: params.sessionName,
|
|
@@ -64940,11 +65114,16 @@ async function captureTmuxSessionIdentity(params) {
|
|
|
64940
65114
|
promptSubmitDelayMs: params.promptSubmitDelayMs,
|
|
64941
65115
|
timingContext: undefined
|
|
64942
65116
|
});
|
|
65117
|
+
let deadline = Date.now() + params.timeoutMs;
|
|
64943
65118
|
while (Date.now() < deadline) {
|
|
64944
65119
|
await sleep(params.pollIntervalMs);
|
|
64945
65120
|
const snapshot = normalizePaneText(await params.tmux.capturePane(params.sessionName, params.captureLines));
|
|
64946
65121
|
if (hasTrustPrompt(snapshot)) {
|
|
64947
|
-
await dismissTrustPrompt(
|
|
65122
|
+
await dismissTrustPrompt({
|
|
65123
|
+
tmux: params.tmux,
|
|
65124
|
+
sessionName: params.sessionName,
|
|
65125
|
+
captureLines: params.captureLines
|
|
65126
|
+
});
|
|
64948
65127
|
deadline = Date.now() + params.timeoutMs;
|
|
64949
65128
|
await submitTmuxSessionInput({
|
|
64950
65129
|
tmux: params.tmux,
|
|
@@ -64973,11 +65152,21 @@ async function dismissTmuxTrustPromptIfPresent(params) {
|
|
|
64973
65152
|
if (!hasTrustPrompt(snapshot)) {
|
|
64974
65153
|
return;
|
|
64975
65154
|
}
|
|
64976
|
-
await dismissTrustPrompt(
|
|
65155
|
+
await dismissTrustPrompt({
|
|
65156
|
+
tmux: params.tmux,
|
|
65157
|
+
sessionName: params.sessionName,
|
|
65158
|
+
captureLines: params.captureLines
|
|
65159
|
+
});
|
|
64977
65160
|
}
|
|
64978
65161
|
}
|
|
64979
65162
|
async function waitForTmuxSessionBootstrap(params) {
|
|
64980
65163
|
const deadline = Date.now() + Math.max(params.startupDelayMs, SESSION_BOOTSTRAP_POLL_INTERVAL_MS);
|
|
65164
|
+
const readyRegex = params.readyPattern ? new RegExp(params.readyPattern, "i") : null;
|
|
65165
|
+
const blockerPatterns = (params.blockers ?? []).map((entry) => ({
|
|
65166
|
+
regex: new RegExp(entry.pattern, "i"),
|
|
65167
|
+
message: entry.message
|
|
65168
|
+
}));
|
|
65169
|
+
let lastSnapshot = "";
|
|
64981
65170
|
while (Date.now() <= deadline) {
|
|
64982
65171
|
let snapshot = "";
|
|
64983
65172
|
try {
|
|
@@ -64985,23 +65174,60 @@ async function waitForTmuxSessionBootstrap(params) {
|
|
|
64985
65174
|
} catch (error) {
|
|
64986
65175
|
const message = error instanceof Error ? error.message : String(error);
|
|
64987
65176
|
if (message.includes("can't find session:") || message.includes("no server running on ")) {
|
|
64988
|
-
return
|
|
65177
|
+
return {
|
|
65178
|
+
status: "timeout",
|
|
65179
|
+
snapshot: lastSnapshot
|
|
65180
|
+
};
|
|
64989
65181
|
}
|
|
64990
65182
|
throw error;
|
|
64991
65183
|
}
|
|
64992
65184
|
if (snapshot) {
|
|
64993
|
-
|
|
65185
|
+
lastSnapshot = snapshot;
|
|
65186
|
+
if (params.trustWorkspace && hasTrustPrompt(snapshot)) {
|
|
65187
|
+
await dismissTrustPrompt({
|
|
65188
|
+
tmux: params.tmux,
|
|
65189
|
+
sessionName: params.sessionName,
|
|
65190
|
+
captureLines: params.captureLines
|
|
65191
|
+
});
|
|
65192
|
+
await sleep(SESSION_BOOTSTRAP_POLL_INTERVAL_MS);
|
|
65193
|
+
continue;
|
|
65194
|
+
}
|
|
65195
|
+
for (const blocker of blockerPatterns) {
|
|
65196
|
+
if (blocker.regex.test(snapshot)) {
|
|
65197
|
+
return {
|
|
65198
|
+
status: "blocked",
|
|
65199
|
+
snapshot,
|
|
65200
|
+
message: blocker.message
|
|
65201
|
+
};
|
|
65202
|
+
}
|
|
65203
|
+
}
|
|
65204
|
+
if (readyRegex && !readyRegex.test(snapshot)) {
|
|
65205
|
+
await sleep(SESSION_BOOTSTRAP_POLL_INTERVAL_MS);
|
|
65206
|
+
continue;
|
|
65207
|
+
}
|
|
65208
|
+
return {
|
|
65209
|
+
status: "ready",
|
|
65210
|
+
snapshot
|
|
65211
|
+
};
|
|
64994
65212
|
}
|
|
64995
65213
|
await sleep(SESSION_BOOTSTRAP_POLL_INTERVAL_MS);
|
|
64996
65214
|
}
|
|
64997
|
-
return
|
|
64998
|
-
|
|
64999
|
-
|
|
65000
|
-
|
|
65215
|
+
return {
|
|
65216
|
+
status: "timeout",
|
|
65217
|
+
snapshot: lastSnapshot
|
|
65218
|
+
};
|
|
65001
65219
|
}
|
|
65002
|
-
async function dismissTrustPrompt(
|
|
65003
|
-
await tmux.sendKey(sessionName, "Enter");
|
|
65004
|
-
|
|
65220
|
+
async function dismissTrustPrompt(params) {
|
|
65221
|
+
await params.tmux.sendKey(params.sessionName, "Enter");
|
|
65222
|
+
const deadline = Date.now() + TRUST_PROMPT_MAX_WAIT_MS;
|
|
65223
|
+
while (Date.now() <= deadline) {
|
|
65224
|
+
await sleep(TRUST_PROMPT_POLL_INTERVAL_MS);
|
|
65225
|
+
const snapshot = normalizePaneText(await params.tmux.capturePane(params.sessionName, params.captureLines));
|
|
65226
|
+
if (!snapshot || hasTrustPrompt(snapshot)) {
|
|
65227
|
+
continue;
|
|
65228
|
+
}
|
|
65229
|
+
return;
|
|
65230
|
+
}
|
|
65005
65231
|
}
|
|
65006
65232
|
async function waitForPaneSubmitConfirmation(params) {
|
|
65007
65233
|
const deadline = Date.now() + SUBMIT_CONFIRM_MAX_WAIT_MS;
|
|
@@ -65017,9 +65243,50 @@ async function waitForPaneSubmitConfirmation(params) {
|
|
|
65017
65243
|
await sleep(Math.min(SUBMIT_CONFIRM_POLL_INTERVAL_MS, remainingMs));
|
|
65018
65244
|
}
|
|
65019
65245
|
}
|
|
65246
|
+
async function waitForPanePasteSettlement(params) {
|
|
65247
|
+
await sleep(params.minDelayMs);
|
|
65248
|
+
let currentState = await params.tmux.getPaneState(params.sessionName);
|
|
65249
|
+
let sawChange = hasPaneStateChanged(params.baseline, currentState);
|
|
65250
|
+
let lastChangeAt = Date.now();
|
|
65251
|
+
const deadline = Date.now() + (shouldWaitForVisiblePaste(params.text) ? PASTE_SETTLE_MULTILINE_MAX_WAIT_MS : PASTE_SETTLE_SINGLE_LINE_MAX_WAIT_MS);
|
|
65252
|
+
while (true) {
|
|
65253
|
+
if (sawChange && Date.now() - lastChangeAt >= PASTE_SETTLE_QUIET_WINDOW_MS) {
|
|
65254
|
+
return currentState;
|
|
65255
|
+
}
|
|
65256
|
+
const remainingMs = deadline - Date.now();
|
|
65257
|
+
if (remainingMs <= 0) {
|
|
65258
|
+
return currentState;
|
|
65259
|
+
}
|
|
65260
|
+
await sleep(Math.min(PASTE_SETTLE_POLL_INTERVAL_MS, remainingMs));
|
|
65261
|
+
const nextState = await params.tmux.getPaneState(params.sessionName);
|
|
65262
|
+
if (!arePaneStatesEqual(currentState, nextState)) {
|
|
65263
|
+
currentState = nextState;
|
|
65264
|
+
if (hasPaneStateChanged(params.baseline, currentState)) {
|
|
65265
|
+
sawChange = true;
|
|
65266
|
+
}
|
|
65267
|
+
lastChangeAt = Date.now();
|
|
65268
|
+
}
|
|
65269
|
+
}
|
|
65270
|
+
}
|
|
65020
65271
|
function hasPaneStateChanged(left, right) {
|
|
65021
65272
|
return left.cursorX !== right.cursorX || left.cursorY !== right.cursorY || left.historySize !== right.historySize;
|
|
65022
65273
|
}
|
|
65274
|
+
function arePaneStatesEqual(left, right) {
|
|
65275
|
+
return left.cursorX === right.cursorX && left.cursorY === right.cursorY && left.historySize === right.historySize;
|
|
65276
|
+
}
|
|
65277
|
+
function looksLikeClaudeTrustPrompt(snapshot) {
|
|
65278
|
+
return snapshot.includes("Quick safety check:") && snapshot.includes("Yes, I trust this folder") || snapshot.includes("Enter to confirm · Esc to cancel");
|
|
65279
|
+
}
|
|
65280
|
+
function looksLikeGeminiTrustPrompt(snapshot) {
|
|
65281
|
+
return snapshot.includes("Skipping project agents due to untrusted folder.") && snapshot.includes("Do you trust the files in this folder?") || snapshot.includes("Trusting a folder allows Gemini CLI to load its local configurations") && snapshot.includes("Trust folder (default)");
|
|
65282
|
+
}
|
|
65283
|
+
function hasTrustPrompt(snapshot) {
|
|
65284
|
+
return snapshot.includes("Do you trust the contents of this directory?") || snapshot.includes("Press enter to continue") || looksLikeClaudeTrustPrompt(snapshot) || looksLikeGeminiTrustPrompt(snapshot);
|
|
65285
|
+
}
|
|
65286
|
+
function shouldWaitForVisiblePaste(text) {
|
|
65287
|
+
return text.includes(`
|
|
65288
|
+
`);
|
|
65289
|
+
}
|
|
65023
65290
|
|
|
65024
65291
|
// src/runners/tmux/shell-command.ts
|
|
65025
65292
|
var BASH_WINDOW_NAME = "bash";
|
|
@@ -65147,6 +65414,11 @@ function buildRunnerLaunchCommand(command, args) {
|
|
|
65147
65414
|
];
|
|
65148
65415
|
return `${exports.join("; ")}; exec ${buildCommandString(command, args)}`;
|
|
65149
65416
|
}
|
|
65417
|
+
function summarizeSnapshot(snapshot) {
|
|
65418
|
+
const compact = snapshot.split(`
|
|
65419
|
+
`).map((line) => line.trim()).filter(Boolean).join(" ").slice(0, 220);
|
|
65420
|
+
return compact ? ` Last visible pane: ${compact}` : "";
|
|
65421
|
+
}
|
|
65150
65422
|
function isTmuxDuplicateSessionError(error) {
|
|
65151
65423
|
const message = error instanceof Error ? error.message : String(error);
|
|
65152
65424
|
return TMUX_DUPLICATE_SESSION_PATTERN.test(message);
|
|
@@ -65239,6 +65511,10 @@ class RunnerSessionService {
|
|
|
65239
65511
|
allowFreshRetry: options.nextAllowFreshRetry
|
|
65240
65512
|
});
|
|
65241
65513
|
}
|
|
65514
|
+
async abortUnreadySession(resolved, reason, snapshot) {
|
|
65515
|
+
await this.tmux.killSession(resolved.sessionName);
|
|
65516
|
+
throw new Error(`${reason}${summarizeSnapshot(snapshot)}`);
|
|
65517
|
+
}
|
|
65242
65518
|
async runSessionCleanup() {
|
|
65243
65519
|
if (this.cleanupInFlight) {
|
|
65244
65520
|
return;
|
|
@@ -65328,11 +65604,14 @@ class RunnerSessionService {
|
|
|
65328
65604
|
resumingExistingSession,
|
|
65329
65605
|
hasStoredSessionId: Boolean(existing?.sessionId)
|
|
65330
65606
|
});
|
|
65331
|
-
await waitForTmuxSessionBootstrap({
|
|
65607
|
+
const bootstrapResult = await waitForTmuxSessionBootstrap({
|
|
65332
65608
|
tmux: this.tmux,
|
|
65333
65609
|
sessionName: resolved.sessionName,
|
|
65334
65610
|
captureLines: resolved.stream.captureLines,
|
|
65335
|
-
startupDelayMs: resolved.runner.startupDelayMs
|
|
65611
|
+
startupDelayMs: resolved.runner.startupDelayMs,
|
|
65612
|
+
trustWorkspace: resolved.runner.trustWorkspace,
|
|
65613
|
+
readyPattern: resolved.runner.startupReadyPattern,
|
|
65614
|
+
blockers: resolved.runner.startupBlockers
|
|
65336
65615
|
});
|
|
65337
65616
|
const sessionStillExists = await this.tmux.hasSession(resolved.sessionName);
|
|
65338
65617
|
if (!sessionStillExists) {
|
|
@@ -65347,6 +65626,12 @@ class RunnerSessionService {
|
|
|
65347
65626
|
}
|
|
65348
65627
|
throw new Error(`Runner session "${resolved.sessionName}" disappeared during startup.`);
|
|
65349
65628
|
}
|
|
65629
|
+
if (bootstrapResult.status === "blocked") {
|
|
65630
|
+
await this.abortUnreadySession(resolved, bootstrapResult.message, bootstrapResult.snapshot);
|
|
65631
|
+
}
|
|
65632
|
+
if (bootstrapResult.status === "timeout" && resolved.runner.startupReadyPattern) {
|
|
65633
|
+
await this.abortUnreadySession(resolved, `Runner session "${resolved.sessionName}" did not reach the configured ready state within ${resolved.runner.startupDelayMs}ms.`, bootstrapResult.snapshot);
|
|
65634
|
+
}
|
|
65350
65635
|
try {
|
|
65351
65636
|
await this.finalizeSessionStartup(target, resolved, {
|
|
65352
65637
|
startupSessionId,
|
|
@@ -65710,6 +65995,7 @@ class ActiveRunManager {
|
|
|
65710
65995
|
runnerSessions;
|
|
65711
65996
|
resolveTarget;
|
|
65712
65997
|
activeRuns = new Map;
|
|
65998
|
+
stopping = false;
|
|
65713
65999
|
constructor(tmux, sessionState, runnerSessions, resolveTarget) {
|
|
65714
66000
|
this.tmux = tmux;
|
|
65715
66001
|
this.sessionState = sessionState;
|
|
@@ -65759,6 +66045,9 @@ class ActiveRunManager {
|
|
|
65759
66045
|
}
|
|
65760
66046
|
}
|
|
65761
66047
|
async executePrompt(target, prompt, observer, options = {}) {
|
|
66048
|
+
if (this.stopping) {
|
|
66049
|
+
throw new Error("Runtime is stopping and cannot accept a new prompt.");
|
|
66050
|
+
}
|
|
65762
66051
|
const existingActiveRun = this.activeRuns.get(target.sessionKey);
|
|
65763
66052
|
if (existingActiveRun) {
|
|
65764
66053
|
throw new ActiveRunInProgressError(existingActiveRun.latestUpdate);
|
|
@@ -65804,6 +66093,9 @@ class ActiveRunManager {
|
|
|
65804
66093
|
const startedAt = Date.now();
|
|
65805
66094
|
const run = this.activeRuns.get(provisionalResolved.sessionKey);
|
|
65806
66095
|
if (!run) {
|
|
66096
|
+
if (this.stopping) {
|
|
66097
|
+
throw new Error("Runtime stopped before the active run finished startup.");
|
|
66098
|
+
}
|
|
65807
66099
|
throw new Error(`Active run disappeared during startup for ${provisionalResolved.sessionKey}.`);
|
|
65808
66100
|
}
|
|
65809
66101
|
run.resolved = resolved;
|
|
@@ -65880,6 +66172,16 @@ class ActiveRunManager {
|
|
|
65880
66172
|
hasActiveRun(target) {
|
|
65881
66173
|
return this.activeRuns.has(target.sessionKey);
|
|
65882
66174
|
}
|
|
66175
|
+
async stop() {
|
|
66176
|
+
this.stopping = true;
|
|
66177
|
+
const activeRuns = [...this.activeRuns.values()];
|
|
66178
|
+
for (const run of activeRuns) {
|
|
66179
|
+
await this.sessionState.setSessionRuntime(run.resolved, {
|
|
66180
|
+
state: "idle"
|
|
66181
|
+
});
|
|
66182
|
+
}
|
|
66183
|
+
this.activeRuns.clear();
|
|
66184
|
+
}
|
|
65883
66185
|
buildDetachedNote(resolved) {
|
|
65884
66186
|
return `This session has been running for over ${resolved.stream.maxRuntimeLabel}. clisbot will keep monitoring it and will post the final result here when it completes. Use \`/attach\` to resume live updates, \`/watch every 30s\` for interval updates, or \`/stop\` to interrupt it.`;
|
|
65885
66187
|
}
|
|
@@ -66060,6 +66362,7 @@ class AgentService {
|
|
|
66060
66362
|
sessionState;
|
|
66061
66363
|
runnerSessions;
|
|
66062
66364
|
activeRuns;
|
|
66365
|
+
stopping = false;
|
|
66063
66366
|
cleanupTimer;
|
|
66064
66367
|
loopTimers = new Set;
|
|
66065
66368
|
intervalLoops = new Map;
|
|
@@ -66095,6 +66398,7 @@ class AgentService {
|
|
|
66095
66398
|
}, cleanup.intervalMinutes * 60000);
|
|
66096
66399
|
}
|
|
66097
66400
|
async stop() {
|
|
66401
|
+
this.stopping = true;
|
|
66098
66402
|
if (this.cleanupTimer) {
|
|
66099
66403
|
clearInterval(this.cleanupTimer);
|
|
66100
66404
|
this.cleanupTimer = undefined;
|
|
@@ -66109,6 +66413,7 @@ class AgentService {
|
|
|
66109
66413
|
clearTimeout(timer);
|
|
66110
66414
|
}
|
|
66111
66415
|
this.loopTimers.clear();
|
|
66416
|
+
await this.activeRuns.stop();
|
|
66112
66417
|
}
|
|
66113
66418
|
async cleanupStaleSessions() {
|
|
66114
66419
|
await this.runnerSessions.runSessionCleanup();
|
|
@@ -66420,6 +66725,9 @@ class AgentService {
|
|
|
66420
66725
|
}
|
|
66421
66726
|
});
|
|
66422
66727
|
result.catch((error) => {
|
|
66728
|
+
if (this.shouldSuppressLoopShutdownError(error)) {
|
|
66729
|
+
return;
|
|
66730
|
+
}
|
|
66423
66731
|
console.error("loop execution failed", error);
|
|
66424
66732
|
});
|
|
66425
66733
|
if (attemptedRuns >= managed.loop.maxRuns) {
|
|
@@ -66445,6 +66753,9 @@ class AgentService {
|
|
|
66445
66753
|
}
|
|
66446
66754
|
current.timer = undefined;
|
|
66447
66755
|
this.runIntervalLoopIteration(loopId).catch((error) => {
|
|
66756
|
+
if (this.shouldSuppressLoopShutdownError(error)) {
|
|
66757
|
+
return;
|
|
66758
|
+
}
|
|
66448
66759
|
console.error("loop execution failed", error);
|
|
66449
66760
|
});
|
|
66450
66761
|
}, delayMs);
|
|
@@ -66459,6 +66770,13 @@ class AgentService {
|
|
|
66459
66770
|
managed.loop = nextLoopState;
|
|
66460
66771
|
return true;
|
|
66461
66772
|
}
|
|
66773
|
+
shouldSuppressLoopShutdownError(error) {
|
|
66774
|
+
if (!this.stopping) {
|
|
66775
|
+
return false;
|
|
66776
|
+
}
|
|
66777
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
66778
|
+
return /Runtime stopped before the active run finished startup|Runtime is stopping and cannot accept a new prompt/i.test(message);
|
|
66779
|
+
}
|
|
66462
66780
|
computeNextManagedLoopRunAtMs(loop, nowMs) {
|
|
66463
66781
|
if (loop.kind === "calendar") {
|
|
66464
66782
|
return computeNextCalendarLoopRunAtMs({
|
|
@@ -67155,12 +67473,14 @@ function buildChannelObserverId(identity) {
|
|
|
67155
67473
|
}
|
|
67156
67474
|
function buildSteeringMessage(text) {
|
|
67157
67475
|
return [
|
|
67476
|
+
"<system>",
|
|
67477
|
+
"A new user message arrived while you were still working.",
|
|
67478
|
+
"Adjust your current work if needed and continue.",
|
|
67479
|
+
"</system>",
|
|
67158
67480
|
"",
|
|
67159
|
-
"
|
|
67160
|
-
|
|
67161
|
-
"
|
|
67162
|
-
"",
|
|
67163
|
-
text
|
|
67481
|
+
"<user>",
|
|
67482
|
+
text,
|
|
67483
|
+
"</user>"
|
|
67164
67484
|
].join(`
|
|
67165
67485
|
`);
|
|
67166
67486
|
}
|
|
@@ -68009,14 +68329,14 @@ function renderAgentPromptInstruction(params) {
|
|
|
68009
68329
|
`[${renderPromptTimestamp()}] ${renderIdentitySummary(params.identity)}`,
|
|
68010
68330
|
"",
|
|
68011
68331
|
"You are operating inside clisbot.",
|
|
68012
|
-
messageToolMode ? "
|
|
68332
|
+
messageToolMode ? "To send a user-visible progress update or final reply, use the following CLI command:" : "channel auto-delivery remains enabled for this conversation; do not send user-facing progress updates or the final response with clisbot message send"
|
|
68013
68333
|
];
|
|
68014
68334
|
if (messageToolMode) {
|
|
68015
68335
|
const replyCommand = buildReplyCommand({
|
|
68016
68336
|
command: getClisbotPromptCommand(),
|
|
68017
68337
|
identity: params.identity
|
|
68018
68338
|
});
|
|
68019
|
-
lines.push("
|
|
68339
|
+
lines.push(replyCommand, "When replying to the user:", "- put the user-facing message inside the --message body of that command", "- use that command to send progress updates and the final reply back to the conversation", `- send at most ${params.config.maxProgressMessages} progress updates`, params.config.requireFinalResponse ? "- send exactly 1 final user-facing response" : "- final response is optional", "- keep progress updates short and meaningful", "- do not send progress updates for trivial internal steps");
|
|
68020
68340
|
}
|
|
68021
68341
|
return lines.join(`
|
|
68022
68342
|
`);
|
|
@@ -69238,6 +69558,7 @@ class SlackSocketService {
|
|
|
69238
69558
|
timestamp: messageTs
|
|
69239
69559
|
};
|
|
69240
69560
|
let responseChunks = [];
|
|
69561
|
+
const cliTool = getAgentEntry(this.loadedConfig, params.route.agentId)?.cliTool;
|
|
69241
69562
|
const agentPromptText = buildAgentPromptText({
|
|
69242
69563
|
text,
|
|
69243
69564
|
identity: {
|
|
@@ -69248,6 +69569,7 @@ class SlackSocketService {
|
|
|
69248
69569
|
threadTs
|
|
69249
69570
|
},
|
|
69250
69571
|
config: this.loadedConfig.raw.channels.slack.agentPrompt,
|
|
69572
|
+
cliTool,
|
|
69251
69573
|
responseMode: params.route.responseMode
|
|
69252
69574
|
});
|
|
69253
69575
|
const timingContext = {
|
|
@@ -69295,6 +69617,7 @@ class SlackSocketService {
|
|
|
69295
69617
|
threadTs
|
|
69296
69618
|
},
|
|
69297
69619
|
config: this.loadedConfig.raw.channels.slack.agentPrompt,
|
|
69620
|
+
cliTool,
|
|
69298
69621
|
responseMode: params.route.responseMode
|
|
69299
69622
|
}),
|
|
69300
69623
|
route: params.route,
|
|
@@ -70644,10 +70967,12 @@ class TelegramPollingService {
|
|
|
70644
70967
|
chatName: message.chat.title?.trim() || undefined,
|
|
70645
70968
|
topicId: routeInfo.topicId != null ? String(routeInfo.topicId) : undefined
|
|
70646
70969
|
};
|
|
70970
|
+
const cliTool = getAgentEntry(this.loadedConfig, routeInfo.route.agentId)?.cliTool;
|
|
70647
70971
|
const agentPromptText = buildAgentPromptText({
|
|
70648
70972
|
text,
|
|
70649
70973
|
identity,
|
|
70650
70974
|
config: this.loadedConfig.raw.channels.telegram.agentPrompt,
|
|
70975
|
+
cliTool,
|
|
70651
70976
|
responseMode: routeInfo.route.responseMode
|
|
70652
70977
|
});
|
|
70653
70978
|
const timingContext = {
|
|
@@ -70680,6 +71005,7 @@ class TelegramPollingService {
|
|
|
70680
71005
|
text: nextText,
|
|
70681
71006
|
identity,
|
|
70682
71007
|
config: this.loadedConfig.raw.channels.telegram.agentPrompt,
|
|
71008
|
+
cliTool,
|
|
70683
71009
|
responseMode: routeInfo.route.responseMode
|
|
70684
71010
|
}),
|
|
70685
71011
|
route: routeInfo.route,
|
|
@@ -71711,7 +72037,7 @@ async function getRuntimeOperatorSummary(params) {
|
|
|
71711
72037
|
const agentSummaries = loadedConfig.raw.agents.list.map((entry) => {
|
|
71712
72038
|
const resolved = new AgentService(loadedConfig).getResolvedAgentConfig(entry.id);
|
|
71713
72039
|
const tool = deriveAgentTool(loadedConfig, entry.id);
|
|
71714
|
-
const bootstrapState = getBootstrapWorkspaceState(resolved.workspacePath, entry.bootstrap?.mode, tool.cliTool === "codex" || tool.cliTool === "claude" ? tool.cliTool : undefined);
|
|
72040
|
+
const bootstrapState = getBootstrapWorkspaceState(resolved.workspacePath, entry.bootstrap?.mode, tool.cliTool === "codex" || tool.cliTool === "claude" || tool.cliTool === "gemini" ? tool.cliTool : undefined);
|
|
71715
72041
|
return {
|
|
71716
72042
|
id: entry.id,
|
|
71717
72043
|
cliTool: tool.cliTool,
|
|
@@ -72048,6 +72374,9 @@ function printCommandOutcomeBanner(outcome) {
|
|
|
72048
72374
|
console.log("+---------+");
|
|
72049
72375
|
console.log("");
|
|
72050
72376
|
}
|
|
72377
|
+
function printCommandOutcomeFooter(outcome) {
|
|
72378
|
+
printCommandOutcomeBanner(outcome);
|
|
72379
|
+
}
|
|
72051
72380
|
function getPrimaryWorkspacePath(summary) {
|
|
72052
72381
|
const preferredAgentId = summary.channelSummaries.find((channel) => channel.enabled)?.defaultAgentId ?? "default";
|
|
72053
72382
|
return summary.agentSummaries.find((agent) => agent.id === preferredAgentId)?.workspacePath ?? summary.agentSummaries[0]?.workspacePath;
|
|
@@ -72068,13 +72397,18 @@ function printMissingBootstrapOptions(commandName) {
|
|
|
72068
72397
|
console.log(` clisbot ${commandName} --cli codex --bot-type team`);
|
|
72069
72398
|
console.log(` clisbot ${commandName} --cli claude --bot-type personal`);
|
|
72070
72399
|
console.log(` clisbot ${commandName} --cli claude --bot-type team`);
|
|
72400
|
+
console.log(` clisbot ${commandName} --cli gemini --bot-type personal`);
|
|
72401
|
+
console.log(` clisbot ${commandName} --cli gemini --bot-type team`);
|
|
72071
72402
|
console.log("Manual setup is still available with `clisbot agents add ...`.");
|
|
72072
72403
|
for (const line of renderOperatorHelpLines()) {
|
|
72073
72404
|
console.log(line);
|
|
72074
72405
|
}
|
|
72406
|
+
if (commandName === "start") {
|
|
72407
|
+
printCommandOutcomeFooter("failure");
|
|
72408
|
+
}
|
|
72075
72409
|
}
|
|
72076
72410
|
function hasLiteralMemCredentials(flags) {
|
|
72077
|
-
return flags
|
|
72411
|
+
return hasLiteralBootstrapCredentials(flags);
|
|
72078
72412
|
}
|
|
72079
72413
|
async function prepareBootstrapState(rawArgs, commandName, options = {
|
|
72080
72414
|
runtimeRunning: false
|
|
@@ -72090,6 +72424,9 @@ async function prepareBootstrapState(rawArgs, commandName, options = {
|
|
|
72090
72424
|
for (const line of renderMissingTokenWarningLines()) {
|
|
72091
72425
|
console.log(line);
|
|
72092
72426
|
}
|
|
72427
|
+
if (commandName === "start") {
|
|
72428
|
+
printCommandOutcomeFooter("failure");
|
|
72429
|
+
}
|
|
72093
72430
|
return null;
|
|
72094
72431
|
}
|
|
72095
72432
|
if (commandName === "init" && hasLiteralMemCredentials(bootstrapFlags) && !bootstrapFlags.persist) {
|
|
@@ -72151,6 +72488,7 @@ async function ensureDefaultAgentBootstrap(state, options, commandName) {
|
|
|
72151
72488
|
for (const line of renderOperatorHelpLines()) {
|
|
72152
72489
|
console.log(line);
|
|
72153
72490
|
}
|
|
72491
|
+
printCommandOutcomeFooter("failure");
|
|
72154
72492
|
return false;
|
|
72155
72493
|
}
|
|
72156
72494
|
}
|
|
@@ -72224,11 +72562,14 @@ async function serveForeground() {
|
|
|
72224
72562
|
async function start(args = []) {
|
|
72225
72563
|
const runtimeStatus = await getRuntimeStatus();
|
|
72226
72564
|
const bootstrapFlags = parseBootstrapFlags(args);
|
|
72227
|
-
|
|
72228
|
-
|
|
72565
|
+
const restartForLiteralBootstrap = runtimeStatus.running && hasLiteralMemCredentials(bootstrapFlags);
|
|
72566
|
+
if (restartForLiteralBootstrap) {
|
|
72567
|
+
await stopDetachedRuntime({
|
|
72568
|
+
configPath: runtimeStatus.configPath
|
|
72569
|
+
});
|
|
72229
72570
|
}
|
|
72230
72571
|
const state = await prepareBootstrapState(args, "start", {
|
|
72231
|
-
runtimeRunning: runtimeStatus.running,
|
|
72572
|
+
runtimeRunning: restartForLiteralBootstrap ? false : runtimeStatus.running,
|
|
72232
72573
|
bootstrapFlags
|
|
72233
72574
|
});
|
|
72234
72575
|
if (!state) {
|
|
@@ -72244,13 +72585,14 @@ async function start(args = []) {
|
|
|
72244
72585
|
for (const line of renderConfiguredChannelTokenStatusLines(state.config, runtimeMemEnv)) {
|
|
72245
72586
|
console.log(line);
|
|
72246
72587
|
}
|
|
72247
|
-
if (!runtimeStatus.running) {
|
|
72588
|
+
if (restartForLiteralBootstrap || !runtimeStatus.running) {
|
|
72248
72589
|
const tokenIssueLines = renderConfiguredChannelTokenIssueLines(state.config, runtimeMemEnv);
|
|
72249
72590
|
for (const line of tokenIssueLines) {
|
|
72250
72591
|
console.log(line);
|
|
72251
72592
|
}
|
|
72252
72593
|
if (tokenIssueLines.length > 0) {
|
|
72253
72594
|
printCommandOutcomeBanner("failure");
|
|
72595
|
+
printCommandOutcomeFooter("failure");
|
|
72254
72596
|
return;
|
|
72255
72597
|
}
|
|
72256
72598
|
}
|
|
@@ -72266,7 +72608,7 @@ async function start(args = []) {
|
|
|
72266
72608
|
const result = await startDetachedRuntime({
|
|
72267
72609
|
scriptPath: fileURLToPath4(import.meta.url),
|
|
72268
72610
|
configPath: state.configResult.configPath,
|
|
72269
|
-
extraEnv: runtimeStatus.running ?
|
|
72611
|
+
extraEnv: restartForLiteralBootstrap || !runtimeStatus.running ? runtimeMemEnv : undefined,
|
|
72270
72612
|
runtimeCredentialsPath: getDefaultRuntimeCredentialsPath()
|
|
72271
72613
|
});
|
|
72272
72614
|
if (result.alreadyRunning) {
|
|
@@ -72284,6 +72626,7 @@ async function start(args = []) {
|
|
|
72284
72626
|
console.log(`config: ${result.configPath}`);
|
|
72285
72627
|
console.log(`log: ${result.logPath}`);
|
|
72286
72628
|
console.log(renderStartSummary(summary));
|
|
72629
|
+
printCommandOutcomeFooter("success");
|
|
72287
72630
|
} catch (error) {
|
|
72288
72631
|
printCommandOutcomeBanner("success");
|
|
72289
72632
|
console.log(`clisbot is already running with pid: ${result.pid}`);
|
|
@@ -72294,6 +72637,7 @@ async function start(args = []) {
|
|
|
72294
72637
|
for (const line of renderRuntimeErrorLines("failed to render already-running summary", error)) {
|
|
72295
72638
|
console.error(line);
|
|
72296
72639
|
}
|
|
72640
|
+
printCommandOutcomeFooter("success");
|
|
72297
72641
|
}
|
|
72298
72642
|
return;
|
|
72299
72643
|
}
|
|
@@ -72314,6 +72658,7 @@ async function start(args = []) {
|
|
|
72314
72658
|
console.log(`config: ${result.configPath}`);
|
|
72315
72659
|
console.log(`log: ${result.logPath}`);
|
|
72316
72660
|
console.log(renderStartSummary(summary));
|
|
72661
|
+
printCommandOutcomeFooter("success");
|
|
72317
72662
|
} catch (error) {
|
|
72318
72663
|
printCommandOutcomeBanner("success");
|
|
72319
72664
|
console.log(`clisbot started with pid: ${result.pid}`);
|
|
@@ -72322,6 +72667,7 @@ async function start(args = []) {
|
|
|
72322
72667
|
for (const line of renderRuntimeErrorLines("failed to render start summary", error)) {
|
|
72323
72668
|
console.error(line);
|
|
72324
72669
|
}
|
|
72670
|
+
printCommandOutcomeFooter("success");
|
|
72325
72671
|
}
|
|
72326
72672
|
}
|
|
72327
72673
|
async function printCliError(error) {
|
|
@@ -72363,15 +72709,18 @@ async function stop(hard = false) {
|
|
|
72363
72709
|
if (!result.stopped && !hard) {
|
|
72364
72710
|
printCommandOutcomeBanner("failure");
|
|
72365
72711
|
console.log("clisbot is not running");
|
|
72712
|
+
printCommandOutcomeFooter("failure");
|
|
72366
72713
|
return;
|
|
72367
72714
|
}
|
|
72368
72715
|
if (hard) {
|
|
72369
72716
|
printCommandOutcomeBanner("success");
|
|
72370
72717
|
console.log(result.stopped ? "clisbot stopped and tmux sessions cleaned up" : "clisbot was not running, but tmux sessions were cleaned up");
|
|
72718
|
+
printCommandOutcomeFooter("success");
|
|
72371
72719
|
return;
|
|
72372
72720
|
}
|
|
72373
72721
|
printCommandOutcomeBanner("success");
|
|
72374
72722
|
console.log("clisbot stopped");
|
|
72723
|
+
printCommandOutcomeFooter("success");
|
|
72375
72724
|
}
|
|
72376
72725
|
async function restart() {
|
|
72377
72726
|
await stopDetachedRuntime({
|