mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
611147a333 | ||
|
|
7d5c60d291 |
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"description": "Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.",
|
"description": "Impeccable design detector: immediate-tier checks after Edit/Write on UI files, full-rule deep pass on Stop.",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"PostToolUse": [
|
"PostToolUse": [
|
||||||
{
|
{
|
||||||
"matcher": "Edit|Write|MultiEdit",
|
"matcher": "Edit|Write",
|
||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"hooks": {
|
"hooks": {
|
||||||
"PostToolUse": [
|
"PostToolUse": [
|
||||||
{
|
{
|
||||||
"matcher": "Edit|Write|MultiEdit",
|
"matcher": "Edit|Write",
|
||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ The first argument is the action. Defaults to `status`.
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `/impeccable hooks on`."
|
3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `/impeccable hooks on`."
|
||||||
4. If `<action>` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write/MultiEdit on a UI file."
|
4. If `<action>` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write on a UI file."
|
||||||
5. If `<action>` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception.
|
5. If `<action>` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception.
|
||||||
6. If `<action>` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question.
|
6. If `<action>` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question.
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,11 @@ const HOOK_MANIFEST_TARGETS = [
|
|||||||
destRel: '.claude/settings.local.json',
|
destRel: '.claude/settings.local.json',
|
||||||
sharedDestRel: '.claude/settings.json',
|
sharedDestRel: '.claude/settings.json',
|
||||||
manifest: () => ({
|
manifest: () => ({
|
||||||
description: 'Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.',
|
description: 'Impeccable design detector: immediate-tier checks after Edit/Write on UI files, full-rule deep pass on Stop.',
|
||||||
hooks: {
|
hooks: {
|
||||||
PostToolUse: [
|
PostToolUse: [
|
||||||
{
|
{
|
||||||
matcher: 'Edit|Write|MultiEdit',
|
matcher: 'Edit|Write',
|
||||||
hooks: [
|
hooks: [
|
||||||
{
|
{
|
||||||
type: 'command',
|
type: 'command',
|
||||||
|
|||||||
@@ -137,9 +137,9 @@ const GROK_PROJECT_HOOK = '.grok/skills/impeccable/scripts/hook.mjs';
|
|||||||
|
|
||||||
export function buildClaudeSettingsManifest() {
|
export function buildClaudeSettingsManifest() {
|
||||||
return {
|
return {
|
||||||
description: 'Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.',
|
description: 'Impeccable design detector: immediate-tier checks after Edit/Write on UI files, full-rule deep pass on Stop.',
|
||||||
hooks: buildClaudeCompatibleHooks(
|
hooks: buildClaudeCompatibleHooks(
|
||||||
'Edit|Write|MultiEdit',
|
'Edit|Write',
|
||||||
CLAUDE_PROJECT_HOOK,
|
CLAUDE_PROJECT_HOOK,
|
||||||
SYSTEM_MESSAGE_NOTICE,
|
SYSTEM_MESSAGE_NOTICE,
|
||||||
),
|
),
|
||||||
@@ -155,7 +155,7 @@ export function buildClaudeSettingsManifest() {
|
|||||||
export function buildClaudePluginHooksManifest() {
|
export function buildClaudePluginHooksManifest() {
|
||||||
return {
|
return {
|
||||||
hooks: buildClaudeCompatibleHooks(
|
hooks: buildClaudeCompatibleHooks(
|
||||||
'Edit|Write|MultiEdit',
|
'Edit|Write',
|
||||||
CLAUDE_PLUGIN_HOOK,
|
CLAUDE_PLUGIN_HOOK,
|
||||||
SYSTEM_MESSAGE_NOTICE,
|
SYSTEM_MESSAGE_NOTICE,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ The first argument is the action. Defaults to `status`.
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `{{command_prefix}}impeccable hooks on`."
|
3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `{{command_prefix}}impeccable hooks on`."
|
||||||
4. If `<action>` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write/MultiEdit on a UI file."
|
4. If `<action>` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write on a UI file."
|
||||||
5. If `<action>` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception.
|
5. If `<action>` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception.
|
||||||
6. If `<action>` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question.
|
6. If `<action>` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question.
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,11 @@ const HOOK_MANIFEST_TARGETS = [
|
|||||||
destRel: '.claude/settings.local.json',
|
destRel: '.claude/settings.local.json',
|
||||||
sharedDestRel: '.claude/settings.json',
|
sharedDestRel: '.claude/settings.json',
|
||||||
manifest: () => ({
|
manifest: () => ({
|
||||||
description: 'Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.',
|
description: 'Impeccable design detector: immediate-tier checks after Edit/Write on UI files, full-rule deep pass on Stop.',
|
||||||
hooks: {
|
hooks: {
|
||||||
PostToolUse: [
|
PostToolUse: [
|
||||||
{
|
{
|
||||||
matcher: 'Edit|Write|MultiEdit',
|
matcher: 'Edit|Write',
|
||||||
hooks: [
|
hooks: [
|
||||||
{
|
{
|
||||||
type: 'command',
|
type: 'command',
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ describe('hook manifest builders', () => {
|
|||||||
const group = manifest.hooks.PostToolUse[0];
|
const group = manifest.hooks.PostToolUse[0];
|
||||||
const handler = group.hooks[0];
|
const handler = group.hooks[0];
|
||||||
|
|
||||||
assert.equal(group.matcher, 'Edit|Write|MultiEdit');
|
assert.equal(group.matcher, 'Edit|Write');
|
||||||
|
assert.doesNotMatch(manifest.description, /MultiEdit/);
|
||||||
assert.equal(handler.type, 'command');
|
assert.equal(handler.type, 'command');
|
||||||
assert.equal(handler.timeout, 5);
|
assert.equal(handler.timeout, 5);
|
||||||
assert.equal(handler.statusMessage, 'Checking UI changes');
|
assert.equal(handler.statusMessage, 'Checking UI changes');
|
||||||
@@ -356,7 +357,7 @@ describe('generated hook artifacts in repo', () => {
|
|||||||
assert.equal(manifest.description, undefined);
|
assert.equal(manifest.description, undefined);
|
||||||
|
|
||||||
const handler = manifest.hooks.PostToolUse[0].hooks[0];
|
const handler = manifest.hooks.PostToolUse[0].hooks[0];
|
||||||
assert.equal(manifest.hooks.PostToolUse[0].matcher, 'Edit|Write|MultiEdit');
|
assert.equal(manifest.hooks.PostToolUse[0].matcher, 'Edit|Write');
|
||||||
expectCommand(handler.command, 'skills/impeccable/scripts/hook.mjs');
|
expectCommand(handler.command, 'skills/impeccable/scripts/hook.mjs');
|
||||||
// Resolves relative to the installed plugin, not a `.claude/skills/` layout.
|
// Resolves relative to the installed plugin, not a `.claude/skills/` layout.
|
||||||
assert.ok(handler.command.includes('${CLAUDE_PLUGIN_ROOT}'),
|
assert.ok(handler.command.includes('${CLAUDE_PLUGIN_ROOT}'),
|
||||||
@@ -375,6 +376,15 @@ describe('generated hook artifacts in repo', () => {
|
|||||||
assert.ok(fs.existsSync(path.join(REPO_ROOT, 'plugin/skills/impeccable/scripts/hook-lib.mjs')));
|
assert.ok(fs.existsSync(path.join(REPO_ROOT, 'plugin/skills/impeccable/scripts/hook-lib.mjs')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps the marketplace hook repair matcher aligned with Claude Code', () => {
|
||||||
|
const hookAdmin = fs.readFileSync(
|
||||||
|
path.join(REPO_ROOT, 'plugin/skills/impeccable/scripts/hook-admin.mjs'),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
assert.match(hookAdmin, /matcher: 'Edit\|Write'/);
|
||||||
|
assert.doesNotMatch(hookAdmin, /matcher: 'Edit\|Write\|MultiEdit'/);
|
||||||
|
});
|
||||||
|
|
||||||
it('generated hook runtime can import the bundled detector', async () => {
|
it('generated hook runtime can import the bundled detector', async () => {
|
||||||
for (const scriptDir of [
|
for (const scriptDir of [
|
||||||
'.claude/skills/impeccable/scripts',
|
'.claude/skills/impeccable/scripts',
|
||||||
|
|||||||
@@ -947,6 +947,11 @@ describe('hook-admin.mjs', () => {
|
|||||||
// impeccable entry must have been stripped, not accumulated.
|
// impeccable entry must have been stripped, not accumulated.
|
||||||
assert.equal(claude.split('skills/impeccable/scripts/hook.mjs').length - 1, 2);
|
assert.equal(claude.split('skills/impeccable/scripts/hook.mjs').length - 1, 2);
|
||||||
assert.match(claude, /"Stop"/);
|
assert.match(claude, /"Stop"/);
|
||||||
|
const claudeManifest = JSON.parse(claude);
|
||||||
|
const impeccableGroup = claudeManifest.hooks.PostToolUse.find((group) =>
|
||||||
|
group.hooks?.some((hook) => hook.command?.includes('skills/impeccable/scripts/hook.mjs')));
|
||||||
|
assert.ok(impeccableGroup, 'repaired Claude settings should contain the Impeccable PostToolUse group');
|
||||||
|
assert.equal(impeccableGroup.matcher, 'Edit|Write');
|
||||||
|
|
||||||
const codex = fs.readFileSync(path.join(cwd, '.codex', 'hooks.json'), 'utf-8');
|
const codex = fs.readFileSync(path.join(cwd, '.codex', 'hooks.json'), 'utf-8');
|
||||||
assert.match(codex, /\.agents\/skills\/impeccable\/scripts\/hook\.mjs/);
|
assert.match(codex, /\.agents\/skills\/impeccable\/scripts\/hook\.mjs/);
|
||||||
|
|||||||
Reference in New Issue
Block a user