oh-my-claudecode 0.1.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/README.md +281 -0
- package/bin/oh-my-claudecode.js +5 -0
- package/dist/agents/azathoth.d.ts +19 -0
- package/dist/agents/azathoth.d.ts.map +1 -0
- package/dist/agents/azathoth.js +105 -0
- package/dist/agents/azathoth.js.map +1 -0
- package/dist/agents/builtin-agents.d.ts +18 -0
- package/dist/agents/builtin-agents.d.ts.map +1 -0
- package/dist/agents/builtin-agents.js +141 -0
- package/dist/agents/builtin-agents.js.map +1 -0
- package/dist/agents/cthulhu.d.ts +21 -0
- package/dist/agents/cthulhu.d.ts.map +1 -0
- package/dist/agents/cthulhu.js +368 -0
- package/dist/agents/cthulhu.js.map +1 -0
- package/dist/agents/dagon.d.ts +17 -0
- package/dist/agents/dagon.d.ts.map +1 -0
- package/dist/agents/dagon.js +190 -0
- package/dist/agents/dagon.js.map +1 -0
- package/dist/agents/hastur.d.ts +18 -0
- package/dist/agents/hastur.d.ts.map +1 -0
- package/dist/agents/hastur.js +92 -0
- package/dist/agents/hastur.js.map +1 -0
- package/dist/agents/index.d.ts +14 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +13 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/ithaqua.d.ts +19 -0
- package/dist/agents/ithaqua.d.ts.map +1 -0
- package/dist/agents/ithaqua.js +254 -0
- package/dist/agents/ithaqua.js.map +1 -0
- package/dist/agents/nyarlathotep.d.ts +18 -0
- package/dist/agents/nyarlathotep.d.ts.map +1 -0
- package/dist/agents/nyarlathotep.js +129 -0
- package/dist/agents/nyarlathotep.js.map +1 -0
- package/dist/agents/shoggoth.d.ts +17 -0
- package/dist/agents/shoggoth.d.ts.map +1 -0
- package/dist/agents/shoggoth.js +123 -0
- package/dist/agents/shoggoth.js.map +1 -0
- package/dist/agents/shub-niggurath.d.ts +18 -0
- package/dist/agents/shub-niggurath.d.ts.map +1 -0
- package/dist/agents/shub-niggurath.js +164 -0
- package/dist/agents/shub-niggurath.js.map +1 -0
- package/dist/agents/the-deep-one.d.ts +17 -0
- package/dist/agents/the-deep-one.d.ts.map +1 -0
- package/dist/agents/the-deep-one.js +114 -0
- package/dist/agents/the-deep-one.js.map +1 -0
- package/dist/agents/tsathoggua.d.ts +19 -0
- package/dist/agents/tsathoggua.d.ts.map +1 -0
- package/dist/agents/tsathoggua.js +177 -0
- package/dist/agents/tsathoggua.js.map +1 -0
- package/dist/agents/types.d.ts +61 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/yog-sothoth.d.ts +17 -0
- package/dist/agents/yog-sothoth.d.ts.map +1 -0
- package/dist/agents/yog-sothoth.js +147 -0
- package/dist/agents/yog-sothoth.js.map +1 -0
- package/dist/cli/doctor.d.ts +2 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +105 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +53 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/install.d.ts +5 -0
- package/dist/cli/install.d.ts.map +1 -0
- package/dist/cli/install.js +179 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +7406 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +197 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/features/background-agent/index.d.ts +58 -0
- package/dist/features/background-agent/index.d.ts.map +1 -0
- package/dist/features/background-agent/index.js +113 -0
- package/dist/features/background-agent/index.js.map +1 -0
- package/dist/features/mcp-manager/index.d.ts +40 -0
- package/dist/features/mcp-manager/index.d.ts.map +1 -0
- package/dist/features/mcp-manager/index.js +71 -0
- package/dist/features/mcp-manager/index.js.map +1 -0
- package/dist/features/skill-loader/index.d.ts +37 -0
- package/dist/features/skill-loader/index.d.ts.map +1 -0
- package/dist/features/skill-loader/index.js +81 -0
- package/dist/features/skill-loader/index.js.map +1 -0
- package/dist/hooks/comment-checker.d.ts +18 -0
- package/dist/hooks/comment-checker.d.ts.map +1 -0
- package/dist/hooks/comment-checker.js +75 -0
- package/dist/hooks/comment-checker.js.map +1 -0
- package/dist/hooks/elder-loop.d.ts +26 -0
- package/dist/hooks/elder-loop.d.ts.map +1 -0
- package/dist/hooks/elder-loop.js +84 -0
- package/dist/hooks/elder-loop.js.map +1 -0
- package/dist/hooks/index.d.ts +20 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +73 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/rules-injector.d.ts +12 -0
- package/dist/hooks/rules-injector.d.ts.map +1 -0
- package/dist/hooks/rules-injector.js +52 -0
- package/dist/hooks/rules-injector.js.map +1 -0
- package/dist/hooks/todo-continuation.d.ts +25 -0
- package/dist/hooks/todo-continuation.d.ts.map +1 -0
- package/dist/hooks/todo-continuation.js +74 -0
- package/dist/hooks/todo-continuation.js.map +1 -0
- package/dist/hooks/write-guard.d.ts +11 -0
- package/dist/hooks/write-guard.d.ts.map +1 -0
- package/dist/hooks/write-guard.js +39 -0
- package/dist/hooks/write-guard.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-config.d.ts +22 -0
- package/dist/plugin-config.d.ts.map +1 -0
- package/dist/plugin-config.js +133 -0
- package/dist/plugin-config.js.map +1 -0
- package/dist/plugin-handlers/config-handler.d.ts +21 -0
- package/dist/plugin-handlers/config-handler.d.ts.map +1 -0
- package/dist/plugin-handlers/config-handler.js +33 -0
- package/dist/plugin-handlers/config-handler.js.map +1 -0
- package/dist/plugin-handlers/index.d.ts +2 -0
- package/dist/plugin-handlers/index.d.ts.map +1 -0
- package/dist/plugin-handlers/index.js +2 -0
- package/dist/plugin-handlers/index.js.map +1 -0
- package/dist/shared/deep-merge.d.ts +6 -0
- package/dist/shared/deep-merge.d.ts.map +1 -0
- package/dist/shared/deep-merge.js +30 -0
- package/dist/shared/deep-merge.js.map +1 -0
- package/dist/shared/index.d.ts +5 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +5 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/log.d.ts +3 -0
- package/dist/shared/log.d.ts.map +1 -0
- package/dist/shared/log.js +22 -0
- package/dist/shared/log.js.map +1 -0
- package/dist/shared/model-resolution.d.ts +15 -0
- package/dist/shared/model-resolution.d.ts.map +1 -0
- package/dist/shared/model-resolution.js +46 -0
- package/dist/shared/model-resolution.js.map +1 -0
- package/dist/shared/parse-jsonc.d.ts +6 -0
- package/dist/shared/parse-jsonc.d.ts.map +1 -0
- package/dist/shared/parse-jsonc.js +14 -0
- package/dist/shared/parse-jsonc.js.map +1 -0
- package/package.json +42 -0
- package/skills/cancel-elder-loop.md +22 -0
- package/skills/cthulhu.md +45 -0
- package/skills/elder-loop.md +39 -0
- package/skills/exorcise-ai-slop.md +45 -0
- package/skills/invoke-shub.md +32 -0
- package/skills/old-ones-init.md +47 -0
- package/skills/session-handoff.md +57 -0
- package/skills/shoggoth.md +34 -0
- package/skills/yog-sothoth.md +30 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Loader
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: skill-loader
|
|
5
|
+
*
|
|
6
|
+
* Discovers and loads user-defined skills from:
|
|
7
|
+
* 1. Project-level: .claude/skills/<name>/SKILL.md
|
|
8
|
+
* 2. User-level: ~/.claude/skills/<name>/SKILL.md
|
|
9
|
+
*
|
|
10
|
+
* Skills are markdown files with YAML frontmatter. They can define:
|
|
11
|
+
* - name: The skill name (used in /name)
|
|
12
|
+
* - description: What the skill does
|
|
13
|
+
* - mcp_config: Optional MCP server to provision with this skill
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
/** Parse YAML-like frontmatter from markdown */
|
|
18
|
+
function parseFrontmatter(content) {
|
|
19
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
20
|
+
if (!match)
|
|
21
|
+
return { frontmatter: {}, body: content };
|
|
22
|
+
const frontmatter = {};
|
|
23
|
+
const rawFm = match[1];
|
|
24
|
+
for (const line of rawFm.split("\n")) {
|
|
25
|
+
const colonIdx = line.indexOf(":");
|
|
26
|
+
if (colonIdx === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = line.slice(0, colonIdx).trim();
|
|
29
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
30
|
+
frontmatter[key] = value;
|
|
31
|
+
}
|
|
32
|
+
return { frontmatter, body: match[2] };
|
|
33
|
+
}
|
|
34
|
+
/** Load skill files from a directory */
|
|
35
|
+
function loadSkillsFromDir(dir, source) {
|
|
36
|
+
if (!fs.existsSync(dir))
|
|
37
|
+
return [];
|
|
38
|
+
const skills = [];
|
|
39
|
+
// Check for flat structure: dir/*.md
|
|
40
|
+
const mdFiles = fs.readdirSync(dir)
|
|
41
|
+
.filter(f => f.endsWith(".md"))
|
|
42
|
+
.map(f => path.join(dir, f));
|
|
43
|
+
// Check for nested structure: dir/*/SKILL.md
|
|
44
|
+
const subdirs = fs.readdirSync(dir, { withFileTypes: true })
|
|
45
|
+
.filter(d => d.isDirectory())
|
|
46
|
+
.map(d => path.join(dir, d.name, "SKILL.md"))
|
|
47
|
+
.filter(p => fs.existsSync(p));
|
|
48
|
+
for (const filePath of [...mdFiles, ...subdirs]) {
|
|
49
|
+
try {
|
|
50
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
51
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
52
|
+
const name = String(frontmatter.name ?? path.basename(filePath, ".md"));
|
|
53
|
+
const description = String(frontmatter.description ?? "");
|
|
54
|
+
const mcpConfig = frontmatter.mcp_config;
|
|
55
|
+
skills.push({ name, description, content: body, mcpConfig, source, filePath });
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Skip unparseable skill files
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return skills;
|
|
62
|
+
}
|
|
63
|
+
/** Discover all skills from project and user directories */
|
|
64
|
+
export function discoverSkills(projectDirectory) {
|
|
65
|
+
const HOME = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
66
|
+
const projectSkillsDir = path.join(projectDirectory, ".claude", "skills");
|
|
67
|
+
const userSkillsDir = path.join(HOME, ".claude", "skills");
|
|
68
|
+
const projectSkills = loadSkillsFromDir(projectSkillsDir, "project");
|
|
69
|
+
const userSkills = loadSkillsFromDir(userSkillsDir, "user");
|
|
70
|
+
// Project skills override user skills with same name
|
|
71
|
+
const skillMap = new Map();
|
|
72
|
+
for (const skill of [...userSkills, ...projectSkills]) {
|
|
73
|
+
skillMap.set(skill.name, skill);
|
|
74
|
+
}
|
|
75
|
+
return [...skillMap.values()];
|
|
76
|
+
}
|
|
77
|
+
/** Get skills as AvailableSkill format for agent prompt building */
|
|
78
|
+
export function toAvailableSkills(skills) {
|
|
79
|
+
return skills.map(s => ({ name: s.name, description: s.description }));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/features/skill-loader/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment Checker Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: comment-checker
|
|
5
|
+
*
|
|
6
|
+
* Detects and removes AI-generated comment patterns that litter codebases.
|
|
7
|
+
* These are the "// Handle error gracefully" and "// TODO: implement this"
|
|
8
|
+
* comments that AI models add automatically — useless noise.
|
|
9
|
+
*
|
|
10
|
+
* In Claude Code: PostToolUse hook that checks written/edited files.
|
|
11
|
+
*/
|
|
12
|
+
/** Patterns that indicate AI-slop comments */
|
|
13
|
+
export declare const AI_SLOP_COMMENT_PATTERNS: RegExp[];
|
|
14
|
+
/** Python equivalents */
|
|
15
|
+
export declare const AI_SLOP_PYTHON_PATTERNS: RegExp[];
|
|
16
|
+
export declare const COMMENT_CHECKER_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Comment Checker PostToolUse Hook\n# Fires after Write/Edit \u2014 warns if AI-slop comments were introduced.\n\nset -euo pipefail\n\nTOOL_NAME=\"${CLAUDE_TOOL_NAME:-}\"\nFILE_PATH=\"${CLAUDE_TOOL_INPUT_FILE_PATH:-${CLAUDE_TOOL_INPUT_PATH:-}}\"\n\n# Only check Write/Edit tools\ncase \"$TOOL_NAME\" in\n Write|Edit) ;;\n *) exit 0 ;;\nesac\n\nif [ -z \"$FILE_PATH\" ] || [ ! -f \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check for AI-slop patterns\nSLOP=$(grep -nE '(//|#)s*(handle[s]? error|return (the )?(result|value)|log (the )?(error|message)|initialize (the )?[a-z]+|business logic|core (logic|functionality)|main implementation)' \"$FILE_PATH\" 2>/dev/null | head -5)\n\nif [ -n \"$SLOP\" ]; then\n echo \"[COMMENT CHECKER] Potential AI-slop comments detected in $FILE_PATH:\"\n echo \"$SLOP\"\n echo \"\"\n echo \"Consider removing comments that explain obvious code. Code should be self-documenting.\"\nfi\n";
|
|
17
|
+
export declare function getCommentCheckerHookConfig(): object;
|
|
18
|
+
//# sourceMappingURL=comment-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-checker.d.ts","sourceRoot":"","sources":["../../src/hooks/comment-checker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,UAapC,CAAA;AAED,yBAAyB;AACzB,eAAO,MAAM,uBAAuB,UAInC,CAAA;AAED,eAAO,MAAM,2BAA2B,08BA8BvC,CAAA;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAUpD"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment Checker Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: comment-checker
|
|
5
|
+
*
|
|
6
|
+
* Detects and removes AI-generated comment patterns that litter codebases.
|
|
7
|
+
* These are the "// Handle error gracefully" and "// TODO: implement this"
|
|
8
|
+
* comments that AI models add automatically — useless noise.
|
|
9
|
+
*
|
|
10
|
+
* In Claude Code: PostToolUse hook that checks written/edited files.
|
|
11
|
+
*/
|
|
12
|
+
/** Patterns that indicate AI-slop comments */
|
|
13
|
+
export const AI_SLOP_COMMENT_PATTERNS = [
|
|
14
|
+
// Explaining obvious things
|
|
15
|
+
/\/\/\s*(handle|handles|handling)\s+error/i,
|
|
16
|
+
/\/\/\s*return\s+(the\s+)?(result|value|response)/i,
|
|
17
|
+
/\/\/\s*log\s+(the\s+)?(error|message|output)/i,
|
|
18
|
+
/\/\/\s*initialize\s+(the\s+)?\w+/i,
|
|
19
|
+
/\/\/\s*check\s+(if\s+)?(the\s+)?\w+\s+(is\s+)?(valid|null|undefined|empty)/i,
|
|
20
|
+
// Generic implementation markers
|
|
21
|
+
/\/\/\s*(main\s+)?implementation/i,
|
|
22
|
+
/\/\/\s*business\s+logic/i,
|
|
23
|
+
/\/\/\s*core\s+(logic|functionality)/i,
|
|
24
|
+
// Unnecessary docstrings
|
|
25
|
+
/\/\*\*\s*\n\s*\*\s*@description\s+.{1,50}\n\s*\*\/\n\s*(export\s+)?(function|const|class)/,
|
|
26
|
+
];
|
|
27
|
+
/** Python equivalents */
|
|
28
|
+
export const AI_SLOP_PYTHON_PATTERNS = [
|
|
29
|
+
/#\s*(handle|handles|handling)\s+error/i,
|
|
30
|
+
/#\s*return\s+(the\s+)?(result|value|response)/i,
|
|
31
|
+
/#\s*main\s+logic/i,
|
|
32
|
+
];
|
|
33
|
+
export const COMMENT_CHECKER_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
34
|
+
# oh-my-claudecode: Comment Checker PostToolUse Hook
|
|
35
|
+
# Fires after Write/Edit — warns if AI-slop comments were introduced.
|
|
36
|
+
|
|
37
|
+
set -euo pipefail
|
|
38
|
+
|
|
39
|
+
TOOL_NAME="\${CLAUDE_TOOL_NAME:-}"
|
|
40
|
+
FILE_PATH="\${CLAUDE_TOOL_INPUT_FILE_PATH:-\${CLAUDE_TOOL_INPUT_PATH:-}}"
|
|
41
|
+
|
|
42
|
+
# Only check Write/Edit tools
|
|
43
|
+
case "$TOOL_NAME" in
|
|
44
|
+
Write|Edit) ;;
|
|
45
|
+
*) exit 0 ;;
|
|
46
|
+
esac
|
|
47
|
+
|
|
48
|
+
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Check for AI-slop patterns
|
|
53
|
+
SLOP=$(grep -nE \
|
|
54
|
+
'(//|#)\s*(handle[s]? error|return (the )?(result|value)|log (the )?(error|message)|initialize (the )?[a-z]+|business logic|core (logic|functionality)|main implementation)' \
|
|
55
|
+
"$FILE_PATH" 2>/dev/null | head -5)
|
|
56
|
+
|
|
57
|
+
if [ -n "$SLOP" ]; then
|
|
58
|
+
echo "[COMMENT CHECKER] Potential AI-slop comments detected in $FILE_PATH:"
|
|
59
|
+
echo "$SLOP"
|
|
60
|
+
echo ""
|
|
61
|
+
echo "Consider removing comments that explain obvious code. Code should be self-documenting."
|
|
62
|
+
fi
|
|
63
|
+
`;
|
|
64
|
+
export function getCommentCheckerHookConfig() {
|
|
65
|
+
return {
|
|
66
|
+
matcher: "Write|Edit",
|
|
67
|
+
hooks: [
|
|
68
|
+
{
|
|
69
|
+
type: "command",
|
|
70
|
+
command: "~/.claude/hooks/comment-checker.sh",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=comment-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-checker.js","sourceRoot":"","sources":["../../src/hooks/comment-checker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8CAA8C;AAC9C,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,4BAA4B;IAC5B,2CAA2C;IAC3C,mDAAmD;IACnD,+CAA+C;IAC/C,mCAAmC;IACnC,6EAA6E;IAC7E,iCAAiC;IACjC,kCAAkC;IAClC,0BAA0B;IAC1B,sCAAsC;IACtC,yBAAyB;IACzB,2FAA2F;CAC5F,CAAA;AAED,yBAAyB;AACzB,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,wCAAwC;IACxC,gDAAgD;IAChD,mBAAmB;CACpB,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAA;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,oCAAoC;aAC9C;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elder Loop Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: ralph-loop
|
|
5
|
+
*
|
|
6
|
+
* The Elder Loop is a self-referential completion mechanism — when activated,
|
|
7
|
+
* it causes Claude Code to continue iterating until a completion promise is met.
|
|
8
|
+
*
|
|
9
|
+
* Like Cthulhu dreaming in R'lyeh, the loop continues until the ancient one
|
|
10
|
+
* is satisfied. Unlike death, it CAN be stopped with /cancel-elder-loop.
|
|
11
|
+
*/
|
|
12
|
+
export interface ElderLoopState {
|
|
13
|
+
active: boolean;
|
|
14
|
+
iteration: number;
|
|
15
|
+
maxIterations: number;
|
|
16
|
+
completionPromise: string;
|
|
17
|
+
strategy: "reset" | "continue";
|
|
18
|
+
}
|
|
19
|
+
export declare function buildElderLoopSystemPrompt(state: ElderLoopState): string;
|
|
20
|
+
/**
|
|
21
|
+
* Stop hook script for the Elder Loop.
|
|
22
|
+
* Reads the loop state file and injects the continuation reminder.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ELDER_LOOP_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Elder Loop Stop Hook\n# Fires on Stop \u2014 if elder loop is active, injects continuation reminder.\n\nset -euo pipefail\n\nSTATE_FILE=\"${CLAUDE_PROJECT_DIR:-.}/.claude/elder-loop-state.json\"\n\nif [ ! -f \"$STATE_FILE\" ]; then\n exit 0\nfi\n\nACTIVE=$(python3 -c \"\nimport json, sys\ntry:\n with open('$STATE_FILE') as f:\n state = json.load(f)\n if state.get('active') and state.get('iteration', 0) < state.get('maxIterations', 10):\n state['iteration'] = state.get('iteration', 0) + 1\n with open('$STATE_FILE', 'w') as f:\n json.dump(state, f)\n print(json.dumps(state))\nexcept Exception:\n pass\n\" 2>/dev/null)\n\nif [ -n \"$ACTIVE\" ]; then\n ITERATION=$(echo \"$ACTIVE\" | python3 -c \"import json,sys; d=json.load(sys.stdin); print(d['iteration'])\")\n MAX=$(echo \"$ACTIVE\" | python3 -c \"import json,sys; d=json.load(sys.stdin); print(d['maxIterations'])\")\n PROMISE=$(echo \"$ACTIVE\" | python3 -c \"import json,sys; d=json.load(sys.stdin); print(d.get('completionPromise','Complete all tasks'))\")\n\n echo \"[SYSTEM REMINDER - ELDER LOOP]\"\n echo \"The Elder Loop is active. Iteration $ITERATION/$MAX.\"\n echo \"\"\n echo \"COMPLETION PROMISE:\"\n echo \"$PROMISE\"\n echo \"\"\n echo \"Continue working until the completion promise is fully met.\"\n echo \"[END ELDER LOOP REMINDER]\"\nfi\n";
|
|
25
|
+
export declare function getElderLoopHookConfig(): object;
|
|
26
|
+
//# sourceMappingURL=elder-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elder-loop.d.ts","sourceRoot":"","sources":["../../src/hooks/elder-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,OAAO,GAAG,UAAU,CAAA;CAC/B;AAID,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAcxE;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,64CAwClC,CAAA;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAU/C"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elder Loop Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: ralph-loop
|
|
5
|
+
*
|
|
6
|
+
* The Elder Loop is a self-referential completion mechanism — when activated,
|
|
7
|
+
* it causes Claude Code to continue iterating until a completion promise is met.
|
|
8
|
+
*
|
|
9
|
+
* Like Cthulhu dreaming in R'lyeh, the loop continues until the ancient one
|
|
10
|
+
* is satisfied. Unlike death, it CAN be stopped with /cancel-elder-loop.
|
|
11
|
+
*/
|
|
12
|
+
const ELDER_LOOP_STATE_FILE = ".claude/elder-loop-state.json";
|
|
13
|
+
export function buildElderLoopSystemPrompt(state) {
|
|
14
|
+
return `[SYSTEM REMINDER - ELDER LOOP]
|
|
15
|
+
The Elder Loop is active. Iteration ${state.iteration}/${state.maxIterations}.
|
|
16
|
+
|
|
17
|
+
COMPLETION PROMISE:
|
|
18
|
+
${state.completionPromise}
|
|
19
|
+
|
|
20
|
+
You must continue working until the completion promise is fully met.
|
|
21
|
+
- If the promise is not yet met: continue working
|
|
22
|
+
- If the promise IS met: report completion and stop
|
|
23
|
+
- If you are uncertain: check by running tests or diagnostics
|
|
24
|
+
|
|
25
|
+
This is iteration ${state.iteration} of ${state.maxIterations}. If the maximum is reached, report status.
|
|
26
|
+
[END ELDER LOOP REMINDER]`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Stop hook script for the Elder Loop.
|
|
30
|
+
* Reads the loop state file and injects the continuation reminder.
|
|
31
|
+
*/
|
|
32
|
+
export const ELDER_LOOP_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
33
|
+
# oh-my-claudecode: Elder Loop Stop Hook
|
|
34
|
+
# Fires on Stop — if elder loop is active, injects continuation reminder.
|
|
35
|
+
|
|
36
|
+
set -euo pipefail
|
|
37
|
+
|
|
38
|
+
STATE_FILE="\${CLAUDE_PROJECT_DIR:-.}/.claude/elder-loop-state.json"
|
|
39
|
+
|
|
40
|
+
if [ ! -f "$STATE_FILE" ]; then
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
ACTIVE=$(python3 -c "
|
|
45
|
+
import json, sys
|
|
46
|
+
try:
|
|
47
|
+
with open('$STATE_FILE') as f:
|
|
48
|
+
state = json.load(f)
|
|
49
|
+
if state.get('active') and state.get('iteration', 0) < state.get('maxIterations', 10):
|
|
50
|
+
state['iteration'] = state.get('iteration', 0) + 1
|
|
51
|
+
with open('$STATE_FILE', 'w') as f:
|
|
52
|
+
json.dump(state, f)
|
|
53
|
+
print(json.dumps(state))
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
" 2>/dev/null)
|
|
57
|
+
|
|
58
|
+
if [ -n "$ACTIVE" ]; then
|
|
59
|
+
ITERATION=$(echo "$ACTIVE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['iteration'])")
|
|
60
|
+
MAX=$(echo "$ACTIVE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['maxIterations'])")
|
|
61
|
+
PROMISE=$(echo "$ACTIVE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('completionPromise','Complete all tasks'))")
|
|
62
|
+
|
|
63
|
+
echo "[SYSTEM REMINDER - ELDER LOOP]"
|
|
64
|
+
echo "The Elder Loop is active. Iteration $ITERATION/$MAX."
|
|
65
|
+
echo ""
|
|
66
|
+
echo "COMPLETION PROMISE:"
|
|
67
|
+
echo "$PROMISE"
|
|
68
|
+
echo ""
|
|
69
|
+
echo "Continue working until the completion promise is fully met."
|
|
70
|
+
echo "[END ELDER LOOP REMINDER]"
|
|
71
|
+
fi
|
|
72
|
+
`;
|
|
73
|
+
export function getElderLoopHookConfig() {
|
|
74
|
+
return {
|
|
75
|
+
matcher: "",
|
|
76
|
+
hooks: [
|
|
77
|
+
{
|
|
78
|
+
type: "command",
|
|
79
|
+
command: "~/.claude/hooks/elder-loop.sh",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=elder-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elder-loop.js","sourceRoot":"","sources":["../../src/hooks/elder-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,qBAAqB,GAAG,+BAA+B,CAAA;AAE7D,MAAM,UAAU,0BAA0B,CAAC,KAAqB;IAC9D,OAAO;sCAC6B,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,aAAa;;;EAG1E,KAAK,CAAC,iBAAiB;;;;;;;oBAOL,KAAK,CAAC,SAAS,OAAO,KAAK,CAAC,aAAa;0BACnC,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCrC,CAAA;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,OAAO,EAAE,EAAE;QACX,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,+BAA+B;aACzC;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OhMyClaudeCodeConfig, HookName } from "../config/schema.js";
|
|
2
|
+
export { TODO_CONTINUATION_HOOK_SCRIPT, getTodoContinuationHookConfig } from "./todo-continuation.js";
|
|
3
|
+
export { ELDER_LOOP_HOOK_SCRIPT, getElderLoopHookConfig } from "./elder-loop.js";
|
|
4
|
+
export { COMMENT_CHECKER_HOOK_SCRIPT, getCommentCheckerHookConfig } from "./comment-checker.js";
|
|
5
|
+
export { RULES_INJECTOR_HOOK_SCRIPT, getRulesInjectorHookConfig } from "./rules-injector.js";
|
|
6
|
+
export { WRITE_GUARD_HOOK_SCRIPT, getWriteGuardHookConfig } from "./write-guard.js";
|
|
7
|
+
export interface HookDefinition {
|
|
8
|
+
name: HookName;
|
|
9
|
+
event: "PreToolUse" | "PostToolUse" | "Stop" | "Notification";
|
|
10
|
+
scriptPath: string;
|
|
11
|
+
scriptContent: string;
|
|
12
|
+
config: object;
|
|
13
|
+
}
|
|
14
|
+
/** All hook definitions for the plugin */
|
|
15
|
+
export declare const ALL_HOOK_DEFINITIONS: HookDefinition[];
|
|
16
|
+
/** Get hooks that should be installed, respecting disabled_hooks config */
|
|
17
|
+
export declare function getEnabledHooks(config: OhMyClaudeCodeConfig): HookDefinition[];
|
|
18
|
+
/** Build Claude Code settings.json hooks section from enabled hook definitions */
|
|
19
|
+
export declare function buildHooksConfig(enabledHooks: HookDefinition[]): Record<string, object[]>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEzE,OAAO,EAAE,6BAA6B,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AACrG,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAA;AAC/F,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA;AAC5F,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAEnF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,YAAY,GAAG,aAAa,GAAG,MAAM,GAAG,cAAc,CAAA;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf;AAuBD,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,EAAE,cAAc,EAoChD,CAAA;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc,EAAE,CAG9E;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAoBzF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export { TODO_CONTINUATION_HOOK_SCRIPT, getTodoContinuationHookConfig } from "./todo-continuation.js";
|
|
2
|
+
export { ELDER_LOOP_HOOK_SCRIPT, getElderLoopHookConfig } from "./elder-loop.js";
|
|
3
|
+
export { COMMENT_CHECKER_HOOK_SCRIPT, getCommentCheckerHookConfig } from "./comment-checker.js";
|
|
4
|
+
export { RULES_INJECTOR_HOOK_SCRIPT, getRulesInjectorHookConfig } from "./rules-injector.js";
|
|
5
|
+
export { WRITE_GUARD_HOOK_SCRIPT, getWriteGuardHookConfig } from "./write-guard.js";
|
|
6
|
+
import { TODO_CONTINUATION_HOOK_SCRIPT, getTodoContinuationHookConfig, } from "./todo-continuation.js";
|
|
7
|
+
import { ELDER_LOOP_HOOK_SCRIPT, getElderLoopHookConfig, } from "./elder-loop.js";
|
|
8
|
+
import { COMMENT_CHECKER_HOOK_SCRIPT, getCommentCheckerHookConfig, } from "./comment-checker.js";
|
|
9
|
+
import { RULES_INJECTOR_HOOK_SCRIPT, getRulesInjectorHookConfig, } from "./rules-injector.js";
|
|
10
|
+
import { WRITE_GUARD_HOOK_SCRIPT, getWriteGuardHookConfig, } from "./write-guard.js";
|
|
11
|
+
/** All hook definitions for the plugin */
|
|
12
|
+
export const ALL_HOOK_DEFINITIONS = [
|
|
13
|
+
{
|
|
14
|
+
name: "todo-continuation",
|
|
15
|
+
event: "Stop",
|
|
16
|
+
scriptPath: "~/.claude/hooks/todo-continuation.sh",
|
|
17
|
+
scriptContent: TODO_CONTINUATION_HOOK_SCRIPT,
|
|
18
|
+
config: getTodoContinuationHookConfig(),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "elder-loop",
|
|
22
|
+
event: "Stop",
|
|
23
|
+
scriptPath: "~/.claude/hooks/elder-loop.sh",
|
|
24
|
+
scriptContent: ELDER_LOOP_HOOK_SCRIPT,
|
|
25
|
+
config: getElderLoopHookConfig(),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "comment-checker",
|
|
29
|
+
event: "PostToolUse",
|
|
30
|
+
scriptPath: "~/.claude/hooks/comment-checker.sh",
|
|
31
|
+
scriptContent: COMMENT_CHECKER_HOOK_SCRIPT,
|
|
32
|
+
config: getCommentCheckerHookConfig(),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "rules-injector",
|
|
36
|
+
event: "PreToolUse",
|
|
37
|
+
scriptPath: "~/.claude/hooks/rules-injector.sh",
|
|
38
|
+
scriptContent: RULES_INJECTOR_HOOK_SCRIPT,
|
|
39
|
+
config: getRulesInjectorHookConfig(),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "write-guard",
|
|
43
|
+
event: "PreToolUse",
|
|
44
|
+
scriptPath: "~/.claude/hooks/write-guard.sh",
|
|
45
|
+
scriptContent: WRITE_GUARD_HOOK_SCRIPT,
|
|
46
|
+
config: getWriteGuardHookConfig(),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
/** Get hooks that should be installed, respecting disabled_hooks config */
|
|
50
|
+
export function getEnabledHooks(config) {
|
|
51
|
+
const disabled = new Set(config.disabled_hooks ?? []);
|
|
52
|
+
return ALL_HOOK_DEFINITIONS.filter(h => !disabled.has(h.name));
|
|
53
|
+
}
|
|
54
|
+
/** Build Claude Code settings.json hooks section from enabled hook definitions */
|
|
55
|
+
export function buildHooksConfig(enabledHooks) {
|
|
56
|
+
const hooksByEvent = {
|
|
57
|
+
PreToolUse: [],
|
|
58
|
+
PostToolUse: [],
|
|
59
|
+
Stop: [],
|
|
60
|
+
Notification: [],
|
|
61
|
+
};
|
|
62
|
+
for (const hook of enabledHooks) {
|
|
63
|
+
hooksByEvent[hook.event].push(hook.config);
|
|
64
|
+
}
|
|
65
|
+
// Remove empty arrays
|
|
66
|
+
for (const event of Object.keys(hooksByEvent)) {
|
|
67
|
+
if (hooksByEvent[event].length === 0) {
|
|
68
|
+
delete hooksByEvent[event];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return hooksByEvent;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rules Injector Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: rules-injector
|
|
5
|
+
*
|
|
6
|
+
* Loads `.elder-gods/rules/*.md` files and injects them as system context.
|
|
7
|
+
* This is the Cthulhu equivalent of sisyphus rules — project-specific
|
|
8
|
+
* architectural enforcement rules that every agent must follow.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RULES_INJECTOR_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Rules Injector PreToolUse Hook\n# Fires on first message \u2014 injects .elder-gods/rules/*.md into context.\n\nset -euo pipefail\n\nRULES_DIR=\"${CLAUDE_PROJECT_DIR:-.}/.elder-gods/rules\"\n\nif [ ! -d \"$RULES_DIR\" ]; then\n exit 0\nfi\n\nRULES_FILES=$(find \"$RULES_DIR\" -name \"*.md\" -type f 2>/dev/null | sort)\n\nif [ -z \"$RULES_FILES\" ]; then\n exit 0\nfi\n\necho \"[SYSTEM RULES - ELDER GODS]\"\necho \"The following architectural rules govern this project:\"\necho \"\"\n\nwhile IFS= read -r rule_file; do\n RULE_NAME=$(basename \"$rule_file\" .md)\n echo \"## Rule: $RULE_NAME\"\n cat \"$rule_file\"\n echo \"\"\ndone <<< \"$RULES_FILES\"\n\necho \"[END SYSTEM RULES]\"\n";
|
|
11
|
+
export declare function getRulesInjectorHookConfig(): object;
|
|
12
|
+
//# sourceMappingURL=rules-injector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-injector.d.ts","sourceRoot":"","sources":["../../src/hooks/rules-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,0BAA0B,kuBA8BtC,CAAA;AAED,wBAAgB,0BAA0B,IAAI,MAAM,CAUnD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rules Injector Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: rules-injector
|
|
5
|
+
*
|
|
6
|
+
* Loads `.elder-gods/rules/*.md` files and injects them as system context.
|
|
7
|
+
* This is the Cthulhu equivalent of sisyphus rules — project-specific
|
|
8
|
+
* architectural enforcement rules that every agent must follow.
|
|
9
|
+
*/
|
|
10
|
+
export const RULES_INJECTOR_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
11
|
+
# oh-my-claudecode: Rules Injector PreToolUse Hook
|
|
12
|
+
# Fires on first message — injects .elder-gods/rules/*.md into context.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
RULES_DIR="\${CLAUDE_PROJECT_DIR:-.}/.elder-gods/rules"
|
|
17
|
+
|
|
18
|
+
if [ ! -d "$RULES_DIR" ]; then
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
RULES_FILES=$(find "$RULES_DIR" -name "*.md" -type f 2>/dev/null | sort)
|
|
23
|
+
|
|
24
|
+
if [ -z "$RULES_FILES" ]; then
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
echo "[SYSTEM RULES - ELDER GODS]"
|
|
29
|
+
echo "The following architectural rules govern this project:"
|
|
30
|
+
echo ""
|
|
31
|
+
|
|
32
|
+
while IFS= read -r rule_file; do
|
|
33
|
+
RULE_NAME=$(basename "$rule_file" .md)
|
|
34
|
+
echo "## Rule: $RULE_NAME"
|
|
35
|
+
cat "$rule_file"
|
|
36
|
+
echo ""
|
|
37
|
+
done <<< "$RULES_FILES"
|
|
38
|
+
|
|
39
|
+
echo "[END SYSTEM RULES]"
|
|
40
|
+
`;
|
|
41
|
+
export function getRulesInjectorHookConfig() {
|
|
42
|
+
return {
|
|
43
|
+
matcher: "",
|
|
44
|
+
hooks: [
|
|
45
|
+
{
|
|
46
|
+
type: "command",
|
|
47
|
+
command: "~/.claude/hooks/rules-injector.sh",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=rules-injector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-injector.js","sourceRoot":"","sources":["../../src/hooks/rules-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BzC,CAAA;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,OAAO,EAAE,EAAE;QACX,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,mCAAmC;aAC7C;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Todo Continuation Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: todo-continuation-enforcer
|
|
5
|
+
*
|
|
6
|
+
* When Claude Code's Stop event fires but there are incomplete todos,
|
|
7
|
+
* this hook injects a reminder that the agent should keep working.
|
|
8
|
+
*
|
|
9
|
+
* In Claude Code: configured as a Stop hook that checks the todo state
|
|
10
|
+
* and emits a system reminder if incomplete todos exist.
|
|
11
|
+
*/
|
|
12
|
+
export interface TodoContinuationOptions {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
checkCommand?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Shell script content for the todo continuation Stop hook.
|
|
18
|
+
* This is installed into Claude Code's settings.json hooks.
|
|
19
|
+
*/
|
|
20
|
+
export declare const TODO_CONTINUATION_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Todo Continuation Enforcer\n# Fires on Stop \u2014 if incomplete todos exist, prints a reminder to keep working.\n\nset -euo pipefail\n\nTRANSCRIPT_PATH=\"${CLAUDE_TRANSCRIPT:-}\"\nif [ -z \"$TRANSCRIPT_PATH\" ]; then\n exit 0\nfi\n\n# Check for incomplete TodoWrite entries in the transcript\nINCOMPLETE=$(python3 -c \"\nimport json, sys\n\ntry:\n with open('$TRANSCRIPT_PATH') as f:\n data = json.load(f)\nexcept Exception:\n sys.exit(0)\n\nmessages = data.get('messages', [])\nfor msg in reversed(messages):\n if msg.get('role') != 'tool':\n continue\n for block in msg.get('content', []):\n if isinstance(block, dict) and block.get('type') == 'tool_result':\n for item in block.get('content', []):\n if isinstance(item, dict) and 'todo' in str(item).lower():\n # Found a todo block \u2014 check for incomplete items\n text = str(item)\n if 'in_progress' in text or 'pending' in text:\n print('INCOMPLETE')\n sys.exit(0)\nsys.exit(0)\n\" 2>/dev/null)\n\nif [ \"$INCOMPLETE\" = \"INCOMPLETE\" ]; then\n echo '[SYSTEM REMINDER - TODO CONTINUATION]'\n echo 'You have incomplete todo items. The Elder Gods demand completion.'\n echo 'Resume work on your in-progress items. Do not stop until all todos are marked completed.'\n echo '[END SYSTEM REMINDER]'\nfi\n";
|
|
21
|
+
/**
|
|
22
|
+
* Generates the hook configuration entry for Claude Code settings.json
|
|
23
|
+
*/
|
|
24
|
+
export declare function getTodoContinuationHookConfig(): object;
|
|
25
|
+
//# sourceMappingURL=todo-continuation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-continuation.d.ts","sourceRoot":"","sources":["../../src/hooks/todo-continuation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,6BAA6B,g8CA2CzC,CAAA;AAED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAUtD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Todo Continuation Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: todo-continuation-enforcer
|
|
5
|
+
*
|
|
6
|
+
* When Claude Code's Stop event fires but there are incomplete todos,
|
|
7
|
+
* this hook injects a reminder that the agent should keep working.
|
|
8
|
+
*
|
|
9
|
+
* In Claude Code: configured as a Stop hook that checks the todo state
|
|
10
|
+
* and emits a system reminder if incomplete todos exist.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Shell script content for the todo continuation Stop hook.
|
|
14
|
+
* This is installed into Claude Code's settings.json hooks.
|
|
15
|
+
*/
|
|
16
|
+
export const TODO_CONTINUATION_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
17
|
+
# oh-my-claudecode: Todo Continuation Enforcer
|
|
18
|
+
# Fires on Stop — if incomplete todos exist, prints a reminder to keep working.
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
TRANSCRIPT_PATH="\${CLAUDE_TRANSCRIPT:-}"
|
|
23
|
+
if [ -z "$TRANSCRIPT_PATH" ]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Check for incomplete TodoWrite entries in the transcript
|
|
28
|
+
INCOMPLETE=$(python3 -c "
|
|
29
|
+
import json, sys
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
with open('$TRANSCRIPT_PATH') as f:
|
|
33
|
+
data = json.load(f)
|
|
34
|
+
except Exception:
|
|
35
|
+
sys.exit(0)
|
|
36
|
+
|
|
37
|
+
messages = data.get('messages', [])
|
|
38
|
+
for msg in reversed(messages):
|
|
39
|
+
if msg.get('role') != 'tool':
|
|
40
|
+
continue
|
|
41
|
+
for block in msg.get('content', []):
|
|
42
|
+
if isinstance(block, dict) and block.get('type') == 'tool_result':
|
|
43
|
+
for item in block.get('content', []):
|
|
44
|
+
if isinstance(item, dict) and 'todo' in str(item).lower():
|
|
45
|
+
# Found a todo block — check for incomplete items
|
|
46
|
+
text = str(item)
|
|
47
|
+
if 'in_progress' in text or 'pending' in text:
|
|
48
|
+
print('INCOMPLETE')
|
|
49
|
+
sys.exit(0)
|
|
50
|
+
sys.exit(0)
|
|
51
|
+
" 2>/dev/null)
|
|
52
|
+
|
|
53
|
+
if [ "$INCOMPLETE" = "INCOMPLETE" ]; then
|
|
54
|
+
echo '[SYSTEM REMINDER - TODO CONTINUATION]'
|
|
55
|
+
echo 'You have incomplete todo items. The Elder Gods demand completion.'
|
|
56
|
+
echo 'Resume work on your in-progress items. Do not stop until all todos are marked completed.'
|
|
57
|
+
echo '[END SYSTEM REMINDER]'
|
|
58
|
+
fi
|
|
59
|
+
`;
|
|
60
|
+
/**
|
|
61
|
+
* Generates the hook configuration entry for Claude Code settings.json
|
|
62
|
+
*/
|
|
63
|
+
export function getTodoContinuationHookConfig() {
|
|
64
|
+
return {
|
|
65
|
+
matcher: "",
|
|
66
|
+
hooks: [
|
|
67
|
+
{
|
|
68
|
+
type: "command",
|
|
69
|
+
command: "~/.claude/hooks/todo-continuation.sh",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=todo-continuation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-continuation.js","sourceRoot":"","sources":["../../src/hooks/todo-continuation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C5C,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,6BAA6B;IAC3C,OAAO;QACL,OAAO,EAAE,EAAE;QACX,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,sCAAsC;aAChD;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write Guard Hook
|
|
3
|
+
*
|
|
4
|
+
* Mapped from: write-existing-file-guard
|
|
5
|
+
*
|
|
6
|
+
* Warns when Write is used on an existing file (should use Edit instead).
|
|
7
|
+
* Prevents accidental full-file overwrites when only a portion should change.
|
|
8
|
+
*/
|
|
9
|
+
export declare const WRITE_GUARD_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Write Guard PreToolUse Hook\n# Fires before Write \u2014 warns if writing to an existing file.\n\nset -euo pipefail\n\nTOOL_NAME=\"${CLAUDE_TOOL_NAME:-}\"\nFILE_PATH=\"${CLAUDE_TOOL_INPUT_FILE_PATH:-}\"\n\nif [ \"$TOOL_NAME\" != \"Write\" ] || [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\nif [ -f \"$FILE_PATH\" ]; then\n echo \"[WRITE GUARD] Warning: Write tool used on existing file: $FILE_PATH\"\n echo \"Consider using Edit instead to preserve unintended changes.\"\n echo \"If you intend to fully replace this file, proceed.\"\nfi\n";
|
|
10
|
+
export declare function getWriteGuardHookConfig(): object;
|
|
11
|
+
//# sourceMappingURL=write-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/write-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,uBAAuB,0kBAkBnC,CAAA;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAUhD"}
|