@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.
Files changed (114) hide show
  1. package/.github/copilot-instructions.md +16 -0
  2. package/.github/skills/jira-ticket/SKILL.md +4 -4
  3. package/.github/skills/omp-autopilot/SKILL.md +4 -0
  4. package/.github/skills/research-codebase/SKILL.md +4 -0
  5. package/.github/skills/schedule/SKILL.md +4 -0
  6. package/.github/skills/team/SKILL.md +4 -0
  7. package/.github/skills/ultrawork/SKILL.md +4 -0
  8. package/.github/skills/weighted-consensus/SKILL.md +4 -0
  9. package/README.md +4 -1
  10. package/dist/src/cli.js +134 -4
  11. package/dist/src/cli.js.map +1 -1
  12. package/dist/src/commands/comms.d.ts +2 -0
  13. package/dist/src/commands/comms.js +110 -0
  14. package/dist/src/commands/comms.js.map +1 -0
  15. package/dist/src/commands/council.d.ts +2 -0
  16. package/dist/src/commands/council.js +77 -0
  17. package/dist/src/commands/council.js.map +1 -0
  18. package/dist/src/commands/env.d.ts +2 -0
  19. package/dist/src/commands/env.js +95 -0
  20. package/dist/src/commands/env.js.map +1 -0
  21. package/dist/src/commands/gateway.d.ts +3 -0
  22. package/dist/src/commands/gateway.js +129 -0
  23. package/dist/src/commands/gateway.js.map +1 -0
  24. package/dist/src/commands/memory.d.ts +7 -0
  25. package/dist/src/commands/memory.js +202 -0
  26. package/dist/src/commands/memory.js.map +1 -0
  27. package/dist/src/commands/mode.d.ts +4 -0
  28. package/dist/src/commands/mode.js +119 -0
  29. package/dist/src/commands/mode.js.map +1 -0
  30. package/dist/src/commands/schedule.d.ts +2 -0
  31. package/dist/src/commands/schedule.js +91 -0
  32. package/dist/src/commands/schedule.js.map +1 -0
  33. package/dist/src/commands/team.d.ts +2 -0
  34. package/dist/src/commands/team.js +146 -0
  35. package/dist/src/commands/team.js.map +1 -0
  36. package/dist/src/commands/utils.d.ts +13 -0
  37. package/dist/src/commands/utils.js +68 -0
  38. package/dist/src/commands/utils.js.map +1 -0
  39. package/dist/src/copilot/doctor.d.ts +1 -0
  40. package/dist/src/copilot/doctor.js +226 -27
  41. package/dist/src/copilot/doctor.js.map +1 -1
  42. package/dist/src/copilot/launch.js +13 -5
  43. package/dist/src/copilot/launch.js.map +1 -1
  44. package/dist/src/copilot/setup.js +13 -0
  45. package/dist/src/copilot/setup.js.map +1 -1
  46. package/dist/src/cost/index.d.ts +3 -0
  47. package/dist/src/cost/index.js +4 -0
  48. package/dist/src/cost/index.js.map +1 -0
  49. package/dist/src/cost/ledger.d.ts +21 -0
  50. package/dist/src/cost/ledger.js +72 -0
  51. package/dist/src/cost/ledger.js.map +1 -0
  52. package/dist/src/cost/summary.d.ts +22 -0
  53. package/dist/src/cost/summary.js +68 -0
  54. package/dist/src/cost/summary.js.map +1 -0
  55. package/dist/src/cost/tokenize.d.ts +7 -0
  56. package/dist/src/cost/tokenize.js +24 -0
  57. package/dist/src/cost/tokenize.js.map +1 -0
  58. package/dist/src/goal.js +6 -8
  59. package/dist/src/goal.js.map +1 -1
  60. package/dist/src/instructions-memory.js +26 -3
  61. package/dist/src/instructions-memory.js.map +1 -1
  62. package/dist/src/memory-review/apply.d.ts +7 -0
  63. package/dist/src/memory-review/apply.js +75 -0
  64. package/dist/src/memory-review/apply.js.map +1 -0
  65. package/dist/src/memory-review/config.d.ts +22 -0
  66. package/dist/src/memory-review/config.js +54 -0
  67. package/dist/src/memory-review/config.js.map +1 -0
  68. package/dist/src/memory-review/guard.d.ts +5 -0
  69. package/dist/src/memory-review/guard.js +37 -0
  70. package/dist/src/memory-review/guard.js.map +1 -0
  71. package/dist/src/memory-review/index.d.ts +17 -0
  72. package/dist/src/memory-review/index.js +87 -0
  73. package/dist/src/memory-review/index.js.map +1 -0
  74. package/dist/src/memory-review/prompt.d.ts +18 -0
  75. package/dist/src/memory-review/prompt.js +89 -0
  76. package/dist/src/memory-review/prompt.js.map +1 -0
  77. package/dist/src/memory-review/spawn.d.ts +2 -0
  78. package/dist/src/memory-review/spawn.js +51 -0
  79. package/dist/src/memory-review/spawn.js.map +1 -0
  80. package/dist/src/memory-review/transcript.d.ts +24 -0
  81. package/dist/src/memory-review/transcript.js +212 -0
  82. package/dist/src/memory-review/transcript.js.map +1 -0
  83. package/dist/src/memory-review/trigger.d.ts +21 -0
  84. package/dist/src/memory-review/trigger.js +27 -0
  85. package/dist/src/memory-review/trigger.js.map +1 -0
  86. package/dist/src/project-memory.d.ts +9 -0
  87. package/dist/src/project-memory.js +72 -1
  88. package/dist/src/project-memory.js.map +1 -1
  89. package/dist/src/state.js +25 -37
  90. package/dist/src/state.js.map +1 -1
  91. package/dist/src/utils/fs.d.ts +14 -0
  92. package/dist/src/utils/fs.js +32 -0
  93. package/dist/src/utils/fs.js.map +1 -0
  94. package/dist/src/utils/paths.d.ts +14 -0
  95. package/dist/src/utils/paths.js +21 -0
  96. package/dist/src/utils/paths.js.map +1 -0
  97. package/docs/general-skills.md +1 -0
  98. package/docs/memory-mode.md +94 -0
  99. package/hooks/hooks.json +9 -2
  100. package/package.json +1 -1
  101. package/plugin.json +1 -1
  102. package/scripts/error.mjs +9 -7
  103. package/scripts/lib/cost-ledger.mjs +91 -0
  104. package/scripts/lib/hook-input.mjs +51 -0
  105. package/scripts/lib/hook-output.mjs +53 -11
  106. package/scripts/lib/memory-review-trigger.mjs +59 -0
  107. package/scripts/lib/minify.mjs +80 -0
  108. package/scripts/lib/pending-directives.mjs +36 -0
  109. package/scripts/post-tool-use-failure.mjs +21 -0
  110. package/scripts/post-tool-use.mjs +71 -8
  111. package/scripts/pre-tool-use.mjs +8 -6
  112. package/scripts/prompt-submit.mjs +12 -5
  113. package/scripts/session-end.mjs +15 -5
  114. 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":"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"}
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, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { ompRoot } from "./omp-root.js";
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 join(ompRoot(cwd), ".omp", "state", "kv");
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
- mkdirSync(dirname(path), { recursive: true });
21
- const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
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
- if (!existsSync(path))
30
- return { value: null };
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
- try {
59
- const entry = JSON.parse(readFileSync(join(dir, f), "utf8"));
60
- if (entry.expiresAt && Date.parse(entry.expiresAt) < now)
61
- continue;
62
- keys.push(f.replace(/\.json$/, ""));
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
- try {
82
- const entry = JSON.parse(readFileSync(path, "utf8"));
83
- if (entry.expiresAt && Date.parse(entry.expiresAt) < now) {
84
- unlinkSync(path);
85
- deleted++;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5H,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAYxC,SAAS,KAAK,CAAC,GAAW;IACxB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,MAAM,CAAC,GAAW,EAAE,GAAW;IACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,GAAW,EAAE,KAAc,EAAE,UAAmB;IACtF,MAAM,KAAK,GAAU;QACnB,KAAK;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;KACnG,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACvD,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3D,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,GAAW;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAU,CAAC;QAC9D,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAChE,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACxC,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;YACtE,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG;gBAAE,SAAS;YACnE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAU,CAAC;YAC9D,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,EAAE,CAAC;gBACzD,UAAU,CAAC,IAAI,CAAC,CAAC;gBACjB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAChD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACvE,CAAC"}
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"}
@@ -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
- "errorOccurred": [
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/error.mjs",
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.10.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.10.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 data = raw ? JSON.parse(raw) : {};
12
- const sessionId = data.sessionId ?? data.session_id ?? "unknown";
13
- const directory = data.cwd ?? data.directory ?? process.cwd();
14
- const toolName = data.toolName ?? data.tool_name ?? "unknown";
15
- const errorMessage = data.error?.message ?? data.message ?? "unknown";
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
- console.log(JSON.stringify({ continue: true }));
28
+ failOpen();
27
29
  } catch (err) {
28
30
  console.error(`[hook ${HOOK_NAME}] failed: ${err?.message ?? err}`);
29
- console.log(JSON.stringify({ continue: true }));
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
+ }