omniagent 0.1.7 → 0.1.8

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.
@@ -0,0 +1,274 @@
1
+ import { c as cleanControlOutput, b as parsePercentRemaining, m as makeUsageLimit, d as parseResetText } from "./cli.js";
2
+ import { r as runPtyScenario, t as typeTextSteps, e as enterKey } from "./pty-CZBSAJzE.js";
3
+ const CODEX_WINDOWS = [
4
+ ["main", "5h", "main5hLimit"],
5
+ ["main", "weekly", "mainWeeklyLimit"],
6
+ ["spark", "5h", "spark5hLimit"],
7
+ ["spark", "weekly", "sparkWeeklyLimit"]
8
+ ];
9
+ const CLEAR_LINE = "";
10
+ async function extractCodexUsage(context) {
11
+ const command = context.command ?? context.launch?.command ?? "codex";
12
+ const ptyResult = await runPtyScenario({
13
+ command,
14
+ args: context.launch?.args ?? ["--no-alt-screen"],
15
+ cwd: context.repoRoot,
16
+ cols: 100,
17
+ rows: 40,
18
+ timeoutMs: context.launch?.timeoutMs ?? 6e4,
19
+ signal: context.signal,
20
+ debug: context.debug,
21
+ steps: [
22
+ { waitFor: isCodexPromptReady, waitForTimeoutMs: 1e4 },
23
+ ...typeTextSteps("/status", 20),
24
+ { write: enterKey() },
25
+ {
26
+ waitFor: hasCodexStatusResponse,
27
+ waitForTimeoutMs: 15e3,
28
+ capture: "status",
29
+ captureWaitMs: 500
30
+ },
31
+ { waitMs: 5e3, skipIf: hasCodexStatusLimits },
32
+ { write: `${CLEAR_LINE}/status${enterKey()}`, skipIf: hasCodexStatusLimits },
33
+ {
34
+ waitFor: hasCodexStatusLimits,
35
+ waitForTimeoutMs: 15e3,
36
+ skipIf: hasCodexStatusLimits,
37
+ optional: true,
38
+ capture: "statusRetry",
39
+ captureWaitMs: 500
40
+ },
41
+ { write: `${CLEAR_LINE}/exit${enterKey()}` },
42
+ { waitMs: 500 }
43
+ ]
44
+ });
45
+ const parsed = selectCodexStatus(ptyResult);
46
+ const result = buildCodexUsageResult(parsed, {
47
+ targetId: context.targetId,
48
+ displayName: context.displayName,
49
+ now: context.now,
50
+ command
51
+ });
52
+ return {
53
+ ...result,
54
+ debug: ptyResult.debug.length > 0 ? ptyResult.debug : void 0
55
+ };
56
+ }
57
+ function selectCodexStatus(result) {
58
+ const snapshots = [
59
+ result.snapshots.statusRetry,
60
+ result,
61
+ result.snapshots.status
62
+ ];
63
+ for (const snapshot of snapshots) {
64
+ if (snapshot == null) {
65
+ continue;
66
+ }
67
+ for (const content of [`${snapshot.screen}
68
+ ${snapshot.raw}`, snapshot.screen, snapshot.raw]) {
69
+ const parsed = parseCodexStatus(cleanControlOutput(content));
70
+ if (parsed.main5hLimit || parsed.mainWeeklyLimit) {
71
+ return parsed;
72
+ }
73
+ }
74
+ }
75
+ const fallback = result.snapshots.statusRetry ?? result.snapshots.status ?? result;
76
+ return parseCodexStatus(cleanControlOutput(`${fallback.screen}
77
+ ${fallback.raw}`));
78
+ }
79
+ function isCodexPromptReady(snapshot) {
80
+ const cleanedOutput = cleanControlOutput(`${snapshot.screen}
81
+ ${snapshot.raw}`);
82
+ return /(?:\u203a|>)\s/.test(cleanedOutput) && /\bContext\b/i.test(cleanedOutput);
83
+ }
84
+ function hasCodexStatusLimits(snapshot) {
85
+ const cleanedOutput = cleanControlOutput(`${snapshot.screen}
86
+ ${snapshot.raw}`);
87
+ const parsed = parseCodexStatus(cleanedOutput);
88
+ return Boolean(parsed.main5hLimit && parsed.mainWeeklyLimit);
89
+ }
90
+ function hasCodexStatusResponse(snapshot) {
91
+ const cleanedOutput = cleanControlOutput(`${snapshot.screen}
92
+ ${snapshot.raw}`);
93
+ const parsed = parseCodexStatus(cleanedOutput);
94
+ return Boolean(parsed.main5hLimit || parsed.mainWeeklyLimit) || /refresh requested/i.test(cleanedOutput);
95
+ }
96
+ function buildCodexUsageResult(parsed, context) {
97
+ assertAnyRequiredCodexLimit(parsed);
98
+ const errors = buildCodexUsageErrors(parsed, context);
99
+ return {
100
+ targetId: context.targetId,
101
+ displayName: context.displayName,
102
+ command: context.command,
103
+ limits: buildCodexUsageLimits(parsed, context),
104
+ errors: errors.length > 0 ? errors : void 0
105
+ };
106
+ }
107
+ function buildCodexUsageLimits(parsed, context) {
108
+ return CODEX_WINDOWS.flatMap(([scope, window, key]) => {
109
+ const raw = parsed[key]?.trim() ?? "";
110
+ if (!raw) {
111
+ return [];
112
+ }
113
+ const percentRemaining = parsePercentRemaining(raw);
114
+ return [
115
+ makeUsageLimit({
116
+ targetId: context.targetId,
117
+ scope,
118
+ window,
119
+ percentUsed: percentRemaining == null ? null : 100 - percentRemaining,
120
+ percentRemaining,
121
+ resetText: parseResetText(raw),
122
+ raw,
123
+ now: context.now
124
+ })
125
+ ];
126
+ });
127
+ }
128
+ function parseCodexStatus(cleanedOutput) {
129
+ const values = {};
130
+ let inStatus = false;
131
+ let section = "main";
132
+ let key = "";
133
+ for (const rawLine of cleanedOutput.split(/\n/)) {
134
+ const normalizedLine = normalizeCodexLine(rawLine);
135
+ if (!inStatus) {
136
+ if (normalizedLine === "Model:" || normalizedLine.startsWith("Model: ")) {
137
+ inStatus = true;
138
+ key = "model";
139
+ setValue(values, key, normalizedLine.slice("Model:".length).trim());
140
+ }
141
+ continue;
142
+ }
143
+ if (normalizedLine.includes("/exit exit Codex")) {
144
+ break;
145
+ }
146
+ if (normalizedLine.startsWith("› ")) {
147
+ key = "";
148
+ continue;
149
+ }
150
+ let line = normalizedLine;
151
+ if (!line || line === "[" || line === "]") {
152
+ continue;
153
+ }
154
+ line = line.replace(/^\]\s*/, "").trim();
155
+ if (!line) {
156
+ continue;
157
+ }
158
+ const labelMatch = /^([-A-Za-z0-9_. ]+):\s*(.*)$/.exec(line);
159
+ if (labelMatch != null) {
160
+ const label = labelMatch[1].trim();
161
+ const inlineValue = labelMatch[2].trim();
162
+ if (isCodexSparkLimitLabel(label)) {
163
+ section = "spark";
164
+ key = "";
165
+ continue;
166
+ }
167
+ key = labelToCodexKey(label, section);
168
+ if (key && inlineValue) {
169
+ setValue(values, key, inlineValue);
170
+ }
171
+ continue;
172
+ }
173
+ if (key && isCodexContinuationLine(line, values[key])) {
174
+ appendValue(values, key, line);
175
+ }
176
+ }
177
+ return {
178
+ model: values.model ?? "",
179
+ directory: values.directory ?? "",
180
+ permissions: values.permissions ?? "",
181
+ agentsMd: values.agentsMd ?? "",
182
+ account: values.account ?? "",
183
+ collaborationMode: values.collaborationMode ?? "",
184
+ session: values.session ?? "",
185
+ main5hLimit: values.main5hLimit ?? "",
186
+ mainWeeklyLimit: values.mainWeeklyLimit ?? "",
187
+ spark5hLimit: values.spark5hLimit ?? "",
188
+ sparkWeeklyLimit: values.sparkWeeklyLimit ?? ""
189
+ };
190
+ }
191
+ function assertAnyRequiredCodexLimit(parsed) {
192
+ if (parsed.main5hLimit || parsed.mainWeeklyLimit) {
193
+ return;
194
+ }
195
+ throw new Error("Codex usage output did not include the required 5h and weekly limit rows.");
196
+ }
197
+ function buildCodexUsageErrors(parsed, context) {
198
+ const missing = [];
199
+ if (!parsed.main5hLimit) {
200
+ missing.push("5h");
201
+ }
202
+ if (!parsed.mainWeeklyLimit) {
203
+ missing.push("weekly");
204
+ }
205
+ if (missing.length === 0) {
206
+ return [];
207
+ }
208
+ return [
209
+ {
210
+ targetId: context.targetId,
211
+ displayName: context.displayName,
212
+ code: "partial_parse",
213
+ message: `Codex usage output did not include the ${missing.join(" and ")} limit row.`
214
+ }
215
+ ];
216
+ }
217
+ function isCodexSparkLimitLabel(label) {
218
+ return /\bspark\b/i.test(label) && /\blimit\b/i.test(label);
219
+ }
220
+ function labelToCodexKey(label, section) {
221
+ if (label === "Model") return "model";
222
+ if (label === "Directory") return "directory";
223
+ if (label === "Permissions") return "permissions";
224
+ if (label === "Agents.md") return "agentsMd";
225
+ if (label === "Account") return "account";
226
+ if (label === "Collaboration mode") return "collaborationMode";
227
+ if (label === "Session") return "session";
228
+ if (label === "5h limit") return section === "spark" ? "spark5hLimit" : "main5hLimit";
229
+ if (label === "Weekly limit") {
230
+ return section === "spark" ? "sparkWeeklyLimit" : "mainWeeklyLimit";
231
+ }
232
+ return "";
233
+ }
234
+ function setValue(values, key, value) {
235
+ const sanitized = sanitizeCodexValue(value);
236
+ if (!sanitized) {
237
+ return;
238
+ }
239
+ values[key] = sanitized;
240
+ }
241
+ function appendValue(values, key, value) {
242
+ const sanitized = sanitizeCodexValue(value);
243
+ if (!sanitized) {
244
+ return;
245
+ }
246
+ values[key] = values[key] == null || values[key] === "" ? sanitized : `${values[key]} ${sanitized}`;
247
+ }
248
+ function isCodexContinuationLine(line, currentValue) {
249
+ if (!line) {
250
+ return false;
251
+ }
252
+ const hasPercent = /\d+(?:\.\d+)?\s*%/.test(line);
253
+ const currentHasPercent = /\d+(?:\.\d+)?\s*%/.test(currentValue ?? "");
254
+ if (hasPercent) {
255
+ return !currentHasPercent;
256
+ }
257
+ return /\breset/i.test(line);
258
+ }
259
+ function normalizeCodexLine(line) {
260
+ return line.replace(/[│╭╮╰╯─]/g, " ").replace(/[ \t]+/g, " ").trim();
261
+ }
262
+ function sanitizeCodexValue(value) {
263
+ const sanitized = value.replace(/›.*$/g, "").trim();
264
+ const limitMatch = /^(.+?\d+(?:\.\d+)?\s*%\s*(?:left|remaining|used)(?:\s*\([^)]*\))?)/i.exec(
265
+ sanitized
266
+ );
267
+ return limitMatch?.[1].trim() ?? sanitized;
268
+ }
269
+ export {
270
+ buildCodexUsageLimits,
271
+ buildCodexUsageResult,
272
+ extractCodexUsage,
273
+ parseCodexStatus
274
+ };
@@ -0,0 +1,168 @@
1
+ import { c as cleanControlOutput, m as makeUsageLimit, a as compactLines } from "./cli.js";
2
+ import { r as runPtyScenario, t as typeTextSteps, e as enterKey, a as escapeKey } from "./pty-CZBSAJzE.js";
3
+ const TIER_MODEL_IDS = /* @__PURE__ */ new Map([
4
+ ["Flash", "flash"],
5
+ ["Flash Lite", "flash-lite"],
6
+ ["Pro", "pro"]
7
+ ]);
8
+ async function extractGeminiUsage(context) {
9
+ const command = context.command ?? context.launch?.command ?? "gemini";
10
+ const ptyResult = await runPtyScenario({
11
+ command,
12
+ args: context.launch?.args ?? ["--skip-trust"],
13
+ cwd: context.repoRoot,
14
+ cols: 110,
15
+ rows: 42,
16
+ timeoutMs: context.launch?.timeoutMs ?? 7e4,
17
+ signal: context.signal,
18
+ debug: context.debug,
19
+ steps: [
20
+ { waitFor: isGeminiPromptReady, waitForTimeoutMs: 12e3 },
21
+ ...typeTextSteps("/model", 20),
22
+ { waitMs: 150, write: enterKey() },
23
+ {
24
+ waitFor: hasGeminiModelUsage,
25
+ waitForTimeoutMs: 15e3,
26
+ capture: "model",
27
+ captureWaitMs: 500
28
+ },
29
+ { write: escapeKey() },
30
+ { waitMs: 500 },
31
+ ...typeTextSteps("/quit", 20),
32
+ { waitMs: 150, write: enterKey() },
33
+ { waitMs: 500 }
34
+ ]
35
+ });
36
+ const modelSnapshot = ptyResult.snapshots.model ?? ptyResult;
37
+ const cleanedOutput = cleanControlOutput(modelSnapshot.raw);
38
+ const parsed = parseGeminiModelDialog(modelSnapshot.screen, cleanedOutput);
39
+ if (parsed.usage.length === 0) {
40
+ throw new Error("Gemini usage output did not include model usage rows.");
41
+ }
42
+ return {
43
+ targetId: context.targetId,
44
+ displayName: context.displayName,
45
+ command,
46
+ limits: parsed.usage.map((row) => {
47
+ const modelId = resolveModelId(row.name, parsed.availableModels);
48
+ return makeUsageLimit({
49
+ targetId: context.targetId,
50
+ scope: modelScope(modelId),
51
+ window: "model",
52
+ label: row.name,
53
+ modelId,
54
+ modelLabel: row.name,
55
+ percentUsed: row.percentUsed,
56
+ percentRemaining: 100 - row.percentUsed,
57
+ resetText: row.resetText,
58
+ raw: row.raw,
59
+ now: context.now
60
+ });
61
+ }),
62
+ debug: ptyResult.debug.length > 0 ? ptyResult.debug : void 0
63
+ };
64
+ }
65
+ function isGeminiPromptReady(snapshot) {
66
+ const screen = snapshot.screen || cleanControlOutput(snapshot.raw);
67
+ return /Type your message|quota/i.test(screen);
68
+ }
69
+ function hasGeminiModelUsage(snapshot) {
70
+ const parsed = parseGeminiModelDialog(snapshot.screen, cleanControlOutput(snapshot.raw));
71
+ return parsed.usage.length > 0;
72
+ }
73
+ function parseGeminiModelDialog(screen, cleanedOutput = "") {
74
+ const fromScreen = parseGeminiLines(compactLines(screen));
75
+ if (fromScreen.usage.length > 0) {
76
+ return fromScreen;
77
+ }
78
+ return parseGeminiLines(compactLines(cleanedOutput));
79
+ }
80
+ function parseGeminiLines(lines) {
81
+ const availableModels = [];
82
+ const usage = [];
83
+ let selectedModel = "";
84
+ let inUsage = false;
85
+ for (const line of lines) {
86
+ const content = stripGeminiFrame(line);
87
+ if (!content) {
88
+ continue;
89
+ }
90
+ const model = parseAvailableModel(content);
91
+ if (model != null) {
92
+ availableModels.push(model.id);
93
+ if (model.selected) {
94
+ selectedModel = model.id;
95
+ }
96
+ continue;
97
+ }
98
+ if (content === "Model usage") {
99
+ inUsage = true;
100
+ continue;
101
+ }
102
+ if (!inUsage) {
103
+ continue;
104
+ }
105
+ if (content.startsWith("(")) {
106
+ break;
107
+ }
108
+ const row = parseUsageRow(content);
109
+ if (row != null) {
110
+ usage.push(row);
111
+ }
112
+ }
113
+ return {
114
+ selectedModel,
115
+ availableModels,
116
+ usage
117
+ };
118
+ }
119
+ function parseAvailableModel(line) {
120
+ const match = /^(\u25cf)?\s*(\d+)\.\s+(\S+)$/u.exec(line);
121
+ if (match == null) {
122
+ return null;
123
+ }
124
+ return {
125
+ selected: match[1] != null,
126
+ index: Number(match[2]),
127
+ id: match[3]
128
+ };
129
+ }
130
+ function parseUsageRow(line) {
131
+ const match = /^(.*?)\s+(\d{1,3})%\s*(?:Resets:\s*(.*?))?$/u.exec(line);
132
+ if (match == null) {
133
+ return null;
134
+ }
135
+ return {
136
+ name: stripUsageBar(match[1]),
137
+ percentUsed: Number(match[2]),
138
+ resetText: (match[3] ?? "").trim(),
139
+ raw: line
140
+ };
141
+ }
142
+ function stripUsageBar(value) {
143
+ return value.replace(/[\s#=\-_\u2500-\u257F\u2580-\u259F\u25AC]+$/giu, "").trim();
144
+ }
145
+ function resolveModelId(name, availableModels) {
146
+ const tierModelId = TIER_MODEL_IDS.get(name);
147
+ if (tierModelId != null) {
148
+ return tierModelId;
149
+ }
150
+ const truncatedPrefix = name.endsWith("...") ? name.slice(0, -3) : name.endsWith("…") ? name.slice(0, -1) : null;
151
+ if (truncatedPrefix) {
152
+ const match = availableModels.find((model) => model.startsWith(truncatedPrefix));
153
+ if (match != null) {
154
+ return match;
155
+ }
156
+ }
157
+ return name;
158
+ }
159
+ function modelScope(modelId) {
160
+ return modelId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
161
+ }
162
+ function stripGeminiFrame(line) {
163
+ return line.replace(/^\s*\u2502\s?/u, "").replace(/\s*\u2502\s*$/u, "").trim();
164
+ }
165
+ export {
166
+ extractGeminiUsage,
167
+ parseGeminiModelDialog
168
+ };