@theia/ai-ide 1.76.0-next.18 → 1.76.0-next.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,49 +97,80 @@ function parseUserInteractionResult(raw) {
97
97
  }
98
98
  return obj;
99
99
  }
100
+ const JSON_ENCODING_HINT = 'Do not JSON-encode nested values - pass real arrays and objects.';
101
+ function describeType(value) {
102
+ // eslint-disable-next-line no-null/no-null
103
+ if (value === null) {
104
+ return 'null';
105
+ }
106
+ if (Array.isArray(value)) {
107
+ return 'array';
108
+ }
109
+ return typeof value;
110
+ }
111
+ /**
112
+ * Describe the received type, adding the JSON-encoding hint when a string was received where
113
+ * a structured value was expected - by far the most common way agents get these arguments wrong.
114
+ */
115
+ function describeReceived(value) {
116
+ const type = describeType(value);
117
+ return type === 'string' ? `${type}. ${JSON_ENCODING_HINT}` : `${type}.`;
118
+ }
100
119
  function parseUserInteractionArgs(args) {
101
120
  if (!args) {
102
- return undefined;
121
+ return { ok: false, error: 'No arguments were provided.' };
103
122
  }
123
+ let parsed;
104
124
  try {
105
- const parsed = JSON.parse(args);
106
- if (!Array.isArray(parsed.interactions)) {
107
- return undefined;
108
- }
109
- const validSteps = parsed.interactions
110
- .map(parseStep)
111
- .filter((step) => step !== undefined);
112
- if (validSteps.length === 0) {
113
- return undefined;
114
- }
115
- return { interactions: validSteps };
125
+ parsed = JSON.parse(args);
116
126
  }
117
127
  catch {
118
- return undefined;
128
+ return { ok: false, error: 'Arguments are not valid JSON.' };
129
+ }
130
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
131
+ return { ok: false, error: `Arguments must be an object with an "interactions" array, received ${describeReceived(parsed)}` };
132
+ }
133
+ const interactions = parsed.interactions;
134
+ if (!Array.isArray(interactions)) {
135
+ return { ok: false, error: `"interactions" must be an array of step objects, received ${describeReceived(interactions)}` };
136
+ }
137
+ if (interactions.length === 0) {
138
+ return { ok: false, error: '"interactions" must contain at least one step.' };
119
139
  }
140
+ const steps = [];
141
+ for (let index = 0; index < interactions.length; index++) {
142
+ const step = parseStep(interactions[index], index + 1);
143
+ if (!step.ok) {
144
+ return step;
145
+ }
146
+ steps.push(step.step);
147
+ }
148
+ return { ok: true, args: { interactions: steps } };
120
149
  }
121
- function parseStep(raw) {
122
- if (!raw || typeof raw !== 'object') {
123
- return undefined;
150
+ function parseStep(raw, position) {
151
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
152
+ return { ok: false, error: `Step ${position}: expected a step object, received ${describeReceived(raw)}` };
124
153
  }
125
154
  const obj = raw;
126
155
  if (typeof obj.title !== 'string' || typeof obj.message !== 'string') {
127
- return undefined;
156
+ return { ok: false, error: `Step ${position}: "title" and "message" are required strings.` };
128
157
  }
129
- let options;
130
- if (Array.isArray(obj.options)) {
131
- const validOptions = obj.options.filter((opt) => !!opt && typeof opt === 'object'
132
- && typeof opt.text === 'string'
133
- && typeof opt.value === 'string');
134
- options = validOptions.length > 0 ? validOptions : undefined;
158
+ const options = parseOptions(obj.options, position);
159
+ if (!options.ok) {
160
+ return options;
135
161
  }
136
162
  let links;
137
- if (Array.isArray(obj.links)) {
138
- const filtered = obj.links
163
+ // eslint-disable-next-line no-null/no-null
164
+ const rawLinks = obj.links === null ? undefined : obj.links;
165
+ if (Array.isArray(rawLinks)) {
166
+ const filtered = rawLinks
139
167
  .map(normalizeUserInteractionLink)
140
168
  .filter((link) => link !== undefined);
141
169
  links = filtered.length > 0 ? filtered : undefined;
142
170
  }
171
+ else if (rawLinks !== undefined) {
172
+ return { ok: false, error: `Step ${position}: "links" must be an array of link objects, received ${describeReceived(rawLinks)}` };
173
+ }
143
174
  else {
144
175
  const link = normalizeUserInteractionLink(obj.link);
145
176
  if (link) {
@@ -147,12 +178,52 @@ function parseStep(raw) {
147
178
  }
148
179
  }
149
180
  return {
150
- title: obj.title,
151
- message: obj.message,
152
- options,
153
- links
181
+ ok: true,
182
+ step: {
183
+ title: obj.title,
184
+ message: obj.message,
185
+ options: options.options,
186
+ links
187
+ }
154
188
  };
155
189
  }
190
+ /**
191
+ * Validate a step's `options`. An absent or explicitly empty list means the step is
192
+ * informational; anything else must be a fully well-formed array, since a partially
193
+ * dropped option would silently offer the user a different choice than the agent intended.
194
+ */
195
+ function parseOptions(raw, stepPosition) {
196
+ // eslint-disable-next-line no-null/no-null
197
+ if (raw === undefined || raw === null) {
198
+ return { ok: true, options: undefined };
199
+ }
200
+ if (!Array.isArray(raw)) {
201
+ return {
202
+ ok: false,
203
+ error: `Step ${stepPosition}: "options" must be an array of {text, value} objects, received ${describeReceived(raw)}`
204
+ };
205
+ }
206
+ const options = [];
207
+ for (let index = 0; index < raw.length; index++) {
208
+ const candidate = raw[index];
209
+ const obj = candidate;
210
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj) || typeof obj.text !== 'string' || typeof obj.value !== 'string') {
211
+ return {
212
+ ok: false,
213
+ error: `Step ${stepPosition}, option ${index + 1}: "text" and "value" are required strings, received ${describeReceived(candidate)}`
214
+ };
215
+ }
216
+ const option = { text: obj.text, value: obj.value };
217
+ if (typeof obj.description === 'string') {
218
+ option.description = obj.description;
219
+ }
220
+ if (typeof obj.buttonLabel === 'string') {
221
+ option.buttonLabel = obj.buttonLabel;
222
+ }
223
+ options.push(option);
224
+ }
225
+ return { ok: true, options: options.length > 0 ? options : undefined };
226
+ }
156
227
  function normalizeContentRef(ref) {
157
228
  if (typeof ref === 'string') {
158
229
  return ref.length > 0 ? ref : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"user-interaction-tool.js","sourceRoot":"","sources":["../../src/common/user-interaction-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"user-interaction-tool.js","sourceRoot":"","sources":["../../src/common/user-interaction-tool.ts"],"names":[],"mappings":"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"}
@@ -17,185 +17,222 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const chai_1 = require("chai");
19
19
  const user_interaction_tool_1 = require("./user-interaction-tool");
20
+ function expectRejected(input) {
21
+ const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
22
+ (0, chai_1.expect)(result.ok, `expected a rejection but got: ${JSON.stringify(result)}`).to.be.false;
23
+ return result.error;
24
+ }
25
+ function expectAccepted(input) {
26
+ const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
27
+ (0, chai_1.expect)(result.ok, `expected acceptance but got: ${JSON.stringify(result)}`).to.be.true;
28
+ return result.args;
29
+ }
20
30
  describe('parseUserInteractionArgs', () => {
21
- it('should return undefined for undefined input', () => {
22
- (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionArgs)(undefined)).to.be.undefined;
23
- });
24
- it('should return undefined for invalid JSON', () => {
25
- (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionArgs)('not json')).to.be.undefined;
26
- });
27
- it('should return undefined when interactions is missing', () => {
28
- const input = JSON.stringify({ foo: 'bar' });
29
- (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionArgs)(input)).to.be.undefined;
30
- });
31
- it('should return undefined when interactions is not an array', () => {
32
- const input = JSON.stringify({ interactions: 'nope' });
33
- (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionArgs)(input)).to.be.undefined;
34
- });
35
- it('should return undefined when no step is valid', () => {
36
- const input = JSON.stringify({ interactions: [{ foo: 'bar' }, { title: 1 }] });
37
- (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionArgs)(input)).to.be.undefined;
38
- });
39
- it('should drop steps that are missing title or message', () => {
40
- const input = JSON.stringify({
41
- interactions: [
42
- { title: 'Valid', message: 'Hello' },
43
- { title: 'No message' },
44
- { message: 'No title' }
45
- ]
46
- });
47
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
48
- (0, chai_1.expect)(result).to.not.be.undefined;
49
- (0, chai_1.expect)(result.interactions).to.have.length(1);
50
- (0, chai_1.expect)(result.interactions[0].title).to.equal('Valid');
51
- });
52
- it('should accept a step without options (informational)', () => {
53
- const input = JSON.stringify({
54
- interactions: [{ title: 'Info', message: 'Just so you know' }]
31
+ describe('rejecting malformed arguments', () => {
32
+ it('should reject undefined input', () => {
33
+ (0, chai_1.expect)(expectRejected(undefined)).to.match(/no arguments/i);
55
34
  });
56
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
57
- (0, chai_1.expect)(result).to.not.be.undefined;
58
- (0, chai_1.expect)(result.interactions[0].options).to.be.undefined;
59
- });
60
- it('should filter out invalid options within a step', () => {
61
- const input = JSON.stringify({
62
- interactions: [{
63
- title: 'T', message: 'M',
64
- options: [{ text: 'A', value: 'a' }, { bad: true }, { text: 'B', value: 'b' }]
65
- }]
66
- });
67
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
68
- (0, chai_1.expect)(result.interactions[0].options).to.have.length(2);
69
- });
70
- it('should drop options array if no options are valid', () => {
71
- const input = JSON.stringify({
72
- interactions: [{
73
- title: 'T', message: 'M',
74
- options: [{ bad: true }]
75
- }]
76
- });
77
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
78
- (0, chai_1.expect)(result.interactions[0].options).to.be.undefined;
79
- });
80
- it('should normalize singular link into a links array on a step', () => {
81
- const input = JSON.stringify({
82
- interactions: [{
83
- title: 'T', message: 'M',
84
- options: [{ text: 'A', value: 'a' }],
85
- link: { ref: 'src/index.ts' }
86
- }]
87
- });
88
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
89
- (0, chai_1.expect)(result.interactions[0].links).to.deep.equal([{ ref: 'src/index.ts' }]);
90
- });
91
- it('should accept a links array with multiple entries', () => {
92
- const input = JSON.stringify({
93
- interactions: [{
94
- title: 'T', message: 'M',
95
- options: [{ text: 'A', value: 'a' }],
96
- links: [
97
- { ref: 'src/a.ts' },
98
- { ref: 'src/old.ts', rightRef: 'src/new.ts' }
99
- ]
100
- }]
101
- });
102
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
103
- (0, chai_1.expect)(result.interactions[0].links).to.have.length(2);
104
- });
105
- it('should filter out invalid links from a step', () => {
106
- const input = JSON.stringify({
107
- interactions: [{
108
- title: 'T', message: 'M',
109
- options: [{ text: 'A', value: 'a' }],
110
- links: [
111
- { ref: 'src/a.ts' },
112
- { noRef: true },
113
- { ref: '' }
114
- ]
115
- }]
116
- });
117
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
118
- (0, chai_1.expect)(result.interactions[0].links).to.have.length(1);
119
- });
120
- it('should ignore invalid rightRef placeholders and keep multi-step file links', () => {
121
- const emptyRightRefPlaceholder = {
122
- path: '',
123
- gitRef: '',
124
- line: 0,
125
- empty: false,
126
- label: ''
127
- };
128
- const input = JSON.stringify({
129
- interactions: ['README.md', 'package.json', 'CONTRIBUTING.md'].map((path, index) => ({
130
- title: `File link: ${path}`,
131
- message: 'Open the file link.',
132
- links: [{
133
- ref: { path, gitRef: '', line: 1, empty: false, label: '' },
134
- rightRef: emptyRightRefPlaceholder,
135
- label: `Open ${path}`,
136
- autoOpen: index === 0
35
+ it('should reject input that is not valid JSON', () => {
36
+ (0, chai_1.expect)(expectRejected('not json')).to.match(/valid JSON/i);
37
+ });
38
+ it('should reject arguments without an interactions property', () => {
39
+ (0, chai_1.expect)(expectRejected(JSON.stringify({ foo: 'bar' }))).to.match(/"interactions" must be an array of step objects/);
40
+ });
41
+ it('should reject a JSON-encoded argument blob and name the received type', () => {
42
+ const error = expectRejected(JSON.stringify('{"interactions":[{"title":"T","message":"M"}]}'));
43
+ (0, chai_1.expect)(error).to.match(/arguments must be an object with an "interactions" array, received string/i);
44
+ (0, chai_1.expect)(error).to.match(/do not JSON-encode nested values/i);
45
+ });
46
+ it('should reject a top-level array', () => {
47
+ (0, chai_1.expect)(expectRejected('[]')).to.match(/arguments must be an object with an "interactions" array, received array/i);
48
+ });
49
+ it('should reject top-level null', () => {
50
+ (0, chai_1.expect)(expectRejected('null')).to.match(/arguments must be an object with an "interactions" array, received null/i);
51
+ });
52
+ it('should reject a JSON-encoded interactions string and name the received type', () => {
53
+ const error = expectRejected(JSON.stringify({ interactions: '[{"title":"T","message":"M"}]' }));
54
+ (0, chai_1.expect)(error).to.match(/"interactions" must be an array of step objects, received string/);
55
+ (0, chai_1.expect)(error).to.match(/do not JSON-encode nested values/i);
56
+ });
57
+ it('should reject an empty interactions array', () => {
58
+ (0, chai_1.expect)(expectRejected(JSON.stringify({ interactions: [] }))).to.match(/at least one step/);
59
+ });
60
+ it('should reject a step that is missing its message, naming the step position', () => {
61
+ const error = expectRejected(JSON.stringify({
62
+ interactions: [{ title: 'Valid', message: 'Hello' }, { title: 'No message' }]
63
+ }));
64
+ (0, chai_1.expect)(error).to.match(/step 2: "title" and "message" are required strings/i);
65
+ });
66
+ it('should reject a step that is missing its title, naming the step position', () => {
67
+ const error = expectRejected(JSON.stringify({
68
+ interactions: [{ message: 'No title' }]
69
+ }));
70
+ (0, chai_1.expect)(error).to.match(/step 1: "title" and "message" are required strings/i);
71
+ });
72
+ it('should reject a step whose options are a JSON-encoded string', () => {
73
+ const error = expectRejected(JSON.stringify({
74
+ interactions: [{ title: 'Apply fix?', message: 'M', options: '[{"text":"Yes","value":"yes"}]' }]
75
+ }));
76
+ (0, chai_1.expect)(error).to.match(/step 1: "options" must be an array of \{text, value\} objects, received string/i);
77
+ (0, chai_1.expect)(error).to.match(/do not JSON-encode nested values/i);
78
+ });
79
+ it('should reject a step when a single option is malformed, even though others are valid', () => {
80
+ const error = expectRejected(JSON.stringify({
81
+ interactions: [{
82
+ title: 'T', message: 'M',
83
+ options: [{ text: 'A', value: 'a' }, { label: 'B', value: 'b' }, { text: 'C', value: 'c' }]
137
84
  }]
138
- }))
139
- });
140
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
141
- (0, chai_1.expect)(result.interactions.map(step => step.links[0])).to.deep.equal([
142
- { ref: { path: 'README.md', line: 1 }, label: 'Open README.md', autoOpen: true },
143
- { ref: { path: 'package.json', line: 1 }, label: 'Open package.json', autoOpen: false },
144
- { ref: { path: 'CONTRIBUTING.md', line: 1 }, label: 'Open CONTRIBUTING.md', autoOpen: false }
145
- ]);
146
- });
147
- it('should accept multiple steps in order', () => {
148
- const input = JSON.stringify({
149
- interactions: [
150
- { title: 'Overview', message: 'PR summary' },
151
- { title: 'Area 1', message: 'finding', options: [{ text: 'OK', value: 'approve' }] },
152
- { title: 'Area 2', message: 'no findings' }
153
- ]
154
- });
155
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
156
- (0, chai_1.expect)(result.interactions).to.have.length(3);
157
- (0, chai_1.expect)(result.interactions[1].options).to.have.length(1);
158
- (0, chai_1.expect)(result.interactions[2].options).to.be.undefined;
159
- });
160
- it('should preserve buttonLabel in options', () => {
161
- const input = JSON.stringify({
162
- interactions: [{
163
- title: 'T', message: 'M',
164
- options: [{ text: 'Confirm changes', value: 'confirm', buttonLabel: '✅ Confirm' }]
165
- }]
166
- });
167
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
168
- (0, chai_1.expect)(result.interactions[0].options[0].buttonLabel).to.equal('✅ Confirm');
169
- });
170
- it('should reject step links with empty path in object ref', () => {
171
- const input = JSON.stringify({
172
- interactions: [{
173
- title: 'T', message: 'M',
174
- links: [{ ref: { path: '' } }]
175
- }]
176
- });
177
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
178
- (0, chai_1.expect)(result.interactions[0].links).to.be.undefined;
85
+ }));
86
+ (0, chai_1.expect)(error).to.match(/step 1, option 2: "text" and "value" are required strings/i);
87
+ });
88
+ it('should reject options given as an object rather than an array', () => {
89
+ const error = expectRejected(JSON.stringify({
90
+ interactions: [{ title: 'T', message: 'M', options: { text: 'Yes', value: 'yes' } }]
91
+ }));
92
+ (0, chai_1.expect)(error).to.match(/step 1: "options" must be an array of \{text, value\} objects, received object/i);
93
+ });
94
+ it('should reject plain string options and name the received type', () => {
95
+ const error = expectRejected(JSON.stringify({
96
+ interactions: [{ title: 'T', message: 'M', options: ['Yes', 'No'] }]
97
+ }));
98
+ (0, chai_1.expect)(error).to.match(/step 1, option 1: "text" and "value" are required strings, received string/i);
99
+ (0, chai_1.expect)(error).to.match(/do not JSON-encode nested values/i);
100
+ });
101
+ it('should reject a JSON-encoded links string', () => {
102
+ const error = expectRejected(JSON.stringify({
103
+ interactions: [{ title: 'T', message: 'M', links: '[{"ref":"a.ts"}]' }]
104
+ }));
105
+ (0, chai_1.expect)(error).to.match(/step 1: "links" must be an array of link objects, received string/i);
106
+ (0, chai_1.expect)(error).to.match(/do not JSON-encode nested values/i);
107
+ });
108
+ it('should report the offending option position within the offending step', () => {
109
+ const error = expectRejected(JSON.stringify({
110
+ interactions: [
111
+ { title: 'Fine', message: 'M', options: [{ text: 'A', value: 'a' }] },
112
+ { title: 'Broken', message: 'M', options: [{ text: 'A', value: 'a' }, { text: 'B' }] }
113
+ ]
114
+ }));
115
+ (0, chai_1.expect)(error).to.match(/step 2, option 2: "text" and "value" are required strings/i);
116
+ });
179
117
  });
180
- it('should accept step links with EmptyContentRef', () => {
181
- const input = JSON.stringify({
182
- interactions: [{
183
- title: 'T', message: 'M',
184
- links: [{ ref: { empty: true, label: 'New file' } }]
185
- }]
186
- });
187
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
188
- (0, chai_1.expect)(result.interactions[0].links[0].ref).to.deep.equal({ empty: true, label: 'New file' });
118
+ describe('accepting well-formed arguments', () => {
119
+ it('should accept a step without options (informational)', () => {
120
+ const args = expectAccepted(JSON.stringify({
121
+ interactions: [{ title: 'Info', message: 'Just so you know' }]
122
+ }));
123
+ (0, chai_1.expect)(args.interactions[0].options).to.be.undefined;
124
+ });
125
+ it('should accept an explicitly empty options array as informational', () => {
126
+ const args = expectAccepted(JSON.stringify({
127
+ interactions: [{ title: 'Info', message: 'Just so you know', options: [] }]
128
+ }));
129
+ (0, chai_1.expect)(args.interactions[0].options).to.be.undefined;
130
+ });
131
+ it('should accept multiple steps in order', () => {
132
+ const args = expectAccepted(JSON.stringify({
133
+ interactions: [
134
+ { title: 'Overview', message: 'PR summary' },
135
+ { title: 'Area 1', message: 'finding', options: [{ text: 'OK', value: 'approve' }] },
136
+ { title: 'Area 2', message: 'no findings' }
137
+ ]
138
+ }));
139
+ (0, chai_1.expect)(args.interactions).to.have.length(3);
140
+ (0, chai_1.expect)(args.interactions[1].options).to.have.length(1);
141
+ (0, chai_1.expect)(args.interactions[2].options).to.be.undefined;
142
+ });
143
+ it('should preserve buttonLabel and description in options', () => {
144
+ const args = expectAccepted(JSON.stringify({
145
+ interactions: [{
146
+ title: 'T', message: 'M',
147
+ options: [{ text: 'Confirm changes', value: 'confirm', description: 'Applies the patch', buttonLabel: '✅ Confirm' }]
148
+ }]
149
+ }));
150
+ (0, chai_1.expect)(args.interactions[0].options[0].buttonLabel).to.equal('✅ Confirm');
151
+ (0, chai_1.expect)(args.interactions[0].options[0].description).to.equal('Applies the patch');
152
+ });
189
153
  });
190
- it('should accept step links with EmptyContentRef as rightRef', () => {
191
- const input = JSON.stringify({
192
- interactions: [{
193
- title: 'T', message: 'M',
194
- links: [{ ref: 'src/old.ts', rightRef: { empty: true } }]
195
- }]
196
- });
197
- const result = (0, user_interaction_tool_1.parseUserInteractionArgs)(input);
198
- (0, chai_1.expect)(result.interactions[0].links[0].rightRef).to.deep.equal({ empty: true });
154
+ describe('links remain leniently filtered', () => {
155
+ it('should normalize a singular link into a links array on a step', () => {
156
+ const args = expectAccepted(JSON.stringify({
157
+ interactions: [{
158
+ title: 'T', message: 'M',
159
+ options: [{ text: 'A', value: 'a' }],
160
+ link: { ref: 'src/index.ts' }
161
+ }]
162
+ }));
163
+ (0, chai_1.expect)(args.interactions[0].links).to.deep.equal([{ ref: 'src/index.ts' }]);
164
+ });
165
+ it('should accept a links array with multiple entries', () => {
166
+ const args = expectAccepted(JSON.stringify({
167
+ interactions: [{
168
+ title: 'T', message: 'M',
169
+ links: [{ ref: 'a.ts' }, { ref: 'b.ts', label: 'B' }]
170
+ }]
171
+ }));
172
+ (0, chai_1.expect)(args.interactions[0].links).to.have.length(2);
173
+ });
174
+ it('should drop invalid links from a step without rejecting the step', () => {
175
+ const args = expectAccepted(JSON.stringify({
176
+ interactions: [{
177
+ title: 'T', message: 'M',
178
+ links: [{ ref: 'a.ts' }, { nope: true }, { ref: 42 }]
179
+ }]
180
+ }));
181
+ (0, chai_1.expect)(args.interactions[0].links).to.have.length(1);
182
+ });
183
+ it('should ignore invalid rightRef placeholders and keep multi-step file links', () => {
184
+ const emptyRightRefPlaceholder = {
185
+ path: '',
186
+ gitRef: '',
187
+ line: 0,
188
+ empty: false,
189
+ label: ''
190
+ };
191
+ const args = expectAccepted(JSON.stringify({
192
+ interactions: ['README.md', 'package.json', 'CONTRIBUTING.md'].map((path, index) => ({
193
+ title: `File link: ${path}`,
194
+ message: 'Open the file link.',
195
+ links: [{
196
+ ref: { path, gitRef: '', line: 1, empty: false, label: '' },
197
+ rightRef: emptyRightRefPlaceholder,
198
+ label: `Open ${path}`,
199
+ autoOpen: index === 0
200
+ }]
201
+ }))
202
+ }));
203
+ (0, chai_1.expect)(args.interactions.map(step => step.links[0])).to.deep.equal([
204
+ { ref: { path: 'README.md', line: 1 }, label: 'Open README.md', autoOpen: true },
205
+ { ref: { path: 'package.json', line: 1 }, label: 'Open package.json', autoOpen: false },
206
+ { ref: { path: 'CONTRIBUTING.md', line: 1 }, label: 'Open CONTRIBUTING.md', autoOpen: false }
207
+ ]);
208
+ });
209
+ it('should drop a link whose object ref has an empty path', () => {
210
+ const args = expectAccepted(JSON.stringify({
211
+ interactions: [{
212
+ title: 'T', message: 'M',
213
+ links: [{ ref: { path: '' } }]
214
+ }]
215
+ }));
216
+ (0, chai_1.expect)(args.interactions[0].links).to.be.undefined;
217
+ });
218
+ it('should accept step links with EmptyContentRef', () => {
219
+ const args = expectAccepted(JSON.stringify({
220
+ interactions: [{
221
+ title: 'T', message: 'M',
222
+ links: [{ ref: { empty: true, label: 'New file' } }]
223
+ }]
224
+ }));
225
+ (0, chai_1.expect)(args.interactions[0].links[0].ref).to.deep.equal({ empty: true, label: 'New file' });
226
+ });
227
+ it('should accept step links with EmptyContentRef as rightRef', () => {
228
+ const args = expectAccepted(JSON.stringify({
229
+ interactions: [{
230
+ title: 'T', message: 'M',
231
+ links: [{ ref: 'src/old.ts', rightRef: { empty: true } }]
232
+ }]
233
+ }));
234
+ (0, chai_1.expect)(args.interactions[0].links[0].rightRef).to.deep.equal({ empty: true });
235
+ });
199
236
  });
200
237
  });
201
238
  describe('parseUserInteractionInput', () => {
@@ -217,6 +254,10 @@ describe('parseUserInteractionInput', () => {
217
254
  const input = '{"interactions": [{"title": "Streaming Title", "message": "incom';
218
255
  (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionInput)(input).title).to.equal('Streaming Title');
219
256
  });
257
+ it('should extract a partial title from JSON truncated mid-title', () => {
258
+ const input = '{"interactions":[{"title":"Streaming ti';
259
+ (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionInput)(input)).to.deep.equal({ title: 'Streaming ti', stepCount: 0 });
260
+ });
220
261
  it('should return empty title from incomplete JSON without title field', () => {
221
262
  const input = '{"interactions": [{"message": "no title here';
222
263
  (0, chai_1.expect)((0, user_interaction_tool_1.parseUserInteractionInput)(input).title).to.equal('');