oh-my-githubcopilot 1.4.1 → 1.8.0-alpha.f50f59a
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/.claude-plugin/plugin.json +36 -6
- package/.mcp.json +17 -0
- package/AGENTS.md +78 -9
- package/CHANGELOG.md +199 -1
- package/README.de.md +112 -26
- package/README.es.md +115 -29
- package/README.fr.md +114 -28
- package/README.it.md +114 -28
- package/README.ja.md +112 -26
- package/README.ko.md +112 -26
- package/README.md +96 -95
- package/README.pt.md +116 -30
- package/README.ru.md +116 -30
- package/README.tr.md +115 -29
- package/README.vi.md +116 -30
- package/README.zh.md +112 -26
- package/agents/analyst.agent.md +27 -0
- package/agents/architect.agent.md +24 -0
- package/agents/code-reviewer.agent.md +24 -0
- package/agents/critic.agent.md +24 -0
- package/agents/debugger.agent.md +24 -0
- package/agents/designer.agent.md +24 -0
- package/agents/document-specialist.agent.md +24 -0
- package/agents/executor.agent.md +27 -0
- package/agents/explorer.agent.md +23 -0
- package/agents/git-master.agent.md +24 -0
- package/agents/orchestrator.agent.md +26 -0
- package/agents/planner.agent.md +24 -0
- package/agents/qa-tester.agent.md +24 -0
- package/agents/researcher.agent.md +18 -0
- package/agents/reviewer.agent.md +23 -0
- package/agents/scientist.agent.md +20 -0
- package/agents/security-reviewer.agent.md +20 -0
- package/agents/simplifier.agent.md +20 -0
- package/agents/test-engineer.agent.md +20 -0
- package/agents/tester.agent.md +20 -0
- package/agents/tracer.agent.md +24 -0
- package/agents/verifier.agent.md +19 -0
- package/agents/writer.agent.md +24 -0
- package/bin/omp-statusline.mjs +179 -0
- package/bin/omp-statusline.mjs.map +7 -0
- package/bin/omp-statusline.sh +21 -0
- package/bin/omp.mjs +709 -16
- package/bin/omp.mjs.map +4 -4
- package/dist/hooks/hud-emitter.mjs +268 -82
- package/dist/hooks/hud-emitter.mjs.map +4 -4
- package/dist/hooks/keyword-detector.mjs +100 -23
- package/dist/hooks/keyword-detector.mjs.map +2 -2
- package/dist/hooks/model-router.mjs +1 -1
- package/dist/hooks/model-router.mjs.map +1 -1
- package/dist/hooks/stop-continuation.mjs +1 -1
- package/dist/hooks/stop-continuation.mjs.map +1 -1
- package/dist/hooks/token-tracker.mjs +2 -1
- package/dist/hooks/token-tracker.mjs.map +2 -2
- package/dist/mcp/server.mjs +85 -53
- package/dist/mcp/server.mjs.map +4 -4
- package/dist/skills/setup.mjs +39 -27
- package/dist/skills/setup.mjs.map +4 -4
- package/hooks/hooks.json +39 -45
- package/package.json +9 -4
- package/plugin.json +71 -0
- package/skills/ai-slop-cleaner/SKILL.md +137 -0
- package/skills/autopilot/SKILL.md +6 -0
- package/skills/configure-notifications/SKILL.md +6 -0
- package/skills/deep-interview/SKILL.md +6 -0
- package/skills/doctor/SKILL.md +188 -0
- package/skills/ecomode/SKILL.md +6 -0
- package/skills/graph-context/SKILL.md +119 -0
- package/skills/graph-provider/SKILL.md +6 -0
- package/skills/graphify/SKILL.md +6 -0
- package/skills/graphwiki/SKILL.md +6 -0
- package/skills/hud/SKILL.md +6 -0
- package/skills/improve-codebase-architecture/SKILL.md +214 -0
- package/skills/interactive-menu/SKILL.md +102 -0
- package/skills/interview/SKILL.md +203 -0
- package/skills/learner/SKILL.md +6 -0
- package/skills/mcp-setup/SKILL.md +6 -0
- package/skills/note/SKILL.md +6 -0
- package/skills/notifications/SKILL.md +190 -0
- package/skills/omp-doctor/SKILL.md +146 -0
- package/skills/omp-plan/SKILL.md +219 -2
- package/skills/omp-reference/SKILL.md +174 -0
- package/skills/omp-setup/SKILL.md +15 -1
- package/skills/pipeline/SKILL.md +6 -0
- package/skills/psm/SKILL.md +6 -0
- package/skills/ralph/SKILL.md +6 -0
- package/skills/ralplan/SKILL.md +148 -0
- package/skills/release/SKILL.md +6 -0
- package/skills/research/SKILL.md +149 -0
- package/skills/session/SKILL.md +220 -0
- package/skills/setup/SKILL.md +6 -0
- package/skills/skillify/SKILL.md +66 -0
- package/skills/spending/SKILL.md +6 -0
- package/skills/swarm/SKILL.md +6 -0
- package/skills/swe-bench/SKILL.md +6 -0
- package/skills/tdd/SKILL.md +246 -0
- package/skills/team/SKILL.md +6 -0
- package/skills/trace/SKILL.md +6 -0
- package/skills/ultrawork/SKILL.md +6 -0
- package/skills/wiki/SKILL.md +6 -0
- package/src/agents/analyst.md +0 -103
- package/src/agents/architect.md +0 -169
- package/src/agents/code-reviewer.md +0 -135
- package/src/agents/critic.md +0 -196
- package/src/agents/debugger.md +0 -132
- package/src/agents/designer.md +0 -103
- package/src/agents/document-specialist.md +0 -111
- package/src/agents/executor.md +0 -120
- package/src/agents/explorer.md +0 -98
- package/src/agents/git-master.md +0 -92
- package/src/agents/orchestrator.md +0 -125
- package/src/agents/planner.md +0 -106
- package/src/agents/qa-tester.md +0 -129
- package/src/agents/researcher.md +0 -102
- package/src/agents/reviewer.md +0 -100
- package/src/agents/scientist.md +0 -150
- package/src/agents/security-reviewer.md +0 -132
- package/src/agents/simplifier.md +0 -109
- package/src/agents/test-engineer.md +0 -124
- package/src/agents/tester.md +0 -102
- package/src/agents/tracer.md +0 -160
- package/src/agents/verifier.md +0 -100
- package/src/agents/writer.md +0 -96
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verifier
|
|
3
|
+
description: >
|
|
4
|
+
Verification and evidence collection specialist.
|
|
5
|
+
Use when: confirming task completion, running tests, collecting diagnostics, validating command outputs.
|
|
6
|
+
model: claude-sonnet-4-6
|
|
7
|
+
tools: [readFile, runInTerminal, search, findTestFiles, testFailures]
|
|
8
|
+
agents: [explore]
|
|
9
|
+
user-invocable: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Verifier
|
|
13
|
+
|
|
14
|
+
## Role
|
|
15
|
+
Run tests, collect diagnostics, validate command outputs, and produce evidence that a task is truly complete.
|
|
16
|
+
|
|
17
|
+
## Constraints
|
|
18
|
+
- NEVER implements — only confirms or denies
|
|
19
|
+
- Last line of defense before marking any task done
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writer
|
|
3
|
+
description: >
|
|
4
|
+
Technical documentation author.
|
|
5
|
+
Use when: writing README, API docs, changelogs, code comments, guides.
|
|
6
|
+
model: claude-sonnet-4-6
|
|
7
|
+
tools: [readFile, editFiles, search]
|
|
8
|
+
agents: [explore]
|
|
9
|
+
user-invocable: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Writer
|
|
13
|
+
|
|
14
|
+
## Role
|
|
15
|
+
Produce clear, accurate technical documentation: README files, API docs, guides, code comments, and changelogs.
|
|
16
|
+
|
|
17
|
+
## Responsibilities
|
|
18
|
+
- README and getting started guides
|
|
19
|
+
- API documentation and code comments
|
|
20
|
+
- Changelog and release notes
|
|
21
|
+
|
|
22
|
+
## Constraints
|
|
23
|
+
- Matches existing documentation style
|
|
24
|
+
- Never documents code that does not exist
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/hud/statusline.mts
|
|
4
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
import { dirname, join } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
|
|
9
|
+
// src/hud/renderer.mts
|
|
10
|
+
function formatAge(startedAt) {
|
|
11
|
+
const elapsed = Date.now() - startedAt;
|
|
12
|
+
const mins = Math.floor(elapsed / 6e4);
|
|
13
|
+
if (mins < 60) return `${mins}m`;
|
|
14
|
+
const hours = Math.floor(mins / 60);
|
|
15
|
+
const remainingMins = mins % 60;
|
|
16
|
+
return `${hours}h${remainingMins}m`;
|
|
17
|
+
}
|
|
18
|
+
function formatTokens(tokens) {
|
|
19
|
+
if (tokens >= 1e6) return `${(tokens / 1e6).toFixed(1)}M`;
|
|
20
|
+
if (tokens >= 1e3) return `${(tokens / 1e3).toFixed(1)}k`;
|
|
21
|
+
return `${tokens}`;
|
|
22
|
+
}
|
|
23
|
+
function renderPlain(state) {
|
|
24
|
+
const age = formatAge(state.startedAt);
|
|
25
|
+
const tokens = formatTokens(state.tokensUsed);
|
|
26
|
+
const ctx = state.contextPct;
|
|
27
|
+
const mode = state.activeMode || "-";
|
|
28
|
+
const model = state.activeModel || "sonnet";
|
|
29
|
+
const reqWarningPlain = state.warningActive ? " !!" : "";
|
|
30
|
+
const reqStrPlain = `req:${state.premiumRequests ?? 0}/${state.premiumRequestsTotal ?? 1500}${reqWarningPlain}`;
|
|
31
|
+
return `[OMP v${state.version}] ${mode} | ${model} | ctx:${ctx}% | tok:~${tokens}/${state.tokensTotal} | ${reqStrPlain} | ${age} | tools:${state.toolsUsed?.size || 0}/${state.toolsTotal ?? 13} | skills:${state.skillsUsed?.size || 0}/${state.skillsTotal ?? 25} | agents:${state.cumulativeAgentsUsed}/${state.agentsTotal ?? 23} | ${state.status}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/hud/statusline.mts
|
|
35
|
+
var DEFAULT_VERSION = "0.0.0";
|
|
36
|
+
var DEFAULT_STATUSLINE = "OMP | hud: no active session";
|
|
37
|
+
var DEFAULT_TOKEN_BUDGET = 2e5;
|
|
38
|
+
var DEFAULT_PREMIUM_REQUESTS_TOTAL = 1500;
|
|
39
|
+
function getStatuslinePaths(home = process.env["HOME"] || homedir()) {
|
|
40
|
+
const ompDir = join(home, ".omp");
|
|
41
|
+
const hudDir = join(ompDir, "hud");
|
|
42
|
+
return {
|
|
43
|
+
legacyLinePath: join(ompDir, "hud.line"),
|
|
44
|
+
hudDir,
|
|
45
|
+
statusJsonPath: join(hudDir, "status.json"),
|
|
46
|
+
displayPath: join(hudDir, "display.txt"),
|
|
47
|
+
tmuxSegmentPath: join(hudDir, "tmux-segment.sh")
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function ensureParent(filePath) {
|
|
51
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
function writeAtomic(filePath, content, mode) {
|
|
54
|
+
ensureParent(filePath);
|
|
55
|
+
const tempPath = `${filePath}.tmp`;
|
|
56
|
+
writeFileSync(tempPath, content, mode === void 0 ? "utf-8" : { encoding: "utf-8", mode });
|
|
57
|
+
renameSync(tempPath, filePath);
|
|
58
|
+
}
|
|
59
|
+
function normalizeStringArray(value) {
|
|
60
|
+
if (!Array.isArray(value)) return [];
|
|
61
|
+
return value.filter((item) => typeof item === "string");
|
|
62
|
+
}
|
|
63
|
+
function serializeHudState(state) {
|
|
64
|
+
return {
|
|
65
|
+
...state,
|
|
66
|
+
toolsUsed: Array.from(state.toolsUsed),
|
|
67
|
+
skillsUsed: Array.from(state.skillsUsed)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function deserializeHudState(raw) {
|
|
71
|
+
if (!raw || typeof raw !== "object") return null;
|
|
72
|
+
const value = raw;
|
|
73
|
+
const toolsUsed = new Set(normalizeStringArray(value.toolsUsed));
|
|
74
|
+
const skillsUsed = new Set(normalizeStringArray(value.skillsUsed));
|
|
75
|
+
const agentsActive = normalizeStringArray(value.agentsActive);
|
|
76
|
+
const status = typeof value.status === "string" ? value.status : "idle";
|
|
77
|
+
return {
|
|
78
|
+
sessionId: typeof value.sessionId === "string" ? value.sessionId : "default",
|
|
79
|
+
activeMode: typeof value.activeMode === "string" ? value.activeMode : null,
|
|
80
|
+
activeModel: typeof value.activeModel === "string" ? value.activeModel : "sonnet",
|
|
81
|
+
contextPct: typeof value.contextPct === "number" ? value.contextPct : 0,
|
|
82
|
+
tokensUsed: typeof value.tokensUsed === "number" ? value.tokensUsed : 0,
|
|
83
|
+
tokensTotal: typeof value.tokensTotal === "number" ? value.tokensTotal : DEFAULT_TOKEN_BUDGET,
|
|
84
|
+
agentsActive,
|
|
85
|
+
lastAgent: typeof value.lastAgent === "string" ? value.lastAgent : agentsActive.at(-1) ?? "-",
|
|
86
|
+
lastOutput: typeof value.lastOutput === "string" ? value.lastOutput : "",
|
|
87
|
+
taskProgress: typeof value.taskProgress === "number" ? value.taskProgress : 0,
|
|
88
|
+
startedAt: typeof value.startedAt === "number" ? value.startedAt : Date.now(),
|
|
89
|
+
updatedAt: typeof value.updatedAt === "number" ? value.updatedAt : Date.now(),
|
|
90
|
+
version: typeof value.version === "string" ? value.version : DEFAULT_VERSION,
|
|
91
|
+
status,
|
|
92
|
+
sessionDurationMs: typeof value.sessionDurationMs === "number" ? value.sessionDurationMs : 0,
|
|
93
|
+
cumulativeAgentsUsed: typeof value.cumulativeAgentsUsed === "number" ? value.cumulativeAgentsUsed : agentsActive.length,
|
|
94
|
+
toolsUsed,
|
|
95
|
+
skillsUsed,
|
|
96
|
+
toolsTotal: typeof value.toolsTotal === "number" ? value.toolsTotal : 13,
|
|
97
|
+
skillsTotal: typeof value.skillsTotal === "number" ? value.skillsTotal : 25,
|
|
98
|
+
agentsTotal: typeof value.agentsTotal === "number" ? value.agentsTotal : 23,
|
|
99
|
+
premiumRequests: typeof value.premiumRequests === "number" ? value.premiumRequests : 0,
|
|
100
|
+
premiumRequestsTotal: typeof value.premiumRequestsTotal === "number" ? value.premiumRequestsTotal : DEFAULT_PREMIUM_REQUESTS_TOTAL,
|
|
101
|
+
warningActive: typeof value.warningActive === "boolean" ? value.warningActive : false
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildHudState(snapshot, now = Date.now()) {
|
|
105
|
+
const startedAt = snapshot.started_at ?? now;
|
|
106
|
+
const updatedAt = snapshot.updated_at ?? now;
|
|
107
|
+
const toolsUsed = new Set(normalizeStringArray(snapshot.tools_used));
|
|
108
|
+
const skillsUsed = new Set(normalizeStringArray(snapshot.skills_used));
|
|
109
|
+
const agentsActive = normalizeStringArray(snapshot.agents_used);
|
|
110
|
+
return {
|
|
111
|
+
sessionId: snapshot.session_id ?? "default",
|
|
112
|
+
activeMode: snapshot.active_mode ?? null,
|
|
113
|
+
activeModel: snapshot.model ?? "sonnet",
|
|
114
|
+
contextPct: snapshot.context_pct ?? 0,
|
|
115
|
+
tokensUsed: snapshot.tokens_estimated ?? 0,
|
|
116
|
+
tokensTotal: snapshot.token_budget ?? DEFAULT_TOKEN_BUDGET,
|
|
117
|
+
agentsActive,
|
|
118
|
+
lastAgent: agentsActive.at(-1) ?? "-",
|
|
119
|
+
lastOutput: snapshot.last_output ?? "",
|
|
120
|
+
taskProgress: snapshot.task_progress ?? 0,
|
|
121
|
+
startedAt,
|
|
122
|
+
updatedAt,
|
|
123
|
+
version: snapshot.version ?? DEFAULT_VERSION,
|
|
124
|
+
status: snapshot.status ?? "idle",
|
|
125
|
+
sessionDurationMs: Math.max(0, updatedAt - startedAt),
|
|
126
|
+
cumulativeAgentsUsed: agentsActive.length,
|
|
127
|
+
toolsUsed,
|
|
128
|
+
skillsUsed,
|
|
129
|
+
toolsTotal: 13,
|
|
130
|
+
skillsTotal: 25,
|
|
131
|
+
agentsTotal: 23,
|
|
132
|
+
premiumRequests: snapshot.premium_requests ?? 0,
|
|
133
|
+
premiumRequestsTotal: snapshot.premium_requests_total ?? DEFAULT_PREMIUM_REQUESTS_TOTAL,
|
|
134
|
+
warningActive: snapshot.warning_active ?? false
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function writeHudArtifacts(snapshot, paths = getStatuslinePaths()) {
|
|
138
|
+
const state = buildHudState(snapshot);
|
|
139
|
+
const line = renderPlain(state);
|
|
140
|
+
const serializedState = `${JSON.stringify(serializeHudState(state), null, 2)}
|
|
141
|
+
`;
|
|
142
|
+
writeAtomic(paths.statusJsonPath, serializedState);
|
|
143
|
+
writeAtomic(paths.displayPath, `${line}
|
|
144
|
+
`);
|
|
145
|
+
writeAtomic(paths.tmuxSegmentPath, `${line}
|
|
146
|
+
`, 493);
|
|
147
|
+
writeAtomic(paths.legacyLinePath, `${line}
|
|
148
|
+
`);
|
|
149
|
+
return { line, state, paths };
|
|
150
|
+
}
|
|
151
|
+
function readStatusline(paths = getStatuslinePaths()) {
|
|
152
|
+
try {
|
|
153
|
+
const line = readFileSync(paths.displayPath, "utf-8").trim();
|
|
154
|
+
if (line) return line;
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const parsed = JSON.parse(readFileSync(paths.statusJsonPath, "utf-8"));
|
|
159
|
+
const state = deserializeHudState(parsed);
|
|
160
|
+
if (state) return renderPlain(state);
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const line = readFileSync(paths.legacyLinePath, "utf-8").trim();
|
|
165
|
+
if (line) return line;
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
return DEFAULT_STATUSLINE;
|
|
169
|
+
}
|
|
170
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
171
|
+
console.log(readStatusline());
|
|
172
|
+
}
|
|
173
|
+
export {
|
|
174
|
+
buildHudState,
|
|
175
|
+
getStatuslinePaths,
|
|
176
|
+
readStatusline,
|
|
177
|
+
writeHudArtifacts
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=omp-statusline.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/hud/statusline.mts", "../src/hud/renderer.mts"],
|
|
4
|
+
"sourcesContent": ["/**\n * HUD statusline helpers and standalone entrypoint.\n *\n * Keeps HUD artifact generation in one place so hooks and shell wrappers\n * can share the same rendering and fallback behavior.\n */\n\nimport { mkdirSync, readFileSync, renameSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { renderPlain, type HudState, type HudStatus } from \"./renderer.mts\";\n\nconst DEFAULT_VERSION = \"0.0.0\";\nconst DEFAULT_STATUSLINE = \"OMP | hud: no active session\";\nconst DEFAULT_TOKEN_BUDGET = 200_000;\nconst DEFAULT_PREMIUM_REQUESTS_TOTAL = 1500;\n\nexport interface StatuslinePaths {\n legacyLinePath: string;\n hudDir: string;\n statusJsonPath: string;\n displayPath: string;\n tmuxSegmentPath: string;\n}\n\nexport interface HudSnapshot {\n version?: string;\n session_id?: string;\n started_at?: number;\n updated_at?: number;\n model?: string;\n tokens_estimated?: number;\n token_budget?: number;\n context_pct?: number;\n tools_used?: string[];\n skills_used?: string[];\n agents_used?: string[];\n active_mode?: string | null;\n last_output?: string;\n task_progress?: number;\n status?: HudStatus;\n premium_requests?: number;\n premium_requests_total?: number;\n warning_active?: boolean;\n}\n\ninterface SerializedHudState extends Omit<HudState, \"toolsUsed\" | \"skillsUsed\"> {\n toolsUsed: string[];\n skillsUsed: string[];\n}\n\nexport function getStatuslinePaths(home = process.env[\"HOME\"] || homedir()): StatuslinePaths {\n const ompDir = join(home, \".omp\");\n const hudDir = join(ompDir, \"hud\");\n return {\n legacyLinePath: join(ompDir, \"hud.line\"),\n hudDir,\n statusJsonPath: join(hudDir, \"status.json\"),\n displayPath: join(hudDir, \"display.txt\"),\n tmuxSegmentPath: join(hudDir, \"tmux-segment.sh\"),\n };\n}\n\nfunction ensureParent(filePath: string): void {\n mkdirSync(dirname(filePath), { recursive: true });\n}\n\nfunction writeAtomic(filePath: string, content: string, mode?: number): void {\n ensureParent(filePath);\n const tempPath = `${filePath}.tmp`;\n writeFileSync(tempPath, content, mode === undefined ? \"utf-8\" : { encoding: \"utf-8\", mode });\n renameSync(tempPath, filePath);\n}\n\nfunction normalizeStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\");\n}\n\nfunction serializeHudState(state: HudState): SerializedHudState {\n return {\n ...state,\n toolsUsed: Array.from(state.toolsUsed),\n skillsUsed: Array.from(state.skillsUsed),\n };\n}\n\nfunction deserializeHudState(raw: unknown): HudState | null {\n if (!raw || typeof raw !== \"object\") return null;\n const value = raw as Record<string, unknown>;\n const toolsUsed = new Set(normalizeStringArray(value.toolsUsed));\n const skillsUsed = new Set(normalizeStringArray(value.skillsUsed));\n const agentsActive = normalizeStringArray(value.agentsActive);\n const status = typeof value.status === \"string\" ? (value.status as HudStatus) : \"idle\";\n\n return {\n sessionId: typeof value.sessionId === \"string\" ? value.sessionId : \"default\",\n activeMode: typeof value.activeMode === \"string\" ? value.activeMode : null,\n activeModel: typeof value.activeModel === \"string\" ? value.activeModel : \"sonnet\",\n contextPct: typeof value.contextPct === \"number\" ? value.contextPct : 0,\n tokensUsed: typeof value.tokensUsed === \"number\" ? value.tokensUsed : 0,\n tokensTotal: typeof value.tokensTotal === \"number\" ? value.tokensTotal : DEFAULT_TOKEN_BUDGET,\n agentsActive,\n lastAgent: typeof value.lastAgent === \"string\" ? value.lastAgent : agentsActive.at(-1) ?? \"-\",\n lastOutput: typeof value.lastOutput === \"string\" ? value.lastOutput : \"\",\n taskProgress: typeof value.taskProgress === \"number\" ? value.taskProgress : 0,\n startedAt: typeof value.startedAt === \"number\" ? value.startedAt : Date.now(),\n updatedAt: typeof value.updatedAt === \"number\" ? value.updatedAt : Date.now(),\n version: typeof value.version === \"string\" ? value.version : DEFAULT_VERSION,\n status,\n sessionDurationMs: typeof value.sessionDurationMs === \"number\" ? value.sessionDurationMs : 0,\n cumulativeAgentsUsed: typeof value.cumulativeAgentsUsed === \"number\" ? value.cumulativeAgentsUsed : agentsActive.length,\n toolsUsed,\n skillsUsed,\n toolsTotal: typeof value.toolsTotal === \"number\" ? value.toolsTotal : 13,\n skillsTotal: typeof value.skillsTotal === \"number\" ? value.skillsTotal : 25,\n agentsTotal: typeof value.agentsTotal === \"number\" ? value.agentsTotal : 23,\n premiumRequests: typeof value.premiumRequests === \"number\" ? value.premiumRequests : 0,\n premiumRequestsTotal: typeof value.premiumRequestsTotal === \"number\" ? value.premiumRequestsTotal : DEFAULT_PREMIUM_REQUESTS_TOTAL,\n warningActive: typeof value.warningActive === \"boolean\" ? value.warningActive : false,\n };\n}\n\nexport function buildHudState(snapshot: HudSnapshot, now = Date.now()): HudState {\n const startedAt = snapshot.started_at ?? now;\n const updatedAt = snapshot.updated_at ?? now;\n const toolsUsed = new Set(normalizeStringArray(snapshot.tools_used));\n const skillsUsed = new Set(normalizeStringArray(snapshot.skills_used));\n const agentsActive = normalizeStringArray(snapshot.agents_used);\n\n return {\n sessionId: snapshot.session_id ?? \"default\",\n activeMode: snapshot.active_mode ?? null,\n activeModel: snapshot.model ?? \"sonnet\",\n contextPct: snapshot.context_pct ?? 0,\n tokensUsed: snapshot.tokens_estimated ?? 0,\n tokensTotal: snapshot.token_budget ?? DEFAULT_TOKEN_BUDGET,\n agentsActive,\n lastAgent: agentsActive.at(-1) ?? \"-\",\n lastOutput: snapshot.last_output ?? \"\",\n taskProgress: snapshot.task_progress ?? 0,\n startedAt,\n updatedAt,\n version: snapshot.version ?? DEFAULT_VERSION,\n status: snapshot.status ?? \"idle\",\n sessionDurationMs: Math.max(0, updatedAt - startedAt),\n cumulativeAgentsUsed: agentsActive.length,\n toolsUsed,\n skillsUsed,\n toolsTotal: 13,\n skillsTotal: 25,\n agentsTotal: 23,\n premiumRequests: snapshot.premium_requests ?? 0,\n premiumRequestsTotal: snapshot.premium_requests_total ?? DEFAULT_PREMIUM_REQUESTS_TOTAL,\n warningActive: snapshot.warning_active ?? false,\n };\n}\n\nexport function writeHudArtifacts(snapshot: HudSnapshot, paths = getStatuslinePaths()): { line: string; state: HudState; paths: StatuslinePaths } {\n const state = buildHudState(snapshot);\n const line = renderPlain(state);\n const serializedState = `${JSON.stringify(serializeHudState(state), null, 2)}\\n`;\n\n writeAtomic(paths.statusJsonPath, serializedState);\n writeAtomic(paths.displayPath, `${line}\\n`);\n writeAtomic(paths.tmuxSegmentPath, `${line}\\n`, 0o755);\n writeAtomic(paths.legacyLinePath, `${line}\\n`);\n\n return { line, state, paths };\n}\n\nexport function readStatusline(paths = getStatuslinePaths()): string {\n try {\n const line = readFileSync(paths.displayPath, \"utf-8\").trim();\n if (line) return line;\n } catch {\n // Fall through to other sources.\n }\n\n try {\n const parsed = JSON.parse(readFileSync(paths.statusJsonPath, \"utf-8\"));\n const state = deserializeHudState(parsed);\n if (state) return renderPlain(state);\n } catch {\n // Fall through to legacy file.\n }\n\n try {\n const line = readFileSync(paths.legacyLinePath, \"utf-8\").trim();\n if (line) return line;\n } catch {\n // No HUD artifacts yet.\n }\n\n return DEFAULT_STATUSLINE;\n}\n\nif (process.argv[1] === fileURLToPath(import.meta.url)) {\n console.log(readStatusline());\n}\n", "/**\n * HUD Renderer\n * Formats HudState into ANSI or plain text status lines.\n */\n\n\nexport interface HudState {\n sessionId: string;\n activeMode: string | null;\n activeModel: string;\n contextPct: number;\n tokensUsed: number;\n tokensTotal: number;\n agentsActive: string[];\n lastAgent: string;\n lastOutput: string;\n taskProgress: number;\n startedAt: number;\n updatedAt: number;\n version: string;\n status: HudStatus;\n sessionDurationMs: number;\n cumulativeAgentsUsed: number;\n toolsUsed: Set<string>;\n skillsUsed: Set<string>;\n toolsTotal: number;\n skillsTotal: number;\n agentsTotal: number;\n premiumRequests: number;\n premiumRequestsTotal: number;\n warningActive: boolean;\n}\n\nexport type HudStatus = \"idle\" | \"running\" | \"waiting\" | \"complete\" | \"error\" | \"eco\";\n\nconst STATUS_ICONS: Record<HudStatus, string> = {\n idle: \"\u25CB\",\n running: \"\u25CF\",\n waiting: \"\u25F7\",\n complete: \"\u2713\",\n error: \"\u2717\",\n eco: \"\u26A1\",\n};\n\nfunction formatAge(startedAt: number): string {\n const elapsed = Date.now() - startedAt;\n const mins = Math.floor(elapsed / 60000);\n if (mins < 60) return `${mins}m`;\n const hours = Math.floor(mins / 60);\n const remainingMins = mins % 60;\n return `${hours}h${remainingMins}m`;\n}\n\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}k`;\n return `${tokens}`;\n}\n\nfunction ctxColor(pct: number): string {\n if (pct < 60) return \"\\x1b[32m\"; // green\n if (pct < 85) return \"\\x1b[33m\"; // yellow\n return \"\\x1b[31m\"; // red\n}\n\nfunction reset(): string {\n return \"\\x1b[0m\";\n}\n\n/**\n * Render HUD line with ANSI color codes.\n * Format: [OMP v1.0.0] mode | model | ctx:N% | tok:~Nk/Nk | Nm | tools:N/N | skills:N/N | agents:N/N | N% status\n */\nexport function renderAnsi(state: HudState): string {\n const age = formatAge(state.startedAt);\n const tokens = formatTokens(state.tokensUsed);\n const ctx = state.contextPct;\n const mode = state.activeMode || \"-\";\n const model = state.activeModel || \"sonnet\";\n const icon = STATUS_ICONS[state.status] || \"\u25CF\";\n\n const ctxClr = ctxColor(ctx);\n const ctxStr = `${ctxClr}ctx:${ctx}%${reset()}`;\n const tokenStr = `tok:~${tokens}/${state.tokensTotal}`;\n const modeStr = mode === \"-\" ? \"-\" : `\\x1b[36m${mode}${reset()}`; // cyan for active modes\n\n const reqWarning = state.warningActive ? \" !!\" : \"\";\n const reqStr = `req:${state.premiumRequests ?? 0}/${state.premiumRequestsTotal ?? 1500}${reqWarning}`;\n\n return `[OMP v${state.version}] ${modeStr} | ${model} | ${ctxStr} | ${tokenStr} | ${reqStr} | ${age} | tools:${state.toolsUsed?.size || 0}/${state.toolsTotal ?? 13} | skills:${state.skillsUsed?.size || 0}/${state.skillsTotal ?? 25} | agents:${state.cumulativeAgentsUsed}/${state.agentsTotal ?? 23} | ${icon} ${state.status}`;\n}\n\n/**\n * Render HUD line as plain text (no ANSI codes).\n * Format: [OMP v1.0.0] mode | model | ctx:N% | tok:~Nk/Nk | Nm | tools:N/N | skills:N/N | agents:N/N | N% status\n */\nexport function renderPlain(state: HudState): string {\n const age = formatAge(state.startedAt);\n const tokens = formatTokens(state.tokensUsed);\n const ctx = state.contextPct;\n const mode = state.activeMode || \"-\";\n const model = state.activeModel || \"sonnet\";\n\n const reqWarningPlain = state.warningActive ? \" !!\" : \"\";\n const reqStrPlain = `req:${state.premiumRequests ?? 0}/${state.premiumRequestsTotal ?? 1500}${reqWarningPlain}`;\n\n return `[OMP v${state.version}] ${mode} | ${model} | ctx:${ctx}% | tok:~${tokens}/${state.tokensTotal} | ${reqStrPlain} | ${age} | tools:${state.toolsUsed?.size || 0}/${state.toolsTotal ?? 13} | skills:${state.skillsUsed?.size || 0}/${state.skillsTotal ?? 25} | agents:${state.cumulativeAgentsUsed}/${state.agentsTotal ?? 23} | ${state.status}`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
ENTRY="$SCRIPT_DIR/omp-statusline.mjs"
|
|
6
|
+
DISPLAY_PATH="${OMP_HUD_DISPLAY_PATH:-$HOME/.omp/hud/display.txt}"
|
|
7
|
+
LEGACY_PATH="${OMP_HUD_LEGACY_PATH:-$HOME/.omp/hud.line}"
|
|
8
|
+
|
|
9
|
+
if [[ -f "$ENTRY" ]]; then
|
|
10
|
+
exec node "$ENTRY" "$@"
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [[ -r "$DISPLAY_PATH" ]]; then
|
|
14
|
+
exec cat "$DISPLAY_PATH"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
if [[ -r "$LEGACY_PATH" ]]; then
|
|
18
|
+
exec cat "$LEGACY_PATH"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
printf 'OMP | hud: no active session\n'
|