clisbot 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -20
- package/config/clisbot.json.template +8 -0
- package/dist/main.js +997 -108
- package/package.json +1 -1
- package/templates/slack/default/app-manifest.json +2 -3
package/dist/main.js
CHANGED
|
@@ -54471,14 +54471,22 @@ function renderPairingSetupHelpLines(prefix = "", options = {}) {
|
|
|
54471
54471
|
return lines;
|
|
54472
54472
|
}
|
|
54473
54473
|
lines.push(`${prefix}Pairing notes:`);
|
|
54474
|
+
if (shouldRenderSlack && shouldRenderTelegram) {
|
|
54475
|
+
lines.push(`${prefix} - Send a direct message (DM) to the Telegram or Slack bot. Send \`/start\` or \`hi\` to receive a pairing code.`);
|
|
54476
|
+
}
|
|
54474
54477
|
if (shouldRenderTelegram) {
|
|
54475
|
-
|
|
54478
|
+
if (!shouldRenderSlack) {
|
|
54479
|
+
lines.push(`${prefix} - Send a direct message (DM) to the Telegram bot. Send \`/start\` or \`hi\` to receive a pairing code.`);
|
|
54480
|
+
}
|
|
54476
54481
|
lines.push(`${prefix} - Approve the returned Telegram code with: \`clisbot pairing approve telegram <code>\``);
|
|
54477
54482
|
}
|
|
54478
54483
|
if (shouldRenderSlack) {
|
|
54479
|
-
|
|
54484
|
+
if (!shouldRenderTelegram) {
|
|
54485
|
+
lines.push(`${prefix} - Send a direct message (DM) to the Slack bot. Say \`hi\` to receive a pairing code.`);
|
|
54486
|
+
}
|
|
54480
54487
|
lines.push(`${prefix} - Approve the returned Slack code with: \`clisbot pairing approve slack <code>\``);
|
|
54481
54488
|
}
|
|
54489
|
+
lines.push(`${prefix} - Configured app owner/admin principals bypass pairing in DMs.`);
|
|
54482
54490
|
return lines;
|
|
54483
54491
|
}
|
|
54484
54492
|
function renderTmuxDebugHelpLines(prefix = "") {
|
|
@@ -54585,6 +54593,12 @@ function parseCliArgs(argv) {
|
|
|
54585
54593
|
args: args.slice(1)
|
|
54586
54594
|
};
|
|
54587
54595
|
}
|
|
54596
|
+
if (command === "auth") {
|
|
54597
|
+
return {
|
|
54598
|
+
name: "auth",
|
|
54599
|
+
args: args.slice(1)
|
|
54600
|
+
};
|
|
54601
|
+
}
|
|
54588
54602
|
if (command === "pairing") {
|
|
54589
54603
|
return {
|
|
54590
54604
|
name: "pairing",
|
|
@@ -54607,6 +54621,10 @@ function renderCliHelp() {
|
|
|
54607
54621
|
return [
|
|
54608
54622
|
`clisbot v${getClisbotVersion()}`,
|
|
54609
54623
|
"",
|
|
54624
|
+
"Platform support:",
|
|
54625
|
+
" Linux/macOS Supported.",
|
|
54626
|
+
" Windows Native Windows is not supported yet. Use WSL2.",
|
|
54627
|
+
"",
|
|
54610
54628
|
"Fastest start:",
|
|
54611
54629
|
" 1. Choose the channels you want to bootstrap explicitly.",
|
|
54612
54630
|
" 2. Run one of these commands:",
|
|
@@ -54639,6 +54657,7 @@ function renderCliHelp() {
|
|
|
54639
54657
|
" clisbot loops <subcommand>",
|
|
54640
54658
|
" clisbot message <subcommand>",
|
|
54641
54659
|
" clisbot agents <subcommand>",
|
|
54660
|
+
" clisbot auth <subcommand>",
|
|
54642
54661
|
" clisbot pairing <subcommand>",
|
|
54643
54662
|
" clisbot init [--cli <codex|claude|gemini>] [--bot-type <personal|team>] [--persist]",
|
|
54644
54663
|
" [--slack-account <id> --slack-app-token <ENV_NAME|${ENV_NAME}|literal> --slack-bot-token <ENV_NAME|${ENV_NAME}|literal>]...",
|
|
@@ -54675,6 +54694,7 @@ function renderCliHelp() {
|
|
|
54675
54694
|
" cancel --all",
|
|
54676
54695
|
" message Run provider message actions such as send, react, read, edit, delete, and pins.",
|
|
54677
54696
|
" agents Manage configured agents and top-level bindings.",
|
|
54697
|
+
" auth Manage app and agent auth roles, principals, and permissions in config. See `clisbot auth --help`.",
|
|
54678
54698
|
" pairing Run the pairing control CLI.",
|
|
54679
54699
|
` init Seed ${configPath} and optionally create the first agent without starting clisbot.`,
|
|
54680
54700
|
" --version, -v Show the installed clisbot version.",
|
|
@@ -59856,6 +59876,10 @@ var authRoleSchema = exports_external.object({
|
|
|
59856
59876
|
allow: exports_external.array(exports_external.string().min(1)).default([]),
|
|
59857
59877
|
users: exports_external.array(exports_external.string().min(1)).default([])
|
|
59858
59878
|
});
|
|
59879
|
+
var authRoleOverrideSchema = exports_external.object({
|
|
59880
|
+
allow: exports_external.array(exports_external.string().min(1)).optional(),
|
|
59881
|
+
users: exports_external.array(exports_external.string().min(1)).optional()
|
|
59882
|
+
});
|
|
59859
59883
|
var appAuthSchema = exports_external.object({
|
|
59860
59884
|
ownerClaimWindowMinutes: exports_external.number().int().positive().default(30),
|
|
59861
59885
|
defaultRole: exports_external.string().min(1).default("member"),
|
|
@@ -59887,11 +59911,15 @@ var agentAuthSchema = exports_external.object({
|
|
|
59887
59911
|
}
|
|
59888
59912
|
})
|
|
59889
59913
|
});
|
|
59914
|
+
var agentAuthOverrideSchema = exports_external.object({
|
|
59915
|
+
defaultRole: exports_external.string().min(1).optional(),
|
|
59916
|
+
roles: exports_external.record(exports_external.string(), authRoleOverrideSchema).default({})
|
|
59917
|
+
});
|
|
59890
59918
|
var agentOverrideSchema = exports_external.object({
|
|
59891
59919
|
workspace: exports_external.string().optional(),
|
|
59892
59920
|
responseMode: exports_external.enum(["capture-pane", "message-tool"]).optional(),
|
|
59893
59921
|
additionalMessageMode: exports_external.enum(["queue", "steer"]).optional(),
|
|
59894
|
-
auth:
|
|
59922
|
+
auth: agentAuthOverrideSchema.optional(),
|
|
59895
59923
|
runner: runnerOverrideSchema.optional(),
|
|
59896
59924
|
stream: streamSchema.partial().optional(),
|
|
59897
59925
|
session: sessionSchema.partial().optional()
|
|
@@ -59986,9 +60014,18 @@ var channelAgentPromptSchema = exports_external.object({
|
|
|
59986
60014
|
var channelResponseModeSchema = exports_external.enum(["capture-pane", "message-tool"]);
|
|
59987
60015
|
var channelAdditionalMessageModeSchema = exports_external.enum(["queue", "steer"]);
|
|
59988
60016
|
var channelVerboseSchema = exports_external.enum(["off", "minimal"]);
|
|
60017
|
+
var surfaceNotificationModeSchema = exports_external.enum(["none", "brief", "full"]);
|
|
59989
60018
|
var timezoneSchema = exports_external.string().refine(isValidLoopTimezone, {
|
|
59990
60019
|
message: "Expected a valid IANA timezone such as Asia/Ho_Chi_Minh"
|
|
59991
60020
|
});
|
|
60021
|
+
var surfaceNotificationsSchema = exports_external.object({
|
|
60022
|
+
queueStart: surfaceNotificationModeSchema.default("brief"),
|
|
60023
|
+
loopStart: surfaceNotificationModeSchema.default("brief")
|
|
60024
|
+
});
|
|
60025
|
+
var surfaceNotificationsOverrideSchema = exports_external.object({
|
|
60026
|
+
queueStart: surfaceNotificationModeSchema.optional(),
|
|
60027
|
+
loopStart: surfaceNotificationModeSchema.optional()
|
|
60028
|
+
});
|
|
59992
60029
|
var slackRouteSchema = exports_external.object({
|
|
59993
60030
|
requireMention: exports_external.boolean().default(true),
|
|
59994
60031
|
allowBots: exports_external.boolean().default(false),
|
|
@@ -59999,6 +60036,7 @@ var slackRouteSchema = exports_external.object({
|
|
|
59999
60036
|
response: slackResponseSchema.optional(),
|
|
60000
60037
|
responseMode: channelResponseModeSchema.optional(),
|
|
60001
60038
|
additionalMessageMode: channelAdditionalMessageModeSchema.optional(),
|
|
60039
|
+
surfaceNotifications: surfaceNotificationsOverrideSchema.optional(),
|
|
60002
60040
|
verbose: channelVerboseSchema.optional(),
|
|
60003
60041
|
followUp: slackFollowUpOverrideSchema.optional(),
|
|
60004
60042
|
timezone: timezoneSchema.optional()
|
|
@@ -60013,6 +60051,7 @@ var telegramTopicRouteSchema = exports_external.object({
|
|
|
60013
60051
|
response: slackResponseSchema.optional(),
|
|
60014
60052
|
responseMode: channelResponseModeSchema.optional(),
|
|
60015
60053
|
additionalMessageMode: channelAdditionalMessageModeSchema.optional(),
|
|
60054
|
+
surfaceNotifications: surfaceNotificationsOverrideSchema.optional(),
|
|
60016
60055
|
verbose: channelVerboseSchema.optional(),
|
|
60017
60056
|
followUp: slackFollowUpOverrideSchema.optional(),
|
|
60018
60057
|
timezone: timezoneSchema.optional()
|
|
@@ -60027,6 +60066,7 @@ var telegramGroupRouteSchema = exports_external.object({
|
|
|
60027
60066
|
response: slackResponseSchema.optional(),
|
|
60028
60067
|
responseMode: channelResponseModeSchema.optional(),
|
|
60029
60068
|
additionalMessageMode: channelAdditionalMessageModeSchema.optional(),
|
|
60069
|
+
surfaceNotifications: surfaceNotificationsOverrideSchema.optional(),
|
|
60030
60070
|
verbose: channelVerboseSchema.optional(),
|
|
60031
60071
|
followUp: slackFollowUpOverrideSchema.optional(),
|
|
60032
60072
|
timezone: timezoneSchema.optional(),
|
|
@@ -60045,6 +60085,7 @@ var telegramDirectMessagesSchema = exports_external.object({
|
|
|
60045
60085
|
response: slackResponseSchema.optional(),
|
|
60046
60086
|
responseMode: channelResponseModeSchema.optional(),
|
|
60047
60087
|
additionalMessageMode: channelAdditionalMessageModeSchema.optional(),
|
|
60088
|
+
surfaceNotifications: surfaceNotificationsOverrideSchema.optional(),
|
|
60048
60089
|
verbose: channelVerboseSchema.optional(),
|
|
60049
60090
|
followUp: slackFollowUpOverrideSchema.optional(),
|
|
60050
60091
|
timezone: timezoneSchema.optional()
|
|
@@ -60082,6 +60123,7 @@ var telegramSchema = exports_external.object({
|
|
|
60082
60123
|
response: slackResponseSchema.default("final"),
|
|
60083
60124
|
responseMode: channelResponseModeSchema.default("message-tool"),
|
|
60084
60125
|
additionalMessageMode: channelAdditionalMessageModeSchema.default("steer"),
|
|
60126
|
+
surfaceNotifications: surfaceNotificationsSchema.optional(),
|
|
60085
60127
|
verbose: channelVerboseSchema.default("minimal"),
|
|
60086
60128
|
followUp: slackFollowUpSchema.default({
|
|
60087
60129
|
mode: "auto",
|
|
@@ -60113,6 +60155,7 @@ var directMessagesSchema = exports_external.object({
|
|
|
60113
60155
|
response: slackResponseSchema.optional(),
|
|
60114
60156
|
responseMode: channelResponseModeSchema.optional(),
|
|
60115
60157
|
additionalMessageMode: channelAdditionalMessageModeSchema.optional(),
|
|
60158
|
+
surfaceNotifications: surfaceNotificationsOverrideSchema.optional(),
|
|
60116
60159
|
verbose: channelVerboseSchema.optional(),
|
|
60117
60160
|
followUp: slackFollowUpOverrideSchema.optional(),
|
|
60118
60161
|
timezone: timezoneSchema.optional()
|
|
@@ -60157,6 +60200,7 @@ var slackSchema = exports_external.object({
|
|
|
60157
60200
|
response: slackResponseSchema.default("final"),
|
|
60158
60201
|
responseMode: channelResponseModeSchema.default("message-tool"),
|
|
60159
60202
|
additionalMessageMode: channelAdditionalMessageModeSchema.default("steer"),
|
|
60203
|
+
surfaceNotifications: surfaceNotificationsSchema.optional(),
|
|
60160
60204
|
verbose: channelVerboseSchema.default("minimal"),
|
|
60161
60205
|
followUp: slackFollowUpSchema.default({
|
|
60162
60206
|
mode: "auto",
|
|
@@ -60308,6 +60352,10 @@ var clisbotConfigSchema = exports_external.object({
|
|
|
60308
60352
|
response: "final",
|
|
60309
60353
|
responseMode: "message-tool",
|
|
60310
60354
|
additionalMessageMode: "steer",
|
|
60355
|
+
surfaceNotifications: {
|
|
60356
|
+
queueStart: "brief",
|
|
60357
|
+
loopStart: "brief"
|
|
60358
|
+
},
|
|
60311
60359
|
verbose: "minimal",
|
|
60312
60360
|
followUp: {
|
|
60313
60361
|
mode: "auto",
|
|
@@ -60625,6 +60673,10 @@ function renderDefaultConfigTemplate(options = {}) {
|
|
|
60625
60673
|
response: "final",
|
|
60626
60674
|
responseMode: "message-tool",
|
|
60627
60675
|
additionalMessageMode: "steer",
|
|
60676
|
+
surfaceNotifications: {
|
|
60677
|
+
queueStart: "brief",
|
|
60678
|
+
loopStart: "brief"
|
|
60679
|
+
},
|
|
60628
60680
|
verbose: "minimal",
|
|
60629
60681
|
followUp: {
|
|
60630
60682
|
mode: "auto",
|
|
@@ -60666,6 +60718,10 @@ function renderDefaultConfigTemplate(options = {}) {
|
|
|
60666
60718
|
response: "final",
|
|
60667
60719
|
responseMode: "message-tool",
|
|
60668
60720
|
additionalMessageMode: "steer",
|
|
60721
|
+
surfaceNotifications: {
|
|
60722
|
+
queueStart: "brief",
|
|
60723
|
+
loopStart: "brief"
|
|
60724
|
+
},
|
|
60669
60725
|
verbose: "minimal",
|
|
60670
60726
|
followUp: {
|
|
60671
60727
|
mode: "auto",
|
|
@@ -62705,40 +62761,329 @@ async function runAccountsCli(args, deps = {}) {
|
|
|
62705
62761
|
throw new Error(renderAccountsHelp());
|
|
62706
62762
|
}
|
|
62707
62763
|
|
|
62708
|
-
// src/
|
|
62709
|
-
function
|
|
62710
|
-
|
|
62711
|
-
|
|
62712
|
-
|
|
62713
|
-
|
|
62764
|
+
// src/control/auth-cli.ts
|
|
62765
|
+
function getEditableConfigPath3() {
|
|
62766
|
+
return process.env.CLISBOT_CONFIG_PATH;
|
|
62767
|
+
}
|
|
62768
|
+
function parseRepeatedOption2(args, name) {
|
|
62769
|
+
const values = [];
|
|
62770
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
62771
|
+
if (args[index] !== name) {
|
|
62772
|
+
continue;
|
|
62773
|
+
}
|
|
62774
|
+
const value = args[index + 1]?.trim();
|
|
62775
|
+
if (!value) {
|
|
62776
|
+
throw new Error(`Missing value for ${name}`);
|
|
62777
|
+
}
|
|
62778
|
+
values.push(value);
|
|
62779
|
+
}
|
|
62780
|
+
return values;
|
|
62781
|
+
}
|
|
62782
|
+
function parseSingleOption2(args, name) {
|
|
62783
|
+
const values = parseRepeatedOption2(args, name);
|
|
62784
|
+
if (values.length === 0) {
|
|
62785
|
+
return;
|
|
62786
|
+
}
|
|
62787
|
+
return values[values.length - 1];
|
|
62788
|
+
}
|
|
62789
|
+
function hasFlag3(args, name) {
|
|
62790
|
+
return args.includes(name);
|
|
62791
|
+
}
|
|
62792
|
+
function parseScope(raw, args) {
|
|
62793
|
+
if (raw === "app") {
|
|
62794
|
+
return { kind: "app" };
|
|
62795
|
+
}
|
|
62796
|
+
if (raw === "agent-defaults") {
|
|
62797
|
+
return { kind: "agent-defaults" };
|
|
62798
|
+
}
|
|
62799
|
+
if (raw === "agent") {
|
|
62800
|
+
const agentId = parseSingleOption2(args, "--agent");
|
|
62801
|
+
if (!agentId) {
|
|
62802
|
+
throw new Error("Missing value for --agent");
|
|
62803
|
+
}
|
|
62804
|
+
return { kind: "agent", agentId };
|
|
62805
|
+
}
|
|
62806
|
+
throw new Error("Scope required: app | agent-defaults | agent");
|
|
62807
|
+
}
|
|
62808
|
+
function renderAuthCliHelp() {
|
|
62809
|
+
return [
|
|
62810
|
+
"clisbot auth",
|
|
62714
62811
|
"",
|
|
62715
|
-
"
|
|
62812
|
+
"Manage auth roles, principals, and permissions in config.",
|
|
62716
62813
|
"",
|
|
62717
|
-
"
|
|
62718
|
-
|
|
62814
|
+
"Usage:",
|
|
62815
|
+
" clisbot auth list [--json]",
|
|
62816
|
+
" clisbot auth show <app|agent-defaults|agent> [--agent <id>] [--json]",
|
|
62817
|
+
" clisbot auth add-user <app|agent-defaults|agent> --role <role> --user <principal> [--agent <id>]",
|
|
62818
|
+
" clisbot auth remove-user <app|agent-defaults|agent> --role <role> --user <principal> [--agent <id>]",
|
|
62819
|
+
" clisbot auth add-permission <app|agent-defaults|agent> --role <role> --permission <permission> [--agent <id>]",
|
|
62820
|
+
" clisbot auth remove-permission <app|agent-defaults|agent> --role <role> --permission <permission> [--agent <id>]",
|
|
62719
62821
|
"",
|
|
62720
|
-
"
|
|
62721
|
-
|
|
62722
|
-
|
|
62723
|
-
|
|
62724
|
-
|
|
62822
|
+
"Scopes:",
|
|
62823
|
+
" app edit app.auth",
|
|
62824
|
+
" agent-defaults edit agents.defaults.auth",
|
|
62825
|
+
" agent edit one agents.list[].auth override; requires --agent <id>",
|
|
62826
|
+
"",
|
|
62827
|
+
"Permission sets:",
|
|
62828
|
+
` app ${APP_ADMIN_PERMISSIONS.join(", ")}`,
|
|
62829
|
+
` agent ${DEFAULT_AGENT_ADMIN_PERMISSIONS.join(", ")}`,
|
|
62830
|
+
"",
|
|
62831
|
+
"Notes:",
|
|
62832
|
+
" add-user/remove-user mutate roles.<role>.users",
|
|
62833
|
+
" add-permission/remove-permission mutate roles.<role>.allow",
|
|
62834
|
+
" agent role edits clone the inherited agent-defaults role into the target agent override on first write",
|
|
62835
|
+
"",
|
|
62836
|
+
"Examples:",
|
|
62837
|
+
" clisbot auth add-user app --role owner --user telegram:1276408333",
|
|
62838
|
+
" clisbot auth remove-user app --role admin --user slack:U123",
|
|
62839
|
+
" clisbot auth add-user agent --agent default --role admin --user slack:U123",
|
|
62840
|
+
" clisbot auth add-permission agent-defaults --role member --permission shellExecute",
|
|
62841
|
+
" clisbot auth remove-permission agent --agent default --role member --permission shellExecute",
|
|
62842
|
+
" clisbot auth show agent-defaults",
|
|
62843
|
+
" clisbot auth list --json"
|
|
62844
|
+
].join(`
|
|
62845
|
+
`);
|
|
62846
|
+
}
|
|
62847
|
+
function cloneRoleDefinition(value) {
|
|
62848
|
+
return {
|
|
62849
|
+
allow: [...value?.allow ?? []],
|
|
62850
|
+
users: [...value?.users ?? []]
|
|
62851
|
+
};
|
|
62852
|
+
}
|
|
62853
|
+
function mergeRoleDefinitions(inherited, override) {
|
|
62854
|
+
return {
|
|
62855
|
+
allow: [...override?.allow ?? inherited?.allow ?? []],
|
|
62856
|
+
users: [...override?.users ?? inherited?.users ?? []]
|
|
62857
|
+
};
|
|
62858
|
+
}
|
|
62859
|
+
function mergeRoleRecord(defaults, overrides) {
|
|
62860
|
+
const merged = {};
|
|
62861
|
+
const roleNames = new Set([
|
|
62862
|
+
...Object.keys(defaults ?? {}),
|
|
62863
|
+
...Object.keys(overrides ?? {})
|
|
62864
|
+
]);
|
|
62865
|
+
for (const roleName of roleNames) {
|
|
62866
|
+
merged[roleName] = mergeRoleDefinitions(defaults?.[roleName], overrides?.[roleName]);
|
|
62725
62867
|
}
|
|
62726
|
-
|
|
62727
|
-
|
|
62728
|
-
|
|
62729
|
-
|
|
62868
|
+
return merged;
|
|
62869
|
+
}
|
|
62870
|
+
function normalizeUnique(values) {
|
|
62871
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort();
|
|
62872
|
+
}
|
|
62873
|
+
function ensureAgentEntry(config, agentId) {
|
|
62874
|
+
const entry = config.agents.list.find((item) => item.id === agentId);
|
|
62875
|
+
if (!entry) {
|
|
62876
|
+
throw new Error(`Unknown agent: ${agentId}`);
|
|
62730
62877
|
}
|
|
62731
|
-
return
|
|
62732
|
-
|
|
62878
|
+
return entry;
|
|
62879
|
+
}
|
|
62880
|
+
function getAuthLabel(scope) {
|
|
62881
|
+
if (scope.kind === "app") {
|
|
62882
|
+
return "app.auth";
|
|
62883
|
+
}
|
|
62884
|
+
if (scope.kind === "agent-defaults") {
|
|
62885
|
+
return "agents.defaults.auth";
|
|
62886
|
+
}
|
|
62887
|
+
return `agents.list[${scope.agentId}].auth`;
|
|
62888
|
+
}
|
|
62889
|
+
function ensureEditableRoleDefinition(role) {
|
|
62890
|
+
role.allow = role.allow ?? [];
|
|
62891
|
+
role.users = role.users ?? [];
|
|
62892
|
+
return role;
|
|
62893
|
+
}
|
|
62894
|
+
function resolveAppRole(config, roleName) {
|
|
62895
|
+
const role = config.app.auth.roles[roleName];
|
|
62896
|
+
if (!role) {
|
|
62897
|
+
throw new Error(`Unknown app role: ${roleName}`);
|
|
62898
|
+
}
|
|
62899
|
+
return ensureEditableRoleDefinition(role);
|
|
62900
|
+
}
|
|
62901
|
+
function resolveAgentDefaultsRole(config, roleName) {
|
|
62902
|
+
const role = config.agents.defaults.auth.roles[roleName];
|
|
62903
|
+
if (!role) {
|
|
62904
|
+
throw new Error(`Unknown agent-defaults role: ${roleName}`);
|
|
62905
|
+
}
|
|
62906
|
+
return ensureEditableRoleDefinition(role);
|
|
62907
|
+
}
|
|
62908
|
+
function ensureAgentOverrideAuth(entry, config) {
|
|
62909
|
+
if (!entry.auth) {
|
|
62910
|
+
entry.auth = {
|
|
62911
|
+
defaultRole: config.agents.defaults.auth.defaultRole,
|
|
62912
|
+
roles: {}
|
|
62913
|
+
};
|
|
62914
|
+
}
|
|
62915
|
+
return entry.auth;
|
|
62916
|
+
}
|
|
62917
|
+
function resolveAgentRoleForEdit(config, agentId, roleName) {
|
|
62918
|
+
const entry = ensureAgentEntry(config, agentId);
|
|
62919
|
+
const explicitRole = entry.auth?.roles?.[roleName];
|
|
62920
|
+
if (explicitRole) {
|
|
62921
|
+
return ensureEditableRoleDefinition(explicitRole);
|
|
62922
|
+
}
|
|
62923
|
+
const inheritedRole = config.agents.defaults.auth.roles[roleName];
|
|
62924
|
+
if (!inheritedRole) {
|
|
62925
|
+
throw new Error(`Unknown agent role: ${roleName}`);
|
|
62926
|
+
}
|
|
62927
|
+
const auth = ensureAgentOverrideAuth(entry, config);
|
|
62928
|
+
auth.roles[roleName] = cloneRoleDefinition(inheritedRole);
|
|
62929
|
+
return ensureEditableRoleDefinition(auth.roles[roleName]);
|
|
62930
|
+
}
|
|
62931
|
+
function resolveRoleForEdit(config, scope, roleName) {
|
|
62932
|
+
if (scope.kind === "app") {
|
|
62933
|
+
return resolveAppRole(config, roleName);
|
|
62934
|
+
}
|
|
62935
|
+
if (scope.kind === "agent-defaults") {
|
|
62936
|
+
return resolveAgentDefaultsRole(config, roleName);
|
|
62937
|
+
}
|
|
62938
|
+
return resolveAgentRoleForEdit(config, scope.agentId, roleName);
|
|
62939
|
+
}
|
|
62940
|
+
function validatePermission(scope, permission) {
|
|
62941
|
+
const trimmed = permission.trim();
|
|
62942
|
+
if (!trimmed) {
|
|
62943
|
+
throw new Error("Missing value for --permission");
|
|
62944
|
+
}
|
|
62945
|
+
const allowedPermissions = new Set(scope.kind === "app" ? APP_ADMIN_PERMISSIONS : DEFAULT_AGENT_ADMIN_PERMISSIONS);
|
|
62946
|
+
if (!allowedPermissions.has(trimmed)) {
|
|
62947
|
+
const sorted = [...allowedPermissions].sort().join(", ");
|
|
62948
|
+
throw new Error(`Unknown permission for ${scope.kind}: ${trimmed}. Allowed: ${sorted}`);
|
|
62949
|
+
}
|
|
62950
|
+
return trimmed;
|
|
62951
|
+
}
|
|
62952
|
+
function buildShowPayload(config, scope) {
|
|
62953
|
+
if (scope.kind === "app") {
|
|
62954
|
+
return config.app.auth;
|
|
62955
|
+
}
|
|
62956
|
+
if (scope.kind === "agent-defaults") {
|
|
62957
|
+
return config.agents.defaults.auth;
|
|
62958
|
+
}
|
|
62959
|
+
const entry = ensureAgentEntry(config, scope.agentId);
|
|
62960
|
+
return {
|
|
62961
|
+
defaultRole: entry.auth?.defaultRole ?? config.agents.defaults.auth.defaultRole,
|
|
62962
|
+
roles: mergeRoleRecord(config.agents.defaults.auth.roles, entry.auth?.roles)
|
|
62963
|
+
};
|
|
62964
|
+
}
|
|
62965
|
+
async function listAuth(args) {
|
|
62966
|
+
const { config } = await readEditableConfig(getEditableConfigPath3());
|
|
62967
|
+
const payload = {
|
|
62968
|
+
app: config.app.auth,
|
|
62969
|
+
agentDefaults: config.agents.defaults.auth,
|
|
62970
|
+
agents: config.agents.list.map((entry) => ({
|
|
62971
|
+
agentId: entry.id,
|
|
62972
|
+
auth: buildShowPayload(config, { kind: "agent", agentId: entry.id })
|
|
62973
|
+
}))
|
|
62974
|
+
};
|
|
62975
|
+
if (hasFlag3(args, "--json")) {
|
|
62976
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
62977
|
+
return;
|
|
62978
|
+
}
|
|
62979
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
62980
|
+
}
|
|
62981
|
+
async function showAuth(args) {
|
|
62982
|
+
const scope = parseScope(args[0], args.slice(1));
|
|
62983
|
+
const { config } = await readEditableConfig(getEditableConfigPath3());
|
|
62984
|
+
const payload = buildShowPayload(config, scope);
|
|
62985
|
+
if (hasFlag3(args, "--json")) {
|
|
62986
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
62987
|
+
return;
|
|
62988
|
+
}
|
|
62989
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
62990
|
+
}
|
|
62991
|
+
async function mutateUsers(mode, args) {
|
|
62992
|
+
const scope = parseScope(args[0], args.slice(1));
|
|
62993
|
+
const roleName = parseSingleOption2(args, "--role");
|
|
62994
|
+
const principal = parseSingleOption2(args, "--user")?.trim();
|
|
62995
|
+
if (!roleName) {
|
|
62996
|
+
throw new Error("Missing value for --role");
|
|
62997
|
+
}
|
|
62998
|
+
if (!principal) {
|
|
62999
|
+
throw new Error("Missing value for --user");
|
|
63000
|
+
}
|
|
63001
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath3());
|
|
63002
|
+
const role = resolveRoleForEdit(config, scope, roleName);
|
|
63003
|
+
role.users = normalizeUnique(mode === "add" ? [...role.users, principal] : role.users.filter((value) => value !== principal));
|
|
63004
|
+
await writeEditableConfig(configPath, config);
|
|
63005
|
+
console.log(`${mode === "add" ? "Added" : "Removed"} user ${principal} ${mode === "add" ? "to" : "from"} ${getAuthLabel(scope)} role ${roleName}.`);
|
|
63006
|
+
}
|
|
63007
|
+
async function mutatePermissions(mode, args) {
|
|
63008
|
+
const scope = parseScope(args[0], args.slice(1));
|
|
63009
|
+
const roleName = parseSingleOption2(args, "--role");
|
|
63010
|
+
const permission = validatePermission(scope, parseSingleOption2(args, "--permission") ?? "");
|
|
63011
|
+
if (!roleName) {
|
|
63012
|
+
throw new Error("Missing value for --role");
|
|
63013
|
+
}
|
|
63014
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath3());
|
|
63015
|
+
const role = resolveRoleForEdit(config, scope, roleName);
|
|
63016
|
+
role.allow = normalizeUnique(mode === "add" ? [...role.allow, permission] : role.allow.filter((value) => value !== permission));
|
|
63017
|
+
await writeEditableConfig(configPath, config);
|
|
63018
|
+
console.log(`${mode === "add" ? "Added" : "Removed"} permission ${permission} ${mode === "add" ? "to" : "from"} ${getAuthLabel(scope)} role ${roleName}.`);
|
|
63019
|
+
}
|
|
63020
|
+
async function runAuthCli(args) {
|
|
63021
|
+
const [command, ...rest] = args;
|
|
63022
|
+
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
63023
|
+
console.log(renderAuthCliHelp());
|
|
63024
|
+
return;
|
|
63025
|
+
}
|
|
63026
|
+
if (command === "list") {
|
|
63027
|
+
await listAuth(rest);
|
|
63028
|
+
return;
|
|
63029
|
+
}
|
|
63030
|
+
if (command === "show") {
|
|
63031
|
+
await showAuth(rest);
|
|
63032
|
+
return;
|
|
63033
|
+
}
|
|
63034
|
+
if (command === "add-user") {
|
|
63035
|
+
await mutateUsers("add", rest);
|
|
63036
|
+
return;
|
|
63037
|
+
}
|
|
63038
|
+
if (command === "remove-user") {
|
|
63039
|
+
await mutateUsers("remove", rest);
|
|
63040
|
+
return;
|
|
63041
|
+
}
|
|
63042
|
+
if (command === "add-permission") {
|
|
63043
|
+
await mutatePermissions("add", rest);
|
|
63044
|
+
return;
|
|
63045
|
+
}
|
|
63046
|
+
if (command === "remove-permission") {
|
|
63047
|
+
await mutatePermissions("remove", rest);
|
|
63048
|
+
return;
|
|
63049
|
+
}
|
|
63050
|
+
throw new Error(renderAuthCliHelp());
|
|
62733
63051
|
}
|
|
62734
63052
|
|
|
62735
63053
|
// src/channels/mode-config-shared.ts
|
|
63054
|
+
function createTelegramGroupRoute() {
|
|
63055
|
+
return {
|
|
63056
|
+
requireMention: true,
|
|
63057
|
+
allowBots: false,
|
|
63058
|
+
topics: {}
|
|
63059
|
+
};
|
|
63060
|
+
}
|
|
63061
|
+
function ensureTelegramGroupRoute(config, chatId) {
|
|
63062
|
+
const existing = config.channels.telegram.groups[chatId];
|
|
63063
|
+
if (existing) {
|
|
63064
|
+
return existing;
|
|
63065
|
+
}
|
|
63066
|
+
const created = createTelegramGroupRoute();
|
|
63067
|
+
config.channels.telegram.groups[chatId] = created;
|
|
63068
|
+
return created;
|
|
63069
|
+
}
|
|
63070
|
+
function ensureTelegramTopicRoute(config, chatId, topicId) {
|
|
63071
|
+
const group = ensureTelegramGroupRoute(config, chatId);
|
|
63072
|
+
const existing = group.topics[topicId];
|
|
63073
|
+
if (existing) {
|
|
63074
|
+
return existing;
|
|
63075
|
+
}
|
|
63076
|
+
const created = {};
|
|
63077
|
+
group.topics[topicId] = created;
|
|
63078
|
+
return created;
|
|
63079
|
+
}
|
|
62736
63080
|
function getModeValue(source, field) {
|
|
62737
63081
|
return source[field];
|
|
62738
63082
|
}
|
|
62739
63083
|
function setModeValue(source, field, value) {
|
|
62740
63084
|
source[field] = value;
|
|
62741
63085
|
}
|
|
63086
|
+
var EMPTY_MODE_SOURCE = {};
|
|
62742
63087
|
function resolveSlackConfigTarget(config, field, params) {
|
|
62743
63088
|
if (!params.target) {
|
|
62744
63089
|
return {
|
|
@@ -62820,22 +63165,25 @@ function resolveTelegramConfigTarget(config, field, params) {
|
|
|
62820
63165
|
};
|
|
62821
63166
|
}
|
|
62822
63167
|
const group = config.channels.telegram.groups[chatId];
|
|
62823
|
-
if (!group) {
|
|
62824
|
-
throw new Error(renderTelegramRouteChoiceMessage({ chatId }));
|
|
62825
|
-
}
|
|
62826
63168
|
if (topicId) {
|
|
62827
|
-
const topic = group
|
|
62828
|
-
if (!topic) {
|
|
62829
|
-
throw new Error(renderTelegramRouteChoiceMessage({ chatId, topicId }));
|
|
62830
|
-
}
|
|
63169
|
+
const topic = group?.topics?.[topicId];
|
|
62831
63170
|
return {
|
|
62832
|
-
get: () => getModeValue(topic, field) ?? getModeValue(group, field) ?? getModeValue(config.channels.telegram, field),
|
|
63171
|
+
get: () => getModeValue(topic ?? EMPTY_MODE_SOURCE, field) ?? getModeValue(group ?? EMPTY_MODE_SOURCE, field) ?? getModeValue(config.channels.telegram, field),
|
|
62833
63172
|
set: (value) => {
|
|
62834
|
-
setModeValue(
|
|
63173
|
+
setModeValue(ensureTelegramTopicRoute(config, chatId, topicId), field, value);
|
|
62835
63174
|
},
|
|
62836
63175
|
label: `telegram topic ${chatId}/${topicId}`
|
|
62837
63176
|
};
|
|
62838
63177
|
}
|
|
63178
|
+
if (!group) {
|
|
63179
|
+
return {
|
|
63180
|
+
get: () => getModeValue(config.channels.telegram, field),
|
|
63181
|
+
set: (value) => {
|
|
63182
|
+
setModeValue(ensureTelegramGroupRoute(config, chatId), field, value);
|
|
63183
|
+
},
|
|
63184
|
+
label: `telegram group ${chatId}`
|
|
63185
|
+
};
|
|
63186
|
+
}
|
|
62839
63187
|
return {
|
|
62840
63188
|
get: () => getModeValue(group, field) ?? getModeValue(config.channels.telegram, field),
|
|
62841
63189
|
set: (value) => {
|
|
@@ -62876,11 +63224,11 @@ function renderFieldLabel(field) {
|
|
|
62876
63224
|
}
|
|
62877
63225
|
|
|
62878
63226
|
// src/channels/additional-message-mode-config.ts
|
|
62879
|
-
function
|
|
63227
|
+
function getEditableConfigPath4() {
|
|
62880
63228
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
62881
63229
|
}
|
|
62882
63230
|
async function getConversationAdditionalMessageMode(params) {
|
|
62883
|
-
const { config } = await readEditableConfig(
|
|
63231
|
+
const { config } = await readEditableConfig(getEditableConfigPath4());
|
|
62884
63232
|
const target = resolveConfiguredSurfaceModeTarget(config, "additionalMessageMode", buildConfiguredTargetFromIdentity(params.identity));
|
|
62885
63233
|
return {
|
|
62886
63234
|
label: target.label,
|
|
@@ -62888,7 +63236,7 @@ async function getConversationAdditionalMessageMode(params) {
|
|
|
62888
63236
|
};
|
|
62889
63237
|
}
|
|
62890
63238
|
async function setConversationAdditionalMessageMode(params) {
|
|
62891
|
-
const { config, configPath } = await readEditableConfig(
|
|
63239
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath4());
|
|
62892
63240
|
const target = resolveConfiguredSurfaceModeTarget(config, "additionalMessageMode", buildConfiguredTargetFromIdentity(params.identity));
|
|
62893
63241
|
target.set(params.additionalMessageMode);
|
|
62894
63242
|
await writeEditableConfig(configPath, config);
|
|
@@ -62899,7 +63247,7 @@ async function setConversationAdditionalMessageMode(params) {
|
|
|
62899
63247
|
};
|
|
62900
63248
|
}
|
|
62901
63249
|
async function getConfiguredAdditionalMessageMode(params) {
|
|
62902
|
-
const { config, configPath } = await readEditableConfig(
|
|
63250
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath4());
|
|
62903
63251
|
const target = resolveConfiguredSurfaceModeTarget(config, "additionalMessageMode", params);
|
|
62904
63252
|
return {
|
|
62905
63253
|
configPath,
|
|
@@ -62908,7 +63256,7 @@ async function getConfiguredAdditionalMessageMode(params) {
|
|
|
62908
63256
|
};
|
|
62909
63257
|
}
|
|
62910
63258
|
async function setConfiguredAdditionalMessageMode(params) {
|
|
62911
|
-
const { config, configPath } = await readEditableConfig(
|
|
63259
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath4());
|
|
62912
63260
|
const target = resolveConfiguredSurfaceModeTarget(config, "additionalMessageMode", params);
|
|
62913
63261
|
target.set(params.additionalMessageMode);
|
|
62914
63262
|
await writeEditableConfig(configPath, config);
|
|
@@ -62920,11 +63268,11 @@ async function setConfiguredAdditionalMessageMode(params) {
|
|
|
62920
63268
|
}
|
|
62921
63269
|
|
|
62922
63270
|
// src/channels/response-mode-config.ts
|
|
62923
|
-
function
|
|
63271
|
+
function getEditableConfigPath5() {
|
|
62924
63272
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
62925
63273
|
}
|
|
62926
63274
|
async function getConversationResponseMode(params) {
|
|
62927
|
-
const { config } = await readEditableConfig(
|
|
63275
|
+
const { config } = await readEditableConfig(getEditableConfigPath5());
|
|
62928
63276
|
const target = resolveConfiguredSurfaceModeTarget(config, "responseMode", buildConfiguredTargetFromIdentity(params.identity));
|
|
62929
63277
|
return {
|
|
62930
63278
|
label: target.label,
|
|
@@ -62932,7 +63280,7 @@ async function getConversationResponseMode(params) {
|
|
|
62932
63280
|
};
|
|
62933
63281
|
}
|
|
62934
63282
|
async function setConversationResponseMode(params) {
|
|
62935
|
-
const { config, configPath } = await readEditableConfig(
|
|
63283
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath5());
|
|
62936
63284
|
const target = resolveConfiguredSurfaceModeTarget(config, "responseMode", buildConfiguredTargetFromIdentity(params.identity));
|
|
62937
63285
|
target.set(params.responseMode);
|
|
62938
63286
|
await writeEditableConfig(configPath, config);
|
|
@@ -62943,7 +63291,7 @@ async function setConversationResponseMode(params) {
|
|
|
62943
63291
|
};
|
|
62944
63292
|
}
|
|
62945
63293
|
async function getConfiguredResponseMode(params) {
|
|
62946
|
-
const { config, configPath } = await readEditableConfig(
|
|
63294
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath5());
|
|
62947
63295
|
const target = resolveConfiguredSurfaceModeTarget(config, "responseMode", params);
|
|
62948
63296
|
return {
|
|
62949
63297
|
configPath,
|
|
@@ -62952,7 +63300,7 @@ async function getConfiguredResponseMode(params) {
|
|
|
62952
63300
|
};
|
|
62953
63301
|
}
|
|
62954
63302
|
async function setConfiguredResponseMode(params) {
|
|
62955
|
-
const { config, configPath } = await readEditableConfig(
|
|
63303
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath5());
|
|
62956
63304
|
const target = resolveConfiguredSurfaceModeTarget(config, "responseMode", params);
|
|
62957
63305
|
target.set(params.responseMode);
|
|
62958
63306
|
await writeEditableConfig(configPath, config);
|
|
@@ -62978,7 +63326,7 @@ async function runChannelPrivilegeCli(_args) {
|
|
|
62978
63326
|
|
|
62979
63327
|
// src/control/channels-cli.ts
|
|
62980
63328
|
var AUTH_USER_GUIDE_DOC_PATH = "docs/user-guide/auth-and-roles.md";
|
|
62981
|
-
function
|
|
63329
|
+
function getEditableConfigPath6() {
|
|
62982
63330
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
62983
63331
|
}
|
|
62984
63332
|
function renderChannelsHelp() {
|
|
@@ -63127,7 +63475,7 @@ function getAgentId(args) {
|
|
|
63127
63475
|
return parseOptionValue2(args, "--agent") ?? "default";
|
|
63128
63476
|
}
|
|
63129
63477
|
async function setChannelEnabled(action, channel) {
|
|
63130
|
-
const { config, configPath } = await readEditableConfig(
|
|
63478
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63131
63479
|
const enabled = action === "enable";
|
|
63132
63480
|
const current = config.channels[channel].enabled;
|
|
63133
63481
|
if (current === enabled) {
|
|
@@ -63147,7 +63495,7 @@ async function addTelegramGroup(args) {
|
|
|
63147
63495
|
if (!chatId) {
|
|
63148
63496
|
throw new Error("Usage: clisbot channels add telegram-group <chatId> [--topic <topicId>] [--agent <id>] [--require-mention true|false]");
|
|
63149
63497
|
}
|
|
63150
|
-
const { config, configPath } = await readEditableConfig(
|
|
63498
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63151
63499
|
const topicId = parseOptionValue2(args, "--topic");
|
|
63152
63500
|
const agentId = getAgentId(args);
|
|
63153
63501
|
const requireMention = parseBooleanOption(args, "--require-mention", true);
|
|
@@ -63200,7 +63548,7 @@ async function removeTelegramGroup(args) {
|
|
|
63200
63548
|
if (!chatId) {
|
|
63201
63549
|
throw new Error("Usage: clisbot channels remove telegram-group <chatId> [--topic <topicId>]");
|
|
63202
63550
|
}
|
|
63203
|
-
const { config, configPath } = await readEditableConfig(
|
|
63551
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63204
63552
|
const topicId = parseOptionValue2(args, "--topic");
|
|
63205
63553
|
const groupRoute = config.channels.telegram.groups[chatId];
|
|
63206
63554
|
if (!groupRoute) {
|
|
@@ -63230,7 +63578,7 @@ async function addSlackRoute(kind, args) {
|
|
|
63230
63578
|
if (!routeId) {
|
|
63231
63579
|
throw new Error(`Usage: clisbot channels add slack-${kind} <${kind}Id> [--agent <id>] [--require-mention true|false]`);
|
|
63232
63580
|
}
|
|
63233
|
-
const { config, configPath } = await readEditableConfig(
|
|
63581
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63234
63582
|
const agentId = getAgentId(args);
|
|
63235
63583
|
const requireMention = parseBooleanOption(args, "--require-mention", false);
|
|
63236
63584
|
const target = kind === "channel" ? config.channels.slack.channels : config.channels.slack.groups;
|
|
@@ -63254,7 +63602,7 @@ async function removeSlackRoute(kind, args) {
|
|
|
63254
63602
|
if (!routeId) {
|
|
63255
63603
|
throw new Error(`Usage: clisbot channels remove slack-${kind} <${kind}Id>`);
|
|
63256
63604
|
}
|
|
63257
|
-
const { config, configPath } = await readEditableConfig(
|
|
63605
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63258
63606
|
const target = kind === "channel" ? config.channels.slack.channels : config.channels.slack.groups;
|
|
63259
63607
|
if (!target[routeId]) {
|
|
63260
63608
|
console.log(`slack ${kind} route ${routeId} is not configured`);
|
|
@@ -63267,7 +63615,7 @@ async function removeSlackRoute(kind, args) {
|
|
|
63267
63615
|
console.log(`config: ${configPath}`);
|
|
63268
63616
|
}
|
|
63269
63617
|
async function setToken(target, value) {
|
|
63270
|
-
const { config, configPath } = await readEditableConfig(
|
|
63618
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63271
63619
|
if (target === "slack-app") {
|
|
63272
63620
|
config.channels.slack.appToken = value;
|
|
63273
63621
|
const defaultAccountId = config.channels.slack.defaultAccount || "default";
|
|
@@ -63299,7 +63647,7 @@ async function setToken(target, value) {
|
|
|
63299
63647
|
console.log(`config: ${configPath}`);
|
|
63300
63648
|
}
|
|
63301
63649
|
async function clearToken(target) {
|
|
63302
|
-
const { config, configPath } = await readEditableConfig(
|
|
63650
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath6());
|
|
63303
63651
|
if (target === "slack-app") {
|
|
63304
63652
|
config.channels.slack.appToken = "";
|
|
63305
63653
|
const defaultAccountId = config.channels.slack.defaultAccount || "default";
|
|
@@ -64038,7 +64386,7 @@ class SessionStore {
|
|
|
64038
64386
|
}
|
|
64039
64387
|
|
|
64040
64388
|
// src/control/loops-cli.ts
|
|
64041
|
-
function
|
|
64389
|
+
function getEditableConfigPath7() {
|
|
64042
64390
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
64043
64391
|
}
|
|
64044
64392
|
function renderLoopsHelp() {
|
|
@@ -64096,7 +64444,7 @@ function getSessionState(sessionStorePath) {
|
|
|
64096
64444
|
return new AgentSessionState(new SessionStore(sessionStorePath));
|
|
64097
64445
|
}
|
|
64098
64446
|
async function loadLoopControlState() {
|
|
64099
|
-
const configPath = await ensureEditableConfigFile(
|
|
64447
|
+
const configPath = await ensureEditableConfigFile(getEditableConfigPath7());
|
|
64100
64448
|
const loadedConfig = await loadConfigWithoutEnvResolution(configPath);
|
|
64101
64449
|
const sessionStorePath = resolveSessionStorePath(loadedConfig);
|
|
64102
64450
|
return {
|
|
@@ -64272,6 +64620,9 @@ function buildReplyCommand(params) {
|
|
|
64272
64620
|
const lines = [`${params.command} message send \\`];
|
|
64273
64621
|
if (params.identity.platform === "slack") {
|
|
64274
64622
|
lines.push(" --channel slack \\");
|
|
64623
|
+
if (params.identity.accountId) {
|
|
64624
|
+
lines.push(` --account ${params.identity.accountId} \\`);
|
|
64625
|
+
}
|
|
64275
64626
|
lines.push(` --target channel:${params.identity.channelId ?? ""} \\`);
|
|
64276
64627
|
if (params.identity.threadTs) {
|
|
64277
64628
|
lines.push(` --thread-id ${params.identity.threadTs} \\`);
|
|
@@ -64286,6 +64637,9 @@ function buildReplyCommand(params) {
|
|
|
64286
64637
|
`);
|
|
64287
64638
|
}
|
|
64288
64639
|
lines.push(" --channel telegram \\");
|
|
64640
|
+
if (params.identity.accountId) {
|
|
64641
|
+
lines.push(` --account ${params.identity.accountId} \\`);
|
|
64642
|
+
}
|
|
64289
64643
|
lines.push(` --target ${params.identity.chatId ?? ""} \\`);
|
|
64290
64644
|
if (params.identity.topicId) {
|
|
64291
64645
|
lines.push(` --thread-id ${params.identity.topicId} \\`);
|
|
@@ -64300,6 +64654,57 @@ function buildReplyCommand(params) {
|
|
|
64300
64654
|
`);
|
|
64301
64655
|
}
|
|
64302
64656
|
|
|
64657
|
+
// src/channels/surface-notifications.ts
|
|
64658
|
+
function sanitizeInlineCode(text) {
|
|
64659
|
+
return text.replaceAll("`", "'");
|
|
64660
|
+
}
|
|
64661
|
+
function summarizeSurfaceNotificationText(text, maxLength = 60) {
|
|
64662
|
+
const singleLine = sanitizeInlineCode(text.replace(/\s+/g, " ").trim());
|
|
64663
|
+
if (!singleLine) {
|
|
64664
|
+
return "(empty)";
|
|
64665
|
+
}
|
|
64666
|
+
if (singleLine.length <= maxLength) {
|
|
64667
|
+
return singleLine;
|
|
64668
|
+
}
|
|
64669
|
+
return `${singleLine.slice(0, maxLength - 3)}...`;
|
|
64670
|
+
}
|
|
64671
|
+
function renderQueueStartNotification(params) {
|
|
64672
|
+
if (params.mode === "none") {
|
|
64673
|
+
return;
|
|
64674
|
+
}
|
|
64675
|
+
const summary = summarizeSurfaceNotificationText(params.promptSummary);
|
|
64676
|
+
if (params.mode === "full") {
|
|
64677
|
+
return `Queued message is now running for agent \`${params.agentId}\`: \`${summary}\`.`;
|
|
64678
|
+
}
|
|
64679
|
+
return `Queued message is now running: \`${summary}\`.`;
|
|
64680
|
+
}
|
|
64681
|
+
function renderLoopScheduleSegment(params) {
|
|
64682
|
+
if (params.kind === "calendar") {
|
|
64683
|
+
return formatCalendarLoopSchedule({
|
|
64684
|
+
cadence: params.cadence,
|
|
64685
|
+
dayOfWeek: params.dayOfWeek,
|
|
64686
|
+
localTime: params.localTime
|
|
64687
|
+
});
|
|
64688
|
+
}
|
|
64689
|
+
return `every ${formatLoopIntervalShort(params.intervalMs)}`;
|
|
64690
|
+
}
|
|
64691
|
+
function renderLoopStartNotification(params) {
|
|
64692
|
+
if (params.mode === "none") {
|
|
64693
|
+
return;
|
|
64694
|
+
}
|
|
64695
|
+
const summary = summarizeSurfaceNotificationText(params.promptSummary);
|
|
64696
|
+
const segments = [
|
|
64697
|
+
`\`${summary}\``,
|
|
64698
|
+
renderLoopScheduleSegment(params),
|
|
64699
|
+
`next run \`${new Date(params.nextRunAt).toISOString()}\``,
|
|
64700
|
+
`remaining \`${params.remainingRuns}/${params.maxRuns}\``
|
|
64701
|
+
];
|
|
64702
|
+
if (params.mode === "full") {
|
|
64703
|
+
return `Loop \`${params.loopId}\` is now running for agent \`${params.agentId}\`: ${segments.join(" · ")}.`;
|
|
64704
|
+
}
|
|
64705
|
+
return `Loop \`${params.loopId}\` is now running: ${segments.join(" · ")}.`;
|
|
64706
|
+
}
|
|
64707
|
+
|
|
64303
64708
|
// src/agents/session-key.ts
|
|
64304
64709
|
var DEFAULT_MAIN_KEY = "main";
|
|
64305
64710
|
var DEFAULT_ACCOUNT_ID = "default";
|
|
@@ -66583,6 +66988,7 @@ class AgentService {
|
|
|
66583
66988
|
cleanupTimer;
|
|
66584
66989
|
loopTimers = new Set;
|
|
66585
66990
|
intervalLoops = new Map;
|
|
66991
|
+
surfaceNotificationHandlers = new Map;
|
|
66586
66992
|
constructor(loadedConfig, deps = {}) {
|
|
66587
66993
|
this.loadedConfig = loadedConfig;
|
|
66588
66994
|
this.tmuxClient = deps.tmux ?? new TmuxClient(this.loadedConfig.raw.tmux.socketPath);
|
|
@@ -66611,7 +67017,9 @@ class AgentService {
|
|
|
66611
67017
|
}
|
|
66612
67018
|
await this.runnerSessions.runSessionCleanup();
|
|
66613
67019
|
this.cleanupTimer = setInterval(() => {
|
|
66614
|
-
this.runnerSessions.runSessionCleanup()
|
|
67020
|
+
this.runnerSessions.runSessionCleanup().catch((error) => {
|
|
67021
|
+
console.error("session cleanup failed", error);
|
|
67022
|
+
});
|
|
66615
67023
|
}, cleanup.intervalMinutes * 60000);
|
|
66616
67024
|
}
|
|
66617
67025
|
async stop() {
|
|
@@ -66635,6 +67043,12 @@ class AgentService {
|
|
|
66635
67043
|
async cleanupStaleSessions() {
|
|
66636
67044
|
await this.runnerSessions.runSessionCleanup();
|
|
66637
67045
|
}
|
|
67046
|
+
registerSurfaceNotificationHandler(params) {
|
|
67047
|
+
this.surfaceNotificationHandlers.set(this.getSurfaceNotificationHandlerKey(params.platform, params.accountId), params.handler);
|
|
67048
|
+
}
|
|
67049
|
+
unregisterSurfaceNotificationHandler(params) {
|
|
67050
|
+
this.surfaceNotificationHandlers.delete(this.getSurfaceNotificationHandlerKey(params.platform, params.accountId));
|
|
67051
|
+
}
|
|
66638
67052
|
resolveTarget(target) {
|
|
66639
67053
|
return resolveAgentTarget(this.loadedConfig, target);
|
|
66640
67054
|
}
|
|
@@ -66743,7 +67157,9 @@ class AgentService {
|
|
|
66743
67157
|
target: params.target,
|
|
66744
67158
|
loop
|
|
66745
67159
|
});
|
|
66746
|
-
await this.runIntervalLoopIteration(loop.id
|
|
67160
|
+
await this.runIntervalLoopIteration(loop.id, {
|
|
67161
|
+
notifyStart: false
|
|
67162
|
+
});
|
|
66747
67163
|
return this.getIntervalLoop(loop.id);
|
|
66748
67164
|
}
|
|
66749
67165
|
async createCalendarLoop(params) {
|
|
@@ -66905,7 +67321,7 @@ class AgentService {
|
|
|
66905
67321
|
}
|
|
66906
67322
|
this.intervalLoops.delete(loopId);
|
|
66907
67323
|
}
|
|
66908
|
-
async runIntervalLoopIteration(loopId) {
|
|
67324
|
+
async runIntervalLoopIteration(loopId, options = {}) {
|
|
66909
67325
|
const managed = this.intervalLoops.get(loopId);
|
|
66910
67326
|
if (!managed) {
|
|
66911
67327
|
return;
|
|
@@ -66941,6 +67357,9 @@ class AgentService {
|
|
|
66941
67357
|
this.dropManagedIntervalLoop(loopId);
|
|
66942
67358
|
return;
|
|
66943
67359
|
}
|
|
67360
|
+
if (options.notifyStart !== false) {
|
|
67361
|
+
await this.notifyManagedLoopStart(managed.target, nextLoopState);
|
|
67362
|
+
}
|
|
66944
67363
|
const promptText = this.buildManagedLoopPrompt(managed.target.agentId, nextLoopState);
|
|
66945
67364
|
const { result } = this.enqueuePrompt(managed.target, promptText, {
|
|
66946
67365
|
observerId: `loop:${loopId}:${attemptedRuns}`,
|
|
@@ -66960,6 +67379,101 @@ class AgentService {
|
|
|
66960
67379
|
}
|
|
66961
67380
|
this.scheduleIntervalLoopTimer(loopId, Math.max(0, nextLoopState.nextRunAt - now));
|
|
66962
67381
|
}
|
|
67382
|
+
getSurfaceNotificationHandlerKey(platform, accountId) {
|
|
67383
|
+
return `${platform}:${accountId?.trim() || "default"}`;
|
|
67384
|
+
}
|
|
67385
|
+
async notifySurface(request) {
|
|
67386
|
+
const handler = this.surfaceNotificationHandlers.get(this.getSurfaceNotificationHandlerKey(request.binding.platform, request.binding.accountId));
|
|
67387
|
+
if (!handler) {
|
|
67388
|
+
return;
|
|
67389
|
+
}
|
|
67390
|
+
await handler(request);
|
|
67391
|
+
}
|
|
67392
|
+
resolveLoopSurfaceNotifications(identity) {
|
|
67393
|
+
if (identity.platform === "slack") {
|
|
67394
|
+
const channelConfig2 = this.loadedConfig.raw.channels.slack;
|
|
67395
|
+
let resolved2 = {
|
|
67396
|
+
queueStart: channelConfig2.surfaceNotifications?.queueStart ?? "brief",
|
|
67397
|
+
loopStart: channelConfig2.surfaceNotifications?.loopStart ?? "brief"
|
|
67398
|
+
};
|
|
67399
|
+
if (identity.conversationKind === "dm") {
|
|
67400
|
+
return {
|
|
67401
|
+
...resolved2,
|
|
67402
|
+
...channelConfig2.directMessages.surfaceNotifications ?? {}
|
|
67403
|
+
};
|
|
67404
|
+
}
|
|
67405
|
+
const routeCollection = identity.conversationKind === "group" ? channelConfig2.groups : channelConfig2.channels;
|
|
67406
|
+
const route = identity.channelId ? routeCollection[identity.channelId] ?? routeCollection["*"] : undefined;
|
|
67407
|
+
return {
|
|
67408
|
+
...resolved2,
|
|
67409
|
+
...route?.surfaceNotifications ?? {}
|
|
67410
|
+
};
|
|
67411
|
+
}
|
|
67412
|
+
const channelConfig = this.loadedConfig.raw.channels.telegram;
|
|
67413
|
+
let resolved = {
|
|
67414
|
+
queueStart: channelConfig.surfaceNotifications?.queueStart ?? "brief",
|
|
67415
|
+
loopStart: channelConfig.surfaceNotifications?.loopStart ?? "brief"
|
|
67416
|
+
};
|
|
67417
|
+
if (identity.conversationKind === "dm") {
|
|
67418
|
+
return {
|
|
67419
|
+
...resolved,
|
|
67420
|
+
...channelConfig.directMessages.surfaceNotifications ?? {}
|
|
67421
|
+
};
|
|
67422
|
+
}
|
|
67423
|
+
const groupRoute = identity.chatId ? channelConfig.groups[identity.chatId] ?? channelConfig.groups["*"] : undefined;
|
|
67424
|
+
resolved = {
|
|
67425
|
+
...resolved,
|
|
67426
|
+
...groupRoute?.surfaceNotifications ?? {}
|
|
67427
|
+
};
|
|
67428
|
+
if (identity.conversationKind === "topic" && identity.topicId) {
|
|
67429
|
+
return {
|
|
67430
|
+
...resolved,
|
|
67431
|
+
...groupRoute?.topics?.[identity.topicId]?.surfaceNotifications ?? {}
|
|
67432
|
+
};
|
|
67433
|
+
}
|
|
67434
|
+
return resolved;
|
|
67435
|
+
}
|
|
67436
|
+
async notifyManagedLoopStart(target, loop) {
|
|
67437
|
+
if (!loop.surfaceBinding) {
|
|
67438
|
+
return;
|
|
67439
|
+
}
|
|
67440
|
+
const identity = this.buildLoopChannelIdentity(loop.surfaceBinding);
|
|
67441
|
+
const notifications = this.resolveLoopSurfaceNotifications(identity);
|
|
67442
|
+
const text = loop.kind === "calendar" ? renderLoopStartNotification({
|
|
67443
|
+
mode: notifications.loopStart,
|
|
67444
|
+
agentId: target.agentId,
|
|
67445
|
+
loopId: loop.id,
|
|
67446
|
+
promptSummary: loop.promptSummary,
|
|
67447
|
+
cadence: loop.cadence,
|
|
67448
|
+
dayOfWeek: loop.dayOfWeek,
|
|
67449
|
+
localTime: loop.localTime,
|
|
67450
|
+
timezone: loop.timezone,
|
|
67451
|
+
nextRunAt: loop.nextRunAt,
|
|
67452
|
+
remainingRuns: Math.max(0, loop.maxRuns - loop.attemptedRuns),
|
|
67453
|
+
maxRuns: loop.maxRuns,
|
|
67454
|
+
kind: "calendar"
|
|
67455
|
+
}) : renderLoopStartNotification({
|
|
67456
|
+
mode: notifications.loopStart,
|
|
67457
|
+
agentId: target.agentId,
|
|
67458
|
+
loopId: loop.id,
|
|
67459
|
+
promptSummary: loop.promptSummary,
|
|
67460
|
+
intervalMs: loop.intervalMs,
|
|
67461
|
+
nextRunAt: loop.nextRunAt,
|
|
67462
|
+
remainingRuns: Math.max(0, loop.maxRuns - loop.attemptedRuns),
|
|
67463
|
+
maxRuns: loop.maxRuns
|
|
67464
|
+
});
|
|
67465
|
+
if (!text) {
|
|
67466
|
+
return;
|
|
67467
|
+
}
|
|
67468
|
+
try {
|
|
67469
|
+
await this.notifySurface({
|
|
67470
|
+
binding: loop.surfaceBinding,
|
|
67471
|
+
text
|
|
67472
|
+
});
|
|
67473
|
+
} catch (error) {
|
|
67474
|
+
console.error("loop start notification failed", error);
|
|
67475
|
+
}
|
|
67476
|
+
}
|
|
66963
67477
|
scheduleIntervalLoopTimer(loopId, delayMs) {
|
|
66964
67478
|
const managed = this.intervalLoops.get(loopId);
|
|
66965
67479
|
if (!managed) {
|
|
@@ -66976,7 +67490,9 @@ class AgentService {
|
|
|
66976
67490
|
return;
|
|
66977
67491
|
}
|
|
66978
67492
|
current.timer = undefined;
|
|
66979
|
-
this.runIntervalLoopIteration(loopId
|
|
67493
|
+
this.runIntervalLoopIteration(loopId, {
|
|
67494
|
+
notifyStart: true
|
|
67495
|
+
}).catch((error) => {
|
|
66980
67496
|
if (this.shouldSuppressLoopShutdownError(error)) {
|
|
66981
67497
|
return;
|
|
66982
67498
|
}
|
|
@@ -67034,6 +67550,7 @@ class AgentService {
|
|
|
67034
67550
|
buildLoopChannelIdentity(binding) {
|
|
67035
67551
|
return {
|
|
67036
67552
|
platform: binding.platform,
|
|
67553
|
+
accountId: binding.accountId,
|
|
67037
67554
|
conversationKind: binding.conversationKind,
|
|
67038
67555
|
channelId: binding.channelId,
|
|
67039
67556
|
chatId: binding.chatId,
|
|
@@ -67649,11 +68166,11 @@ function formatChannelFollowUpStatus(params) {
|
|
|
67649
68166
|
}
|
|
67650
68167
|
|
|
67651
68168
|
// src/channels/streaming-config.ts
|
|
67652
|
-
function
|
|
68169
|
+
function getEditableConfigPath8() {
|
|
67653
68170
|
return process.env.CLISBOT_CONFIG_PATH;
|
|
67654
68171
|
}
|
|
67655
68172
|
async function getConversationStreaming(params) {
|
|
67656
|
-
const { config } = await readEditableConfig(
|
|
68173
|
+
const { config } = await readEditableConfig(getEditableConfigPath8());
|
|
67657
68174
|
const target = resolveConfiguredSurfaceModeTarget(config, "streaming", buildConfiguredTargetFromIdentity(params.identity));
|
|
67658
68175
|
return {
|
|
67659
68176
|
label: target.label,
|
|
@@ -67661,7 +68178,7 @@ async function getConversationStreaming(params) {
|
|
|
67661
68178
|
};
|
|
67662
68179
|
}
|
|
67663
68180
|
async function setConversationStreaming(params) {
|
|
67664
|
-
const { config, configPath } = await readEditableConfig(
|
|
68181
|
+
const { config, configPath } = await readEditableConfig(getEditableConfigPath8());
|
|
67665
68182
|
const target = resolveConfiguredSurfaceModeTarget(config, "streaming", buildConfiguredTargetFromIdentity(params.identity));
|
|
67666
68183
|
target.set(params.streaming);
|
|
67667
68184
|
await writeEditableConfig(configPath, config);
|
|
@@ -67742,7 +68259,7 @@ function renderRouteStatusMessage(params) {
|
|
|
67742
68259
|
if (params.identity.topicId) {
|
|
67743
68260
|
lines.push(`topicId: \`${params.identity.topicId}\``);
|
|
67744
68261
|
}
|
|
67745
|
-
lines.push(`streaming: \`${params.route.streaming}\``, `response: \`${params.route.response}\``, `responseMode: \`${params.route.responseMode}\``, `additionalMessageMode: \`${params.route.additionalMessageMode}\``, `verbose: \`${params.route.verbose}\``, `principal: \`${params.auth.principal ?? "(none)"}\``, `appRole: \`${params.auth.appRole}\``, `agentRole: \`${params.auth.agentRole}\``, `mayManageProtectedResources: \`${params.auth.mayManageProtectedResources}\``, `canUseShell: \`${params.auth.canUseShell}\``, `timezone: \`${params.route.timezone ?? "(inherit host/app)"}\``, `followUp.mode: \`${params.followUpState.overrideMode ?? params.route.followUp.mode}\``, `followUp.windowMinutes: \`${formatFollowUpTtlMinutes(params.route.followUp.participationTtlMs)}\``, `run.state: \`${params.runtimeState.state}\``);
|
|
68262
|
+
lines.push(`streaming: \`${params.route.streaming}\``, `response: \`${params.route.response}\``, `responseMode: \`${params.route.responseMode}\``, `additionalMessageMode: \`${params.route.additionalMessageMode}\``, `surfaceNotifications.queueStart: \`${params.route.surfaceNotifications.queueStart}\``, `surfaceNotifications.loopStart: \`${params.route.surfaceNotifications.loopStart}\``, `verbose: \`${params.route.verbose}\``, `principal: \`${params.auth.principal ?? "(none)"}\``, `appRole: \`${params.auth.appRole}\``, `agentRole: \`${params.auth.agentRole}\``, `mayManageProtectedResources: \`${params.auth.mayManageProtectedResources}\``, `canUseShell: \`${params.auth.canUseShell}\``, `timezone: \`${params.route.timezone ?? "(inherit host/app)"}\``, `followUp.mode: \`${params.followUpState.overrideMode ?? params.route.followUp.mode}\``, `followUp.windowMinutes: \`${formatFollowUpTtlMinutes(params.route.followUp.participationTtlMs)}\``, `run.state: \`${params.runtimeState.state}\``);
|
|
67746
68263
|
if (params.runtimeState.startedAt) {
|
|
67747
68264
|
lines.push(`run.startedAt: \`${new Date(params.runtimeState.startedAt).toISOString()}\``);
|
|
67748
68265
|
}
|
|
@@ -67979,6 +68496,7 @@ async function resolveLoopPromptText(params) {
|
|
|
67979
68496
|
function buildLoopSurfaceBinding(identity) {
|
|
67980
68497
|
return {
|
|
67981
68498
|
platform: identity.platform,
|
|
68499
|
+
accountId: identity.accountId,
|
|
67982
68500
|
conversationKind: identity.conversationKind,
|
|
67983
68501
|
channelId: identity.channelId,
|
|
67984
68502
|
chatId: identity.chatId,
|
|
@@ -67995,6 +68513,8 @@ async function executePromptDelivery(params) {
|
|
|
67995
68513
|
let loggedFirstRunningUpdate = false;
|
|
67996
68514
|
let activePreviewStartedAt;
|
|
67997
68515
|
let messageToolPreviewHandedOff = false;
|
|
68516
|
+
let queueStartPending = false;
|
|
68517
|
+
let deferredQueueStartPreview = false;
|
|
67998
68518
|
const paneManagedDelivery = params.route.responseMode === "capture-pane" || params.forceQueuedDelivery === true;
|
|
67999
68519
|
const messageToolPreview = params.route.responseMode === "message-tool" && params.forceQueuedDelivery !== true && params.route.streaming !== "off";
|
|
68000
68520
|
const previewEnabled = params.route.streaming !== "off" && (paneManagedDelivery || messageToolPreview);
|
|
@@ -68069,6 +68589,68 @@ async function executePromptDelivery(params) {
|
|
|
68069
68589
|
agentId: params.route.agentId,
|
|
68070
68590
|
sessionKey: params.sessionTarget.sessionKey
|
|
68071
68591
|
});
|
|
68592
|
+
async function maybeRenderQueueStartNotification() {
|
|
68593
|
+
if (!queueStartPending) {
|
|
68594
|
+
return false;
|
|
68595
|
+
}
|
|
68596
|
+
const text = renderQueueStartNotification({
|
|
68597
|
+
mode: params.queueStartMode ?? "none",
|
|
68598
|
+
agentId: params.route.agentId,
|
|
68599
|
+
promptSummary: params.notificationPromptSummary ?? summarizeSurfaceNotificationText(params.promptText)
|
|
68600
|
+
});
|
|
68601
|
+
if (!text) {
|
|
68602
|
+
queueStartPending = false;
|
|
68603
|
+
return false;
|
|
68604
|
+
}
|
|
68605
|
+
if (previewEnabled && responseChunks.length === 0) {
|
|
68606
|
+
deferredQueueStartPreview = true;
|
|
68607
|
+
return true;
|
|
68608
|
+
}
|
|
68609
|
+
queueStartPending = false;
|
|
68610
|
+
if (responseChunks.length > 0) {
|
|
68611
|
+
const postedNew = await renderResponseText(text);
|
|
68612
|
+
if (postedNew) {
|
|
68613
|
+
await recordVisibleReply("reply", "channel");
|
|
68614
|
+
activePreviewStartedAt = Date.now();
|
|
68615
|
+
}
|
|
68616
|
+
renderedState = {
|
|
68617
|
+
text,
|
|
68618
|
+
body: ""
|
|
68619
|
+
};
|
|
68620
|
+
return true;
|
|
68621
|
+
}
|
|
68622
|
+
const posted = await params.postText(text);
|
|
68623
|
+
if (posted.length > 0) {
|
|
68624
|
+
await recordVisibleReply("reply", "channel");
|
|
68625
|
+
}
|
|
68626
|
+
return posted.length > 0;
|
|
68627
|
+
}
|
|
68628
|
+
function buildInitialPlaceholderText(positionAhead) {
|
|
68629
|
+
if (deferredQueueStartPreview && queueStartPending) {
|
|
68630
|
+
deferredQueueStartPreview = false;
|
|
68631
|
+
queueStartPending = false;
|
|
68632
|
+
return renderQueueStartNotification({
|
|
68633
|
+
mode: params.queueStartMode ?? "none",
|
|
68634
|
+
agentId: params.route.agentId,
|
|
68635
|
+
promptSummary: params.notificationPromptSummary ?? summarizeSurfaceNotificationText(params.promptText)
|
|
68636
|
+
}) ?? renderPlatformInteraction({
|
|
68637
|
+
platform: params.identity.platform,
|
|
68638
|
+
status: positionAhead > 0 ? "queued" : "running",
|
|
68639
|
+
content: "",
|
|
68640
|
+
queuePosition: positionAhead,
|
|
68641
|
+
maxChars: Number.POSITIVE_INFINITY,
|
|
68642
|
+
note: positionAhead > 0 ? "Waiting for the agent queue to clear." : "Working..."
|
|
68643
|
+
});
|
|
68644
|
+
}
|
|
68645
|
+
return renderPlatformInteraction({
|
|
68646
|
+
platform: params.identity.platform,
|
|
68647
|
+
status: positionAhead > 0 ? "queued" : "running",
|
|
68648
|
+
content: "",
|
|
68649
|
+
queuePosition: positionAhead,
|
|
68650
|
+
maxChars: Number.POSITIVE_INFINITY,
|
|
68651
|
+
note: positionAhead > 0 ? "Waiting for the agent queue to clear." : "Working..."
|
|
68652
|
+
});
|
|
68653
|
+
}
|
|
68072
68654
|
try {
|
|
68073
68655
|
const { positionAhead, result } = params.agentService.enqueuePrompt(params.sessionTarget, params.promptText, {
|
|
68074
68656
|
observerId: params.observerId,
|
|
@@ -68077,9 +68659,6 @@ async function executePromptDelivery(params) {
|
|
|
68077
68659
|
if (!paneManagedDelivery && !messageToolPreview) {
|
|
68078
68660
|
return;
|
|
68079
68661
|
}
|
|
68080
|
-
if (params.route.streaming === "off" && update.status === "running") {
|
|
68081
|
-
return;
|
|
68082
|
-
}
|
|
68083
68662
|
if (update.status === "running" && !loggedFirstRunningUpdate) {
|
|
68084
68663
|
loggedFirstRunningUpdate = true;
|
|
68085
68664
|
logLatencyDebug("channel-first-running-update", params.timingContext, {
|
|
@@ -68088,14 +68667,21 @@ async function executePromptDelivery(params) {
|
|
|
68088
68667
|
});
|
|
68089
68668
|
}
|
|
68090
68669
|
await (renderChain = renderChain.then(async () => {
|
|
68670
|
+
let renderedQueueStart = false;
|
|
68671
|
+
if (update.status === "running") {
|
|
68672
|
+
renderedQueueStart = await maybeRenderQueueStartNotification();
|
|
68673
|
+
}
|
|
68674
|
+
if (params.route.streaming === "off" && update.status === "running") {
|
|
68675
|
+
return;
|
|
68676
|
+
}
|
|
68677
|
+
if (renderedQueueStart) {
|
|
68678
|
+
return;
|
|
68679
|
+
}
|
|
68091
68680
|
const signals = await getMessageToolRuntimeSignals();
|
|
68092
68681
|
if (messageToolPreview && typeof activePreviewStartedAt === "number" && (typeof signals.messageToolFinalReplyAt === "number" && signals.messageToolFinalReplyAt >= activePreviewStartedAt || typeof signals.lastMessageToolReplyAt === "number" && signals.lastMessageToolReplyAt >= activePreviewStartedAt)) {
|
|
68093
68682
|
await handoffMessageToolPreview();
|
|
68094
68683
|
return;
|
|
68095
68684
|
}
|
|
68096
|
-
if (messageToolPreview) {
|
|
68097
|
-
return;
|
|
68098
|
-
}
|
|
68099
68685
|
const nextState2 = buildRenderedMessageState({
|
|
68100
68686
|
platform: params.identity.platform,
|
|
68101
68687
|
status: update.status,
|
|
@@ -68119,15 +68705,9 @@ async function executePromptDelivery(params) {
|
|
|
68119
68705
|
}));
|
|
68120
68706
|
}
|
|
68121
68707
|
});
|
|
68708
|
+
queueStartPending = positionAhead > 0 && (params.queueStartMode ?? "none") !== "none";
|
|
68122
68709
|
if (previewEnabled) {
|
|
68123
|
-
const placeholderText =
|
|
68124
|
-
platform: params.identity.platform,
|
|
68125
|
-
status: positionAhead > 0 ? "queued" : "running",
|
|
68126
|
-
content: "",
|
|
68127
|
-
queuePosition: positionAhead,
|
|
68128
|
-
maxChars: Number.POSITIVE_INFINITY,
|
|
68129
|
-
note: positionAhead > 0 ? "Waiting for the agent queue to clear." : "Working..."
|
|
68130
|
-
});
|
|
68710
|
+
const placeholderText = buildInitialPlaceholderText(positionAhead);
|
|
68131
68711
|
const postedNew2 = await renderResponseText(placeholderText);
|
|
68132
68712
|
if (postedNew2) {
|
|
68133
68713
|
await recordVisibleReply("reply", "channel");
|
|
@@ -68157,6 +68737,7 @@ async function executePromptDelivery(params) {
|
|
|
68157
68737
|
}
|
|
68158
68738
|
const finalResult = await result;
|
|
68159
68739
|
await renderChain;
|
|
68740
|
+
await maybeRenderQueueStartNotification();
|
|
68160
68741
|
if (!paneManagedDelivery && messageToolPreviewHandedOff) {
|
|
68161
68742
|
return;
|
|
68162
68743
|
}
|
|
@@ -68641,6 +69222,8 @@ ${renderLoopUsage()}`);
|
|
|
68641
69222
|
route: params.route,
|
|
68642
69223
|
maxChars: params.maxChars,
|
|
68643
69224
|
promptText: buildLoopPromptText(resolvedLoopPrompt.text),
|
|
69225
|
+
queueStartMode: params.route.surfaceNotifications.queueStart,
|
|
69226
|
+
notificationPromptSummary: summarizeLoopPrompt(resolvedLoopPrompt.text, resolvedLoopPrompt.maintenancePrompt),
|
|
68644
69227
|
postText: params.postText,
|
|
68645
69228
|
reconcileText: params.reconcileText,
|
|
68646
69229
|
observerId: `${observerId}:loop:${index + 1}`
|
|
@@ -68781,6 +69364,8 @@ ${escapeCodeFence(shellResult.output)}
|
|
|
68781
69364
|
route: params.route,
|
|
68782
69365
|
maxChars: params.maxChars,
|
|
68783
69366
|
promptText: delayedPromptText,
|
|
69367
|
+
queueStartMode: params.route.surfaceNotifications.queueStart,
|
|
69368
|
+
notificationPromptSummary: explicitQueueMessage ?? summarizeSurfaceNotificationText(params.text),
|
|
68784
69369
|
postText: params.postText,
|
|
68785
69370
|
reconcileText: params.reconcileText,
|
|
68786
69371
|
observerId,
|
|
@@ -68841,6 +69426,23 @@ function isTelegramSenderAllowed(params) {
|
|
|
68841
69426
|
}
|
|
68842
69427
|
|
|
68843
69428
|
// src/auth/resolve.ts
|
|
69429
|
+
function mergeRoleDefinitions2(inherited, override) {
|
|
69430
|
+
return {
|
|
69431
|
+
allow: override?.allow ?? inherited?.allow ?? [],
|
|
69432
|
+
users: override?.users ?? inherited?.users ?? []
|
|
69433
|
+
};
|
|
69434
|
+
}
|
|
69435
|
+
function mergeRoleRecord2(defaults, overrides) {
|
|
69436
|
+
const merged = {};
|
|
69437
|
+
const roleNames = new Set([
|
|
69438
|
+
...Object.keys(defaults ?? {}),
|
|
69439
|
+
...Object.keys(overrides ?? {})
|
|
69440
|
+
]);
|
|
69441
|
+
for (const roleName of roleNames) {
|
|
69442
|
+
merged[roleName] = mergeRoleDefinitions2(defaults?.[roleName], overrides?.[roleName]);
|
|
69443
|
+
}
|
|
69444
|
+
return merged;
|
|
69445
|
+
}
|
|
68844
69446
|
function normalizePrincipal(principal) {
|
|
68845
69447
|
const trimmed = principal.trim();
|
|
68846
69448
|
if (!trimmed) {
|
|
@@ -68888,10 +69490,7 @@ function getAgentAuth(config, agentId) {
|
|
|
68888
69490
|
const override = entry?.auth;
|
|
68889
69491
|
return {
|
|
68890
69492
|
defaultRole: override?.defaultRole ?? defaults.defaultRole,
|
|
68891
|
-
roles:
|
|
68892
|
-
...defaults.roles,
|
|
68893
|
-
...override?.roles ?? {}
|
|
68894
|
-
}
|
|
69493
|
+
roles: mergeRoleRecord2(defaults.roles, override?.roles)
|
|
68895
69494
|
};
|
|
68896
69495
|
}
|
|
68897
69496
|
function getAllowedPermissions(roles, role) {
|
|
@@ -69014,6 +69613,10 @@ function buildSharedChannelRoute(params) {
|
|
|
69014
69613
|
response: params.route?.response ?? params.channelConfig.response,
|
|
69015
69614
|
responseMode: params.route?.responseMode ?? agentEntry?.responseMode ?? params.channelConfig.responseMode,
|
|
69016
69615
|
additionalMessageMode: params.route?.additionalMessageMode ?? agentEntry?.additionalMessageMode ?? params.channelConfig.additionalMessageMode,
|
|
69616
|
+
surfaceNotifications: {
|
|
69617
|
+
queueStart: params.route?.surfaceNotifications?.queueStart ?? params.channelConfig.surfaceNotifications?.queueStart ?? "brief",
|
|
69618
|
+
loopStart: params.route?.surfaceNotifications?.loopStart ?? params.channelConfig.surfaceNotifications?.loopStart ?? "brief"
|
|
69619
|
+
},
|
|
69017
69620
|
verbose: params.route?.verbose ?? params.channelConfig.verbose,
|
|
69018
69621
|
followUp: {
|
|
69019
69622
|
mode: params.route?.followUp?.mode ?? params.channelConfig.followUp.mode,
|
|
@@ -69990,6 +70593,20 @@ class SlackSocketService {
|
|
|
69990
70593
|
appToken: this.accountConfig.appToken,
|
|
69991
70594
|
socketMode: true
|
|
69992
70595
|
});
|
|
70596
|
+
this.agentService.registerSurfaceNotificationHandler({
|
|
70597
|
+
platform: "slack",
|
|
70598
|
+
accountId: this.accountId,
|
|
70599
|
+
handler: async ({ binding, text }) => {
|
|
70600
|
+
if (!binding.channelId) {
|
|
70601
|
+
return;
|
|
70602
|
+
}
|
|
70603
|
+
await postSlackText(this.app.client, {
|
|
70604
|
+
channel: binding.channelId,
|
|
70605
|
+
threadTs: binding.threadTs,
|
|
70606
|
+
text
|
|
70607
|
+
});
|
|
70608
|
+
}
|
|
70609
|
+
});
|
|
69993
70610
|
this.registerEvents();
|
|
69994
70611
|
}
|
|
69995
70612
|
getSlackMaxChars(agentId) {
|
|
@@ -70243,6 +70860,7 @@ class SlackSocketService {
|
|
|
70243
70860
|
const cliTool = getAgentEntry(this.loadedConfig, params.route.agentId)?.cliTool;
|
|
70244
70861
|
const identity = {
|
|
70245
70862
|
platform: "slack",
|
|
70863
|
+
accountId: this.accountId,
|
|
70246
70864
|
conversationKind: params.conversationKind,
|
|
70247
70865
|
senderId: typeof event.user === "string" ? event.user.trim().toUpperCase() : undefined,
|
|
70248
70866
|
channelId,
|
|
@@ -70426,6 +71044,10 @@ class SlackSocketService {
|
|
|
70426
71044
|
await this.startPromise;
|
|
70427
71045
|
}
|
|
70428
71046
|
async stop() {
|
|
71047
|
+
this.agentService.unregisterSurfaceNotificationHandler({
|
|
71048
|
+
platform: "slack",
|
|
71049
|
+
accountId: this.accountId
|
|
71050
|
+
});
|
|
70429
71051
|
await this.app.stop();
|
|
70430
71052
|
}
|
|
70431
71053
|
getBotUserLabel() {
|
|
@@ -71280,6 +71902,33 @@ async function resolveTelegramAttachmentPaths(params) {
|
|
|
71280
71902
|
return attachmentPaths;
|
|
71281
71903
|
}
|
|
71282
71904
|
|
|
71905
|
+
// src/channels/telegram/route-guidance.ts
|
|
71906
|
+
function renderTelegramRouteChoiceMessage(params) {
|
|
71907
|
+
const chatId = String(params.chatId);
|
|
71908
|
+
const topicId = params.topicId != null ? String(params.topicId) : undefined;
|
|
71909
|
+
const lines = [
|
|
71910
|
+
topicId != null ? "clisbot: this Telegram topic is not configured yet." : "clisbot: this Telegram group is not configured yet.",
|
|
71911
|
+
"",
|
|
71912
|
+
"Ask the bot owner to choose one of these:",
|
|
71913
|
+
"",
|
|
71914
|
+
"Add the whole group with the default agent:",
|
|
71915
|
+
`\`clisbot channels add telegram-group ${chatId}\``,
|
|
71916
|
+
"",
|
|
71917
|
+
"Add the whole group with a specific agent:",
|
|
71918
|
+
`\`clisbot channels add telegram-group ${chatId} --agent <id>\``
|
|
71919
|
+
];
|
|
71920
|
+
if (topicId != null) {
|
|
71921
|
+
lines.push("", "Add only this topic with a specific agent:", `\`clisbot channels add telegram-group ${chatId} --topic ${topicId} --agent <id>\``);
|
|
71922
|
+
}
|
|
71923
|
+
if (params.includeConfigPath) {
|
|
71924
|
+
lines.push("", topicId != null ? `Config path: \`channels.telegram.groups."${chatId}".topics."${topicId}"\`` : `Config path: \`channels.telegram.groups."${chatId}"\``);
|
|
71925
|
+
} else {
|
|
71926
|
+
lines.push("", "After that, routed commands such as `/status`, `/stop`, `/nudge`, `/followup`, and `/bash` will work here.");
|
|
71927
|
+
}
|
|
71928
|
+
return lines.join(`
|
|
71929
|
+
`);
|
|
71930
|
+
}
|
|
71931
|
+
|
|
71283
71932
|
// src/channels/telegram/typing.ts
|
|
71284
71933
|
var TELEGRAM_TYPING_HEARTBEAT_MS = 4500;
|
|
71285
71934
|
function logTelegramTypingError(onError, error) {
|
|
@@ -71423,6 +72072,7 @@ class TelegramPollingService {
|
|
|
71423
72072
|
activityStore;
|
|
71424
72073
|
accountId;
|
|
71425
72074
|
accountConfig;
|
|
72075
|
+
reportLifecycle;
|
|
71426
72076
|
botUserId = 0;
|
|
71427
72077
|
botUsername = "";
|
|
71428
72078
|
running = false;
|
|
@@ -71431,13 +72081,35 @@ class TelegramPollingService {
|
|
|
71431
72081
|
activePollController;
|
|
71432
72082
|
inFlightUpdates = new Set;
|
|
71433
72083
|
processingIndicators = new ConversationProcessingIndicatorCoordinator;
|
|
71434
|
-
constructor(loadedConfig, agentService, processedEventsStore, activityStore, accountId = "default", accountConfig) {
|
|
72084
|
+
constructor(loadedConfig, agentService, processedEventsStore, activityStore, accountId = "default", accountConfig, reportLifecycle) {
|
|
71435
72085
|
this.loadedConfig = loadedConfig;
|
|
71436
72086
|
this.agentService = agentService;
|
|
71437
72087
|
this.processedEventsStore = processedEventsStore;
|
|
71438
72088
|
this.activityStore = activityStore;
|
|
71439
72089
|
this.accountId = accountId;
|
|
71440
72090
|
this.accountConfig = accountConfig;
|
|
72091
|
+
this.reportLifecycle = reportLifecycle;
|
|
72092
|
+
this.agentService.registerSurfaceNotificationHandler({
|
|
72093
|
+
platform: "telegram",
|
|
72094
|
+
accountId: this.accountId,
|
|
72095
|
+
handler: async ({ binding, text }) => {
|
|
72096
|
+
if (!binding.chatId) {
|
|
72097
|
+
return;
|
|
72098
|
+
}
|
|
72099
|
+
const chatId = Number(binding.chatId);
|
|
72100
|
+
if (!Number.isFinite(chatId)) {
|
|
72101
|
+
return;
|
|
72102
|
+
}
|
|
72103
|
+
const topicId = binding.topicId ? Number(binding.topicId) : undefined;
|
|
72104
|
+
await postTelegramText({
|
|
72105
|
+
token: this.accountConfig.botToken,
|
|
72106
|
+
chatId,
|
|
72107
|
+
text,
|
|
72108
|
+
topicId: Number.isFinite(topicId) ? topicId : undefined,
|
|
72109
|
+
omitThreadId: shouldOmitTelegramThreadId(Number.isFinite(topicId) ? topicId : undefined)
|
|
72110
|
+
});
|
|
72111
|
+
}
|
|
72112
|
+
});
|
|
71441
72113
|
}
|
|
71442
72114
|
async start() {
|
|
71443
72115
|
const me = await callTelegramApi(this.accountConfig.botToken, "getMe", {});
|
|
@@ -71454,6 +72126,10 @@ class TelegramPollingService {
|
|
|
71454
72126
|
this.activePollController?.abort();
|
|
71455
72127
|
await this.loopPromise;
|
|
71456
72128
|
await Promise.allSettled([...this.inFlightUpdates]);
|
|
72129
|
+
this.agentService.unregisterSurfaceNotificationHandler({
|
|
72130
|
+
platform: "telegram",
|
|
72131
|
+
accountId: this.accountId
|
|
72132
|
+
});
|
|
71457
72133
|
}
|
|
71458
72134
|
getBotLabel() {
|
|
71459
72135
|
return this.botUsername ? `@${this.botUsername}` : `${this.botUserId || "unknown"}`;
|
|
@@ -71500,6 +72176,15 @@ class TelegramPollingService {
|
|
|
71500
72176
|
}
|
|
71501
72177
|
if (isTelegramPollingConflict(error)) {
|
|
71502
72178
|
this.running = false;
|
|
72179
|
+
await this.reportLifecycle?.({
|
|
72180
|
+
connection: "failed",
|
|
72181
|
+
summary: "Telegram polling stopped because another instance is already using this bot token.",
|
|
72182
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
72183
|
+
actions: [
|
|
72184
|
+
"stop the other Telegram poller that is using the same bot token",
|
|
72185
|
+
"run `clisbot start` again after the token is no longer in use elsewhere"
|
|
72186
|
+
]
|
|
72187
|
+
});
|
|
71503
72188
|
console.error("telegram polling stopped: another bot instance is already calling getUpdates for this token");
|
|
71504
72189
|
return;
|
|
71505
72190
|
}
|
|
@@ -71667,6 +72352,7 @@ class TelegramPollingService {
|
|
|
71667
72352
|
const senderName = [message.from?.first_name, message.from?.last_name].filter((value) => typeof value === "string" && value.trim().length > 0).join(" ").trim();
|
|
71668
72353
|
const identity = {
|
|
71669
72354
|
platform: "telegram",
|
|
72355
|
+
accountId: this.accountId,
|
|
71670
72356
|
conversationKind: routeInfo.conversationKind,
|
|
71671
72357
|
senderId: message.from?.id != null ? String(message.from.id).trim() : undefined,
|
|
71672
72358
|
senderName: senderName || message.from?.username?.trim() || undefined,
|
|
@@ -72079,7 +72765,7 @@ var telegramChannelPlugin = {
|
|
|
72079
72765
|
accountId,
|
|
72080
72766
|
config
|
|
72081
72767
|
})),
|
|
72082
|
-
createRuntimeService: (context, account) => new TelegramPollingService(context.loadedConfig, context.agentService, context.processedEventsStore, context.activityStore, account.accountId, account.config),
|
|
72768
|
+
createRuntimeService: (context, account) => new TelegramPollingService(context.loadedConfig, context.agentService, context.processedEventsStore, context.activityStore, account.accountId, account.config, context.reportLifecycle),
|
|
72083
72769
|
renderHealthSummary: (state) => {
|
|
72084
72770
|
switch (state) {
|
|
72085
72771
|
case "starting":
|
|
@@ -72173,7 +72859,7 @@ var defaultMessageCliDependencies = {
|
|
|
72173
72859
|
await agentService.recordConversationReply(target, kind, source);
|
|
72174
72860
|
}
|
|
72175
72861
|
};
|
|
72176
|
-
function
|
|
72862
|
+
function parseRepeatedOption3(args, name) {
|
|
72177
72863
|
const values = [];
|
|
72178
72864
|
for (let index = 0;index < args.length; index += 1) {
|
|
72179
72865
|
if (args[index] !== name) {
|
|
@@ -72188,7 +72874,7 @@ function parseRepeatedOption2(args, name) {
|
|
|
72188
72874
|
return values;
|
|
72189
72875
|
}
|
|
72190
72876
|
function parseOptionValue4(args, name) {
|
|
72191
|
-
const values =
|
|
72877
|
+
const values = parseRepeatedOption3(args, name);
|
|
72192
72878
|
return values.length > 0 ? values.at(-1) : undefined;
|
|
72193
72879
|
}
|
|
72194
72880
|
function parseIntegerOption(args, name) {
|
|
@@ -72202,7 +72888,7 @@ function parseIntegerOption(args, name) {
|
|
|
72202
72888
|
}
|
|
72203
72889
|
return parsed;
|
|
72204
72890
|
}
|
|
72205
|
-
function
|
|
72891
|
+
function hasFlag4(args, name) {
|
|
72206
72892
|
return args.includes(name);
|
|
72207
72893
|
}
|
|
72208
72894
|
function resolveReplyKind(command) {
|
|
@@ -72234,18 +72920,18 @@ function parseMessageCommand(args) {
|
|
|
72234
72920
|
media: parseOptionValue4(rest, "--media"),
|
|
72235
72921
|
messageId: parseOptionValue4(rest, "--message-id"),
|
|
72236
72922
|
emoji: parseOptionValue4(rest, "--emoji"),
|
|
72237
|
-
remove:
|
|
72923
|
+
remove: hasFlag4(rest, "--remove"),
|
|
72238
72924
|
threadId: parseOptionValue4(rest, "--thread-id"),
|
|
72239
72925
|
replyTo: parseOptionValue4(rest, "--reply-to"),
|
|
72240
72926
|
limit: parseIntegerOption(rest, "--limit"),
|
|
72241
72927
|
query: parseOptionValue4(rest, "--query"),
|
|
72242
72928
|
pollQuestion: parseOptionValue4(rest, "--poll-question"),
|
|
72243
|
-
pollOptions:
|
|
72244
|
-
forceDocument:
|
|
72245
|
-
silent:
|
|
72246
|
-
progress:
|
|
72247
|
-
final:
|
|
72248
|
-
json:
|
|
72929
|
+
pollOptions: parseRepeatedOption3(rest, "--poll-option"),
|
|
72930
|
+
forceDocument: hasFlag4(rest, "--force-document"),
|
|
72931
|
+
silent: hasFlag4(rest, "--silent"),
|
|
72932
|
+
progress: hasFlag4(rest, "--progress"),
|
|
72933
|
+
final: hasFlag4(rest, "--final"),
|
|
72934
|
+
json: hasFlag4(rest, "--json")
|
|
72249
72935
|
};
|
|
72250
72936
|
}
|
|
72251
72937
|
function renderMessageHelp() {
|
|
@@ -72468,6 +73154,7 @@ class RuntimeSupervisor {
|
|
|
72468
73154
|
reloadInFlight = false;
|
|
72469
73155
|
reloadRequested = false;
|
|
72470
73156
|
configWatchDebounceMs = 250;
|
|
73157
|
+
nextRuntimeId = 1;
|
|
72471
73158
|
dependencies;
|
|
72472
73159
|
constructor(configPath, dependencies) {
|
|
72473
73160
|
this.configPath = configPath;
|
|
@@ -72484,15 +73171,50 @@ class RuntimeSupervisor {
|
|
|
72484
73171
|
async start() {
|
|
72485
73172
|
await this.reload("initial");
|
|
72486
73173
|
}
|
|
72487
|
-
async stop() {
|
|
73174
|
+
async stop(options = {}) {
|
|
72488
73175
|
this.clearReloadTimer();
|
|
72489
73176
|
this.stopWatchingConfig();
|
|
72490
73177
|
await this.stopActiveRuntime();
|
|
73178
|
+
if (options.markChannelsStopped !== false) {
|
|
73179
|
+
for (const plugin of this.dependencies.listChannelPlugins()) {
|
|
73180
|
+
await this.dependencies.runtimeHealthStore.setChannel({
|
|
73181
|
+
channel: plugin.id,
|
|
73182
|
+
connection: "stopped",
|
|
73183
|
+
summary: plugin.renderHealthSummary("stopped")
|
|
73184
|
+
});
|
|
73185
|
+
}
|
|
73186
|
+
}
|
|
73187
|
+
}
|
|
73188
|
+
async markFatalFailure(error) {
|
|
73189
|
+
const activeRuntime = this.activeRuntime;
|
|
73190
|
+
if (!activeRuntime) {
|
|
73191
|
+
return;
|
|
73192
|
+
}
|
|
73193
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
73194
|
+
const instancesByChannel = new Map;
|
|
73195
|
+
for (const entry of activeRuntime.channelServices) {
|
|
73196
|
+
const identity = entry.service.getRuntimeIdentity?.();
|
|
73197
|
+
if (!identity) {
|
|
73198
|
+
continue;
|
|
73199
|
+
}
|
|
73200
|
+
const existing = instancesByChannel.get(entry.channel) ?? [];
|
|
73201
|
+
existing.push(identity);
|
|
73202
|
+
instancesByChannel.set(entry.channel, existing);
|
|
73203
|
+
}
|
|
72491
73204
|
for (const plugin of this.dependencies.listChannelPlugins()) {
|
|
73205
|
+
if (!plugin.isEnabled(activeRuntime.loadedConfig)) {
|
|
73206
|
+
continue;
|
|
73207
|
+
}
|
|
72492
73208
|
await this.dependencies.runtimeHealthStore.setChannel({
|
|
72493
73209
|
channel: plugin.id,
|
|
72494
|
-
connection: "
|
|
72495
|
-
summary:
|
|
73210
|
+
connection: "failed",
|
|
73211
|
+
summary: "Runtime crashed due to a fatal error.",
|
|
73212
|
+
detail,
|
|
73213
|
+
actions: [
|
|
73214
|
+
"run `clisbot logs` and inspect the fatal error",
|
|
73215
|
+
"fix the underlying runtime fault, then restart with `clisbot start`"
|
|
73216
|
+
],
|
|
73217
|
+
instances: instancesByChannel.get(plugin.id) ?? []
|
|
72496
73218
|
});
|
|
72497
73219
|
}
|
|
72498
73220
|
}
|
|
@@ -72570,6 +73292,7 @@ class RuntimeSupervisor {
|
|
|
72570
73292
|
}
|
|
72571
73293
|
}
|
|
72572
73294
|
async createRuntime(loadedConfig) {
|
|
73295
|
+
const runtimeId = this.nextRuntimeId++;
|
|
72573
73296
|
const agentService = this.dependencies.createAgentService(loadedConfig);
|
|
72574
73297
|
const processedEventsStore = this.dependencies.createProcessedEventsStore(loadedConfig.processedEventsPath);
|
|
72575
73298
|
const activityStore = this.dependencies.createActivityStore();
|
|
@@ -72591,7 +73314,14 @@ class RuntimeSupervisor {
|
|
|
72591
73314
|
loadedConfig,
|
|
72592
73315
|
agentService,
|
|
72593
73316
|
processedEventsStore,
|
|
72594
|
-
activityStore
|
|
73317
|
+
activityStore,
|
|
73318
|
+
reportLifecycle: (event) => this.reportChannelLifecycle({
|
|
73319
|
+
runtimeId,
|
|
73320
|
+
plugin,
|
|
73321
|
+
channelServices,
|
|
73322
|
+
accountId: account.accountId,
|
|
73323
|
+
event
|
|
73324
|
+
})
|
|
72595
73325
|
}, account)
|
|
72596
73326
|
});
|
|
72597
73327
|
}
|
|
@@ -72622,6 +73352,8 @@ class RuntimeSupervisor {
|
|
|
72622
73352
|
});
|
|
72623
73353
|
}
|
|
72624
73354
|
return {
|
|
73355
|
+
id: runtimeId,
|
|
73356
|
+
loadedConfig,
|
|
72625
73357
|
agentService,
|
|
72626
73358
|
channelServices
|
|
72627
73359
|
};
|
|
@@ -72661,6 +73393,38 @@ class RuntimeSupervisor {
|
|
|
72661
73393
|
});
|
|
72662
73394
|
}
|
|
72663
73395
|
}
|
|
73396
|
+
getChannelInstances(channelServices, channel) {
|
|
73397
|
+
return channelServices.filter((entry) => entry.channel === channel).map((entry) => entry.service.getRuntimeIdentity?.()).filter((identity) => identity != null);
|
|
73398
|
+
}
|
|
73399
|
+
async reportChannelLifecycle(params) {
|
|
73400
|
+
if (this.activeRuntime?.id !== params.runtimeId) {
|
|
73401
|
+
return;
|
|
73402
|
+
}
|
|
73403
|
+
const instances = this.getChannelInstances(params.channelServices, params.plugin.id);
|
|
73404
|
+
if (params.event.connection === "active") {
|
|
73405
|
+
await this.dependencies.runtimeHealthStore.setChannel({
|
|
73406
|
+
channel: params.plugin.id,
|
|
73407
|
+
connection: "active",
|
|
73408
|
+
summary: params.event.summary ?? params.plugin.renderActiveHealthSummary(Math.max(1, instances.length)),
|
|
73409
|
+
detail: params.event.detail,
|
|
73410
|
+
actions: params.event.actions,
|
|
73411
|
+
instances
|
|
73412
|
+
});
|
|
73413
|
+
return;
|
|
73414
|
+
}
|
|
73415
|
+
const detailPrefix = `account=${params.accountId}`;
|
|
73416
|
+
await this.dependencies.runtimeHealthStore.setChannel({
|
|
73417
|
+
channel: params.plugin.id,
|
|
73418
|
+
connection: "failed",
|
|
73419
|
+
summary: params.event.summary ?? `${params.plugin.id} channel failed after startup.`,
|
|
73420
|
+
detail: params.event.detail ? `${detailPrefix}; ${params.event.detail}` : detailPrefix,
|
|
73421
|
+
actions: params.event.actions ?? [
|
|
73422
|
+
"run `clisbot logs` and inspect the latest channel error",
|
|
73423
|
+
"restart `clisbot` after fixing the channel-level issue"
|
|
73424
|
+
],
|
|
73425
|
+
instances
|
|
73426
|
+
});
|
|
73427
|
+
}
|
|
72664
73428
|
async reconcileConfigWatcher(loadedConfig) {
|
|
72665
73429
|
const configReload = loadedConfig.raw.control.configReload;
|
|
72666
73430
|
this.configWatchDebounceMs = configReload.watchDebounceMs;
|
|
@@ -72851,6 +73615,11 @@ async function getRuntimeOperatorSummary(params) {
|
|
|
72851
73615
|
];
|
|
72852
73616
|
return {
|
|
72853
73617
|
loadedConfig,
|
|
73618
|
+
ownerSummary: {
|
|
73619
|
+
ownerPrincipals: loadedConfig.raw.app.auth.roles.owner?.users ?? [],
|
|
73620
|
+
adminPrincipals: loadedConfig.raw.app.auth.roles.admin?.users ?? [],
|
|
73621
|
+
ownerClaimWindowMinutes: loadedConfig.raw.app.auth.ownerClaimWindowMinutes
|
|
73622
|
+
},
|
|
72854
73623
|
agentSummaries,
|
|
72855
73624
|
channelSummaries,
|
|
72856
73625
|
activeRuns: await agentService.listActiveSessionRuntimes(),
|
|
@@ -72932,11 +73701,75 @@ function renderAgentSummaryLines(summary) {
|
|
|
72932
73701
|
})
|
|
72933
73702
|
];
|
|
72934
73703
|
}
|
|
73704
|
+
function renderOwnerSummaryLines(summary) {
|
|
73705
|
+
const ownerPrincipals = summary.ownerSummary.ownerPrincipals;
|
|
73706
|
+
const adminPrincipals = summary.ownerSummary.adminPrincipals;
|
|
73707
|
+
const configuredOwners = ownerPrincipals.length > 0 ? ownerPrincipals.join(",") : "none";
|
|
73708
|
+
const claimWindow = `${summary.ownerSummary.ownerClaimWindowMinutes}m`;
|
|
73709
|
+
const lines = [
|
|
73710
|
+
"Owner:",
|
|
73711
|
+
` - configured=${ownerPrincipals.length > 0 ? "yes" : "no"} principals=${configuredOwners} claimWindow=${claimWindow}`,
|
|
73712
|
+
" - access=full app control, DM pairing bypass, implicit admin across all agents/channels"
|
|
73713
|
+
];
|
|
73714
|
+
if (adminPrincipals.length > 0) {
|
|
73715
|
+
lines.push(` - appAdmins=${adminPrincipals.join(",")}`);
|
|
73716
|
+
}
|
|
73717
|
+
return lines;
|
|
73718
|
+
}
|
|
73719
|
+
function hasConfiguredPrivilegedPrincipal(summary) {
|
|
73720
|
+
return summary.ownerSummary.ownerPrincipals.length > 0 || summary.ownerSummary.adminPrincipals.length > 0;
|
|
73721
|
+
}
|
|
73722
|
+
function renderPrivilegedChatHint(summary, action) {
|
|
73723
|
+
if (hasConfiguredPrivilegedPrincipal(summary)) {
|
|
73724
|
+
return `chat with the bot from that owner/admin account to ${action}`;
|
|
73725
|
+
}
|
|
73726
|
+
return `after you configure an owner/admin principal, use that account to ${action}`;
|
|
73727
|
+
}
|
|
73728
|
+
function appendChannelNextStepLines(lines, summary, prefix = "") {
|
|
73729
|
+
const slackEnabled = summary.channelSummaries.some((channel) => channel.channel === "slack" && channel.enabled);
|
|
73730
|
+
const telegramEnabled = summary.channelSummaries.some((channel) => channel.channel === "telegram" && channel.enabled);
|
|
73731
|
+
const hasEnabledChannel = slackEnabled || telegramEnabled;
|
|
73732
|
+
if (!hasEnabledChannel) {
|
|
73733
|
+
lines.push(`${prefix}- run \`clisbot channels enable <slack|telegram>\` for the first channel you want to expose`);
|
|
73734
|
+
return;
|
|
73735
|
+
}
|
|
73736
|
+
if (telegramEnabled && slackEnabled) {
|
|
73737
|
+
lines.push(`${prefix}- DM the Telegram or Slack bot first to confirm it responds normally`);
|
|
73738
|
+
} else if (telegramEnabled) {
|
|
73739
|
+
lines.push(`${prefix}- DM the Telegram bot first to confirm it responds normally`);
|
|
73740
|
+
} else {
|
|
73741
|
+
lines.push(`${prefix}- DM the Slack bot first to confirm it responds normally`);
|
|
73742
|
+
}
|
|
73743
|
+
lines.push(`${prefix}- after DM works, add the bot to the target Slack channel or Telegram group/topic`);
|
|
73744
|
+
lines.push(`${prefix}- route that surface with \`clisbot channels add slack-channel <channelId> --agent <id>\` or \`clisbot channels add telegram-group <chatId> --agent <id>\``);
|
|
73745
|
+
if (telegramEnabled) {
|
|
73746
|
+
lines.push(`${prefix}- Telegram: send \`/start\` in the target DM, group, or topic to get onboarding or pairing guidance`);
|
|
73747
|
+
}
|
|
73748
|
+
if (slackEnabled) {
|
|
73749
|
+
lines.push(`${prefix}- Slack: mention \`@<botname> \\start\` in the target channel to verify mention flow`);
|
|
73750
|
+
}
|
|
73751
|
+
}
|
|
73752
|
+
function appendAuthOnboardingLines(lines, summary, prefix = "") {
|
|
73753
|
+
lines.push(`${prefix}Auth onboarding:`);
|
|
73754
|
+
if (!hasConfiguredPrivilegedPrincipal(summary)) {
|
|
73755
|
+
lines.push(`${prefix} - get the principal from a surface the bot can already see; Telegram groups or topics can use \`/whoami\` before routing, while DMs with pairing must pair first`);
|
|
73756
|
+
lines.push(`${prefix} - set the first owner with: \`clisbot auth add-user app --role owner --user <principal>\``);
|
|
73757
|
+
} else {
|
|
73758
|
+
lines.push(`${prefix} - inspect current app roles with: \`clisbot auth show app\``);
|
|
73759
|
+
}
|
|
73760
|
+
lines.push(`${prefix} - inspect default agent roles with: \`clisbot auth show agent-defaults\``);
|
|
73761
|
+
lines.push(`${prefix} - add or remove principals with: \`clisbot auth add-user ...\` and \`clisbot auth remove-user ...\``);
|
|
73762
|
+
lines.push(`${prefix} - tune role permissions with: \`clisbot auth add-permission ...\` and \`clisbot auth remove-permission ...\``);
|
|
73763
|
+
lines.push(`${prefix} - run \`clisbot auth --help\` or read docs/user-guide/auth-and-roles.md for scopes and permission names`);
|
|
73764
|
+
}
|
|
72935
73765
|
function renderChannelSummaryLines(summary) {
|
|
72936
73766
|
return [
|
|
72937
73767
|
"",
|
|
72938
73768
|
"Channels:",
|
|
72939
73769
|
...summary.channelSummaries.map((channel) => {
|
|
73770
|
+
if (!channel.enabled) {
|
|
73771
|
+
return ` - ${channel.channel} enabled=no`;
|
|
73772
|
+
}
|
|
72940
73773
|
const last = channel.lastActivityAt ? ` last=${formatTime(channel.lastActivityAt)} via ${channel.lastActivityAgentId ?? "unknown"}` : " last=never";
|
|
72941
73774
|
const dm = ` dm=${channel.directMessagesEnabled ? channel.directMessagesPolicy : "disabled"}`;
|
|
72942
73775
|
const group = channel.groupPolicy ? ` groups=${channel.groupPolicy}` : "";
|
|
@@ -72992,8 +73825,9 @@ function renderRuntimeDiagnosticsSummary(summary) {
|
|
|
72992
73825
|
`).trim();
|
|
72993
73826
|
}
|
|
72994
73827
|
function renderStartSummary(summary) {
|
|
72995
|
-
const configPath = collapseHomePath(getDefaultConfigPath());
|
|
72996
73828
|
const lines = [
|
|
73829
|
+
...renderOwnerSummaryLines(summary),
|
|
73830
|
+
"",
|
|
72997
73831
|
...renderAgentSummaryLines(summary),
|
|
72998
73832
|
...renderChannelSummaryLines(summary)
|
|
72999
73833
|
];
|
|
@@ -73031,7 +73865,10 @@ function renderStartSummary(summary) {
|
|
|
73031
73865
|
lines.push("");
|
|
73032
73866
|
lines.push(" Next steps after bootstrap:");
|
|
73033
73867
|
lines.push(" - chat with the bot or open the workspace, then follow BOOTSTRAP.md");
|
|
73034
|
-
lines
|
|
73868
|
+
appendChannelNextStepLines(lines, summary, " ");
|
|
73869
|
+
lines.push(` - ${renderPrivilegedChatHint(summary, "verify DM access and adjust in-chat settings")}`);
|
|
73870
|
+
lines.push("");
|
|
73871
|
+
appendAuthOnboardingLines(lines, summary, " ");
|
|
73035
73872
|
lines.push(" - run `clisbot status` to recheck runtime and bootstrap state");
|
|
73036
73873
|
lines.push(" - run `clisbot logs` if the bot does not answer as expected");
|
|
73037
73874
|
lines.push(...renderPairingSetupHelpLines(" ", {
|
|
@@ -73049,9 +73886,11 @@ function renderStartSummary(summary) {
|
|
|
73049
73886
|
}
|
|
73050
73887
|
lines.push("");
|
|
73051
73888
|
lines.push("Next steps:");
|
|
73052
|
-
lines
|
|
73053
|
-
lines.push(" - verify
|
|
73054
|
-
lines.push(
|
|
73889
|
+
appendChannelNextStepLines(lines, summary, " ");
|
|
73890
|
+
lines.push(" - verify routes and defaultAgentId values match the agent you want to expose");
|
|
73891
|
+
lines.push(` - ${renderPrivilegedChatHint(summary, "adjust in-chat surface settings")}`);
|
|
73892
|
+
lines.push("");
|
|
73893
|
+
appendAuthOnboardingLines(lines, summary);
|
|
73055
73894
|
lines.push(" - run `clisbot status` to inspect agents, channels, and tmux session state");
|
|
73056
73895
|
lines.push(" - run `clisbot logs` if anything looks wrong");
|
|
73057
73896
|
lines.push(...renderPairingSetupHelpLines("", {
|
|
@@ -73078,20 +73917,24 @@ function appendChannelSetupNotes(lines, summary, prefix = "") {
|
|
|
73078
73917
|
if (channel.channel === "telegram") {
|
|
73079
73918
|
lines.push(`${prefix} - telegram: no explicit group or topic routes are configured yet`);
|
|
73080
73919
|
lines.push(`${prefix} dms: ${channel.directMessagesEnabled ? `enabled (${channel.directMessagesPolicy})` : "disabled"}`);
|
|
73081
|
-
lines.push(`${prefix}
|
|
73082
|
-
lines.push(`${prefix}
|
|
73083
|
-
lines.push(`${prefix}
|
|
73920
|
+
lines.push(`${prefix} add group: \`clisbot channels add telegram-group <chatId> --agent <id>\``);
|
|
73921
|
+
lines.push(`${prefix} add topic: \`clisbot channels add telegram-group <chatId> --topic <topicId> --agent <id>\``);
|
|
73922
|
+
lines.push(`${prefix} adjust later: ${renderPrivilegedChatHint(summary, "run in-chat commands here")}`);
|
|
73084
73923
|
continue;
|
|
73085
73924
|
}
|
|
73086
73925
|
lines.push(`${prefix} - slack: no explicit channel or group routes are configured yet`);
|
|
73087
73926
|
lines.push(`${prefix} dms: ${channel.directMessagesEnabled ? `enabled (${channel.directMessagesPolicy})` : "disabled"}`);
|
|
73088
73927
|
lines.push(`${prefix} groups: ${channel.groupPolicy ?? "n/a"}`);
|
|
73089
|
-
lines.push(`${prefix}
|
|
73928
|
+
lines.push(`${prefix} add channel: \`clisbot channels add slack-channel <channelId> --agent <id>\``);
|
|
73929
|
+
lines.push(`${prefix} add group: \`clisbot channels add slack-group <groupId> --agent <id>\``);
|
|
73930
|
+
lines.push(`${prefix} adjust later: ${renderPrivilegedChatHint(summary, "run in-chat commands here")}`);
|
|
73090
73931
|
}
|
|
73091
73932
|
}
|
|
73092
73933
|
function renderStatusSummary(summary) {
|
|
73093
73934
|
const lines = [
|
|
73094
73935
|
`stats agents=${summary.configuredAgents} bootstrapped=${summary.bootstrappedAgents} pendingBootstrap=${summary.bootstrapPendingAgents} tmuxSessions=${summary.runningTmuxSessions}`,
|
|
73936
|
+
...renderOwnerSummaryLines(summary),
|
|
73937
|
+
"",
|
|
73095
73938
|
...renderAgentSummaryLines(summary),
|
|
73096
73939
|
...renderChannelSummaryLines(summary),
|
|
73097
73940
|
...renderChannelDiagnosticLines(summary),
|
|
@@ -73113,6 +73956,15 @@ function printCommandOutcomeBanner(outcome) {
|
|
|
73113
73956
|
function printCommandOutcomeFooter(outcome) {
|
|
73114
73957
|
printCommandOutcomeBanner(outcome);
|
|
73115
73958
|
}
|
|
73959
|
+
function assertSupportedPlatform(command) {
|
|
73960
|
+
if (process.platform !== "win32") {
|
|
73961
|
+
return;
|
|
73962
|
+
}
|
|
73963
|
+
if (command.name === "help" || command.name === "version") {
|
|
73964
|
+
return;
|
|
73965
|
+
}
|
|
73966
|
+
throw new Error("Native Windows is not supported yet. Run clisbot from WSL2 or use Linux/macOS instead.");
|
|
73967
|
+
}
|
|
73116
73968
|
function getPrimaryWorkspacePath(summary) {
|
|
73117
73969
|
const preferredAgentId = summary.channelSummaries.find((channel) => channel.enabled)?.defaultAgentId ?? "default";
|
|
73118
73970
|
return summary.agentSummaries.find((agent) => agent.id === preferredAgentId)?.workspacePath ?? summary.agentSummaries[0]?.workspacePath;
|
|
@@ -73262,25 +74114,57 @@ async function serveForeground() {
|
|
|
73262
74114
|
const runtimeCredentialsPath = getDefaultRuntimeCredentialsPath();
|
|
73263
74115
|
const runtimeSupervisor = new RuntimeSupervisor(configPath);
|
|
73264
74116
|
let shuttingDown = false;
|
|
73265
|
-
|
|
74117
|
+
let fatalHandling = false;
|
|
74118
|
+
const shutdown = async (exitCode = 0, options = {}) => {
|
|
73266
74119
|
if (shuttingDown) {
|
|
73267
74120
|
return;
|
|
73268
74121
|
}
|
|
73269
74122
|
shuttingDown = true;
|
|
73270
74123
|
try {
|
|
73271
|
-
await runtimeSupervisor.stop(
|
|
74124
|
+
await runtimeSupervisor.stop({
|
|
74125
|
+
markChannelsStopped: options.markChannelsStopped
|
|
74126
|
+
});
|
|
73272
74127
|
} finally {
|
|
73273
74128
|
removeRuntimeCredentials(runtimeCredentialsPath);
|
|
73274
74129
|
removeRuntimePid(pidPath);
|
|
73275
74130
|
process.exit(exitCode);
|
|
73276
74131
|
}
|
|
73277
74132
|
};
|
|
74133
|
+
const handleFatal = async (source, error) => {
|
|
74134
|
+
if (fatalHandling || shuttingDown) {
|
|
74135
|
+
return;
|
|
74136
|
+
}
|
|
74137
|
+
fatalHandling = true;
|
|
74138
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
74139
|
+
const fatalError = new Error(`fatal ${source}: ${detail}`);
|
|
74140
|
+
console.error(`clisbot fatal ${source}`, error);
|
|
74141
|
+
const forceExitTimer = setTimeout(() => {
|
|
74142
|
+
process.exit(1);
|
|
74143
|
+
}, 5000);
|
|
74144
|
+
forceExitTimer.unref?.();
|
|
74145
|
+
try {
|
|
74146
|
+
await runtimeSupervisor.markFatalFailure(fatalError);
|
|
74147
|
+
} catch (markError) {
|
|
74148
|
+
console.error("failed to record fatal runtime health", markError);
|
|
74149
|
+
}
|
|
74150
|
+
try {
|
|
74151
|
+
await shutdown(1, { markChannelsStopped: false });
|
|
74152
|
+
} finally {
|
|
74153
|
+
clearTimeout(forceExitTimer);
|
|
74154
|
+
}
|
|
74155
|
+
};
|
|
73278
74156
|
process.once("SIGINT", () => {
|
|
73279
74157
|
shutdown(0);
|
|
73280
74158
|
});
|
|
73281
74159
|
process.once("SIGTERM", () => {
|
|
73282
74160
|
shutdown(0);
|
|
73283
74161
|
});
|
|
74162
|
+
process.once("uncaughtException", (error) => {
|
|
74163
|
+
handleFatal("uncaughtException", error);
|
|
74164
|
+
});
|
|
74165
|
+
process.once("unhandledRejection", (error) => {
|
|
74166
|
+
handleFatal("unhandledRejection", error);
|
|
74167
|
+
});
|
|
73284
74168
|
try {
|
|
73285
74169
|
await runtimeSupervisor.start();
|
|
73286
74170
|
await writeRuntimePid(pidPath, process.pid);
|
|
@@ -73357,7 +74241,7 @@ async function start(args = []) {
|
|
|
73357
74241
|
console.log(`clisbot is already running with pid: ${result.pid}`);
|
|
73358
74242
|
const workspacePath = getPrimaryWorkspacePath(summary);
|
|
73359
74243
|
if (workspacePath) {
|
|
73360
|
-
console.log(`workspace: ${workspacePath}
|
|
74244
|
+
console.log(`workspace: ${workspacePath}`);
|
|
73361
74245
|
}
|
|
73362
74246
|
console.log(`config: ${result.configPath}`);
|
|
73363
74247
|
console.log(`log: ${result.logPath}`);
|
|
@@ -73389,7 +74273,7 @@ async function start(args = []) {
|
|
|
73389
74273
|
console.log(`clisbot started with pid: ${result.pid}`);
|
|
73390
74274
|
const workspacePath = getPrimaryWorkspacePath(summary);
|
|
73391
74275
|
if (workspacePath) {
|
|
73392
|
-
console.log(`workspace: ${workspacePath}
|
|
74276
|
+
console.log(`workspace: ${workspacePath}`);
|
|
73393
74277
|
}
|
|
73394
74278
|
console.log(`config: ${result.configPath}`);
|
|
73395
74279
|
console.log(`log: ${result.logPath}`);
|
|
@@ -73478,7 +74362,7 @@ async function status() {
|
|
|
73478
74362
|
});
|
|
73479
74363
|
const workspacePath = getPrimaryWorkspacePath(summary);
|
|
73480
74364
|
if (workspacePath) {
|
|
73481
|
-
console.log(`workspace: ${workspacePath}
|
|
74365
|
+
console.log(`workspace: ${workspacePath}`);
|
|
73482
74366
|
}
|
|
73483
74367
|
console.log(`config: ${runtimeStatus.configPath}`);
|
|
73484
74368
|
console.log(`pid file: ${runtimeStatus.pidPath}`);
|
|
@@ -73521,6 +74405,7 @@ async function logs(lines) {
|
|
|
73521
74405
|
} catch {}
|
|
73522
74406
|
}
|
|
73523
74407
|
async function main(command = parseCliArgs(process.argv)) {
|
|
74408
|
+
assertSupportedPlatform(command);
|
|
73524
74409
|
if (command.name === "help") {
|
|
73525
74410
|
console.log(renderCliHelp());
|
|
73526
74411
|
return;
|
|
@@ -73577,6 +74462,10 @@ async function main(command = parseCliArgs(process.argv)) {
|
|
|
73577
74462
|
await runAgentsCli(command.args);
|
|
73578
74463
|
return;
|
|
73579
74464
|
}
|
|
74465
|
+
if (command.name === "auth") {
|
|
74466
|
+
await runAuthCli(command.args);
|
|
74467
|
+
return;
|
|
74468
|
+
}
|
|
73580
74469
|
if (command.name === "pairing") {
|
|
73581
74470
|
await runPairingCli(command.args);
|
|
73582
74471
|
return;
|