Skip to content

Commit 1ff3330

Browse files
committed
Merge remote-tracking branch 'origin/main' into host/rehydration-cs-9977
2 parents be2367a + 06f550e commit 1ff3330

35 files changed

Lines changed: 1117 additions & 608 deletions

packages/ai-bot/lib/code-patch-correctness.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export function buildCheckCorrectnessCommandRequests(
6767
if (correctnessCheckAttempt > MAX_CORRECTNESS_FIX_ATTEMPTS) {
6868
continue;
6969
}
70+
let lintIssues = file.lintIssues;
7071
requests.push({
7172
id: `check-${uuidv4()}`,
7273
name: CHECK_CORRECTNESS_COMMAND_NAME,
@@ -78,6 +79,7 @@ export function buildCheckCorrectnessCommandRequests(
7879
roomId: summary.roomId,
7980
targetEventId: summary.targetEventId,
8081
correctnessCheckAttempt,
82+
...(lintIssues !== undefined ? { lintIssues } : {}),
8183
},
8284
},
8385
});

packages/base/command.gts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,19 @@ export class FileContents extends CardDef {
117117
export class SwitchSubmodeInput extends CardDef {
118118
@field submode = contains(StringField);
119119
@field codePath = contains(StringField);
120+
@field createFile = contains(BooleanField);
121+
}
122+
123+
export class SwitchSubmodeResult extends CardDef {
124+
@field codePath = contains(StringField);
120125
}
121126

122127
export class WriteTextFileInput extends CardDef {
123128
@field content = contains(StringField);
124129
@field realm = contains(StringField);
125130
@field path = contains(StringField);
126131
@field overwrite = contains(BooleanField);
132+
@field useNonConflictingFilename = contains(BooleanField);
127133
}
128134

129135
export class CreateInstanceInput extends CardDef {
@@ -198,6 +204,7 @@ export class LintAndFixInput extends CardDef {
198204

199205
export class LintAndFixResult extends CardDef {
200206
@field output = contains(StringField);
207+
@field lintIssues = containsMany(StringField);
201208
}
202209

203210
export class PatchCodeResultField extends FieldDef {
@@ -208,6 +215,7 @@ export class PatchCodeResultField extends FieldDef {
208215
export class PatchCodeCommandResult extends CardDef {
209216
@field patchedContent = contains(StringField);
210217
@field finalFileUrl = contains(StringField);
218+
@field lintIssues = containsMany(StringField);
211219
@field results = containsMany(PatchCodeResultField);
212220
}
213221

@@ -221,6 +229,7 @@ export class CheckCorrectnessInput extends CardDef {
221229
@field targetType = contains(StringField);
222230
@field targetRef = contains(StringField);
223231
@field roomId = contains(StringField);
232+
@field lintIssues = containsMany(StringField);
224233
}
225234

226235
export class CorrectnessResultCard extends CardDef {
@@ -355,7 +364,8 @@ export class CreateListingPRResult extends CardDef {
355364

356365
export class ListingCreateInput extends CardDef {
357366
@field openCardId = contains(StringField);
358-
@field targetRealm = contains(StringField);
367+
@field codeRef = contains(CodeRefField);
368+
@field targetRealm = contains(RealmField);
359369
}
360370

361371
export class ListingCreateResult extends CardDef {

packages/base/matrix-event.gts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ export interface CodePatchResultContent {
354354
context?: BoxelContext;
355355
attachedFiles?: (SerializedFile & { content?: string; error?: string })[];
356356
attachedCards?: (SerializedFile & { content?: string; error?: string })[];
357+
lintIssues?: string[];
357358
};
358359
}
359360

packages/base/menu-items.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
isResolvedCodeRef,
2323
realmURL,
2424
} from '@cardstack/runtime-common';
25+
import { resolveAdoptsFrom } from '@cardstack/runtime-common';
2526

2627
import CodeIcon from '@cardstack/boxel-icons/code';
2728
import ArrowLeft from '@cardstack/boxel-icons/arrow-left';
@@ -156,8 +157,18 @@ export function getDefaultCardMenuItems(
156157
menuItems.push({
157158
label: `Create listing with AI`,
158159
action: async () => {
160+
const codeRef = resolveAdoptsFrom(card);
161+
if (!codeRef) {
162+
throw new Error('Unable to resolve codeRef from card');
163+
}
164+
const targetRealm = card[realmURL]?.href;
165+
if (!targetRealm) {
166+
throw new Error('Unable to determine target realm from card');
167+
}
159168
await new ListingCreateCommand(params.commandContext).execute({
160169
openCardId: cardId,
170+
codeRef,
171+
targetRealm,
161172
});
162173
},
163174
icon: Wand,

packages/catalog-realm/components/post-composer.gts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import GlimmerComponent from '@glimmer/component';
22
import { type BaseDef } from 'https://cardstack.com/base/card-api';
33
import { on } from '@ember/modifier';
44
import { BoxelSelect, BoxelButton } from '@cardstack/boxel-ui/components';
5-
import { type PostType } from '../news-feed/communication-log';
5+
6+
export interface PostType {
7+
value: string;
8+
label: string;
9+
}
610

711
interface PostComposerArgs {
812
Args: {

packages/catalog-realm/news-feed/communication-log.gts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,11 @@ import StringField from 'https://cardstack.com/base/string';
1919
import { not } from '@cardstack/boxel-ui/helpers';
2020

2121
import { Post, EventPost, ReminderPost } from './post';
22-
import { PostComposer } from '../components/post-composer';
22+
import { PostComposer, PostType } from '../components/post-composer';
2323
import { CardList } from '../components/card-list';
2424
import { Author } from './author';
2525
import ProfileEditButton from './components/profile-edit-button';
2626

27-
export interface PostType {
28-
value: string;
29-
label: string;
30-
}
31-
3227
export const POST_TYPES: PostType[] = [
3328
{ value: 'post', label: 'Default' },
3429
{ value: 'event', label: 'Event' },

packages/host/app/commands/check-correctness.ts

Lines changed: 1 addition & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import { service } from '@ember/service';
33
import {
44
isCardDocumentString,
55
isCardErrorJSONAPI,
6-
SupportedMimeType,
76
type CardErrorJSONAPI,
8-
type LintResult,
97
} from '@cardstack/runtime-common';
108

119
import ENV from '@cardstack/host/config/environment';
@@ -16,7 +14,6 @@ import HostBaseCommand from '../lib/host-base-command';
1614

1715
import type CardService from '../services/card-service';
1816
import type CommandService from '../services/command-service';
19-
import type NetworkService from '../services/network';
2017
import type RealmService from '../services/realm';
2118
import type RealmServerService from '../services/realm-server';
2219
import type StoreService from '../services/store';
@@ -32,7 +29,6 @@ export default class CheckCorrectnessCommand extends HostBaseCommand<
3229
@service declare private commandService: CommandService;
3330
@service declare private cardService: CardService;
3431
@service declare private realmServer: RealmServerService;
35-
@service declare private network: NetworkService;
3632

3733
description =
3834
'Run post-change correctness checks for a specific file or card instance.';
@@ -76,7 +72,7 @@ export default class CheckCorrectnessCommand extends HostBaseCommand<
7672
let commandModule = await this.loadCommandModule();
7773
const { CorrectnessResultCard } = commandModule;
7874
let errors: string[] = [];
79-
let lintIssues: string[] = [];
75+
let lintIssues: string[] = input.lintIssues ?? [];
8076

8177
let sizeLimitError = this.cardService.getSizeLimitError(input.targetRef);
8278
if (sizeLimitError) {
@@ -100,9 +96,6 @@ export default class CheckCorrectnessCommand extends HostBaseCommand<
10096

10197
if (targetType === 'file' && input.targetRef.endsWith('.gts')) {
10298
errors = await this.collectModuleErrors(input.targetRef, roomId);
103-
lintIssues = await this.collectLintIssues(input.targetRef);
104-
} else if (targetType === 'file' && this.isLintableFile(input.targetRef)) {
105-
lintIssues = await this.collectLintIssues(input.targetRef);
10699
} else if (targetType === 'card') {
107100
if (!cardId) {
108101
throw new Error('Card correctness checks require a targetRef.');
@@ -268,81 +261,6 @@ export default class CheckCorrectnessCommand extends HostBaseCommand<
268261
}
269262
}
270263

271-
private isLintableFile(targetRef: string): boolean {
272-
let path = targetRef;
273-
try {
274-
path = new URL(targetRef).pathname;
275-
} catch {
276-
// fall back to original targetRef when it's not a URL
277-
}
278-
return /\.(gts|ts)$/.test(path);
279-
}
280-
281-
private async collectLintIssues(targetRef: string): Promise<string[]> {
282-
try {
283-
if (!this.isLintableFile(targetRef)) {
284-
return [];
285-
}
286-
287-
let fileUrl = new URL(targetRef);
288-
let realmURL = this.realm.realmOfURL(fileUrl);
289-
if (!realmURL) {
290-
return [];
291-
}
292-
293-
let { status, content } = await this.cardService.getSource(fileUrl);
294-
if (status !== 200 || !content.trim()) {
295-
return [];
296-
}
297-
298-
let filename = fileUrl.pathname.split('/').pop() || 'input.gts';
299-
let response = await this.network.authedFetch(
300-
`${realmURL.href}_lint?lintMode=lint`,
301-
{
302-
method: 'POST',
303-
body: content,
304-
headers: {
305-
Accept: 'application/json',
306-
'Content-Type': SupportedMimeType.CardSource,
307-
'X-HTTP-Method-Override': 'QUERY',
308-
'X-Filename': filename,
309-
},
310-
},
311-
);
312-
313-
if (!response.ok) {
314-
console.warn(
315-
`CheckCorrectnessCommand: lint request failed for ${targetRef} (${response.status})`,
316-
);
317-
return [];
318-
}
319-
320-
let lintResult: LintResult;
321-
try {
322-
lintResult = (await response.json()) as LintResult;
323-
} catch (error) {
324-
console.warn(
325-
`CheckCorrectnessCommand: unable to parse lint response for ${targetRef}`,
326-
error,
327-
);
328-
return [];
329-
}
330-
331-
let messages = Array.isArray(lintResult?.messages)
332-
? lintResult.messages
333-
: [];
334-
return messages
335-
.map((message) => this.formatLintIssue(message))
336-
.filter((warning) => warning.length > 0);
337-
} catch (error) {
338-
console.warn(
339-
`CheckCorrectnessCommand: lint warning collection failed for ${targetRef}`,
340-
error,
341-
);
342-
return [];
343-
}
344-
}
345-
346264
private async isEmptyFileContent(targetRef: string): Promise<boolean> {
347265
try {
348266
let fileUrl = new URL(targetRef);
@@ -353,31 +271,6 @@ export default class CheckCorrectnessCommand extends HostBaseCommand<
353271
}
354272
}
355273

356-
private formatLintIssue(message: LintResult['messages'][number]): string {
357-
if (!message || typeof message.message !== 'string') {
358-
return '';
359-
}
360-
let trimmedMessage = message.message.trim();
361-
if (!trimmedMessage) {
362-
return '';
363-
}
364-
365-
let location = '';
366-
if (typeof message.line === 'number') {
367-
if (typeof message.column === 'number') {
368-
location = `line ${message.line}:${message.column}`;
369-
} else {
370-
location = `line ${message.line}`;
371-
}
372-
}
373-
374-
let ruleId = message.ruleId ? ` (${message.ruleId})` : '';
375-
if (location) {
376-
return `${location} ${trimmedMessage}${ruleId}`.trim();
377-
}
378-
return `${trimmedMessage}${ruleId}`.trim();
379-
}
380-
381274
private describeCardError(cardId: string, error: CardErrorJSONAPI): string {
382275
let pieces = [error.title, error.message]
383276
.filter((part): part is string => typeof part === 'string')

packages/host/app/commands/lint-and-fix.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SupportedMimeType } from '@cardstack/runtime-common';
55
import type * as BaseCommandModule from 'https://cardstack.com/base/command';
66

77
import HostBaseCommand from '../lib/host-base-command';
8+
import { formatLintIssues } from '../utils/lint-formatting';
89

910
import type NetworkService from '../services/network';
1011

@@ -29,23 +30,21 @@ export default class LintAndFixCommand extends HostBaseCommand<
2930
): Promise<BaseCommandModule.LintAndFixResult> {
3031
let commandModule = await this.loadCommandModule();
3132
const { LintAndFixResult } = commandModule;
32-
let response = await this.network.authedFetch(
33-
`${input.realm}_lint?lintMode=lintAndAutofix`,
34-
{
35-
method: 'POST',
36-
body: input.fileContent,
37-
headers: {
38-
Accept: 'application/json',
39-
'Content-Type': SupportedMimeType.CardSource,
40-
'X-HTTP-Method-Override': 'QUERY',
41-
'X-Filename': input.filename || 'input.gts',
42-
},
33+
let response = await this.network.authedFetch(`${input.realm}_lint`, {
34+
method: 'POST',
35+
body: input.fileContent,
36+
headers: {
37+
Accept: 'application/json',
38+
'Content-Type': SupportedMimeType.CardSource,
39+
'X-HTTP-Method-Override': 'QUERY',
40+
'X-Filename': input.filename || 'input.gts',
4341
},
44-
);
42+
});
4543
if (response.status === 200) {
4644
let result = await response.json();
4745
return new LintAndFixResult({
4846
output: result.output,
47+
lintIssues: formatLintIssues(result?.messages),
4948
});
5049
}
5150
let result = await response.json();

0 commit comments

Comments
 (0)