@damian87/omp 0.10.0 → 0.13.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 +134 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/comms.d.ts +2 -0
- package/dist/src/commands/comms.js +110 -0
- package/dist/src/commands/comms.js.map +1 -0
- package/dist/src/commands/council.d.ts +2 -0
- package/dist/src/commands/council.js +77 -0
- package/dist/src/commands/council.js.map +1 -0
- package/dist/src/commands/env.d.ts +2 -0
- package/dist/src/commands/env.js +95 -0
- package/dist/src/commands/env.js.map +1 -0
- package/dist/src/commands/gateway.d.ts +3 -0
- package/dist/src/commands/gateway.js +129 -0
- package/dist/src/commands/gateway.js.map +1 -0
- package/dist/src/commands/memory.d.ts +7 -0
- package/dist/src/commands/memory.js +202 -0
- package/dist/src/commands/memory.js.map +1 -0
- package/dist/src/commands/mode.d.ts +4 -0
- package/dist/src/commands/mode.js +119 -0
- package/dist/src/commands/mode.js.map +1 -0
- package/dist/src/commands/schedule.d.ts +2 -0
- package/dist/src/commands/schedule.js +91 -0
- package/dist/src/commands/schedule.js.map +1 -0
- package/dist/src/commands/team.d.ts +2 -0
- package/dist/src/commands/team.js +146 -0
- package/dist/src/commands/team.js.map +1 -0
- package/dist/src/commands/utils.d.ts +13 -0
- package/dist/src/commands/utils.js +68 -0
- package/dist/src/commands/utils.js.map +1 -0
- 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/goal.js +6 -8
- package/dist/src/goal.js.map +1 -1
- package/dist/src/instructions-memory.js +26 -3
- package/dist/src/instructions-memory.js.map +1 -1
- package/dist/src/memory-review/apply.d.ts +7 -0
- package/dist/src/memory-review/apply.js +75 -0
- package/dist/src/memory-review/apply.js.map +1 -0
- package/dist/src/memory-review/config.d.ts +22 -0
- package/dist/src/memory-review/config.js +54 -0
- package/dist/src/memory-review/config.js.map +1 -0
- package/dist/src/memory-review/guard.d.ts +5 -0
- package/dist/src/memory-review/guard.js +37 -0
- package/dist/src/memory-review/guard.js.map +1 -0
- package/dist/src/memory-review/index.d.ts +17 -0
- package/dist/src/memory-review/index.js +87 -0
- package/dist/src/memory-review/index.js.map +1 -0
- package/dist/src/memory-review/prompt.d.ts +18 -0
- package/dist/src/memory-review/prompt.js +89 -0
- package/dist/src/memory-review/prompt.js.map +1 -0
- package/dist/src/memory-review/spawn.d.ts +2 -0
- package/dist/src/memory-review/spawn.js +51 -0
- package/dist/src/memory-review/spawn.js.map +1 -0
- package/dist/src/memory-review/transcript.d.ts +24 -0
- package/dist/src/memory-review/transcript.js +212 -0
- package/dist/src/memory-review/transcript.js.map +1 -0
- package/dist/src/memory-review/trigger.d.ts +21 -0
- package/dist/src/memory-review/trigger.js +27 -0
- package/dist/src/memory-review/trigger.js.map +1 -0
- package/dist/src/project-memory.d.ts +9 -0
- package/dist/src/project-memory.js +72 -1
- package/dist/src/project-memory.js.map +1 -1
- package/dist/src/state.js +25 -37
- package/dist/src/state.js.map +1 -1
- package/dist/src/utils/fs.d.ts +14 -0
- package/dist/src/utils/fs.js +32 -0
- package/dist/src/utils/fs.js.map +1 -0
- package/dist/src/utils/paths.d.ts +14 -0
- package/dist/src/utils/paths.js +21 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/docs/general-skills.md +1 -0
- package/docs/memory-mode.md +94 -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/memory-review-trigger.mjs +59 -0
- package/scripts/lib/minify.mjs +80 -0
- package/scripts/lib/pending-directives.mjs +36 -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 +15 -5
- package/scripts/session-start.mjs +9 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger.js","sourceRoot":"","sources":["../../../src/memory-review/trigger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA4B/C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AAEjD,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,IAA4B;IAE5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAChF,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;IACxE,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC1E,IAAI,CAAC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAK,SAAoC,CAAC;IAClE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CACjB,OAAO,CAAC,QAAQ,EAChB,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,EAChF,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CACpC,CAAC;QACF,4EAA4E;QAC5E,KAAK,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/B,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QACjB,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
|
|
@@ -9,5 +9,14 @@ export interface NoteMeta {
|
|
|
9
9
|
export declare function addNote(cwd: string, title: string, body?: string): string;
|
|
10
10
|
/** Cheap index of (id, title) — the only thing surfaced; bodies stay on disk. */
|
|
11
11
|
export declare function noteIndex(cwd: string): NoteMeta[];
|
|
12
|
+
/** Notes ordered newest-first by mtime, optionally capped. Used to surface the
|
|
13
|
+
* most recent titles in the injected block without unbounded growth. */
|
|
14
|
+
export declare function recentNotes(cwd: string, limit?: number): NoteMeta[];
|
|
15
|
+
/** Prune notes by count (keep N newest) and/or age (older than N days).
|
|
16
|
+
* Returns the ids removed. No options → no-op (never deletes silently). */
|
|
17
|
+
export declare function pruneNotes(cwd: string, opts: {
|
|
18
|
+
keep?: number;
|
|
19
|
+
olderThanDays?: number;
|
|
20
|
+
}): string[];
|
|
12
21
|
/** Full note body by id, or null when missing. */
|
|
13
22
|
export declare function readNote(cwd: string, id: string): string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { ompRoot } from "./omp-root.js";
|
|
4
4
|
function memPath(cwd) {
|
|
@@ -86,6 +86,77 @@ export function noteIndex(cwd) {
|
|
|
86
86
|
})
|
|
87
87
|
.sort((a, b) => a.id.localeCompare(b.id));
|
|
88
88
|
}
|
|
89
|
+
/** Notes ordered newest-first by mtime, optionally capped. Used to surface the
|
|
90
|
+
* most recent titles in the injected block without unbounded growth. */
|
|
91
|
+
export function recentNotes(cwd, limit) {
|
|
92
|
+
const dir = notesDir(cwd);
|
|
93
|
+
if (!existsSync(dir))
|
|
94
|
+
return [];
|
|
95
|
+
const entries = readdirSync(dir)
|
|
96
|
+
.filter((f) => f.endsWith(".md"))
|
|
97
|
+
.map((f) => {
|
|
98
|
+
const id = f.replace(/\.md$/, "");
|
|
99
|
+
let title = id;
|
|
100
|
+
let mtime = 0;
|
|
101
|
+
try {
|
|
102
|
+
const full = join(dir, f);
|
|
103
|
+
mtime = statSync(full).mtimeMs;
|
|
104
|
+
const first = readFileSync(full, "utf8").split("\n")[0] ?? "";
|
|
105
|
+
title = first.replace(/^#\s*/, "").trim() || id;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// keep defaults
|
|
109
|
+
}
|
|
110
|
+
return { id, title, mtime };
|
|
111
|
+
})
|
|
112
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
113
|
+
const capped = typeof limit === "number" ? entries.slice(0, limit) : entries;
|
|
114
|
+
return capped.map(({ id, title }) => ({ id, title }));
|
|
115
|
+
}
|
|
116
|
+
/** Prune notes by count (keep N newest) and/or age (older than N days).
|
|
117
|
+
* Returns the ids removed. No options → no-op (never deletes silently). */
|
|
118
|
+
export function pruneNotes(cwd, opts) {
|
|
119
|
+
const dir = notesDir(cwd);
|
|
120
|
+
if (!existsSync(dir))
|
|
121
|
+
return [];
|
|
122
|
+
const files = readdirSync(dir)
|
|
123
|
+
.filter((f) => f.endsWith(".md"))
|
|
124
|
+
.map((f) => {
|
|
125
|
+
let mtime = 0;
|
|
126
|
+
try {
|
|
127
|
+
mtime = statSync(join(dir, f)).mtimeMs;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// unreadable — treat as oldest so it's eligible for pruning
|
|
131
|
+
}
|
|
132
|
+
return { id: f.replace(/\.md$/, ""), file: f, mtime };
|
|
133
|
+
})
|
|
134
|
+
.sort((a, b) => b.mtime - a.mtime); // newest-first
|
|
135
|
+
const toRemove = new Set();
|
|
136
|
+
if (typeof opts.keep === "number" && opts.keep >= 0) {
|
|
137
|
+
for (const e of files.slice(opts.keep))
|
|
138
|
+
toRemove.add(e.file);
|
|
139
|
+
}
|
|
140
|
+
if (typeof opts.olderThanDays === "number" && opts.olderThanDays >= 0) {
|
|
141
|
+
const cutoff = Date.now() - opts.olderThanDays * 86400_000;
|
|
142
|
+
for (const e of files)
|
|
143
|
+
if (e.mtime < cutoff)
|
|
144
|
+
toRemove.add(e.file);
|
|
145
|
+
}
|
|
146
|
+
const removed = [];
|
|
147
|
+
for (const e of files) {
|
|
148
|
+
if (!toRemove.has(e.file))
|
|
149
|
+
continue;
|
|
150
|
+
try {
|
|
151
|
+
unlinkSync(join(dir, e.file));
|
|
152
|
+
removed.push(e.id);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// skip files we can't remove
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return removed.sort();
|
|
159
|
+
}
|
|
89
160
|
/** Full note body by id, or null when missing. */
|
|
90
161
|
export function readNote(cwd, id) {
|
|
91
162
|
// Ids are slugs ([a-z0-9-]); reject anything else so a crafted id can't
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-memory.js","sourceRoot":"","sources":["../../src/project-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"project-memory.js","sourceRoot":"","sources":["../../src/project-memory.ts"],"names":[],"mappings":"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"}
|
package/dist/src/state.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync, readdirSync, statSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { atomicWrite, ensureDir, readJSON } from "./utils/fs.js";
|
|
4
|
+
import { statePath } from "./utils/paths.js";
|
|
4
5
|
function kvDir(cwd) {
|
|
5
|
-
return
|
|
6
|
+
return statePath(cwd, "kv");
|
|
6
7
|
}
|
|
7
8
|
function kvPath(cwd, key) {
|
|
8
9
|
if (!/^[\w.-]+$/.test(key))
|
|
@@ -17,28 +18,21 @@ export function stateWrite(cwd, key, value, ttlSeconds) {
|
|
|
17
18
|
expiresAt: ttlSeconds != null ? new Date(Date.now() + ttlSeconds * 1000).toISOString() : undefined,
|
|
18
19
|
};
|
|
19
20
|
const path = kvPath(cwd, key);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
writeFileSync(tmp, JSON.stringify(entry, null, 2), "utf8");
|
|
23
|
-
renameSync(tmp, path);
|
|
21
|
+
ensureDir(path);
|
|
22
|
+
atomicWrite(path, JSON.stringify(entry, null, 2));
|
|
24
23
|
return entry.expiresAt;
|
|
25
24
|
}
|
|
26
25
|
/** Read a value. Returns { value: null } when missing; auto-deletes if expired. */
|
|
27
26
|
export function stateRead(cwd, key) {
|
|
28
27
|
const path = kvPath(cwd, key);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
const entry = JSON.parse(readFileSync(path, "utf8"));
|
|
33
|
-
if (entry.expiresAt && Date.parse(entry.expiresAt) < Date.now()) {
|
|
34
|
-
unlinkSync(path);
|
|
35
|
-
return { value: null, expired: true };
|
|
36
|
-
}
|
|
37
|
-
return { value: entry.value };
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
28
|
+
const entry = readJSON(path, null);
|
|
29
|
+
if (!entry)
|
|
40
30
|
return { value: null };
|
|
31
|
+
if (entry.expiresAt && Date.parse(entry.expiresAt) < Date.now()) {
|
|
32
|
+
unlinkSync(path);
|
|
33
|
+
return { value: null, expired: true };
|
|
41
34
|
}
|
|
35
|
+
return { value: entry.value };
|
|
42
36
|
}
|
|
43
37
|
export function stateDelete(cwd, key) {
|
|
44
38
|
const path = kvPath(cwd, key);
|
|
@@ -55,15 +49,12 @@ export function stateList(cwd) {
|
|
|
55
49
|
for (const f of readdirSync(dir)) {
|
|
56
50
|
if (!f.endsWith(".json"))
|
|
57
51
|
continue;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
catch {
|
|
65
|
-
// skip unparseable
|
|
66
|
-
}
|
|
52
|
+
const entry = readJSON(join(dir, f), null);
|
|
53
|
+
if (!entry)
|
|
54
|
+
continue;
|
|
55
|
+
if (entry.expiresAt && Date.parse(entry.expiresAt) < now)
|
|
56
|
+
continue;
|
|
57
|
+
keys.push(f.replace(/\.json$/, ""));
|
|
67
58
|
}
|
|
68
59
|
return keys.sort();
|
|
69
60
|
}
|
|
@@ -78,15 +69,12 @@ export function stateCleanup(cwd) {
|
|
|
78
69
|
if (!f.endsWith(".json"))
|
|
79
70
|
continue;
|
|
80
71
|
const path = join(dir, f);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// skip
|
|
72
|
+
const entry = readJSON(path, null);
|
|
73
|
+
if (!entry)
|
|
74
|
+
continue;
|
|
75
|
+
if (entry.expiresAt && Date.parse(entry.expiresAt) < now) {
|
|
76
|
+
unlinkSync(path);
|
|
77
|
+
deleted++;
|
|
90
78
|
}
|
|
91
79
|
}
|
|
92
80
|
return deleted;
|
package/dist/src/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomically write content to a file using a temporary file + rename.
|
|
3
|
+
* Ensures the target file is never left in a partially-written state.
|
|
4
|
+
*/
|
|
5
|
+
export declare function atomicWrite(path: string, content: string | Buffer): void;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure the directory for the given path exists, creating it recursively if needed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureDir(path: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Read and parse JSON from a file, returning the fallback value if the file
|
|
12
|
+
* doesn't exist or cannot be parsed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function readJSON<T>(path: string, fallback: T): T;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Atomically write content to a file using a temporary file + rename.
|
|
5
|
+
* Ensures the target file is never left in a partially-written state.
|
|
6
|
+
*/
|
|
7
|
+
export function atomicWrite(path, content) {
|
|
8
|
+
const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
9
|
+
writeFileSync(tmp, content);
|
|
10
|
+
renameSync(tmp, path);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Ensure the directory for the given path exists, creating it recursively if needed.
|
|
14
|
+
*/
|
|
15
|
+
export function ensureDir(path) {
|
|
16
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Read and parse JSON from a file, returning the fallback value if the file
|
|
20
|
+
* doesn't exist or cannot be parsed.
|
|
21
|
+
*/
|
|
22
|
+
export function readJSON(path, fallback) {
|
|
23
|
+
if (!existsSync(path))
|
|
24
|
+
return fallback;
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAwB;IAChE,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACvD,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAI,IAAY,EAAE,QAAW;IACnD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Construct a path within the project's .omp directory.
|
|
3
|
+
* @param cwd - The current working directory (project root)
|
|
4
|
+
* @param segments - Additional path segments to join
|
|
5
|
+
* @returns Absolute path to .omp/<segments>
|
|
6
|
+
*/
|
|
7
|
+
export declare function ompPath(cwd: string, ...segments: string[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* Construct a path within the project's .omp/state directory.
|
|
10
|
+
* @param cwd - The current working directory (project root)
|
|
11
|
+
* @param segments - Additional path segments to join
|
|
12
|
+
* @returns Absolute path to .omp/state/<segments>
|
|
13
|
+
*/
|
|
14
|
+
export declare function statePath(cwd: string, ...segments: string[]): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { ompRoot } from "../omp-root.js";
|
|
3
|
+
/**
|
|
4
|
+
* Construct a path within the project's .omp directory.
|
|
5
|
+
* @param cwd - The current working directory (project root)
|
|
6
|
+
* @param segments - Additional path segments to join
|
|
7
|
+
* @returns Absolute path to .omp/<segments>
|
|
8
|
+
*/
|
|
9
|
+
export function ompPath(cwd, ...segments) {
|
|
10
|
+
return join(ompRoot(cwd), ".omp", ...segments);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Construct a path within the project's .omp/state directory.
|
|
14
|
+
* @param cwd - The current working directory (project root)
|
|
15
|
+
* @param segments - Additional path segments to join
|
|
16
|
+
* @returns Absolute path to .omp/state/<segments>
|
|
17
|
+
*/
|
|
18
|
+
export function statePath(cwd, ...segments) {
|
|
19
|
+
return join(ompRoot(cwd), ".omp", "state", ...segments);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,GAAG,QAAkB;IACxD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,GAAG,QAAkB;IAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC1D,CAAC"}
|
package/docs/general-skills.md
CHANGED
|
@@ -39,6 +39,7 @@ Rules:
|
|
|
39
39
|
- Keep each `SKILL.md` small: YAML frontmatter (`name`, `description`) plus focused Markdown instructions.
|
|
40
40
|
- Optional `references/`, `scripts/`, or `assets/` may live beside `SKILL.md` when a fetched skill needs progressive disclosure.
|
|
41
41
|
- Do not add runtime state to the lite skills.
|
|
42
|
+
- Do not duplicate global cost/token boilerplate in every skill. The plugin-level hooks and `.github/copilot-instructions.md` provide estimate-only cost visibility; add only concise reminders to genuinely high-cost skills.
|
|
42
43
|
|
|
43
44
|
## Fetched skills
|
|
44
45
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Memory mode (self-improving review loop)
|
|
2
|
+
|
|
3
|
+
Memory mode is an **opt-in** end-of-session review that mirrors Hermes Agent's
|
|
4
|
+
background-review fork, adapted to GitHub Copilot CLI. After a session ends, a
|
|
5
|
+
**cheap model** reads the session transcript and extracts durable knowledge into
|
|
6
|
+
oh-my-copilot's existing memory/skill stores — so the next session starts a
|
|
7
|
+
little smarter without you having to repeat yourself.
|
|
8
|
+
|
|
9
|
+
It is **off by default** because it adds one extra (cheap) model call per
|
|
10
|
+
session.
|
|
11
|
+
|
|
12
|
+
## Enable
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
omp config set memory-mode on # opt in (this project)
|
|
16
|
+
omp config set memory-review-model gpt-5-mini # optional; defaults to gpt-5-mini
|
|
17
|
+
omp config set memory-review-min-messages 4 # optional; skip sessions shorter than this (default 4)
|
|
18
|
+
omp config get # show current (effective) settings
|
|
19
|
+
|
|
20
|
+
# Set once for EVERY project (~/.omp/config.json):
|
|
21
|
+
omp config set memory-mode on --global
|
|
22
|
+
omp config set memory-review-model <slug> --global
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Resolution precedence (high → low):** `OMP_MEMORY_MODE` env › project
|
|
26
|
+
`.omp/config.json` › global `~/.omp/config.json` › defaults. So `--global` is the
|
|
27
|
+
"set it once" default, and a project's `.omp/config.json` overrides it per key.
|
|
28
|
+
|
|
29
|
+
## How it triggers
|
|
30
|
+
|
|
31
|
+
| Surface | Trigger | Notes |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| Interactive `copilot` (plugin installed) | `sessionEnd` hook | Detaches `omp memory-review` as a background process and returns immediately (hooks have a 5s budget). |
|
|
34
|
+
| `omp -p` / `omp launch -- -p` (headless) | wrapper, post-exit | Headless `copilot -p` skips hooks, so the omp wrapper detaches the review. It snapshots session dirs before launch and reviews the **exact** session created by that run — if it can't identify one, it skips rather than guess. |
|
|
35
|
+
| Manual | `omp memory-review --session <uuid\|latest>` | Run it yourself against any session (`latest` = newest by mtime). |
|
|
36
|
+
|
|
37
|
+
Both automatic triggers only **detach** the work. The review claims the session
|
|
38
|
+
atomically (`.oh-my-copilot/memory-review/.claim-<uuid>`), so even if the hook
|
|
39
|
+
and wrapper both fire, the review runs **exactly once**.
|
|
40
|
+
|
|
41
|
+
## What it writes
|
|
42
|
+
|
|
43
|
+
| Output | Destination | Applied? |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| **Notes** (durable facts) | project memory (`omp project-memory`) | ✅ applied — progressive disclosure, low blast radius |
|
|
46
|
+
| **Skill drafts** (procedures) | `.oh-my-copilot/self-evolve/drafts/<slug>/SKILL.md` | ⏸ human-promote — never auto-loaded (same as `/self-evolve`) |
|
|
47
|
+
| **Directives** (every-session rules) | `.oh-my-copilot/memory-review/pending-directives.md` | ⏸ **gated** — never auto-applied |
|
|
48
|
+
|
|
49
|
+
After the review writes notes it refreshes the managed block in
|
|
50
|
+
`.github/copilot-instructions.md`, listing the most recent note **titles** (capped,
|
|
51
|
+
newest-first) so the next session knows what it remembers; bodies stay on demand
|
|
52
|
+
(`omp project-memory read <id>`). The review also ensures `.omp/` and
|
|
53
|
+
`.oh-my-copilot/` are gitignored so memory (which may contain tool output) isn't
|
|
54
|
+
accidentally committed.
|
|
55
|
+
|
|
56
|
+
### Promoting a pending directive (manual, by design)
|
|
57
|
+
|
|
58
|
+
Directives are gated: they inject into every future session, so an injected/poisoned
|
|
59
|
+
one would steer everything. The review prompt treats the transcript as **data, not
|
|
60
|
+
instructions**, and only proposes directives from corrections / standing preferences —
|
|
61
|
+
never one-off task instructions. On the next session start you'll see a nudge:
|
|
62
|
+
`[MEMORY REVIEW] N proposed directive(s) await your review…`. To promote one:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cat .oh-my-copilot/memory-review/pending-directives.md # review the proposals
|
|
66
|
+
omp project-memory add-directive "User prefers concise replies" # apply the ones you want
|
|
67
|
+
# then delete the promoted line from pending-directives.md
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Skill drafts promote the same way as `/self-evolve`: move
|
|
71
|
+
`.oh-my-copilot/self-evolve/drafts/<slug>/` to `.github/skills/learned-<slug>/`.
|
|
72
|
+
|
|
73
|
+
### Pruning notes
|
|
74
|
+
|
|
75
|
+
Notes accumulate over time. Trim them anytime (never silent — requires a flag):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
omp project-memory prune-notes --keep 50 # keep the 50 newest
|
|
79
|
+
omp project-memory prune-notes --older-than 30 # drop notes older than 30 days
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Cost & observability
|
|
83
|
+
|
|
84
|
+
- The expensive reasoning already happened in the main session; the review is a
|
|
85
|
+
single cheap-model call over the transcript.
|
|
86
|
+
- Token cost is recorded in the cost ledger (`omp cost`) under the
|
|
87
|
+
`memory-review` event.
|
|
88
|
+
- Each run appends a line to `.omp/state/memory-review.log`.
|
|
89
|
+
|
|
90
|
+
## Disable
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
omp config set memory-mode off
|
|
94
|
+
```
|
package/hooks/hooks.json
CHANGED
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"timeoutSec": 5
|
|
30
30
|
}
|
|
31
31
|
],
|
|
32
|
-
"
|
|
32
|
+
"postToolUseFailure": [
|
|
33
33
|
{
|
|
34
34
|
"type": "command",
|
|
35
|
-
"bash": "node \"${COPILOT_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}}}}\"/scripts/
|
|
35
|
+
"bash": "node \"${COPILOT_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}}}}\"/scripts/post-tool-use-failure.mjs",
|
|
36
36
|
"timeoutSec": 5
|
|
37
37
|
}
|
|
38
38
|
],
|
|
@@ -49,6 +49,13 @@
|
|
|
49
49
|
"bash": "node \"${COPILOT_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}}}}\"/scripts/agent-stop.mjs",
|
|
50
50
|
"timeoutSec": 10
|
|
51
51
|
}
|
|
52
|
+
],
|
|
53
|
+
"errorOccurred": [
|
|
54
|
+
{
|
|
55
|
+
"type": "command",
|
|
56
|
+
"bash": "node \"${COPILOT_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-${OMP_PLUGIN_ROOT:-$OMC_PLUGIN_ROOT}}}}\"/scripts/error.mjs",
|
|
57
|
+
"timeoutSec": 5
|
|
58
|
+
}
|
|
52
59
|
]
|
|
53
60
|
}
|
|
54
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@damian87/omp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Multi-agent orchestration for GitHub Copilot CLI — autonomous loops (Autopilot, Ralph, UltraQA, Ultrawork), parallel tmux agent teams, a weighted-consensus model council, a Slack chat bridge, durable scheduled jobs, and in-session skills + custom agents. Zero learning curve.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-copilot",
|
|
3
3
|
"description": "Multi-agent orchestration skills for GitHub Copilot CLI — autopilot, ralph, ultrawork, ultraqa, team, council, code-review and more as in-session slash skills + custom agents.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.13.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Damian Borek",
|
|
7
7
|
"email": "borekdamian@yahoo.pl"
|
package/scripts/error.mjs
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
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 = "Error";
|
|
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 =
|
|
15
|
-
const errorMessage =
|
|
13
|
+
const input = parseHookInput(raw);
|
|
14
|
+
const sessionId = input.sessionId;
|
|
15
|
+
const directory = input.cwd;
|
|
16
|
+
const toolName = input.toolName;
|
|
17
|
+
const errorMessage = input.error ?? "unknown";
|
|
16
18
|
const logFile = join(directory, ".omp", "state", "hooks.log");
|
|
17
19
|
try {
|
|
18
20
|
mkdirSync(dirname(logFile), { recursive: true });
|
|
@@ -23,9 +25,9 @@ const HOOK_NAME = "Error";
|
|
|
23
25
|
} catch {
|
|
24
26
|
// best effort
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
failOpen();
|
|
27
29
|
} catch (err) {
|
|
28
30
|
console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
|
|
29
|
-
|
|
31
|
+
failOpen();
|
|
30
32
|
}
|
|
31
33
|
})();
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { ompRoot } from "./omp-root.mjs";
|
|
4
|
+
|
|
5
|
+
export function normalizeTokenInput(value) {
|
|
6
|
+
if (value == null) return "";
|
|
7
|
+
if (typeof value === "string") return value;
|
|
8
|
+
try {
|
|
9
|
+
return JSON.stringify(value) ?? "";
|
|
10
|
+
} catch {
|
|
11
|
+
return String(value);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function countTokens(value) {
|
|
16
|
+
const text = normalizeTokenInput(value);
|
|
17
|
+
if (text.length === 0) return 0;
|
|
18
|
+
return Math.ceil(text.length / 4);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function costDir(cwd) {
|
|
22
|
+
return join(ompRoot(cwd), ".omp", "state", "cost");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function safeSessionId(sessionId) {
|
|
26
|
+
return (
|
|
27
|
+
String(sessionId || "unknown")
|
|
28
|
+
.trim()
|
|
29
|
+
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
30
|
+
.replace(/^-+|-+$/g, "") || "unknown"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function costLedgerPath(cwd, sessionId) {
|
|
35
|
+
return join(costDir(cwd), `${safeSessionId(sessionId)}.jsonl`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalizeRecord(record = {}) {
|
|
39
|
+
return {
|
|
40
|
+
ts: record.ts ?? new Date().toISOString(),
|
|
41
|
+
sessionId: record.sessionId || "unknown",
|
|
42
|
+
event: record.event,
|
|
43
|
+
toolName: record.toolName,
|
|
44
|
+
model: record.model,
|
|
45
|
+
inTokens: Number.isFinite(record.inTokens) ? Math.max(0, Number(record.inTokens)) : 0,
|
|
46
|
+
outTokens: Number.isFinite(record.outTokens) ? Math.max(0, Number(record.outTokens)) : 0,
|
|
47
|
+
rawOutTokens: Number.isFinite(record.rawOutTokens) ? Math.max(0, Number(record.rawOutTokens)) : undefined,
|
|
48
|
+
savedTokens: Number.isFinite(record.savedTokens) ? Math.max(0, Number(record.savedTokens)) : undefined,
|
|
49
|
+
rawPath: typeof record.rawPath === "string" ? record.rawPath : undefined,
|
|
50
|
+
estUSD: Number.isFinite(record.estUSD) ? Number(record.estUSD) : undefined,
|
|
51
|
+
note: record.note,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function appendCostRecord(cwd, record) {
|
|
56
|
+
const normalized = normalizeRecord(record);
|
|
57
|
+
const file = costLedgerPath(cwd, normalized.sessionId);
|
|
58
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
59
|
+
appendFileSync(file, `${JSON.stringify(normalized)}\n`, "utf8");
|
|
60
|
+
return file;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readFileRecords(file) {
|
|
64
|
+
if (!existsSync(file)) return [];
|
|
65
|
+
const records = [];
|
|
66
|
+
for (const line of readFileSync(file, "utf8").split("\n")) {
|
|
67
|
+
if (!line.trim()) continue;
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(line);
|
|
70
|
+
if (parsed && typeof parsed === "object" && typeof parsed.event === "string") records.push(normalizeRecord(parsed));
|
|
71
|
+
} catch {
|
|
72
|
+
// ignore corrupt rows
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return records;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function readCostRecords(cwd, options = {}) {
|
|
79
|
+
const dir = costDir(cwd);
|
|
80
|
+
const todayPrefix = new Date().toISOString().slice(0, 10);
|
|
81
|
+
const files = options.sessionId
|
|
82
|
+
? [costLedgerPath(cwd, options.sessionId)]
|
|
83
|
+
: existsSync(dir)
|
|
84
|
+
? readdirSync(dir)
|
|
85
|
+
.filter((file) => file.endsWith(".jsonl"))
|
|
86
|
+
.sort()
|
|
87
|
+
.map((file) => join(dir, file))
|
|
88
|
+
: [];
|
|
89
|
+
const records = files.flatMap(readFileRecords);
|
|
90
|
+
return options.today ? records.filter((record) => String(record.ts ?? "").startsWith(todayPrefix)) : records;
|
|
91
|
+
}
|