@ethlete/agent-rules 0.1.0-next.4 → 0.1.0-next.5
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 +16 -0
- package/README.md +27 -10
- package/content/hooks/context-warning.py +232 -98
- package/content/skills/figma-export/SKILL.md +193 -0
- package/content/skills/figma-export/dump-figma-layers.py +83 -0
- package/content/skills/figma-export/dump-figma-svg.py +235 -0
- package/content/skills/figma-export/measure-template.mjs +87 -0
- package/content/skills/query/SKILL.md +6 -0
- package/package.json +1 -1
- package/src/lib/config.d.ts +2 -2
- package/src/lib/owned-paths.js +19 -1
- package/src/lib/owned-paths.js.map +1 -1
- package/src/lib/plan.js +9 -3
- package/src/lib/plan.js.map +1 -1
- package/src/lib/targets/claude-hooks.d.ts +1 -23
- package/src/lib/targets/claude-hooks.js +15 -84
- package/src/lib/targets/claude-hooks.js.map +1 -1
- package/src/lib/targets/codex-hooks.d.ts +12 -0
- package/src/lib/targets/codex-hooks.js +33 -0
- package/src/lib/targets/codex-hooks.js.map +1 -0
- package/src/lib/targets/hooks-shared.d.ts +38 -0
- package/src/lib/targets/hooks-shared.js +95 -0
- package/src/lib/targets/hooks-shared.js.map +1 -0
package/src/lib/owned-paths.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs_1 = require("fs");
|
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
// `.agents/ethlete` and `.github/instructions/ethlete-*` are no longer emitted, but stay owned so
|
|
7
7
|
// a sync prunes them from repos generated by older versions.
|
|
8
|
-
const OWNED_DIRECTORIES = ['.agents/ethlete', '.claude/rules/ethlete', '.claude/hooks/ethlete'];
|
|
8
|
+
const OWNED_DIRECTORIES = ['.agents/ethlete', '.claude/rules/ethlete', '.claude/hooks/ethlete', '.codex/hooks/ethlete'];
|
|
9
9
|
const OWNED_PARENTS = [
|
|
10
10
|
{ dir: '.agents/skills', match: (entry) => entry.startsWith('ethlete-') },
|
|
11
11
|
{ dir: '.claude/skills', match: (entry) => entry.startsWith('ethlete-') },
|
|
@@ -15,6 +15,23 @@ const OWNED_PARENTS = [
|
|
|
15
15
|
match: (entry) => entry.startsWith('ethlete-') && entry.endsWith('.instructions.md'),
|
|
16
16
|
},
|
|
17
17
|
];
|
|
18
|
+
/**
|
|
19
|
+
* Files that exist only to register hooks: once the last generated entry is removed the merge
|
|
20
|
+
* leaves `{}` behind, which is ours to clean up. Any hand-written entry keeps the file non-empty
|
|
21
|
+
* and therefore unowned.
|
|
22
|
+
*/
|
|
23
|
+
const OWNED_WHEN_EMPTY = ['.codex/hooks.json'];
|
|
24
|
+
const isEmptyObject = (absolute) => {
|
|
25
|
+
if (!(0, fs_1.existsSync)(absolute))
|
|
26
|
+
return false;
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse((0, fs_1.readFileSync)(absolute, 'utf8'));
|
|
29
|
+
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) && Object.keys(parsed).length === 0;
|
|
30
|
+
}
|
|
31
|
+
catch (_a) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
18
35
|
const walk = (root, absoluteDir) => {
|
|
19
36
|
if (!(0, fs_1.existsSync)(absoluteDir))
|
|
20
37
|
return [];
|
|
@@ -44,6 +61,7 @@ const collectOwnedPaths = (root) => {
|
|
|
44
61
|
owned.push(...((0, fs_1.statSync)(absolute).isDirectory() ? walk(root, absolute) : [`${parent.dir}/${entry}`]));
|
|
45
62
|
}
|
|
46
63
|
}
|
|
64
|
+
owned.push(...OWNED_WHEN_EMPTY.filter((path) => isEmptyObject((0, path_1.join)(root, path))));
|
|
47
65
|
return owned;
|
|
48
66
|
};
|
|
49
67
|
exports.collectOwnedPaths = collectOwnedPaths;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owned-paths.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/owned-paths.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"owned-paths.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/owned-paths.ts"],"names":[],"mappings":"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"}
|
package/src/lib/plan.js
CHANGED
|
@@ -10,6 +10,8 @@ const agents_skills_1 = require("./targets/agents-skills");
|
|
|
10
10
|
const claude_hooks_1 = require("./targets/claude-hooks");
|
|
11
11
|
const claude_1 = require("./targets/claude");
|
|
12
12
|
const codex_1 = require("./targets/codex");
|
|
13
|
+
const codex_hooks_1 = require("./targets/codex-hooks");
|
|
14
|
+
const hooks_shared_1 = require("./targets/hooks-shared");
|
|
13
15
|
const copilot_1 = require("./targets/copilot");
|
|
14
16
|
const cursor_1 = require("./targets/cursor");
|
|
15
17
|
const SKILL_LINK_PATTERN = /\{%\s*skill:([a-zA-Z0-9_.-]+)\s*%\}/g;
|
|
@@ -72,9 +74,9 @@ const collectLocalConfigWarnings = (root) => {
|
|
|
72
74
|
warnings.push(`${config_1.LOCAL_CONFIG_FILE_NAME} has an invalid "disableHooks" value — use true or an array of hook names; hooks stay enabled.`);
|
|
73
75
|
}
|
|
74
76
|
if (Array.isArray(disable)) {
|
|
75
|
-
const unknown = disable.filter((name) => !(name in
|
|
77
|
+
const unknown = disable.filter((name) => !(name in hooks_shared_1.KNOWN_HOOKS));
|
|
76
78
|
if (unknown.length > 0) {
|
|
77
|
-
warnings.push(`${config_1.LOCAL_CONFIG_FILE_NAME} disables unknown hook(s): ${unknown.join(', ')}. Known hooks: ${Object.keys(
|
|
79
|
+
warnings.push(`${config_1.LOCAL_CONFIG_FILE_NAME} disables unknown hook(s): ${unknown.join(', ')}. Known hooks: ${Object.keys(hooks_shared_1.KNOWN_HOOKS).join(', ')}.`);
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
82
|
const disableAutoHandoffSave = local.config.disableAutoHandoffSave;
|
|
@@ -101,7 +103,7 @@ const collectWarnings = (config) => {
|
|
|
101
103
|
*/
|
|
102
104
|
const buildPlan = (options) => {
|
|
103
105
|
const { config, version } = options;
|
|
104
|
-
(0,
|
|
106
|
+
(0, hooks_shared_1.assertKnownHooks)(config.hooks);
|
|
105
107
|
const { kept, skipped } = (0, filter_1.filterContent)((0, load_content_1.loadContent)(), config);
|
|
106
108
|
const skills = kept.filter((item) => item.frontmatter.kind === 'skill');
|
|
107
109
|
const emittedSkills = new Set(skills.map((item) => item.frontmatter.name));
|
|
@@ -133,6 +135,10 @@ const buildPlan = (options) => {
|
|
|
133
135
|
context,
|
|
134
136
|
claudeTarget: config.targets.includes('claude'),
|
|
135
137
|
existingSettings: readExisting(config.root, claude_hooks_1.CLAUDE_SETTINGS_FILE),
|
|
138
|
+
}), ...(0, codex_hooks_1.emitCodexHooks)({
|
|
139
|
+
context,
|
|
140
|
+
codexTarget: config.targets.includes('codex'),
|
|
141
|
+
existingHooks: readExisting(config.root, codex_hooks_1.CODEX_HOOKS_FILE),
|
|
136
142
|
}));
|
|
137
143
|
return { files, skipped, danglingLinks: findDanglingLinks(kept, emittedSkills), warnings: collectWarnings(config) };
|
|
138
144
|
};
|
package/src/lib/plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/plan.ts"],"names":[],"mappings":";;;AAAA,2BAAuE;AACvE,+BAAqC;AACrC,qCAA+E;AAC/E,qCAAsD;AACtD,iDAA0D;AAC1D,2DAA2D;AAC3D,yDAA+
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,33 +1,11 @@
|
|
|
1
1
|
import { EmitContext, EmittedFile } from './shared';
|
|
2
2
|
export declare const CLAUDE_SETTINGS_FILE = ".claude/settings.json";
|
|
3
|
-
type HookDefinition = {
|
|
4
|
-
event: string;
|
|
5
|
-
file: string;
|
|
6
|
-
timeout: number;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Hooks a repo can opt into via the config's `hooks` array. Hooks run arbitrary commands on the
|
|
10
|
-
* developer's machine, so unlike rules and skills they are never emitted by default.
|
|
11
|
-
*/
|
|
12
|
-
export declare const CLAUDE_HOOKS: Record<string, HookDefinition>;
|
|
13
|
-
export declare const assertKnownHooks: (hooks: string[]) => void;
|
|
14
|
-
/**
|
|
15
|
-
* Rewrites the generated entries in `.claude/settings.json` declaratively: every entry pointing
|
|
16
|
-
* into `.claude/hooks/ethlete/` is dropped and the currently enabled hooks are re-added, so
|
|
17
|
-
* disabling a hook in the config also unregisters it. Everything else in the file is untouched.
|
|
18
|
-
*/
|
|
19
|
-
export declare const mergeClaudeSettings: (options: {
|
|
20
|
-
existing: string;
|
|
21
|
-
hooks: string[];
|
|
22
|
-
}) => string;
|
|
23
3
|
/**
|
|
24
4
|
* The hook scripts plus the settings registration. Runs even when the claude target is off so a
|
|
25
|
-
* repo that drops the target also gets its stale registrations removed
|
|
26
|
-
* only planned when its parsed content actually changes, and an unparseable file is left alone.
|
|
5
|
+
* repo that drops the target also gets its stale registrations removed.
|
|
27
6
|
*/
|
|
28
7
|
export declare const emitClaudeHooks: (options: {
|
|
29
8
|
context: EmitContext;
|
|
30
9
|
claudeTarget: boolean;
|
|
31
10
|
existingSettings: string;
|
|
32
11
|
}) => EmittedFile[];
|
|
33
|
-
export {};
|
|
@@ -1,97 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.emitClaudeHooks = exports.
|
|
4
|
-
const
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
const load_content_1 = require("../load-content");
|
|
3
|
+
exports.emitClaudeHooks = exports.CLAUDE_SETTINGS_FILE = void 0;
|
|
4
|
+
const hooks_shared_1 = require("./hooks-shared");
|
|
7
5
|
exports.CLAUDE_SETTINGS_FILE = '.claude/settings.json';
|
|
8
6
|
const HOOKS_DIR = '.claude/hooks/ethlete';
|
|
9
|
-
|
|
10
|
-
* Hooks a repo can opt into via the config's `hooks` array. Hooks run arbitrary commands on the
|
|
11
|
-
* developer's machine, so unlike rules and skills they are never emitted by default.
|
|
12
|
-
*/
|
|
13
|
-
exports.CLAUDE_HOOKS = {
|
|
14
|
-
'context-warning': { event: 'UserPromptSubmit', file: 'context-warning.py', timeout: 10 },
|
|
15
|
-
};
|
|
16
|
-
const assertKnownHooks = (hooks) => {
|
|
17
|
-
const unknown = hooks.filter((name) => !(name in exports.CLAUDE_HOOKS));
|
|
18
|
-
if (unknown.length > 0) {
|
|
19
|
-
throw new Error(`Unknown hook(s): ${unknown.join(', ')}. Known hooks: ${Object.keys(exports.CLAUDE_HOOKS).join(', ')}.`);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
exports.assertKnownHooks = assertKnownHooks;
|
|
23
|
-
const commandFor = (file) => `python3 "$CLAUDE_PROJECT_DIR/${HOOKS_DIR}/${file}"`;
|
|
24
|
-
/** `#` comment instead of the HTML banner, placed after the shebang so the file stays runnable. */
|
|
25
|
-
const withBanner = (raw, version) => {
|
|
26
|
-
var _a;
|
|
27
|
-
const banner = `# Generated by @ethlete/agent-rules v${version} — DO NOT EDIT. Run \`npx ethlete-agents sync\`.`;
|
|
28
|
-
const lines = raw.split('\n');
|
|
29
|
-
if ((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.startsWith('#!'))
|
|
30
|
-
return [lines[0], banner, ...lines.slice(1)].join('\n');
|
|
31
|
-
return `${banner}\n${raw}`;
|
|
32
|
-
};
|
|
33
|
-
const isGenerated = (hook) => { var _a; return ((_a = hook.command) !== null && _a !== void 0 ? _a : '').includes(HOOKS_DIR); };
|
|
34
|
-
/**
|
|
35
|
-
* Rewrites the generated entries in `.claude/settings.json` declaratively: every entry pointing
|
|
36
|
-
* into `.claude/hooks/ethlete/` is dropped and the currently enabled hooks are re-added, so
|
|
37
|
-
* disabling a hook in the config also unregisters it. Everything else in the file is untouched.
|
|
38
|
-
*/
|
|
39
|
-
const mergeClaudeSettings = (options) => {
|
|
40
|
-
var _a, _b;
|
|
41
|
-
const { existing, hooks } = options;
|
|
42
|
-
const settings = JSON.parse(existing.trim() || '{}');
|
|
43
|
-
const events = Object.assign({}, ((_a = settings.hooks) !== null && _a !== void 0 ? _a : {}));
|
|
44
|
-
for (const [event, groups] of Object.entries(events)) {
|
|
45
|
-
const kept = groups
|
|
46
|
-
.map((group) => { var _a; return (Object.assign(Object.assign({}, group), { hooks: ((_a = group.hooks) !== null && _a !== void 0 ? _a : []).filter((hook) => !isGenerated(hook)) })); })
|
|
47
|
-
.filter((group) => group.hooks.length > 0);
|
|
48
|
-
if (kept.length > 0)
|
|
49
|
-
events[event] = kept;
|
|
50
|
-
else
|
|
51
|
-
delete events[event];
|
|
52
|
-
}
|
|
53
|
-
for (const name of hooks) {
|
|
54
|
-
const definition = exports.CLAUDE_HOOKS[name];
|
|
55
|
-
if (!definition)
|
|
56
|
-
continue;
|
|
57
|
-
events[definition.event] = [
|
|
58
|
-
...((_b = events[definition.event]) !== null && _b !== void 0 ? _b : []),
|
|
59
|
-
{ hooks: [{ type: 'command', command: commandFor(definition.file), timeout: definition.timeout }] },
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
if (Object.keys(events).length > 0)
|
|
63
|
-
settings.hooks = events;
|
|
64
|
-
else
|
|
65
|
-
delete settings.hooks;
|
|
66
|
-
return `${JSON.stringify(settings, null, 2)}\n`;
|
|
67
|
-
};
|
|
68
|
-
exports.mergeClaudeSettings = mergeClaudeSettings;
|
|
7
|
+
const commandFor = (file) => `python3 "$CLAUDE_PROJECT_DIR/${HOOKS_DIR}/${file}" --agent claude`;
|
|
69
8
|
/**
|
|
70
9
|
* The hook scripts plus the settings registration. Runs even when the claude target is off so a
|
|
71
|
-
* repo that drops the target also gets its stale registrations removed
|
|
72
|
-
* only planned when its parsed content actually changes, and an unparseable file is left alone.
|
|
10
|
+
* repo that drops the target also gets its stale registrations removed.
|
|
73
11
|
*/
|
|
74
12
|
const emitClaudeHooks = (options) => {
|
|
75
13
|
const { context, claudeTarget, existingSettings } = options;
|
|
76
14
|
const hooks = claudeTarget ? context.hooks : [];
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
files.push({ path: exports.CLAUDE_SETTINGS_FILE, contents: merged });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (_a) {
|
|
92
|
-
// Unparseable settings.json — never clobber a file the repo owns.
|
|
93
|
-
}
|
|
94
|
-
return files;
|
|
15
|
+
return [
|
|
16
|
+
...(0, hooks_shared_1.emitHookScripts)({ hooks, hooksDir: HOOKS_DIR, version: context.version }),
|
|
17
|
+
...(0, hooks_shared_1.emitHookSettings)({
|
|
18
|
+
path: exports.CLAUDE_SETTINGS_FILE,
|
|
19
|
+
existing: existingSettings,
|
|
20
|
+
hooks,
|
|
21
|
+
hooksDir: HOOKS_DIR,
|
|
22
|
+
commandFor,
|
|
23
|
+
createWhenEmpty: true,
|
|
24
|
+
}),
|
|
25
|
+
];
|
|
95
26
|
};
|
|
96
27
|
exports.emitClaudeHooks = emitClaudeHooks;
|
|
97
28
|
//# sourceMappingURL=claude-hooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-hooks.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/targets/claude-hooks.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"claude-hooks.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/targets/claude-hooks.ts"],"names":[],"mappings":";;;AACA,iDAAmE;AAEtD,QAAA,oBAAoB,GAAG,uBAAuB,CAAC;AAE5D,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,gCAAgC,SAAS,IAAI,IAAI,kBAAkB,CAAC;AAEzG;;;GAGG;AACI,MAAM,eAAe,GAAG,CAAC,OAI/B,EAAiB,EAAE;IAClB,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC;IAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAEhD,OAAO;QACL,GAAG,IAAA,8BAAe,EAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5E,GAAG,IAAA,+BAAgB,EAAC;YAClB,IAAI,EAAE,4BAAoB;YAC1B,QAAQ,EAAE,gBAAgB;YAC1B,KAAK;YACL,QAAQ,EAAE,SAAS;YACnB,UAAU;YACV,eAAe,EAAE,IAAI;SACtB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,eAAe,mBAmB1B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EmitContext, EmittedFile } from './shared';
|
|
2
|
+
export declare const CODEX_HOOKS_FILE = ".codex/hooks.json";
|
|
3
|
+
/**
|
|
4
|
+
* The hook scripts plus the `.codex/hooks.json` registration. Runs even when the codex target is
|
|
5
|
+
* off so a repo that drops the target also gets its stale registrations removed — but an absent
|
|
6
|
+
* file stays absent rather than being created empty.
|
|
7
|
+
*/
|
|
8
|
+
export declare const emitCodexHooks: (options: {
|
|
9
|
+
context: EmitContext;
|
|
10
|
+
codexTarget: boolean;
|
|
11
|
+
existingHooks: string;
|
|
12
|
+
}) => EmittedFile[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitCodexHooks = exports.CODEX_HOOKS_FILE = void 0;
|
|
4
|
+
const hooks_shared_1 = require("./hooks-shared");
|
|
5
|
+
exports.CODEX_HOOKS_FILE = '.codex/hooks.json';
|
|
6
|
+
const HOOKS_DIR = '.codex/hooks/ethlete';
|
|
7
|
+
/**
|
|
8
|
+
* Codex exposes no project-dir variable, so the path is resolved the way Codex's own hook docs
|
|
9
|
+
* resolve it — the command string is evaluated by a shell.
|
|
10
|
+
*/
|
|
11
|
+
const commandFor = (file) => `python3 "$(git rev-parse --show-toplevel)/${HOOKS_DIR}/${file}" --agent codex`;
|
|
12
|
+
/**
|
|
13
|
+
* The hook scripts plus the `.codex/hooks.json` registration. Runs even when the codex target is
|
|
14
|
+
* off so a repo that drops the target also gets its stale registrations removed — but an absent
|
|
15
|
+
* file stays absent rather than being created empty.
|
|
16
|
+
*/
|
|
17
|
+
const emitCodexHooks = (options) => {
|
|
18
|
+
const { context, codexTarget, existingHooks } = options;
|
|
19
|
+
const hooks = codexTarget ? context.hooks : [];
|
|
20
|
+
return [
|
|
21
|
+
...(0, hooks_shared_1.emitHookScripts)({ hooks, hooksDir: HOOKS_DIR, version: context.version }),
|
|
22
|
+
...(0, hooks_shared_1.emitHookSettings)({
|
|
23
|
+
path: exports.CODEX_HOOKS_FILE,
|
|
24
|
+
existing: existingHooks,
|
|
25
|
+
hooks,
|
|
26
|
+
hooksDir: HOOKS_DIR,
|
|
27
|
+
commandFor,
|
|
28
|
+
createWhenEmpty: false,
|
|
29
|
+
}),
|
|
30
|
+
];
|
|
31
|
+
};
|
|
32
|
+
exports.emitCodexHooks = emitCodexHooks;
|
|
33
|
+
//# sourceMappingURL=codex-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-hooks.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/targets/codex-hooks.ts"],"names":[],"mappings":";;;AACA,iDAAmE;AAEtD,QAAA,gBAAgB,GAAG,mBAAmB,CAAC;AAEpD,MAAM,SAAS,GAAG,sBAAsB,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,6CAA6C,SAAS,IAAI,IAAI,iBAAiB,CAAC;AAErH;;;;GAIG;AACI,MAAM,cAAc,GAAG,CAAC,OAI9B,EAAiB,EAAE;IAClB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/C,OAAO;QACL,GAAG,IAAA,8BAAe,EAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5E,GAAG,IAAA,+BAAgB,EAAC;YAClB,IAAI,EAAE,wBAAgB;YACtB,QAAQ,EAAE,aAAa;YACvB,KAAK;YACL,QAAQ,EAAE,SAAS;YACnB,UAAU;YACV,eAAe,EAAE,KAAK;SACvB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,cAAc,kBAmBzB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { EmittedFile } from './shared';
|
|
2
|
+
type HookDefinition = {
|
|
3
|
+
event: string;
|
|
4
|
+
file: string;
|
|
5
|
+
timeout: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Hooks a repo can opt into via the config's `hooks` array. Hooks run arbitrary commands on the
|
|
9
|
+
* developer's machine, so unlike rules and skills they are never emitted by default.
|
|
10
|
+
*/
|
|
11
|
+
export declare const KNOWN_HOOKS: Record<string, HookDefinition>;
|
|
12
|
+
export declare const assertKnownHooks: (hooks: string[]) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Rewrites the generated entries declaratively: every entry whose command points into the
|
|
15
|
+
* agent's `hooks/ethlete/` directory is dropped and the currently enabled hooks are re-added, so
|
|
16
|
+
* disabling a hook in the config also unregisters it. Everything else in the file is untouched.
|
|
17
|
+
*/
|
|
18
|
+
export declare const mergeHookSettings: (options: {
|
|
19
|
+
existing: string;
|
|
20
|
+
hooks: string[];
|
|
21
|
+
hooksDir: string;
|
|
22
|
+
commandFor: (file: string) => string;
|
|
23
|
+
}) => string;
|
|
24
|
+
export declare const emitHookScripts: (options: {
|
|
25
|
+
hooks: string[];
|
|
26
|
+
hooksDir: string;
|
|
27
|
+
version: string;
|
|
28
|
+
}) => EmittedFile[];
|
|
29
|
+
/** Only planned when the parsed content actually changes; an unparseable file is left alone. */
|
|
30
|
+
export declare const emitHookSettings: (options: {
|
|
31
|
+
path: string;
|
|
32
|
+
existing: string;
|
|
33
|
+
hooks: string[];
|
|
34
|
+
hooksDir: string;
|
|
35
|
+
commandFor: (file: string) => string;
|
|
36
|
+
createWhenEmpty: boolean;
|
|
37
|
+
}) => EmittedFile[];
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitHookSettings = exports.emitHookScripts = exports.mergeHookSettings = exports.assertKnownHooks = exports.KNOWN_HOOKS = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const load_content_1 = require("../load-content");
|
|
7
|
+
/**
|
|
8
|
+
* Hooks a repo can opt into via the config's `hooks` array. Hooks run arbitrary commands on the
|
|
9
|
+
* developer's machine, so unlike rules and skills they are never emitted by default.
|
|
10
|
+
*/
|
|
11
|
+
exports.KNOWN_HOOKS = {
|
|
12
|
+
'context-warning': { event: 'UserPromptSubmit', file: 'context-warning.py', timeout: 10 },
|
|
13
|
+
};
|
|
14
|
+
const assertKnownHooks = (hooks) => {
|
|
15
|
+
const unknown = hooks.filter((name) => !(name in exports.KNOWN_HOOKS));
|
|
16
|
+
if (unknown.length > 0) {
|
|
17
|
+
throw new Error(`Unknown hook(s): ${unknown.join(', ')}. Known hooks: ${Object.keys(exports.KNOWN_HOOKS).join(', ')}.`);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.assertKnownHooks = assertKnownHooks;
|
|
21
|
+
/** `#` comment instead of the HTML banner, placed after the shebang so the file stays runnable. */
|
|
22
|
+
const withBanner = (raw, version) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const banner = `# Generated by @ethlete/agent-rules v${version} — DO NOT EDIT. Run \`npx ethlete-agents sync\`.`;
|
|
25
|
+
const lines = raw.split('\n');
|
|
26
|
+
if ((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.startsWith('#!'))
|
|
27
|
+
return [lines[0], banner, ...lines.slice(1)].join('\n');
|
|
28
|
+
return `${banner}\n${raw}`;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Rewrites the generated entries declaratively: every entry whose command points into the
|
|
32
|
+
* agent's `hooks/ethlete/` directory is dropped and the currently enabled hooks are re-added, so
|
|
33
|
+
* disabling a hook in the config also unregisters it. Everything else in the file is untouched.
|
|
34
|
+
*/
|
|
35
|
+
const mergeHookSettings = (options) => {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const { existing, hooks, hooksDir, commandFor } = options;
|
|
38
|
+
const settings = JSON.parse(existing.trim() || '{}');
|
|
39
|
+
const events = Object.assign({}, ((_a = settings.hooks) !== null && _a !== void 0 ? _a : {}));
|
|
40
|
+
for (const [event, groups] of Object.entries(events)) {
|
|
41
|
+
const kept = groups
|
|
42
|
+
.map((group) => {
|
|
43
|
+
var _a;
|
|
44
|
+
return (Object.assign(Object.assign({}, group), { hooks: ((_a = group.hooks) !== null && _a !== void 0 ? _a : []).filter((hook) => { var _a; return !((_a = hook.command) !== null && _a !== void 0 ? _a : '').includes(hooksDir); }) }));
|
|
45
|
+
})
|
|
46
|
+
.filter((group) => group.hooks.length > 0);
|
|
47
|
+
if (kept.length > 0)
|
|
48
|
+
events[event] = kept;
|
|
49
|
+
else
|
|
50
|
+
delete events[event];
|
|
51
|
+
}
|
|
52
|
+
for (const name of hooks) {
|
|
53
|
+
const definition = exports.KNOWN_HOOKS[name];
|
|
54
|
+
if (!definition)
|
|
55
|
+
continue;
|
|
56
|
+
events[definition.event] = [
|
|
57
|
+
...((_b = events[definition.event]) !== null && _b !== void 0 ? _b : []),
|
|
58
|
+
{ hooks: [{ type: 'command', command: commandFor(definition.file), timeout: definition.timeout }] },
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
if (Object.keys(events).length > 0)
|
|
62
|
+
settings.hooks = events;
|
|
63
|
+
else
|
|
64
|
+
delete settings.hooks;
|
|
65
|
+
return `${JSON.stringify(settings, null, 2)}\n`;
|
|
66
|
+
};
|
|
67
|
+
exports.mergeHookSettings = mergeHookSettings;
|
|
68
|
+
const emitHookScripts = (options) => {
|
|
69
|
+
const { hooks, hooksDir, version } = options;
|
|
70
|
+
return hooks.flatMap((name) => {
|
|
71
|
+
const definition = exports.KNOWN_HOOKS[name];
|
|
72
|
+
if (!definition)
|
|
73
|
+
return [];
|
|
74
|
+
const raw = (0, fs_1.readFileSync)((0, path_1.join)((0, load_content_1.resolveContentRoot)(), 'hooks', definition.file), 'utf8');
|
|
75
|
+
return [{ path: `${hooksDir}/${definition.file}`, contents: withBanner(raw, version) }];
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
exports.emitHookScripts = emitHookScripts;
|
|
79
|
+
/** Only planned when the parsed content actually changes; an unparseable file is left alone. */
|
|
80
|
+
const emitHookSettings = (options) => {
|
|
81
|
+
const { path, existing, hooks, hooksDir, commandFor, createWhenEmpty } = options;
|
|
82
|
+
if (existing.trim().length === 0 && hooks.length === 0 && !createWhenEmpty)
|
|
83
|
+
return [];
|
|
84
|
+
try {
|
|
85
|
+
const merged = (0, exports.mergeHookSettings)({ existing, hooks, hooksDir, commandFor });
|
|
86
|
+
if (JSON.stringify(JSON.parse(existing.trim() || '{}')) === JSON.stringify(JSON.parse(merged)))
|
|
87
|
+
return [];
|
|
88
|
+
return [{ path, contents: merged }];
|
|
89
|
+
}
|
|
90
|
+
catch (_a) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
exports.emitHookSettings = emitHookSettings;
|
|
95
|
+
//# sourceMappingURL=hooks-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-shared.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/targets/hooks-shared.ts"],"names":[],"mappings":"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"}
|