@damian87/omp 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.
Files changed (166) hide show
  1. package/.github/agents/architect.md +25 -0
  2. package/.github/agents/code-reviewer.md +25 -0
  3. package/.github/agents/designer.md +26 -0
  4. package/.github/agents/executor.md +24 -0
  5. package/.github/agents/planner.md +26 -0
  6. package/.github/agents/researcher.md +26 -0
  7. package/.github/agents/verifier.md +26 -0
  8. package/.github/copilot-instructions.md +20 -0
  9. package/.github/plugin/marketplace.json +30 -0
  10. package/.github/skills/caveman/SKILL.md +20 -0
  11. package/.github/skills/code-review/SKILL.md +22 -0
  12. package/.github/skills/codebase-research/SKILL.md +20 -0
  13. package/.github/skills/create-skill/SKILL.md +78 -0
  14. package/.github/skills/create-skill/references/best-practices.md +449 -0
  15. package/.github/skills/create-skill/references/examples.md +69 -0
  16. package/.github/skills/create-skill/references/progressive-disclosure.md +25 -0
  17. package/.github/skills/create-skill/references/skill-structure.md +55 -0
  18. package/.github/skills/debug/SKILL.md +22 -0
  19. package/.github/skills/grill-me/SKILL.md +16 -0
  20. package/.github/skills/jira-ticket/SKILL.md +21 -0
  21. package/.github/skills/omp-autopilot/SKILL.md +20 -0
  22. package/.github/skills/prototype/SKILL.md +21 -0
  23. package/.github/skills/ralph/SKILL.md +20 -0
  24. package/.github/skills/ralplan/SKILL.md +21 -0
  25. package/.github/skills/self-evolve/SKILL.md +157 -0
  26. package/.github/skills/tdd/SKILL.md +19 -0
  27. package/.github/skills/team/SKILL.md +20 -0
  28. package/.github/skills/ultraqa/SKILL.md +20 -0
  29. package/.github/skills/ultrawork/SKILL.md +20 -0
  30. package/.github/skills/verify/SKILL.md +20 -0
  31. package/LICENSE +21 -0
  32. package/README.md +214 -0
  33. package/catalog/capabilities.json +729 -0
  34. package/catalog/skills-general.json +427 -0
  35. package/dist/src/catalog.d.ts +79 -0
  36. package/dist/src/catalog.js +113 -0
  37. package/dist/src/catalog.js.map +1 -0
  38. package/dist/src/cli.d.ts +9 -0
  39. package/dist/src/cli.js +475 -0
  40. package/dist/src/cli.js.map +1 -0
  41. package/dist/src/copilot/config.d.ts +7 -0
  42. package/dist/src/copilot/config.js +24 -0
  43. package/dist/src/copilot/config.js.map +1 -0
  44. package/dist/src/copilot/doctor.d.ts +18 -0
  45. package/dist/src/copilot/doctor.js +85 -0
  46. package/dist/src/copilot/doctor.js.map +1 -0
  47. package/dist/src/copilot/launch.d.ts +14 -0
  48. package/dist/src/copilot/launch.js +64 -0
  49. package/dist/src/copilot/launch.js.map +1 -0
  50. package/dist/src/copilot/list.d.ts +17 -0
  51. package/dist/src/copilot/list.js +82 -0
  52. package/dist/src/copilot/list.js.map +1 -0
  53. package/dist/src/copilot/paths.d.ts +21 -0
  54. package/dist/src/copilot/paths.js +36 -0
  55. package/dist/src/copilot/paths.js.map +1 -0
  56. package/dist/src/copilot/setup.d.ts +20 -0
  57. package/dist/src/copilot/setup.js +90 -0
  58. package/dist/src/copilot/setup.js.map +1 -0
  59. package/dist/src/copilot/version.d.ts +13 -0
  60. package/dist/src/copilot/version.js +34 -0
  61. package/dist/src/copilot/version.js.map +1 -0
  62. package/dist/src/jira.d.ts +149 -0
  63. package/dist/src/jira.js +492 -0
  64. package/dist/src/jira.js.map +1 -0
  65. package/dist/src/lint.d.ts +11 -0
  66. package/dist/src/lint.js +85 -0
  67. package/dist/src/lint.js.map +1 -0
  68. package/dist/src/mcp/server.d.ts +10 -0
  69. package/dist/src/mcp/server.js +44 -0
  70. package/dist/src/mcp/server.js.map +1 -0
  71. package/dist/src/mcp/tools/index.d.ts +9 -0
  72. package/dist/src/mcp/tools/index.js +15 -0
  73. package/dist/src/mcp/tools/index.js.map +1 -0
  74. package/dist/src/mcp/tools/notepad.d.ts +2 -0
  75. package/dist/src/mcp/tools/notepad.js +135 -0
  76. package/dist/src/mcp/tools/notepad.js.map +1 -0
  77. package/dist/src/mcp/tools/project-memory.d.ts +2 -0
  78. package/dist/src/mcp/tools/project-memory.js +91 -0
  79. package/dist/src/mcp/tools/project-memory.js.map +1 -0
  80. package/dist/src/mcp/tools/shared-memory.d.ts +2 -0
  81. package/dist/src/mcp/tools/shared-memory.js +148 -0
  82. package/dist/src/mcp/tools/shared-memory.js.map +1 -0
  83. package/dist/src/mcp/tools/state.d.ts +2 -0
  84. package/dist/src/mcp/tools/state.js +107 -0
  85. package/dist/src/mcp/tools/state.js.map +1 -0
  86. package/dist/src/mcp/tools/trace.d.ts +10 -0
  87. package/dist/src/mcp/tools/trace.js +102 -0
  88. package/dist/src/mcp/tools/trace.js.map +1 -0
  89. package/dist/src/mcp/types.d.ts +29 -0
  90. package/dist/src/mcp/types.js +7 -0
  91. package/dist/src/mcp/types.js.map +1 -0
  92. package/dist/src/mode-state/index.d.ts +4 -0
  93. package/dist/src/mode-state/index.js +5 -0
  94. package/dist/src/mode-state/index.js.map +1 -0
  95. package/dist/src/mode-state/paths.d.ts +5 -0
  96. package/dist/src/mode-state/paths.js +29 -0
  97. package/dist/src/mode-state/paths.js.map +1 -0
  98. package/dist/src/mode-state/ralph.d.ts +25 -0
  99. package/dist/src/mode-state/ralph.js +44 -0
  100. package/dist/src/mode-state/ralph.js.map +1 -0
  101. package/dist/src/mode-state/ultraqa.d.ts +26 -0
  102. package/dist/src/mode-state/ultraqa.js +51 -0
  103. package/dist/src/mode-state/ultraqa.js.map +1 -0
  104. package/dist/src/mode-state/ultrawork.d.ts +20 -0
  105. package/dist/src/mode-state/ultrawork.js +34 -0
  106. package/dist/src/mode-state/ultrawork.js.map +1 -0
  107. package/dist/src/project.d.ts +29 -0
  108. package/dist/src/project.js +101 -0
  109. package/dist/src/project.js.map +1 -0
  110. package/dist/src/skills.d.ts +17 -0
  111. package/dist/src/skills.js +61 -0
  112. package/dist/src/skills.js.map +1 -0
  113. package/dist/src/sync.d.ts +6 -0
  114. package/dist/src/sync.js +27 -0
  115. package/dist/src/sync.js.map +1 -0
  116. package/dist/src/team/api.d.ts +20 -0
  117. package/dist/src/team/api.js +55 -0
  118. package/dist/src/team/api.js.map +1 -0
  119. package/dist/src/team/heartbeat.d.ts +4 -0
  120. package/dist/src/team/heartbeat.js +27 -0
  121. package/dist/src/team/heartbeat.js.map +1 -0
  122. package/dist/src/team/idle-nudge.d.ts +27 -0
  123. package/dist/src/team/idle-nudge.js +60 -0
  124. package/dist/src/team/idle-nudge.js.map +1 -0
  125. package/dist/src/team/inbox.d.ts +3 -0
  126. package/dist/src/team/inbox.js +16 -0
  127. package/dist/src/team/inbox.js.map +1 -0
  128. package/dist/src/team/index.d.ts +11 -0
  129. package/dist/src/team/index.js +12 -0
  130. package/dist/src/team/index.js.map +1 -0
  131. package/dist/src/team/outbox.d.ts +14 -0
  132. package/dist/src/team/outbox.js +82 -0
  133. package/dist/src/team/outbox.js.map +1 -0
  134. package/dist/src/team/runtime.d.ts +84 -0
  135. package/dist/src/team/runtime.js +243 -0
  136. package/dist/src/team/runtime.js.map +1 -0
  137. package/dist/src/team/state-paths.d.ts +31 -0
  138. package/dist/src/team/state-paths.js +54 -0
  139. package/dist/src/team/state-paths.js.map +1 -0
  140. package/dist/src/team/task-store.d.ts +41 -0
  141. package/dist/src/team/task-store.js +153 -0
  142. package/dist/src/team/task-store.js.map +1 -0
  143. package/dist/src/team/tmux.d.ts +26 -0
  144. package/dist/src/team/tmux.js +87 -0
  145. package/dist/src/team/tmux.js.map +1 -0
  146. package/dist/src/team/types.d.ts +45 -0
  147. package/dist/src/team/types.js +2 -0
  148. package/dist/src/team/types.js.map +1 -0
  149. package/dist/src/team/worker-bootstrap.d.ts +8 -0
  150. package/dist/src/team/worker-bootstrap.js +52 -0
  151. package/dist/src/team/worker-bootstrap.js.map +1 -0
  152. package/docs/copilot-distribution.md +100 -0
  153. package/docs/general-skills.md +76 -0
  154. package/docs/jira.md +64 -0
  155. package/docs/self-evolve.md +22 -0
  156. package/hooks/hooks.json +74 -0
  157. package/package.json +58 -0
  158. package/plugin.json +14 -0
  159. package/scripts/error.mjs +31 -0
  160. package/scripts/lib/hook-output.mjs +30 -0
  161. package/scripts/lib/stdin.mjs +29 -0
  162. package/scripts/post-tool-use.mjs +31 -0
  163. package/scripts/pre-tool-use.mjs +30 -0
  164. package/scripts/prompt-submit.mjs +66 -0
  165. package/scripts/session-end.mjs +29 -0
  166. package/scripts/session-start.mjs +33 -0
@@ -0,0 +1,22 @@
1
+ # Self-evolve loop
2
+
3
+ A two-file mechanism that turns repeated user corrections into draft project skills.
4
+
5
+ - `AGENTS.md` instructs the agent to invoke `/self-evolve` before ending a session.
6
+ - `.github/skills/self-evolve/SKILL.md` is the loop itself: log corrections to `.oh-my-copilot/self-evolve/log.md`, count repeats per topic, and when a topic recurs three times draft `.oh-my-copilot/self-evolve/drafts/<slug>/SKILL.md` with `status: draft`.
7
+
8
+ ## Why drafts live outside `.github/skills/`
9
+
10
+ `plugin.json` exposes `.github/skills/` as the active plugin skill root, so anything placed there is auto-loaded as a usable slash command on the next Copilot session. Drafts are written by an LLM from inferred mistake patterns and may misfire; auto-loading them before human review would let a malicious "correction" smuggle in a hostile instruction. Drafts land in `.oh-my-copilot/self-evolve/drafts/` instead — a path Copilot CLI never reads.
11
+
12
+ ## Promoting a draft
13
+
14
+ Move the draft directory from `.oh-my-copilot/self-evolve/drafts/<slug>/` to `.github/skills/learned-<slug>/`. The frontmatter `name` already matches the new directory name (set to `learned-<slug>` at draft time). Optionally delete the `status: draft` line; the project lint does not require it. On the next Copilot session the skill is loaded as `/learned-<slug>`.
15
+
16
+ ## Pruning
17
+
18
+ `.oh-my-copilot/self-evolve/log.md` is the source of truth and is committed. Delete or edit lines to reset the counter for a given topic.
19
+
20
+ ## Why agent-driven, not a CLI
21
+
22
+ Copilot CLI exposes no user-installable hook surface. The cheapest reliable trigger is the agent itself: `AGENTS.md` is loaded into every session, and the instruction there ensures `/self-evolve` runs at wrap-up without any binary, dependency, or shell modification.
@@ -0,0 +1,74 @@
1
+ {
2
+ "SessionStart": [
3
+ {
4
+ "matcher": "*",
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/session-start.mjs",
9
+ "timeout": 5
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "UserPromptSubmit": [
15
+ {
16
+ "matcher": "*",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/prompt-submit.mjs",
21
+ "timeout": 5
22
+ }
23
+ ]
24
+ }
25
+ ],
26
+ "PreToolUse": [
27
+ {
28
+ "matcher": "*",
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/pre-tool-use.mjs",
33
+ "timeout": 5
34
+ }
35
+ ]
36
+ }
37
+ ],
38
+ "PostToolUse": [
39
+ {
40
+ "matcher": "*",
41
+ "hooks": [
42
+ {
43
+ "type": "command",
44
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/post-tool-use.mjs",
45
+ "timeout": 5
46
+ }
47
+ ]
48
+ }
49
+ ],
50
+ "SessionEnd": [
51
+ {
52
+ "matcher": "*",
53
+ "hooks": [
54
+ {
55
+ "type": "command",
56
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/session-end.mjs",
57
+ "timeout": 5
58
+ }
59
+ ]
60
+ }
61
+ ],
62
+ "Error": [
63
+ {
64
+ "matcher": "*",
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "node \"${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}\"/scripts/error.mjs",
69
+ "timeout": 5
70
+ }
71
+ ]
72
+ }
73
+ ]
74
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@damian87/omp",
3
+ "version": "0.1.0",
4
+ "description": "GitHub Copilot project skills catalog and Jira handoff tools.",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "bin": {
10
+ "oh-my-copilot": "dist/src/cli.js",
11
+ "omp": "dist/src/cli.js",
12
+ "omcc": "dist/src/cli.js"
13
+ },
14
+ "files": [
15
+ ".github",
16
+ "LICENSE",
17
+ "README.md",
18
+ "catalog",
19
+ "dist",
20
+ "docs",
21
+ "hooks",
22
+ "plugin.json",
23
+ "scripts"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "check:catalog": "npm run build && node dist/src/cli.js catalog validate",
28
+ "catalog:list": "npm run build && node dist/src/cli.js catalog list",
29
+ "project:inspect": "npm run build && node dist/src/cli.js project inspect",
30
+ "test": "vitest run",
31
+ "lint:skills": "npm run build && node dist/src/cli.js lint:skills --root .",
32
+ "sync:dry-run": "npm run build && node dist/src/cli.js sync:dry-run --root .",
33
+ "jira:dry-run": "npm run build && node dist/src/cli.js jira:dry-run --root .",
34
+ "omp:version": "npm run build && node dist/src/cli.js version",
35
+ "omp:list": "npm run build && node dist/src/cli.js list",
36
+ "omp:setup:dry-run": "npm run build && node dist/src/cli.js setup --dry-run",
37
+ "omp:doctor": "npm run build && node dist/src/cli.js doctor --skip-copilot"
38
+ },
39
+ "keywords": [
40
+ "copilot",
41
+ "skills",
42
+ "agents",
43
+ "slash-commands"
44
+ ],
45
+ "license": "MIT",
46
+ "engines": {
47
+ "node": ">=20"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.15.29",
51
+ "tsx": "^4.19.4",
52
+ "typescript": "^5.8.3",
53
+ "vitest": "^3.1.4"
54
+ },
55
+ "dependencies": {
56
+ "@modelcontextprotocol/sdk": "^1.29.0"
57
+ }
58
+ }
package/plugin.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "oh-my-copilot",
3
+ "description": "Lite slash-skill workflows for GitHub Copilot.",
4
+ "version": "0.1.0",
5
+ "author": { "name": "Damian Borek", "email": "borekdamian@yahoo.pl" },
6
+ "license": "MIT",
7
+ "repository": "https://github.com/damian87x/oh-my-copilot",
8
+ "keywords": ["copilot", "skills", "agents", "slash-commands"],
9
+ "skills": ".github/skills/",
10
+ "agents": ".github/agents/",
11
+ "instructions": ".github/copilot-instructions.md",
12
+ "hooks": "hooks/hooks.json",
13
+ "scriptsDir": "scripts/"
14
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "Error";
7
+
8
+ (async () => {
9
+ try {
10
+ const raw = await readStdin();
11
+ const data = raw ? JSON.parse(raw) : {};
12
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
+ const directory = data.directory ?? process.cwd();
14
+ const toolName = data.toolName ?? data.tool_name ?? "unknown";
15
+ const errorMessage = data.error?.message ?? data.message ?? "unknown";
16
+ const logFile = join(directory, ".omp", "state", "hooks.log");
17
+ try {
18
+ mkdirSync(dirname(logFile), { recursive: true });
19
+ appendFileSync(
20
+ logFile,
21
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, sessionId, toolName, errorMessage })}\n`,
22
+ );
23
+ } catch {
24
+ // best effort
25
+ }
26
+ console.log(JSON.stringify({ continue: true }));
27
+ } catch (err) {
28
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
29
+ console.log(JSON.stringify({ continue: true }));
30
+ }
31
+ })();
@@ -0,0 +1,30 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ export function printContinue(hookEventName, additionalContext = "") {
5
+ const output = additionalContext
6
+ ? { continue: true, hookSpecificOutput: { hookEventName, additionalContext } }
7
+ : { continue: true };
8
+ console.log(JSON.stringify(output));
9
+ }
10
+
11
+ export function printBlock(reason) {
12
+ console.log(JSON.stringify({ continue: false, reason }));
13
+ }
14
+
15
+ export function failOpen() {
16
+ console.log(JSON.stringify({ continue: true }));
17
+ }
18
+
19
+ export function appendHookLog(directory, hookName, payload) {
20
+ const logFile = join(directory, ".omp", "state", "hooks.log");
21
+ try {
22
+ mkdirSync(dirname(logFile), { recursive: true });
23
+ appendFileSync(
24
+ logFile,
25
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: hookName, ...payload })}\n`,
26
+ );
27
+ } catch {
28
+ // best effort
29
+ }
30
+ }
@@ -0,0 +1,29 @@
1
+ const DEFAULT_MAX_BYTES = 10 * 1024 * 1024; // 10 MB sanity cap
2
+
3
+ export function readStdin(maxBytes = DEFAULT_MAX_BYTES) {
4
+ return new Promise((resolve) => {
5
+ if (process.stdin.isTTY) {
6
+ resolve("");
7
+ return;
8
+ }
9
+ let buf = "";
10
+ let truncated = false;
11
+ process.stdin.setEncoding("utf8");
12
+ process.stdin.on("data", (chunk) => {
13
+ if (truncated) return;
14
+ buf += chunk;
15
+ if (buf.length > maxBytes) {
16
+ truncated = true;
17
+ buf = buf.slice(0, maxBytes);
18
+ try { process.stdin.pause(); } catch { /* best effort */ }
19
+ resolve(buf);
20
+ }
21
+ });
22
+ process.stdin.on("end", () => {
23
+ if (!truncated) resolve(buf);
24
+ });
25
+ process.stdin.on("error", () => {
26
+ if (!truncated) resolve(buf);
27
+ });
28
+ });
29
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "PostToolUse";
7
+
8
+ (async () => {
9
+ try {
10
+ const raw = await readStdin();
11
+ const data = raw ? JSON.parse(raw) : {};
12
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
+ const directory = data.directory ?? process.cwd();
14
+ const toolName = data.toolName ?? data.tool_name ?? "unknown";
15
+ const ok = data.toolOutput != null;
16
+ const logFile = join(directory, ".omp", "state", "hooks.log");
17
+ try {
18
+ mkdirSync(dirname(logFile), { recursive: true });
19
+ appendFileSync(
20
+ logFile,
21
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, sessionId, toolName, ok })}\n`,
22
+ );
23
+ } catch {
24
+ // best effort
25
+ }
26
+ console.log(JSON.stringify({ continue: true }));
27
+ } catch (err) {
28
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
29
+ console.log(JSON.stringify({ continue: true }));
30
+ }
31
+ })();
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "PreToolUse";
7
+
8
+ (async () => {
9
+ try {
10
+ const raw = await readStdin();
11
+ const data = raw ? JSON.parse(raw) : {};
12
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
+ const directory = data.directory ?? process.cwd();
14
+ const toolName = data.toolName ?? data.tool_name ?? "unknown";
15
+ const logFile = join(directory, ".omp", "state", "hooks.log");
16
+ try {
17
+ mkdirSync(dirname(logFile), { recursive: true });
18
+ appendFileSync(
19
+ logFile,
20
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, sessionId, toolName })}\n`,
21
+ );
22
+ } catch {
23
+ // best effort
24
+ }
25
+ console.log(JSON.stringify({ continue: true }));
26
+ } catch (err) {
27
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
28
+ console.log(JSON.stringify({ continue: true }));
29
+ }
30
+ })();
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "UserPromptSubmit";
7
+
8
+ function readModeState(directory, mode) {
9
+ const p = join(directory, ".omp", "state", `${mode}.json`);
10
+ if (!existsSync(p)) return undefined;
11
+ try {
12
+ return JSON.parse(readFileSync(p, "utf8"));
13
+ } catch {
14
+ return undefined;
15
+ }
16
+ }
17
+
18
+ function buildContinuationContext(directory) {
19
+ const ralph = readModeState(directory, "ralph");
20
+ const ultrawork = readModeState(directory, "ultrawork");
21
+ const ultraqa = readModeState(directory, "ultraqa");
22
+ const parts = [];
23
+ if (ralph?.active)
24
+ parts.push(
25
+ `[RALPH ACTIVE: iteration ${ralph.iteration}/${ralph.maxIterations}]\nPrompt: ${ralph.prompt}\nContinue the loop. Report concrete progress.`,
26
+ );
27
+ if (ultrawork?.active)
28
+ parts.push(`[ULTRAWORK ACTIVE]\nObjective: ${ultrawork.objective}\nSustain the objective. Batch parallel tasks.`);
29
+ if (ultraqa?.active)
30
+ parts.push(
31
+ `[ULTRAQA ACTIVE: cycle ${ultraqa.cycleCount}/${ultraqa.maxCycles}]\nGoal: ${ultraqa.goal}\nRun tests → verify → fix. Iterate.`,
32
+ );
33
+ return parts.join("\n\n---\n\n");
34
+ }
35
+
36
+ function appendLog(directory, payload) {
37
+ const logFile = join(directory, ".omp", "state", "hooks.log");
38
+ try {
39
+ mkdirSync(dirname(logFile), { recursive: true });
40
+ appendFileSync(
41
+ logFile,
42
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, ...payload })}\n`,
43
+ );
44
+ } catch {
45
+ // best effort
46
+ }
47
+ }
48
+
49
+ (async () => {
50
+ try {
51
+ const raw = await readStdin();
52
+ const data = raw ? JSON.parse(raw) : {};
53
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
54
+ const directory = data.directory ?? process.cwd();
55
+ const prompt = data.prompt ?? data.message?.content ?? "";
56
+ appendLog(directory, { sessionId, promptBytes: String(prompt).length });
57
+ const additionalContext = buildContinuationContext(directory);
58
+ const output = additionalContext
59
+ ? { continue: true, hookSpecificOutput: { hookEventName: HOOK_NAME, additionalContext } }
60
+ : { continue: true };
61
+ console.log(JSON.stringify(output));
62
+ } catch (err) {
63
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
64
+ console.log(JSON.stringify({ continue: true }));
65
+ }
66
+ })();
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "SessionEnd";
7
+
8
+ (async () => {
9
+ try {
10
+ const raw = await readStdin();
11
+ const data = raw ? JSON.parse(raw) : {};
12
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
+ const directory = data.directory ?? process.cwd();
14
+ const logFile = join(directory, ".omp", "state", "hooks.log");
15
+ try {
16
+ mkdirSync(dirname(logFile), { recursive: true });
17
+ appendFileSync(
18
+ logFile,
19
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, sessionId, directory })}\n`,
20
+ );
21
+ } catch {
22
+ // best effort
23
+ }
24
+ console.log(JSON.stringify({ continue: true }));
25
+ } catch (err) {
26
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
27
+ console.log(JSON.stringify({ continue: true }));
28
+ }
29
+ })();
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { appendFileSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readStdin } from "./lib/stdin.mjs";
5
+
6
+ const HOOK_NAME = "SessionStart";
7
+
8
+ (async () => {
9
+ try {
10
+ const raw = await readStdin();
11
+ const data = raw ? JSON.parse(raw) : {};
12
+ const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
+ const directory = data.directory ?? process.cwd();
14
+ const logFile = join(directory, ".omp", "state", "hooks.log");
15
+ mkdirSync(dirname(logFile), { recursive: true });
16
+ const line = JSON.stringify({
17
+ ts: new Date().toISOString(),
18
+ hook: HOOK_NAME,
19
+ sessionId,
20
+ directory,
21
+ });
22
+ appendFileSync(logFile, `${line}\n`);
23
+ console.log(
24
+ JSON.stringify({
25
+ continue: true,
26
+ hookSpecificOutput: { hookEventName: HOOK_NAME, additionalContext: "" },
27
+ }),
28
+ );
29
+ } catch (err) {
30
+ console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
31
+ console.log(JSON.stringify({ continue: true }));
32
+ }
33
+ })();