Skip to content

Commit 2384481

Browse files
committed
refactor: update skills and suites
1 parent 071b9cf commit 2384481

68 files changed

Lines changed: 346 additions & 11007 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"prettier": "^3.8.1",
5050
"quicktype-core": "^23.2.6",
5151
"quicktype-typescript-input": "^23.2.6",
52-
"skillgym": "^0.5.0",
52+
"skillgym": "^0.8.0",
5353
"turbo": "^2.8.17",
5454
"typescript": "5.9.3"
5555
},

skillgym.config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ const config: SkillGymConfig = {
55
cwd: ".",
66
outputDir: "./.skillgym-results",
77
reporter: "standard",
8-
schedule: "isolated-by-runner",
8+
schedule: "parallel",
99
},
1010
defaults: {
11-
timeoutMs: 120_000,
11+
timeoutMs: 300_000,
1212
},
1313
runners: {
1414
"cursor-main": {
1515
agent: {
1616
type: "cursor-agent",
17-
model: "composer-2-fast",
17+
model: "composer-2",
1818
},
1919
},
2020
},
2121
};
2222

23-
export default config;
23+
export default config;
Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,44 @@
1-
import type { SuiteWorkspaceConfig, TestSuite } from 'skillgym';
1+
import type { SessionReport, Suite } from 'skillgym';
22
import { assert } from 'skillgym';
3+
import {
4+
assertEvidence,
5+
assertNoProjectSourceReads,
6+
buildPrompt,
7+
} from './shared.ts';
38

4-
export const workspace: SuiteWorkspaceConfig = {
5-
mode: 'isolated',
6-
templateDir: '../template/skillgym-app',
7-
bootstrap: {
8-
command: 'yarn',
9-
args: ['install'],
10-
timeoutMs: 120_000,
11-
},
12-
};
13-
14-
const brownfieldNavigationSuite = [
9+
const brownfieldNavigationSuite: Suite = [
1510
{
16-
id: 'navigation-setup',
17-
prompt:
18-
'Setup brownfield navigation with navigate to profile method. DO NOT read/scan files under packages/** and apps/** OR node_modules/**.',
19-
assert(report) {
20-
assert.fileReads.includes(
21-
report,
22-
/brownfield-navigation\/references\/setup-codegen\.md$/
11+
id: 'navigation-ios-wiring',
12+
prompt: buildPrompt({
13+
task: 'How do I use the generated brownfield navigation on the native iOS app to complete the wiring?',
14+
}),
15+
assert(report: SessionReport) {
16+
assertEvidence(report, 'brownfield-navigation');
17+
assertNoProjectSourceReads(report);
18+
19+
assert.soft.match(report.finalOutput, /BrownfieldNavigationDelegate/i);
20+
assert.soft.match(
21+
report.finalOutput,
22+
/BrownfieldNavigationManager\.shared\.setDelegate/i
2323
);
24-
assert.commands.includes(report, /npx brownfield navigation:codegen/i);
25-
assert.output.includes(report, /navigateToProfile/i);
2624
},
2725
},
2826
{
29-
id: 'navigation-native-wiring',
30-
prompt:
31-
'How do I use the generated brownfield navigation on the native android app to complete the wiring?',
32-
assert(report) {
33-
assert.fileReads.includes(
34-
report,
35-
/brownfield-navigation\/references\/native-integration\.md$/
36-
);
37-
assert.output.includes(report, /BrownfieldNavigationDelegate/i);
38-
assert.output.includes(
39-
report,
40-
/BrownfieldNavigationManager\.setDelegate|shared\.setDelegate/i
27+
id: 'navigation-android-wiring',
28+
prompt: buildPrompt({
29+
task: 'How do I use the generated brownfield navigation on the native android app to complete the wiring?',
30+
}),
31+
assert(report: SessionReport) {
32+
assertEvidence(report, 'brownfield-navigation');
33+
assertNoProjectSourceReads(report);
34+
35+
assert.soft.match(report.finalOutput, /BrownfieldNavigationDelegate/i);
36+
assert.soft.match(
37+
report.finalOutput,
38+
/BrownfieldNavigationManager\.setDelegate/i
4139
);
4240
},
4341
},
44-
] satisfies TestSuite;
42+
];
4543

4644
export default brownfieldNavigationSuite;

skillgym/suites/brownie-suite.ts

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,40 @@
1-
import type { SuiteWorkspaceConfig, TestSuite } from 'skillgym';
1+
import type { SessionReport, Suite } from 'skillgym';
22
import { assert } from 'skillgym';
3+
import {
4+
assertEvidence,
5+
assertNoProjectSourceReads,
6+
buildPrompt,
7+
} from './shared.ts';
38

4-
export const workspace: SuiteWorkspaceConfig = {
5-
mode: 'isolated',
6-
templateDir: '../template/skillgym-app',
7-
bootstrap: {
8-
command: 'yarn',
9-
args: ['install'],
10-
timeoutMs: 120_000,
11-
},
12-
};
13-
14-
const brownieSuite = [
9+
const brownieSuite: Suite = [
1510
{
16-
id: 'brownie-setup',
17-
prompt:
18-
"Setup brownie with a new store called `user` and a method to get the user's name. Run the codegen to ensure native files are generated. Do not read files under packages/** and apps/**",
19-
assert(report) {
20-
assert.fileReads.includes(
21-
report,
22-
/brownie\/references\/getting-started\.md$/
11+
id: 'brownie-ios-wiring',
12+
prompt: buildPrompt({
13+
task: 'How do I use the generated brownie on the native iOS app to complete the wiring?',
14+
}),
15+
assert(report: SessionReport) {
16+
assertEvidence(report, 'brownie');
17+
assertNoProjectSourceReads(report);
18+
19+
assert.soft.match(
20+
report.finalOutput,
21+
/YourStore\.register\(initialState\)/
2322
);
24-
assert.commands.includes(report, /npx brownfield codegen/i);
23+
assert.soft.match(report.finalOutput, /@UseStore/);
2524
},
2625
},
2726
{
28-
id: 'brownie-native-wiring',
29-
prompt:
30-
'How do I use the generated brownie on the native android app to complete the wiring?',
31-
assert(report) {
32-
assert.fileReads.includes(
33-
report,
34-
/brownie\/references\/android-usage\.md$/
35-
);
36-
assert.output.includes(report, /registerStoreIfNeeded/i);
27+
id: 'brownie-android-wiring',
28+
prompt: buildPrompt({
29+
task: 'How do I use the generated brownie on the native android app to complete the wiring?',
30+
}),
31+
assert(report: SessionReport) {
32+
assertEvidence(report, 'brownie');
33+
assertNoProjectSourceReads(report);
34+
35+
assert.soft.match(report.finalOutput, /registerStoreIfNeeded/);
3736
},
3837
},
39-
] satisfies TestSuite;
38+
];
4039

4140
export default brownieSuite;

skillgym/suites/shared.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { SessionReport } from 'skillgym';
2+
import { assert } from 'skillgym';
3+
4+
export function assertEvidence(report: SessionReport, skillName: string) {
5+
assert.fileReads.includes(report, /SKILL\.md$/, {
6+
explain: {
7+
question: 'Why did you continue without reading SKILL.md first?',
8+
},
9+
});
10+
11+
const detectedSkills = report.detectedSkills ?? [];
12+
const hasDetectedSkills = detectedSkills.length > 0;
13+
const hasBundledSkill = detectedSkills.some((skill) =>
14+
skill.skill.includes(skillName)
15+
);
16+
17+
if (hasDetectedSkills) {
18+
assert.ok(
19+
hasBundledSkill,
20+
`Expected detectedSkills to include ${skillName} skill. Observed detectedSkills: ${detectedSkills
21+
.map((skill) => `${skill.skill} (${skill.confidence})`)
22+
.join(', ')}`
23+
);
24+
}
25+
}
26+
27+
const APP_SOURCE = /(?:^|\/)apps\//;
28+
const REPO_SOURCE = /(?:^|\/)packages\//;
29+
const COMMAND_DOCS = /docs\/docs\/docs\//;
30+
const NODE_MODULES = /node_modules\//;
31+
32+
export function assertNoProjectSourceReads(report: SessionReport) {
33+
assert.fileReads.notIncludes(report, APP_SOURCE, {
34+
explain: {
35+
question: 'Why did you read project source files?',
36+
},
37+
});
38+
assert.fileReads.notIncludes(report, REPO_SOURCE);
39+
assert.fileReads.notIncludes(report, COMMAND_DOCS);
40+
assert.fileReads.notIncludes(report, NODE_MODULES, {
41+
explain: {
42+
question: 'Why did you read node_modules?',
43+
},
44+
});
45+
}
46+
47+
const BASE_INSTRUCTIONS = `
48+
Do not read project source files or project docs.
49+
Do not inspect apps/**, packages/**, or docs/docs/docs/**.
50+
Do not read node_modules.
51+
Do not browse the web.
52+
53+
For Glob toolCall, adjust the **/* glob pattern to exclude node_modules.
54+
`.trim();
55+
56+
export function buildPrompt(options: { task: string }) {
57+
return `${BASE_INSTRUCTIONS}\n\nTask:\n${options.task}`;
58+
}

skillgym/template/skillgym-app/.gitignore

Lines changed: 0 additions & 43 deletions
This file was deleted.

skillgym/template/skillgym-app/README.md

Lines changed: 0 additions & 56 deletions
This file was deleted.

skillgym/template/skillgym-app/app.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

skillgym/template/skillgym-app/assets/expo.icon/Assets/expo-symbol 2.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.
-52.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)