oft-agt 0.5.8 → 0.5.10

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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "oft-agt",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "oft-agt",
9
- "version": "0.5.8",
9
+ "version": "0.5.10",
10
10
  "dependencies": {
11
11
  "discord.js": "^14.14.0",
12
12
  "ws": "^8.18.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oft-agt",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -84,15 +84,36 @@ async function executeAdmitted(command, interaction, client, options) {
84
84
  const optionValues = { ...(options.buttonSnapshot?.variables || resolveOptions(command.options, interaction)), ...contextVariables(interaction, client), ...(options.contextVariables || {}) };
85
85
 
86
86
  optionValues.command_name=command.name;
87
- const usesCustomVariables = Boolean(JSON.stringify(command).includes('randomCondition') || referencedVariables(command).length || JSON.stringify(command).includes('"fn":"setVariable"') || JSON.stringify(command).includes('"fn":"deleteVariable"'));
88
- const privateAck = usesCustomVariables || (() => {
89
- function flatten(calls) { return calls.flatMap(call => call.fn !== 'condition' ? [call] : (() => { const args = interpolateOptions(call.args, optionValues); const index = selectConditionBranch(args.kind, args.rules, interaction, options.random); return flatten(index < 0 ? call.otherwise.calls : call.branches[index].calls); })()); }
90
- const firstReply = flatten(command.calls).find(call => call.fn === 'sendMessage' && call.args.sendMode === 'reply' && call.args.replyMode === 'command');
91
- return !firstReply || Boolean(firstReply.args.ephemeral);
92
- })();
87
+ // Visibility belongs to the configured reply, not to its use of variables.
88
+ // Inspect possible first replies without reading variables, running actions
89
+ // or drawing random branches before execution. A private first reply on any
90
+ // path keeps mixed-visibility commands private until their branch is known.
91
+ function firstReplies(calls) {
92
+ const visibility = new Set();
93
+ for (const call of calls) {
94
+ if (call.fn === 'sendMessage' && (call.args.sendMode || 'reply') === 'reply' && (call.args.replyMode || 'command') === 'command') {
95
+ visibility.add(Boolean(call.args.ephemeral));
96
+ return { visibility, fallsThrough: false };
97
+ }
98
+ if (call.fn === 'condition') {
99
+ let branches = [...call.branches, call.otherwise];
100
+ if (call.args.kind !== 'randomCondition' && !referencedVariables(call.args).length) {
101
+ const args = interpolateOptions(call.args, optionValues);
102
+ const index = selectConditionBranch(args.kind, args.rules, interaction);
103
+ branches = [index < 0 ? call.otherwise : call.branches[index]];
104
+ }
105
+ const paths = branches.map(branch => firstReplies(branch.calls));
106
+ for (const path of paths) for (const value of path.visibility) visibility.add(value);
107
+ if (!paths.some(path => path.fallsThrough)) return { visibility, fallsThrough: false };
108
+ }
109
+ }
110
+ return { visibility, fallsThrough: true };
111
+ }
112
+ const { visibility } = firstReplies(command.calls);
113
+ const privateAck = !visibility.size || visibility.has(true);
93
114
  if (!interaction.eventTrigger) await interaction.deferReply(privateAck ? { flags: 64 } : {});
94
115
  if (options.signal.aborted) throw options.signal.reason;
95
- const context = { interaction, client, messages: new Map(options.buttonSnapshot?.messages), channels: new Map(options.buttonSnapshot?.channels), hasCommandReply: false, signal: options.signal || AbortSignal.timeout(870000), variableStore: options.variableStore, variableReplyMode: usesCustomVariables };
116
+ const context = { interaction, client, messages: new Map(options.buttonSnapshot?.messages), channels: new Map(options.buttonSnapshot?.channels), hasCommandReply: false, signal: options.signal || AbortSignal.timeout(870000), variableStore: options.variableStore, ackEphemeral: privateAck };
96
117
  const definitions = options.variableDefinitions || [];
97
118
  const warn = code => options.onWarning?.(code);
98
119
  context.variableOptions = variableRuntimeOptions(context, optionValues, definitions, options.variableStore, warn);
@@ -101,8 +101,18 @@ async function sendMessage(context, parameters) {
101
101
 
102
102
  if (!context.hasCommandReply) {
103
103
 
104
- const message = context.variableReplyMode && !config.ephemeral ? await interaction.followUp({ ...payload, flags: 0 }) : await interaction.editReply(payload);
105
- if (context.variableReplyMode && !config.ephemeral) context.removeDeferredReply = true;
104
+ // Discord treats the first follow-up after a defer as an edit of that
105
+ // acknowledgement, preserving its visibility. Complete it before sending
106
+ // a separate response whose visibility differs from the acknowledgement.
107
+ const differentVisibility = context.ackEphemeral !== undefined
108
+ ? context.ackEphemeral !== config.ephemeral
109
+ : context.variableReplyMode && !config.ephemeral;
110
+ let message;
111
+ if (differentVisibility) {
112
+ await interaction.editReply({ content: '\u200b', embeds: [], components: [] });
113
+ context.removeDeferredReply = true;
114
+ message = await interaction.followUp({ ...payload, flags: config.ephemeral ? 64 : 0 });
115
+ } else message = await interaction.editReply(payload);
106
116
 
107
117
  context.hasCommandReply = true;
108
118
 
package/version.mjs CHANGED
@@ -1 +1 @@
1
- export const AGENT_VERSION = '0.5.8';
1
+ export const AGENT_VERSION = '0.5.10';