@damian87/omp 0.10.0 → 0.12.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/.github/copilot-instructions.md +16 -0
- package/.github/skills/jira-ticket/SKILL.md +4 -4
- package/.github/skills/omp-autopilot/SKILL.md +4 -0
- package/.github/skills/research-codebase/SKILL.md +4 -0
- package/.github/skills/schedule/SKILL.md +4 -0
- package/.github/skills/team/SKILL.md +4 -0
- package/.github/skills/ultrawork/SKILL.md +4 -0
- package/.github/skills/weighted-consensus/SKILL.md +4 -0
- package/README.md +4 -1
- package/dist/src/cli.js +10 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/copilot/doctor.d.ts +1 -0
- package/dist/src/copilot/doctor.js +226 -27
- package/dist/src/copilot/doctor.js.map +1 -1
- package/dist/src/copilot/launch.js +13 -5
- package/dist/src/copilot/launch.js.map +1 -1
- package/dist/src/copilot/setup.js +13 -0
- package/dist/src/copilot/setup.js.map +1 -1
- package/dist/src/cost/index.d.ts +3 -0
- package/dist/src/cost/index.js +4 -0
- package/dist/src/cost/index.js.map +1 -0
- package/dist/src/cost/ledger.d.ts +21 -0
- package/dist/src/cost/ledger.js +72 -0
- package/dist/src/cost/ledger.js.map +1 -0
- package/dist/src/cost/summary.d.ts +22 -0
- package/dist/src/cost/summary.js +68 -0
- package/dist/src/cost/summary.js.map +1 -0
- package/dist/src/cost/tokenize.d.ts +7 -0
- package/dist/src/cost/tokenize.js +24 -0
- package/dist/src/cost/tokenize.js.map +1 -0
- package/dist/src/instructions-memory.js +1 -1
- package/dist/src/instructions-memory.js.map +1 -1
- package/docs/general-skills.md +1 -0
- package/hooks/hooks.json +9 -2
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/error.mjs +9 -7
- package/scripts/lib/cost-ledger.mjs +91 -0
- package/scripts/lib/hook-input.mjs +51 -0
- package/scripts/lib/hook-output.mjs +53 -11
- package/scripts/lib/minify.mjs +80 -0
- package/scripts/post-tool-use-failure.mjs +21 -0
- package/scripts/post-tool-use.mjs +71 -8
- package/scripts/pre-tool-use.mjs +8 -6
- package/scripts/prompt-submit.mjs +12 -5
- package/scripts/session-end.mjs +7 -5
- package/scripts/session-start.mjs +5 -4
|
@@ -1,31 +1,94 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { readStdin } from "./lib/stdin.mjs";
|
|
5
|
+
import { buildModifiedResultOutput, failOpen } from "./lib/hook-output.mjs";
|
|
6
|
+
import { parseHookInput } from "./lib/hook-input.mjs";
|
|
7
|
+
import { appendCostRecord, countTokens } from "./lib/cost-ledger.mjs";
|
|
8
|
+
import { minifyToolOutput } from "./lib/minify.mjs";
|
|
5
9
|
|
|
6
10
|
const HOOK_NAME = "PostToolUse";
|
|
11
|
+
const NOISY_COMMAND_RE = /\b(npm|pnpm|yarn|bun|vitest|jest|mocha|pytest|cargo|go|tsc|eslint|biome|ruff|mypy|make|gradle|mvn)\b/i;
|
|
12
|
+
|
|
13
|
+
function safePathPart(value) {
|
|
14
|
+
return (
|
|
15
|
+
String(value || "unknown")
|
|
16
|
+
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
17
|
+
.replace(/^-+|-+$/g, "") || "unknown"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function shouldMinify(input) {
|
|
22
|
+
if (process.env.OMP_MINIFY === "0") return false;
|
|
23
|
+
const toolName = String(input.toolName || "").toLowerCase();
|
|
24
|
+
const command = String(input.toolArgs?.command ?? input.toolArgs?.cmd ?? "");
|
|
25
|
+
return (toolName === "bash" || toolName === "shell" || toolName === "terminal") && NOISY_COMMAND_RE.test(command);
|
|
26
|
+
}
|
|
7
27
|
|
|
8
28
|
(async () => {
|
|
9
29
|
try {
|
|
10
30
|
const raw = await readStdin();
|
|
11
|
-
const
|
|
12
|
-
const sessionId =
|
|
13
|
-
const directory =
|
|
14
|
-
const toolName =
|
|
15
|
-
const ok =
|
|
31
|
+
const input = parseHookInput(raw);
|
|
32
|
+
const sessionId = input.sessionId;
|
|
33
|
+
const directory = input.cwd;
|
|
34
|
+
const toolName = input.toolName;
|
|
35
|
+
const ok = input.toolResult != null;
|
|
36
|
+
const rawText = input.toolResult?.textResultForLlm ?? "";
|
|
37
|
+
const minified = !shouldMinify(input) ? {
|
|
38
|
+
changed: false,
|
|
39
|
+
text: rawText,
|
|
40
|
+
rawTokens: countTokens(rawText),
|
|
41
|
+
modelTokens: countTokens(rawText),
|
|
42
|
+
savedTokens: 0,
|
|
43
|
+
} : minifyToolOutput(rawText);
|
|
44
|
+
let rawPath;
|
|
16
45
|
const logFile = join(directory, ".omp", "state", "hooks.log");
|
|
46
|
+
let canModifyResult = minified.changed;
|
|
17
47
|
try {
|
|
18
48
|
mkdirSync(dirname(logFile), { recursive: true });
|
|
19
49
|
appendFileSync(
|
|
20
50
|
logFile,
|
|
21
51
|
`${JSON.stringify({ ts: new Date().toISOString(), hook: HOOK_NAME, sessionId, toolName, ok })}\n`,
|
|
22
52
|
);
|
|
53
|
+
if (minified.changed) {
|
|
54
|
+
rawPath = join(
|
|
55
|
+
directory,
|
|
56
|
+
".omp",
|
|
57
|
+
"state",
|
|
58
|
+
"cost",
|
|
59
|
+
"raw",
|
|
60
|
+
`${safePathPart(sessionId)}-${Date.now()}-${safePathPart(toolName)}.txt`,
|
|
61
|
+
);
|
|
62
|
+
mkdirSync(dirname(rawPath), { recursive: true });
|
|
63
|
+
writeFileSync(rawPath, rawText, "utf8");
|
|
64
|
+
}
|
|
65
|
+
} catch {
|
|
66
|
+
canModifyResult = false;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
appendCostRecord(directory, {
|
|
70
|
+
sessionId,
|
|
71
|
+
event: "postToolUse",
|
|
72
|
+
toolName,
|
|
73
|
+
inTokens: countTokens(input.toolArgs),
|
|
74
|
+
outTokens: canModifyResult ? minified.modelTokens : minified.rawTokens,
|
|
75
|
+
rawOutTokens: minified.rawTokens,
|
|
76
|
+
savedTokens: canModifyResult ? minified.savedTokens : 0,
|
|
77
|
+
rawPath,
|
|
78
|
+
});
|
|
23
79
|
} catch {
|
|
24
80
|
// best effort
|
|
25
81
|
}
|
|
26
|
-
|
|
82
|
+
if (canModifyResult) {
|
|
83
|
+
console.log(JSON.stringify(buildModifiedResultOutput(
|
|
84
|
+
minified.text,
|
|
85
|
+
`[omp] output trimmed ${minified.rawTokens}→${minified.modelTokens} tokens; full output at ${rawPath}`,
|
|
86
|
+
)));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
failOpen();
|
|
27
90
|
} catch (err) {
|
|
28
91
|
console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
|
|
29
|
-
|
|
92
|
+
failOpen();
|
|
30
93
|
}
|
|
31
94
|
})();
|
package/scripts/pre-tool-use.mjs
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { readStdin } from "./lib/stdin.mjs";
|
|
5
|
+
import { failOpen } from "./lib/hook-output.mjs";
|
|
6
|
+
import { parseHookInput } from "./lib/hook-input.mjs";
|
|
5
7
|
|
|
6
8
|
const HOOK_NAME = "PreToolUse";
|
|
7
9
|
|
|
8
10
|
(async () => {
|
|
9
11
|
try {
|
|
10
12
|
const raw = await readStdin();
|
|
11
|
-
const
|
|
12
|
-
const sessionId =
|
|
13
|
-
const directory =
|
|
14
|
-
const toolName =
|
|
13
|
+
const input = parseHookInput(raw);
|
|
14
|
+
const sessionId = input.sessionId;
|
|
15
|
+
const directory = input.cwd;
|
|
16
|
+
const toolName = input.toolName;
|
|
15
17
|
const logFile = join(directory, ".omp", "state", "hooks.log");
|
|
16
18
|
try {
|
|
17
19
|
mkdirSync(dirname(logFile), { recursive: true });
|
|
@@ -22,9 +24,9 @@ const HOOK_NAME = "PreToolUse";
|
|
|
22
24
|
} catch {
|
|
23
25
|
// best effort
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
failOpen();
|
|
26
28
|
} catch (err) {
|
|
27
29
|
console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
|
|
28
|
-
|
|
30
|
+
failOpen();
|
|
29
31
|
}
|
|
30
32
|
})();
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { readStdin } from "./lib/stdin.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { failOpen, printContinue } from "./lib/hook-output.mjs";
|
|
6
6
|
import { recordPrompt } from "./lib/daily-log.mjs";
|
|
7
7
|
import { ompRoot } from "./lib/omp-root.mjs";
|
|
8
|
+
import { parseHookInput } from "./lib/hook-input.mjs";
|
|
9
|
+
import { appendCostRecord, countTokens } from "./lib/cost-ledger.mjs";
|
|
8
10
|
|
|
9
11
|
const HOOK_NAME = "UserPromptSubmit";
|
|
10
12
|
|
|
@@ -52,11 +54,16 @@ function appendLog(directory, payload) {
|
|
|
52
54
|
(async () => {
|
|
53
55
|
try {
|
|
54
56
|
const raw = await readStdin();
|
|
55
|
-
const
|
|
56
|
-
const sessionId =
|
|
57
|
-
const directory =
|
|
58
|
-
const prompt =
|
|
57
|
+
const input = parseHookInput(raw);
|
|
58
|
+
const sessionId = input.sessionId;
|
|
59
|
+
const directory = input.cwd;
|
|
60
|
+
const prompt = input.prompt;
|
|
59
61
|
appendLog(directory, { sessionId, promptBytes: String(prompt).length });
|
|
62
|
+
appendCostRecord(directory, {
|
|
63
|
+
sessionId,
|
|
64
|
+
event: "userPromptSubmitted",
|
|
65
|
+
inTokens: countTokens(prompt),
|
|
66
|
+
});
|
|
60
67
|
// Count this prompt as session work (signals the SessionEnd nudge logic).
|
|
61
68
|
// Injects nothing — keeps per-turn token cost at zero.
|
|
62
69
|
try {
|
package/scripts/session-end.mjs
CHANGED
|
@@ -4,15 +4,17 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { readStdin } from "./lib/stdin.mjs";
|
|
5
5
|
import { endSession } from "./lib/daily-log.mjs";
|
|
6
6
|
import { ompRoot } from "./lib/omp-root.mjs";
|
|
7
|
+
import { failOpen } from "./lib/hook-output.mjs";
|
|
8
|
+
import { parseHookInput } from "./lib/hook-input.mjs";
|
|
7
9
|
|
|
8
10
|
const HOOK_NAME = "SessionEnd";
|
|
9
11
|
|
|
10
12
|
(async () => {
|
|
11
13
|
try {
|
|
12
14
|
const raw = await readStdin();
|
|
13
|
-
const
|
|
14
|
-
const sessionId =
|
|
15
|
-
const directory =
|
|
15
|
+
const input = parseHookInput(raw);
|
|
16
|
+
const sessionId = input.sessionId;
|
|
17
|
+
const directory = input.cwd;
|
|
16
18
|
const logFile = join(ompRoot(directory), ".omp", "state", "hooks.log");
|
|
17
19
|
try {
|
|
18
20
|
mkdirSync(dirname(logFile), { recursive: true });
|
|
@@ -26,9 +28,9 @@ const HOOK_NAME = "SessionEnd";
|
|
|
26
28
|
// Arm a daily-log nudge for the next session if this one did work but
|
|
27
29
|
// logged nothing. endSession never throws.
|
|
28
30
|
endSession(directory);
|
|
29
|
-
|
|
31
|
+
failOpen();
|
|
30
32
|
} catch (err) {
|
|
31
33
|
console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
|
|
32
|
-
|
|
34
|
+
failOpen();
|
|
33
35
|
}
|
|
34
36
|
})();
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { readStdin } from "./lib/stdin.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { failOpen, printContinue } from "./lib/hook-output.mjs";
|
|
6
6
|
import { checkForUpdate, formatUpdateNotice } from "./lib/version-check.mjs";
|
|
7
7
|
import { scanScheduleResults } from "./lib/schedule-results.mjs";
|
|
8
8
|
import { readRepoGoal, readTodayGoal, recentEntryStats, startSession } from "./lib/daily-log.mjs";
|
|
9
9
|
import { readDirectives } from "./lib/project-memory.mjs";
|
|
10
10
|
import { ompRoot } from "./lib/omp-root.mjs";
|
|
11
|
+
import { parseHookInput } from "./lib/hook-input.mjs";
|
|
11
12
|
|
|
12
13
|
const HOOK_NAME = "SessionStart";
|
|
13
14
|
|
|
@@ -31,9 +32,9 @@ function buildDailyLogBreadcrumb(directory) {
|
|
|
31
32
|
(async () => {
|
|
32
33
|
try {
|
|
33
34
|
const raw = await readStdin();
|
|
34
|
-
const
|
|
35
|
-
const sessionId =
|
|
36
|
-
const directory =
|
|
35
|
+
const input = parseHookInput(raw);
|
|
36
|
+
const sessionId = input.sessionId;
|
|
37
|
+
const directory = input.cwd;
|
|
37
38
|
const stateDir = join(ompRoot(directory), ".omp", "state");
|
|
38
39
|
const logFile = join(stateDir, "hooks.log");
|
|
39
40
|
mkdirSync(dirname(logFile), { recursive: true });
|