@ethlete/agent-rules 0.1.0-next.0
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/CHANGELOG.md +23 -0
- package/README.md +106 -0
- package/content/defaults.json +10 -0
- package/content/rules/comments.md +31 -0
- package/content/rules/lint-and-format.md +26 -0
- package/content/rules/reactive-state.md +15 -0
- package/content/rules/styling.md +35 -0
- package/content/skills/angular-patterns/SKILL.md +60 -0
- package/content/skills/git-commit/SKILL.md +29 -0
- package/content/skills/handoff/SKILL.md +98 -0
- package/content/skills/query/SKILL.md +114 -0
- package/content/skills/rxjs-signals/SKILL.md +65 -0
- package/content/skills/sdk-docs/SKILL.md +70 -0
- package/content/skills/story-styling/SKILL.md +83 -0
- package/content/skills/styleguide/SKILL.md +66 -0
- package/content/skills/styleguide/STYLEGUIDE.md +520 -0
- package/content/skills/theming/SKILL.md +110 -0
- package/content/skills/verify-in-storybook/SKILL.md +78 -0
- package/content/skills/verify-in-storybook/verify-template.mjs +42 -0
- package/package.json +15 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +79 -0
- package/src/index.js.map +1 -0
- package/src/lib/config.d.ts +21 -0
- package/src/lib/config.js +54 -0
- package/src/lib/config.js.map +1 -0
- package/src/lib/filter.d.ts +16 -0
- package/src/lib/filter.js +49 -0
- package/src/lib/filter.js.map +1 -0
- package/src/lib/frontmatter.d.ts +23 -0
- package/src/lib/frontmatter.js +117 -0
- package/src/lib/frontmatter.js.map +1 -0
- package/src/lib/index.d.ts +9 -0
- package/src/lib/index.js +13 -0
- package/src/lib/index.js.map +1 -0
- package/src/lib/load-content.d.ts +19 -0
- package/src/lib/load-content.js +79 -0
- package/src/lib/load-content.js.map +1 -0
- package/src/lib/owned-paths.d.ts +7 -0
- package/src/lib/owned-paths.js +47 -0
- package/src/lib/owned-paths.js.map +1 -0
- package/src/lib/plan.d.ts +20 -0
- package/src/lib/plan.js +57 -0
- package/src/lib/plan.js.map +1 -0
- package/src/lib/render.d.ts +39 -0
- package/src/lib/render.js +73 -0
- package/src/lib/render.js.map +1 -0
- package/src/lib/sync.d.ts +9 -0
- package/src/lib/sync.js +90 -0
- package/src/lib/sync.js.map +1 -0
- package/src/lib/targets/claude.d.ts +7 -0
- package/src/lib/targets/claude.js +46 -0
- package/src/lib/targets/claude.js.map +1 -0
- package/src/lib/targets/codex.d.ts +11 -0
- package/src/lib/targets/codex.js +26 -0
- package/src/lib/targets/codex.js.map +1 -0
- package/src/lib/targets/copilot.d.ts +11 -0
- package/src/lib/targets/copilot.js +43 -0
- package/src/lib/targets/copilot.js.map +1 -0
- package/src/lib/targets/cursor.d.ts +7 -0
- package/src/lib/targets/cursor.js +35 -0
- package/src/lib/targets/cursor.js.map +1 -0
- package/src/lib/targets/neutral.d.ts +8 -0
- package/src/lib/targets/neutral.js +29 -0
- package/src/lib/targets/neutral.js.map +1 -0
- package/src/lib/targets/shared.d.ts +60 -0
- package/src/lib/targets/shared.js +50 -0
- package/src/lib/targets/shared.js.map +1 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verify-in-storybook
|
|
3
|
+
description: Visually/behaviorally verify a component change by driving its Storybook story headlessly with Playwright. Use whenever you change a UI component and need to confirm the rendered DOM, computed styles, animations, or interactions actually work - not just that it compiles.
|
|
4
|
+
kind: skill
|
|
5
|
+
scope: consumer
|
|
6
|
+
vars: [storybookUrl, storybookStartCommand]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Verify a component change in Storybook (headless Playwright)
|
|
10
|
+
|
|
11
|
+
Storybook is the ground truth for component behaviour. Drive the real story in a
|
|
12
|
+
headless browser and assert on the rendered DOM / computed styles, rather than
|
|
13
|
+
trusting a build alone.
|
|
14
|
+
|
|
15
|
+
## 1. Make sure Storybook is running
|
|
16
|
+
|
|
17
|
+
It is usually already up. Check first - **do not blindly start a second
|
|
18
|
+
instance**, it will hit an interactive port prompt and hang:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
curl -s -o /dev/null -w "%{http_code}" {%storybookUrl%}/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `200` → it's up, proceed.
|
|
25
|
+
- anything else → start it in the background and wait for the port:
|
|
26
|
+
```bash
|
|
27
|
+
{%storybookStartCommand%}
|
|
28
|
+
```
|
|
29
|
+
Run it in the background and poll the curl above until it returns `200`
|
|
30
|
+
(a cold start can take 30–60s).
|
|
31
|
+
|
|
32
|
+
## 2. Find the story ID
|
|
33
|
+
|
|
34
|
+
Story IDs are derived from the story `title` + export name, e.g.
|
|
35
|
+
`Components/Tabs/Inline` → `components-tabs-inline--default`. List them from the
|
|
36
|
+
index:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -s {%storybookUrl%}/index.json \
|
|
40
|
+
| node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const j=JSON.parse(d);Object.values(j.entries).filter(s=>/YOURFILTER/i.test(s.title)).forEach(s=>console.log(s.id,'::',s.title,'::',s.name))})"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 3. Open the story headlessly
|
|
44
|
+
|
|
45
|
+
Render a single story in isolation via the **iframe URL** (no manager chrome):
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
{%storybookUrl%}/iframe.html?id=<story-id>&viewMode=story
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 4. Drive it with Playwright
|
|
52
|
+
|
|
53
|
+
Playwright must be in the repo's devDependencies (`@playwright/test` /
|
|
54
|
+
`playwright`). Write the script in a scratch directory, resolve Playwright from
|
|
55
|
+
the repo's `node_modules`, and run it - {%resource:verify-template.mjs%} is a
|
|
56
|
+
copy-paste starting point.
|
|
57
|
+
|
|
58
|
+
Gotchas that will waste your time if you forget them:
|
|
59
|
+
|
|
60
|
+
- **`playwright` is CommonJS.** In an `.mjs`, resolve it with `createRequire`
|
|
61
|
+
(as the template does) - a named `import { chromium } from 'playwright'` fails.
|
|
62
|
+
- **Use `waitUntil: 'domcontentloaded'`**, never `networkidle` - Storybook's HMR
|
|
63
|
+
websocket keeps the connection open so `networkidle` times out forever.
|
|
64
|
+
- **`waitForSelector` defaults to `state: 'visible'`.** Elements that are
|
|
65
|
+
correctly hidden (`visibility:hidden`, `opacity:0`, collapsed height, `inert`)
|
|
66
|
+
will never become "visible" and you'll get a misleading timeout. Use
|
|
67
|
+
`{ state: 'attached' }` when you intend to inspect a hidden element.
|
|
68
|
+
- **Assert on the real signal.** Portal/`ng-content` text lands as text nodes, so
|
|
69
|
+
`childElementCount` is 0 even when content is present - check `el.textContent`.
|
|
70
|
+
Read computed styles with `getComputedStyle(el)` inside `page.$eval`.
|
|
71
|
+
- After a click that triggers a CSS transition, `waitForTimeout(transitionMs + buffer)`
|
|
72
|
+
before reading final-state styles.
|
|
73
|
+
|
|
74
|
+
## 5. Report
|
|
75
|
+
|
|
76
|
+
State plainly what you drove and observed (collapsed→open→collapsed, tab switch,
|
|
77
|
+
etc.) and whether it matched the expected behaviour. Keep the throwaway script in
|
|
78
|
+
the scratch directory, not the repo.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Headless Storybook verification template.
|
|
2
|
+
// Copy into a scratch directory, adjust STORY_ID + the assertions, then run:
|
|
3
|
+
// node <scratch>/verify.mjs
|
|
4
|
+
//
|
|
5
|
+
// Playwright is CommonJS and lives in the repo's node_modules, so resolve it
|
|
6
|
+
// through createRequire from the repo root rather than importing it by name.
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
|
|
9
|
+
const require = createRequire(`${process.cwd()}/`);
|
|
10
|
+
const { chromium } = require('playwright');
|
|
11
|
+
|
|
12
|
+
const STORY_ID = 'components-button--default'; // <-- change me
|
|
13
|
+
const url = `{%storybookUrl%}/iframe.html?viewMode=story&id=${STORY_ID}`;
|
|
14
|
+
|
|
15
|
+
const browser = await chromium.launch(); // headless by default
|
|
16
|
+
const page = await browser.newPage({ viewport: { width: 900, height: 700 } });
|
|
17
|
+
|
|
18
|
+
// domcontentloaded, NOT networkidle (Storybook's HMR socket never goes idle)
|
|
19
|
+
await page.goto(url, { waitUntil: 'domcontentloaded' });
|
|
20
|
+
|
|
21
|
+
// state:'attached' so intentionally-hidden elements don't time out on 'visible'
|
|
22
|
+
await page.waitForSelector('.et-some-component', { state: 'attached' });
|
|
23
|
+
|
|
24
|
+
// Inspect rendered DOM + computed styles. textContent (not childElementCount)
|
|
25
|
+
// is the reliable signal for ng-content / portal-projected text.
|
|
26
|
+
const state = await page.$eval('.et-some-component', (el) => {
|
|
27
|
+
const cs = getComputedStyle(el);
|
|
28
|
+
return {
|
|
29
|
+
visibility: cs.visibility,
|
|
30
|
+
opacity: cs.opacity,
|
|
31
|
+
height: el.offsetHeight,
|
|
32
|
+
text: el.textContent.trim(),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
console.log('state:', JSON.stringify(state));
|
|
36
|
+
|
|
37
|
+
// Example interaction: click, wait out a CSS transition, re-read.
|
|
38
|
+
// await page.click('.et-some-trigger');
|
|
39
|
+
// await page.waitForTimeout(500); // >= transition duration
|
|
40
|
+
// console.log('after:', JSON.stringify(await page.$eval('.et-some-component', ...)));
|
|
41
|
+
|
|
42
|
+
await browser.close();
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ethlete/agent-rules",
|
|
3
|
+
"version": "0.1.0-next.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"typings": "./src/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ethlete-agents": "./src/index.js"
|
|
10
|
+
},
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"tslib": "2.8.1"
|
|
13
|
+
},
|
|
14
|
+
"types": "./src/index.d.ts"
|
|
15
|
+
}
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const config_1 = require("./lib/config");
|
|
8
|
+
const sync_1 = require("./lib/sync");
|
|
9
|
+
const USAGE = `ethlete-agents — compile @ethlete agent rules and skills into your repo
|
|
10
|
+
|
|
11
|
+
ethlete-agents sync Write the generated rules/skills for every detected agent
|
|
12
|
+
ethlete-agents check Exit non-zero when the generated files are out of date (for CI)
|
|
13
|
+
ethlete-agents init Write a starter ${config_1.CONFIG_FILE_NAME}
|
|
14
|
+
|
|
15
|
+
Options
|
|
16
|
+
--targets <list> Comma-separated subset of: ${config_1.AGENT_TARGETS.join(', ')}
|
|
17
|
+
--root <path> Repo root to write into (default: current directory)
|
|
18
|
+
--dry-run Print what sync would change without writing (sync only)
|
|
19
|
+
`;
|
|
20
|
+
const readFlag = (args, flag) => {
|
|
21
|
+
const index = args.indexOf(flag);
|
|
22
|
+
if (index === -1)
|
|
23
|
+
return undefined;
|
|
24
|
+
return args[index + 1];
|
|
25
|
+
};
|
|
26
|
+
const parseTargets = (args) => {
|
|
27
|
+
const raw = readFlag(args, '--targets');
|
|
28
|
+
if (!raw)
|
|
29
|
+
return undefined;
|
|
30
|
+
return raw.split(',').map((entry) => entry.trim());
|
|
31
|
+
};
|
|
32
|
+
const readVersion = () => {
|
|
33
|
+
const manifest = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'package.json'), 'utf8'));
|
|
34
|
+
return manifest.version;
|
|
35
|
+
};
|
|
36
|
+
const init = (root) => {
|
|
37
|
+
const path = (0, path_1.join)(root, config_1.CONFIG_FILE_NAME);
|
|
38
|
+
if ((0, fs_1.existsSync)(path)) {
|
|
39
|
+
console.error(`${config_1.CONFIG_FILE_NAME} already exists.`);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
const template = {
|
|
43
|
+
targets: (0, config_1.detectTargets)(root),
|
|
44
|
+
vars: {},
|
|
45
|
+
exclude: [],
|
|
46
|
+
};
|
|
47
|
+
(0, fs_1.writeFileSync)(path, `${JSON.stringify(template, null, 2)}\n`, 'utf8');
|
|
48
|
+
console.log(`Wrote ${config_1.CONFIG_FILE_NAME}. Fill in "vars" for your repo, then run \`ethlete-agents sync\`.`);
|
|
49
|
+
return 0;
|
|
50
|
+
};
|
|
51
|
+
const run = (argv) => {
|
|
52
|
+
var _a;
|
|
53
|
+
const command = argv[0];
|
|
54
|
+
const root = (_a = readFlag(argv, '--root')) !== null && _a !== void 0 ? _a : process.cwd();
|
|
55
|
+
const options = { root, version: readVersion(), targets: parseTargets(argv) };
|
|
56
|
+
switch (command) {
|
|
57
|
+
case 'sync':
|
|
58
|
+
return (0, sync_1.sync)(Object.assign(Object.assign({}, options), { dryRun: argv.includes('--dry-run') }));
|
|
59
|
+
case 'check':
|
|
60
|
+
return (0, sync_1.check)(options);
|
|
61
|
+
case 'init':
|
|
62
|
+
return init(root);
|
|
63
|
+
default:
|
|
64
|
+
console.log(USAGE);
|
|
65
|
+
return command === undefined || command === '--help' || command === '-h' ? 0 : 1;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
tslib_1.__exportStar(require("./lib"), exports);
|
|
69
|
+
// Guarded so the package can also be imported as a library without running the CLI.
|
|
70
|
+
if (require.main === module) {
|
|
71
|
+
try {
|
|
72
|
+
process.exit(run(process.argv.slice(2)));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error(error instanceof Error ? error.message : error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/agent-rules/src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ContentScope } from './frontmatter';
|
|
2
|
+
export declare const AGENT_TARGETS: readonly ["claude", "codex", "cursor", "copilot"];
|
|
3
|
+
export type AgentTarget = (typeof AGENT_TARGETS)[number];
|
|
4
|
+
export declare const CONFIG_FILE_NAME = "ethlete-agents.config.json";
|
|
5
|
+
export type SyncConfig = {
|
|
6
|
+
root: string;
|
|
7
|
+
targets: AgentTarget[];
|
|
8
|
+
/** Scopes to emit: a consumer repo wants `consumer` + `both`, the SDK repo only `both`. */
|
|
9
|
+
scopes: ContentScope[];
|
|
10
|
+
vars: Record<string, string | string[]>;
|
|
11
|
+
exclude: string[];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Emit for the agents a repo already uses. Everything falls back to Codex's `AGENTS.md`,
|
|
15
|
+
* which Cursor, Copilot and most other agents read as well.
|
|
16
|
+
*/
|
|
17
|
+
export declare const detectTargets: (root: string) => AgentTarget[];
|
|
18
|
+
export declare const loadConfig: (options: {
|
|
19
|
+
root: string;
|
|
20
|
+
targetOverride?: AgentTarget[];
|
|
21
|
+
}) => SyncConfig;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfig = exports.detectTargets = exports.CONFIG_FILE_NAME = exports.AGENT_TARGETS = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const load_content_1 = require("./load-content");
|
|
7
|
+
exports.AGENT_TARGETS = ['claude', 'codex', 'cursor', 'copilot'];
|
|
8
|
+
exports.CONFIG_FILE_NAME = 'ethlete-agents.config.json';
|
|
9
|
+
const readRawConfig = (root) => {
|
|
10
|
+
const path = (0, path_1.join)(root, exports.CONFIG_FILE_NAME);
|
|
11
|
+
if (!(0, fs_1.existsSync)(path))
|
|
12
|
+
return {};
|
|
13
|
+
return JSON.parse((0, fs_1.readFileSync)(path, 'utf8'));
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Emit for the agents a repo already uses. Everything falls back to Codex's `AGENTS.md`,
|
|
17
|
+
* which Cursor, Copilot and most other agents read as well.
|
|
18
|
+
*/
|
|
19
|
+
const detectTargets = (root) => {
|
|
20
|
+
const detected = [];
|
|
21
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, '.claude')))
|
|
22
|
+
detected.push('claude');
|
|
23
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, 'AGENTS.md')) || (0, fs_1.existsSync)((0, path_1.join)(root, '.codex')))
|
|
24
|
+
detected.push('codex');
|
|
25
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, '.cursor')))
|
|
26
|
+
detected.push('cursor');
|
|
27
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, '.github')))
|
|
28
|
+
detected.push('copilot');
|
|
29
|
+
return detected.length > 0 ? detected : ['codex'];
|
|
30
|
+
};
|
|
31
|
+
exports.detectTargets = detectTargets;
|
|
32
|
+
const assertKnownTargets = (targets) => {
|
|
33
|
+
const unknown = targets.filter((target) => !exports.AGENT_TARGETS.includes(target));
|
|
34
|
+
if (unknown.length > 0) {
|
|
35
|
+
throw new Error(`Unknown target(s): ${unknown.join(', ')}. Known targets: ${exports.AGENT_TARGETS.join(', ')}.`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const loadConfig = (options) => {
|
|
39
|
+
var _a, _b, _c;
|
|
40
|
+
const { root, targetOverride } = options;
|
|
41
|
+
const raw = readRawConfig(root);
|
|
42
|
+
const configured = raw.targets && raw.targets !== 'auto' ? raw.targets : undefined;
|
|
43
|
+
const targets = (_a = targetOverride !== null && targetOverride !== void 0 ? targetOverride : configured) !== null && _a !== void 0 ? _a : (0, exports.detectTargets)(root);
|
|
44
|
+
assertKnownTargets(targets);
|
|
45
|
+
return {
|
|
46
|
+
root,
|
|
47
|
+
targets,
|
|
48
|
+
scopes: raw.profile === 'sdk' ? ['both'] : ['consumer', 'both'],
|
|
49
|
+
vars: Object.assign(Object.assign({}, (0, load_content_1.loadDefaultVars)()), ((_b = raw.vars) !== null && _b !== void 0 ? _b : {})),
|
|
50
|
+
exclude: (_c = raw.exclude) !== null && _c !== void 0 ? _c : [],
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
exports.loadConfig = loadConfig;
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SyncConfig } from './config';
|
|
2
|
+
import { ContentItem } from './load-content';
|
|
3
|
+
export type SkippedItem = {
|
|
4
|
+
name: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
};
|
|
7
|
+
export type FilterResult = {
|
|
8
|
+
kept: ContentItem[];
|
|
9
|
+
skipped: SkippedItem[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A hoisted `node_modules` entry counts as installed even when the dependency is declared in a
|
|
13
|
+
* workspace package rather than at the root, so monorepo consumers are not silently filtered out.
|
|
14
|
+
*/
|
|
15
|
+
export declare const isPackageInstalled: (root: string, packageName: string) => boolean;
|
|
16
|
+
export declare const filterContent: (items: ContentItem[], config: SyncConfig) => FilterResult;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterContent = exports.isPackageInstalled = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
/**
|
|
7
|
+
* A hoisted `node_modules` entry counts as installed even when the dependency is declared in a
|
|
8
|
+
* workspace package rather than at the root, so monorepo consumers are not silently filtered out.
|
|
9
|
+
*/
|
|
10
|
+
const isPackageInstalled = (root, packageName) => {
|
|
11
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(root, 'node_modules', ...packageName.split('/'))))
|
|
12
|
+
return true;
|
|
13
|
+
const manifestPath = (0, path_1.join)(root, 'package.json');
|
|
14
|
+
if (!(0, fs_1.existsSync)(manifestPath))
|
|
15
|
+
return false;
|
|
16
|
+
const manifest = JSON.parse((0, fs_1.readFileSync)(manifestPath, 'utf8'));
|
|
17
|
+
const declared = Object.assign(Object.assign(Object.assign({}, manifest.dependencies), manifest.devDependencies), manifest.peerDependencies);
|
|
18
|
+
return Object.prototype.hasOwnProperty.call(declared, packageName);
|
|
19
|
+
};
|
|
20
|
+
exports.isPackageInstalled = isPackageInstalled;
|
|
21
|
+
const filterContent = (items, config) => {
|
|
22
|
+
const kept = [];
|
|
23
|
+
const skipped = [];
|
|
24
|
+
for (const item of items) {
|
|
25
|
+
const { name, scope, requires, vars } = item.frontmatter;
|
|
26
|
+
if (config.exclude.includes(name)) {
|
|
27
|
+
skipped.push({ name, reason: 'excluded by config' });
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!config.scopes.includes(scope)) {
|
|
31
|
+
skipped.push({ name, reason: `scope "${scope}" is not emitted for this profile` });
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const missingPackage = requires.find((packageName) => !(0, exports.isPackageInstalled)(config.root, packageName));
|
|
35
|
+
if (missingPackage) {
|
|
36
|
+
skipped.push({ name, reason: `requires ${missingPackage}, which is not installed` });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const missingVar = vars.find((varName) => config.vars[varName] === undefined);
|
|
40
|
+
if (missingVar) {
|
|
41
|
+
skipped.push({ name, reason: `needs the "${missingVar}" variable — set it in vars` });
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
kept.push(item);
|
|
45
|
+
}
|
|
46
|
+
return { kept, skipped };
|
|
47
|
+
};
|
|
48
|
+
exports.filterContent = filterContent;
|
|
49
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/filter.ts"],"names":[],"mappings":";;;AAAA,2BAA8C;AAC9C,+BAA4B;AAoB5B;;;GAGG;AACI,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAE,WAAmB,EAAE,EAAE;IACtE,IAAI,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnF,MAAM,YAAY,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAEhD,IAAI,CAAC,IAAA,eAAU,EAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IAE5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,YAAY,EAAE,MAAM,CAAC,CAAoB,CAAC;IACnF,MAAM,QAAQ,iDACT,QAAQ,CAAC,YAAY,GACrB,QAAQ,CAAC,eAAe,GACxB,QAAQ,CAAC,gBAAgB,CAC7B,CAAC;IAEF,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrE,CAAC,CAAC;AAfW,QAAA,kBAAkB,sBAe7B;AAEK,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAE,MAAkB,EAAgB,EAAE;IACtF,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;QAEzD,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,KAAK,mCAAmC,EAAE,CAAC,CAAC;YACnF,SAAS;QACX,CAAC;QAED,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAA,0BAAkB,EAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;QAErG,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,cAAc,0BAA0B,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC;QAE9E,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,UAAU,6BAA6B,EAAE,CAAC,CAAC;YACtF,SAAS;QACX,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC,CAAC;AAnCW,QAAA,aAAa,iBAmCxB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const CONTENT_KINDS: readonly ["rule", "skill"];
|
|
2
|
+
export declare const CONTENT_SCOPES: readonly ["consumer", "sdk", "both"];
|
|
3
|
+
export type ContentKind = (typeof CONTENT_KINDS)[number];
|
|
4
|
+
export type ContentScope = (typeof CONTENT_SCOPES)[number];
|
|
5
|
+
export type Frontmatter = {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
kind: ContentKind;
|
|
9
|
+
scope: ContentScope;
|
|
10
|
+
requires: string[];
|
|
11
|
+
paths: string[];
|
|
12
|
+
vars: string[];
|
|
13
|
+
};
|
|
14
|
+
export type ParsedDocument = {
|
|
15
|
+
frontmatter: Frontmatter;
|
|
16
|
+
body: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Reads the tiny subset of YAML the content files are allowed to use: single-line
|
|
20
|
+
* `key: value` pairs, inline `key: [a, b]` lists, and `- item` block lists. Anything
|
|
21
|
+
* else throws — silently mis-parsing an agent instruction is worse than failing the build.
|
|
22
|
+
*/
|
|
23
|
+
export declare const parseFrontmatter: (source: string, origin: string) => ParsedDocument;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFrontmatter = exports.CONTENT_SCOPES = exports.CONTENT_KINDS = void 0;
|
|
4
|
+
exports.CONTENT_KINDS = ['rule', 'skill'];
|
|
5
|
+
exports.CONTENT_SCOPES = ['consumer', 'sdk', 'both'];
|
|
6
|
+
const FENCE = '---';
|
|
7
|
+
const KNOWN_KEYS = ['name', 'description', 'kind', 'scope', 'requires', 'paths', 'vars'];
|
|
8
|
+
const LIST_KEYS = ['requires', 'paths', 'vars'];
|
|
9
|
+
const unquote = (value) => {
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
const quoted = trimmed.length >= 2 &&
|
|
12
|
+
((trimmed.startsWith("'") && trimmed.endsWith("'")) || (trimmed.startsWith('"') && trimmed.endsWith('"')));
|
|
13
|
+
return quoted ? trimmed.slice(1, -1) : trimmed;
|
|
14
|
+
};
|
|
15
|
+
const parseInlineList = (value) => {
|
|
16
|
+
const inner = value.trim().slice(1, -1).trim();
|
|
17
|
+
if (!inner)
|
|
18
|
+
return [];
|
|
19
|
+
return inner
|
|
20
|
+
.split(',')
|
|
21
|
+
.map(unquote)
|
|
22
|
+
.filter((entry) => entry.length > 0);
|
|
23
|
+
};
|
|
24
|
+
const splitBlock = (source, origin) => {
|
|
25
|
+
const normalized = source.replace(/\r\n/g, '\n');
|
|
26
|
+
const padded = normalized.endsWith('\n') ? normalized : `${normalized}\n`;
|
|
27
|
+
if (!padded.startsWith(`${FENCE}\n`)) {
|
|
28
|
+
throw new Error(`${origin}: missing the opening '---' frontmatter fence.`);
|
|
29
|
+
}
|
|
30
|
+
const end = padded.indexOf(`\n${FENCE}\n`, FENCE.length);
|
|
31
|
+
if (end === -1) {
|
|
32
|
+
throw new Error(`${origin}: the frontmatter block is never closed with '---'.`);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
head: padded.slice(FENCE.length + 1, end).split('\n'),
|
|
36
|
+
body: padded.slice(end + FENCE.length + 2).replace(/^\n+/, ''),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Reads the tiny subset of YAML the content files are allowed to use: single-line
|
|
41
|
+
* `key: value` pairs, inline `key: [a, b]` lists, and `- item` block lists. Anything
|
|
42
|
+
* else throws — silently mis-parsing an agent instruction is worse than failing the build.
|
|
43
|
+
*/
|
|
44
|
+
const parseFrontmatter = (source, origin) => {
|
|
45
|
+
var _a;
|
|
46
|
+
const { head, body } = splitBlock(source, origin);
|
|
47
|
+
const raw = {};
|
|
48
|
+
let listKey = null;
|
|
49
|
+
for (const line of head) {
|
|
50
|
+
if (!line.trim() || line.trim().startsWith('#'))
|
|
51
|
+
continue;
|
|
52
|
+
const item = /^\s*-\s+(.*)$/.exec(line);
|
|
53
|
+
if ((item === null || item === void 0 ? void 0 : item[1]) !== undefined) {
|
|
54
|
+
if (!listKey) {
|
|
55
|
+
throw new Error(`${origin}: list item "${line.trim()}" does not belong to a key.`);
|
|
56
|
+
}
|
|
57
|
+
raw[listKey].push(unquote(item[1]));
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const separator = line.indexOf(':');
|
|
61
|
+
if (separator === -1) {
|
|
62
|
+
throw new Error(`${origin}: cannot parse frontmatter line "${line}".`);
|
|
63
|
+
}
|
|
64
|
+
const key = line.slice(0, separator).trim();
|
|
65
|
+
const value = line.slice(separator + 1).trim();
|
|
66
|
+
if (!KNOWN_KEYS.includes(key)) {
|
|
67
|
+
throw new Error(`${origin}: unknown frontmatter key "${key}". Known keys: ${KNOWN_KEYS.join(', ')}.`);
|
|
68
|
+
}
|
|
69
|
+
if (LIST_KEYS.includes(key) && !value) {
|
|
70
|
+
raw[key] = [];
|
|
71
|
+
listKey = key;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
listKey = null;
|
|
75
|
+
raw[key] = value.startsWith('[') ? parseInlineList(value) : unquote(value);
|
|
76
|
+
}
|
|
77
|
+
const readText = (key) => {
|
|
78
|
+
const value = raw[key];
|
|
79
|
+
return typeof value === 'string' ? value : undefined;
|
|
80
|
+
};
|
|
81
|
+
const readList = (key) => {
|
|
82
|
+
const value = raw[key];
|
|
83
|
+
if (value === undefined)
|
|
84
|
+
return [];
|
|
85
|
+
return Array.isArray(value) ? value : [value];
|
|
86
|
+
};
|
|
87
|
+
const name = readText('name');
|
|
88
|
+
const description = readText('description');
|
|
89
|
+
const kind = readText('kind');
|
|
90
|
+
const scope = (_a = readText('scope')) !== null && _a !== void 0 ? _a : 'consumer';
|
|
91
|
+
if (!name)
|
|
92
|
+
throw new Error(`${origin}: frontmatter is missing "name".`);
|
|
93
|
+
if (!description)
|
|
94
|
+
throw new Error(`${origin}: frontmatter is missing "description".`);
|
|
95
|
+
if (!kind)
|
|
96
|
+
throw new Error(`${origin}: frontmatter is missing "kind".`);
|
|
97
|
+
if (!exports.CONTENT_KINDS.includes(kind)) {
|
|
98
|
+
throw new Error(`${origin}: kind "${kind}" must be one of ${exports.CONTENT_KINDS.join(', ')}.`);
|
|
99
|
+
}
|
|
100
|
+
if (!exports.CONTENT_SCOPES.includes(scope)) {
|
|
101
|
+
throw new Error(`${origin}: scope "${scope}" must be one of ${exports.CONTENT_SCOPES.join(', ')}.`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
frontmatter: {
|
|
105
|
+
name,
|
|
106
|
+
description,
|
|
107
|
+
kind: kind,
|
|
108
|
+
scope: scope,
|
|
109
|
+
requires: readList('requires'),
|
|
110
|
+
paths: readList('paths'),
|
|
111
|
+
vars: readList('vars'),
|
|
112
|
+
},
|
|
113
|
+
body: body.trimEnd(),
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
exports.parseFrontmatter = parseFrontmatter;
|
|
117
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './config';
|
|
2
|
+
export * from './filter';
|
|
3
|
+
export * from './frontmatter';
|
|
4
|
+
export * from './load-content';
|
|
5
|
+
export * from './owned-paths';
|
|
6
|
+
export * from './plan';
|
|
7
|
+
export * from './render';
|
|
8
|
+
export * from './sync';
|
|
9
|
+
export * from './targets/shared';
|
package/src/lib/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./config"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./filter"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./frontmatter"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./load-content"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./owned-paths"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./plan"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./render"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./sync"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./targets/shared"), exports);
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/index.ts"],"names":[],"mappings":";;;AAAA,mDAAyB;AACzB,mDAAyB;AACzB,wDAA8B;AAC9B,yDAA+B;AAC/B,wDAA8B;AAC9B,iDAAuB;AACvB,mDAAyB;AACzB,iDAAuB;AACvB,2DAAiC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Frontmatter } from './frontmatter';
|
|
2
|
+
export type ContentResource = {
|
|
3
|
+
/** File name as referenced from a body via `{{resource:…}}`. */
|
|
4
|
+
fileName: string;
|
|
5
|
+
absolutePath: string;
|
|
6
|
+
};
|
|
7
|
+
export type ContentItem = {
|
|
8
|
+
frontmatter: Frontmatter;
|
|
9
|
+
body: string;
|
|
10
|
+
sourcePath: string;
|
|
11
|
+
resources: ContentResource[];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The compiled CLI lives at `<pkg>/src/lib/`, the shipped markdown at `<pkg>/content/`.
|
|
15
|
+
* The same relative hop works from the TypeScript sources, so dev and published runs agree.
|
|
16
|
+
*/
|
|
17
|
+
export declare const resolveContentRoot: () => string;
|
|
18
|
+
export declare const loadContent: (contentRoot?: string) => ContentItem[];
|
|
19
|
+
export declare const loadDefaultVars: (contentRoot?: string) => Record<string, string | string[]>;
|